diff --git a/.github/workflows/triage-move-labelled.yml b/.github/workflows/triage-move-labelled.yml index 4645e9b02..d1e110540 100644 --- a/.github/workflows/triage-move-labelled.yml +++ b/.github/workflows/triage-move-labelled.yml @@ -191,7 +191,7 @@ jobs: PROJECT_ID: "PN_kwDOAM0swc3m-g" GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} -move_FTUE_issues: + move_FTUE_issues: name: Z-FTUE to FTUE board runs-on: ubuntu-latest if: > @@ -214,7 +214,7 @@ move_FTUE_issues: PROJECT_ID: "PN_kwDOAM0swc4AAqVx" GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} -move_WTF_issues: + move_WTF_issues: name: Z-WTF to WTF board runs-on: ubuntu-latest if: > diff --git a/.swiftlint.yml b/.swiftlint.yml index 4d215eb98..f210c1ac3 100755 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -36,7 +36,7 @@ line_length: error: 1000 file_length: - warning: 700 + warning: 800 error: 1000 type_body_length: diff --git a/CHANGES.md b/CHANGES.md index c5c23b33f..c8f9b1ae3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,64 @@ +## Changes in 1.8.1 (2022-02-16) + +🙌 Improvements + +- Upgrade MatrixSDK version ([v0.22.1](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.22.1)). + +🐛 Bugfixes + +- Settings: Fix a bug where tapping a toggle could change multiple settings. ([#5463](https://github.com/vector-im/element-ios/issues/5463)) +- Fix for images sometimes being sent unencrypted inside an encrypted room. ([#5564](https://github.com/vector-im/element-ios/issues/5564)) + + +## Changes in 1.8.0 (2022-02-09) + +✨ Features + +- Threads: Add `View in room` action to the thread root event. ([#5117](https://github.com/vector-im/element-ios/issues/5117)) +- Add a splash screen before authentication is shown. ([#5159](https://github.com/vector-im/element-ios/issues/5159)) +- Remove location sharing settings entry and enable it by default. Add .well-known configuration support for tile server and map styles. ([#5298](https://github.com/vector-im/element-ios/issues/5298)) + +🙌 Improvements + +- Show target user avatars for collapsed membership changes ([#4148](https://github.com/vector-im/element-ios/pull/4148)) +- Updated available emojis with data from https://github.com/missive/emoji-mart/blob/master/data/apple.json ([#5517](https://github.com/vector-im/element-ios/pull/5517)) +- Upgrade MatrixSDK version ([v0.22.0](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.22.0)). +- Permalinks: Create for thread events & handle navigations. ([#5094](https://github.com/vector-im/element-ios/issues/5094)) +- Search: Navigate to thread view for search results in threads. ([#5095](https://github.com/vector-im/element-ios/issues/5095)) +- Search: display matching pattern with a highlight color ([#5252](https://github.com/vector-im/element-ios/issues/5252)) + +🐛 Bugfixes + +- Share: Handle jpeg and png UTType properly ([#3636](https://github.com/vector-im/element-ios/issues/3636)) +- Timeline: automatically scroll timeline to the bottom when opening a room or rotating device. ([#4524](https://github.com/vector-im/element-ios/issues/4524)) +- Fix bugs when building with Xcode 13: bar appearance / header padding / space avatar content size. Additionally, use UIKit context menus on the home screen. ([#4883](https://github.com/vector-im/element-ios/issues/4883)) +- joining a space seemed to noop ([#5171](https://github.com/vector-im/element-ios/issues/5171)) +- Accepting a Space Invite has shouty button labels ([#5175](https://github.com/vector-im/element-ios/issues/5175)) +- RoomDataSource: Avoid reloading of data source on thread screen itself. ([#5263](https://github.com/vector-im/element-ios/issues/5263)) +- MXKAccount: Gracefully pause the session. ([#5426](https://github.com/vector-im/element-ios/issues/5426)) +- HomeViewController: Reload section if total number of rooms changed. ([#5448](https://github.com/vector-im/element-ios/issues/5448)) +- Selecting Transfer in a call should immediately put the the other person on hold until the call connects or the Transfer is cancelled. ([#5451](https://github.com/vector-im/element-ios/issues/5451)) +- Avatar view prevents to select space in space list ([#5454](https://github.com/vector-im/element-ios/issues/5454)) +- Fixes media library freezing under iOS 15.2. ([#5465](https://github.com/vector-im/element-ios/issues/5465)) +- Room Settings: Fix incorrect header title. ([#5525](https://github.com/vector-im/element-ios/issues/5525)) + +🗣 Translations + +- Localisation: Add Indonesian and Slovak languages. ([#5048](https://github.com/vector-im/element-ios/issues/5048)) + +🧱 Build + +- Fix CI builds for external contributors using forked repos. ([#5496](https://github.com/vector-im/element-ios/pull/5496), [#5491](https://github.com/vector-im/element-ios/issues/5491)) +- Use Xcode 13.2 to build the project. ([#4883](https://github.com/vector-im/element-ios/issues/4883)) + +Others + +- Add WIP to towncrier. ([#5446](https://github.com/vector-im/element-ios/pull/5446)) +- Add a simple screen SwiftUI template. ([#5349](https://github.com/vector-im/element-ios/issues/5349)) +- Added a new automation for FTUE and WTF Project boards ([#5493](https://github.com/vector-im/element-ios/issues/5493)) +- Fix the indentation in the project board automation file on FTU and WTF labels ([#5504](https://github.com/vector-im/element-ios/issues/5504)) + + ## Changes in 1.7.0 (2022-01-25) ✨ Features diff --git a/CommonKit/Common.xcconfig b/CommonKit/Common.xcconfig new file mode 100644 index 000000000..38afbcfe3 --- /dev/null +++ b/CommonKit/Common.xcconfig @@ -0,0 +1,28 @@ +// +// Copyright 2021 Vector Creations Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +#include "Config/AppIdentifiers.xcconfig" +#include "Config/AppVersion.xcconfig" + +PRODUCT_NAME = CommonKit +PRODUCT_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_IDENTIFIER).commonkit + +INFOPLIST_FILE = CommonKit/Info.plist + +SKIP_INSTALL = YES diff --git a/CommonKit/CommonKit.h b/CommonKit/CommonKit.h new file mode 100644 index 000000000..b057961e6 --- /dev/null +++ b/CommonKit/CommonKit.h @@ -0,0 +1,27 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +//! Project version number for CommonKit. +FOUNDATION_EXPORT double CommonKitVersionNumber; + +//! Project version string for CommonKit. +FOUNDATION_EXPORT const unsigned char CommonKitVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/CommonKit/Debug.xcconfig b/CommonKit/Debug.xcconfig new file mode 100644 index 000000000..11a7288a4 --- /dev/null +++ b/CommonKit/Debug.xcconfig @@ -0,0 +1,20 @@ +// +// Copyright 2021 Vector Creations Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +#include "Common.xcconfig" diff --git a/CommonKit/Info.plist b/CommonKit/Info.plist new file mode 100644 index 000000000..c0701c6d7 --- /dev/null +++ b/CommonKit/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/CommonKit/Release.xcconfig b/CommonKit/Release.xcconfig new file mode 100644 index 000000000..11a7288a4 --- /dev/null +++ b/CommonKit/Release.xcconfig @@ -0,0 +1,20 @@ +// +// Copyright 2021 Vector Creations Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +#include "Common.xcconfig" diff --git a/CommonKit/Source/Activity/Activity.swift b/CommonKit/Source/Activity/Activity.swift new file mode 100644 index 000000000..d72e87800 --- /dev/null +++ b/CommonKit/Source/Activity/Activity.swift @@ -0,0 +1,94 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import UIKit + +/// An `Activity` represents the state of a temporary visual indicator, such as activity indicator, success notification or an error message. It does not directly manage the UI, instead it delegates to a `presenter` +/// whenever the UI should be shown or hidden. +/// +/// More than one `Activity` may be requested by the system at the same time (e.g. global syncing vs local refresh), +/// and the `ActivityCenter` will ensure that only one activity is shown at a given time, putting the other in a pending queue. +/// +/// A client that requests an activity can specify a default timeout after which the activity is dismissed, or it has to be manually +/// responsible for dismissing it via `cancel` method, or by deallocating itself. +public class Activity { + enum State { + case pending + case executing + case completed + } + + private let request: ActivityRequest + private let completion: () -> Void + + private(set) var state: State + + public init(request: ActivityRequest, completion: @escaping () -> Void) { + self.request = request + self.completion = completion + + state = .pending + } + + deinit { + cancel() + } + + internal func start() { + guard state == .pending else { + return + } + + state = .executing + request.presenter.present() + + switch request.dismissal { + case .manual: + break + case .timeout(let interval): + Timer.scheduledTimer(withTimeInterval: interval, repeats: false) { [weak self] _ in + self?.complete() + } + } + } + + /// Cancel the activity, triggering any dismissal action / animation + /// + /// Note: clients can call this method directly, if they have access to the `Activity`. + /// Once cancelled, `ActivityCenter` will automatically start the next `Activity` in the queue. + func cancel() { + complete() + } + + private func complete() { + guard state != .completed else { + return + } + if state == .executing { + request.presenter.dismiss() + } + + state = .completed + completion() + } +} + +public extension Activity { + func store(in collection: inout C) where C: RangeReplaceableCollection, C.Element == Activity { + collection.append(self) + } +} diff --git a/CommonKit/Source/Activity/ActivityCenter.swift b/CommonKit/Source/Activity/ActivityCenter.swift new file mode 100644 index 000000000..9d9e0c704 --- /dev/null +++ b/CommonKit/Source/Activity/ActivityCenter.swift @@ -0,0 +1,60 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +/// A shared activity center with a single FIFO queue which will ensure only one activity is shown at a given time. +/// +/// `ActivityCenter` offers a `shared` center that can be used by any clients, but clients are also allowed +/// to create local `ActivityCenter` if the context requres multiple simultaneous activities. +public class ActivityCenter { + private class Weak { + weak var element: T? + init(_ element: T) { + self.element = element + } + } + + public static let shared = ActivityCenter() + private var queue = [Weak]() + + /// Add a new activity to the queue by providing a request. + /// + /// The queue will start the activity right away, if there are no currently running activities, + /// otherwise the activity will be put on hold. + public func add(_ request: ActivityRequest) -> Activity { + let activity = Activity(request: request) { [weak self] in + self?.startNextIfIdle() + } + + queue.append(Weak(activity)) + startNextIfIdle() + return activity + } + + private func startNextIfIdle() { + cleanup() + if let activity = queue.first?.element, activity.state == .pending { + activity.start() + } + } + + private func cleanup() { + queue.removeAll { + $0.element == nil || $0.element?.state == .completed + } + } +} diff --git a/CommonKit/Source/Activity/ActivityDismissal.swift b/CommonKit/Source/Activity/ActivityDismissal.swift new file mode 100644 index 000000000..69405c579 --- /dev/null +++ b/CommonKit/Source/Activity/ActivityDismissal.swift @@ -0,0 +1,25 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +/// Different ways in which an `Activity` can be dismissed +public enum ActivityDismissal { + /// The `Activity` will not manage the dismissal, but will expect the calling client to do so manually + case manual + /// The `Activity` will be automatically dismissed after `TimeInterval` + case timeout(TimeInterval) +} diff --git a/CommonKit/Source/Activity/ActivityPresentable.swift b/CommonKit/Source/Activity/ActivityPresentable.swift new file mode 100644 index 000000000..5bb489fcc --- /dev/null +++ b/CommonKit/Source/Activity/ActivityPresentable.swift @@ -0,0 +1,25 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +/// A presenter associated with and called by an `Activity`, and responsible for the underlying view shown on the screen. +public protocol ActivityPresentable { + /// Called when the `Activity` is started (manually or by the `ActivityCenter`) + func present() + /// Called when the `Activity` is manually cancelled or completed + func dismiss() +} diff --git a/CommonKit/Source/Activity/ActivityRequest.swift b/CommonKit/Source/Activity/ActivityRequest.swift new file mode 100644 index 000000000..f009fc211 --- /dev/null +++ b/CommonKit/Source/Activity/ActivityRequest.swift @@ -0,0 +1,28 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +/// A request used to create an underlying `Activity`, allowing clients to only specify the visual aspects of an activity. +public struct ActivityRequest { + internal let presenter: ActivityPresentable + internal let dismissal: ActivityDismissal + + public init(presenter: ActivityPresentable, dismissal: ActivityDismissal) { + self.presenter = presenter + self.dismissal = dismissal + } +} diff --git a/CommonKit/Source/Activity/Tests/ActivityCenterTests.swift b/CommonKit/Source/Activity/Tests/ActivityCenterTests.swift new file mode 100644 index 000000000..a1e375851 --- /dev/null +++ b/CommonKit/Source/Activity/Tests/ActivityCenterTests.swift @@ -0,0 +1,55 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import XCTest + +class ActivityCenterTests: XCTestCase { + var activities: [Activity]! + var center: ActivityCenter! + + override func setUp() { + activities = [] + center = ActivityCenter() + } + + func makeRequest() -> ActivityRequest { + return ActivityRequest( + presenter: ActivityPresenterSpy(), + dismissal: .manual + ) + } + + func testStartsActivityWhenAdded() { + let activity = center.add(makeRequest()) + XCTAssertEqual(activity.state, .executing) + } + + func testSecondActivityIsPending() { + center.add(makeRequest()).store(in: &activities) + let activity = center.add(makeRequest()) + XCTAssertEqual(activity.state, .pending) + } + + func testSecondActivityIsExecutingWhenFirstCompleted() { + let first = center.add(makeRequest()) + let second = center.add(makeRequest()) + + first.cancel() + + XCTAssertEqual(second.state, .executing) + } +} diff --git a/Riot/Modules/Common/Alert/AlertPresentable.swift b/CommonKit/Source/Activity/Tests/ActivityPresenterSpy.swift similarity index 53% rename from Riot/Modules/Common/Alert/AlertPresentable.swift rename to CommonKit/Source/Activity/Tests/ActivityPresenterSpy.swift index d0ee0dcd4..2a0d03249 100644 --- a/Riot/Modules/Common/Alert/AlertPresentable.swift +++ b/CommonKit/Source/Activity/Tests/ActivityPresenterSpy.swift @@ -16,21 +16,14 @@ import Foundation -/// AlertPresentable absracts an alert presenter -protocol AlertPresentable { +class ActivityPresenterSpy: ActivityPresentable { + var intel = [String]() - func showError(_ error: Error, animated: Bool, completion: (() -> Void)?) - func show(title: String?, message: String?, animated: Bool, completion: (() -> Void)?) -} - -// MARK: Default implementation -extension AlertPresentable { - - func showError(_ error: Error) { - self.showError(error, animated: true, completion: nil) + func present() { + intel.append(#function) } - func show(title: String?, message: String?) { - self.show(title: title, message: message, animated: true, completion: nil) + func dismiss() { + intel.append(#function) } } diff --git a/CommonKit/Source/Activity/Tests/ActivityTests.swift b/CommonKit/Source/Activity/Tests/ActivityTests.swift new file mode 100644 index 000000000..11cc7eec2 --- /dev/null +++ b/CommonKit/Source/Activity/Tests/ActivityTests.swift @@ -0,0 +1,127 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import XCTest + +class ActivityTests: XCTestCase { + var presenter: ActivityPresenterSpy! + + override func setUp() { + super.setUp() + presenter = ActivityPresenterSpy() + } + + func makeActivity(dismissal: ActivityDismissal = .manual, callback: @escaping () -> Void = {}) -> Activity { + let request = ActivityRequest( + presenter: presenter, + dismissal: dismissal + ) + return Activity( + request: request, + completion: callback + ) + } + + // MARK: - State + + func testNewActivityIsPending() { + let activity = makeActivity() + XCTAssertEqual(activity.state, .pending) + } + + func testStartedActivityIsExecuting() { + let activity = makeActivity() + activity.start() + XCTAssertEqual(activity.state, .executing) + } + + func testCancelledActivityIsCompleted() { + let activity = makeActivity() + activity.cancel() + XCTAssertEqual(activity.state, .completed) + } + + // MARK: - Presenter + + func testStartingActivityPresentsUI() { + let activity = makeActivity() + activity.start() + XCTAssertEqual(presenter.intel, ["present()"]) + } + + func testAllowStartingOnlyOnce() { + let activity = makeActivity() + activity.start() + presenter.intel = [] + + activity.start() + + XCTAssertEqual(presenter.intel, []) + } + + func testCancellingActivityDismissesUI() { + let activity = makeActivity() + activity.start() + presenter.intel = [] + + activity.cancel() + + XCTAssertEqual(presenter.intel, ["dismiss()"]) + } + + func testAllowCancellingOnlyOnce() { + let activity = makeActivity() + activity.start() + activity.cancel() + presenter.intel = [] + + activity.cancel() + + XCTAssertEqual(presenter.intel, []) + } + + // MARK: - Dismissal + + func testDismissAfterTimeout() { + let interval: TimeInterval = 0.01 + let activity = makeActivity(dismissal: .timeout(interval)) + + activity.start() + + let exp = expectation(description: "") + DispatchQueue.main.asyncAfter(deadline: .now() + interval) { + exp.fulfill() + } + waitForExpectations(timeout: 1) + + XCTAssertEqual(activity.state, .completed) + } + + // MARK: - Completion callback + + func testTriggersCallbackWhenCompleted() { + var didComplete = false + let activity = makeActivity { + didComplete = true + } + activity.start() + + activity.cancel() + + XCTAssertTrue(didComplete) + } +} diff --git a/CommonKit/target.yml b/CommonKit/target.yml new file mode 100644 index 000000000..fad6e8375 --- /dev/null +++ b/CommonKit/target.yml @@ -0,0 +1,40 @@ +name: CommonKit + +schemes: + CommonKit: + analyze: + config: Debug + archive: + config: Release + build: + targets: + CommonKit: + - running + - testing + - profiling + - analyzing + - archiving + profile: + config: Release + run: + config: Debug + disableMainThreadChecker: true + test: + config: Debug + disableMainThreadChecker: true + targets: + - CommonKitUnitTests + +targets: + CommonKit: + type: framework + platform: iOS + + configFiles: + Debug: Debug.xcconfig + Release: Release.xcconfig + + sources: + - path: . + excludes: + - "**/Tests/**" diff --git a/CommonKit/targetUnitTests.yml b/CommonKit/targetUnitTests.yml new file mode 100644 index 000000000..4a8f8a7b2 --- /dev/null +++ b/CommonKit/targetUnitTests.yml @@ -0,0 +1,42 @@ +name: CommonKitUnitTests + +schemes: + CommonKitUnitTests: + analyze: + config: Debug + archive: + config: Release + build: + targets: + CommonKitUnitTests: + - running + - testing + - profiling + - analyzing + - archiving + profile: + config: Release + run: + config: Debug + disableMainThreadChecker: true + test: + config: Debug + disableMainThreadChecker: true + targets: + - CommonKitUnitTests + +targets: + CommonKitUnitTests: + type: bundle.unit-test + platform: iOS + + dependencies: + - target: CommonKit + + configFiles: + Debug: Debug.xcconfig + Release: Release.xcconfig + + sources: + - path: . + diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index cc05f87f8..de6ddc959 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.7.1 -CURRENT_PROJECT_VERSION = 1.7.1 +MARKETING_VERSION = 1.8.2 +CURRENT_PROJECT_VERSION = 1.8.2 diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index 07645cff8..3348ba964 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -146,8 +146,6 @@ final class BuildSettings: NSObject { static let stunServerFallbackUrlString: String? = "stun:turn.matrix.org" // MARK: - Public rooms Directory - #warning("Unused build setting: should this be implemented in ShowDirectory?") - static let publicRoomsAllowServerChange: Bool = true // List of homeservers for the public rooms directory static let publicRoomsDirectoryServers = [ "matrix.org", @@ -212,6 +210,15 @@ final class BuildSettings: NSObject { static let allowInviteExernalUsers: Bool = true + /// Whether a screen uses legacy local activity indicators or improved app-wide indicators + static var appActivityIndicators: Bool { + #if DEBUG + return false + #else + return false + #endif + } + // MARK: - Side Menu static let enableSideMenu: Bool = true static let sideMenuShowInviteFriends: Bool = true @@ -293,7 +300,7 @@ final class BuildSettings: NSObject { static let roomScreenAllowFilesAction: Bool = true // Timeline style - static let roomScreenAllowTimelineStyleConfiguration: Bool = false + static let roomScreenAllowTimelineStyleConfiguration: Bool = true static let roomScreenTimelineDefaultStyleIdentifier: RoomTimelineStyleIdentifier = .plain static var isRoomScreenEnableMessageBubblesByDefault: Bool { return self.roomScreenTimelineDefaultStyleIdentifier == .bubble diff --git a/Config/Project-Warnings.xcconfig b/Config/Project-Warnings.xcconfig index 8c9512128..350f6dd29 100644 --- a/Config/Project-Warnings.xcconfig +++ b/Config/Project-Warnings.xcconfig @@ -46,3 +46,7 @@ GCC_WARN_UNDECLARED_SELECTOR = YES GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE GCC_WARN_UNUSED_FUNCTION = YES GCC_WARN_UNUSED_VARIABLE = YES + +WARNING_CFLAGS = $(inherited) -Wno-nullability-completeness; +OTHER_SWIFT_FLAGS = $(inherited) -Xcc -Wno-nullability-completeness + diff --git a/Podfile b/Podfile index 286135afb..b37f3c61b 100644 --- a/Podfile +++ b/Podfile @@ -13,7 +13,7 @@ use_frameworks! # - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI # # Warning: our internal tooling depends on the name of this variable name, so be sure not to change it -$matrixSDKVersion = '= 0.21.0' +$matrixSDKVersion = '= 0.22.1' # $matrixSDKVersion = :local # $matrixSDKVersion = { :branch => 'develop'} # $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } } @@ -49,7 +49,6 @@ end ######################################## def import_MatrixKit_pods - pod 'HPGrowingTextView', '~> 1.1' pod 'libPhoneNumber-iOS', '~> 0.9.13' pod 'DTCoreText', '~> 1.6.25' #pod 'DTCoreText/Extension', '~> 1.6.25' @@ -98,7 +97,7 @@ abstract_target 'RiotPods' do pod 'DSWaveformImage', '~> 6.1.1' pod 'ffmpeg-kit-ios-audio', '4.5.1' - pod 'FLEX', '~> 4.5.0', :configurations => ['Debug'] + pod 'FLEX', '~> 4.5.0', :configurations => ['Debug'], :inhibit_warnings => true target 'RiotTests' do inherit! :search_paths @@ -149,6 +148,10 @@ post_install do |installer| # Stop Xcode 12 complaining about old IPHONEOS_DEPLOYMENT_TARGET from pods config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' + + # Disable nullability checks + config.build_settings['WARNING_CFLAGS'] ||= ['$(inherited)','-Wno-nullability-completeness'] + config.build_settings['OTHER_SWIFT_FLAGS'] ||= ['$(inherited)', '-Xcc', '-Wno-nullability-completeness'] end end end \ No newline at end of file diff --git a/Podfile.lock b/Podfile.lock index 878065ce0..8636a4170 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -45,7 +45,6 @@ PODS: - GBDeviceInfo/Core (= 6.6.0) - GBDeviceInfo/Core (6.6.0) - GZIP (1.3.0) - - HPGrowingTextView (1.1) - Introspect (0.1.4) - JitsiMeetSDK (3.10.2) - KeychainAccess (4.2.2) @@ -57,16 +56,16 @@ PODS: - LoggerAPI (1.9.200): - Logging (~> 1.1) - Logging (1.4.0) - - MatrixSDK (0.21.0): - - MatrixSDK/Core (= 0.21.0) - - MatrixSDK/Core (0.21.0): + - MatrixSDK (0.22.1): + - MatrixSDK/Core (= 0.22.1) + - MatrixSDK/Core (0.22.1): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) - OLMKit (~> 3.2.5) - Realm (= 10.16.0) - SwiftyBeaver (= 1.9.5) - - MatrixSDK/JingleCallStack (0.21.0): + - MatrixSDK/JingleCallStack (0.22.1): - JitsiMeetSDK (= 3.10.2) - MatrixSDK/Core - OLMKit (3.2.5): @@ -112,13 +111,12 @@ DEPENDENCIES: - FLEX (~> 4.5.0) - FlowCommoniOS (~> 1.12.0) - GBDeviceInfo (~> 6.6.0) - - HPGrowingTextView (~> 1.1) - Introspect (~> 0.1) - KeychainAccess (~> 4.2.2) - KTCenterFlowLayout (~> 1.3.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.21.0) - - MatrixSDK/JingleCallStack (= 0.21.0) + - MatrixSDK (= 0.22.1) + - MatrixSDK/JingleCallStack (= 0.22.1) - OLMKit - PostHog (~> 1.4.4) - ReadMoreTextView (~> 3.0.1) @@ -149,7 +147,6 @@ SPEC REPOS: - FlowCommoniOS - GBDeviceInfo - GZIP - - HPGrowingTextView - Introspect - JitsiMeetSDK - KeychainAccess @@ -183,7 +180,7 @@ EXTERNAL SOURCES: CHECKOUT OPTIONS: AnalyticsEvents: - :commit: 8058dc6ec07ce0acfe5fdb19eb7e309b0c13845c + :commit: 53844e3f6f9fefa88384a996b2bf5e60bb301b94 :git: https://github.com/matrix-org/matrix-analytics-events.git SPEC CHECKSUMS: @@ -202,7 +199,6 @@ SPEC CHECKSUMS: FlowCommoniOS: ca92071ab526dc89905495a37844fd7e78d1a7f2 GBDeviceInfo: ed0db16230d2fa280e1cbb39a5a7f60f6946aaec GZIP: 416858efbe66b41b206895ac6dfd5493200d95b3 - HPGrowingTextView: 88a716d97fb853bcb08a4a08e4727da17efc9b19 Introspect: b62c4dd2063072327c21d618ef2bedc3c87bc366 JitsiMeetSDK: 2f118fa770f23e518f3560fc224fae3ac7062223 KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51 @@ -212,7 +208,7 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: cd98e3e4287b8a4f3a5bb47642beae80e8f62534 + MatrixSDK: 12c1a56e037f629e493cbcd615fd13cfc58cee3a OLMKit: 9fb4799c4a044dd2c06bda31ec31a12191ad30b5 PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d @@ -229,6 +225,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 01b4ac5047b44a6de6738134fa67cdf14a7c3b7a +PODFILE CHECKSUM: 03d59acfc44f69c0727a98aff6c5cbc2470844ef COCOAPODS: 1.11.2 diff --git a/Riot/Assets/Base.lproj/LaunchScreen.storyboard b/Riot/Assets/Base.lproj/LaunchScreen.storyboard index 47f7c6d30..07c996ecf 100644 --- a/Riot/Assets/Base.lproj/LaunchScreen.storyboard +++ b/Riot/Assets/Base.lproj/LaunchScreen.storyboard @@ -1,9 +1,10 @@ - + - + + @@ -21,14 +22,14 @@ - + - + @@ -42,5 +43,8 @@ + + + diff --git a/Riot/Assets/Base.lproj/Main.storyboard b/Riot/Assets/Base.lproj/Main.storyboard index 4708d7dbc..885be7db7 100644 --- a/Riot/Assets/Base.lproj/Main.storyboard +++ b/Riot/Assets/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -46,24 +46,6 @@ - - - - - - - - - - - - - - - - - - @@ -116,14 +98,6 @@ - - - - - - - - @@ -501,24 +475,6 @@ - - - - - - - - - - - - - - - - - - diff --git a/Riot/Assets/Images.xcassets/Common/filter_off.imageset/Contents.json b/Riot/Assets/Images.xcassets/Common/filter_off.imageset/Contents.json new file mode 100644 index 000000000..0ada96c02 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Common/filter_off.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "filter_off.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "filter_off@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "filter_off@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off.png b/Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off.png new file mode 100644 index 000000000..7f42aaf6d Binary files /dev/null and b/Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off.png differ diff --git a/Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off@2x.png b/Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off@2x.png new file mode 100644 index 000000000..50b077fd2 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off@3x.png b/Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off@3x.png new file mode 100644 index 000000000..f03bf3c7b Binary files /dev/null and b/Riot/Assets/Images.xcassets/Common/filter_off.imageset/filter_off@3x.png differ diff --git a/Riot/Assets/Images.xcassets/Search/search_bg.imageset/Contents.json b/Riot/Assets/Images.xcassets/Common/filter_on.imageset/Contents.json similarity index 58% rename from Riot/Assets/Images.xcassets/Search/search_bg.imageset/Contents.json rename to Riot/Assets/Images.xcassets/Common/filter_on.imageset/Contents.json index 568f8cb3f..7d1ae8514 100644 --- a/Riot/Assets/Images.xcassets/Search/search_bg.imageset/Contents.json +++ b/Riot/Assets/Images.xcassets/Common/filter_on.imageset/Contents.json @@ -1,23 +1,23 @@ { "images" : [ { + "filename" : "filter_on.png", "idiom" : "universal", - "filename" : "search_bg.png", "scale" : "1x" }, { + "filename" : "filter_on@2x.png", "idiom" : "universal", - "filename" : "search_bg@2x.png", "scale" : "2x" }, { + "filename" : "filter_on@3x.png", "idiom" : "universal", - "filename" : "search_bg@3x.png", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on.png b/Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on.png new file mode 100644 index 000000000..7710fa90e Binary files /dev/null and b/Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on.png differ diff --git a/Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on@2x.png b/Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on@2x.png new file mode 100644 index 000000000..b9cff9c1b Binary files /dev/null and b/Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on@3x.png b/Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on@3x.png new file mode 100644 index 000000000..5fec0029d Binary files /dev/null and b/Riot/Assets/Images.xcassets/Common/filter_on.imageset/filter_on@3x.png differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Contents.json b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Contents.json index abf2a35a2..4d5b7ef83 100644 --- a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Contents.json +++ b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Contents.json @@ -1,17 +1,50 @@ { "images" : [ { - "filename" : "Group 3153.png", + "filename" : "capture_avatar.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "Group 3153@2x.png", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "capture_avatar_dark.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "capture_avatar@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "Group 3153@3x.png", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "capture_avatar_dark@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "capture_avatar@3x.png", + "idiom" : "universal", + "scale" : "3x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "capture_avatar_dark@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Group 3153.png b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Group 3153.png deleted file mode 100644 index 621edca32..000000000 Binary files a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Group 3153.png and /dev/null differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Group 3153@2x.png b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Group 3153@2x.png deleted file mode 100644 index 8ea43080b..000000000 Binary files a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Group 3153@2x.png and /dev/null differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Group 3153@3x.png b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Group 3153@3x.png deleted file mode 100644 index c43b02a01..000000000 Binary files a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/Group 3153@3x.png and /dev/null differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar.png b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar.png new file mode 100644 index 000000000..ee020a419 Binary files /dev/null and b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar.png differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar@2x.png b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar@2x.png new file mode 100644 index 000000000..db29b82de Binary files /dev/null and b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar@2x.png differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar@3x.png b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar@3x.png new file mode 100644 index 000000000..3ed02ca09 Binary files /dev/null and b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar@3x.png differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar_dark.png b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar_dark.png new file mode 100644 index 000000000..5036ec95f Binary files /dev/null and b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar_dark.png differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar_dark@2x.png b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar_dark@2x.png new file mode 100644 index 000000000..3dd16d8a8 Binary files /dev/null and b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar_dark@2x.png differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar_dark@3x.png b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar_dark@3x.png new file mode 100644 index 000000000..39bed95c0 Binary files /dev/null and b/Riot/Assets/Images.xcassets/CreateRoom/capture_avatar.imageset/capture_avatar_dark@3x.png differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/Contents.json b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/Contents.json new file mode 100644 index 000000000..a52435f30 --- /dev/null +++ b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/Contents.json @@ -0,0 +1,56 @@ +{ + "images" : [ + { + "filename" : "delete_avatar.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "delete_avatar_dark.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "delete_avatar@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "delete_avatar_dark@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "delete_avatar@3x.png", + "idiom" : "universal", + "scale" : "3x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "delete_avatar_dark@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar.png b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar.png new file mode 100644 index 000000000..9a9633eb8 Binary files /dev/null and b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar.png differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar@2x.png b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar@2x.png new file mode 100644 index 000000000..2d2aa1c8f Binary files /dev/null and b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar@2x.png differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar@3x.png b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar@3x.png new file mode 100644 index 000000000..e7c0e930c Binary files /dev/null and b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar@3x.png differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar_dark.png b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar_dark.png new file mode 100644 index 000000000..3326e8487 Binary files /dev/null and b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar_dark.png differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar_dark@2x.png b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar_dark@2x.png new file mode 100644 index 000000000..119522a87 Binary files /dev/null and b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar_dark@2x.png differ diff --git a/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar_dark@3x.png b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar_dark@3x.png new file mode 100644 index 000000000..2f9258882 Binary files /dev/null and b/Riot/Assets/Images.xcassets/CreateRoom/delete_avatar.imageset/delete_avatar_dark@3x.png differ diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_community.imageset/Contents.json b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_community.imageset/Contents.json new file mode 100644 index 000000000..9f6e8de0a --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_community.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "onboarding_use_case_community.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_community.imageset/onboarding_use_case_community.svg b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_community.imageset/onboarding_use_case_community.svg new file mode 100644 index 000000000..6b58a7b56 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_community.imageset/onboarding_use_case_community.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_community_dark.imageset/Contents.json b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_community_dark.imageset/Contents.json new file mode 100644 index 000000000..e34cfce4e --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_community_dark.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "onboarding_use_case_community_dark.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_community_dark.imageset/onboarding_use_case_community_dark.svg b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_community_dark.imageset/onboarding_use_case_community_dark.svg new file mode 100644 index 000000000..1fb2f8af1 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_community_dark.imageset/onboarding_use_case_community_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_icon.imageset/Contents.json b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_icon.imageset/Contents.json new file mode 100644 index 000000000..f4e9e56ac --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_icon.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "onboarding_use_case_icon.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_icon.imageset/onboarding_use_case_icon.svg b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_icon.imageset/onboarding_use_case_icon.svg new file mode 100644 index 000000000..2366becdb --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_icon.imageset/onboarding_use_case_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_personal.imageset/Contents.json b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_personal.imageset/Contents.json new file mode 100644 index 000000000..1073b4087 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_personal.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "onboarding_use_case_personal.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_personal.imageset/onboarding_use_case_personal.svg b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_personal.imageset/onboarding_use_case_personal.svg new file mode 100644 index 000000000..efd561c9a --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_personal.imageset/onboarding_use_case_personal.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_personal_dark.imageset/Contents.json b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_personal_dark.imageset/Contents.json new file mode 100644 index 000000000..081fb3fde --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_personal_dark.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "onboarding_use_case_personal_dark.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_personal_dark.imageset/onboarding_use_case_personal_dark.svg b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_personal_dark.imageset/onboarding_use_case_personal_dark.svg new file mode 100644 index 000000000..b5c728adc --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_personal_dark.imageset/onboarding_use_case_personal_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_work.imageset/Contents.json b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_work.imageset/Contents.json new file mode 100644 index 000000000..40d6dcbdf --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_work.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "onboarding_use_case_work.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_work.imageset/onboarding_use_case_work.svg b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_work.imageset/onboarding_use_case_work.svg new file mode 100644 index 000000000..61cf7bd86 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_work.imageset/onboarding_use_case_work.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_work_dark.imageset/Contents.json b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_work_dark.imageset/Contents.json new file mode 100644 index 000000000..da38b9aad --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_work_dark.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "onboarding_use_case_work_dark.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_work_dark.imageset/onboarding_use_case_work_dark.svg b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_work_dark.imageset/onboarding_use_case_work_dark.svg new file mode 100644 index 000000000..0f6ee387a --- /dev/null +++ b/Riot/Assets/Images.xcassets/Onboarding/onboarding_use_case_work_dark.imageset/onboarding_use_case_work_dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Riot/Assets/Images.xcassets/Search/Contents.json b/Riot/Assets/Images.xcassets/Search/Contents.json index da4a164c9..73c00596a 100644 --- a/Riot/Assets/Images.xcassets/Search/Contents.json +++ b/Riot/Assets/Images.xcassets/Search/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Riot/Assets/Images.xcassets/Search/search_bg.imageset/search_bg.png b/Riot/Assets/Images.xcassets/Search/search_bg.imageset/search_bg.png deleted file mode 100644 index b78748b04..000000000 Binary files a/Riot/Assets/Images.xcassets/Search/search_bg.imageset/search_bg.png and /dev/null differ diff --git a/Riot/Assets/Images.xcassets/Search/search_bg.imageset/search_bg@2x.png b/Riot/Assets/Images.xcassets/Search/search_bg.imageset/search_bg@2x.png deleted file mode 100644 index 284358c5e..000000000 Binary files a/Riot/Assets/Images.xcassets/Search/search_bg.imageset/search_bg@2x.png and /dev/null differ diff --git a/Riot/Assets/Images.xcassets/Search/search_bg.imageset/search_bg@3x.png b/Riot/Assets/Images.xcassets/Search/search_bg.imageset/search_bg@3x.png deleted file mode 100644 index 4525d4f5a..000000000 Binary files a/Riot/Assets/Images.xcassets/Search/search_bg.imageset/search_bg@3x.png and /dev/null differ diff --git a/Riot/Assets/apple_emojis_data.json b/Riot/Assets/apple_emojis_data.json index 5af4e34d0..1b30b33c6 100644 --- a/Riot/Assets/apple_emojis_data.json +++ b/Riot/Assets/apple_emojis_data.json @@ -1 +1 @@ -{"compressed":true,"categories":[{"id":"people","name":"Smileys & People","emojis":["grinning","grin","joy","rolling_on_the_floor_laughing","smiley","smile","sweat_smile","laughing","wink","blush","yum","sunglasses","heart_eyes","kissing_heart","kissing","kissing_smiling_eyes","kissing_closed_eyes","relaxed","slightly_smiling_face","hugging_face","star-struck","thinking_face","face_with_raised_eyebrow","neutral_face","expressionless","no_mouth","face_with_rolling_eyes","smirk","persevere","disappointed_relieved","open_mouth","zipper_mouth_face","hushed","sleepy","tired_face","sleeping","relieved","stuck_out_tongue","stuck_out_tongue_winking_eye","stuck_out_tongue_closed_eyes","drooling_face","unamused","sweat","pensive","confused","upside_down_face","money_mouth_face","astonished","white_frowning_face","slightly_frowning_face","confounded","disappointed","worried","triumph","cry","sob","frowning","anguished","fearful","weary","exploding_head","grimacing","cold_sweat","scream","flushed","zany_face","dizzy_face","rage","angry","face_with_symbols_on_mouth","mask","face_with_thermometer","face_with_head_bandage","nauseated_face","face_vomiting","sneezing_face","innocent","face_with_cowboy_hat","clown_face","lying_face","shushing_face","face_with_hand_over_mouth","face_with_monocle","nerd_face","smiling_imp","imp","japanese_ogre","japanese_goblin","skull","skull_and_crossbones","ghost","alien","space_invader","robot_face","hankey","smiley_cat","smile_cat","joy_cat","heart_eyes_cat","smirk_cat","kissing_cat","scream_cat","crying_cat_face","pouting_cat","see_no_evil","hear_no_evil","speak_no_evil","baby","child","boy","girl","adult","man","woman","older_adult","older_man","older_woman","male-doctor","female-doctor","male-student","female-student","male-teacher","female-teacher","male-judge","female-judge","male-farmer","female-farmer","male-cook","female-cook","male-mechanic","female-mechanic","male-factory-worker","female-factory-worker","male-office-worker","female-office-worker","male-scientist","female-scientist","male-technologist","female-technologist","male-singer","female-singer","male-artist","female-artist","male-pilot","female-pilot","male-astronaut","female-astronaut","male-firefighter","female-firefighter","cop","male-police-officer","female-police-officer","sleuth_or_spy","male-detective","female-detective","guardsman","male-guard","female-guard","construction_worker","male-construction-worker","female-construction-worker","prince","princess","man_with_turban","man-wearing-turban","woman-wearing-turban","man_with_gua_pi_mao","person_with_headscarf","bearded_person","person_with_blond_hair","blond-haired-man","blond-haired-woman","man_in_tuxedo","bride_with_veil","pregnant_woman","breast-feeding","angel","santa","mrs_claus","mage","female_mage","male_mage","fairy","female_fairy","male_fairy","vampire","female_vampire","male_vampire","merperson","mermaid","merman","elf","female_elf","male_elf","genie","female_genie","male_genie","zombie","female_zombie","male_zombie","person_frowning","man-frowning","woman-frowning","person_with_pouting_face","man-pouting","woman-pouting","no_good","man-gesturing-no","woman-gesturing-no","ok_woman","man-gesturing-ok","woman-gesturing-ok","information_desk_person","man-tipping-hand","woman-tipping-hand","raising_hand","man-raising-hand","woman-raising-hand","bow","man-bowing","woman-bowing","face_palm","man-facepalming","woman-facepalming","shrug","man-shrugging","woman-shrugging","massage","man-getting-massage","woman-getting-massage","haircut","man-getting-haircut","woman-getting-haircut","walking","man-walking","woman-walking","runner","man-running","woman-running","dancer","man_dancing","dancers","man-with-bunny-ears-partying","woman-with-bunny-ears-partying","person_in_steamy_room","woman_in_steamy_room","man_in_steamy_room","person_climbing","woman_climbing","man_climbing","person_in_lotus_position","woman_in_lotus_position","man_in_lotus_position","bath","sleeping_accommodation","man_in_business_suit_levitating","speaking_head_in_silhouette","bust_in_silhouette","busts_in_silhouette","fencer","horse_racing","skier","snowboarder","golfer","man-golfing","woman-golfing","surfer","man-surfing","woman-surfing","rowboat","man-rowing-boat","woman-rowing-boat","swimmer","man-swimming","woman-swimming","person_with_ball","man-bouncing-ball","woman-bouncing-ball","weight_lifter","man-lifting-weights","woman-lifting-weights","bicyclist","man-biking","woman-biking","mountain_bicyclist","man-mountain-biking","woman-mountain-biking","racing_car","racing_motorcycle","person_doing_cartwheel","man-cartwheeling","woman-cartwheeling","wrestlers","man-wrestling","woman-wrestling","water_polo","man-playing-water-polo","woman-playing-water-polo","handball","man-playing-handball","woman-playing-handball","juggling","man-juggling","woman-juggling","couple","two_men_holding_hands","two_women_holding_hands","couplekiss","woman-kiss-man","man-kiss-man","woman-kiss-woman","couple_with_heart","woman-heart-man","man-heart-man","woman-heart-woman","family","man-woman-boy","man-woman-girl","man-woman-girl-boy","man-woman-boy-boy","man-woman-girl-girl","man-man-boy","man-man-girl","man-man-girl-boy","man-man-boy-boy","man-man-girl-girl","woman-woman-boy","woman-woman-girl","woman-woman-girl-boy","woman-woman-boy-boy","woman-woman-girl-girl","man-boy","man-boy-boy","man-girl","man-girl-boy","man-girl-girl","woman-boy","woman-boy-boy","woman-girl","woman-girl-boy","woman-girl-girl","selfie","muscle","point_left","point_right","point_up","point_up_2","middle_finger","point_down","v","crossed_fingers","spock-hand","the_horns","call_me_hand","raised_hand_with_fingers_splayed","hand","ok_hand","+1","-1","fist","facepunch","left-facing_fist","right-facing_fist","raised_back_of_hand","wave","i_love_you_hand_sign","writing_hand","clap","open_hands","raised_hands","palms_up_together","pray","handshake","nail_care","ear","nose","footprints","eyes","eye","eye-in-speech-bubble","brain","tongue","lips","kiss","cupid","heart","heartbeat","broken_heart","two_hearts","sparkling_heart","heartpulse","blue_heart","green_heart","yellow_heart","orange_heart","purple_heart","black_heart","gift_heart","revolving_hearts","heart_decoration","heavy_heart_exclamation_mark_ornament","love_letter","zzz","anger","bomb","boom","sweat_drops","dash","dizzy","speech_balloon","left_speech_bubble","right_anger_bubble","thought_balloon","hole","eyeglasses","dark_sunglasses","necktie","shirt","jeans","scarf","gloves","coat","socks","dress","kimono","bikini","womans_clothes","purse","handbag","pouch","shopping_bags","school_satchel","mans_shoe","athletic_shoe","high_heel","sandal","boot","crown","womans_hat","tophat","mortar_board","billed_cap","helmet_with_white_cross","prayer_beads","lipstick","ring","gem"]},{"id":"nature","name":"Animals & Nature","emojis":["monkey_face","monkey","gorilla","dog","dog2","poodle","wolf","fox_face","cat","cat2","lion_face","tiger","tiger2","leopard","horse","racehorse","unicorn_face","zebra_face","deer","cow","ox","water_buffalo","cow2","pig","pig2","boar","pig_nose","ram","sheep","goat","dromedary_camel","camel","giraffe_face","elephant","rhinoceros","mouse","mouse2","rat","hamster","rabbit","rabbit2","chipmunk","hedgehog","bat","bear","koala","panda_face","feet","turkey","chicken","rooster","hatching_chick","baby_chick","hatched_chick","bird","penguin","dove_of_peace","eagle","duck","owl","frog","crocodile","turtle","lizard","snake","dragon_face","dragon","sauropod","t-rex","whale","whale2","dolphin","fish","tropical_fish","blowfish","shark","octopus","shell","crab","shrimp","squid","snail","butterfly","bug","ant","bee","beetle","cricket","spider","spider_web","scorpion","bouquet","cherry_blossom","white_flower","rosette","rose","wilted_flower","hibiscus","sunflower","blossom","tulip","seedling","evergreen_tree","deciduous_tree","palm_tree","cactus","ear_of_rice","herb","shamrock","four_leaf_clover","maple_leaf","fallen_leaf","leaves"]},{"id":"foods","name":"Food & Drink","emojis":["grapes","melon","watermelon","tangerine","lemon","banana","pineapple","apple","green_apple","pear","peach","cherries","strawberry","kiwifruit","tomato","coconut","avocado","eggplant","potato","carrot","corn","hot_pepper","cucumber","broccoli","mushroom","peanuts","chestnut","bread","croissant","baguette_bread","pretzel","pancakes","cheese_wedge","meat_on_bone","poultry_leg","cut_of_meat","bacon","hamburger","fries","pizza","hotdog","sandwich","taco","burrito","stuffed_flatbread","egg","fried_egg","shallow_pan_of_food","stew","bowl_with_spoon","green_salad","popcorn","canned_food","bento","rice_cracker","rice_ball","rice","curry","ramen","spaghetti","sweet_potato","oden","sushi","fried_shrimp","fish_cake","dango","dumpling","fortune_cookie","takeout_box","icecream","shaved_ice","ice_cream","doughnut","cookie","birthday","cake","pie","chocolate_bar","candy","lollipop","custard","honey_pot","baby_bottle","glass_of_milk","coffee","tea","sake","champagne","wine_glass","cocktail","tropical_drink","beer","beers","clinking_glasses","tumbler_glass","cup_with_straw","chopsticks","knife_fork_plate","fork_and_knife","spoon","hocho","amphora"]},{"id":"activity","name":"Activities","emojis":["jack_o_lantern","christmas_tree","fireworks","sparkler","sparkles","balloon","tada","confetti_ball","tanabata_tree","bamboo","dolls","flags","wind_chime","rice_scene","ribbon","gift","reminder_ribbon","admission_tickets","ticket","medal","trophy","sports_medal","first_place_medal","second_place_medal","third_place_medal","soccer","baseball","basketball","volleyball","football","rugby_football","tennis","8ball","bowling","cricket_bat_and_ball","field_hockey_stick_and_ball","ice_hockey_stick_and_puck","table_tennis_paddle_and_ball","badminton_racquet_and_shuttlecock","boxing_glove","martial_arts_uniform","goal_net","dart","golf","ice_skate","fishing_pole_and_fish","running_shirt_with_sash","ski","sled","curling_stone","video_game","joystick","game_die","spades","hearts","diamonds","clubs","black_joker","mahjong","flower_playing_cards"]},{"id":"places","name":"Travel & Places","emojis":["earth_africa","earth_americas","earth_asia","globe_with_meridians","world_map","japan","snow_capped_mountain","mountain","volcano","mount_fuji","camping","beach_with_umbrella","desert","desert_island","national_park","stadium","classical_building","building_construction","house_buildings","cityscape","derelict_house_building","house","house_with_garden","office","post_office","european_post_office","hospital","bank","hotel","love_hotel","convenience_store","school","department_store","factory","japanese_castle","european_castle","wedding","tokyo_tower","statue_of_liberty","church","mosque","synagogue","shinto_shrine","kaaba","fountain","tent","foggy","night_with_stars","sunrise_over_mountains","sunrise","city_sunset","city_sunrise","bridge_at_night","hotsprings","milky_way","carousel_horse","ferris_wheel","roller_coaster","barber","circus_tent","performing_arts","frame_with_picture","art","slot_machine","steam_locomotive","railway_car","bullettrain_side","bullettrain_front","train2","metro","light_rail","station","tram","monorail","mountain_railway","train","bus","oncoming_bus","trolleybus","minibus","ambulance","fire_engine","police_car","oncoming_police_car","taxi","oncoming_taxi","car","oncoming_automobile","blue_car","truck","articulated_lorry","tractor","bike","scooter","motor_scooter","busstop","motorway","railway_track","fuelpump","rotating_light","traffic_light","vertical_traffic_light","construction","octagonal_sign","anchor","boat","canoe","speedboat","passenger_ship","ferry","motor_boat","ship","airplane","small_airplane","airplane_departure","airplane_arriving","seat","helicopter","suspension_railway","mountain_cableway","aerial_tramway","satellite","rocket","flying_saucer","bellhop_bell","door","bed","couch_and_lamp","toilet","shower","bathtub","hourglass","hourglass_flowing_sand","watch","alarm_clock","stopwatch","timer_clock","mantelpiece_clock","clock12","clock1230","clock1","clock130","clock2","clock230","clock3","clock330","clock4","clock430","clock5","clock530","clock6","clock630","clock7","clock730","clock8","clock830","clock9","clock930","clock10","clock1030","clock11","clock1130","new_moon","waxing_crescent_moon","first_quarter_moon","moon","full_moon","waning_gibbous_moon","last_quarter_moon","waning_crescent_moon","crescent_moon","new_moon_with_face","first_quarter_moon_with_face","last_quarter_moon_with_face","thermometer","sunny","full_moon_with_face","sun_with_face","star","star2","stars","cloud","partly_sunny","thunder_cloud_and_rain","mostly_sunny","barely_sunny","partly_sunny_rain","rain_cloud","snow_cloud","lightning","tornado","fog","wind_blowing_face","cyclone","rainbow","closed_umbrella","umbrella","umbrella_with_rain_drops","umbrella_on_ground","zap","snowflake","snowman","snowman_without_snow","comet","fire","droplet","ocean"]},{"id":"objects","name":"Objects","emojis":["mute","speaker","sound","loud_sound","loudspeaker","mega","postal_horn","bell","no_bell","musical_score","musical_note","notes","studio_microphone","level_slider","control_knobs","microphone","headphones","radio","saxophone","guitar","musical_keyboard","trumpet","violin","drum_with_drumsticks","iphone","calling","phone","telephone_receiver","pager","fax","battery","electric_plug","computer","desktop_computer","printer","keyboard","three_button_mouse","trackball","minidisc","floppy_disk","cd","dvd","movie_camera","film_frames","film_projector","clapper","tv","camera","camera_with_flash","video_camera","vhs","mag","mag_right","microscope","telescope","satellite_antenna","candle","bulb","flashlight","izakaya_lantern","notebook_with_decorative_cover","closed_book","book","green_book","blue_book","orange_book","books","notebook","ledger","page_with_curl","scroll","page_facing_up","newspaper","rolled_up_newspaper","bookmark_tabs","bookmark","label","moneybag","yen","dollar","euro","pound","money_with_wings","credit_card","chart","currency_exchange","heavy_dollar_sign","email","e-mail","incoming_envelope","envelope_with_arrow","outbox_tray","inbox_tray","package","mailbox","mailbox_closed","mailbox_with_mail","mailbox_with_no_mail","postbox","ballot_box_with_ballot","pencil2","black_nib","lower_left_fountain_pen","lower_left_ballpoint_pen","lower_left_paintbrush","lower_left_crayon","memo","briefcase","file_folder","open_file_folder","card_index_dividers","date","calendar","spiral_note_pad","spiral_calendar_pad","card_index","chart_with_upwards_trend","chart_with_downwards_trend","bar_chart","clipboard","pushpin","round_pushpin","paperclip","linked_paperclips","straight_ruler","triangular_ruler","scissors","card_file_box","file_cabinet","wastebasket","lock","unlock","lock_with_ink_pen","closed_lock_with_key","key","old_key","hammer","pick","hammer_and_pick","hammer_and_wrench","dagger_knife","crossed_swords","gun","bow_and_arrow","shield","wrench","nut_and_bolt","gear","compression","alembic","scales","link","chains","syringe","pill","smoking","coffin","funeral_urn","moyai","oil_drum","crystal_ball","shopping_trolley"]},{"id":"symbols","name":"Symbols","emojis":["atm","put_litter_in_its_place","potable_water","wheelchair","mens","womens","restroom","baby_symbol","wc","passport_control","customs","baggage_claim","left_luggage","warning","children_crossing","no_entry","no_entry_sign","no_bicycles","no_smoking","do_not_litter","non-potable_water","no_pedestrians","no_mobile_phones","underage","radioactive_sign","biohazard_sign","arrow_up","arrow_upper_right","arrow_right","arrow_lower_right","arrow_down","arrow_lower_left","arrow_left","arrow_upper_left","arrow_up_down","left_right_arrow","leftwards_arrow_with_hook","arrow_right_hook","arrow_heading_up","arrow_heading_down","arrows_clockwise","arrows_counterclockwise","back","end","on","soon","top","place_of_worship","atom_symbol","om_symbol","star_of_david","wheel_of_dharma","yin_yang","latin_cross","orthodox_cross","star_and_crescent","peace_symbol","menorah_with_nine_branches","six_pointed_star","aries","taurus","gemini","cancer","leo","virgo","libra","scorpius","sagittarius","capricorn","aquarius","pisces","ophiuchus","twisted_rightwards_arrows","repeat","repeat_one","arrow_forward","fast_forward","black_right_pointing_double_triangle_with_vertical_bar","black_right_pointing_triangle_with_double_vertical_bar","arrow_backward","rewind","black_left_pointing_double_triangle_with_vertical_bar","arrow_up_small","arrow_double_up","arrow_down_small","arrow_double_down","double_vertical_bar","black_square_for_stop","black_circle_for_record","eject","cinema","low_brightness","high_brightness","signal_strength","vibration_mode","mobile_phone_off","recycle","fleur_de_lis","trident","name_badge","beginner","o","white_check_mark","ballot_box_with_check","heavy_check_mark","heavy_multiplication_x","x","negative_squared_cross_mark","heavy_plus_sign","heavy_minus_sign","heavy_division_sign","curly_loop","loop","part_alternation_mark","eight_spoked_asterisk","eight_pointed_black_star","sparkle","bangbang","interrobang","question","grey_question","grey_exclamation","exclamation","wavy_dash","copyright","registered","tm","hash","keycap_star","zero","one","two","three","four","five","six","seven","eight","nine","keycap_ten","100","capital_abcd","abcd","1234","symbols","abc","a","ab","b","cl","cool","free","information_source","id","m","new","ng","o2","ok","parking","sos","up","vs","koko","sa","u6708","u6709","u6307","ideograph_advantage","u5272","u7121","u7981","accept","u7533","u5408","u7a7a","congratulations","secret","u55b6","u6e80","black_small_square","white_small_square","white_medium_square","black_medium_square","white_medium_small_square","black_medium_small_square","black_large_square","white_large_square","large_orange_diamond","large_blue_diamond","small_orange_diamond","small_blue_diamond","small_red_triangle","small_red_triangle_down","diamond_shape_with_a_dot_inside","radio_button","black_square_button","white_square_button","white_circle","black_circle","red_circle","large_blue_circle"]},{"id":"flags","name":"Flags","emojis":["checkered_flag","cn","crossed_flags","de","es","flag-ac","flag-ad","flag-ae","flag-af","flag-ag","flag-ai","flag-al","flag-am","flag-ao","flag-aq","flag-ar","flag-as","flag-at","flag-au","flag-aw","flag-ax","flag-az","flag-ba","flag-bb","flag-bd","flag-be","flag-bf","flag-bg","flag-bh","flag-bi","flag-bj","flag-bl","flag-bm","flag-bn","flag-bo","flag-bq","flag-br","flag-bs","flag-bt","flag-bv","flag-bw","flag-by","flag-bz","flag-ca","flag-cc","flag-cd","flag-cf","flag-cg","flag-ch","flag-ci","flag-ck","flag-cl","flag-cm","flag-co","flag-cp","flag-cr","flag-cu","flag-cv","flag-cw","flag-cx","flag-cy","flag-cz","flag-dg","flag-dj","flag-dk","flag-dm","flag-do","flag-dz","flag-ea","flag-ec","flag-ee","flag-eg","flag-eh","flag-england","flag-er","flag-et","flag-eu","flag-fi","flag-fj","flag-fk","flag-fm","flag-fo","flag-ga","flag-gd","flag-ge","flag-gf","flag-gg","flag-gh","flag-gi","flag-gl","flag-gm","flag-gn","flag-gp","flag-gq","flag-gr","flag-gs","flag-gt","flag-gu","flag-gw","flag-gy","flag-hk","flag-hm","flag-hn","flag-hr","flag-ht","flag-hu","flag-ic","flag-id","flag-ie","flag-il","flag-im","flag-in","flag-io","flag-iq","flag-ir","flag-is","flag-je","flag-jm","flag-jo","flag-ke","flag-kg","flag-kh","flag-ki","flag-km","flag-kn","flag-kp","flag-kw","flag-ky","flag-kz","flag-la","flag-lb","flag-lc","flag-li","flag-lk","flag-lr","flag-ls","flag-lt","flag-lu","flag-lv","flag-ly","flag-ma","flag-mc","flag-md","flag-me","flag-mf","flag-mg","flag-mh","flag-mk","flag-ml","flag-mm","flag-mn","flag-mo","flag-mp","flag-mq","flag-mr","flag-ms","flag-mt","flag-mu","flag-mv","flag-mw","flag-mx","flag-my","flag-mz","flag-na","flag-nc","flag-ne","flag-nf","flag-ng","flag-ni","flag-nl","flag-no","flag-np","flag-nr","flag-nu","flag-nz","flag-om","flag-pa","flag-pe","flag-pf","flag-pg","flag-ph","flag-pk","flag-pl","flag-pm","flag-pn","flag-pr","flag-ps","flag-pt","flag-pw","flag-py","flag-qa","flag-re","flag-ro","flag-rs","flag-rw","flag-sa","flag-sb","flag-sc","flag-scotland","flag-sd","flag-se","flag-sg","flag-sh","flag-si","flag-sj","flag-sk","flag-sl","flag-sm","flag-sn","flag-so","flag-sr","flag-ss","flag-st","flag-sv","flag-sx","flag-sy","flag-sz","flag-ta","flag-tc","flag-td","flag-tf","flag-tg","flag-th","flag-tj","flag-tk","flag-tl","flag-tm","flag-tn","flag-to","flag-tr","flag-tt","flag-tv","flag-tw","flag-tz","flag-ua","flag-ug","flag-um","flag-uy","flag-uz","flag-va","flag-vc","flag-ve","flag-vg","flag-vi","flag-vn","flag-vu","flag-wales","flag-wf","flag-ws","flag-xk","flag-ye","flag-yt","flag-za","flag-zm","flag-zw","fr","gb","it","jp","kr","rainbow-flag","ru","triangular_flag_on_post","us","waving_black_flag","waving_white_flag"]}],"emojis":{"100":{"a":"Hundred Points Symbol","b":"1F4AF","j":["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],"k":[25,26]},"1234":{"a":"Input Symbol for Numbers","b":"1F522","j":["numbers","blue-square"],"k":[27,36]},"monkey_face":{"a":"Monkey Face","b":"1F435","j":["animal","nature","circus"],"k":[13,31],"l":[":o)"]},"grinning":{"a":"Grinning Face","b":"1F600","j":["face","smile","happy","joy",":D","grin"],"k":[30,24],"m":":D"},"earth_africa":{"a":"Earth Globe Europe-Africa","b":"1F30D","j":["globe","world","international"],"k":[6,5]},"checkered_flag":{"a":"Chequered Flag","b":"1F3C1","j":["contest","finishline","race","gokart"],"k":[9,27]},"mute":{"a":"Speaker with Cancellation Stroke","b":"1F507","j":["sound","volume","silence","quiet"],"k":[27,9]},"jack_o_lantern":{"a":"Jack-O-Lantern","b":"1F383","j":["halloween","light","pumpkin","creepy","fall"],"k":[8,17]},"atm":{"a":"Automated Teller Machine","b":"1F3E7","j":["money","sales","cash","blue-square","payment","bank"],"k":[12,4]},"grapes":{"a":"Grapes","b":"1F347","j":["fruit","food","wine"],"k":[7,9]},"earth_americas":{"a":"Earth Globe Americas","b":"1F30E","j":["globe","world","USA","international"],"k":[6,6]},"grin":{"a":"Grinning Face with Smiling Eyes","b":"1F601","j":["face","happy","smile","joy","kawaii"],"k":[30,25]},"melon":{"a":"Melon","b":"1F348","j":["fruit","nature","food"],"k":[7,10]},"triangular_flag_on_post":{"a":"Triangular Flag on Post","b":"1F6A9","j":["mark","milestone","place"],"k":[35,14]},"monkey":{"a":"Monkey","b":"1F412","j":["animal","nature","banana","circus"],"k":[12,48]},"christmas_tree":{"a":"Christmas Tree","b":"1F384","j":["festival","vacation","december","xmas","celebration"],"k":[8,18]},"put_litter_in_its_place":{"a":"Put Litter in Its Place Symbol","b":"1F6AE","j":["blue-square","sign","human","info"],"k":[35,19]},"speaker":{"a":"Speaker","b":"1F508","j":["sound","volume","silence","broadcast"],"k":[27,10]},"earth_asia":{"a":"Earth Globe Asia-Australia","b":"1F30F","j":["globe","world","east","international"],"k":[6,7]},"crossed_flags":{"a":"Crossed Flags","b":"1F38C","j":["japanese","nation","country","border"],"k":[8,31]},"joy":{"a":"Face with Tears of Joy","b":"1F602","j":["face","cry","tears","weep","happy","happytears","haha"],"k":[30,26]},"sound":{"a":"Speaker with One Sound Wave","b":"1F509","j":["volume","speaker","broadcast"],"k":[27,11]},"watermelon":{"a":"Watermelon","b":"1F349","j":["fruit","food","picnic","summer"],"k":[7,11]},"gorilla":{"a":"Gorilla","b":"1F98D","j":["animal","nature","circus"],"k":[42,37],"o":9},"fireworks":{"a":"Fireworks","b":"1F386","j":["photo","festival","carnival","congratulations"],"k":[8,25]},"potable_water":{"a":"Potable Water Symbol","b":"1F6B0","j":["blue-square","liquid","restroom","cleaning","faucet"],"k":[35,21]},"wheelchair":{"a":"Wheelchair Symbol","b":"267F","j":["blue-square","disabled","a11y","accessibility"],"k":[48,10],"o":4},"rolling_on_the_floor_laughing":{"a":"Rolling on the Floor Laughing","b":"1F923","k":[38,26],"o":9},"loud_sound":{"a":"Speaker with Three Sound Waves","b":"1F50A","j":["volume","noise","noisy","speaker","broadcast"],"k":[27,12]},"waving_black_flag":{"a":"Waving Black Flag","b":"1F3F4","k":[12,19],"o":7},"tangerine":{"a":"Tangerine","b":"1F34A","j":["food","fruit","nature","orange"],"k":[7,12]},"dog":{"a":"Dog Face","b":"1F436","j":["animal","friend","nature","woof","puppy","pet","faithful"],"k":[13,32]},"sparkler":{"a":"Firework Sparkler","b":"1F387","j":["stars","night","shine"],"k":[8,26]},"globe_with_meridians":{"a":"Globe with Meridians","b":"1F310","j":["earth","international","world","internet","interweb","i18n"],"k":[6,8]},"smiley":{"a":"Smiling Face with Open Mouth","b":"1F603","j":["face","happy","joy","haha",":D",":)","smile","funny"],"k":[30,27],"l":["=)","=-)"],"m":":)"},"loudspeaker":{"a":"Public Address Loudspeaker","b":"1F4E2","j":["volume","sound"],"k":[26,25]},"sparkles":{"a":"Sparkles","b":"2728","j":["stars","shine","shiny","cool","awesome","good","magic"],"k":[49,48]},"dog2":{"a":"Dog","b":"1F415","j":["animal","nature","friend","doge","pet","faithful"],"k":[12,51]},"waving_white_flag":{"a":"Waving White Flag","b":"1F3F3-FE0F","c":"1F3F3","k":[12,15],"o":7},"world_map":{"a":"World Map","b":"1F5FA-FE0F","c":"1F5FA","j":["location","direction"],"k":[30,18],"o":7},"lemon":{"a":"Lemon","b":"1F34B","j":["fruit","nature"],"k":[7,13]},"mens":{"a":"Mens Symbol","b":"1F6B9","j":["toilet","restroom","wc","blue-square","gender","male"],"k":[36,29]},"womens":{"a":"Womens Symbol","b":"1F6BA","j":["purple-square","woman","female","toilet","loo","restroom","gender"],"k":[36,30]},"rainbow-flag":{"a":"Rainbow Flag","b":"1F3F3-FE0F-200D-1F308","c":"1F3F3-200D-1F308","k":[12,14],"o":7},"smile":{"a":"Smiling Face with Open Mouth and Smiling Eyes","b":"1F604","j":["face","happy","joy","funny","haha","laugh","like",":D",":)"],"k":[30,28],"l":["C:","c:",":D",":-D"],"m":":)"},"banana":{"a":"Banana","b":"1F34C","j":["fruit","food","monkey"],"k":[7,14]},"mega":{"a":"Cheering Megaphone","b":"1F4E3","j":["sound","speaker","volume"],"k":[26,26]},"japan":{"a":"Silhouette of Japan","b":"1F5FE","j":["nation","country","japanese","asia"],"k":[30,22]},"poodle":{"a":"Poodle","b":"1F429","j":["dog","animal","101","nature","pet"],"k":[13,19]},"balloon":{"a":"Balloon","b":"1F388","j":["party","celebration","birthday","circus"],"k":[8,27]},"flag-ac":{"a":"Ascension Island Flag","b":"1F1E6-1F1E8","k":[0,31]},"sweat_smile":{"a":"Smiling Face with Open Mouth and Cold Sweat","b":"1F605","j":["face","hot","happy","laugh","sweat","smile","relief"],"k":[30,29]},"pineapple":{"a":"Pineapple","b":"1F34D","j":["fruit","nature","food"],"k":[7,15]},"restroom":{"a":"Restroom","b":"1F6BB","j":["blue-square","toilet","refresh","wc","gender"],"k":[36,31]},"postal_horn":{"a":"Postal Horn","b":"1F4EF","j":["instrument","music"],"k":[26,38]},"wolf":{"a":"Wolf Face","b":"1F43A","j":["animal","nature","wild"],"k":[13,36]},"tada":{"a":"Party Popper","b":"1F389","j":["party","congratulations","birthday","magic","circus","celebration"],"k":[8,28]},"snow_capped_mountain":{"a":"Snow Capped Mountain","b":"1F3D4-FE0F","c":"1F3D4","k":[11,37],"o":7},"laughing":{"a":"Smiling Face with Open Mouth and Tightly-Closed Eyes","b":"1F606","j":["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],"k":[30,30],"l":[":>",":->"],"n":["satisfied"]},"apple":{"a":"Red Apple","b":"1F34E","j":["fruit","mac","school"],"k":[7,16]},"flag-ad":{"a":"Andorra Flag","b":"1F1E6-1F1E9","k":[0,32]},"fox_face":{"a":"Fox Face","b":"1F98A","j":["animal","nature","face"],"k":[42,34],"o":9},"confetti_ball":{"a":"Confetti Ball","b":"1F38A","j":["festival","party","birthday","circus"],"k":[8,29]},"bell":{"a":"Bell","b":"1F514","j":["sound","notification","christmas","xmas","chime"],"k":[27,22]},"mountain":{"a":"Mountain","b":"26F0-FE0F","c":"26F0","j":["photo","nature","environment"],"k":[48,38],"o":5},"baby_symbol":{"a":"Baby Symbol","b":"1F6BC","j":["orange-square","child"],"k":[36,32]},"wc":{"a":"Water Closet","b":"1F6BE","j":["toilet","restroom","blue-square"],"k":[36,34]},"wink":{"a":"Winking Face","b":"1F609","j":["face","happy","mischievous","secret",";)","smile","eye"],"k":[30,33],"l":[";)",";-)"],"m":";)"},"no_bell":{"a":"Bell with Cancellation Stroke","b":"1F515","j":["sound","volume","mute","quiet","silent"],"k":[27,23]},"green_apple":{"a":"Green Apple","b":"1F34F","j":["fruit","nature"],"k":[7,17]},"tanabata_tree":{"a":"Tanabata Tree","b":"1F38B","j":["plant","nature","branch","summer"],"k":[8,30]},"flag-ae":{"a":"United Arab Emirates Flag","b":"1F1E6-1F1EA","k":[0,33]},"volcano":{"a":"Volcano","b":"1F30B","j":["photo","nature","disaster"],"k":[6,3]},"cat":{"a":"Cat Face","b":"1F431","j":["animal","meow","nature","pet","kitten"],"k":[13,27]},"flag-af":{"a":"Afghanistan Flag","b":"1F1E6-1F1EB","k":[0,34]},"musical_score":{"a":"Musical Score","b":"1F3BC","j":["treble","clef","compose"],"k":[9,22]},"blush":{"a":"Smiling Face with Smiling Eyes","b":"1F60A","j":["face","smile","happy","flushed","crush","embarrassed","shy","joy"],"k":[30,34],"m":":)"},"pear":{"a":"Pear","b":"1F350","j":["fruit","nature","food"],"k":[7,18]},"bamboo":{"a":"Pine Decoration","b":"1F38D","j":["plant","nature","vegetable","panda","pine_decoration"],"k":[8,32]},"passport_control":{"a":"Passport Control","b":"1F6C2","j":["custom","blue-square"],"k":[36,43]},"mount_fuji":{"a":"Mount Fuji","b":"1F5FB","j":["photo","mountain","nature","japanese"],"k":[30,19]},"cat2":{"a":"Cat","b":"1F408","j":["animal","meow","pet","cats"],"k":[12,38]},"musical_note":{"a":"Musical Note","b":"1F3B5","j":["score","tone","sound"],"k":[9,15]},"dolls":{"a":"Japanese Dolls","b":"1F38E","j":["japanese","toy","kimono"],"k":[8,33]},"lion_face":{"a":"Lion Face","b":"1F981","k":[42,25],"o":8},"camping":{"a":"Camping","b":"1F3D5-FE0F","c":"1F3D5","j":["photo","outdoors","tent"],"k":[11,38],"o":7},"flag-ag":{"a":"Antigua & Barbuda Flag","b":"1F1E6-1F1EC","k":[0,35]},"customs":{"a":"Customs","b":"1F6C3","j":["passport","border","blue-square"],"k":[36,44]},"yum":{"a":"Face Savouring Delicious Food","b":"1F60B","j":["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],"k":[30,35]},"peach":{"a":"Peach","b":"1F351","j":["fruit","nature","food"],"k":[7,19]},"tiger":{"a":"Tiger Face","b":"1F42F","j":["animal","cat","danger","wild","nature","roar"],"k":[13,25]},"notes":{"a":"Multiple Musical Notes","b":"1F3B6","j":["music","score"],"k":[9,16]},"flags":{"a":"Carp Streamer","b":"1F38F","j":["fish","japanese","koinobori","carp","banner"],"k":[8,34]},"beach_with_umbrella":{"a":"Beach with Umbrella","b":"1F3D6-FE0F","c":"1F3D6","k":[11,39],"o":7},"cherries":{"a":"Cherries","b":"1F352","j":["food","fruit"],"k":[7,20]},"flag-ai":{"a":"Anguilla Flag","b":"1F1E6-1F1EE","k":[0,36]},"baggage_claim":{"a":"Baggage Claim","b":"1F6C4","j":["blue-square","airport","transport"],"k":[36,45]},"sunglasses":{"a":"Smiling Face with Sunglasses","b":"1F60E","j":["face","cool","smile","summer","beach","sunglass"],"k":[30,38],"l":["8)"]},"left_luggage":{"a":"Left Luggage","b":"1F6C5","j":["blue-square","travel"],"k":[36,46]},"wind_chime":{"a":"Wind Chime","b":"1F390","j":["nature","ding","spring","bell"],"k":[8,35]},"strawberry":{"a":"Strawberry","b":"1F353","j":["fruit","food","nature"],"k":[7,21]},"desert":{"a":"Desert","b":"1F3DC-FE0F","c":"1F3DC","j":["photo","warm","saharah"],"k":[11,45],"o":7},"studio_microphone":{"a":"Studio Microphone","b":"1F399-FE0F","c":"1F399","j":["sing","recording","artist","talkshow"],"k":[8,41],"o":7},"flag-al":{"a":"Albania Flag","b":"1F1E6-1F1F1","k":[0,37]},"tiger2":{"a":"Tiger","b":"1F405","j":["animal","nature","roar"],"k":[12,35]},"heart_eyes":{"a":"Smiling Face with Heart-Shaped Eyes","b":"1F60D","j":["face","love","like","affection","valentines","infatuation","crush","heart"],"k":[30,37]},"desert_island":{"a":"Desert Island","b":"1F3DD-FE0F","c":"1F3DD","j":["photo","tropical","mojito"],"k":[11,46],"o":7},"kiwifruit":{"a":"Kiwifruit","b":"1F95D","k":[42,9],"o":9},"rice_scene":{"a":"Moon Viewing Ceremony","b":"1F391","j":["photo","japan","asia","tsukimi"],"k":[8,36]},"kissing_heart":{"a":"Face Throwing a Kiss","b":"1F618","j":["face","love","like","affection","valentines","infatuation","kiss"],"k":[30,48],"l":[":*",":-*"]},"warning":{"a":"Warning Sign","b":"26A0-FE0F","c":"26A0","j":["exclamation","wip","alert","error","problem","issue"],"k":[48,20],"o":4},"flag-am":{"a":"Armenia Flag","b":"1F1E6-1F1F2","k":[0,38]},"leopard":{"a":"Leopard","b":"1F406","j":["animal","nature"],"k":[12,36]},"level_slider":{"a":"Level Slider","b":"1F39A-FE0F","c":"1F39A","j":["scale"],"k":[8,42],"o":7},"horse":{"a":"Horse Face","b":"1F434","j":["animal","brown","nature"],"k":[13,30]},"children_crossing":{"a":"Children Crossing","b":"1F6B8","j":["school","warning","danger","sign","driving","yellow-diamond"],"k":[36,28]},"ribbon":{"a":"Ribbon","b":"1F380","j":["decoration","pink","girl","bowtie"],"k":[8,14]},"national_park":{"a":"National Park","b":"1F3DE-FE0F","c":"1F3DE","j":["photo","environment","nature"],"k":[11,47],"o":7},"control_knobs":{"a":"Control Knobs","b":"1F39B-FE0F","c":"1F39B","j":["dial"],"k":[8,43],"o":7},"kissing":{"a":"Kissing Face","b":"1F617","j":["love","like","face","3","valentines","infatuation","kiss"],"k":[30,47]},"tomato":{"a":"Tomato","b":"1F345","j":["fruit","vegetable","nature","food"],"k":[7,7]},"flag-ao":{"a":"Angola Flag","b":"1F1E6-1F1F4","k":[0,39]},"stadium":{"a":"Stadium","b":"1F3DF-FE0F","c":"1F3DF","j":["photo","place","sports","concert","venue"],"k":[11,48],"o":7},"flag-aq":{"a":"Antarctica Flag","b":"1F1E6-1F1F6","k":[0,40]},"gift":{"a":"Wrapped Present","b":"1F381","j":["present","birthday","christmas","xmas"],"k":[8,15]},"no_entry":{"a":"No Entry","b":"26D4","j":["limit","security","privacy","bad","denied","stop","circle"],"k":[48,35],"o":5},"kissing_smiling_eyes":{"a":"Kissing Face with Smiling Eyes","b":"1F619","j":["face","affection","valentines","infatuation","kiss"],"k":[30,49]},"coconut":{"a":"Coconut","b":"1F965","k":[42,17],"o":10},"racehorse":{"a":"Horse","b":"1F40E","j":["animal","gamble","luck"],"k":[12,44]},"microphone":{"a":"Microphone","b":"1F3A4","j":["sound","music","PA","sing","talkshow"],"k":[8,50]},"classical_building":{"a":"Classical Building","b":"1F3DB-FE0F","c":"1F3DB","j":["art","culture","history"],"k":[11,44],"o":7},"no_entry_sign":{"a":"No Entry Sign","b":"1F6AB","j":["forbid","stop","limit","denied","disallow","circle"],"k":[35,16]},"reminder_ribbon":{"a":"Reminder Ribbon","b":"1F397-FE0F","c":"1F397","j":["sports","cause","support","awareness"],"k":[8,40],"o":7},"kissing_closed_eyes":{"a":"Kissing Face with Closed Eyes","b":"1F61A","j":["face","love","like","affection","valentines","infatuation","kiss"],"k":[30,50]},"unicorn_face":{"a":"Unicorn Face","b":"1F984","k":[42,28],"o":8},"flag-ar":{"a":"Argentina Flag","b":"1F1E6-1F1F7","k":[0,41]},"headphones":{"a":"Headphone","b":"1F3A7","j":["music","score","gadgets"],"k":[9,1]},"avocado":{"a":"Avocado","b":"1F951","j":["fruit","food"],"k":[41,49],"o":9},"relaxed":{"a":"White Smiling Face","b":"263A-FE0F","c":"263A","j":["face","blush","massage","happiness"],"k":[47,41],"o":1},"zebra_face":{"a":"Zebra Face","b":"1F993","k":[42,43],"o":10},"eggplant":{"a":"Aubergine","b":"1F346","j":["vegetable","nature","food","aubergine"],"k":[7,8]},"radio":{"a":"Radio","b":"1F4FB","j":["communication","music","podcast","program"],"k":[26,50]},"building_construction":{"a":"Building Construction","b":"1F3D7-FE0F","c":"1F3D7","j":["wip","working","progress"],"k":[11,40],"o":7},"flag-as":{"a":"American Samoa Flag","b":"1F1E6-1F1F8","k":[0,42]},"admission_tickets":{"a":"Admission Tickets","b":"1F39F-FE0F","c":"1F39F","k":[8,45],"o":7},"no_bicycles":{"a":"No Bicycles","b":"1F6B3","j":["cyclist","prohibited","circle"],"k":[35,24]},"no_smoking":{"a":"No Smoking Symbol","b":"1F6AD","j":["cigarette","blue-square","smell","smoke"],"k":[35,18]},"slightly_smiling_face":{"a":"Slightly Smiling Face","b":"1F642","j":["face","smile"],"k":[31,38],"l":[":)","(:",":-)"],"o":7},"flag-at":{"a":"Austria Flag","b":"1F1E6-1F1F9","k":[0,43]},"ticket":{"a":"Ticket","b":"1F3AB","j":["event","concert","pass"],"k":[9,5]},"saxophone":{"a":"Saxophone","b":"1F3B7","j":["music","instrument","jazz","blues"],"k":[9,17]},"deer":{"a":"Deer","b":"1F98C","j":["animal","nature","horns","venison"],"k":[42,36],"o":9},"house_buildings":{"a":"House Buildings","b":"1F3D8-FE0F","c":"1F3D8","k":[11,41],"o":7},"potato":{"a":"Potato","b":"1F954","j":["food","tuber","vegatable","starch"],"k":[42,0],"o":9},"guitar":{"a":"Guitar","b":"1F3B8","j":["music","instrument"],"k":[9,18]},"carrot":{"a":"Carrot","b":"1F955","j":["vegetable","food","orange"],"k":[42,1],"o":9},"cityscape":{"a":"Cityscape","b":"1F3D9-FE0F","c":"1F3D9","j":["photo","night life","urban"],"k":[11,42],"o":7},"flag-au":{"a":"Australia Flag","b":"1F1E6-1F1FA","k":[0,44]},"do_not_litter":{"a":"Do Not Litter Symbol","b":"1F6AF","j":["trash","bin","garbage","circle"],"k":[35,20]},"hugging_face":{"a":"Hugging Face","b":"1F917","k":[37,31],"o":8},"cow":{"a":"Cow Face","b":"1F42E","j":["beef","ox","animal","nature","moo","milk"],"k":[13,24]},"medal":{"a":"Medal","b":"1F396-FE0F","c":"1F396","k":[8,39],"o":7},"musical_keyboard":{"a":"Musical Keyboard","b":"1F3B9","j":["piano","instrument","compose"],"k":[9,19]},"corn":{"a":"Ear of Maize","b":"1F33D","j":["food","vegetable","plant"],"k":[6,51]},"derelict_house_building":{"a":"Derelict House Building","b":"1F3DA-FE0F","c":"1F3DA","k":[11,43],"o":7},"non-potable_water":{"a":"Non-Potable Water Symbol","b":"1F6B1","j":["drink","faucet","tap","circle"],"k":[35,22]},"trophy":{"a":"Trophy","b":"1F3C6","j":["win","award","contest","place","ftw","ceremony"],"k":[10,19]},"flag-aw":{"a":"Aruba Flag","b":"1F1E6-1F1FC","k":[0,45]},"star-struck":{"a":"Grinning Face with Star Eyes","b":"1F929","k":[38,49],"n":["grinning_face_with_star_eyes"],"o":10},"ox":{"a":"Ox","b":"1F402","j":["animal","cow","beef"],"k":[12,32]},"trumpet":{"a":"Trumpet","b":"1F3BA","j":["music","brass"],"k":[9,20]},"hot_pepper":{"a":"Hot Pepper","b":"1F336-FE0F","c":"1F336","j":["food","spicy","chilli","chili"],"k":[6,44],"o":7},"sports_medal":{"a":"Sports Medal","b":"1F3C5","k":[10,18],"o":7},"flag-ax":{"a":"Åland Islands Flag","b":"1F1E6-1F1FD","k":[0,46]},"water_buffalo":{"a":"Water Buffalo","b":"1F403","j":["animal","nature","ox","cow"],"k":[12,33]},"no_pedestrians":{"a":"No Pedestrians","b":"1F6B7","j":["rules","crossing","walking","circle"],"k":[36,27]},"thinking_face":{"a":"Thinking Face","b":"1F914","k":[37,28],"o":8},"house":{"a":"House Building","b":"1F3E0","j":["building","home"],"k":[11,49]},"no_mobile_phones":{"a":"No Mobile Phones","b":"1F4F5","j":["iphone","mute","circle"],"k":[26,44]},"flag-az":{"a":"Azerbaijan Flag","b":"1F1E6-1F1FF","k":[0,47]},"first_place_medal":{"a":"First Place Medal","b":"1F947","k":[41,42],"o":9},"house_with_garden":{"a":"House with Garden","b":"1F3E1","j":["home","plant","nature"],"k":[11,50]},"violin":{"a":"Violin","b":"1F3BB","j":["music","instrument","orchestra","symphony"],"k":[9,21]},"face_with_raised_eyebrow":{"a":"Face with One Eyebrow Raised","b":"1F928","k":[38,48],"n":["face_with_one_eyebrow_raised"],"o":10},"cucumber":{"a":"Cucumber","b":"1F952","j":["fruit","food","pickle"],"k":[41,50],"o":9},"cow2":{"a":"Cow","b":"1F404","j":["beef","ox","animal","nature","moo","milk"],"k":[12,34]},"flag-ba":{"a":"Bosnia & Herzegovina Flag","b":"1F1E7-1F1E6","k":[0,48]},"pig":{"a":"Pig Face","b":"1F437","j":["animal","oink","nature"],"k":[13,33]},"drum_with_drumsticks":{"a":"Drum with Drumsticks","b":"1F941","k":[41,37],"o":9},"underage":{"a":"No One Under Eighteen Symbol","b":"1F51E","j":["18","drink","pub","night","minor","circle"],"k":[27,32]},"broccoli":{"a":"Broccoli","b":"1F966","k":[42,18],"o":10},"office":{"a":"Office Building","b":"1F3E2","j":["building","bureau","work"],"k":[11,51]},"second_place_medal":{"a":"Second Place Medal","b":"1F948","k":[41,43],"o":9},"neutral_face":{"a":"Neutral Face","b":"1F610","j":["indifference","meh",":|","neutral"],"k":[30,40],"l":[":|",":-|"]},"third_place_medal":{"a":"Third Place Medal","b":"1F949","k":[41,44],"o":9},"mushroom":{"a":"Mushroom","b":"1F344","j":["plant","vegetable"],"k":[7,6]},"flag-bb":{"a":"Barbados Flag","b":"1F1E7-1F1E7","k":[0,49]},"radioactive_sign":{"a":"Radioactive Sign","b":"2622-FE0F","c":"2622","k":[47,33],"o":1},"pig2":{"a":"Pig","b":"1F416","j":["animal","nature"],"k":[13,0]},"expressionless":{"a":"Expressionless Face","b":"1F611","j":["face","indifferent","-_-","meh","deadpan"],"k":[30,41]},"iphone":{"a":"Mobile Phone","b":"1F4F1","j":["technology","apple","gadgets","dial"],"k":[26,40]},"post_office":{"a":"Japanese Post Office","b":"1F3E3","j":["building","envelope","communication"],"k":[12,0]},"european_post_office":{"a":"European Post Office","b":"1F3E4","j":["building","email"],"k":[12,1]},"soccer":{"a":"Soccer Ball","b":"26BD","j":["sports","football"],"k":[48,26],"o":5},"boar":{"a":"Boar","b":"1F417","j":["animal","nature"],"k":[13,1]},"peanuts":{"a":"Peanuts","b":"1F95C","j":["food","nut"],"k":[42,8],"o":9},"calling":{"a":"Mobile Phone with Rightwards Arrow at Left","b":"1F4F2","j":["iphone","incoming"],"k":[26,41]},"biohazard_sign":{"a":"Biohazard Sign","b":"2623-FE0F","c":"2623","k":[47,34],"o":1},"flag-bd":{"a":"Bangladesh Flag","b":"1F1E7-1F1E9","k":[0,50]},"no_mouth":{"a":"Face Without Mouth","b":"1F636","j":["face","hellokitty"],"k":[31,26]},"face_with_rolling_eyes":{"a":"Face with Rolling Eyes","b":"1F644","k":[31,40],"o":8},"phone":{"a":"Black Telephone","b":"260E-FE0F","c":"260E","j":["technology","communication","dial","telephone"],"k":[47,21],"n":["telephone"],"o":1},"pig_nose":{"a":"Pig Nose","b":"1F43D","j":["animal","oink"],"k":[13,39]},"chestnut":{"a":"Chestnut","b":"1F330","j":["food","squirrel"],"k":[6,38]},"arrow_up":{"a":"Upwards Black Arrow","b":"2B06-FE0F","c":"2B06","j":["blue-square","continue","top","direction"],"k":[50,18],"o":4},"hospital":{"a":"Hospital","b":"1F3E5","j":["building","health","surgery","doctor"],"k":[12,2]},"flag-be":{"a":"Belgium Flag","b":"1F1E7-1F1EA","k":[0,51]},"baseball":{"a":"Baseball","b":"26BE","j":["sports","balls"],"k":[48,27],"o":5},"smirk":{"a":"Smirking Face","b":"1F60F","j":["face","smile","mean","prank","smug","sarcasm"],"k":[30,39]},"arrow_upper_right":{"a":"North East Arrow","b":"2197-FE0F","c":"2197","j":["blue-square","point","direction","diagonal","northeast"],"k":[46,36],"o":1},"flag-bf":{"a":"Burkina Faso Flag","b":"1F1E7-1F1EB","k":[1,0]},"basketball":{"a":"Basketball and Hoop","b":"1F3C0","j":["sports","balls","NBA"],"k":[9,26]},"ram":{"a":"Ram","b":"1F40F","j":["animal","sheep","nature"],"k":[12,45]},"bank":{"a":"Bank","b":"1F3E6","j":["building","money","sales","cash","business","enterprise"],"k":[12,3]},"bread":{"a":"Bread","b":"1F35E","j":["food","wheat","breakfast","toast"],"k":[7,32]},"telephone_receiver":{"a":"Telephone Receiver","b":"1F4DE","j":["technology","communication","dial"],"k":[26,21]},"croissant":{"a":"Croissant","b":"1F950","j":["food","bread","french"],"k":[41,48],"o":9},"pager":{"a":"Pager","b":"1F4DF","j":["bbcall","oldschool","90s"],"k":[26,22]},"sheep":{"a":"Sheep","b":"1F411","j":["animal","nature","wool","shipit"],"k":[12,47]},"arrow_right":{"a":"Black Rightwards Arrow","b":"27A1-FE0F","c":"27A1","j":["blue-square","next"],"k":[50,12],"o":1},"persevere":{"a":"Persevering Face","b":"1F623","j":["face","sick","no","upset","oops"],"k":[31,7]},"flag-bg":{"a":"Bulgaria Flag","b":"1F1E7-1F1EC","k":[1,1]},"volleyball":{"a":"Volleyball","b":"1F3D0","j":["sports","balls"],"k":[11,33],"o":8},"hotel":{"a":"Hotel","b":"1F3E8","j":["building","accomodation","checkin"],"k":[12,5]},"arrow_lower_right":{"a":"South East Arrow","b":"2198-FE0F","c":"2198","j":["blue-square","direction","diagonal","southeast"],"k":[46,37],"o":1},"goat":{"a":"Goat","b":"1F410","j":["animal","nature"],"k":[12,46]},"flag-bh":{"a":"Bahrain Flag","b":"1F1E7-1F1ED","k":[1,2]},"love_hotel":{"a":"Love Hotel","b":"1F3E9","j":["like","affection","dating"],"k":[12,6]},"disappointed_relieved":{"a":"Disappointed but Relieved Face","b":"1F625","j":["face","phew","sweat","nervous"],"k":[31,9]},"baguette_bread":{"a":"Baguette Bread","b":"1F956","j":["food","bread","french"],"k":[42,2],"o":9},"football":{"a":"American Football","b":"1F3C8","j":["sports","balls","NFL"],"k":[10,26]},"fax":{"a":"Fax Machine","b":"1F4E0","j":["communication","technology"],"k":[26,23]},"convenience_store":{"a":"Convenience Store","b":"1F3EA","j":["building","shopping","groceries"],"k":[12,7]},"dromedary_camel":{"a":"Dromedary Camel","b":"1F42A","j":["animal","hot","desert","hump"],"k":[13,20]},"arrow_down":{"a":"Downwards Black Arrow","b":"2B07-FE0F","c":"2B07","j":["blue-square","direction","bottom"],"k":[50,19],"o":4},"battery":{"a":"Battery","b":"1F50B","j":["power","energy","sustain"],"k":[27,13]},"rugby_football":{"a":"Rugby Football","b":"1F3C9","j":["sports","team"],"k":[10,27]},"pretzel":{"a":"Pretzel","b":"1F968","k":[42,20],"o":10},"open_mouth":{"a":"Face with Open Mouth","b":"1F62E","j":["face","surprise","impressed","wow","whoa",":O"],"k":[31,18],"l":[":o",":-o",":O",":-O"]},"flag-bi":{"a":"Burundi Flag","b":"1F1E7-1F1EE","k":[1,3]},"flag-bj":{"a":"Benin Flag","b":"1F1E7-1F1EF","k":[1,4]},"pancakes":{"a":"Pancakes","b":"1F95E","j":["food","breakfast","flapjacks","hotcakes"],"k":[42,10],"o":9},"school":{"a":"School","b":"1F3EB","j":["building","student","education","learn","teach"],"k":[12,8]},"tennis":{"a":"Tennis Racquet and Ball","b":"1F3BE","j":["sports","balls","green"],"k":[9,24]},"zipper_mouth_face":{"a":"Zipper-Mouth Face","b":"1F910","j":["face","sealed","zipper","secret"],"k":[37,24],"o":8},"camel":{"a":"Bactrian Camel","b":"1F42B","j":["animal","nature","hot","desert","hump"],"k":[13,21]},"arrow_lower_left":{"a":"South West Arrow","b":"2199-FE0F","c":"2199","j":["blue-square","direction","diagonal","southwest"],"k":[46,38],"o":1},"electric_plug":{"a":"Electric Plug","b":"1F50C","j":["charger","power"],"k":[27,14]},"cheese_wedge":{"a":"Cheese Wedge","b":"1F9C0","k":[42,48],"o":8},"hushed":{"a":"Hushed Face","b":"1F62F","j":["face","woo","shh"],"k":[31,19]},"computer":{"a":"Personal Computer","b":"1F4BB","j":["technology","laptop","screen","display","monitor"],"k":[25,38]},"giraffe_face":{"a":"Giraffe Face","b":"1F992","k":[42,42],"o":10},"8ball":{"a":"Billiards","b":"1F3B1","j":["pool","hobby","game","luck","magic"],"k":[9,11]},"flag-bl":{"a":"St. Barthélemy Flag","b":"1F1E7-1F1F1","k":[1,5]},"arrow_left":{"a":"Leftwards Black Arrow","b":"2B05-FE0F","c":"2B05","j":["blue-square","previous","back"],"k":[50,17],"o":4},"department_store":{"a":"Department Store","b":"1F3EC","j":["building","shopping","mall"],"k":[12,9]},"meat_on_bone":{"a":"Meat on Bone","b":"1F356","j":["good","food","drumstick"],"k":[7,24]},"arrow_upper_left":{"a":"North West Arrow","b":"2196-FE0F","c":"2196","j":["blue-square","point","direction","diagonal","northwest"],"k":[46,35],"o":1},"flag-bm":{"a":"Bermuda Flag","b":"1F1E7-1F1F2","k":[1,6]},"sleepy":{"a":"Sleepy Face","b":"1F62A","j":["face","tired","rest","nap"],"k":[31,14]},"bowling":{"a":"Bowling","b":"1F3B3","j":["sports","fun","play"],"k":[9,13]},"factory":{"a":"Factory","b":"1F3ED","j":["building","industry","pollution","smoke"],"k":[12,10]},"desktop_computer":{"a":"Desktop Computer","b":"1F5A5-FE0F","c":"1F5A5","j":["technology","computing","screen"],"k":[29,51],"o":7},"elephant":{"a":"Elephant","b":"1F418","j":["animal","nature","nose","th","circus"],"k":[13,2]},"rhinoceros":{"a":"Rhinoceros","b":"1F98F","j":["animal","nature","horn"],"k":[42,39],"o":9},"arrow_up_down":{"a":"Up Down Arrow","b":"2195-FE0F","c":"2195","j":["blue-square","direction","way","vertical"],"k":[46,34],"o":1},"cricket_bat_and_ball":{"a":"Cricket Bat and Ball","b":"1F3CF","k":[11,32],"o":8},"printer":{"a":"Printer","b":"1F5A8-FE0F","c":"1F5A8","j":["paper","ink"],"k":[30,0],"o":7},"poultry_leg":{"a":"Poultry Leg","b":"1F357","j":["food","meat","drumstick","bird","chicken","turkey"],"k":[7,25]},"tired_face":{"a":"Tired Face","b":"1F62B","j":["sick","whine","upset","frustrated"],"k":[31,15]},"japanese_castle":{"a":"Japanese Castle","b":"1F3EF","j":["photo","building"],"k":[12,12]},"flag-bn":{"a":"Brunei Flag","b":"1F1E7-1F1F3","k":[1,7]},"field_hockey_stick_and_ball":{"a":"Field Hockey Stick and Ball","b":"1F3D1","k":[11,34],"o":8},"sleeping":{"a":"Sleeping Face","b":"1F634","j":["face","tired","sleepy","night","zzz"],"k":[31,24]},"left_right_arrow":{"a":"Left Right Arrow","b":"2194-FE0F","c":"2194","j":["shape","direction","horizontal","sideways"],"k":[46,33],"o":1},"keyboard":{"a":"Keyboard","b":"2328-FE0F","c":"2328","j":["technology","computer","type","input","text"],"k":[46,43],"o":1},"european_castle":{"a":"European Castle","b":"1F3F0","j":["building","royalty","history"],"k":[12,13]},"mouse":{"a":"Mouse Face","b":"1F42D","j":["animal","nature","cheese_wedge","rodent"],"k":[13,23]},"flag-bo":{"a":"Bolivia Flag","b":"1F1E7-1F1F4","k":[1,8]},"cut_of_meat":{"a":"Cut of Meat","b":"1F969","k":[42,21],"o":10},"ice_hockey_stick_and_puck":{"a":"Ice Hockey Stick and Puck","b":"1F3D2","k":[11,35],"o":8},"mouse2":{"a":"Mouse","b":"1F401","j":["animal","nature","rodent"],"k":[12,31]},"three_button_mouse":{"a":"Three Button Mouse","b":"1F5B1-FE0F","c":"1F5B1","k":[30,1],"o":7},"leftwards_arrow_with_hook":{"a":"Leftwards Arrow with Hook","b":"21A9-FE0F","c":"21A9","j":["back","return","blue-square","undo","enter"],"k":[46,39],"o":1},"bacon":{"a":"Bacon","b":"1F953","j":["food","breakfast","pork","pig","meat"],"k":[41,51],"o":9},"relieved":{"a":"Relieved Face","b":"1F60C","j":["face","relaxed","phew","massage","happiness"],"k":[30,36]},"flag-bq":{"a":"Caribbean Netherlands Flag","b":"1F1E7-1F1F6","k":[1,9]},"wedding":{"a":"Wedding","b":"1F492","j":["love","like","affection","couple","marriage","bride","groom"],"k":[24,44]},"tokyo_tower":{"a":"Tokyo Tower","b":"1F5FC","j":["photo","japanese"],"k":[30,20]},"arrow_right_hook":{"a":"Rightwards Arrow with Hook","b":"21AA-FE0F","c":"21AA","j":["blue-square","return","rotate","direction"],"k":[46,40],"o":1},"hamburger":{"a":"Hamburger","b":"1F354","j":["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],"k":[7,22]},"stuck_out_tongue":{"a":"Face with Stuck-out Tongue","b":"1F61B","j":["face","prank","childish","playful","mischievous","smile","tongue"],"k":[30,51],"l":[":p",":-p",":P",":-P",":b",":-b"],"m":":p"},"trackball":{"a":"Trackball","b":"1F5B2-FE0F","c":"1F5B2","j":["technology","trackpad"],"k":[30,2],"o":7},"flag-br":{"a":"Brazil Flag","b":"1F1E7-1F1F7","k":[1,10]},"rat":{"a":"Rat","b":"1F400","j":["animal","mouse","rodent"],"k":[12,30]},"table_tennis_paddle_and_ball":{"a":"Table Tennis Paddle and Ball","b":"1F3D3","k":[11,36],"o":8},"minidisc":{"a":"Minidisc","b":"1F4BD","j":["technology","record","data","disk","90s"],"k":[25,40]},"stuck_out_tongue_winking_eye":{"a":"Face with Stuck-out Tongue and Winking Eye","b":"1F61C","j":["face","prank","childish","playful","mischievous","smile","wink","tongue"],"k":[31,0],"l":[";p",";-p",";b",";-b",";P",";-P"],"m":";p"},"fries":{"a":"French Fries","b":"1F35F","j":["chips","snack","fast food"],"k":[7,33]},"badminton_racquet_and_shuttlecock":{"a":"Badminton Racquet and Shuttlecock","b":"1F3F8","k":[12,22],"o":8},"statue_of_liberty":{"a":"Statue of Liberty","b":"1F5FD","j":["american","newyork"],"k":[30,21]},"flag-bs":{"a":"Bahamas Flag","b":"1F1E7-1F1F8","k":[1,11]},"arrow_heading_up":{"a":"Arrow Pointing Rightwards Then Curving Upwards","b":"2934-FE0F","c":"2934","j":["blue-square","direction","top"],"k":[50,15],"o":3},"hamster":{"a":"Hamster Face","b":"1F439","j":["animal","nature"],"k":[13,35]},"stuck_out_tongue_closed_eyes":{"a":"Face with Stuck-out Tongue and Tightly-Closed Eyes","b":"1F61D","j":["face","prank","playful","mischievous","smile","tongue"],"k":[31,1]},"pizza":{"a":"Slice of Pizza","b":"1F355","j":["food","party"],"k":[7,23]},"boxing_glove":{"a":"Boxing Glove","b":"1F94A","j":["sports","fighting"],"k":[41,45],"o":9},"floppy_disk":{"a":"Floppy Disk","b":"1F4BE","j":["oldschool","technology","save","90s","80s"],"k":[25,41]},"arrow_heading_down":{"a":"Arrow Pointing Rightwards Then Curving Downwards","b":"2935-FE0F","c":"2935","j":["blue-square","direction","bottom"],"k":[50,16],"o":3},"flag-bt":{"a":"Bhutan Flag","b":"1F1E7-1F1F9","k":[1,12]},"rabbit":{"a":"Rabbit Face","b":"1F430","j":["animal","nature","pet","spring","magic","bunny"],"k":[13,26]},"church":{"a":"Church","b":"26EA","j":["building","religion","christ"],"k":[48,37],"o":5},"drooling_face":{"a":"Drooling Face","b":"1F924","j":["face"],"k":[38,27],"o":9},"flag-bv":{"a":"Bouvet Island Flag","b":"1F1E7-1F1FB","k":[1,13]},"mosque":{"a":"Mosque","b":"1F54C","j":["islam","worship","minaret"],"k":[28,15],"o":8},"rabbit2":{"a":"Rabbit","b":"1F407","j":["animal","nature","pet","magic","spring"],"k":[12,37]},"hotdog":{"a":"Hot Dog","b":"1F32D","j":["food","frankfurter"],"k":[6,35],"o":8},"martial_arts_uniform":{"a":"Martial Arts Uniform","b":"1F94B","j":["judo","karate","taekwondo"],"k":[41,46],"o":9},"arrows_clockwise":{"a":"Clockwise Downwards and Upwards Open Circle Arrows","b":"1F503","j":["sync","cycle","round","repeat"],"k":[27,5]},"cd":{"a":"Optical Disc","b":"1F4BF","j":["technology","dvd","disk","disc","90s"],"k":[25,42]},"arrows_counterclockwise":{"a":"Anticlockwise Downwards and Upwards Open Circle Arrows","b":"1F504","j":["blue-square","sync","cycle"],"k":[27,6]},"sandwich":{"a":"Sandwich","b":"1F96A","k":[42,22],"o":10},"chipmunk":{"a":"Chipmunk","b":"1F43F-FE0F","c":"1F43F","j":["animal","nature","rodent","squirrel"],"k":[13,41],"o":7},"synagogue":{"a":"Synagogue","b":"1F54D","j":["judaism","worship","temple","jewish"],"k":[28,16],"o":8},"unamused":{"a":"Unamused Face","b":"1F612","j":["indifference","bored","straight face","serious","sarcasm"],"k":[30,42],"m":":("},"goal_net":{"a":"Goal Net","b":"1F945","j":["sports"],"k":[41,41],"o":9},"flag-bw":{"a":"Botswana Flag","b":"1F1E7-1F1FC","k":[1,14]},"dvd":{"a":"Dvd","b":"1F4C0","j":["cd","disk","disc"],"k":[25,43]},"hedgehog":{"a":"Hedgehog","b":"1F994","k":[42,44],"o":10},"dart":{"a":"Direct Hit","b":"1F3AF","j":["game","play","bar"],"k":[9,9]},"taco":{"a":"Taco","b":"1F32E","j":["food","mexican"],"k":[6,36],"o":8},"back":{"a":"Back with Leftwards Arrow Above","b":"1F519","j":["arrow","words","return"],"k":[27,27]},"flag-by":{"a":"Belarus Flag","b":"1F1E7-1F1FE","k":[1,15]},"shinto_shrine":{"a":"Shinto Shrine","b":"26E9-FE0F","c":"26E9","j":["temple","japan","kyoto"],"k":[48,36],"o":5},"movie_camera":{"a":"Movie Camera","b":"1F3A5","j":["film","record"],"k":[8,51]},"sweat":{"a":"Face with Cold Sweat","b":"1F613","j":["face","hot","sad","tired","exercise"],"k":[30,43]},"burrito":{"a":"Burrito","b":"1F32F","j":["food","mexican"],"k":[6,37],"o":8},"flag-bz":{"a":"Belize Flag","b":"1F1E7-1F1FF","k":[1,16]},"pensive":{"a":"Pensive Face","b":"1F614","j":["face","sad","depressed","upset"],"k":[30,44]},"kaaba":{"a":"Kaaba","b":"1F54B","j":["mecca","mosque","islam"],"k":[28,14],"o":8},"film_frames":{"a":"Film Frames","b":"1F39E-FE0F","c":"1F39E","k":[8,44],"o":7},"bat":{"a":"Bat","b":"1F987","j":["animal","nature","blind","vampire"],"k":[42,31],"o":9},"golf":{"a":"Flag in Hole","b":"26F3","j":["sports","business","flag","hole","summer"],"k":[48,41],"o":5},"end":{"a":"End with Leftwards Arrow Above","b":"1F51A","j":["words","arrow"],"k":[27,28]},"film_projector":{"a":"Film Projector","b":"1F4FD-FE0F","c":"1F4FD","j":["video","tape","record","movie"],"k":[27,0],"o":7},"bear":{"a":"Bear Face","b":"1F43B","j":["animal","nature","wild"],"k":[13,37]},"ice_skate":{"a":"Ice Skate","b":"26F8-FE0F","c":"26F8","j":["sports"],"k":[48,45],"o":5},"fountain":{"a":"Fountain","b":"26F2","j":["photo","summer","water","fresh"],"k":[48,40],"o":5},"confused":{"a":"Confused Face","b":"1F615","j":["face","indifference","huh","weird","hmmm",":/"],"k":[30,45],"l":[":\\",":-\\",":/",":-/"]},"flag-ca":{"a":"Canada Flag","b":"1F1E8-1F1E6","k":[1,17]},"on":{"a":"On with Exclamation Mark with Left Right Arrow Above","b":"1F51B","j":["arrow","words"],"k":[27,29]},"stuffed_flatbread":{"a":"Stuffed Flatbread","b":"1F959","j":["food","flatbread","stuffed","gyro"],"k":[42,5],"o":9},"soon":{"a":"Soon with Rightwards Arrow Above","b":"1F51C","j":["arrow","words"],"k":[27,30]},"upside_down_face":{"a":"Upside-Down Face","b":"1F643","j":["face","flipped","silly","smile"],"k":[31,39],"o":8},"fishing_pole_and_fish":{"a":"Fishing Pole and Fish","b":"1F3A3","j":["food","hobby","summer"],"k":[8,49]},"tent":{"a":"Tent","b":"26FA","j":["photo","camping","outdoors"],"k":[49,12],"o":5},"clapper":{"a":"Clapper Board","b":"1F3AC","j":["movie","film","record"],"k":[9,6]},"egg":{"a":"Egg","b":"1F95A","j":["food","chicken","breakfast"],"k":[42,6],"o":9},"flag-cc":{"a":"Cocos (keeling) Islands Flag","b":"1F1E8-1F1E8","k":[1,18]},"koala":{"a":"Koala","b":"1F428","j":["animal","nature"],"k":[13,18]},"foggy":{"a":"Foggy","b":"1F301","j":["photo","mountain"],"k":[5,45]},"tv":{"a":"Television","b":"1F4FA","j":["technology","program","oldschool","show","television"],"k":[26,49]},"panda_face":{"a":"Panda Face","b":"1F43C","j":["animal","nature","panda"],"k":[13,38]},"fried_egg":{"a":"Cooking","b":"1F373","j":["food","breakfast","kitchen","egg"],"k":[8,1],"n":["cooking"]},"top":{"a":"Top with Upwards Arrow Above","b":"1F51D","j":["words","blue-square"],"k":[27,31]},"flag-cd":{"a":"Congo - Kinshasa Flag","b":"1F1E8-1F1E9","k":[1,19]},"money_mouth_face":{"a":"Money-Mouth Face","b":"1F911","j":["face","rich","dollar","money"],"k":[37,25],"o":8},"running_shirt_with_sash":{"a":"Running Shirt with Sash","b":"1F3BD","j":["play","pageant"],"k":[9,23]},"astonished":{"a":"Astonished Face","b":"1F632","j":["face","xox","surprised","poisoned"],"k":[31,22]},"feet":{"a":"Paw Prints","b":"1F43E","k":[13,40],"n":["paw_prints"]},"camera":{"a":"Camera","b":"1F4F7","j":["gadgets","photography"],"k":[26,46]},"flag-cf":{"a":"Central African Republic Flag","b":"1F1E8-1F1EB","k":[1,20]},"place_of_worship":{"a":"Place of Worship","b":"1F6D0","j":["religion","church","temple","prayer"],"k":[37,5],"o":8},"night_with_stars":{"a":"Night with Stars","b":"1F303","j":["evening","city","downtown"],"k":[5,47]},"ski":{"a":"Ski and Ski Boot","b":"1F3BF","j":["sports","winter","cold","snow"],"k":[9,25]},"shallow_pan_of_food":{"a":"Shallow Pan of Food","b":"1F958","j":["food","cooking","casserole","paella"],"k":[42,4],"o":9},"camera_with_flash":{"a":"Camera with Flash","b":"1F4F8","k":[26,47],"o":7},"sunrise_over_mountains":{"a":"Sunrise over Mountains","b":"1F304","j":["view","vacation","photo"],"k":[5,48]},"turkey":{"a":"Turkey","b":"1F983","j":["animal","bird"],"k":[42,27],"o":8},"white_frowning_face":{"a":"White Frowning Face","b":"2639-FE0F","c":"2639","k":[47,40],"o":1},"flag-cg":{"a":"Congo - Brazzaville Flag","b":"1F1E8-1F1EC","k":[1,21]},"stew":{"a":"Pot of Food","b":"1F372","j":["food","meat","soup"],"k":[8,0]},"sled":{"a":"Sled","b":"1F6F7","k":[37,22],"o":10},"atom_symbol":{"a":"Atom Symbol","b":"269B-FE0F","c":"269B","j":["science","physics","chemistry"],"k":[48,18],"o":4},"curling_stone":{"a":"Curling Stone","b":"1F94C","k":[41,47],"o":10},"slightly_frowning_face":{"a":"Slightly Frowning Face","b":"1F641","j":["face","frowning","disappointed","sad","upset"],"k":[31,37],"o":7},"sunrise":{"a":"Sunrise","b":"1F305","j":["morning","view","vacation","photo"],"k":[5,49]},"om_symbol":{"a":"Om Symbol","b":"1F549-FE0F","c":"1F549","k":[28,12],"o":7},"chicken":{"a":"Chicken","b":"1F414","j":["animal","cluck","nature","bird"],"k":[12,50]},"bowl_with_spoon":{"a":"Bowl with Spoon","b":"1F963","k":[42,15],"o":10},"flag-ch":{"a":"Switzerland Flag","b":"1F1E8-1F1ED","k":[1,22]},"video_camera":{"a":"Video Camera","b":"1F4F9","j":["film","record"],"k":[26,48]},"video_game":{"a":"Video Game","b":"1F3AE","j":["play","console","PS4","controller"],"k":[9,8]},"rooster":{"a":"Rooster","b":"1F413","j":["animal","nature","chicken"],"k":[12,49]},"vhs":{"a":"Videocassette","b":"1F4FC","j":["record","video","oldschool","90s","80s"],"k":[26,51]},"city_sunset":{"a":"Cityscape at Dusk","b":"1F306","j":["photo","evening","sky","buildings"],"k":[5,50]},"confounded":{"a":"Confounded Face","b":"1F616","j":["face","confused","sick","unwell","oops",":S"],"k":[30,46]},"green_salad":{"a":"Green Salad","b":"1F957","j":["food","healthy","lettuce"],"k":[42,3],"o":9},"star_of_david":{"a":"Star of David","b":"2721-FE0F","c":"2721","j":["judaism"],"k":[49,47],"o":1},"flag-ci":{"a":"Côte D’ivoire Flag","b":"1F1E8-1F1EE","k":[1,23]},"popcorn":{"a":"Popcorn","b":"1F37F","j":["food","movie theater","films","snack"],"k":[8,13],"o":8},"city_sunrise":{"a":"Sunset over Buildings","b":"1F307","j":["photo","good morning","dawn"],"k":[5,51]},"disappointed":{"a":"Disappointed Face","b":"1F61E","j":["face","sad","upset","depressed",":("],"k":[31,2],"l":["):",":(",":-("],"m":":("},"mag":{"a":"Left-Pointing Magnifying Glass","b":"1F50D","j":["search","zoom","find","detective"],"k":[27,15]},"hatching_chick":{"a":"Hatching Chick","b":"1F423","j":["animal","chicken","egg","born","baby","bird"],"k":[13,13]},"joystick":{"a":"Joystick","b":"1F579-FE0F","c":"1F579","j":["game","play"],"k":[29,20],"o":7},"wheel_of_dharma":{"a":"Wheel of Dharma","b":"2638-FE0F","c":"2638","j":["hinduism","buddhism","sikhism","jainism"],"k":[47,39],"o":1},"flag-ck":{"a":"Cook Islands Flag","b":"1F1E8-1F1F0","k":[1,24]},"canned_food":{"a":"Canned Food","b":"1F96B","k":[42,23],"o":10},"worried":{"a":"Worried Face","b":"1F61F","j":["face","concern","nervous",":("],"k":[31,3]},"baby_chick":{"a":"Baby Chick","b":"1F424","j":["animal","chicken","bird"],"k":[13,14]},"flag-cl":{"a":"Chile Flag","b":"1F1E8-1F1F1","k":[1,25]},"game_die":{"a":"Game Die","b":"1F3B2","j":["dice","random","tabletop","play","luck"],"k":[9,12]},"mag_right":{"a":"Right-Pointing Magnifying Glass","b":"1F50E","j":["search","zoom","find","detective"],"k":[27,16]},"yin_yang":{"a":"Yin Yang","b":"262F-FE0F","c":"262F","j":["balance"],"k":[47,38],"o":1},"bridge_at_night":{"a":"Bridge at Night","b":"1F309","j":["photo","sanfrancisco"],"k":[6,1]},"spades":{"a":"Black Spade Suit","b":"2660-FE0F","c":"2660","j":["poker","cards","suits","magic"],"k":[48,4],"o":1},"hatched_chick":{"a":"Front-Facing Baby Chick","b":"1F425","j":["animal","chicken","baby","bird"],"k":[13,15]},"flag-cm":{"a":"Cameroon Flag","b":"1F1E8-1F1F2","k":[1,26]},"latin_cross":{"a":"Latin Cross","b":"271D-FE0F","c":"271D","j":["christianity"],"k":[49,46],"o":1},"triumph":{"a":"Face with Look of Triumph","b":"1F624","j":["face","gas","phew","proud","pride"],"k":[31,8]},"hotsprings":{"a":"Hot Springs","b":"2668-FE0F","c":"2668","j":["bath","warm","relax"],"k":[48,8],"o":1},"bento":{"a":"Bento Box","b":"1F371","j":["food","japanese","box"],"k":[7,51]},"microscope":{"a":"Microscope","b":"1F52C","j":["laboratory","experiment","zoomin","science","study"],"k":[27,46]},"cry":{"a":"Crying Face","b":"1F622","j":["face","tears","sad","depressed","upset",":'("],"k":[31,6],"l":[":'("],"m":":'("},"bird":{"a":"Bird","b":"1F426","j":["animal","nature","fly","tweet","spring"],"k":[13,16]},"cn":{"a":"China Flag","b":"1F1E8-1F1F3","j":["china","chinese","prc","flag","country","nation","banner"],"k":[1,27],"n":["flag-cn"]},"telescope":{"a":"Telescope","b":"1F52D","j":["stars","space","zoom","science","astronomy"],"k":[27,47]},"rice_cracker":{"a":"Rice Cracker","b":"1F358","j":["food","japanese"],"k":[7,26]},"hearts":{"a":"Black Heart Suit","b":"2665-FE0F","c":"2665","j":["poker","cards","magic","suits"],"k":[48,6],"o":1},"orthodox_cross":{"a":"Orthodox Cross","b":"2626-FE0F","c":"2626","j":["suppedaneum","religion"],"k":[47,35],"o":1},"milky_way":{"a":"Milky Way","b":"1F30C","j":["photo","space","stars"],"k":[6,4]},"rice_ball":{"a":"Rice Ball","b":"1F359","j":["food","japanese"],"k":[7,27]},"satellite_antenna":{"a":"Satellite Antenna","b":"1F4E1","k":[26,24]},"flag-co":{"a":"Colombia Flag","b":"1F1E8-1F1F4","k":[1,28]},"carousel_horse":{"a":"Carousel Horse","b":"1F3A0","j":["photo","carnival"],"k":[8,46]},"sob":{"a":"Loudly Crying Face","b":"1F62D","j":["face","cry","tears","sad","upset","depressed"],"k":[31,17],"m":":'("},"diamonds":{"a":"Black Diamond Suit","b":"2666-FE0F","c":"2666","j":["poker","cards","magic","suits"],"k":[48,7],"o":1},"star_and_crescent":{"a":"Star and Crescent","b":"262A-FE0F","c":"262A","j":["islam"],"k":[47,36],"o":1},"penguin":{"a":"Penguin","b":"1F427","j":["animal","nature"],"k":[13,17]},"dove_of_peace":{"a":"Dove of Peace","b":"1F54A-FE0F","c":"1F54A","k":[28,13],"o":7},"flag-cp":{"a":"Clipperton Island Flag","b":"1F1E8-1F1F5","k":[1,29]},"ferris_wheel":{"a":"Ferris Wheel","b":"1F3A1","j":["photo","carnival","londoneye"],"k":[8,47]},"clubs":{"a":"Black Club Suit","b":"2663-FE0F","c":"2663","j":["poker","cards","magic","suits"],"k":[48,5],"o":1},"peace_symbol":{"a":"Peace Symbol","b":"262E-FE0F","c":"262E","j":["hippie"],"k":[47,37],"o":1},"candle":{"a":"Candle","b":"1F56F-FE0F","c":"1F56F","j":["fire","wax"],"k":[28,42],"o":7},"frowning":{"a":"Frowning Face with Open Mouth","b":"1F626","j":["face","aw","what"],"k":[31,10]},"rice":{"a":"Cooked Rice","b":"1F35A","j":["food","china","asian"],"k":[7,28]},"flag-cr":{"a":"Costa Rica Flag","b":"1F1E8-1F1F7","k":[1,30]},"roller_coaster":{"a":"Roller Coaster","b":"1F3A2","j":["carnival","playground","photo","fun"],"k":[8,48]},"menorah_with_nine_branches":{"a":"Menorah with Nine Branches","b":"1F54E","k":[28,17],"o":8},"black_joker":{"a":"Playing Card Black Joker","b":"1F0CF","j":["poker","cards","game","play","magic"],"k":[0,15]},"eagle":{"a":"Eagle","b":"1F985","j":["animal","nature","bird"],"k":[42,29],"o":9},"curry":{"a":"Curry and Rice","b":"1F35B","j":["food","spicy","hot","indian"],"k":[7,29]},"bulb":{"a":"Electric Light Bulb","b":"1F4A1","j":["light","electricity","idea"],"k":[25,7]},"anguished":{"a":"Anguished Face","b":"1F627","j":["face","stunned","nervous"],"k":[31,11],"l":["D:"]},"flag-cu":{"a":"Cuba Flag","b":"1F1E8-1F1FA","k":[1,31]},"barber":{"a":"Barber Pole","b":"1F488","j":["hair","salon","style"],"k":[24,34]},"duck":{"a":"Duck","b":"1F986","j":["animal","nature","bird","mallard"],"k":[42,30],"o":9},"six_pointed_star":{"a":"Six Pointed Star with Middle Dot","b":"1F52F","j":["purple-square","religion","jewish","hexagram"],"k":[27,49]},"ramen":{"a":"Steaming Bowl","b":"1F35C","j":["food","japanese","noodle","chopsticks"],"k":[7,30]},"flashlight":{"a":"Electric Torch","b":"1F526","j":["dark","camping","sight","night"],"k":[27,40]},"mahjong":{"a":"Mahjong Tile Red Dragon","b":"1F004","j":["game","play","chinese","kanji"],"k":[0,14],"o":5},"fearful":{"a":"Fearful Face","b":"1F628","j":["face","scared","terrified","nervous","oops","huh"],"k":[31,12]},"aries":{"a":"Aries","b":"2648","j":["sign","purple-square","zodiac","astrology"],"k":[47,44],"o":1},"spaghetti":{"a":"Spaghetti","b":"1F35D","j":["food","italian","noodle"],"k":[7,31]},"circus_tent":{"a":"Circus Tent","b":"1F3AA","j":["festival","carnival","party"],"k":[9,4]},"izakaya_lantern":{"a":"Izakaya Lantern","b":"1F3EE","j":["light","paper","halloween","spooky"],"k":[12,11],"n":["lantern"]},"flag-cv":{"a":"Cape Verde Flag","b":"1F1E8-1F1FB","k":[1,32]},"weary":{"a":"Weary Face","b":"1F629","j":["face","tired","sleepy","sad","frustrated","upset"],"k":[31,13]},"flower_playing_cards":{"a":"Flower Playing Cards","b":"1F3B4","j":["game","sunset","red"],"k":[9,14]},"owl":{"a":"Owl","b":"1F989","j":["animal","nature","bird","hoot"],"k":[42,33],"o":9},"performing_arts":{"a":"Performing Arts","b":"1F3AD","j":["acting","theater","drama"],"k":[9,7]},"frog":{"a":"Frog Face","b":"1F438","j":["animal","nature","croak","toad"],"k":[13,34]},"flag-cw":{"a":"Curaçao Flag","b":"1F1E8-1F1FC","k":[1,33]},"notebook_with_decorative_cover":{"a":"Notebook with Decorative Cover","b":"1F4D4","j":["classroom","notes","record","paper","study"],"k":[26,11]},"exploding_head":{"a":"Shocked Face with Exploding Head","b":"1F92F","k":[39,3],"n":["shocked_face_with_exploding_head"],"o":10},"taurus":{"a":"Taurus","b":"2649","j":["purple-square","sign","zodiac","astrology"],"k":[47,45],"o":1},"sweet_potato":{"a":"Roasted Sweet Potato","b":"1F360","j":["food","nature"],"k":[7,34]},"closed_book":{"a":"Closed Book","b":"1F4D5","j":["read","library","knowledge","textbook","learn"],"k":[26,12]},"gemini":{"a":"Gemini","b":"264A","j":["sign","zodiac","purple-square","astrology"],"k":[47,46],"o":1},"frame_with_picture":{"a":"Frame with Picture","b":"1F5BC-FE0F","c":"1F5BC","k":[30,3],"o":7},"flag-cx":{"a":"Christmas Island Flag","b":"1F1E8-1F1FD","k":[1,34]},"grimacing":{"a":"Grimacing Face","b":"1F62C","j":["face","grimace","teeth"],"k":[31,16]},"crocodile":{"a":"Crocodile","b":"1F40A","j":["animal","nature","reptile","lizard","alligator"],"k":[12,40]},"oden":{"a":"Oden","b":"1F362","j":["food","japanese"],"k":[7,36]},"flag-cy":{"a":"Cyprus Flag","b":"1F1E8-1F1FE","k":[1,35]},"book":{"a":"Open Book","b":"1F4D6","k":[26,13],"n":["open_book"]},"turtle":{"a":"Turtle","b":"1F422","j":["animal","slow","nature","tortoise"],"k":[13,12]},"art":{"a":"Artist Palette","b":"1F3A8","j":["design","paint","draw","colors"],"k":[9,2]},"sushi":{"a":"Sushi","b":"1F363","j":["food","fish","japanese","rice"],"k":[7,37]},"cold_sweat":{"a":"Face with Open Mouth and Cold Sweat","b":"1F630","j":["face","nervous","sweat"],"k":[31,20]},"cancer":{"a":"Cancer","b":"264B","j":["sign","zodiac","purple-square","astrology"],"k":[47,47],"o":1},"fried_shrimp":{"a":"Fried Shrimp","b":"1F364","j":["food","animal","appetizer","summer"],"k":[7,38]},"slot_machine":{"a":"Slot Machine","b":"1F3B0","j":["bet","gamble","vegas","fruit machine","luck","casino"],"k":[9,10]},"scream":{"a":"Face Screaming in Fear","b":"1F631","j":["face","munch","scared","omg"],"k":[31,21]},"green_book":{"a":"Green Book","b":"1F4D7","j":["read","library","knowledge","study"],"k":[26,14]},"leo":{"a":"Leo","b":"264C","j":["sign","purple-square","zodiac","astrology"],"k":[47,48],"o":1},"flag-cz":{"a":"Czechia Flag","b":"1F1E8-1F1FF","k":[1,36]},"lizard":{"a":"Lizard","b":"1F98E","j":["animal","nature","reptile"],"k":[42,38],"o":9},"virgo":{"a":"Virgo","b":"264D","j":["sign","zodiac","purple-square","astrology"],"k":[47,49],"o":1},"steam_locomotive":{"a":"Steam Locomotive","b":"1F682","j":["transportation","vehicle","train"],"k":[34,10]},"de":{"a":"Germany Flag","b":"1F1E9-1F1EA","j":["german","nation","flag","country","banner"],"k":[1,37],"n":["flag-de"]},"flushed":{"a":"Flushed Face","b":"1F633","j":["face","blush","shy","flattered"],"k":[31,23]},"blue_book":{"a":"Blue Book","b":"1F4D8","j":["read","library","knowledge","learn","study"],"k":[26,15]},"snake":{"a":"Snake","b":"1F40D","j":["animal","evil","nature","hiss","python"],"k":[12,43]},"fish_cake":{"a":"Fish Cake with Swirl Design","b":"1F365","j":["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],"k":[7,39]},"railway_car":{"a":"Railway Car","b":"1F683","j":["transportation","vehicle"],"k":[34,11]},"dango":{"a":"Dango","b":"1F361","j":["food","dessert","sweet","japanese","barbecue","meat"],"k":[7,35]},"orange_book":{"a":"Orange Book","b":"1F4D9","j":["read","library","knowledge","textbook","study"],"k":[26,16]},"libra":{"a":"Libra","b":"264E","j":["sign","purple-square","zodiac","astrology"],"k":[47,50],"o":1},"dragon_face":{"a":"Dragon Face","b":"1F432","j":["animal","myth","nature","chinese","green"],"k":[13,28]},"flag-dg":{"a":"Diego Garcia Flag","b":"1F1E9-1F1EC","k":[1,38]},"zany_face":{"a":"Grinning Face with One Large and One Small Eye","b":"1F92A","k":[38,50],"n":["grinning_face_with_one_large_and_one_small_eye"],"o":10},"books":{"a":"Books","b":"1F4DA","j":["literature","library","study"],"k":[26,17]},"dragon":{"a":"Dragon","b":"1F409","j":["animal","myth","nature","chinese","green"],"k":[12,39]},"flag-dj":{"a":"Djibouti Flag","b":"1F1E9-1F1EF","k":[1,39]},"dumpling":{"a":"Dumpling","b":"1F95F","k":[42,11],"o":10},"dizzy_face":{"a":"Dizzy Face","b":"1F635","j":["spent","unconscious","xox","dizzy"],"k":[31,25]},"scorpius":{"a":"Scorpius","b":"264F","j":["sign","zodiac","purple-square","astrology","scorpio"],"k":[47,51],"o":1},"bullettrain_side":{"a":"High-Speed Train","b":"1F684","j":["transportation","vehicle"],"k":[34,12]},"bullettrain_front":{"a":"High-Speed Train with Bullet Nose","b":"1F685","j":["transportation","vehicle","speed","fast","public","travel"],"k":[34,13]},"notebook":{"a":"Notebook","b":"1F4D3","j":["stationery","record","notes","paper","study"],"k":[26,10]},"fortune_cookie":{"a":"Fortune Cookie","b":"1F960","k":[42,12],"o":10},"sagittarius":{"a":"Sagittarius","b":"2650","j":["sign","zodiac","purple-square","astrology"],"k":[48,0],"o":1},"sauropod":{"a":"Sauropod","b":"1F995","k":[42,45],"o":10},"flag-dk":{"a":"Denmark Flag","b":"1F1E9-1F1F0","k":[1,40]},"rage":{"a":"Pouting Face","b":"1F621","j":["angry","mad","hate","despise"],"k":[31,5]},"ledger":{"a":"Ledger","b":"1F4D2","j":["notes","paper"],"k":[26,9]},"angry":{"a":"Angry Face","b":"1F620","j":["mad","face","annoyed","frustrated"],"k":[31,4],"l":[">:(",">:-("]},"t-rex":{"a":"T-Rex","b":"1F996","k":[42,46],"o":10},"capricorn":{"a":"Capricorn","b":"2651","j":["sign","zodiac","purple-square","astrology"],"k":[48,1],"o":1},"takeout_box":{"a":"Takeout Box","b":"1F961","k":[42,13],"o":10},"flag-dm":{"a":"Dominica Flag","b":"1F1E9-1F1F2","k":[1,41]},"train2":{"a":"Train","b":"1F686","j":["transportation","vehicle"],"k":[34,14]},"page_with_curl":{"a":"Page with Curl","b":"1F4C3","j":["documents","office","paper"],"k":[25,46]},"whale":{"a":"Spouting Whale","b":"1F433","j":["animal","nature","sea","ocean"],"k":[13,29]},"face_with_symbols_on_mouth":{"a":"Serious Face with Symbols Covering Mouth","b":"1F92C","k":[39,0],"n":["serious_face_with_symbols_covering_mouth"],"o":10},"flag-do":{"a":"Dominican Republic Flag","b":"1F1E9-1F1F4","k":[1,42]},"metro":{"a":"Metro","b":"1F687","j":["transportation","blue-square","mrt","underground","tube"],"k":[34,15]},"icecream":{"a":"Soft Ice Cream","b":"1F366","j":["food","hot","dessert","summer"],"k":[7,40]},"aquarius":{"a":"Aquarius","b":"2652","j":["sign","purple-square","zodiac","astrology"],"k":[48,2],"o":1},"flag-dz":{"a":"Algeria Flag","b":"1F1E9-1F1FF","k":[1,43]},"whale2":{"a":"Whale","b":"1F40B","j":["animal","nature","sea","ocean"],"k":[12,41]},"mask":{"a":"Face with Medical Mask","b":"1F637","j":["face","sick","ill","disease"],"k":[31,27]},"scroll":{"a":"Scroll","b":"1F4DC","j":["documents","ancient","history","paper"],"k":[26,19]},"shaved_ice":{"a":"Shaved Ice","b":"1F367","j":["hot","dessert","summer"],"k":[7,41]},"pisces":{"a":"Pisces","b":"2653","j":["purple-square","sign","zodiac","astrology"],"k":[48,3],"o":1},"light_rail":{"a":"Light Rail","b":"1F688","j":["transportation","vehicle"],"k":[34,16]},"dolphin":{"a":"Dolphin","b":"1F42C","j":["animal","nature","fish","sea","ocean","flipper","fins","beach"],"k":[13,22],"n":["flipper"]},"face_with_thermometer":{"a":"Face with Thermometer","b":"1F912","j":["sick","temperature","thermometer","cold","fever"],"k":[37,26],"o":8},"flag-ea":{"a":"Ceuta & Melilla Flag","b":"1F1EA-1F1E6","k":[1,44]},"ophiuchus":{"a":"Ophiuchus","b":"26CE","j":["sign","purple-square","constellation","astrology"],"k":[48,31]},"station":{"a":"Station","b":"1F689","j":["transportation","vehicle","public"],"k":[34,17]},"ice_cream":{"a":"Ice Cream","b":"1F368","j":["food","hot","dessert"],"k":[7,42]},"page_facing_up":{"a":"Page Facing Up","b":"1F4C4","j":["documents","office","paper","information"],"k":[25,47]},"doughnut":{"a":"Doughnut","b":"1F369","j":["food","dessert","snack","sweet","donut"],"k":[7,43]},"face_with_head_bandage":{"a":"Face with Head-Bandage","b":"1F915","j":["injured","clumsy","bandage","hurt"],"k":[37,29],"o":8},"fish":{"a":"Fish","b":"1F41F","j":["animal","food","nature"],"k":[13,9]},"newspaper":{"a":"Newspaper","b":"1F4F0","j":["press","headline"],"k":[26,39]},"tram":{"a":"Tram","b":"1F68A","j":["transportation","vehicle"],"k":[34,18]},"flag-ec":{"a":"Ecuador Flag","b":"1F1EA-1F1E8","k":[1,45]},"twisted_rightwards_arrows":{"a":"Twisted Rightwards Arrows","b":"1F500","j":["blue-square","shuffle","music","random"],"k":[27,2]},"flag-ee":{"a":"Estonia Flag","b":"1F1EA-1F1EA","k":[1,46]},"cookie":{"a":"Cookie","b":"1F36A","j":["food","snack","oreo","chocolate","sweet","dessert"],"k":[7,44]},"monorail":{"a":"Monorail","b":"1F69D","j":["transportation","vehicle"],"k":[34,37]},"tropical_fish":{"a":"Tropical Fish","b":"1F420","j":["animal","swim","ocean","beach","nemo"],"k":[13,10]},"rolled_up_newspaper":{"a":"Rolled Up Newspaper","b":"1F5DE-FE0F","c":"1F5DE","k":[30,12],"o":7},"nauseated_face":{"a":"Nauseated Face","b":"1F922","j":["face","vomit","gross","green","sick","throw up","ill"],"k":[38,25],"o":9},"repeat":{"a":"Clockwise Rightwards and Leftwards Open Circle Arrows","b":"1F501","j":["loop","record"],"k":[27,3]},"bookmark_tabs":{"a":"Bookmark Tabs","b":"1F4D1","j":["favorite","save","order","tidy"],"k":[26,8]},"repeat_one":{"a":"Clockwise Rightwards and Leftwards Open Circle Arrows with Circled One Overlay","b":"1F502","j":["blue-square","loop"],"k":[27,4]},"flag-eg":{"a":"Egypt Flag","b":"1F1EA-1F1EC","k":[1,47]},"mountain_railway":{"a":"Mountain Railway","b":"1F69E","j":["transportation","vehicle"],"k":[34,38]},"birthday":{"a":"Birthday Cake","b":"1F382","j":["food","dessert","cake"],"k":[8,16]},"blowfish":{"a":"Blowfish","b":"1F421","j":["animal","nature","food","sea","ocean"],"k":[13,11]},"face_vomiting":{"a":"Face with Open Mouth Vomiting","b":"1F92E","k":[39,2],"n":["face_with_open_mouth_vomiting"],"o":10},"arrow_forward":{"a":"Black Right-Pointing Triangle","b":"25B6-FE0F","c":"25B6","j":["blue-square","right","direction","play"],"k":[47,10],"o":1},"bookmark":{"a":"Bookmark","b":"1F516","j":["favorite","label","save"],"k":[27,24]},"flag-eh":{"a":"Western Sahara Flag","b":"1F1EA-1F1ED","k":[1,48]},"shark":{"a":"Shark","b":"1F988","j":["animal","nature","fish","sea","ocean","jaws","fins","beach"],"k":[42,32],"o":9},"train":{"a":"Tram Car","b":"1F68B","j":["transportation","vehicle","carriage","public","travel"],"k":[34,19]},"sneezing_face":{"a":"Sneezing Face","b":"1F927","j":["face","gesundheit","sneeze","sick","allergy"],"k":[38,47],"o":9},"cake":{"a":"Shortcake","b":"1F370","j":["food","dessert"],"k":[7,50]},"bus":{"a":"Bus","b":"1F68C","j":["car","vehicle","transportation"],"k":[34,20]},"pie":{"a":"Pie","b":"1F967","k":[42,19],"o":10},"innocent":{"a":"Smiling Face with Halo","b":"1F607","j":["face","angel","heaven","halo"],"k":[30,31]},"fast_forward":{"a":"Black Right-Pointing Double Triangle","b":"23E9","j":["blue-square","play","speed","continue"],"k":[46,45]},"label":{"a":"Label","b":"1F3F7-FE0F","c":"1F3F7","j":["sale","tag"],"k":[12,21],"o":7},"octopus":{"a":"Octopus","b":"1F419","j":["animal","creature","ocean","sea","nature","beach"],"k":[13,3]},"flag-er":{"a":"Eritrea Flag","b":"1F1EA-1F1F7","k":[1,49]},"black_right_pointing_double_triangle_with_vertical_bar":{"a":"Black Right Pointing Double Triangle with Vertical Bar","b":"23ED-FE0F","c":"23ED","k":[46,49]},"chocolate_bar":{"a":"Chocolate Bar","b":"1F36B","j":["food","snack","dessert","sweet"],"k":[7,45]},"oncoming_bus":{"a":"Oncoming Bus","b":"1F68D","j":["vehicle","transportation"],"k":[34,21]},"shell":{"a":"Spiral Shell","b":"1F41A","j":["nature","sea","beach"],"k":[13,4]},"face_with_cowboy_hat":{"a":"Face with Cowboy Hat","b":"1F920","k":[38,23],"o":9},"moneybag":{"a":"Money Bag","b":"1F4B0","j":["dollar","payment","coins","sale"],"k":[25,27]},"es":{"a":"Spain Flag","b":"1F1EA-1F1F8","j":["spain","flag","nation","country","banner"],"k":[1,50],"n":["flag-es"]},"crab":{"a":"Crab","b":"1F980","j":["animal","crustacean"],"k":[42,24],"o":8},"yen":{"a":"Banknote with Yen Sign","b":"1F4B4","j":["money","sales","japanese","dollar","currency"],"k":[25,31]},"flag-et":{"a":"Ethiopia Flag","b":"1F1EA-1F1F9","k":[1,51]},"clown_face":{"a":"Clown Face","b":"1F921","j":["face"],"k":[38,24],"o":9},"black_right_pointing_triangle_with_double_vertical_bar":{"a":"Black Right Pointing Triangle with Double Vertical Bar","b":"23EF-FE0F","c":"23EF","k":[46,51]},"trolleybus":{"a":"Trolleybus","b":"1F68E","j":["bart","transportation","vehicle"],"k":[34,22]},"candy":{"a":"Candy","b":"1F36C","j":["snack","dessert","sweet","lolly"],"k":[7,46]},"lying_face":{"a":"Lying Face","b":"1F925","j":["face","lie","pinocchio"],"k":[38,28],"o":9},"arrow_backward":{"a":"Black Left-Pointing Triangle","b":"25C0-FE0F","c":"25C0","j":["blue-square","left","direction"],"k":[47,11],"o":1},"dollar":{"a":"Banknote with Dollar Sign","b":"1F4B5","j":["money","sales","bill","currency"],"k":[25,32]},"shrimp":{"a":"Shrimp","b":"1F990","j":["animal","ocean","nature","seafood"],"k":[42,40],"o":9},"minibus":{"a":"Minibus","b":"1F690","j":["vehicle","car","transportation"],"k":[34,24]},"flag-eu":{"a":"European Union Flag","b":"1F1EA-1F1FA","k":[2,0]},"lollipop":{"a":"Lollipop","b":"1F36D","j":["food","snack","candy","sweet"],"k":[7,47]},"squid":{"a":"Squid","b":"1F991","j":["animal","nature","ocean","sea"],"k":[42,41],"o":9},"euro":{"a":"Banknote with Euro Sign","b":"1F4B6","j":["money","sales","dollar","currency"],"k":[25,33]},"flag-fi":{"a":"Finland Flag","b":"1F1EB-1F1EE","k":[2,1]},"ambulance":{"a":"Ambulance","b":"1F691","j":["health","911","hospital"],"k":[34,25]},"custard":{"a":"Custard","b":"1F36E","j":["dessert","food"],"k":[7,48]},"shushing_face":{"a":"Face with Finger Covering Closed Lips","b":"1F92B","k":[38,51],"n":["face_with_finger_covering_closed_lips"],"o":10},"rewind":{"a":"Black Left-Pointing Double Triangle","b":"23EA","j":["play","blue-square"],"k":[46,46]},"black_left_pointing_double_triangle_with_vertical_bar":{"a":"Black Left Pointing Double Triangle with Vertical Bar","b":"23EE-FE0F","c":"23EE","k":[46,50]},"face_with_hand_over_mouth":{"a":"Smiling Face with Smiling Eyes and Hand Covering Mouth","b":"1F92D","k":[39,1],"n":["smiling_face_with_smiling_eyes_and_hand_covering_mouth"],"o":10},"flag-fj":{"a":"Fiji Flag","b":"1F1EB-1F1EF","k":[2,2]},"honey_pot":{"a":"Honey Pot","b":"1F36F","j":["bees","sweet","kitchen"],"k":[7,49]},"snail":{"a":"Snail","b":"1F40C","j":["slow","animal","shell"],"k":[12,42]},"pound":{"a":"Banknote with Pound Sign","b":"1F4B7","j":["british","sterling","money","sales","bills","uk","england","currency"],"k":[25,34]},"fire_engine":{"a":"Fire Engine","b":"1F692","j":["transportation","cars","vehicle"],"k":[34,26]},"baby_bottle":{"a":"Baby Bottle","b":"1F37C","j":["food","container","milk"],"k":[8,10]},"flag-fk":{"a":"Falkland Islands Flag","b":"1F1EB-1F1F0","k":[2,3]},"butterfly":{"a":"Butterfly","b":"1F98B","j":["animal","insect","nature","caterpillar"],"k":[42,35],"o":9},"money_with_wings":{"a":"Money with Wings","b":"1F4B8","j":["dollar","bills","payment","sale"],"k":[25,35]},"face_with_monocle":{"a":"Face with Monocle","b":"1F9D0","k":[42,49],"o":10},"police_car":{"a":"Police Car","b":"1F693","j":["vehicle","cars","transportation","law","legal","enforcement"],"k":[34,27]},"arrow_up_small":{"a":"Up-Pointing Small Red Triangle","b":"1F53C","j":["blue-square","triangle","direction","point","forward","top"],"k":[28,10]},"flag-fm":{"a":"Micronesia Flag","b":"1F1EB-1F1F2","k":[2,4]},"glass_of_milk":{"a":"Glass of Milk","b":"1F95B","k":[42,7],"o":9},"credit_card":{"a":"Credit Card","b":"1F4B3","j":["money","sales","dollar","bill","payment","shopping"],"k":[25,30]},"oncoming_police_car":{"a":"Oncoming Police Car","b":"1F694","j":["vehicle","law","legal","enforcement","911"],"k":[34,28]},"bug":{"a":"Bug","b":"1F41B","j":["animal","insect","nature","worm"],"k":[13,5]},"nerd_face":{"a":"Nerd Face","b":"1F913","j":["face","nerdy","geek","dork"],"k":[37,27],"o":8},"arrow_double_up":{"a":"Black Up-Pointing Double Triangle","b":"23EB","j":["blue-square","direction","top"],"k":[46,47]},"chart":{"a":"Chart with Upwards Trend and Yen Sign","b":"1F4B9","j":["green-square","graph","presentation","stats"],"k":[25,36]},"flag-fo":{"a":"Faroe Islands Flag","b":"1F1EB-1F1F4","k":[2,5]},"ant":{"a":"Ant","b":"1F41C","j":["animal","insect","nature","bug"],"k":[13,6]},"arrow_down_small":{"a":"Down-Pointing Small Red Triangle","b":"1F53D","j":["blue-square","direction","bottom"],"k":[28,11]},"smiling_imp":{"a":"Smiling Face with Horns","b":"1F608","j":["devil","horns"],"k":[30,32]},"taxi":{"a":"Taxi","b":"1F695","j":["uber","vehicle","cars","transportation"],"k":[34,29]},"coffee":{"a":"Hot Beverage","b":"2615","j":["beverage","caffeine","latte","espresso"],"k":[47,24],"o":4},"fr":{"a":"France Flag","b":"1F1EB-1F1F7","j":["banner","flag","nation","france","french","country"],"k":[2,6],"n":["flag-fr"]},"oncoming_taxi":{"a":"Oncoming Taxi","b":"1F696","j":["vehicle","cars","uber"],"k":[34,30]},"arrow_double_down":{"a":"Black Down-Pointing Double Triangle","b":"23EC","j":["blue-square","direction","bottom"],"k":[46,48]},"imp":{"a":"Imp","b":"1F47F","j":["devil","angry","horns"],"k":[22,51]},"currency_exchange":{"a":"Currency Exchange","b":"1F4B1","j":["money","sales","dollar","travel"],"k":[25,28]},"tea":{"a":"Teacup Without Handle","b":"1F375","j":["drink","bowl","breakfast","green","british"],"k":[8,3]},"bee":{"a":"Honeybee","b":"1F41D","k":[13,7],"n":["honeybee"]},"heavy_dollar_sign":{"a":"Heavy Dollar Sign","b":"1F4B2","j":["money","sales","payment","currency","buck"],"k":[25,29]},"car":{"a":"Automobile","b":"1F697","k":[34,31],"n":["red_car"]},"sake":{"a":"Sake Bottle and Cup","b":"1F376","j":["wine","drink","drunk","beverage","japanese","alcohol","booze"],"k":[8,4]},"flag-ga":{"a":"Gabon Flag","b":"1F1EC-1F1E6","k":[2,7]},"beetle":{"a":"Lady Beetle","b":"1F41E","j":["animal","insect","nature","ladybug"],"k":[13,8]},"japanese_ogre":{"a":"Japanese Ogre","b":"1F479","j":["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],"k":[22,40]},"double_vertical_bar":{"a":"Double Vertical Bar","b":"23F8-FE0F","c":"23F8","k":[47,4],"o":7},"champagne":{"a":"Bottle with Popping Cork","b":"1F37E","j":["drink","wine","bottle","celebration"],"k":[8,12],"o":8},"japanese_goblin":{"a":"Japanese Goblin","b":"1F47A","j":["red","evil","mask","monster","scary","creepy","japanese","goblin"],"k":[22,41]},"black_square_for_stop":{"a":"Black Square for Stop","b":"23F9-FE0F","c":"23F9","k":[47,5],"o":7},"oncoming_automobile":{"a":"Oncoming Automobile","b":"1F698","j":["car","vehicle","transportation"],"k":[34,32]},"email":{"a":"Envelope","b":"2709-FE0F","c":"2709","j":["letter","postal","inbox","communication"],"k":[49,17],"n":["envelope"],"o":1},"cricket":{"a":"Cricket","b":"1F997","j":["sports"],"k":[42,47],"o":10},"gb":{"a":"United Kingdom Flag","b":"1F1EC-1F1E7","k":[2,8],"n":["uk","flag-gb"]},"black_circle_for_record":{"a":"Black Circle for Record","b":"23FA-FE0F","c":"23FA","k":[47,6],"o":7},"flag-gd":{"a":"Grenada Flag","b":"1F1EC-1F1E9","k":[2,9]},"spider":{"a":"Spider","b":"1F577-FE0F","c":"1F577","j":["animal","arachnid"],"k":[29,18],"o":7},"blue_car":{"a":"Recreational Vehicle","b":"1F699","j":["transportation","vehicle"],"k":[34,33]},"skull":{"a":"Skull","b":"1F480","j":["dead","skeleton","creepy","death"],"k":[23,0]},"e-mail":{"a":"E-Mail Symbol","b":"1F4E7","j":["communication","inbox"],"k":[26,30]},"wine_glass":{"a":"Wine Glass","b":"1F377","j":["drink","beverage","drunk","alcohol","booze"],"k":[8,5]},"spider_web":{"a":"Spider Web","b":"1F578-FE0F","c":"1F578","j":["animal","insect","arachnid","silk"],"k":[29,19],"o":7},"cocktail":{"a":"Cocktail Glass","b":"1F378","j":["drink","drunk","alcohol","beverage","booze","mojito"],"k":[8,6]},"skull_and_crossbones":{"a":"Skull and Crossbones","b":"2620-FE0F","c":"2620","j":["poison","danger","deadly","scary","death","pirate","evil"],"k":[47,32],"o":1},"flag-ge":{"a":"Georgia Flag","b":"1F1EC-1F1EA","k":[2,10]},"eject":{"a":"Eject","b":"23CF-FE0F","c":"23CF","k":[46,44],"o":4},"truck":{"a":"Delivery Truck","b":"1F69A","j":["cars","transportation"],"k":[34,34]},"incoming_envelope":{"a":"Incoming Envelope","b":"1F4E8","j":["email","inbox"],"k":[26,31]},"tropical_drink":{"a":"Tropical Drink","b":"1F379","j":["beverage","cocktail","summer","beach","alcohol","booze","mojito"],"k":[8,7]},"scorpion":{"a":"Scorpion","b":"1F982","j":["animal","arachnid"],"k":[42,26],"o":8},"cinema":{"a":"Cinema","b":"1F3A6","j":["blue-square","record","film","movie","curtain","stage","theater"],"k":[9,0]},"articulated_lorry":{"a":"Articulated Lorry","b":"1F69B","j":["vehicle","cars","transportation","express"],"k":[34,35]},"envelope_with_arrow":{"a":"Envelope with Downwards Arrow Above","b":"1F4E9","j":["email","communication"],"k":[26,32]},"ghost":{"a":"Ghost","b":"1F47B","j":["halloween","spooky","scary"],"k":[22,42]},"flag-gf":{"a":"French Guiana Flag","b":"1F1EC-1F1EB","k":[2,11]},"bouquet":{"a":"Bouquet","b":"1F490","j":["flowers","nature","spring"],"k":[24,42]},"tractor":{"a":"Tractor","b":"1F69C","j":["vehicle","car","farming","agriculture"],"k":[34,36]},"beer":{"a":"Beer Mug","b":"1F37A","j":["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],"k":[8,8]},"outbox_tray":{"a":"Outbox Tray","b":"1F4E4","j":["inbox","email"],"k":[26,27]},"low_brightness":{"a":"Low Brightness Symbol","b":"1F505","j":["sun","afternoon","warm","summer"],"k":[27,7]},"alien":{"a":"Extraterrestrial Alien","b":"1F47D","j":["UFO","paul","weird","outer_space"],"k":[22,49]},"flag-gg":{"a":"Guernsey Flag","b":"1F1EC-1F1EC","k":[2,12]},"cherry_blossom":{"a":"Cherry Blossom","b":"1F338","j":["nature","plant","spring","flower"],"k":[6,46]},"inbox_tray":{"a":"Inbox Tray","b":"1F4E5","j":["email","documents"],"k":[26,28]},"flag-gh":{"a":"Ghana Flag","b":"1F1EC-1F1ED","k":[2,13]},"bike":{"a":"Bicycle","b":"1F6B2","j":["sports","bicycle","exercise","hipster"],"k":[35,23]},"space_invader":{"a":"Alien Monster","b":"1F47E","j":["game","arcade","play"],"k":[22,50]},"beers":{"a":"Clinking Beer Mugs","b":"1F37B","j":["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],"k":[8,9]},"high_brightness":{"a":"High Brightness Symbol","b":"1F506","j":["sun","light"],"k":[27,8]},"package":{"a":"Package","b":"1F4E6","j":["mail","gift","cardboard","box","moving"],"k":[26,29]},"scooter":{"a":"Scooter","b":"1F6F4","k":[37,19],"o":9},"white_flower":{"a":"White Flower","b":"1F4AE","j":["japanese","spring"],"k":[25,25]},"clinking_glasses":{"a":"Clinking Glasses","b":"1F942","j":["beverage","drink","party","alcohol","celebrate","cheers"],"k":[41,38],"o":9},"robot_face":{"a":"Robot Face","b":"1F916","k":[37,30],"o":8},"signal_strength":{"a":"Antenna with Bars","b":"1F4F6","j":["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],"k":[26,45]},"flag-gi":{"a":"Gibraltar Flag","b":"1F1EC-1F1EE","k":[2,14]},"flag-gl":{"a":"Greenland Flag","b":"1F1EC-1F1F1","k":[2,15]},"motor_scooter":{"a":"Motor Scooter","b":"1F6F5","j":["vehicle","vespa","sasha"],"k":[37,20],"o":9},"mailbox":{"a":"Closed Mailbox with Raised Flag","b":"1F4EB","j":["email","inbox","communication"],"k":[26,34]},"vibration_mode":{"a":"Vibration Mode","b":"1F4F3","j":["orange-square","phone"],"k":[26,42]},"hankey":{"a":"Pile of Poo","b":"1F4A9","k":[25,15],"n":["poop","shit"]},"rosette":{"a":"Rosette","b":"1F3F5-FE0F","c":"1F3F5","j":["flower","decoration","military"],"k":[12,20],"o":7},"tumbler_glass":{"a":"Tumbler Glass","b":"1F943","j":["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],"k":[41,39],"o":9},"cup_with_straw":{"a":"Cup with Straw","b":"1F964","k":[42,16],"o":10},"flag-gm":{"a":"Gambia Flag","b":"1F1EC-1F1F2","k":[2,16]},"mailbox_closed":{"a":"Closed Mailbox with Lowered Flag","b":"1F4EA","j":["email","communication","inbox"],"k":[26,33]},"mobile_phone_off":{"a":"Mobile Phone off","b":"1F4F4","j":["mute","orange-square","silence","quiet"],"k":[26,43]},"busstop":{"a":"Bus Stop","b":"1F68F","j":["transportation","wait"],"k":[34,23]},"smiley_cat":{"a":"Smiling Cat Face with Open Mouth","b":"1F63A","j":["animal","cats","happy","smile"],"k":[31,30]},"rose":{"a":"Rose","b":"1F339","j":["flowers","valentines","love","spring"],"k":[6,47]},"motorway":{"a":"Motorway","b":"1F6E3-FE0F","c":"1F6E3","j":["road","cupertino","interstate","highway"],"k":[37,11],"o":7},"smile_cat":{"a":"Grinning Cat Face with Smiling Eyes","b":"1F638","j":["animal","cats","smile"],"k":[31,28]},"flag-gn":{"a":"Guinea Flag","b":"1F1EC-1F1F3","k":[2,17]},"wilted_flower":{"a":"Wilted Flower","b":"1F940","j":["plant","nature","flower"],"k":[41,36],"o":9},"mailbox_with_mail":{"a":"Open Mailbox with Raised Flag","b":"1F4EC","j":["email","inbox","communication"],"k":[26,35]},"chopsticks":{"a":"Chopsticks","b":"1F962","k":[42,14],"o":10},"mailbox_with_no_mail":{"a":"Open Mailbox with Lowered Flag","b":"1F4ED","j":["email","inbox"],"k":[26,36]},"knife_fork_plate":{"a":"Knife Fork Plate","b":"1F37D-FE0F","c":"1F37D","k":[8,11],"o":7},"hibiscus":{"a":"Hibiscus","b":"1F33A","j":["plant","vegetable","flowers","beach"],"k":[6,48]},"flag-gp":{"a":"Guadeloupe Flag","b":"1F1EC-1F1F5","k":[2,18]},"railway_track":{"a":"Railway Track","b":"1F6E4-FE0F","c":"1F6E4","j":["train","transportation"],"k":[37,12],"o":7},"joy_cat":{"a":"Cat Face with Tears of Joy","b":"1F639","j":["animal","cats","haha","happy","tears"],"k":[31,29]},"fuelpump":{"a":"Fuel Pump","b":"26FD","j":["gas station","petroleum"],"k":[49,13],"o":5},"sunflower":{"a":"Sunflower","b":"1F33B","j":["nature","plant","fall"],"k":[6,49]},"postbox":{"a":"Postbox","b":"1F4EE","j":["email","letter","envelope"],"k":[26,37]},"flag-gq":{"a":"Equatorial Guinea Flag","b":"1F1EC-1F1F6","k":[2,19]},"heart_eyes_cat":{"a":"Smiling Cat Face with Heart-Shaped Eyes","b":"1F63B","j":["animal","love","like","affection","cats","valentines","heart"],"k":[31,31]},"fork_and_knife":{"a":"Fork and Knife","b":"1F374","j":["cutlery","kitchen"],"k":[8,2]},"recycle":{"a":"Black Universal Recycling Symbol","b":"267B-FE0F","c":"267B","j":["arrow","environment","garbage","trash"],"k":[48,9],"o":3},"spoon":{"a":"Spoon","b":"1F944","j":["cutlery","kitchen","tableware"],"k":[41,40],"o":9},"blossom":{"a":"Blossom","b":"1F33C","j":["nature","flowers","yellow"],"k":[6,50]},"rotating_light":{"a":"Police Cars Revolving Light","b":"1F6A8","j":["police","ambulance","911","emergency","alert","error","pinged","law","legal"],"k":[35,13]},"smirk_cat":{"a":"Cat Face with Wry Smile","b":"1F63C","j":["animal","cats","smirk"],"k":[31,32]},"ballot_box_with_ballot":{"a":"Ballot Box with Ballot","b":"1F5F3-FE0F","c":"1F5F3","k":[30,17],"o":7},"flag-gr":{"a":"Greece Flag","b":"1F1EC-1F1F7","k":[2,20]},"kissing_cat":{"a":"Kissing Cat Face with Closed Eyes","b":"1F63D","j":["animal","cats","kiss"],"k":[31,33]},"pencil2":{"a":"Pencil","b":"270F-FE0F","c":"270F","j":["stationery","write","paper","writing","school","study"],"k":[49,42],"o":1},"traffic_light":{"a":"Horizontal Traffic Light","b":"1F6A5","j":["transportation","signal"],"k":[35,10]},"fleur_de_lis":{"a":"Fleur De Lis","b":"269C-FE0F","c":"269C","j":["decorative","scout"],"k":[48,19],"o":4},"tulip":{"a":"Tulip","b":"1F337","j":["flowers","plant","nature","summer","spring"],"k":[6,45]},"hocho":{"a":"Hocho","b":"1F52A","j":["knife","blade","cutlery","kitchen","weapon"],"k":[27,44],"n":["knife"]},"flag-gs":{"a":"South Georgia & South Sandwich Islands Flag","b":"1F1EC-1F1F8","k":[2,21]},"seedling":{"a":"Seedling","b":"1F331","j":["plant","nature","grass","lawn","spring"],"k":[6,39]},"amphora":{"a":"Amphora","b":"1F3FA","j":["vase","jar"],"k":[12,24],"o":8},"scream_cat":{"a":"Weary Cat Face","b":"1F640","j":["animal","cats","munch","scared","scream"],"k":[31,36]},"vertical_traffic_light":{"a":"Vertical Traffic Light","b":"1F6A6","j":["transportation","driving"],"k":[35,11]},"black_nib":{"a":"Black Nib","b":"2712-FE0F","c":"2712","j":["pen","stationery","writing","write"],"k":[49,43],"o":1},"flag-gt":{"a":"Guatemala Flag","b":"1F1EC-1F1F9","k":[2,22]},"trident":{"a":"Trident Emblem","b":"1F531","j":["weapon","spear"],"k":[27,51]},"flag-gu":{"a":"Guam Flag","b":"1F1EC-1F1FA","k":[2,23]},"name_badge":{"a":"Name Badge","b":"1F4DB","j":["fire","forbid"],"k":[26,18]},"construction":{"a":"Construction Sign","b":"1F6A7","j":["wip","progress","caution","warning"],"k":[35,12]},"lower_left_fountain_pen":{"a":"Lower Left Fountain Pen","b":"1F58B-FE0F","c":"1F58B","k":[29,29],"o":7},"evergreen_tree":{"a":"Evergreen Tree","b":"1F332","j":["plant","nature"],"k":[6,40]},"crying_cat_face":{"a":"Crying Cat Face","b":"1F63F","j":["animal","tears","weep","sad","cats","upset","cry"],"k":[31,35]},"flag-gw":{"a":"Guinea-Bissau Flag","b":"1F1EC-1F1FC","k":[2,24]},"lower_left_ballpoint_pen":{"a":"Lower Left Ballpoint Pen","b":"1F58A-FE0F","c":"1F58A","k":[29,28],"o":7},"pouting_cat":{"a":"Pouting Cat Face","b":"1F63E","j":["animal","cats"],"k":[31,34]},"deciduous_tree":{"a":"Deciduous Tree","b":"1F333","j":["plant","nature"],"k":[6,41]},"octagonal_sign":{"a":"Octagonal Sign","b":"1F6D1","k":[37,6],"o":9},"beginner":{"a":"Japanese Symbol for Beginner","b":"1F530","j":["badge","shield"],"k":[27,50]},"flag-gy":{"a":"Guyana Flag","b":"1F1EC-1F1FE","k":[2,25]},"lower_left_paintbrush":{"a":"Lower Left Paintbrush","b":"1F58C-FE0F","c":"1F58C","k":[29,30],"o":7},"o":{"a":"Heavy Large Circle","b":"2B55","j":["circle","round"],"k":[50,23],"o":5},"palm_tree":{"a":"Palm Tree","b":"1F334","j":["plant","vegetable","nature","summer","beach","mojito","tropical"],"k":[6,42]},"anchor":{"a":"Anchor","b":"2693","j":["ship","ferry","sea","boat"],"k":[48,12],"o":4},"see_no_evil":{"a":"See-No-Evil Monkey","b":"1F648","j":["monkey","animal","nature","haha"],"k":[32,43]},"boat":{"a":"Sailboat","b":"26F5","k":[48,43],"n":["sailboat"],"o":5},"white_check_mark":{"a":"White Heavy Check Mark","b":"2705","j":["green-square","ok","agree","vote","election","answer","tick"],"k":[49,15]},"flag-hk":{"a":"Hong Kong Sar China Flag","b":"1F1ED-1F1F0","k":[2,26]},"lower_left_crayon":{"a":"Lower Left Crayon","b":"1F58D-FE0F","c":"1F58D","k":[29,31],"o":7},"hear_no_evil":{"a":"Hear-No-Evil Monkey","b":"1F649","j":["animal","monkey","nature"],"k":[32,44]},"cactus":{"a":"Cactus","b":"1F335","j":["vegetable","plant","nature"],"k":[6,43]},"ear_of_rice":{"a":"Ear of Rice","b":"1F33E","j":["nature","plant"],"k":[7,0]},"speak_no_evil":{"a":"Speak-No-Evil Monkey","b":"1F64A","j":["monkey","animal","nature","omg"],"k":[32,45]},"flag-hm":{"a":"Heard & Mcdonald Islands Flag","b":"1F1ED-1F1F2","k":[2,27]},"ballot_box_with_check":{"a":"Ballot Box with Check","b":"2611-FE0F","c":"2611","j":["ok","agree","confirm","black-square","vote","election","yes","tick"],"k":[47,22],"o":1},"canoe":{"a":"Canoe","b":"1F6F6","j":["boat","paddle","water","ship"],"k":[37,21],"o":9},"memo":{"a":"Memo","b":"1F4DD","j":["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],"k":[26,20],"n":["pencil"]},"herb":{"a":"Herb","b":"1F33F","j":["vegetable","plant","medicine","weed","grass","lawn"],"k":[7,1]},"flag-hn":{"a":"Honduras Flag","b":"1F1ED-1F1F3","k":[2,28]},"heavy_check_mark":{"a":"Heavy Check Mark","b":"2714-FE0F","c":"2714","j":["ok","nike","answer","yes","tick"],"k":[49,44],"o":1},"briefcase":{"a":"Briefcase","b":"1F4BC","j":["business","documents","work","law","legal","job","career"],"k":[25,39]},"speedboat":{"a":"Speedboat","b":"1F6A4","j":["ship","transportation","vehicle","summer"],"k":[35,9]},"baby":{"skin_variations":{"1F3FB":{"unified":"1F476-1F3FB","non_qualified":null,"image":"1f476-1f3fb.png","sheet_x":22,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F476-1F3FC","non_qualified":null,"image":"1f476-1f3fc.png","sheet_x":22,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F476-1F3FD","non_qualified":null,"image":"1f476-1f3fd.png","sheet_x":22,"sheet_y":13,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F476-1F3FE","non_qualified":null,"image":"1f476-1f3fe.png","sheet_x":22,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F476-1F3FF","non_qualified":null,"image":"1f476-1f3ff.png","sheet_x":22,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Baby","b":"1F476","j":["child","boy","girl","toddler"],"k":[22,10]},"heavy_multiplication_x":{"a":"Heavy Multiplication X","b":"2716-FE0F","c":"2716","j":["math","calculation"],"k":[49,45],"o":1},"child":{"skin_variations":{"1F3FB":{"unified":"1F9D2-1F3FB","non_qualified":null,"image":"1f9d2-1f3fb.png","sheet_x":43,"sheet_y":5,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F9D2-1F3FC","non_qualified":null,"image":"1f9d2-1f3fc.png","sheet_x":43,"sheet_y":6,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F9D2-1F3FD","non_qualified":null,"image":"1f9d2-1f3fd.png","sheet_x":43,"sheet_y":7,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F9D2-1F3FE","non_qualified":null,"image":"1f9d2-1f3fe.png","sheet_x":43,"sheet_y":8,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F9D2-1F3FF","non_qualified":null,"image":"1f9d2-1f3ff.png","sheet_x":43,"sheet_y":9,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Child","b":"1F9D2","k":[43,4],"o":10},"shamrock":{"a":"Shamrock","b":"2618-FE0F","c":"2618","j":["vegetable","plant","nature","irish","clover"],"k":[47,25],"o":4},"passenger_ship":{"a":"Passenger Ship","b":"1F6F3-FE0F","c":"1F6F3","j":["yacht","cruise","ferry"],"k":[37,18],"o":7},"flag-hr":{"a":"Croatia Flag","b":"1F1ED-1F1F7","k":[2,29]},"file_folder":{"a":"File Folder","b":"1F4C1","j":["documents","business","office"],"k":[25,44]},"x":{"a":"Cross Mark","b":"274C","j":["no","delete","remove","cancel"],"k":[50,1]},"four_leaf_clover":{"a":"Four Leaf Clover","b":"1F340","j":["vegetable","plant","nature","lucky","irish"],"k":[7,2]},"open_file_folder":{"a":"Open File Folder","b":"1F4C2","j":["documents","load"],"k":[25,45]},"boy":{"skin_variations":{"1F3FB":{"unified":"1F466-1F3FB","non_qualified":null,"image":"1f466-1f3fb.png","sheet_x":15,"sheet_y":43,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F466-1F3FC","non_qualified":null,"image":"1f466-1f3fc.png","sheet_x":15,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F466-1F3FD","non_qualified":null,"image":"1f466-1f3fd.png","sheet_x":15,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F466-1F3FE","non_qualified":null,"image":"1f466-1f3fe.png","sheet_x":15,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F466-1F3FF","non_qualified":null,"image":"1f466-1f3ff.png","sheet_x":15,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Boy","b":"1F466","j":["man","male","guy","teenager"],"k":[15,42]},"ferry":{"a":"Ferry","b":"26F4-FE0F","c":"26F4","j":["boat","ship","yacht"],"k":[48,42],"o":5},"flag-ht":{"a":"Haiti Flag","b":"1F1ED-1F1F9","k":[2,30]},"girl":{"skin_variations":{"1F3FB":{"unified":"1F467-1F3FB","non_qualified":null,"image":"1f467-1f3fb.png","sheet_x":15,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F467-1F3FC","non_qualified":null,"image":"1f467-1f3fc.png","sheet_x":15,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F467-1F3FD","non_qualified":null,"image":"1f467-1f3fd.png","sheet_x":15,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F467-1F3FE","non_qualified":null,"image":"1f467-1f3fe.png","sheet_x":16,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F467-1F3FF","non_qualified":null,"image":"1f467-1f3ff.png","sheet_x":16,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Girl","b":"1F467","j":["female","woman","teenager"],"k":[15,48]},"negative_squared_cross_mark":{"a":"Negative Squared Cross Mark","b":"274E","j":["x","green-square","no","deny"],"k":[50,2]},"flag-hu":{"a":"Hungary Flag","b":"1F1ED-1F1FA","k":[2,31]},"card_index_dividers":{"a":"Card Index Dividers","b":"1F5C2-FE0F","c":"1F5C2","j":["organizing","business","stationery"],"k":[30,4],"o":7},"maple_leaf":{"a":"Maple Leaf","b":"1F341","j":["nature","plant","vegetable","ca","fall"],"k":[7,3]},"motor_boat":{"a":"Motor Boat","b":"1F6E5-FE0F","c":"1F6E5","j":["ship"],"k":[37,13],"o":7},"flag-ic":{"a":"Canary Islands Flag","b":"1F1EE-1F1E8","k":[2,32]},"fallen_leaf":{"a":"Fallen Leaf","b":"1F342","j":["nature","plant","vegetable","leaves"],"k":[7,4]},"adult":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB","non_qualified":null,"image":"1f9d1-1f3fb.png","sheet_x":42,"sheet_y":51,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F9D1-1F3FC","non_qualified":null,"image":"1f9d1-1f3fc.png","sheet_x":43,"sheet_y":0,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F9D1-1F3FD","non_qualified":null,"image":"1f9d1-1f3fd.png","sheet_x":43,"sheet_y":1,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F9D1-1F3FE","non_qualified":null,"image":"1f9d1-1f3fe.png","sheet_x":43,"sheet_y":2,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F9D1-1F3FF","non_qualified":null,"image":"1f9d1-1f3ff.png","sheet_x":43,"sheet_y":3,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Adult","b":"1F9D1","k":[42,50],"o":10},"ship":{"a":"Ship","b":"1F6A2","j":["transportation","titanic","deploy"],"k":[34,42]},"heavy_plus_sign":{"a":"Heavy Plus Sign","b":"2795","j":["math","calculation","addition","more","increase"],"k":[50,9]},"date":{"a":"Calendar","b":"1F4C5","j":["calendar","schedule"],"k":[25,48]},"man":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB","non_qualified":null,"image":"1f468-1f3fb.png","sheet_x":18,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F468-1F3FC","non_qualified":null,"image":"1f468-1f3fc.png","sheet_x":18,"sheet_y":13,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F468-1F3FD","non_qualified":null,"image":"1f468-1f3fd.png","sheet_x":18,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F468-1F3FE","non_qualified":null,"image":"1f468-1f3fe.png","sheet_x":18,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F468-1F3FF","non_qualified":null,"image":"1f468-1f3ff.png","sheet_x":18,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Man","b":"1F468","j":["mustache","father","dad","guy","classy","sir","moustache"],"k":[18,11]},"flag-id":{"a":"Indonesia Flag","b":"1F1EE-1F1E9","k":[2,33]},"leaves":{"a":"Leaf Fluttering in Wind","b":"1F343","j":["nature","plant","tree","vegetable","grass","lawn","spring"],"k":[7,5]},"heavy_minus_sign":{"a":"Heavy Minus Sign","b":"2796","j":["math","calculation","subtract","less"],"k":[50,10]},"calendar":{"a":"Tear-off Calendar","b":"1F4C6","j":["schedule","date","planning"],"k":[25,49]},"airplane":{"a":"Airplane","b":"2708-FE0F","c":"2708","j":["vehicle","transportation","flight","fly"],"k":[49,16],"o":1},"spiral_note_pad":{"a":"Spiral Note Pad","b":"1F5D2-FE0F","c":"1F5D2","k":[30,8],"o":7},"heavy_division_sign":{"a":"Heavy Division Sign","b":"2797","j":["divide","math","calculation"],"k":[50,11]},"small_airplane":{"a":"Small Airplane","b":"1F6E9-FE0F","c":"1F6E9","j":["flight","transportation","fly","vehicle"],"k":[37,14],"o":7},"woman":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB","non_qualified":null,"image":"1f469-1f3fb.png","sheet_x":20,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F469-1F3FC","non_qualified":null,"image":"1f469-1f3fc.png","sheet_x":20,"sheet_y":25,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F469-1F3FD","non_qualified":null,"image":"1f469-1f3fd.png","sheet_x":20,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F469-1F3FE","non_qualified":null,"image":"1f469-1f3fe.png","sheet_x":20,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F469-1F3FF","non_qualified":null,"image":"1f469-1f3ff.png","sheet_x":20,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Woman","b":"1F469","j":["female","girls","lady"],"k":[20,23]},"flag-ie":{"a":"Ireland Flag","b":"1F1EE-1F1EA","k":[2,34]},"curly_loop":{"a":"Curly Loop","b":"27B0","j":["scribble","draw","shape","squiggle"],"k":[50,13]},"flag-il":{"a":"Israel Flag","b":"1F1EE-1F1F1","k":[2,35]},"airplane_departure":{"a":"Airplane Departure","b":"1F6EB","k":[37,15],"o":7},"spiral_calendar_pad":{"a":"Spiral Calendar Pad","b":"1F5D3-FE0F","c":"1F5D3","k":[30,9],"o":7},"older_adult":{"skin_variations":{"1F3FB":{"unified":"1F9D3-1F3FB","non_qualified":null,"image":"1f9d3-1f3fb.png","sheet_x":43,"sheet_y":11,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F9D3-1F3FC","non_qualified":null,"image":"1f9d3-1f3fc.png","sheet_x":43,"sheet_y":12,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F9D3-1F3FD","non_qualified":null,"image":"1f9d3-1f3fd.png","sheet_x":43,"sheet_y":13,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F9D3-1F3FE","non_qualified":null,"image":"1f9d3-1f3fe.png","sheet_x":43,"sheet_y":14,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F9D3-1F3FF","non_qualified":null,"image":"1f9d3-1f3ff.png","sheet_x":43,"sheet_y":15,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Older Adult","b":"1F9D3","k":[43,10],"o":10},"airplane_arriving":{"a":"Airplane Arriving","b":"1F6EC","k":[37,16],"o":7},"card_index":{"a":"Card Index","b":"1F4C7","j":["business","stationery"],"k":[25,50]},"loop":{"a":"Double Curly Loop","b":"27BF","j":["tape","cassette"],"k":[50,14]},"older_man":{"skin_variations":{"1F3FB":{"unified":"1F474-1F3FB","non_qualified":null,"image":"1f474-1f3fb.png","sheet_x":21,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F474-1F3FC","non_qualified":null,"image":"1f474-1f3fc.png","sheet_x":22,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F474-1F3FD","non_qualified":null,"image":"1f474-1f3fd.png","sheet_x":22,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F474-1F3FE","non_qualified":null,"image":"1f474-1f3fe.png","sheet_x":22,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F474-1F3FF","non_qualified":null,"image":"1f474-1f3ff.png","sheet_x":22,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Older Man","b":"1F474","j":["human","male","men","old","elder","senior"],"k":[21,50]},"flag-im":{"a":"Isle of Man Flag","b":"1F1EE-1F1F2","k":[2,36]},"flag-in":{"a":"India Flag","b":"1F1EE-1F1F3","k":[2,37]},"chart_with_upwards_trend":{"a":"Chart with Upwards Trend","b":"1F4C8","j":["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],"k":[25,51]},"part_alternation_mark":{"a":"Part Alternation Mark","b":"303D-FE0F","c":"303D","j":["graph","presentation","stats","business","economics","bad"],"k":[50,25],"o":3},"seat":{"a":"Seat","b":"1F4BA","j":["sit","airplane","transport","bus","flight","fly"],"k":[25,37]},"older_woman":{"skin_variations":{"1F3FB":{"unified":"1F475-1F3FB","non_qualified":null,"image":"1f475-1f3fb.png","sheet_x":22,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F475-1F3FC","non_qualified":null,"image":"1f475-1f3fc.png","sheet_x":22,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F475-1F3FD","non_qualified":null,"image":"1f475-1f3fd.png","sheet_x":22,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F475-1F3FE","non_qualified":null,"image":"1f475-1f3fe.png","sheet_x":22,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F475-1F3FF","non_qualified":null,"image":"1f475-1f3ff.png","sheet_x":22,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Older Woman","b":"1F475","j":["human","female","women","lady","old","elder","senior"],"k":[22,4]},"eight_spoked_asterisk":{"a":"Eight Spoked Asterisk","b":"2733-FE0F","c":"2733","j":["star","sparkle","green-square"],"k":[49,49],"o":1},"chart_with_downwards_trend":{"a":"Chart with Downwards Trend","b":"1F4C9","j":["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],"k":[26,0]},"flag-io":{"a":"British Indian Ocean Territory Flag","b":"1F1EE-1F1F4","k":[2,38]},"male-doctor":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-2695-FE0F","non_qualified":"1F468-1F3FB-200D-2695","image":"1f468-1f3fb-200d-2695-fe0f.png","sheet_x":17,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-2695-FE0F","non_qualified":"1F468-1F3FC-200D-2695","image":"1f468-1f3fc-200d-2695-fe0f.png","sheet_x":17,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-2695-FE0F","non_qualified":"1F468-1F3FD-200D-2695","image":"1f468-1f3fd-200d-2695-fe0f.png","sheet_x":17,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-2695-FE0F","non_qualified":"1F468-1F3FE-200D-2695","image":"1f468-1f3fe-200d-2695-fe0f.png","sheet_x":17,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-2695-FE0F","non_qualified":"1F468-1F3FF-200D-2695","image":"1f468-1f3ff-200d-2695-fe0f.png","sheet_x":17,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Male Doctor","b":"1F468-200D-2695-FE0F","c":"1F468-200D-2695","k":[17,43]},"helicopter":{"a":"Helicopter","b":"1F681","j":["transportation","vehicle","fly"],"k":[34,9]},"female-doctor":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-2695-FE0F","non_qualified":"1F469-1F3FB-200D-2695","image":"1f469-1f3fb-200d-2695-fe0f.png","sheet_x":20,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-2695-FE0F","non_qualified":"1F469-1F3FC-200D-2695","image":"1f469-1f3fc-200d-2695-fe0f.png","sheet_x":20,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-2695-FE0F","non_qualified":"1F469-1F3FD-200D-2695","image":"1f469-1f3fd-200d-2695-fe0f.png","sheet_x":20,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-2695-FE0F","non_qualified":"1F469-1F3FE-200D-2695","image":"1f469-1f3fe-200d-2695-fe0f.png","sheet_x":20,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-2695-FE0F","non_qualified":"1F469-1F3FF-200D-2695","image":"1f469-1f3ff-200d-2695-fe0f.png","sheet_x":20,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Female Doctor","b":"1F469-200D-2695-FE0F","c":"1F469-200D-2695","k":[20,1]},"suspension_railway":{"a":"Suspension Railway","b":"1F69F","j":["vehicle","transportation"],"k":[34,39]},"bar_chart":{"a":"Bar Chart","b":"1F4CA","j":["graph","presentation","stats"],"k":[26,1]},"flag-iq":{"a":"Iraq Flag","b":"1F1EE-1F1F6","k":[2,39]},"eight_pointed_black_star":{"a":"Eight Pointed Black Star","b":"2734-FE0F","c":"2734","j":["orange-square","shape","polygon"],"k":[49,50],"o":1},"mountain_cableway":{"a":"Mountain Cableway","b":"1F6A0","j":["transportation","vehicle","ski"],"k":[34,40]},"male-student":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F393","non_qualified":null,"image":"1f468-1f3fb-200d-1f393.png","sheet_x":16,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F393","non_qualified":null,"image":"1f468-1f3fc-200d-1f393.png","sheet_x":16,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F393","non_qualified":null,"image":"1f468-1f3fd-200d-1f393.png","sheet_x":16,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F393","non_qualified":null,"image":"1f468-1f3fe-200d-1f393.png","sheet_x":16,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F393","non_qualified":null,"image":"1f468-1f3ff-200d-1f393.png","sheet_x":16,"sheet_y":19,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Student","b":"1F468-200D-1F393","k":[16,14]},"clipboard":{"a":"Clipboard","b":"1F4CB","j":["stationery","documents"],"k":[26,2]},"flag-ir":{"a":"Iran Flag","b":"1F1EE-1F1F7","k":[2,40]},"sparkle":{"a":"Sparkle","b":"2747-FE0F","c":"2747","j":["stars","green-square","awesome","good","fireworks"],"k":[50,0],"o":1},"female-student":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F393","non_qualified":null,"image":"1f469-1f3fb-200d-1f393.png","sheet_x":18,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F393","non_qualified":null,"image":"1f469-1f3fc-200d-1f393.png","sheet_x":18,"sheet_y":31,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F393","non_qualified":null,"image":"1f469-1f3fd-200d-1f393.png","sheet_x":18,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F393","non_qualified":null,"image":"1f469-1f3fe-200d-1f393.png","sheet_x":18,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F393","non_qualified":null,"image":"1f469-1f3ff-200d-1f393.png","sheet_x":18,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Student","b":"1F469-200D-1F393","k":[18,29]},"pushpin":{"a":"Pushpin","b":"1F4CC","j":["stationery","mark","here"],"k":[26,3]},"aerial_tramway":{"a":"Aerial Tramway","b":"1F6A1","j":["transportation","vehicle","ski"],"k":[34,41]},"flag-is":{"a":"Iceland Flag","b":"1F1EE-1F1F8","k":[2,41]},"bangbang":{"a":"Double Exclamation Mark","b":"203C-FE0F","c":"203C","j":["exclamation","surprise"],"k":[46,29],"o":1},"interrobang":{"a":"Exclamation Question Mark","b":"2049-FE0F","c":"2049","j":["wat","punctuation","surprise"],"k":[46,30],"o":3},"satellite":{"a":"Satellite","b":"1F6F0-FE0F","c":"1F6F0","j":["communication","future","radio","space"],"k":[37,17],"o":7},"it":{"a":"Italy Flag","b":"1F1EE-1F1F9","j":["italy","flag","nation","country","banner"],"k":[2,42],"n":["flag-it"]},"male-teacher":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F3EB","non_qualified":null,"image":"1f468-1f3fb-200d-1f3eb.png","sheet_x":16,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F3EB","non_qualified":null,"image":"1f468-1f3fc-200d-1f3eb.png","sheet_x":16,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F3EB","non_qualified":null,"image":"1f468-1f3fd-200d-1f3eb.png","sheet_x":16,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F3EB","non_qualified":null,"image":"1f468-1f3fe-200d-1f3eb.png","sheet_x":16,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F3EB","non_qualified":null,"image":"1f468-1f3ff-200d-1f3eb.png","sheet_x":16,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Teacher","b":"1F468-200D-1F3EB","k":[16,32]},"round_pushpin":{"a":"Round Pushpin","b":"1F4CD","j":["stationery","location","map","here"],"k":[26,4]},"flag-je":{"a":"Jersey Flag","b":"1F1EF-1F1EA","k":[2,43]},"question":{"a":"Black Question Mark Ornament","b":"2753","j":["doubt","confused"],"k":[50,3]},"rocket":{"a":"Rocket","b":"1F680","j":["launch","ship","staffmode","NASA","outer space","outer_space","fly"],"k":[34,8]},"female-teacher":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F3EB","non_qualified":null,"image":"1f469-1f3fb-200d-1f3eb.png","sheet_x":18,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F3EB","non_qualified":null,"image":"1f469-1f3fc-200d-1f3eb.png","sheet_x":18,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F3EB","non_qualified":null,"image":"1f469-1f3fd-200d-1f3eb.png","sheet_x":18,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F3EB","non_qualified":null,"image":"1f469-1f3fe-200d-1f3eb.png","sheet_x":18,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F3EB","non_qualified":null,"image":"1f469-1f3ff-200d-1f3eb.png","sheet_x":19,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Teacher","b":"1F469-200D-1F3EB","k":[18,47]},"paperclip":{"a":"Paperclip","b":"1F4CE","j":["documents","stationery"],"k":[26,5]},"linked_paperclips":{"a":"Linked Paperclips","b":"1F587-FE0F","c":"1F587","k":[29,27],"o":7},"flying_saucer":{"a":"Flying Saucer","b":"1F6F8","k":[37,23],"o":10},"male-judge":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-2696-FE0F","non_qualified":"1F468-1F3FB-200D-2696","image":"1f468-1f3fb-200d-2696-fe0f.png","sheet_x":17,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-2696-FE0F","non_qualified":"1F468-1F3FC-200D-2696","image":"1f468-1f3fc-200d-2696-fe0f.png","sheet_x":17,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-2696-FE0F","non_qualified":"1F468-1F3FD-200D-2696","image":"1f468-1f3fd-200d-2696-fe0f.png","sheet_x":18,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-2696-FE0F","non_qualified":"1F468-1F3FE-200D-2696","image":"1f468-1f3fe-200d-2696-fe0f.png","sheet_x":18,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-2696-FE0F","non_qualified":"1F468-1F3FF-200D-2696","image":"1f468-1f3ff-200d-2696-fe0f.png","sheet_x":18,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Male Judge","b":"1F468-200D-2696-FE0F","c":"1F468-200D-2696","k":[17,49]},"grey_question":{"a":"White Question Mark Ornament","b":"2754","j":["doubts","gray","huh","confused"],"k":[50,4]},"flag-jm":{"a":"Jamaica Flag","b":"1F1EF-1F1F2","k":[2,44]},"bellhop_bell":{"a":"Bellhop Bell","b":"1F6CE-FE0F","c":"1F6CE","j":["service"],"k":[37,3],"o":7},"straight_ruler":{"a":"Straight Ruler","b":"1F4CF","j":["stationery","calculate","length","math","school","drawing","architect","sketch"],"k":[26,6]},"flag-jo":{"a":"Jordan Flag","b":"1F1EF-1F1F4","k":[2,45]},"female-judge":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-2696-FE0F","non_qualified":"1F469-1F3FB-200D-2696","image":"1f469-1f3fb-200d-2696-fe0f.png","sheet_x":20,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-2696-FE0F","non_qualified":"1F469-1F3FC-200D-2696","image":"1f469-1f3fc-200d-2696-fe0f.png","sheet_x":20,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-2696-FE0F","non_qualified":"1F469-1F3FD-200D-2696","image":"1f469-1f3fd-200d-2696-fe0f.png","sheet_x":20,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-2696-FE0F","non_qualified":"1F469-1F3FE-200D-2696","image":"1f469-1f3fe-200d-2696-fe0f.png","sheet_x":20,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-2696-FE0F","non_qualified":"1F469-1F3FF-200D-2696","image":"1f469-1f3ff-200d-2696-fe0f.png","sheet_x":20,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Female Judge","b":"1F469-200D-2696-FE0F","c":"1F469-200D-2696","k":[20,7]},"grey_exclamation":{"a":"White Exclamation Mark Ornament","b":"2755","j":["surprise","punctuation","gray","wow","warning"],"k":[50,5]},"door":{"a":"Door","b":"1F6AA","j":["house","entry","exit"],"k":[35,15]},"male-farmer":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F33E","non_qualified":null,"image":"1f468-1f3fb-200d-1f33e.png","sheet_x":16,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F33E","non_qualified":null,"image":"1f468-1f3fc-200d-1f33e.png","sheet_x":16,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F33E","non_qualified":null,"image":"1f468-1f3fd-200d-1f33e.png","sheet_x":16,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F33E","non_qualified":null,"image":"1f468-1f3fe-200d-1f33e.png","sheet_x":16,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F33E","non_qualified":null,"image":"1f468-1f3ff-200d-1f33e.png","sheet_x":16,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Farmer","b":"1F468-200D-1F33E","k":[16,2]},"jp":{"a":"Japan Flag","b":"1F1EF-1F1F5","j":["japanese","nation","flag","country","banner"],"k":[2,46],"n":["flag-jp"]},"triangular_ruler":{"a":"Triangular Ruler","b":"1F4D0","j":["stationery","math","architect","sketch"],"k":[26,7]},"exclamation":{"a":"Heavy Exclamation Mark Symbol","b":"2757","j":["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],"k":[50,6],"n":["heavy_exclamation_mark"],"o":5},"bed":{"a":"Bed","b":"1F6CF-FE0F","c":"1F6CF","j":["sleep","rest"],"k":[37,4],"o":7},"female-farmer":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F33E","non_qualified":null,"image":"1f469-1f3fb-200d-1f33e.png","sheet_x":18,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F33E","non_qualified":null,"image":"1f469-1f3fc-200d-1f33e.png","sheet_x":18,"sheet_y":19,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F33E","non_qualified":null,"image":"1f469-1f3fd-200d-1f33e.png","sheet_x":18,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F33E","non_qualified":null,"image":"1f469-1f3fe-200d-1f33e.png","sheet_x":18,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F33E","non_qualified":null,"image":"1f469-1f3ff-200d-1f33e.png","sheet_x":18,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Farmer","b":"1F469-200D-1F33E","k":[18,17]},"scissors":{"a":"Black Scissors","b":"2702-FE0F","c":"2702","j":["stationery","cut"],"k":[49,14],"o":1},"wavy_dash":{"a":"Wavy Dash","b":"3030-FE0F","c":"3030","j":["draw","line","moustache","mustache","squiggle","scribble"],"k":[50,24],"o":1},"flag-ke":{"a":"Kenya Flag","b":"1F1F0-1F1EA","k":[2,47]},"flag-kg":{"a":"Kyrgyzstan Flag","b":"1F1F0-1F1EC","k":[2,48]},"couch_and_lamp":{"a":"Couch and Lamp","b":"1F6CB-FE0F","c":"1F6CB","j":["read","chill"],"k":[36,47],"o":7},"male-cook":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F373","non_qualified":null,"image":"1f468-1f3fb-200d-1f373.png","sheet_x":16,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F373","non_qualified":null,"image":"1f468-1f3fc-200d-1f373.png","sheet_x":16,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F373","non_qualified":null,"image":"1f468-1f3fd-200d-1f373.png","sheet_x":16,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F373","non_qualified":null,"image":"1f468-1f3fe-200d-1f373.png","sheet_x":16,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F373","non_qualified":null,"image":"1f468-1f3ff-200d-1f373.png","sheet_x":16,"sheet_y":13,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Cook","b":"1F468-200D-1F373","k":[16,8]},"card_file_box":{"a":"Card File Box","b":"1F5C3-FE0F","c":"1F5C3","j":["business","stationery"],"k":[30,5],"o":7},"copyright":{"a":"Copyright Sign","b":"00A9-FE0F","c":"00A9","j":["ip","license","circle","law","legal"],"k":[0,12],"o":1},"file_cabinet":{"a":"File Cabinet","b":"1F5C4-FE0F","c":"1F5C4","j":["filing","organizing"],"k":[30,6],"o":7},"registered":{"a":"Registered Sign","b":"00AE-FE0F","c":"00AE","j":["alphabet","circle"],"k":[0,13],"o":1},"flag-kh":{"a":"Cambodia Flag","b":"1F1F0-1F1ED","k":[2,49]},"female-cook":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F373","non_qualified":null,"image":"1f469-1f3fb-200d-1f373.png","sheet_x":18,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F373","non_qualified":null,"image":"1f469-1f3fc-200d-1f373.png","sheet_x":18,"sheet_y":25,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F373","non_qualified":null,"image":"1f469-1f3fd-200d-1f373.png","sheet_x":18,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F373","non_qualified":null,"image":"1f469-1f3fe-200d-1f373.png","sheet_x":18,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F373","non_qualified":null,"image":"1f469-1f3ff-200d-1f373.png","sheet_x":18,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Cook","b":"1F469-200D-1F373","k":[18,23]},"toilet":{"a":"Toilet","b":"1F6BD","j":["restroom","wc","washroom","bathroom","potty"],"k":[36,33]},"wastebasket":{"a":"Wastebasket","b":"1F5D1-FE0F","c":"1F5D1","j":["bin","trash","rubbish","garbage","toss"],"k":[30,7],"o":7},"flag-ki":{"a":"Kiribati Flag","b":"1F1F0-1F1EE","k":[2,50]},"shower":{"a":"Shower","b":"1F6BF","j":["clean","water","bathroom"],"k":[36,35]},"male-mechanic":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F527","non_qualified":null,"image":"1f468-1f3fb-200d-1f527.png","sheet_x":17,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F527","non_qualified":null,"image":"1f468-1f3fc-200d-1f527.png","sheet_x":17,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F527","non_qualified":null,"image":"1f468-1f3fd-200d-1f527.png","sheet_x":17,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F527","non_qualified":null,"image":"1f468-1f3fe-200d-1f527.png","sheet_x":17,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F527","non_qualified":null,"image":"1f468-1f3ff-200d-1f527.png","sheet_x":17,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Mechanic","b":"1F468-200D-1F527","k":[17,19]},"tm":{"a":"Trade Mark Sign","b":"2122-FE0F","c":"2122","j":["trademark","brand","law","legal"],"k":[46,31],"o":1},"hash":{"a":"Hash Key","b":"0023-FE0F-20E3","c":"0023-20E3","j":["symbol","blue-square","twitter"],"k":[0,0],"o":3},"flag-km":{"a":"Comoros Flag","b":"1F1F0-1F1F2","k":[2,51]},"bathtub":{"a":"Bathtub","b":"1F6C1","j":["clean","shower","bathroom"],"k":[36,42]},"female-mechanic":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F527","non_qualified":null,"image":"1f469-1f3fb-200d-1f527.png","sheet_x":19,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F527","non_qualified":null,"image":"1f469-1f3fc-200d-1f527.png","sheet_x":19,"sheet_y":31,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F527","non_qualified":null,"image":"1f469-1f3fd-200d-1f527.png","sheet_x":19,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F527","non_qualified":null,"image":"1f469-1f3fe-200d-1f527.png","sheet_x":19,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F527","non_qualified":null,"image":"1f469-1f3ff-200d-1f527.png","sheet_x":19,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Mechanic","b":"1F469-200D-1F527","k":[19,29]},"lock":{"a":"Lock","b":"1F512","j":["security","password","padlock"],"k":[27,20]},"male-factory-worker":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F3ED","non_qualified":null,"image":"1f468-1f3fb-200d-1f3ed.png","sheet_x":16,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F3ED","non_qualified":null,"image":"1f468-1f3fc-200d-1f3ed.png","sheet_x":16,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F3ED","non_qualified":null,"image":"1f468-1f3fd-200d-1f3ed.png","sheet_x":16,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F3ED","non_qualified":null,"image":"1f468-1f3fe-200d-1f3ed.png","sheet_x":16,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F3ED","non_qualified":null,"image":"1f468-1f3ff-200d-1f3ed.png","sheet_x":16,"sheet_y":43,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Factory Worker","b":"1F468-200D-1F3ED","k":[16,38]},"flag-kn":{"a":"St. Kitts & Nevis Flag","b":"1F1F0-1F1F3","k":[3,0]},"hourglass":{"a":"Hourglass","b":"231B","j":["time","clock","oldschool","limit","exam","quiz","test"],"k":[46,42],"o":1},"keycap_star":{"a":"Keycap Star","b":"002A-FE0F-20E3","c":"002A-20E3","k":[0,1],"o":3},"unlock":{"a":"Open Lock","b":"1F513","j":["privacy","security"],"k":[27,21]},"flag-kp":{"a":"North Korea Flag","b":"1F1F0-1F1F5","k":[3,1]},"female-factory-worker":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F3ED","non_qualified":null,"image":"1f469-1f3fb-200d-1f3ed.png","sheet_x":19,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F3ED","non_qualified":null,"image":"1f469-1f3fc-200d-1f3ed.png","sheet_x":19,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F3ED","non_qualified":null,"image":"1f469-1f3fd-200d-1f3ed.png","sheet_x":19,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F3ED","non_qualified":null,"image":"1f469-1f3fe-200d-1f3ed.png","sheet_x":19,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F3ED","non_qualified":null,"image":"1f469-1f3ff-200d-1f3ed.png","sheet_x":19,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Factory Worker","b":"1F469-200D-1F3ED","k":[19,1]},"zero":{"a":"Keycap 0","b":"0030-FE0F-20E3","c":"0030-20E3","j":["0","numbers","blue-square","null"],"k":[0,2],"o":3},"lock_with_ink_pen":{"a":"Lock with Ink Pen","b":"1F50F","j":["security","secret"],"k":[27,17]},"hourglass_flowing_sand":{"a":"Hourglass with Flowing Sand","b":"23F3","j":["oldschool","time","countdown"],"k":[47,3]},"one":{"a":"Keycap 1","b":"0031-FE0F-20E3","c":"0031-20E3","j":["blue-square","numbers","1"],"k":[0,3],"o":3},"kr":{"a":"South Korea Flag","b":"1F1F0-1F1F7","j":["south","korea","nation","flag","country","banner"],"k":[3,2],"n":["flag-kr"]},"watch":{"a":"Watch","b":"231A","j":["time","accessories"],"k":[46,41],"o":1},"male-office-worker":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F4BC","non_qualified":null,"image":"1f468-1f3fb-200d-1f4bc.png","sheet_x":17,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F4BC","non_qualified":null,"image":"1f468-1f3fc-200d-1f4bc.png","sheet_x":17,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F4BC","non_qualified":null,"image":"1f468-1f3fd-200d-1f4bc.png","sheet_x":17,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F4BC","non_qualified":null,"image":"1f468-1f3fe-200d-1f4bc.png","sheet_x":17,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F4BC","non_qualified":null,"image":"1f468-1f3ff-200d-1f4bc.png","sheet_x":17,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Office Worker","b":"1F468-200D-1F4BC","k":[17,13]},"closed_lock_with_key":{"a":"Closed Lock with Key","b":"1F510","j":["security","privacy"],"k":[27,18]},"female-office-worker":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F4BC","non_qualified":null,"image":"1f469-1f3fb-200d-1f4bc.png","sheet_x":19,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F4BC","non_qualified":null,"image":"1f469-1f3fc-200d-1f4bc.png","sheet_x":19,"sheet_y":25,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F4BC","non_qualified":null,"image":"1f469-1f3fd-200d-1f4bc.png","sheet_x":19,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F4BC","non_qualified":null,"image":"1f469-1f3fe-200d-1f4bc.png","sheet_x":19,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F4BC","non_qualified":null,"image":"1f469-1f3ff-200d-1f4bc.png","sheet_x":19,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Office Worker","b":"1F469-200D-1F4BC","k":[19,23]},"two":{"a":"Keycap 2","b":"0032-FE0F-20E3","c":"0032-20E3","j":["numbers","2","prime","blue-square"],"k":[0,4],"o":3},"alarm_clock":{"a":"Alarm Clock","b":"23F0","j":["time","wake"],"k":[47,0]},"key":{"a":"Key","b":"1F511","j":["lock","door","password"],"k":[27,19]},"flag-kw":{"a":"Kuwait Flag","b":"1F1F0-1F1FC","k":[3,3]},"stopwatch":{"a":"Stopwatch","b":"23F1-FE0F","c":"23F1","j":["time","deadline"],"k":[47,1]},"male-scientist":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F52C","non_qualified":null,"image":"1f468-1f3fb-200d-1f52c.png","sheet_x":17,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F52C","non_qualified":null,"image":"1f468-1f3fc-200d-1f52c.png","sheet_x":17,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F52C","non_qualified":null,"image":"1f468-1f3fd-200d-1f52c.png","sheet_x":17,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F52C","non_qualified":null,"image":"1f468-1f3fe-200d-1f52c.png","sheet_x":17,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F52C","non_qualified":null,"image":"1f468-1f3ff-200d-1f52c.png","sheet_x":17,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Scientist","b":"1F468-200D-1F52C","k":[17,25]},"three":{"a":"Keycap 3","b":"0033-FE0F-20E3","c":"0033-20E3","j":["3","numbers","prime","blue-square"],"k":[0,5],"o":3},"flag-ky":{"a":"Cayman Islands Flag","b":"1F1F0-1F1FE","k":[3,4]},"old_key":{"a":"Old Key","b":"1F5DD-FE0F","c":"1F5DD","j":["lock","door","password"],"k":[30,11],"o":7},"flag-kz":{"a":"Kazakhstan Flag","b":"1F1F0-1F1FF","k":[3,5]},"hammer":{"a":"Hammer","b":"1F528","j":["tools","build","create"],"k":[27,42]},"female-scientist":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F52C","non_qualified":null,"image":"1f469-1f3fb-200d-1f52c.png","sheet_x":19,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F52C","non_qualified":null,"image":"1f469-1f3fc-200d-1f52c.png","sheet_x":19,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F52C","non_qualified":null,"image":"1f469-1f3fd-200d-1f52c.png","sheet_x":19,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F52C","non_qualified":null,"image":"1f469-1f3fe-200d-1f52c.png","sheet_x":19,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F52C","non_qualified":null,"image":"1f469-1f3ff-200d-1f52c.png","sheet_x":19,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Scientist","b":"1F469-200D-1F52C","k":[19,35]},"timer_clock":{"a":"Timer Clock","b":"23F2-FE0F","c":"23F2","j":["alarm"],"k":[47,2]},"four":{"a":"Keycap 4","b":"0034-FE0F-20E3","c":"0034-20E3","j":["4","numbers","blue-square"],"k":[0,6],"o":3},"male-technologist":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F4BB","non_qualified":null,"image":"1f468-1f3fb-200d-1f4bb.png","sheet_x":17,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F4BB","non_qualified":null,"image":"1f468-1f3fc-200d-1f4bb.png","sheet_x":17,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F4BB","non_qualified":null,"image":"1f468-1f3fd-200d-1f4bb.png","sheet_x":17,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F4BB","non_qualified":null,"image":"1f468-1f3fe-200d-1f4bb.png","sheet_x":17,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F4BB","non_qualified":null,"image":"1f468-1f3ff-200d-1f4bb.png","sheet_x":17,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Technologist","b":"1F468-200D-1F4BB","k":[17,7]},"mantelpiece_clock":{"a":"Mantelpiece Clock","b":"1F570-FE0F","c":"1F570","j":["time"],"k":[28,43],"o":7},"five":{"a":"Keycap 5","b":"0035-FE0F-20E3","c":"0035-20E3","j":["5","numbers","blue-square","prime"],"k":[0,7],"o":3},"flag-la":{"a":"Laos Flag","b":"1F1F1-1F1E6","k":[3,6]},"pick":{"a":"Pick","b":"26CF-FE0F","c":"26CF","j":["tools","dig"],"k":[48,32],"o":5},"flag-lb":{"a":"Lebanon Flag","b":"1F1F1-1F1E7","k":[3,7]},"clock12":{"a":"Clock Face Twelve Oclock","b":"1F55B","j":["time","noon","midnight","midday","late","early","schedule"],"k":[28,29]},"hammer_and_pick":{"a":"Hammer and Pick","b":"2692-FE0F","c":"2692","j":["tools","build","create"],"k":[48,11],"o":4},"six":{"a":"Keycap 6","b":"0036-FE0F-20E3","c":"0036-20E3","j":["6","numbers","blue-square"],"k":[0,8],"o":3},"female-technologist":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F4BB","non_qualified":null,"image":"1f469-1f3fb-200d-1f4bb.png","sheet_x":19,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F4BB","non_qualified":null,"image":"1f469-1f3fc-200d-1f4bb.png","sheet_x":19,"sheet_y":19,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F4BB","non_qualified":null,"image":"1f469-1f3fd-200d-1f4bb.png","sheet_x":19,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F4BB","non_qualified":null,"image":"1f469-1f3fe-200d-1f4bb.png","sheet_x":19,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F4BB","non_qualified":null,"image":"1f469-1f3ff-200d-1f4bb.png","sheet_x":19,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Technologist","b":"1F469-200D-1F4BB","k":[19,17]},"hammer_and_wrench":{"a":"Hammer and Wrench","b":"1F6E0-FE0F","c":"1F6E0","j":["tools","build","create"],"k":[37,8],"o":7},"flag-lc":{"a":"St. Lucia Flag","b":"1F1F1-1F1E8","k":[3,8]},"clock1230":{"a":"Clock Face Twelve-Thirty","b":"1F567","j":["time","late","early","schedule"],"k":[28,41]},"seven":{"a":"Keycap 7","b":"0037-FE0F-20E3","c":"0037-20E3","j":["7","numbers","blue-square","prime"],"k":[0,9],"o":3},"male-singer":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F3A4","non_qualified":null,"image":"1f468-1f3fb-200d-1f3a4.png","sheet_x":16,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F3A4","non_qualified":null,"image":"1f468-1f3fc-200d-1f3a4.png","sheet_x":16,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F3A4","non_qualified":null,"image":"1f468-1f3fd-200d-1f3a4.png","sheet_x":16,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F3A4","non_qualified":null,"image":"1f468-1f3fe-200d-1f3a4.png","sheet_x":16,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F3A4","non_qualified":null,"image":"1f468-1f3ff-200d-1f3a4.png","sheet_x":16,"sheet_y":25,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Singer","b":"1F468-200D-1F3A4","k":[16,20]},"eight":{"a":"Keycap 8","b":"0038-FE0F-20E3","c":"0038-20E3","j":["8","blue-square","numbers"],"k":[0,10],"o":3},"flag-li":{"a":"Liechtenstein Flag","b":"1F1F1-1F1EE","k":[3,9]},"dagger_knife":{"a":"Dagger Knife","b":"1F5E1-FE0F","c":"1F5E1","k":[30,13],"o":7},"clock1":{"a":"Clock Face One Oclock","b":"1F550","j":["time","late","early","schedule"],"k":[28,18]},"female-singer":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F3A4","non_qualified":null,"image":"1f469-1f3fb-200d-1f3a4.png","sheet_x":18,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F3A4","non_qualified":null,"image":"1f469-1f3fc-200d-1f3a4.png","sheet_x":18,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F3A4","non_qualified":null,"image":"1f469-1f3fd-200d-1f3a4.png","sheet_x":18,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F3A4","non_qualified":null,"image":"1f469-1f3fe-200d-1f3a4.png","sheet_x":18,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F3A4","non_qualified":null,"image":"1f469-1f3ff-200d-1f3a4.png","sheet_x":18,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Singer","b":"1F469-200D-1F3A4","k":[18,35]},"male-artist":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F3A8","non_qualified":null,"image":"1f468-1f3fb-200d-1f3a8.png","sheet_x":16,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F3A8","non_qualified":null,"image":"1f468-1f3fc-200d-1f3a8.png","sheet_x":16,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F3A8","non_qualified":null,"image":"1f468-1f3fd-200d-1f3a8.png","sheet_x":16,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F3A8","non_qualified":null,"image":"1f468-1f3fe-200d-1f3a8.png","sheet_x":16,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F3A8","non_qualified":null,"image":"1f468-1f3ff-200d-1f3a8.png","sheet_x":16,"sheet_y":31,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Artist","b":"1F468-200D-1F3A8","k":[16,26]},"crossed_swords":{"a":"Crossed Swords","b":"2694-FE0F","c":"2694","j":["weapon"],"k":[48,13],"o":4},"nine":{"a":"Keycap 9","b":"0039-FE0F-20E3","c":"0039-20E3","j":["blue-square","numbers","9"],"k":[0,11],"o":3},"flag-lk":{"a":"Sri Lanka Flag","b":"1F1F1-1F1F0","k":[3,10]},"clock130":{"a":"Clock Face One-Thirty","b":"1F55C","j":["time","late","early","schedule"],"k":[28,30]},"clock2":{"a":"Clock Face Two Oclock","b":"1F551","j":["time","late","early","schedule"],"k":[28,19]},"gun":{"a":"Pistol","b":"1F52B","j":["violence","weapon","pistol","revolver"],"k":[27,45]},"keycap_ten":{"a":"Keycap Ten","b":"1F51F","j":["numbers","10","blue-square"],"k":[27,33]},"female-artist":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F3A8","non_qualified":null,"image":"1f469-1f3fb-200d-1f3a8.png","sheet_x":18,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F3A8","non_qualified":null,"image":"1f469-1f3fc-200d-1f3a8.png","sheet_x":18,"sheet_y":43,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F3A8","non_qualified":null,"image":"1f469-1f3fd-200d-1f3a8.png","sheet_x":18,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F3A8","non_qualified":null,"image":"1f469-1f3fe-200d-1f3a8.png","sheet_x":18,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F3A8","non_qualified":null,"image":"1f469-1f3ff-200d-1f3a8.png","sheet_x":18,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Artist","b":"1F469-200D-1F3A8","k":[18,41]},"flag-lr":{"a":"Liberia Flag","b":"1F1F1-1F1F7","k":[3,11]},"clock230":{"a":"Clock Face Two-Thirty","b":"1F55D","j":["time","late","early","schedule"],"k":[28,31]},"bow_and_arrow":{"a":"Bow and Arrow","b":"1F3F9","j":["sports"],"k":[12,23],"o":8},"male-pilot":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-2708-FE0F","non_qualified":"1F468-1F3FB-200D-2708","image":"1f468-1f3fb-200d-2708-fe0f.png","sheet_x":18,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-2708-FE0F","non_qualified":"1F468-1F3FC-200D-2708","image":"1f468-1f3fc-200d-2708-fe0f.png","sheet_x":18,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-2708-FE0F","non_qualified":"1F468-1F3FD-200D-2708","image":"1f468-1f3fd-200d-2708-fe0f.png","sheet_x":18,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-2708-FE0F","non_qualified":"1F468-1F3FE-200D-2708","image":"1f468-1f3fe-200d-2708-fe0f.png","sheet_x":18,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-2708-FE0F","non_qualified":"1F468-1F3FF-200D-2708","image":"1f468-1f3ff-200d-2708-fe0f.png","sheet_x":18,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Male Pilot","b":"1F468-200D-2708-FE0F","c":"1F468-200D-2708","k":[18,3]},"flag-ls":{"a":"Lesotho Flag","b":"1F1F1-1F1F8","k":[3,12]},"flag-lt":{"a":"Lithuania Flag","b":"1F1F1-1F1F9","k":[3,13]},"capital_abcd":{"a":"Input Symbol for Latin Capital Letters","b":"1F520","j":["alphabet","words","blue-square"],"k":[27,34]},"female-pilot":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-2708-FE0F","non_qualified":"1F469-1F3FB-200D-2708","image":"1f469-1f3fb-200d-2708-fe0f.png","sheet_x":20,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-2708-FE0F","non_qualified":"1F469-1F3FC-200D-2708","image":"1f469-1f3fc-200d-2708-fe0f.png","sheet_x":20,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-2708-FE0F","non_qualified":"1F469-1F3FD-200D-2708","image":"1f469-1f3fd-200d-2708-fe0f.png","sheet_x":20,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-2708-FE0F","non_qualified":"1F469-1F3FE-200D-2708","image":"1f469-1f3fe-200d-2708-fe0f.png","sheet_x":20,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-2708-FE0F","non_qualified":"1F469-1F3FF-200D-2708","image":"1f469-1f3ff-200d-2708-fe0f.png","sheet_x":20,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Female Pilot","b":"1F469-200D-2708-FE0F","c":"1F469-200D-2708","k":[20,13]},"clock3":{"a":"Clock Face Three Oclock","b":"1F552","j":["time","late","early","schedule"],"k":[28,20]},"shield":{"a":"Shield","b":"1F6E1-FE0F","c":"1F6E1","j":["protection","security"],"k":[37,9],"o":7},"male-astronaut":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F680","non_qualified":null,"image":"1f468-1f3fb-200d-1f680.png","sheet_x":17,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F680","non_qualified":null,"image":"1f468-1f3fc-200d-1f680.png","sheet_x":17,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F680","non_qualified":null,"image":"1f468-1f3fd-200d-1f680.png","sheet_x":17,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F680","non_qualified":null,"image":"1f468-1f3fe-200d-1f680.png","sheet_x":17,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F680","non_qualified":null,"image":"1f468-1f3ff-200d-1f680.png","sheet_x":17,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Astronaut","b":"1F468-200D-1F680","k":[17,31]},"abcd":{"a":"Input Symbol for Latin Small Letters","b":"1F521","j":["blue-square","alphabet"],"k":[27,35]},"clock330":{"a":"Clock Face Three-Thirty","b":"1F55E","j":["time","late","early","schedule"],"k":[28,32]},"flag-lu":{"a":"Luxembourg Flag","b":"1F1F1-1F1FA","k":[3,14]},"wrench":{"a":"Wrench","b":"1F527","j":["tools","diy","ikea","fix","maintainer"],"k":[27,41]},"nut_and_bolt":{"a":"Nut and Bolt","b":"1F529","j":["handy","tools","fix"],"k":[27,43]},"clock4":{"a":"Clock Face Four Oclock","b":"1F553","j":["time","late","early","schedule"],"k":[28,21]},"female-astronaut":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F680","non_qualified":null,"image":"1f469-1f3fb-200d-1f680.png","sheet_x":19,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F680","non_qualified":null,"image":"1f469-1f3fc-200d-1f680.png","sheet_x":19,"sheet_y":43,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F680","non_qualified":null,"image":"1f469-1f3fd-200d-1f680.png","sheet_x":19,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F680","non_qualified":null,"image":"1f469-1f3fe-200d-1f680.png","sheet_x":19,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F680","non_qualified":null,"image":"1f469-1f3ff-200d-1f680.png","sheet_x":19,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Astronaut","b":"1F469-200D-1F680","k":[19,41]},"flag-lv":{"a":"Latvia Flag","b":"1F1F1-1F1FB","k":[3,15]},"gear":{"a":"Gear","b":"2699-FE0F","c":"2699","j":["cog"],"k":[48,17],"o":4},"male-firefighter":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F692","non_qualified":null,"image":"1f468-1f3fb-200d-1f692.png","sheet_x":17,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F468-1F3FC-200D-1F692","non_qualified":null,"image":"1f468-1f3fc-200d-1f692.png","sheet_x":17,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F468-1F3FD-200D-1F692","non_qualified":null,"image":"1f468-1f3fd-200d-1f692.png","sheet_x":17,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F468-1F3FE-200D-1F692","non_qualified":null,"image":"1f468-1f3fe-200d-1f692.png","sheet_x":17,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F468-1F3FF-200D-1F692","non_qualified":null,"image":"1f468-1f3ff-200d-1f692.png","sheet_x":17,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Male Firefighter","b":"1F468-200D-1F692","k":[17,37]},"flag-ly":{"a":"Libya Flag","b":"1F1F1-1F1FE","k":[3,16]},"symbols":{"a":"Input Symbol for Symbols","b":"1F523","j":["blue-square","music","note","ampersand","percent","glyphs","characters"],"k":[27,37]},"clock430":{"a":"Clock Face Four-Thirty","b":"1F55F","j":["time","late","early","schedule"],"k":[28,33]},"flag-ma":{"a":"Morocco Flag","b":"1F1F2-1F1E6","k":[3,17]},"compression":{"a":"Compression","b":"1F5DC-FE0F","c":"1F5DC","k":[30,10],"o":7},"female-firefighter":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F692","non_qualified":null,"image":"1f469-1f3fb-200d-1f692.png","sheet_x":19,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F469-1F3FC-200D-1F692","non_qualified":null,"image":"1f469-1f3fc-200d-1f692.png","sheet_x":19,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F469-1F3FD-200D-1F692","non_qualified":null,"image":"1f469-1f3fd-200d-1f692.png","sheet_x":19,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F469-1F3FE-200D-1F692","non_qualified":null,"image":"1f469-1f3fe-200d-1f692.png","sheet_x":19,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F469-1F3FF-200D-1F692","non_qualified":null,"image":"1f469-1f3ff-200d-1f692.png","sheet_x":20,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Female Firefighter","b":"1F469-200D-1F692","k":[19,47]},"abc":{"a":"Input Symbol for Latin Letters","b":"1F524","j":["blue-square","alphabet"],"k":[27,38]},"clock5":{"a":"Clock Face Five Oclock","b":"1F554","j":["time","late","early","schedule"],"k":[28,22]},"clock530":{"a":"Clock Face Five-Thirty","b":"1F560","j":["time","late","early","schedule"],"k":[28,34]},"a":{"a":"Negative Squared Latin Capital Letter a","b":"1F170-FE0F","c":"1F170","j":["red-square","alphabet","letter"],"k":[0,16]},"alembic":{"a":"Alembic","b":"2697-FE0F","c":"2697","j":["distilling","science","experiment","chemistry"],"k":[48,16],"o":4},"flag-mc":{"a":"Monaco Flag","b":"1F1F2-1F1E8","k":[3,18]},"cop":{"skin_variations":{"1F3FB":{"unified":"1F46E-1F3FB","non_qualified":null,"image":"1f46e-1f3fb.png","sheet_x":20,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F46E-1F3FC","non_qualified":null,"image":"1f46e-1f3fc.png","sheet_x":20,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F46E-1F3FD","non_qualified":null,"image":"1f46e-1f3fd.png","sheet_x":20,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F46E-1F3FE","non_qualified":null,"image":"1f46e-1f3fe.png","sheet_x":20,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F46E-1F3FF","non_qualified":null,"image":"1f46e-1f3ff.png","sheet_x":20,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F46E-200D-2642-FE0F","a":"Police Officer","b":"1F46E","k":[20,45]},"scales":{"a":"Scales","b":"2696-FE0F","c":"2696","k":[48,15],"o":4},"clock6":{"a":"Clock Face Six Oclock","b":"1F555","j":["time","late","early","schedule","dawn","dusk"],"k":[28,23]},"flag-md":{"a":"Moldova Flag","b":"1F1F2-1F1E9","k":[3,19]},"ab":{"a":"Negative Squared Ab","b":"1F18E","j":["red-square","alphabet"],"k":[0,20]},"male-police-officer":{"skin_variations":{"1F3FB":{"unified":"1F46E-1F3FB-200D-2642-FE0F","non_qualified":"1F46E-1F3FB-200D-2642","image":"1f46e-1f3fb-200d-2642-fe0f.png","sheet_x":20,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F46E-1F3FC-200D-2642-FE0F","non_qualified":"1F46E-1F3FC-200D-2642","image":"1f46e-1f3fc-200d-2642-fe0f.png","sheet_x":20,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F46E-1F3FD-200D-2642-FE0F","non_qualified":"1F46E-1F3FD-200D-2642","image":"1f46e-1f3fd-200d-2642-fe0f.png","sheet_x":20,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F46E-1F3FE-200D-2642-FE0F","non_qualified":"1F46E-1F3FE-200D-2642","image":"1f46e-1f3fe-200d-2642-fe0f.png","sheet_x":20,"sheet_y":43,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F46E-1F3FF-200D-2642-FE0F","non_qualified":"1F46E-1F3FF-200D-2642","image":"1f46e-1f3ff-200d-2642-fe0f.png","sheet_x":20,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F46E","a":"Male Police Officer","b":"1F46E-200D-2642-FE0F","c":"1F46E-200D-2642","k":[20,39]},"link":{"a":"Link Symbol","b":"1F517","j":["rings","url"],"k":[27,25]},"flag-me":{"a":"Montenegro Flag","b":"1F1F2-1F1EA","k":[3,20]},"clock630":{"a":"Clock Face Six-Thirty","b":"1F561","j":["time","late","early","schedule"],"k":[28,35]},"b":{"a":"Negative Squared Latin Capital Letter B","b":"1F171-FE0F","c":"1F171","j":["red-square","alphabet","letter"],"k":[0,17]},"female-police-officer":{"skin_variations":{"1F3FB":{"unified":"1F46E-1F3FB-200D-2640-FE0F","non_qualified":"1F46E-1F3FB-200D-2640","image":"1f46e-1f3fb-200d-2640-fe0f.png","sheet_x":20,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F46E-1F3FC-200D-2640-FE0F","non_qualified":"1F46E-1F3FC-200D-2640","image":"1f46e-1f3fc-200d-2640-fe0f.png","sheet_x":20,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F46E-1F3FD-200D-2640-FE0F","non_qualified":"1F46E-1F3FD-200D-2640","image":"1f46e-1f3fd-200d-2640-fe0f.png","sheet_x":20,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F46E-1F3FE-200D-2640-FE0F","non_qualified":"1F46E-1F3FE-200D-2640","image":"1f46e-1f3fe-200d-2640-fe0f.png","sheet_x":20,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F46E-1F3FF-200D-2640-FE0F","non_qualified":"1F46E-1F3FF-200D-2640","image":"1f46e-1f3ff-200d-2640-fe0f.png","sheet_x":20,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Female Police Officer","b":"1F46E-200D-2640-FE0F","c":"1F46E-200D-2640","k":[20,33]},"clock7":{"a":"Clock Face Seven Oclock","b":"1F556","j":["time","late","early","schedule"],"k":[28,24]},"cl":{"a":"Squared Cl","b":"1F191","j":["alphabet","words","red-square"],"k":[0,21]},"sleuth_or_spy":{"skin_variations":{"1F3FB":{"unified":"1F575-1F3FB","non_qualified":null,"image":"1f575-1f3fb.png","sheet_x":29,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F575-1F3FC","non_qualified":null,"image":"1f575-1f3fc.png","sheet_x":29,"sheet_y":13,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F575-1F3FD","non_qualified":null,"image":"1f575-1f3fd.png","sheet_x":29,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F575-1F3FE","non_qualified":null,"image":"1f575-1f3fe.png","sheet_x":29,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F575-1F3FF","non_qualified":null,"image":"1f575-1f3ff.png","sheet_x":29,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoleted_by":"1F575-FE0F-200D-2642-FE0F","a":"Sleuth or Spy","b":"1F575-FE0F","c":"1F575","k":[29,11],"o":7},"flag-mf":{"a":"St. Martin Flag","b":"1F1F2-1F1EB","k":[3,21]},"chains":{"a":"Chains","b":"26D3-FE0F","c":"26D3","j":["lock","arrest"],"k":[48,34],"o":5},"syringe":{"a":"Syringe","b":"1F489","j":["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],"k":[24,35]},"male-detective":{"skin_variations":{"1F3FB":{"unified":"1F575-1F3FB-200D-2642-FE0F","non_qualified":"1F575-1F3FB-200D-2642","image":"1f575-1f3fb-200d-2642-fe0f.png","sheet_x":29,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F575-1F3FC-200D-2642-FE0F","non_qualified":"1F575-1F3FC-200D-2642","image":"1f575-1f3fc-200d-2642-fe0f.png","sheet_x":29,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F575-1F3FD-200D-2642-FE0F","non_qualified":"1F575-1F3FD-200D-2642","image":"1f575-1f3fd-200d-2642-fe0f.png","sheet_x":29,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F575-1F3FE-200D-2642-FE0F","non_qualified":"1F575-1F3FE-200D-2642","image":"1f575-1f3fe-200d-2642-fe0f.png","sheet_x":29,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F575-1F3FF-200D-2642-FE0F","non_qualified":"1F575-1F3FF-200D-2642","image":"1f575-1f3ff-200d-2642-fe0f.png","sheet_x":29,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F575-FE0F","a":"Male Detective","b":"1F575-FE0F-200D-2642-FE0F","k":[29,5],"o":7},"cool":{"a":"Squared Cool","b":"1F192","j":["words","blue-square"],"k":[0,22]},"clock730":{"a":"Clock Face Seven-Thirty","b":"1F562","j":["time","late","early","schedule"],"k":[28,36]},"flag-mg":{"a":"Madagascar Flag","b":"1F1F2-1F1EC","k":[3,22]},"free":{"a":"Squared Free","b":"1F193","j":["blue-square","words"],"k":[0,23]},"flag-mh":{"a":"Marshall Islands Flag","b":"1F1F2-1F1ED","k":[3,23]},"clock8":{"a":"Clock Face Eight Oclock","b":"1F557","j":["time","late","early","schedule"],"k":[28,25]},"pill":{"a":"Pill","b":"1F48A","j":["health","medicine","doctor","pharmacy","drug"],"k":[24,36]},"female-detective":{"skin_variations":{"1F3FB":{"unified":"1F575-1F3FB-200D-2640-FE0F","non_qualified":"1F575-1F3FB-200D-2640","image":"1f575-1f3fb-200d-2640-fe0f.png","sheet_x":29,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F575-1F3FC-200D-2640-FE0F","non_qualified":"1F575-1F3FC-200D-2640","image":"1f575-1f3fc-200d-2640-fe0f.png","sheet_x":29,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F575-1F3FD-200D-2640-FE0F","non_qualified":"1F575-1F3FD-200D-2640","image":"1f575-1f3fd-200d-2640-fe0f.png","sheet_x":29,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F575-1F3FE-200D-2640-FE0F","non_qualified":"1F575-1F3FE-200D-2640","image":"1f575-1f3fe-200d-2640-fe0f.png","sheet_x":29,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F575-1F3FF-200D-2640-FE0F","non_qualified":"1F575-1F3FF-200D-2640","image":"1f575-1f3ff-200d-2640-fe0f.png","sheet_x":29,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Female Detective","b":"1F575-FE0F-200D-2640-FE0F","k":[28,51],"o":7},"clock830":{"a":"Clock Face Eight-Thirty","b":"1F563","j":["time","late","early","schedule"],"k":[28,37]},"guardsman":{"skin_variations":{"1F3FB":{"unified":"1F482-1F3FB","non_qualified":null,"image":"1f482-1f3fb.png","sheet_x":23,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F482-1F3FC","non_qualified":null,"image":"1f482-1f3fc.png","sheet_x":23,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F482-1F3FD","non_qualified":null,"image":"1f482-1f3fd.png","sheet_x":23,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F482-1F3FE","non_qualified":null,"image":"1f482-1f3fe.png","sheet_x":23,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F482-1F3FF","non_qualified":null,"image":"1f482-1f3ff.png","sheet_x":23,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F482-200D-2642-FE0F","a":"Guardsman","b":"1F482","j":["uk","gb","british","male","guy","royal"],"k":[23,31]},"information_source":{"a":"Information Source","b":"2139-FE0F","c":"2139","j":["blue-square","alphabet","letter"],"k":[46,32],"o":3},"flag-mk":{"a":"Macedonia Flag","b":"1F1F2-1F1F0","k":[3,24]},"smoking":{"a":"Smoking Symbol","b":"1F6AC","j":["kills","tobacco","cigarette","joint","smoke"],"k":[35,17]},"id":{"a":"Squared Id","b":"1F194","j":["purple-square","words"],"k":[0,24]},"clock9":{"a":"Clock Face Nine Oclock","b":"1F558","j":["time","late","early","schedule"],"k":[28,26]},"flag-ml":{"a":"Mali Flag","b":"1F1F2-1F1F1","k":[3,25]},"coffin":{"a":"Coffin","b":"26B0-FE0F","c":"26B0","j":["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],"k":[48,24],"o":4},"male-guard":{"skin_variations":{"1F3FB":{"unified":"1F482-1F3FB-200D-2642-FE0F","non_qualified":"1F482-1F3FB-200D-2642","image":"1f482-1f3fb-200d-2642-fe0f.png","sheet_x":23,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F482-1F3FC-200D-2642-FE0F","non_qualified":"1F482-1F3FC-200D-2642","image":"1f482-1f3fc-200d-2642-fe0f.png","sheet_x":23,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F482-1F3FD-200D-2642-FE0F","non_qualified":"1F482-1F3FD-200D-2642","image":"1f482-1f3fd-200d-2642-fe0f.png","sheet_x":23,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F482-1F3FE-200D-2642-FE0F","non_qualified":"1F482-1F3FE-200D-2642","image":"1f482-1f3fe-200d-2642-fe0f.png","sheet_x":23,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F482-1F3FF-200D-2642-FE0F","non_qualified":"1F482-1F3FF-200D-2642","image":"1f482-1f3ff-200d-2642-fe0f.png","sheet_x":23,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F482","a":"Male Guard","b":"1F482-200D-2642-FE0F","c":"1F482-200D-2642","k":[23,25]},"m":{"a":"Circled Latin Capital Letter M","b":"24C2-FE0F","c":"24C2","j":["alphabet","blue-circle","letter"],"k":[47,7],"o":1},"funeral_urn":{"a":"Funeral Urn","b":"26B1-FE0F","c":"26B1","j":["dead","die","death","rip","ashes"],"k":[48,25],"o":4},"female-guard":{"skin_variations":{"1F3FB":{"unified":"1F482-1F3FB-200D-2640-FE0F","non_qualified":"1F482-1F3FB-200D-2640","image":"1f482-1f3fb-200d-2640-fe0f.png","sheet_x":23,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F482-1F3FC-200D-2640-FE0F","non_qualified":"1F482-1F3FC-200D-2640","image":"1f482-1f3fc-200d-2640-fe0f.png","sheet_x":23,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F482-1F3FD-200D-2640-FE0F","non_qualified":"1F482-1F3FD-200D-2640","image":"1f482-1f3fd-200d-2640-fe0f.png","sheet_x":23,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F482-1F3FE-200D-2640-FE0F","non_qualified":"1F482-1F3FE-200D-2640","image":"1f482-1f3fe-200d-2640-fe0f.png","sheet_x":23,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F482-1F3FF-200D-2640-FE0F","non_qualified":"1F482-1F3FF-200D-2640","image":"1f482-1f3ff-200d-2640-fe0f.png","sheet_x":23,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Female Guard","b":"1F482-200D-2640-FE0F","c":"1F482-200D-2640","k":[23,19]},"flag-mm":{"a":"Myanmar (burma) Flag","b":"1F1F2-1F1F2","k":[3,26]},"clock930":{"a":"Clock Face Nine-Thirty","b":"1F564","j":["time","late","early","schedule"],"k":[28,38]},"moyai":{"a":"Moyai","b":"1F5FF","j":["rock","easter island","moai"],"k":[30,23]},"new":{"a":"Squared New","b":"1F195","j":["blue-square","words","start"],"k":[0,25]},"flag-mn":{"a":"Mongolia Flag","b":"1F1F2-1F1F3","k":[3,27]},"construction_worker":{"skin_variations":{"1F3FB":{"unified":"1F477-1F3FB","non_qualified":null,"image":"1f477-1f3fb.png","sheet_x":22,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F477-1F3FC","non_qualified":null,"image":"1f477-1f3fc.png","sheet_x":22,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F477-1F3FD","non_qualified":null,"image":"1f477-1f3fd.png","sheet_x":22,"sheet_y":31,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F477-1F3FE","non_qualified":null,"image":"1f477-1f3fe.png","sheet_x":22,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F477-1F3FF","non_qualified":null,"image":"1f477-1f3ff.png","sheet_x":22,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F477-200D-2642-FE0F","a":"Construction Worker","b":"1F477","k":[22,28]},"clock10":{"a":"Clock Face Ten Oclock","b":"1F559","j":["time","late","early","schedule"],"k":[28,27]},"clock1030":{"a":"Clock Face Ten-Thirty","b":"1F565","j":["time","late","early","schedule"],"k":[28,39]},"ng":{"a":"Squared Ng","b":"1F196","j":["blue-square","words","shape","icon"],"k":[0,26]},"male-construction-worker":{"skin_variations":{"1F3FB":{"unified":"1F477-1F3FB-200D-2642-FE0F","non_qualified":"1F477-1F3FB-200D-2642","image":"1f477-1f3fb-200d-2642-fe0f.png","sheet_x":22,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F477-1F3FC-200D-2642-FE0F","non_qualified":"1F477-1F3FC-200D-2642","image":"1f477-1f3fc-200d-2642-fe0f.png","sheet_x":22,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F477-1F3FD-200D-2642-FE0F","non_qualified":"1F477-1F3FD-200D-2642","image":"1f477-1f3fd-200d-2642-fe0f.png","sheet_x":22,"sheet_y":25,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F477-1F3FE-200D-2642-FE0F","non_qualified":"1F477-1F3FE-200D-2642","image":"1f477-1f3fe-200d-2642-fe0f.png","sheet_x":22,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F477-1F3FF-200D-2642-FE0F","non_qualified":"1F477-1F3FF-200D-2642","image":"1f477-1f3ff-200d-2642-fe0f.png","sheet_x":22,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F477","a":"Male Construction Worker","b":"1F477-200D-2642-FE0F","c":"1F477-200D-2642","k":[22,22]},"flag-mo":{"a":"Macau Sar China Flag","b":"1F1F2-1F1F4","k":[3,28]},"oil_drum":{"a":"Oil Drum","b":"1F6E2-FE0F","c":"1F6E2","j":["barrell"],"k":[37,10],"o":7},"o2":{"a":"Negative Squared Latin Capital Letter O","b":"1F17E-FE0F","c":"1F17E","j":["alphabet","red-square","letter"],"k":[0,18]},"female-construction-worker":{"skin_variations":{"1F3FB":{"unified":"1F477-1F3FB-200D-2640-FE0F","non_qualified":"1F477-1F3FB-200D-2640","image":"1f477-1f3fb-200d-2640-fe0f.png","sheet_x":22,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F477-1F3FC-200D-2640-FE0F","non_qualified":"1F477-1F3FC-200D-2640","image":"1f477-1f3fc-200d-2640-fe0f.png","sheet_x":22,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F477-1F3FD-200D-2640-FE0F","non_qualified":"1F477-1F3FD-200D-2640","image":"1f477-1f3fd-200d-2640-fe0f.png","sheet_x":22,"sheet_y":19,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F477-1F3FE-200D-2640-FE0F","non_qualified":"1F477-1F3FE-200D-2640","image":"1f477-1f3fe-200d-2640-fe0f.png","sheet_x":22,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F477-1F3FF-200D-2640-FE0F","non_qualified":"1F477-1F3FF-200D-2640","image":"1f477-1f3ff-200d-2640-fe0f.png","sheet_x":22,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Female Construction Worker","b":"1F477-200D-2640-FE0F","c":"1F477-200D-2640","k":[22,16]},"clock11":{"a":"Clock Face Eleven Oclock","b":"1F55A","j":["time","late","early","schedule"],"k":[28,28]},"crystal_ball":{"a":"Crystal Ball","b":"1F52E","j":["disco","party","magic","circus","fortune_teller"],"k":[27,48]},"flag-mp":{"a":"Northern Mariana Islands Flag","b":"1F1F2-1F1F5","k":[3,29]},"flag-mq":{"a":"Martinique Flag","b":"1F1F2-1F1F6","k":[3,30]},"prince":{"skin_variations":{"1F3FB":{"unified":"1F934-1F3FB","non_qualified":null,"image":"1f934-1f3fb.png","sheet_x":39,"sheet_y":29,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F934-1F3FC","non_qualified":null,"image":"1f934-1f3fc.png","sheet_x":39,"sheet_y":30,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F934-1F3FD","non_qualified":null,"image":"1f934-1f3fd.png","sheet_x":39,"sheet_y":31,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F934-1F3FE","non_qualified":null,"image":"1f934-1f3fe.png","sheet_x":39,"sheet_y":32,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F934-1F3FF","non_qualified":null,"image":"1f934-1f3ff.png","sheet_x":39,"sheet_y":33,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Prince","b":"1F934","j":["boy","man","male","crown","royal","king"],"k":[39,28],"o":9},"ok":{"a":"Squared Ok","b":"1F197","j":["good","agree","yes","blue-square"],"k":[0,27]},"clock1130":{"a":"Clock Face Eleven-Thirty","b":"1F566","j":["time","late","early","schedule"],"k":[28,40]},"shopping_trolley":{"a":"Shopping Trolley","b":"1F6D2","k":[37,7],"o":9},"flag-mr":{"a":"Mauritania Flag","b":"1F1F2-1F1F7","k":[3,31]},"princess":{"skin_variations":{"1F3FB":{"unified":"1F478-1F3FB","non_qualified":null,"image":"1f478-1f3fb.png","sheet_x":22,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F478-1F3FC","non_qualified":null,"image":"1f478-1f3fc.png","sheet_x":22,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F478-1F3FD","non_qualified":null,"image":"1f478-1f3fd.png","sheet_x":22,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F478-1F3FE","non_qualified":null,"image":"1f478-1f3fe.png","sheet_x":22,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F478-1F3FF","non_qualified":null,"image":"1f478-1f3ff.png","sheet_x":22,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Princess","b":"1F478","j":["girl","woman","female","blond","crown","royal","queen"],"k":[22,34]},"new_moon":{"a":"New Moon Symbol","b":"1F311","j":["nature","twilight","planet","space","night","evening","sleep"],"k":[6,9]},"parking":{"a":"Negative Squared Latin Capital Letter P","b":"1F17F-FE0F","c":"1F17F","j":["cars","blue-square","alphabet","letter"],"k":[0,19],"o":5},"sos":{"a":"Squared Sos","b":"1F198","j":["help","red-square","words","emergency","911"],"k":[0,28]},"man_with_turban":{"skin_variations":{"1F3FB":{"unified":"1F473-1F3FB","non_qualified":null,"image":"1f473-1f3fb.png","sheet_x":21,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F473-1F3FC","non_qualified":null,"image":"1f473-1f3fc.png","sheet_x":21,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F473-1F3FD","non_qualified":null,"image":"1f473-1f3fd.png","sheet_x":21,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F473-1F3FE","non_qualified":null,"image":"1f473-1f3fe.png","sheet_x":21,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F473-1F3FF","non_qualified":null,"image":"1f473-1f3ff.png","sheet_x":21,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F473-200D-2642-FE0F","a":"Man with Turban","b":"1F473","j":["male","indian","hinduism","arabs"],"k":[21,44]},"flag-ms":{"a":"Montserrat Flag","b":"1F1F2-1F1F8","k":[3,32]},"waxing_crescent_moon":{"a":"Waxing Crescent Moon Symbol","b":"1F312","j":["nature","twilight","planet","space","night","evening","sleep"],"k":[6,10]},"up":{"a":"Squared Up with Exclamation Mark","b":"1F199","j":["blue-square","above","high"],"k":[0,29]},"first_quarter_moon":{"a":"First Quarter Moon Symbol","b":"1F313","j":["nature","twilight","planet","space","night","evening","sleep"],"k":[6,11]},"flag-mt":{"a":"Malta Flag","b":"1F1F2-1F1F9","k":[3,33]},"man-wearing-turban":{"skin_variations":{"1F3FB":{"unified":"1F473-1F3FB-200D-2642-FE0F","non_qualified":"1F473-1F3FB-200D-2642","image":"1f473-1f3fb-200d-2642-fe0f.png","sheet_x":21,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F473-1F3FC-200D-2642-FE0F","non_qualified":"1F473-1F3FC-200D-2642","image":"1f473-1f3fc-200d-2642-fe0f.png","sheet_x":21,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F473-1F3FD-200D-2642-FE0F","non_qualified":"1F473-1F3FD-200D-2642","image":"1f473-1f3fd-200d-2642-fe0f.png","sheet_x":21,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F473-1F3FE-200D-2642-FE0F","non_qualified":"1F473-1F3FE-200D-2642","image":"1f473-1f3fe-200d-2642-fe0f.png","sheet_x":21,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F473-1F3FF-200D-2642-FE0F","non_qualified":"1F473-1F3FF-200D-2642","image":"1f473-1f3ff-200d-2642-fe0f.png","sheet_x":21,"sheet_y":43,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F473","a":"Man Wearing Turban","b":"1F473-200D-2642-FE0F","c":"1F473-200D-2642","k":[21,38]},"moon":{"a":"Waxing Gibbous Moon Symbol","b":"1F314","k":[6,12],"n":["waxing_gibbous_moon"]},"woman-wearing-turban":{"skin_variations":{"1F3FB":{"unified":"1F473-1F3FB-200D-2640-FE0F","non_qualified":"1F473-1F3FB-200D-2640","image":"1f473-1f3fb-200d-2640-fe0f.png","sheet_x":21,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F473-1F3FC-200D-2640-FE0F","non_qualified":"1F473-1F3FC-200D-2640","image":"1f473-1f3fc-200d-2640-fe0f.png","sheet_x":21,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F473-1F3FD-200D-2640-FE0F","non_qualified":"1F473-1F3FD-200D-2640","image":"1f473-1f3fd-200d-2640-fe0f.png","sheet_x":21,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F473-1F3FE-200D-2640-FE0F","non_qualified":"1F473-1F3FE-200D-2640","image":"1f473-1f3fe-200d-2640-fe0f.png","sheet_x":21,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F473-1F3FF-200D-2640-FE0F","non_qualified":"1F473-1F3FF-200D-2640","image":"1f473-1f3ff-200d-2640-fe0f.png","sheet_x":21,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Wearing Turban","b":"1F473-200D-2640-FE0F","c":"1F473-200D-2640","k":[21,32]},"vs":{"a":"Squared Vs","b":"1F19A","j":["words","orange-square"],"k":[0,30]},"flag-mu":{"a":"Mauritius Flag","b":"1F1F2-1F1FA","k":[3,34]},"man_with_gua_pi_mao":{"skin_variations":{"1F3FB":{"unified":"1F472-1F3FB","non_qualified":null,"image":"1f472-1f3fb.png","sheet_x":21,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F472-1F3FC","non_qualified":null,"image":"1f472-1f3fc.png","sheet_x":21,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F472-1F3FD","non_qualified":null,"image":"1f472-1f3fd.png","sheet_x":21,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F472-1F3FE","non_qualified":null,"image":"1f472-1f3fe.png","sheet_x":21,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F472-1F3FF","non_qualified":null,"image":"1f472-1f3ff.png","sheet_x":21,"sheet_y":31,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Man with Gua Pi Mao","b":"1F472","j":["male","boy","chinese"],"k":[21,26]},"koko":{"a":"Squared Katakana Koko","b":"1F201","j":["blue-square","here","katakana","japanese","destination"],"k":[5,29]},"full_moon":{"a":"Full Moon Symbol","b":"1F315","j":["nature","yellow","twilight","planet","space","night","evening","sleep"],"k":[6,13]},"flag-mv":{"a":"Maldives Flag","b":"1F1F2-1F1FB","k":[3,35]},"person_with_headscarf":{"skin_variations":{"1F3FB":{"unified":"1F9D5-1F3FB","non_qualified":null,"image":"1f9d5-1f3fb.png","sheet_x":43,"sheet_y":23,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F9D5-1F3FC","non_qualified":null,"image":"1f9d5-1f3fc.png","sheet_x":43,"sheet_y":24,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F9D5-1F3FD","non_qualified":null,"image":"1f9d5-1f3fd.png","sheet_x":43,"sheet_y":25,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F9D5-1F3FE","non_qualified":null,"image":"1f9d5-1f3fe.png","sheet_x":43,"sheet_y":26,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F9D5-1F3FF","non_qualified":null,"image":"1f9d5-1f3ff.png","sheet_x":43,"sheet_y":27,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Person with Headscarf","b":"1F9D5","k":[43,22],"o":10},"waning_gibbous_moon":{"a":"Waning Gibbous Moon Symbol","b":"1F316","j":["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],"k":[6,14]},"sa":{"a":"Squared Katakana Sa","b":"1F202-FE0F","c":"1F202","j":["japanese","blue-square","katakana"],"k":[5,30]},"flag-mw":{"a":"Malawi Flag","b":"1F1F2-1F1FC","k":[3,36]},"last_quarter_moon":{"a":"Last Quarter Moon Symbol","b":"1F317","j":["nature","twilight","planet","space","night","evening","sleep"],"k":[6,15]},"u6708":{"a":"Squared Cjk Unified Ideograph-6708","b":"1F237-FE0F","c":"1F237","j":["chinese","month","moon","japanese","orange-square","kanji"],"k":[5,38]},"bearded_person":{"skin_variations":{"1F3FB":{"unified":"1F9D4-1F3FB","non_qualified":null,"image":"1f9d4-1f3fb.png","sheet_x":43,"sheet_y":17,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F9D4-1F3FC","non_qualified":null,"image":"1f9d4-1f3fc.png","sheet_x":43,"sheet_y":18,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F9D4-1F3FD","non_qualified":null,"image":"1f9d4-1f3fd.png","sheet_x":43,"sheet_y":19,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F9D4-1F3FE","non_qualified":null,"image":"1f9d4-1f3fe.png","sheet_x":43,"sheet_y":20,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F9D4-1F3FF","non_qualified":null,"image":"1f9d4-1f3ff.png","sheet_x":43,"sheet_y":21,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Bearded Person","b":"1F9D4","k":[43,16],"o":10},"flag-mx":{"a":"Mexico Flag","b":"1F1F2-1F1FD","k":[3,37]},"u6709":{"a":"Squared Cjk Unified Ideograph-6709","b":"1F236","j":["orange-square","chinese","have","kanji"],"k":[5,37]},"person_with_blond_hair":{"skin_variations":{"1F3FB":{"unified":"1F471-1F3FB","non_qualified":null,"image":"1f471-1f3fb.png","sheet_x":21,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F471-1F3FC","non_qualified":null,"image":"1f471-1f3fc.png","sheet_x":21,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F471-1F3FD","non_qualified":null,"image":"1f471-1f3fd.png","sheet_x":21,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F471-1F3FE","non_qualified":null,"image":"1f471-1f3fe.png","sheet_x":21,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F471-1F3FF","non_qualified":null,"image":"1f471-1f3ff.png","sheet_x":21,"sheet_y":25,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F471-200D-2642-FE0F","a":"Person with Blond Hair","b":"1F471","k":[21,20]},"waning_crescent_moon":{"a":"Waning Crescent Moon Symbol","b":"1F318","j":["nature","twilight","planet","space","night","evening","sleep"],"k":[6,16]},"flag-my":{"a":"Malaysia Flag","b":"1F1F2-1F1FE","k":[3,38]},"u6307":{"a":"Squared Cjk Unified Ideograph-6307","b":"1F22F","j":["chinese","point","green-square","kanji"],"k":[5,32],"o":5},"blond-haired-man":{"skin_variations":{"1F3FB":{"unified":"1F471-1F3FB-200D-2642-FE0F","non_qualified":"1F471-1F3FB-200D-2642","image":"1f471-1f3fb-200d-2642-fe0f.png","sheet_x":21,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F471-1F3FC-200D-2642-FE0F","non_qualified":"1F471-1F3FC-200D-2642","image":"1f471-1f3fc-200d-2642-fe0f.png","sheet_x":21,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F471-1F3FD-200D-2642-FE0F","non_qualified":"1F471-1F3FD-200D-2642","image":"1f471-1f3fd-200d-2642-fe0f.png","sheet_x":21,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F471-1F3FE-200D-2642-FE0F","non_qualified":"1F471-1F3FE-200D-2642","image":"1f471-1f3fe-200d-2642-fe0f.png","sheet_x":21,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F471-1F3FF-200D-2642-FE0F","non_qualified":"1F471-1F3FF-200D-2642","image":"1f471-1f3ff-200d-2642-fe0f.png","sheet_x":21,"sheet_y":19,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F471","a":"Blond Haired Man","b":"1F471-200D-2642-FE0F","c":"1F471-200D-2642","k":[21,14]},"crescent_moon":{"a":"Crescent Moon","b":"1F319","j":["night","sleep","sky","evening","magic"],"k":[6,17]},"flag-mz":{"a":"Mozambique Flag","b":"1F1F2-1F1FF","k":[3,39]},"new_moon_with_face":{"a":"New Moon with Face","b":"1F31A","j":["nature","twilight","planet","space","night","evening","sleep"],"k":[6,18]},"flag-na":{"a":"Namibia Flag","b":"1F1F3-1F1E6","k":[3,40]},"blond-haired-woman":{"skin_variations":{"1F3FB":{"unified":"1F471-1F3FB-200D-2640-FE0F","non_qualified":"1F471-1F3FB-200D-2640","image":"1f471-1f3fb-200d-2640-fe0f.png","sheet_x":21,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F471-1F3FC-200D-2640-FE0F","non_qualified":"1F471-1F3FC-200D-2640","image":"1f471-1f3fc-200d-2640-fe0f.png","sheet_x":21,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F471-1F3FD-200D-2640-FE0F","non_qualified":"1F471-1F3FD-200D-2640","image":"1f471-1f3fd-200d-2640-fe0f.png","sheet_x":21,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F471-1F3FE-200D-2640-FE0F","non_qualified":"1F471-1F3FE-200D-2640","image":"1f471-1f3fe-200d-2640-fe0f.png","sheet_x":21,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F471-1F3FF-200D-2640-FE0F","non_qualified":"1F471-1F3FF-200D-2640","image":"1f471-1f3ff-200d-2640-fe0f.png","sheet_x":21,"sheet_y":13,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Blond Haired Woman","b":"1F471-200D-2640-FE0F","c":"1F471-200D-2640","k":[21,8]},"ideograph_advantage":{"a":"Circled Ideograph Advantage","b":"1F250","j":["chinese","kanji","obtain","get","circle"],"k":[5,42]},"first_quarter_moon_with_face":{"a":"First Quarter Moon with Face","b":"1F31B","j":["nature","twilight","planet","space","night","evening","sleep"],"k":[6,19]},"man_in_tuxedo":{"skin_variations":{"1F3FB":{"unified":"1F935-1F3FB","non_qualified":null,"image":"1f935-1f3fb.png","sheet_x":39,"sheet_y":35,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F935-1F3FC","non_qualified":null,"image":"1f935-1f3fc.png","sheet_x":39,"sheet_y":36,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F935-1F3FD","non_qualified":null,"image":"1f935-1f3fd.png","sheet_x":39,"sheet_y":37,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F935-1F3FE","non_qualified":null,"image":"1f935-1f3fe.png","sheet_x":39,"sheet_y":38,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F935-1F3FF","non_qualified":null,"image":"1f935-1f3ff.png","sheet_x":39,"sheet_y":39,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Man in Tuxedo","b":"1F935","j":["couple","marriage","wedding","groom"],"k":[39,34],"o":9},"flag-nc":{"a":"New Caledonia Flag","b":"1F1F3-1F1E8","k":[3,41]},"u5272":{"a":"Squared Cjk Unified Ideograph-5272","b":"1F239","j":["cut","divide","chinese","kanji","pink-square"],"k":[5,40]},"flag-ne":{"a":"Niger Flag","b":"1F1F3-1F1EA","k":[3,42]},"last_quarter_moon_with_face":{"a":"Last Quarter Moon with Face","b":"1F31C","j":["nature","twilight","planet","space","night","evening","sleep"],"k":[6,20]},"u7121":{"a":"Squared Cjk Unified Ideograph-7121","b":"1F21A","j":["nothing","chinese","kanji","japanese","orange-square"],"k":[5,31],"o":5},"bride_with_veil":{"skin_variations":{"1F3FB":{"unified":"1F470-1F3FB","non_qualified":null,"image":"1f470-1f3fb.png","sheet_x":21,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F470-1F3FC","non_qualified":null,"image":"1f470-1f3fc.png","sheet_x":21,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F470-1F3FD","non_qualified":null,"image":"1f470-1f3fd.png","sheet_x":21,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F470-1F3FE","non_qualified":null,"image":"1f470-1f3fe.png","sheet_x":21,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F470-1F3FF","non_qualified":null,"image":"1f470-1f3ff.png","sheet_x":21,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Bride with Veil","b":"1F470","j":["couple","marriage","wedding","woman","bride"],"k":[21,2]},"u7981":{"a":"Squared Cjk Unified Ideograph-7981","b":"1F232","j":["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],"k":[5,33]},"pregnant_woman":{"skin_variations":{"1F3FB":{"unified":"1F930-1F3FB","non_qualified":null,"image":"1f930-1f3fb.png","sheet_x":39,"sheet_y":5,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F930-1F3FC","non_qualified":null,"image":"1f930-1f3fc.png","sheet_x":39,"sheet_y":6,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F930-1F3FD","non_qualified":null,"image":"1f930-1f3fd.png","sheet_x":39,"sheet_y":7,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F930-1F3FE","non_qualified":null,"image":"1f930-1f3fe.png","sheet_x":39,"sheet_y":8,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F930-1F3FF","non_qualified":null,"image":"1f930-1f3ff.png","sheet_x":39,"sheet_y":9,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Pregnant Woman","b":"1F930","j":["baby"],"k":[39,4],"o":9},"thermometer":{"a":"Thermometer","b":"1F321-FE0F","c":"1F321","j":["weather","temperature","hot","cold"],"k":[6,25],"o":7},"flag-nf":{"a":"Norfolk Island Flag","b":"1F1F3-1F1EB","k":[3,43]},"sunny":{"a":"Black Sun with Rays","b":"2600-FE0F","c":"2600","j":["weather","nature","brightness","summer","beach","spring"],"k":[47,16],"o":1},"accept":{"a":"Circled Ideograph Accept","b":"1F251","j":["ok","good","chinese","kanji","agree","yes","orange-circle"],"k":[5,43]},"flag-ng":{"a":"Nigeria Flag","b":"1F1F3-1F1EC","k":[3,44]},"breast-feeding":{"skin_variations":{"1F3FB":{"unified":"1F931-1F3FB","non_qualified":null,"image":"1f931-1f3fb.png","sheet_x":39,"sheet_y":11,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F931-1F3FC","non_qualified":null,"image":"1f931-1f3fc.png","sheet_x":39,"sheet_y":12,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F931-1F3FD","non_qualified":null,"image":"1f931-1f3fd.png","sheet_x":39,"sheet_y":13,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F931-1F3FE","non_qualified":null,"image":"1f931-1f3fe.png","sheet_x":39,"sheet_y":14,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F931-1F3FF","non_qualified":null,"image":"1f931-1f3ff.png","sheet_x":39,"sheet_y":15,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Breast-Feeding","b":"1F931","k":[39,10],"o":10},"full_moon_with_face":{"a":"Full Moon with Face","b":"1F31D","j":["nature","twilight","planet","space","night","evening","sleep"],"k":[6,21]},"flag-ni":{"a":"Nicaragua Flag","b":"1F1F3-1F1EE","k":[3,45]},"u7533":{"a":"Squared Cjk Unified Ideograph-7533","b":"1F238","j":["chinese","japanese","kanji","orange-square"],"k":[5,39]},"angel":{"skin_variations":{"1F3FB":{"unified":"1F47C-1F3FB","non_qualified":null,"image":"1f47c-1f3fb.png","sheet_x":22,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F47C-1F3FC","non_qualified":null,"image":"1f47c-1f3fc.png","sheet_x":22,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F47C-1F3FD","non_qualified":null,"image":"1f47c-1f3fd.png","sheet_x":22,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F47C-1F3FE","non_qualified":null,"image":"1f47c-1f3fe.png","sheet_x":22,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F47C-1F3FF","non_qualified":null,"image":"1f47c-1f3ff.png","sheet_x":22,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Baby Angel","b":"1F47C","j":["heaven","wings","halo"],"k":[22,43]},"sun_with_face":{"a":"Sun with Face","b":"1F31E","j":["nature","morning","sky"],"k":[6,22]},"santa":{"skin_variations":{"1F3FB":{"unified":"1F385-1F3FB","non_qualified":null,"image":"1f385-1f3fb.png","sheet_x":8,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F385-1F3FC","non_qualified":null,"image":"1f385-1f3fc.png","sheet_x":8,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F385-1F3FD","non_qualified":null,"image":"1f385-1f3fd.png","sheet_x":8,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F385-1F3FE","non_qualified":null,"image":"1f385-1f3fe.png","sheet_x":8,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F385-1F3FF","non_qualified":null,"image":"1f385-1f3ff.png","sheet_x":8,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Father Christmas","b":"1F385","j":["festival","man","male","xmas","father christmas"],"k":[8,19]},"u5408":{"a":"Squared Cjk Unified Ideograph-5408","b":"1F234","j":["japanese","chinese","join","kanji","red-square"],"k":[5,35]},"flag-nl":{"a":"Netherlands Flag","b":"1F1F3-1F1F1","k":[3,46]},"mrs_claus":{"skin_variations":{"1F3FB":{"unified":"1F936-1F3FB","non_qualified":null,"image":"1f936-1f3fb.png","sheet_x":39,"sheet_y":41,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F936-1F3FC","non_qualified":null,"image":"1f936-1f3fc.png","sheet_x":39,"sheet_y":42,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F936-1F3FD","non_qualified":null,"image":"1f936-1f3fd.png","sheet_x":39,"sheet_y":43,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F936-1F3FE","non_qualified":null,"image":"1f936-1f3fe.png","sheet_x":39,"sheet_y":44,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F936-1F3FF","non_qualified":null,"image":"1f936-1f3ff.png","sheet_x":39,"sheet_y":45,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Mother Christmas","b":"1F936","j":["woman","female","xmas","mother christmas"],"k":[39,40],"n":["mother_christmas"],"o":9},"u7a7a":{"a":"Squared Cjk Unified Ideograph-7a7a","b":"1F233","j":["kanji","japanese","chinese","empty","sky","blue-square"],"k":[5,34]},"star":{"a":"White Medium Star","b":"2B50","j":["night","yellow"],"k":[50,22],"o":5},"flag-no":{"a":"Norway Flag","b":"1F1F3-1F1F4","k":[3,47]},"mage":{"skin_variations":{"1F3FB":{"unified":"1F9D9-1F3FB","non_qualified":null,"image":"1f9d9-1f3fb.png","sheet_x":44,"sheet_y":43,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D9-1F3FB-200D-2640-FE0F"},"1F3FC":{"unified":"1F9D9-1F3FC","non_qualified":null,"image":"1f9d9-1f3fc.png","sheet_x":44,"sheet_y":44,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D9-1F3FC-200D-2640-FE0F"},"1F3FD":{"unified":"1F9D9-1F3FD","non_qualified":null,"image":"1f9d9-1f3fd.png","sheet_x":44,"sheet_y":45,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D9-1F3FD-200D-2640-FE0F"},"1F3FE":{"unified":"1F9D9-1F3FE","non_qualified":null,"image":"1f9d9-1f3fe.png","sheet_x":44,"sheet_y":46,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D9-1F3FE-200D-2640-FE0F"},"1F3FF":{"unified":"1F9D9-1F3FF","non_qualified":null,"image":"1f9d9-1f3ff.png","sheet_x":44,"sheet_y":47,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D9-1F3FF-200D-2640-FE0F"}},"obsoleted_by":"1F9D9-200D-2640-FE0F","a":"Mage","b":"1F9D9","k":[44,42],"o":10},"star2":{"a":"Glowing Star","b":"1F31F","j":["night","sparkle","awesome","good","magic"],"k":[6,23]},"flag-np":{"a":"Nepal Flag","b":"1F1F3-1F1F5","k":[3,48]},"congratulations":{"a":"Circled Ideograph Congratulation","b":"3297-FE0F","c":"3297","j":["chinese","kanji","japanese","red-circle"],"k":[50,26],"o":1},"flag-nr":{"a":"Nauru Flag","b":"1F1F3-1F1F7","k":[3,49]},"stars":{"a":"Shooting Star","b":"1F320","j":["night","photo"],"k":[6,24]},"female_mage":{"skin_variations":{"1F3FB":{"unified":"1F9D9-1F3FB-200D-2640-FE0F","non_qualified":"1F9D9-1F3FB-200D-2640","image":"1f9d9-1f3fb-200d-2640-fe0f.png","sheet_x":44,"sheet_y":31,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D9-1F3FB"},"1F3FC":{"unified":"1F9D9-1F3FC-200D-2640-FE0F","non_qualified":"1F9D9-1F3FC-200D-2640","image":"1f9d9-1f3fc-200d-2640-fe0f.png","sheet_x":44,"sheet_y":32,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D9-1F3FC"},"1F3FD":{"unified":"1F9D9-1F3FD-200D-2640-FE0F","non_qualified":"1F9D9-1F3FD-200D-2640","image":"1f9d9-1f3fd-200d-2640-fe0f.png","sheet_x":44,"sheet_y":33,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D9-1F3FD"},"1F3FE":{"unified":"1F9D9-1F3FE-200D-2640-FE0F","non_qualified":"1F9D9-1F3FE-200D-2640","image":"1f9d9-1f3fe-200d-2640-fe0f.png","sheet_x":44,"sheet_y":34,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D9-1F3FE"},"1F3FF":{"unified":"1F9D9-1F3FF-200D-2640-FE0F","non_qualified":"1F9D9-1F3FF-200D-2640","image":"1f9d9-1f3ff-200d-2640-fe0f.png","sheet_x":44,"sheet_y":35,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D9-1F3FF"}},"obsoletes":"1F9D9","a":"Female Mage","b":"1F9D9-200D-2640-FE0F","c":"1F9D9-200D-2640","k":[44,30],"o":10},"secret":{"a":"Circled Ideograph Secret","b":"3299-FE0F","c":"3299","j":["privacy","chinese","sshh","kanji","red-circle"],"k":[50,27],"o":1},"flag-nu":{"a":"Niue Flag","b":"1F1F3-1F1FA","k":[3,50]},"u55b6":{"a":"Squared Cjk Unified Ideograph-55b6","b":"1F23A","j":["japanese","opening hours","orange-square"],"k":[5,41]},"male_mage":{"skin_variations":{"1F3FB":{"unified":"1F9D9-1F3FB-200D-2642-FE0F","non_qualified":"1F9D9-1F3FB-200D-2642","image":"1f9d9-1f3fb-200d-2642-fe0f.png","sheet_x":44,"sheet_y":37,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F9D9-1F3FC-200D-2642-FE0F","non_qualified":"1F9D9-1F3FC-200D-2642","image":"1f9d9-1f3fc-200d-2642-fe0f.png","sheet_x":44,"sheet_y":38,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F9D9-1F3FD-200D-2642-FE0F","non_qualified":"1F9D9-1F3FD-200D-2642","image":"1f9d9-1f3fd-200d-2642-fe0f.png","sheet_x":44,"sheet_y":39,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F9D9-1F3FE-200D-2642-FE0F","non_qualified":"1F9D9-1F3FE-200D-2642","image":"1f9d9-1f3fe-200d-2642-fe0f.png","sheet_x":44,"sheet_y":40,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F9D9-1F3FF-200D-2642-FE0F","non_qualified":"1F9D9-1F3FF-200D-2642","image":"1f9d9-1f3ff-200d-2642-fe0f.png","sheet_x":44,"sheet_y":41,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Male Mage","b":"1F9D9-200D-2642-FE0F","c":"1F9D9-200D-2642","k":[44,36],"o":10},"cloud":{"a":"Cloud","b":"2601-FE0F","c":"2601","j":["weather","sky"],"k":[47,17],"o":1},"flag-nz":{"a":"New Zealand Flag","b":"1F1F3-1F1FF","k":[3,51]},"partly_sunny":{"a":"Sun Behind Cloud","b":"26C5","j":["weather","nature","cloudy","morning","fall","spring"],"k":[48,29],"o":5},"fairy":{"skin_variations":{"1F3FB":{"unified":"1F9DA-1F3FB","non_qualified":null,"image":"1f9da-1f3fb.png","sheet_x":45,"sheet_y":9,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoleted_by":"1F9DA-1F3FB-200D-2640-FE0F"},"1F3FC":{"unified":"1F9DA-1F3FC","non_qualified":null,"image":"1f9da-1f3fc.png","sheet_x":45,"sheet_y":10,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoleted_by":"1F9DA-1F3FC-200D-2640-FE0F"},"1F3FD":{"unified":"1F9DA-1F3FD","non_qualified":null,"image":"1f9da-1f3fd.png","sheet_x":45,"sheet_y":11,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoleted_by":"1F9DA-1F3FD-200D-2640-FE0F"},"1F3FE":{"unified":"1F9DA-1F3FE","non_qualified":null,"image":"1f9da-1f3fe.png","sheet_x":45,"sheet_y":12,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoleted_by":"1F9DA-1F3FE-200D-2640-FE0F"},"1F3FF":{"unified":"1F9DA-1F3FF","non_qualified":null,"image":"1f9da-1f3ff.png","sheet_x":45,"sheet_y":13,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoleted_by":"1F9DA-1F3FF-200D-2640-FE0F"}},"obsoleted_by":"1F9DA-200D-2640-FE0F","a":"Fairy","b":"1F9DA","k":[45,8],"o":10},"u6e80":{"a":"Squared Cjk Unified Ideograph-6e80","b":"1F235","j":["full","chinese","japanese","red-square","kanji"],"k":[5,36]},"black_small_square":{"a":"Black Small Square","b":"25AA-FE0F","c":"25AA","j":["shape","icon"],"k":[47,8],"o":1},"thunder_cloud_and_rain":{"a":"Thunder Cloud and Rain","b":"26C8-FE0F","c":"26C8","k":[48,30],"o":5},"female_fairy":{"skin_variations":{"1F3FB":{"unified":"1F9DA-1F3FB-200D-2640-FE0F","non_qualified":"1F9DA-1F3FB-200D-2640","image":"1f9da-1f3fb-200d-2640-fe0f.png","sheet_x":44,"sheet_y":49,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DA-1F3FB"},"1F3FC":{"unified":"1F9DA-1F3FC-200D-2640-FE0F","non_qualified":"1F9DA-1F3FC-200D-2640","image":"1f9da-1f3fc-200d-2640-fe0f.png","sheet_x":44,"sheet_y":50,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DA-1F3FC"},"1F3FD":{"unified":"1F9DA-1F3FD-200D-2640-FE0F","non_qualified":"1F9DA-1F3FD-200D-2640","image":"1f9da-1f3fd-200d-2640-fe0f.png","sheet_x":44,"sheet_y":51,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DA-1F3FD"},"1F3FE":{"unified":"1F9DA-1F3FE-200D-2640-FE0F","non_qualified":"1F9DA-1F3FE-200D-2640","image":"1f9da-1f3fe-200d-2640-fe0f.png","sheet_x":45,"sheet_y":0,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DA-1F3FE"},"1F3FF":{"unified":"1F9DA-1F3FF-200D-2640-FE0F","non_qualified":"1F9DA-1F3FF-200D-2640","image":"1f9da-1f3ff-200d-2640-fe0f.png","sheet_x":45,"sheet_y":1,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DA-1F3FF"}},"obsoletes":"1F9DA","a":"Female Fairy","b":"1F9DA-200D-2640-FE0F","c":"1F9DA-200D-2640","k":[44,48],"o":10},"flag-om":{"a":"Oman Flag","b":"1F1F4-1F1F2","k":[4,0]},"white_small_square":{"a":"White Small Square","b":"25AB-FE0F","c":"25AB","j":["shape","icon"],"k":[47,9],"o":1},"flag-pa":{"a":"Panama Flag","b":"1F1F5-1F1E6","k":[4,1]},"mostly_sunny":{"a":"Mostly Sunny","b":"1F324-FE0F","c":"1F324","k":[6,26],"n":["sun_small_cloud"],"o":7},"male_fairy":{"skin_variations":{"1F3FB":{"unified":"1F9DA-1F3FB-200D-2642-FE0F","non_qualified":"1F9DA-1F3FB-200D-2642","image":"1f9da-1f3fb-200d-2642-fe0f.png","sheet_x":45,"sheet_y":3,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F9DA-1F3FC-200D-2642-FE0F","non_qualified":"1F9DA-1F3FC-200D-2642","image":"1f9da-1f3fc-200d-2642-fe0f.png","sheet_x":45,"sheet_y":4,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F9DA-1F3FD-200D-2642-FE0F","non_qualified":"1F9DA-1F3FD-200D-2642","image":"1f9da-1f3fd-200d-2642-fe0f.png","sheet_x":45,"sheet_y":5,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F9DA-1F3FE-200D-2642-FE0F","non_qualified":"1F9DA-1F3FE-200D-2642","image":"1f9da-1f3fe-200d-2642-fe0f.png","sheet_x":45,"sheet_y":6,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F9DA-1F3FF-200D-2642-FE0F","non_qualified":"1F9DA-1F3FF-200D-2642","image":"1f9da-1f3ff-200d-2642-fe0f.png","sheet_x":45,"sheet_y":7,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Male Fairy","b":"1F9DA-200D-2642-FE0F","c":"1F9DA-200D-2642","k":[45,2],"o":10},"barely_sunny":{"a":"Barely Sunny","b":"1F325-FE0F","c":"1F325","k":[6,27],"n":["sun_behind_cloud"],"o":7},"white_medium_square":{"a":"White Medium Square","b":"25FB-FE0F","c":"25FB","j":["shape","stone","icon"],"k":[47,12],"o":3},"flag-pe":{"a":"Peru Flag","b":"1F1F5-1F1EA","k":[4,2]},"vampire":{"skin_variations":{"1F3FB":{"unified":"1F9DB-1F3FB","non_qualified":null,"image":"1f9db-1f3fb.png","sheet_x":45,"sheet_y":27,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoleted_by":"1F9DB-1F3FB-200D-2640-FE0F"},"1F3FC":{"unified":"1F9DB-1F3FC","non_qualified":null,"image":"1f9db-1f3fc.png","sheet_x":45,"sheet_y":28,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoleted_by":"1F9DB-1F3FC-200D-2640-FE0F"},"1F3FD":{"unified":"1F9DB-1F3FD","non_qualified":null,"image":"1f9db-1f3fd.png","sheet_x":45,"sheet_y":29,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoleted_by":"1F9DB-1F3FD-200D-2640-FE0F"},"1F3FE":{"unified":"1F9DB-1F3FE","non_qualified":null,"image":"1f9db-1f3fe.png","sheet_x":45,"sheet_y":30,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoleted_by":"1F9DB-1F3FE-200D-2640-FE0F"},"1F3FF":{"unified":"1F9DB-1F3FF","non_qualified":null,"image":"1f9db-1f3ff.png","sheet_x":45,"sheet_y":31,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoleted_by":"1F9DB-1F3FF-200D-2640-FE0F"}},"obsoleted_by":"1F9DB-200D-2640-FE0F","a":"Vampire","b":"1F9DB","k":[45,26],"o":10},"female_vampire":{"skin_variations":{"1F3FB":{"unified":"1F9DB-1F3FB-200D-2640-FE0F","non_qualified":"1F9DB-1F3FB-200D-2640","image":"1f9db-1f3fb-200d-2640-fe0f.png","sheet_x":45,"sheet_y":15,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DB-1F3FB"},"1F3FC":{"unified":"1F9DB-1F3FC-200D-2640-FE0F","non_qualified":"1F9DB-1F3FC-200D-2640","image":"1f9db-1f3fc-200d-2640-fe0f.png","sheet_x":45,"sheet_y":16,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DB-1F3FC"},"1F3FD":{"unified":"1F9DB-1F3FD-200D-2640-FE0F","non_qualified":"1F9DB-1F3FD-200D-2640","image":"1f9db-1f3fd-200d-2640-fe0f.png","sheet_x":45,"sheet_y":17,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DB-1F3FD"},"1F3FE":{"unified":"1F9DB-1F3FE-200D-2640-FE0F","non_qualified":"1F9DB-1F3FE-200D-2640","image":"1f9db-1f3fe-200d-2640-fe0f.png","sheet_x":45,"sheet_y":18,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DB-1F3FE"},"1F3FF":{"unified":"1F9DB-1F3FF-200D-2640-FE0F","non_qualified":"1F9DB-1F3FF-200D-2640","image":"1f9db-1f3ff-200d-2640-fe0f.png","sheet_x":45,"sheet_y":19,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DB-1F3FF"}},"obsoletes":"1F9DB","a":"Female Vampire","b":"1F9DB-200D-2640-FE0F","c":"1F9DB-200D-2640","k":[45,14],"o":10},"partly_sunny_rain":{"a":"Partly Sunny Rain","b":"1F326-FE0F","c":"1F326","k":[6,28],"n":["sun_behind_rain_cloud"],"o":7},"flag-pf":{"a":"French Polynesia Flag","b":"1F1F5-1F1EB","k":[4,3]},"black_medium_square":{"a":"Black Medium Square","b":"25FC-FE0F","c":"25FC","j":["shape","button","icon"],"k":[47,13],"o":3},"white_medium_small_square":{"a":"White Medium Small Square","b":"25FD","j":["shape","stone","icon","button"],"k":[47,14],"o":3},"rain_cloud":{"a":"Rain Cloud","b":"1F327-FE0F","c":"1F327","k":[6,29],"o":7},"flag-pg":{"a":"Papua New Guinea Flag","b":"1F1F5-1F1EC","k":[4,4]},"male_vampire":{"skin_variations":{"1F3FB":{"unified":"1F9DB-1F3FB-200D-2642-FE0F","non_qualified":"1F9DB-1F3FB-200D-2642","image":"1f9db-1f3fb-200d-2642-fe0f.png","sheet_x":45,"sheet_y":21,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F9DB-1F3FC-200D-2642-FE0F","non_qualified":"1F9DB-1F3FC-200D-2642","image":"1f9db-1f3fc-200d-2642-fe0f.png","sheet_x":45,"sheet_y":22,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F9DB-1F3FD-200D-2642-FE0F","non_qualified":"1F9DB-1F3FD-200D-2642","image":"1f9db-1f3fd-200d-2642-fe0f.png","sheet_x":45,"sheet_y":23,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F9DB-1F3FE-200D-2642-FE0F","non_qualified":"1F9DB-1F3FE-200D-2642","image":"1f9db-1f3fe-200d-2642-fe0f.png","sheet_x":45,"sheet_y":24,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F9DB-1F3FF-200D-2642-FE0F","non_qualified":"1F9DB-1F3FF-200D-2642","image":"1f9db-1f3ff-200d-2642-fe0f.png","sheet_x":45,"sheet_y":25,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Male Vampire","b":"1F9DB-200D-2642-FE0F","c":"1F9DB-200D-2642","k":[45,20],"o":10},"flag-ph":{"a":"Philippines Flag","b":"1F1F5-1F1ED","k":[4,5]},"merperson":{"skin_variations":{"1F3FB":{"unified":"1F9DC-1F3FB","non_qualified":null,"image":"1f9dc-1f3fb.png","sheet_x":45,"sheet_y":45,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9DC-1F3FB-200D-2642-FE0F"},"1F3FC":{"unified":"1F9DC-1F3FC","non_qualified":null,"image":"1f9dc-1f3fc.png","sheet_x":45,"sheet_y":46,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9DC-1F3FC-200D-2642-FE0F"},"1F3FD":{"unified":"1F9DC-1F3FD","non_qualified":null,"image":"1f9dc-1f3fd.png","sheet_x":45,"sheet_y":47,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9DC-1F3FD-200D-2642-FE0F"},"1F3FE":{"unified":"1F9DC-1F3FE","non_qualified":null,"image":"1f9dc-1f3fe.png","sheet_x":45,"sheet_y":48,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9DC-1F3FE-200D-2642-FE0F"},"1F3FF":{"unified":"1F9DC-1F3FF","non_qualified":null,"image":"1f9dc-1f3ff.png","sheet_x":45,"sheet_y":49,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9DC-1F3FF-200D-2642-FE0F"}},"obsoleted_by":"1F9DC-200D-2642-FE0F","a":"Merperson","b":"1F9DC","k":[45,44],"o":10},"black_medium_small_square":{"a":"Black Medium Small Square","b":"25FE","j":["icon","shape","button"],"k":[47,15],"o":3},"snow_cloud":{"a":"Snow Cloud","b":"1F328-FE0F","c":"1F328","k":[6,30],"o":7},"lightning":{"a":"Lightning","b":"1F329-FE0F","c":"1F329","k":[6,31],"n":["lightning_cloud"],"o":7},"black_large_square":{"a":"Black Large Square","b":"2B1B","j":["shape","icon","button"],"k":[50,20],"o":5},"mermaid":{"skin_variations":{"1F3FB":{"unified":"1F9DC-1F3FB-200D-2640-FE0F","non_qualified":"1F9DC-1F3FB-200D-2640","image":"1f9dc-1f3fb-200d-2640-fe0f.png","sheet_x":45,"sheet_y":33,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F9DC-1F3FC-200D-2640-FE0F","non_qualified":"1F9DC-1F3FC-200D-2640","image":"1f9dc-1f3fc-200d-2640-fe0f.png","sheet_x":45,"sheet_y":34,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F9DC-1F3FD-200D-2640-FE0F","non_qualified":"1F9DC-1F3FD-200D-2640","image":"1f9dc-1f3fd-200d-2640-fe0f.png","sheet_x":45,"sheet_y":35,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F9DC-1F3FE-200D-2640-FE0F","non_qualified":"1F9DC-1F3FE-200D-2640","image":"1f9dc-1f3fe-200d-2640-fe0f.png","sheet_x":45,"sheet_y":36,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F9DC-1F3FF-200D-2640-FE0F","non_qualified":"1F9DC-1F3FF-200D-2640","image":"1f9dc-1f3ff-200d-2640-fe0f.png","sheet_x":45,"sheet_y":37,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Mermaid","b":"1F9DC-200D-2640-FE0F","c":"1F9DC-200D-2640","k":[45,32],"o":10},"flag-pk":{"a":"Pakistan Flag","b":"1F1F5-1F1F0","k":[4,6]},"merman":{"skin_variations":{"1F3FB":{"unified":"1F9DC-1F3FB-200D-2642-FE0F","non_qualified":"1F9DC-1F3FB-200D-2642","image":"1f9dc-1f3fb-200d-2642-fe0f.png","sheet_x":45,"sheet_y":39,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DC-1F3FB"},"1F3FC":{"unified":"1F9DC-1F3FC-200D-2642-FE0F","non_qualified":"1F9DC-1F3FC-200D-2642","image":"1f9dc-1f3fc-200d-2642-fe0f.png","sheet_x":45,"sheet_y":40,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DC-1F3FC"},"1F3FD":{"unified":"1F9DC-1F3FD-200D-2642-FE0F","non_qualified":"1F9DC-1F3FD-200D-2642","image":"1f9dc-1f3fd-200d-2642-fe0f.png","sheet_x":45,"sheet_y":41,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DC-1F3FD"},"1F3FE":{"unified":"1F9DC-1F3FE-200D-2642-FE0F","non_qualified":"1F9DC-1F3FE-200D-2642","image":"1f9dc-1f3fe-200d-2642-fe0f.png","sheet_x":45,"sheet_y":42,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DC-1F3FE"},"1F3FF":{"unified":"1F9DC-1F3FF-200D-2642-FE0F","non_qualified":"1F9DC-1F3FF-200D-2642","image":"1f9dc-1f3ff-200d-2642-fe0f.png","sheet_x":45,"sheet_y":43,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DC-1F3FF"}},"obsoletes":"1F9DC","a":"Merman","b":"1F9DC-200D-2642-FE0F","c":"1F9DC-200D-2642","k":[45,38],"o":10},"white_large_square":{"a":"White Large Square","b":"2B1C","j":["shape","icon","stone","button"],"k":[50,21],"o":5},"tornado":{"a":"Tornado","b":"1F32A-FE0F","c":"1F32A","j":["weather","cyclone","twister"],"k":[6,32],"n":["tornado_cloud"],"o":7},"flag-pl":{"a":"Poland Flag","b":"1F1F5-1F1F1","k":[4,7]},"elf":{"skin_variations":{"1F3FB":{"unified":"1F9DD-1F3FB","non_qualified":null,"image":"1f9dd-1f3fb.png","sheet_x":46,"sheet_y":11,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9DD-1F3FB-200D-2642-FE0F"},"1F3FC":{"unified":"1F9DD-1F3FC","non_qualified":null,"image":"1f9dd-1f3fc.png","sheet_x":46,"sheet_y":12,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9DD-1F3FC-200D-2642-FE0F"},"1F3FD":{"unified":"1F9DD-1F3FD","non_qualified":null,"image":"1f9dd-1f3fd.png","sheet_x":46,"sheet_y":13,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9DD-1F3FD-200D-2642-FE0F"},"1F3FE":{"unified":"1F9DD-1F3FE","non_qualified":null,"image":"1f9dd-1f3fe.png","sheet_x":46,"sheet_y":14,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9DD-1F3FE-200D-2642-FE0F"},"1F3FF":{"unified":"1F9DD-1F3FF","non_qualified":null,"image":"1f9dd-1f3ff.png","sheet_x":46,"sheet_y":15,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9DD-1F3FF-200D-2642-FE0F"}},"obsoleted_by":"1F9DD-200D-2642-FE0F","a":"Elf","b":"1F9DD","k":[46,10],"o":10},"fog":{"a":"Fog","b":"1F32B-FE0F","c":"1F32B","j":["weather"],"k":[6,33],"o":7},"large_orange_diamond":{"a":"Large Orange Diamond","b":"1F536","j":["shape","jewel","gem"],"k":[28,4]},"flag-pm":{"a":"St. Pierre & Miquelon Flag","b":"1F1F5-1F1F2","k":[4,8]},"flag-pn":{"a":"Pitcairn Islands Flag","b":"1F1F5-1F1F3","k":[4,9]},"wind_blowing_face":{"a":"Wind Blowing Face","b":"1F32C-FE0F","c":"1F32C","k":[6,34],"o":7},"female_elf":{"skin_variations":{"1F3FB":{"unified":"1F9DD-1F3FB-200D-2640-FE0F","non_qualified":"1F9DD-1F3FB-200D-2640","image":"1f9dd-1f3fb-200d-2640-fe0f.png","sheet_x":45,"sheet_y":51,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F9DD-1F3FC-200D-2640-FE0F","non_qualified":"1F9DD-1F3FC-200D-2640","image":"1f9dd-1f3fc-200d-2640-fe0f.png","sheet_x":46,"sheet_y":0,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F9DD-1F3FD-200D-2640-FE0F","non_qualified":"1F9DD-1F3FD-200D-2640","image":"1f9dd-1f3fd-200d-2640-fe0f.png","sheet_x":46,"sheet_y":1,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F9DD-1F3FE-200D-2640-FE0F","non_qualified":"1F9DD-1F3FE-200D-2640","image":"1f9dd-1f3fe-200d-2640-fe0f.png","sheet_x":46,"sheet_y":2,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F9DD-1F3FF-200D-2640-FE0F","non_qualified":"1F9DD-1F3FF-200D-2640","image":"1f9dd-1f3ff-200d-2640-fe0f.png","sheet_x":46,"sheet_y":3,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Female Elf","b":"1F9DD-200D-2640-FE0F","c":"1F9DD-200D-2640","k":[45,50],"o":10},"large_blue_diamond":{"a":"Large Blue Diamond","b":"1F537","j":["shape","jewel","gem"],"k":[28,5]},"male_elf":{"skin_variations":{"1F3FB":{"unified":"1F9DD-1F3FB-200D-2642-FE0F","non_qualified":"1F9DD-1F3FB-200D-2642","image":"1f9dd-1f3fb-200d-2642-fe0f.png","sheet_x":46,"sheet_y":5,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DD-1F3FB"},"1F3FC":{"unified":"1F9DD-1F3FC-200D-2642-FE0F","non_qualified":"1F9DD-1F3FC-200D-2642","image":"1f9dd-1f3fc-200d-2642-fe0f.png","sheet_x":46,"sheet_y":6,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DD-1F3FC"},"1F3FD":{"unified":"1F9DD-1F3FD-200D-2642-FE0F","non_qualified":"1F9DD-1F3FD-200D-2642","image":"1f9dd-1f3fd-200d-2642-fe0f.png","sheet_x":46,"sheet_y":7,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DD-1F3FD"},"1F3FE":{"unified":"1F9DD-1F3FE-200D-2642-FE0F","non_qualified":"1F9DD-1F3FE-200D-2642","image":"1f9dd-1f3fe-200d-2642-fe0f.png","sheet_x":46,"sheet_y":8,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DD-1F3FE"},"1F3FF":{"unified":"1F9DD-1F3FF-200D-2642-FE0F","non_qualified":"1F9DD-1F3FF-200D-2642","image":"1f9dd-1f3ff-200d-2642-fe0f.png","sheet_x":46,"sheet_y":9,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9DD-1F3FF"}},"obsoletes":"1F9DD","a":"Male Elf","b":"1F9DD-200D-2642-FE0F","c":"1F9DD-200D-2642","k":[46,4],"o":10},"small_orange_diamond":{"a":"Small Orange Diamond","b":"1F538","j":["shape","jewel","gem"],"k":[28,6]},"flag-pr":{"a":"Puerto Rico Flag","b":"1F1F5-1F1F7","k":[4,10]},"cyclone":{"a":"Cyclone","b":"1F300","j":["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],"k":[5,44]},"rainbow":{"a":"Rainbow","b":"1F308","j":["nature","happy","unicorn_face","photo","sky","spring"],"k":[6,0]},"small_blue_diamond":{"a":"Small Blue Diamond","b":"1F539","j":["shape","jewel","gem"],"k":[28,7]},"genie":{"obsoleted_by":"1F9DE-200D-2642-FE0F","a":"Genie","b":"1F9DE","k":[46,18],"o":10},"flag-ps":{"a":"Palestinian Territories Flag","b":"1F1F5-1F1F8","k":[4,11]},"small_red_triangle":{"a":"Up-Pointing Red Triangle","b":"1F53A","j":["shape","direction","up","top"],"k":[28,8]},"closed_umbrella":{"a":"Closed Umbrella","b":"1F302","j":["weather","rain","drizzle"],"k":[5,46]},"female_genie":{"a":"Female Genie","b":"1F9DE-200D-2640-FE0F","c":"1F9DE-200D-2640","k":[46,16],"o":10},"flag-pt":{"a":"Portugal Flag","b":"1F1F5-1F1F9","k":[4,12]},"flag-pw":{"a":"Palau Flag","b":"1F1F5-1F1FC","k":[4,13]},"small_red_triangle_down":{"a":"Down-Pointing Red Triangle","b":"1F53B","j":["shape","direction","bottom"],"k":[28,9]},"umbrella":{"a":"Umbrella","b":"2602-FE0F","c":"2602","j":["rainy","weather","spring"],"k":[47,18],"o":1},"male_genie":{"obsoletes":"1F9DE","a":"Male Genie","b":"1F9DE-200D-2642-FE0F","c":"1F9DE-200D-2642","k":[46,17],"o":10},"zombie":{"obsoleted_by":"1F9DF-200D-2642-FE0F","a":"Zombie","b":"1F9DF","k":[46,21],"o":10},"flag-py":{"a":"Paraguay Flag","b":"1F1F5-1F1FE","k":[4,14]},"diamond_shape_with_a_dot_inside":{"a":"Diamond Shape with a Dot Inside","b":"1F4A0","j":["jewel","blue","gem","crystal","fancy"],"k":[25,6]},"umbrella_with_rain_drops":{"a":"Umbrella with Rain Drops","b":"2614","k":[47,23],"o":4},"radio_button":{"a":"Radio Button","b":"1F518","j":["input","old","music","circle"],"k":[27,26]},"female_zombie":{"a":"Female Zombie","b":"1F9DF-200D-2640-FE0F","c":"1F9DF-200D-2640","k":[46,19],"o":10},"flag-qa":{"a":"Qatar Flag","b":"1F1F6-1F1E6","k":[4,15]},"umbrella_on_ground":{"a":"Umbrella on Ground","b":"26F1-FE0F","c":"26F1","k":[48,39],"o":5},"black_square_button":{"a":"Black Square Button","b":"1F532","j":["shape","input","frame"],"k":[28,0]},"zap":{"a":"High Voltage Sign","b":"26A1","j":["thunder","weather","lightning bolt","fast"],"k":[48,21],"o":4},"male_zombie":{"obsoletes":"1F9DF","a":"Male Zombie","b":"1F9DF-200D-2642-FE0F","c":"1F9DF-200D-2642","k":[46,20],"o":10},"flag-re":{"a":"Réunion Flag","b":"1F1F7-1F1EA","k":[4,16]},"flag-ro":{"a":"Romania Flag","b":"1F1F7-1F1F4","k":[4,17]},"snowflake":{"a":"Snowflake","b":"2744-FE0F","c":"2744","j":["winter","season","cold","weather","christmas","xmas"],"k":[49,51],"o":1},"white_square_button":{"a":"White Square Button","b":"1F533","j":["shape","input"],"k":[28,1]},"person_frowning":{"skin_variations":{"1F3FB":{"unified":"1F64D-1F3FB","non_qualified":null,"image":"1f64d-1f3fb.png","sheet_x":33,"sheet_y":31,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F64D-1F3FC","non_qualified":null,"image":"1f64d-1f3fc.png","sheet_x":33,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F64D-1F3FD","non_qualified":null,"image":"1f64d-1f3fd.png","sheet_x":33,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F64D-1F3FE","non_qualified":null,"image":"1f64d-1f3fe.png","sheet_x":33,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F64D-1F3FF","non_qualified":null,"image":"1f64d-1f3ff.png","sheet_x":33,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F64D-200D-2640-FE0F","a":"Person Frowning","b":"1F64D","k":[33,30]},"flag-rs":{"a":"Serbia Flag","b":"1F1F7-1F1F8","k":[4,18]},"man-frowning":{"skin_variations":{"1F3FB":{"unified":"1F64D-1F3FB-200D-2642-FE0F","non_qualified":"1F64D-1F3FB-200D-2642","image":"1f64d-1f3fb-200d-2642-fe0f.png","sheet_x":33,"sheet_y":25,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F64D-1F3FC-200D-2642-FE0F","non_qualified":"1F64D-1F3FC-200D-2642","image":"1f64d-1f3fc-200d-2642-fe0f.png","sheet_x":33,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F64D-1F3FD-200D-2642-FE0F","non_qualified":"1F64D-1F3FD-200D-2642","image":"1f64d-1f3fd-200d-2642-fe0f.png","sheet_x":33,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F64D-1F3FE-200D-2642-FE0F","non_qualified":"1F64D-1F3FE-200D-2642","image":"1f64d-1f3fe-200d-2642-fe0f.png","sheet_x":33,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F64D-1F3FF-200D-2642-FE0F","non_qualified":"1F64D-1F3FF-200D-2642","image":"1f64d-1f3ff-200d-2642-fe0f.png","sheet_x":33,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Frowning","b":"1F64D-200D-2642-FE0F","c":"1F64D-200D-2642","k":[33,24]},"white_circle":{"a":"Medium White Circle","b":"26AA","j":["shape","round"],"k":[48,22],"o":4},"snowman":{"a":"Snowman","b":"2603-FE0F","c":"2603","j":["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],"k":[47,19],"o":1},"snowman_without_snow":{"a":"Snowman Without Snow","b":"26C4","k":[48,28],"o":5},"ru":{"a":"Russia Flag","b":"1F1F7-1F1FA","j":["russian","federation","flag","nation","country","banner"],"k":[4,19],"n":["flag-ru"]},"black_circle":{"a":"Medium Black Circle","b":"26AB","j":["shape","button","round"],"k":[48,23],"o":4},"woman-frowning":{"skin_variations":{"1F3FB":{"unified":"1F64D-1F3FB-200D-2640-FE0F","non_qualified":"1F64D-1F3FB-200D-2640","image":"1f64d-1f3fb-200d-2640-fe0f.png","sheet_x":33,"sheet_y":19,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F64D-1F3FC-200D-2640-FE0F","non_qualified":"1F64D-1F3FC-200D-2640","image":"1f64d-1f3fc-200d-2640-fe0f.png","sheet_x":33,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F64D-1F3FD-200D-2640-FE0F","non_qualified":"1F64D-1F3FD-200D-2640","image":"1f64d-1f3fd-200d-2640-fe0f.png","sheet_x":33,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F64D-1F3FE-200D-2640-FE0F","non_qualified":"1F64D-1F3FE-200D-2640","image":"1f64d-1f3fe-200d-2640-fe0f.png","sheet_x":33,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F64D-1F3FF-200D-2640-FE0F","non_qualified":"1F64D-1F3FF-200D-2640","image":"1f64d-1f3ff-200d-2640-fe0f.png","sheet_x":33,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F64D","a":"Woman Frowning","b":"1F64D-200D-2640-FE0F","c":"1F64D-200D-2640","k":[33,18]},"flag-rw":{"a":"Rwanda Flag","b":"1F1F7-1F1FC","k":[4,20]},"comet":{"a":"Comet","b":"2604-FE0F","c":"2604","j":["space"],"k":[47,20],"o":1},"person_with_pouting_face":{"skin_variations":{"1F3FB":{"unified":"1F64E-1F3FB","non_qualified":null,"image":"1f64e-1f3fb.png","sheet_x":33,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F64E-1F3FC","non_qualified":null,"image":"1f64e-1f3fc.png","sheet_x":33,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F64E-1F3FD","non_qualified":null,"image":"1f64e-1f3fd.png","sheet_x":33,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F64E-1F3FE","non_qualified":null,"image":"1f64e-1f3fe.png","sheet_x":34,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F64E-1F3FF","non_qualified":null,"image":"1f64e-1f3ff.png","sheet_x":34,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F64E-200D-2640-FE0F","a":"Person with Pouting Face","b":"1F64E","k":[33,48]},"red_circle":{"a":"Large Red Circle","b":"1F534","j":["shape","error","danger"],"k":[28,2]},"large_blue_circle":{"a":"Large Blue Circle","b":"1F535","j":["shape","icon","button"],"k":[28,3]},"man-pouting":{"skin_variations":{"1F3FB":{"unified":"1F64E-1F3FB-200D-2642-FE0F","non_qualified":"1F64E-1F3FB-200D-2642","image":"1f64e-1f3fb-200d-2642-fe0f.png","sheet_x":33,"sheet_y":43,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F64E-1F3FC-200D-2642-FE0F","non_qualified":"1F64E-1F3FC-200D-2642","image":"1f64e-1f3fc-200d-2642-fe0f.png","sheet_x":33,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F64E-1F3FD-200D-2642-FE0F","non_qualified":"1F64E-1F3FD-200D-2642","image":"1f64e-1f3fd-200d-2642-fe0f.png","sheet_x":33,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F64E-1F3FE-200D-2642-FE0F","non_qualified":"1F64E-1F3FE-200D-2642","image":"1f64e-1f3fe-200d-2642-fe0f.png","sheet_x":33,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F64E-1F3FF-200D-2642-FE0F","non_qualified":"1F64E-1F3FF-200D-2642","image":"1f64e-1f3ff-200d-2642-fe0f.png","sheet_x":33,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Pouting","b":"1F64E-200D-2642-FE0F","c":"1F64E-200D-2642","k":[33,42]},"flag-sa":{"a":"Saudi Arabia Flag","b":"1F1F8-1F1E6","k":[4,21]},"fire":{"a":"Fire","b":"1F525","j":["hot","cook","flame"],"k":[27,39]},"woman-pouting":{"skin_variations":{"1F3FB":{"unified":"1F64E-1F3FB-200D-2640-FE0F","non_qualified":"1F64E-1F3FB-200D-2640","image":"1f64e-1f3fb-200d-2640-fe0f.png","sheet_x":33,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F64E-1F3FC-200D-2640-FE0F","non_qualified":"1F64E-1F3FC-200D-2640","image":"1f64e-1f3fc-200d-2640-fe0f.png","sheet_x":33,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F64E-1F3FD-200D-2640-FE0F","non_qualified":"1F64E-1F3FD-200D-2640","image":"1f64e-1f3fd-200d-2640-fe0f.png","sheet_x":33,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F64E-1F3FE-200D-2640-FE0F","non_qualified":"1F64E-1F3FE-200D-2640","image":"1f64e-1f3fe-200d-2640-fe0f.png","sheet_x":33,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F64E-1F3FF-200D-2640-FE0F","non_qualified":"1F64E-1F3FF-200D-2640","image":"1f64e-1f3ff-200d-2640-fe0f.png","sheet_x":33,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F64E","a":"Woman Pouting","b":"1F64E-200D-2640-FE0F","c":"1F64E-200D-2640","k":[33,36]},"flag-sb":{"a":"Solomon Islands Flag","b":"1F1F8-1F1E7","k":[4,22]},"droplet":{"a":"Droplet","b":"1F4A7","j":["water","drip","faucet","spring"],"k":[25,13]},"no_good":{"skin_variations":{"1F3FB":{"unified":"1F645-1F3FB","non_qualified":null,"image":"1f645-1f3fb.png","sheet_x":32,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F645-1F3FC","non_qualified":null,"image":"1f645-1f3fc.png","sheet_x":32,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F645-1F3FD","non_qualified":null,"image":"1f645-1f3fd.png","sheet_x":32,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F645-1F3FE","non_qualified":null,"image":"1f645-1f3fe.png","sheet_x":32,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F645-1F3FF","non_qualified":null,"image":"1f645-1f3ff.png","sheet_x":32,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F645-200D-2640-FE0F","a":"Face with No Good Gesture","b":"1F645","k":[32,1]},"flag-sc":{"a":"Seychelles Flag","b":"1F1F8-1F1E8","k":[4,23]},"ocean":{"a":"Water Wave","b":"1F30A","j":["sea","water","wave","nature","tsunami","disaster"],"k":[6,2]},"man-gesturing-no":{"skin_variations":{"1F3FB":{"unified":"1F645-1F3FB-200D-2642-FE0F","non_qualified":"1F645-1F3FB-200D-2642","image":"1f645-1f3fb-200d-2642-fe0f.png","sheet_x":31,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F645-1F3FC-200D-2642-FE0F","non_qualified":"1F645-1F3FC-200D-2642","image":"1f645-1f3fc-200d-2642-fe0f.png","sheet_x":31,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F645-1F3FD-200D-2642-FE0F","non_qualified":"1F645-1F3FD-200D-2642","image":"1f645-1f3fd-200d-2642-fe0f.png","sheet_x":31,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F645-1F3FE-200D-2642-FE0F","non_qualified":"1F645-1F3FE-200D-2642","image":"1f645-1f3fe-200d-2642-fe0f.png","sheet_x":31,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F645-1F3FF-200D-2642-FE0F","non_qualified":"1F645-1F3FF-200D-2642","image":"1f645-1f3ff-200d-2642-fe0f.png","sheet_x":32,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Gesturing No","b":"1F645-200D-2642-FE0F","c":"1F645-200D-2642","k":[31,47]},"flag-sd":{"a":"Sudan Flag","b":"1F1F8-1F1E9","k":[4,24]},"woman-gesturing-no":{"skin_variations":{"1F3FB":{"unified":"1F645-1F3FB-200D-2640-FE0F","non_qualified":"1F645-1F3FB-200D-2640","image":"1f645-1f3fb-200d-2640-fe0f.png","sheet_x":31,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F645-1F3FC-200D-2640-FE0F","non_qualified":"1F645-1F3FC-200D-2640","image":"1f645-1f3fc-200d-2640-fe0f.png","sheet_x":31,"sheet_y":43,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F645-1F3FD-200D-2640-FE0F","non_qualified":"1F645-1F3FD-200D-2640","image":"1f645-1f3fd-200d-2640-fe0f.png","sheet_x":31,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F645-1F3FE-200D-2640-FE0F","non_qualified":"1F645-1F3FE-200D-2640","image":"1f645-1f3fe-200d-2640-fe0f.png","sheet_x":31,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F645-1F3FF-200D-2640-FE0F","non_qualified":"1F645-1F3FF-200D-2640","image":"1f645-1f3ff-200d-2640-fe0f.png","sheet_x":31,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F645","a":"Woman Gesturing No","b":"1F645-200D-2640-FE0F","c":"1F645-200D-2640","k":[31,41]},"flag-se":{"a":"Sweden Flag","b":"1F1F8-1F1EA","k":[4,25]},"flag-sg":{"a":"Singapore Flag","b":"1F1F8-1F1EC","k":[4,26]},"ok_woman":{"skin_variations":{"1F3FB":{"unified":"1F646-1F3FB","non_qualified":null,"image":"1f646-1f3fb.png","sheet_x":32,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F646-1F3FC","non_qualified":null,"image":"1f646-1f3fc.png","sheet_x":32,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F646-1F3FD","non_qualified":null,"image":"1f646-1f3fd.png","sheet_x":32,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F646-1F3FE","non_qualified":null,"image":"1f646-1f3fe.png","sheet_x":32,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F646-1F3FF","non_qualified":null,"image":"1f646-1f3ff.png","sheet_x":32,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F646-200D-2640-FE0F","a":"Face with Ok Gesture","b":"1F646","j":["women","girl","female","pink","human","woman"],"k":[32,19]},"flag-sh":{"a":"St. Helena Flag","b":"1F1F8-1F1ED","k":[4,27]},"man-gesturing-ok":{"skin_variations":{"1F3FB":{"unified":"1F646-1F3FB-200D-2642-FE0F","non_qualified":"1F646-1F3FB-200D-2642","image":"1f646-1f3fb-200d-2642-fe0f.png","sheet_x":32,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F646-1F3FC-200D-2642-FE0F","non_qualified":"1F646-1F3FC-200D-2642","image":"1f646-1f3fc-200d-2642-fe0f.png","sheet_x":32,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F646-1F3FD-200D-2642-FE0F","non_qualified":"1F646-1F3FD-200D-2642","image":"1f646-1f3fd-200d-2642-fe0f.png","sheet_x":32,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F646-1F3FE-200D-2642-FE0F","non_qualified":"1F646-1F3FE-200D-2642","image":"1f646-1f3fe-200d-2642-fe0f.png","sheet_x":32,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F646-1F3FF-200D-2642-FE0F","non_qualified":"1F646-1F3FF-200D-2642","image":"1f646-1f3ff-200d-2642-fe0f.png","sheet_x":32,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Gesturing Ok","b":"1F646-200D-2642-FE0F","c":"1F646-200D-2642","k":[32,13]},"flag-si":{"a":"Slovenia Flag","b":"1F1F8-1F1EE","k":[4,28]},"woman-gesturing-ok":{"skin_variations":{"1F3FB":{"unified":"1F646-1F3FB-200D-2640-FE0F","non_qualified":"1F646-1F3FB-200D-2640","image":"1f646-1f3fb-200d-2640-fe0f.png","sheet_x":32,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F646-1F3FC-200D-2640-FE0F","non_qualified":"1F646-1F3FC-200D-2640","image":"1f646-1f3fc-200d-2640-fe0f.png","sheet_x":32,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F646-1F3FD-200D-2640-FE0F","non_qualified":"1F646-1F3FD-200D-2640","image":"1f646-1f3fd-200d-2640-fe0f.png","sheet_x":32,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F646-1F3FE-200D-2640-FE0F","non_qualified":"1F646-1F3FE-200D-2640","image":"1f646-1f3fe-200d-2640-fe0f.png","sheet_x":32,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F646-1F3FF-200D-2640-FE0F","non_qualified":"1F646-1F3FF-200D-2640","image":"1f646-1f3ff-200d-2640-fe0f.png","sheet_x":32,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F646","a":"Woman Gesturing Ok","b":"1F646-200D-2640-FE0F","c":"1F646-200D-2640","k":[32,7]},"information_desk_person":{"skin_variations":{"1F3FB":{"unified":"1F481-1F3FB","non_qualified":null,"image":"1f481-1f3fb.png","sheet_x":23,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F481-1F3FC","non_qualified":null,"image":"1f481-1f3fc.png","sheet_x":23,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F481-1F3FD","non_qualified":null,"image":"1f481-1f3fd.png","sheet_x":23,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F481-1F3FE","non_qualified":null,"image":"1f481-1f3fe.png","sheet_x":23,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F481-1F3FF","non_qualified":null,"image":"1f481-1f3ff.png","sheet_x":23,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F481-200D-2640-FE0F","a":"Information Desk Person","b":"1F481","k":[23,13]},"flag-sj":{"a":"Svalbard & Jan Mayen Flag","b":"1F1F8-1F1EF","k":[4,29]},"man-tipping-hand":{"skin_variations":{"1F3FB":{"unified":"1F481-1F3FB-200D-2642-FE0F","non_qualified":"1F481-1F3FB-200D-2642","image":"1f481-1f3fb-200d-2642-fe0f.png","sheet_x":23,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F481-1F3FC-200D-2642-FE0F","non_qualified":"1F481-1F3FC-200D-2642","image":"1f481-1f3fc-200d-2642-fe0f.png","sheet_x":23,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F481-1F3FD-200D-2642-FE0F","non_qualified":"1F481-1F3FD-200D-2642","image":"1f481-1f3fd-200d-2642-fe0f.png","sheet_x":23,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F481-1F3FE-200D-2642-FE0F","non_qualified":"1F481-1F3FE-200D-2642","image":"1f481-1f3fe-200d-2642-fe0f.png","sheet_x":23,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F481-1F3FF-200D-2642-FE0F","non_qualified":"1F481-1F3FF-200D-2642","image":"1f481-1f3ff-200d-2642-fe0f.png","sheet_x":23,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Tipping Hand","b":"1F481-200D-2642-FE0F","c":"1F481-200D-2642","k":[23,7]},"flag-sk":{"a":"Slovakia Flag","b":"1F1F8-1F1F0","k":[4,30]},"flag-sl":{"a":"Sierra Leone Flag","b":"1F1F8-1F1F1","k":[4,31]},"woman-tipping-hand":{"skin_variations":{"1F3FB":{"unified":"1F481-1F3FB-200D-2640-FE0F","non_qualified":"1F481-1F3FB-200D-2640","image":"1f481-1f3fb-200d-2640-fe0f.png","sheet_x":23,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F481-1F3FC-200D-2640-FE0F","non_qualified":"1F481-1F3FC-200D-2640","image":"1f481-1f3fc-200d-2640-fe0f.png","sheet_x":23,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F481-1F3FD-200D-2640-FE0F","non_qualified":"1F481-1F3FD-200D-2640","image":"1f481-1f3fd-200d-2640-fe0f.png","sheet_x":23,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F481-1F3FE-200D-2640-FE0F","non_qualified":"1F481-1F3FE-200D-2640","image":"1f481-1f3fe-200d-2640-fe0f.png","sheet_x":23,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F481-1F3FF-200D-2640-FE0F","non_qualified":"1F481-1F3FF-200D-2640","image":"1f481-1f3ff-200d-2640-fe0f.png","sheet_x":23,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F481","a":"Woman Tipping Hand","b":"1F481-200D-2640-FE0F","c":"1F481-200D-2640","k":[23,1]},"flag-sm":{"a":"San Marino Flag","b":"1F1F8-1F1F2","k":[4,32]},"raising_hand":{"skin_variations":{"1F3FB":{"unified":"1F64B-1F3FB","non_qualified":null,"image":"1f64b-1f3fb.png","sheet_x":33,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F64B-1F3FC","non_qualified":null,"image":"1f64b-1f3fc.png","sheet_x":33,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F64B-1F3FD","non_qualified":null,"image":"1f64b-1f3fd.png","sheet_x":33,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F64B-1F3FE","non_qualified":null,"image":"1f64b-1f3fe.png","sheet_x":33,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F64B-1F3FF","non_qualified":null,"image":"1f64b-1f3ff.png","sheet_x":33,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F64B-200D-2640-FE0F","a":"Happy Person Raising One Hand","b":"1F64B","k":[33,6]},"flag-sn":{"a":"Senegal Flag","b":"1F1F8-1F1F3","k":[4,33]},"man-raising-hand":{"skin_variations":{"1F3FB":{"unified":"1F64B-1F3FB-200D-2642-FE0F","non_qualified":"1F64B-1F3FB-200D-2642","image":"1f64b-1f3fb-200d-2642-fe0f.png","sheet_x":33,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F64B-1F3FC-200D-2642-FE0F","non_qualified":"1F64B-1F3FC-200D-2642","image":"1f64b-1f3fc-200d-2642-fe0f.png","sheet_x":33,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F64B-1F3FD-200D-2642-FE0F","non_qualified":"1F64B-1F3FD-200D-2642","image":"1f64b-1f3fd-200d-2642-fe0f.png","sheet_x":33,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F64B-1F3FE-200D-2642-FE0F","non_qualified":"1F64B-1F3FE-200D-2642","image":"1f64b-1f3fe-200d-2642-fe0f.png","sheet_x":33,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F64B-1F3FF-200D-2642-FE0F","non_qualified":"1F64B-1F3FF-200D-2642","image":"1f64b-1f3ff-200d-2642-fe0f.png","sheet_x":33,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Raising Hand","b":"1F64B-200D-2642-FE0F","c":"1F64B-200D-2642","k":[33,0]},"flag-so":{"a":"Somalia Flag","b":"1F1F8-1F1F4","k":[4,34]},"woman-raising-hand":{"skin_variations":{"1F3FB":{"unified":"1F64B-1F3FB-200D-2640-FE0F","non_qualified":"1F64B-1F3FB-200D-2640","image":"1f64b-1f3fb-200d-2640-fe0f.png","sheet_x":32,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F64B-1F3FC-200D-2640-FE0F","non_qualified":"1F64B-1F3FC-200D-2640","image":"1f64b-1f3fc-200d-2640-fe0f.png","sheet_x":32,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F64B-1F3FD-200D-2640-FE0F","non_qualified":"1F64B-1F3FD-200D-2640","image":"1f64b-1f3fd-200d-2640-fe0f.png","sheet_x":32,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F64B-1F3FE-200D-2640-FE0F","non_qualified":"1F64B-1F3FE-200D-2640","image":"1f64b-1f3fe-200d-2640-fe0f.png","sheet_x":32,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F64B-1F3FF-200D-2640-FE0F","non_qualified":"1F64B-1F3FF-200D-2640","image":"1f64b-1f3ff-200d-2640-fe0f.png","sheet_x":32,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F64B","a":"Woman Raising Hand","b":"1F64B-200D-2640-FE0F","c":"1F64B-200D-2640","k":[32,46]},"flag-sr":{"a":"Suriname Flag","b":"1F1F8-1F1F7","k":[4,35]},"bow":{"skin_variations":{"1F3FB":{"unified":"1F647-1F3FB","non_qualified":null,"image":"1f647-1f3fb.png","sheet_x":32,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F647-1F3FC","non_qualified":null,"image":"1f647-1f3fc.png","sheet_x":32,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F647-1F3FD","non_qualified":null,"image":"1f647-1f3fd.png","sheet_x":32,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F647-1F3FE","non_qualified":null,"image":"1f647-1f3fe.png","sheet_x":32,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F647-1F3FF","non_qualified":null,"image":"1f647-1f3ff.png","sheet_x":32,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F647-200D-2642-FE0F","a":"Person Bowing Deeply","b":"1F647","k":[32,37]},"man-bowing":{"skin_variations":{"1F3FB":{"unified":"1F647-1F3FB-200D-2642-FE0F","non_qualified":"1F647-1F3FB-200D-2642","image":"1f647-1f3fb-200d-2642-fe0f.png","sheet_x":32,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F647-1F3FC-200D-2642-FE0F","non_qualified":"1F647-1F3FC-200D-2642","image":"1f647-1f3fc-200d-2642-fe0f.png","sheet_x":32,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F647-1F3FD-200D-2642-FE0F","non_qualified":"1F647-1F3FD-200D-2642","image":"1f647-1f3fd-200d-2642-fe0f.png","sheet_x":32,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F647-1F3FE-200D-2642-FE0F","non_qualified":"1F647-1F3FE-200D-2642","image":"1f647-1f3fe-200d-2642-fe0f.png","sheet_x":32,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F647-1F3FF-200D-2642-FE0F","non_qualified":"1F647-1F3FF-200D-2642","image":"1f647-1f3ff-200d-2642-fe0f.png","sheet_x":32,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F647","a":"Man Bowing","b":"1F647-200D-2642-FE0F","c":"1F647-200D-2642","k":[32,31]},"flag-ss":{"a":"South Sudan Flag","b":"1F1F8-1F1F8","k":[4,36]},"woman-bowing":{"skin_variations":{"1F3FB":{"unified":"1F647-1F3FB-200D-2640-FE0F","non_qualified":"1F647-1F3FB-200D-2640","image":"1f647-1f3fb-200d-2640-fe0f.png","sheet_x":32,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F647-1F3FC-200D-2640-FE0F","non_qualified":"1F647-1F3FC-200D-2640","image":"1f647-1f3fc-200d-2640-fe0f.png","sheet_x":32,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F647-1F3FD-200D-2640-FE0F","non_qualified":"1F647-1F3FD-200D-2640","image":"1f647-1f3fd-200d-2640-fe0f.png","sheet_x":32,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F647-1F3FE-200D-2640-FE0F","non_qualified":"1F647-1F3FE-200D-2640","image":"1f647-1f3fe-200d-2640-fe0f.png","sheet_x":32,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F647-1F3FF-200D-2640-FE0F","non_qualified":"1F647-1F3FF-200D-2640","image":"1f647-1f3ff-200d-2640-fe0f.png","sheet_x":32,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Bowing","b":"1F647-200D-2640-FE0F","c":"1F647-200D-2640","k":[32,25]},"flag-st":{"a":"São Tomé & Príncipe Flag","b":"1F1F8-1F1F9","k":[4,37]},"face_palm":{"skin_variations":{"1F3FB":{"unified":"1F926-1F3FB","non_qualified":null,"image":"1f926-1f3fb.png","sheet_x":38,"sheet_y":42,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F926-1F3FC","non_qualified":null,"image":"1f926-1f3fc.png","sheet_x":38,"sheet_y":43,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F926-1F3FD","non_qualified":null,"image":"1f926-1f3fd.png","sheet_x":38,"sheet_y":44,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F926-1F3FE","non_qualified":null,"image":"1f926-1f3fe.png","sheet_x":38,"sheet_y":45,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F926-1F3FF","non_qualified":null,"image":"1f926-1f3ff.png","sheet_x":38,"sheet_y":46,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Face Palm","b":"1F926","k":[38,41],"o":9},"flag-sv":{"a":"El Salvador Flag","b":"1F1F8-1F1FB","k":[4,38]},"man-facepalming":{"skin_variations":{"1F3FB":{"unified":"1F926-1F3FB-200D-2642-FE0F","non_qualified":"1F926-1F3FB-200D-2642","image":"1f926-1f3fb-200d-2642-fe0f.png","sheet_x":38,"sheet_y":36,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F926-1F3FC-200D-2642-FE0F","non_qualified":"1F926-1F3FC-200D-2642","image":"1f926-1f3fc-200d-2642-fe0f.png","sheet_x":38,"sheet_y":37,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F926-1F3FD-200D-2642-FE0F","non_qualified":"1F926-1F3FD-200D-2642","image":"1f926-1f3fd-200d-2642-fe0f.png","sheet_x":38,"sheet_y":38,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F926-1F3FE-200D-2642-FE0F","non_qualified":"1F926-1F3FE-200D-2642","image":"1f926-1f3fe-200d-2642-fe0f.png","sheet_x":38,"sheet_y":39,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F926-1F3FF-200D-2642-FE0F","non_qualified":"1F926-1F3FF-200D-2642","image":"1f926-1f3ff-200d-2642-fe0f.png","sheet_x":38,"sheet_y":40,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Facepalming","b":"1F926-200D-2642-FE0F","c":"1F926-200D-2642","k":[38,35],"o":9},"flag-sx":{"a":"Sint Maarten Flag","b":"1F1F8-1F1FD","k":[4,39]},"flag-sy":{"a":"Syria Flag","b":"1F1F8-1F1FE","k":[4,40]},"woman-facepalming":{"skin_variations":{"1F3FB":{"unified":"1F926-1F3FB-200D-2640-FE0F","non_qualified":"1F926-1F3FB-200D-2640","image":"1f926-1f3fb-200d-2640-fe0f.png","sheet_x":38,"sheet_y":30,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F926-1F3FC-200D-2640-FE0F","non_qualified":"1F926-1F3FC-200D-2640","image":"1f926-1f3fc-200d-2640-fe0f.png","sheet_x":38,"sheet_y":31,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F926-1F3FD-200D-2640-FE0F","non_qualified":"1F926-1F3FD-200D-2640","image":"1f926-1f3fd-200d-2640-fe0f.png","sheet_x":38,"sheet_y":32,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F926-1F3FE-200D-2640-FE0F","non_qualified":"1F926-1F3FE-200D-2640","image":"1f926-1f3fe-200d-2640-fe0f.png","sheet_x":38,"sheet_y":33,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F926-1F3FF-200D-2640-FE0F","non_qualified":"1F926-1F3FF-200D-2640","image":"1f926-1f3ff-200d-2640-fe0f.png","sheet_x":38,"sheet_y":34,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Facepalming","b":"1F926-200D-2640-FE0F","c":"1F926-200D-2640","k":[38,29],"o":9},"shrug":{"skin_variations":{"1F3FB":{"unified":"1F937-1F3FB","non_qualified":null,"image":"1f937-1f3fb.png","sheet_x":40,"sheet_y":7,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F937-1F3FC","non_qualified":null,"image":"1f937-1f3fc.png","sheet_x":40,"sheet_y":8,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F937-1F3FD","non_qualified":null,"image":"1f937-1f3fd.png","sheet_x":40,"sheet_y":9,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F937-1F3FE","non_qualified":null,"image":"1f937-1f3fe.png","sheet_x":40,"sheet_y":10,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F937-1F3FF","non_qualified":null,"image":"1f937-1f3ff.png","sheet_x":40,"sheet_y":11,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Shrug","b":"1F937","k":[40,6],"o":9},"flag-sz":{"a":"Swaziland Flag","b":"1F1F8-1F1FF","k":[4,41]},"flag-ta":{"a":"Tristan Da Cunha Flag","b":"1F1F9-1F1E6","k":[4,42]},"man-shrugging":{"skin_variations":{"1F3FB":{"unified":"1F937-1F3FB-200D-2642-FE0F","non_qualified":"1F937-1F3FB-200D-2642","image":"1f937-1f3fb-200d-2642-fe0f.png","sheet_x":40,"sheet_y":1,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F937-1F3FC-200D-2642-FE0F","non_qualified":"1F937-1F3FC-200D-2642","image":"1f937-1f3fc-200d-2642-fe0f.png","sheet_x":40,"sheet_y":2,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F937-1F3FD-200D-2642-FE0F","non_qualified":"1F937-1F3FD-200D-2642","image":"1f937-1f3fd-200d-2642-fe0f.png","sheet_x":40,"sheet_y":3,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F937-1F3FE-200D-2642-FE0F","non_qualified":"1F937-1F3FE-200D-2642","image":"1f937-1f3fe-200d-2642-fe0f.png","sheet_x":40,"sheet_y":4,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F937-1F3FF-200D-2642-FE0F","non_qualified":"1F937-1F3FF-200D-2642","image":"1f937-1f3ff-200d-2642-fe0f.png","sheet_x":40,"sheet_y":5,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Shrugging","b":"1F937-200D-2642-FE0F","c":"1F937-200D-2642","k":[40,0],"o":9},"woman-shrugging":{"skin_variations":{"1F3FB":{"unified":"1F937-1F3FB-200D-2640-FE0F","non_qualified":"1F937-1F3FB-200D-2640","image":"1f937-1f3fb-200d-2640-fe0f.png","sheet_x":39,"sheet_y":47,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F937-1F3FC-200D-2640-FE0F","non_qualified":"1F937-1F3FC-200D-2640","image":"1f937-1f3fc-200d-2640-fe0f.png","sheet_x":39,"sheet_y":48,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F937-1F3FD-200D-2640-FE0F","non_qualified":"1F937-1F3FD-200D-2640","image":"1f937-1f3fd-200d-2640-fe0f.png","sheet_x":39,"sheet_y":49,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F937-1F3FE-200D-2640-FE0F","non_qualified":"1F937-1F3FE-200D-2640","image":"1f937-1f3fe-200d-2640-fe0f.png","sheet_x":39,"sheet_y":50,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F937-1F3FF-200D-2640-FE0F","non_qualified":"1F937-1F3FF-200D-2640","image":"1f937-1f3ff-200d-2640-fe0f.png","sheet_x":39,"sheet_y":51,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Shrugging","b":"1F937-200D-2640-FE0F","c":"1F937-200D-2640","k":[39,46],"o":9},"flag-tc":{"a":"Turks & Caicos Islands Flag","b":"1F1F9-1F1E8","k":[4,43]},"massage":{"skin_variations":{"1F3FB":{"unified":"1F486-1F3FB","non_qualified":null,"image":"1f486-1f3fb.png","sheet_x":24,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F486-1F3FC","non_qualified":null,"image":"1f486-1f3fc.png","sheet_x":24,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F486-1F3FD","non_qualified":null,"image":"1f486-1f3fd.png","sheet_x":24,"sheet_y":13,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F486-1F3FE","non_qualified":null,"image":"1f486-1f3fe.png","sheet_x":24,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F486-1F3FF","non_qualified":null,"image":"1f486-1f3ff.png","sheet_x":24,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F486-200D-2640-FE0F","a":"Face Massage","b":"1F486","k":[24,10]},"flag-td":{"a":"Chad Flag","b":"1F1F9-1F1E9","k":[4,44]},"man-getting-massage":{"skin_variations":{"1F3FB":{"unified":"1F486-1F3FB-200D-2642-FE0F","non_qualified":"1F486-1F3FB-200D-2642","image":"1f486-1f3fb-200d-2642-fe0f.png","sheet_x":24,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F486-1F3FC-200D-2642-FE0F","non_qualified":"1F486-1F3FC-200D-2642","image":"1f486-1f3fc-200d-2642-fe0f.png","sheet_x":24,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F486-1F3FD-200D-2642-FE0F","non_qualified":"1F486-1F3FD-200D-2642","image":"1f486-1f3fd-200d-2642-fe0f.png","sheet_x":24,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F486-1F3FE-200D-2642-FE0F","non_qualified":"1F486-1F3FE-200D-2642","image":"1f486-1f3fe-200d-2642-fe0f.png","sheet_x":24,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F486-1F3FF-200D-2642-FE0F","non_qualified":"1F486-1F3FF-200D-2642","image":"1f486-1f3ff-200d-2642-fe0f.png","sheet_x":24,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Getting Massage","b":"1F486-200D-2642-FE0F","c":"1F486-200D-2642","k":[24,4]},"flag-tf":{"a":"French Southern Territories Flag","b":"1F1F9-1F1EB","k":[4,45]},"woman-getting-massage":{"skin_variations":{"1F3FB":{"unified":"1F486-1F3FB-200D-2640-FE0F","non_qualified":"1F486-1F3FB-200D-2640","image":"1f486-1f3fb-200d-2640-fe0f.png","sheet_x":23,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F486-1F3FC-200D-2640-FE0F","non_qualified":"1F486-1F3FC-200D-2640","image":"1f486-1f3fc-200d-2640-fe0f.png","sheet_x":24,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F486-1F3FD-200D-2640-FE0F","non_qualified":"1F486-1F3FD-200D-2640","image":"1f486-1f3fd-200d-2640-fe0f.png","sheet_x":24,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F486-1F3FE-200D-2640-FE0F","non_qualified":"1F486-1F3FE-200D-2640","image":"1f486-1f3fe-200d-2640-fe0f.png","sheet_x":24,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F486-1F3FF-200D-2640-FE0F","non_qualified":"1F486-1F3FF-200D-2640","image":"1f486-1f3ff-200d-2640-fe0f.png","sheet_x":24,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F486","a":"Woman Getting Massage","b":"1F486-200D-2640-FE0F","c":"1F486-200D-2640","k":[23,50]},"flag-tg":{"a":"Togo Flag","b":"1F1F9-1F1EC","k":[4,46]},"haircut":{"skin_variations":{"1F3FB":{"unified":"1F487-1F3FB","non_qualified":null,"image":"1f487-1f3fb.png","sheet_x":24,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F487-1F3FC","non_qualified":null,"image":"1f487-1f3fc.png","sheet_x":24,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F487-1F3FD","non_qualified":null,"image":"1f487-1f3fd.png","sheet_x":24,"sheet_y":31,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F487-1F3FE","non_qualified":null,"image":"1f487-1f3fe.png","sheet_x":24,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F487-1F3FF","non_qualified":null,"image":"1f487-1f3ff.png","sheet_x":24,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F487-200D-2640-FE0F","a":"Haircut","b":"1F487","k":[24,28]},"flag-th":{"a":"Thailand Flag","b":"1F1F9-1F1ED","k":[4,47]},"man-getting-haircut":{"skin_variations":{"1F3FB":{"unified":"1F487-1F3FB-200D-2642-FE0F","non_qualified":"1F487-1F3FB-200D-2642","image":"1f487-1f3fb-200d-2642-fe0f.png","sheet_x":24,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F487-1F3FC-200D-2642-FE0F","non_qualified":"1F487-1F3FC-200D-2642","image":"1f487-1f3fc-200d-2642-fe0f.png","sheet_x":24,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F487-1F3FD-200D-2642-FE0F","non_qualified":"1F487-1F3FD-200D-2642","image":"1f487-1f3fd-200d-2642-fe0f.png","sheet_x":24,"sheet_y":25,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F487-1F3FE-200D-2642-FE0F","non_qualified":"1F487-1F3FE-200D-2642","image":"1f487-1f3fe-200d-2642-fe0f.png","sheet_x":24,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F487-1F3FF-200D-2642-FE0F","non_qualified":"1F487-1F3FF-200D-2642","image":"1f487-1f3ff-200d-2642-fe0f.png","sheet_x":24,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Getting Haircut","b":"1F487-200D-2642-FE0F","c":"1F487-200D-2642","k":[24,22]},"flag-tj":{"a":"Tajikistan Flag","b":"1F1F9-1F1EF","k":[4,48]},"flag-tk":{"a":"Tokelau Flag","b":"1F1F9-1F1F0","k":[4,49]},"woman-getting-haircut":{"skin_variations":{"1F3FB":{"unified":"1F487-1F3FB-200D-2640-FE0F","non_qualified":"1F487-1F3FB-200D-2640","image":"1f487-1f3fb-200d-2640-fe0f.png","sheet_x":24,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F487-1F3FC-200D-2640-FE0F","non_qualified":"1F487-1F3FC-200D-2640","image":"1f487-1f3fc-200d-2640-fe0f.png","sheet_x":24,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F487-1F3FD-200D-2640-FE0F","non_qualified":"1F487-1F3FD-200D-2640","image":"1f487-1f3fd-200d-2640-fe0f.png","sheet_x":24,"sheet_y":19,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F487-1F3FE-200D-2640-FE0F","non_qualified":"1F487-1F3FE-200D-2640","image":"1f487-1f3fe-200d-2640-fe0f.png","sheet_x":24,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F487-1F3FF-200D-2640-FE0F","non_qualified":"1F487-1F3FF-200D-2640","image":"1f487-1f3ff-200d-2640-fe0f.png","sheet_x":24,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F487","a":"Woman Getting Haircut","b":"1F487-200D-2640-FE0F","c":"1F487-200D-2640","k":[24,16]},"walking":{"skin_variations":{"1F3FB":{"unified":"1F6B6-1F3FB","non_qualified":null,"image":"1f6b6-1f3fb.png","sheet_x":36,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F6B6-1F3FC","non_qualified":null,"image":"1f6b6-1f3fc.png","sheet_x":36,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F6B6-1F3FD","non_qualified":null,"image":"1f6b6-1f3fd.png","sheet_x":36,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F6B6-1F3FE","non_qualified":null,"image":"1f6b6-1f3fe.png","sheet_x":36,"sheet_y":25,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F6B6-1F3FF","non_qualified":null,"image":"1f6b6-1f3ff.png","sheet_x":36,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F6B6-200D-2642-FE0F","a":"Pedestrian","b":"1F6B6","k":[36,21]},"flag-tl":{"a":"Timor-Leste Flag","b":"1F1F9-1F1F1","k":[4,50]},"man-walking":{"skin_variations":{"1F3FB":{"unified":"1F6B6-1F3FB-200D-2642-FE0F","non_qualified":"1F6B6-1F3FB-200D-2642","image":"1f6b6-1f3fb-200d-2642-fe0f.png","sheet_x":36,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F6B6-1F3FC-200D-2642-FE0F","non_qualified":"1F6B6-1F3FC-200D-2642","image":"1f6b6-1f3fc-200d-2642-fe0f.png","sheet_x":36,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F6B6-1F3FD-200D-2642-FE0F","non_qualified":"1F6B6-1F3FD-200D-2642","image":"1f6b6-1f3fd-200d-2642-fe0f.png","sheet_x":36,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F6B6-1F3FE-200D-2642-FE0F","non_qualified":"1F6B6-1F3FE-200D-2642","image":"1f6b6-1f3fe-200d-2642-fe0f.png","sheet_x":36,"sheet_y":19,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F6B6-1F3FF-200D-2642-FE0F","non_qualified":"1F6B6-1F3FF-200D-2642","image":"1f6b6-1f3ff-200d-2642-fe0f.png","sheet_x":36,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F6B6","a":"Man Walking","b":"1F6B6-200D-2642-FE0F","c":"1F6B6-200D-2642","k":[36,15]},"flag-tm":{"a":"Turkmenistan Flag","b":"1F1F9-1F1F2","k":[4,51]},"woman-walking":{"skin_variations":{"1F3FB":{"unified":"1F6B6-1F3FB-200D-2640-FE0F","non_qualified":"1F6B6-1F3FB-200D-2640","image":"1f6b6-1f3fb-200d-2640-fe0f.png","sheet_x":36,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F6B6-1F3FC-200D-2640-FE0F","non_qualified":"1F6B6-1F3FC-200D-2640","image":"1f6b6-1f3fc-200d-2640-fe0f.png","sheet_x":36,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F6B6-1F3FD-200D-2640-FE0F","non_qualified":"1F6B6-1F3FD-200D-2640","image":"1f6b6-1f3fd-200d-2640-fe0f.png","sheet_x":36,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F6B6-1F3FE-200D-2640-FE0F","non_qualified":"1F6B6-1F3FE-200D-2640","image":"1f6b6-1f3fe-200d-2640-fe0f.png","sheet_x":36,"sheet_y":13,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F6B6-1F3FF-200D-2640-FE0F","non_qualified":"1F6B6-1F3FF-200D-2640","image":"1f6b6-1f3ff-200d-2640-fe0f.png","sheet_x":36,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Walking","b":"1F6B6-200D-2640-FE0F","c":"1F6B6-200D-2640","k":[36,9]},"flag-tn":{"a":"Tunisia Flag","b":"1F1F9-1F1F3","k":[5,0]},"runner":{"skin_variations":{"1F3FB":{"unified":"1F3C3-1F3FB","non_qualified":null,"image":"1f3c3-1f3fb.png","sheet_x":9,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F3C3-1F3FC","non_qualified":null,"image":"1f3c3-1f3fc.png","sheet_x":9,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F3C3-1F3FD","non_qualified":null,"image":"1f3c3-1f3fd.png","sheet_x":9,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F3C3-1F3FE","non_qualified":null,"image":"1f3c3-1f3fe.png","sheet_x":9,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F3C3-1F3FF","non_qualified":null,"image":"1f3c3-1f3ff.png","sheet_x":9,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F3C3-200D-2642-FE0F","a":"Runner","b":"1F3C3","k":[9,46],"n":["running"]},"flag-to":{"a":"Tonga Flag","b":"1F1F9-1F1F4","k":[5,1]},"man-running":{"skin_variations":{"1F3FB":{"unified":"1F3C3-1F3FB-200D-2642-FE0F","non_qualified":"1F3C3-1F3FB-200D-2642","image":"1f3c3-1f3fb-200d-2642-fe0f.png","sheet_x":9,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F3C3-1F3FC-200D-2642-FE0F","non_qualified":"1F3C3-1F3FC-200D-2642","image":"1f3c3-1f3fc-200d-2642-fe0f.png","sheet_x":9,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F3C3-1F3FD-200D-2642-FE0F","non_qualified":"1F3C3-1F3FD-200D-2642","image":"1f3c3-1f3fd-200d-2642-fe0f.png","sheet_x":9,"sheet_y":43,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F3C3-1F3FE-200D-2642-FE0F","non_qualified":"1F3C3-1F3FE-200D-2642","image":"1f3c3-1f3fe-200d-2642-fe0f.png","sheet_x":9,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F3C3-1F3FF-200D-2642-FE0F","non_qualified":"1F3C3-1F3FF-200D-2642","image":"1f3c3-1f3ff-200d-2642-fe0f.png","sheet_x":9,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F3C3","a":"Man Running","b":"1F3C3-200D-2642-FE0F","c":"1F3C3-200D-2642","k":[9,40]},"flag-tr":{"a":"Turkey Flag","b":"1F1F9-1F1F7","k":[5,2]},"flag-tt":{"a":"Trinidad & Tobago Flag","b":"1F1F9-1F1F9","k":[5,3]},"woman-running":{"skin_variations":{"1F3FB":{"unified":"1F3C3-1F3FB-200D-2640-FE0F","non_qualified":"1F3C3-1F3FB-200D-2640","image":"1f3c3-1f3fb-200d-2640-fe0f.png","sheet_x":9,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F3C3-1F3FC-200D-2640-FE0F","non_qualified":"1F3C3-1F3FC-200D-2640","image":"1f3c3-1f3fc-200d-2640-fe0f.png","sheet_x":9,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F3C3-1F3FD-200D-2640-FE0F","non_qualified":"1F3C3-1F3FD-200D-2640","image":"1f3c3-1f3fd-200d-2640-fe0f.png","sheet_x":9,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F3C3-1F3FE-200D-2640-FE0F","non_qualified":"1F3C3-1F3FE-200D-2640","image":"1f3c3-1f3fe-200d-2640-fe0f.png","sheet_x":9,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F3C3-1F3FF-200D-2640-FE0F","non_qualified":"1F3C3-1F3FF-200D-2640","image":"1f3c3-1f3ff-200d-2640-fe0f.png","sheet_x":9,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Running","b":"1F3C3-200D-2640-FE0F","c":"1F3C3-200D-2640","k":[9,34]},"flag-tv":{"a":"Tuvalu Flag","b":"1F1F9-1F1FB","k":[5,4]},"dancer":{"skin_variations":{"1F3FB":{"unified":"1F483-1F3FB","non_qualified":null,"image":"1f483-1f3fb.png","sheet_x":23,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F483-1F3FC","non_qualified":null,"image":"1f483-1f3fc.png","sheet_x":23,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F483-1F3FD","non_qualified":null,"image":"1f483-1f3fd.png","sheet_x":23,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F483-1F3FE","non_qualified":null,"image":"1f483-1f3fe.png","sheet_x":23,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F483-1F3FF","non_qualified":null,"image":"1f483-1f3ff.png","sheet_x":23,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Dancer","b":"1F483","j":["female","girl","woman","fun"],"k":[23,37]},"flag-tw":{"a":"Taiwan Flag","b":"1F1F9-1F1FC","k":[5,5]},"man_dancing":{"skin_variations":{"1F3FB":{"unified":"1F57A-1F3FB","non_qualified":null,"image":"1f57a-1f3fb.png","sheet_x":29,"sheet_y":22,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F57A-1F3FC","non_qualified":null,"image":"1f57a-1f3fc.png","sheet_x":29,"sheet_y":23,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F57A-1F3FD","non_qualified":null,"image":"1f57a-1f3fd.png","sheet_x":29,"sheet_y":24,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F57A-1F3FE","non_qualified":null,"image":"1f57a-1f3fe.png","sheet_x":29,"sheet_y":25,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F57A-1F3FF","non_qualified":null,"image":"1f57a-1f3ff.png","sheet_x":29,"sheet_y":26,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Man Dancing","b":"1F57A","j":["male","boy","fun","dancer"],"k":[29,21],"o":9},"dancers":{"obsoleted_by":"1F46F-200D-2640-FE0F","a":"Woman with Bunny Ears","b":"1F46F","k":[21,1]},"flag-tz":{"a":"Tanzania Flag","b":"1F1F9-1F1FF","k":[5,6]},"flag-ua":{"a":"Ukraine Flag","b":"1F1FA-1F1E6","k":[5,7]},"man-with-bunny-ears-partying":{"a":"Man with Bunny Ears Partying","b":"1F46F-200D-2642-FE0F","c":"1F46F-200D-2642","k":[21,0]},"woman-with-bunny-ears-partying":{"obsoletes":"1F46F","a":"Woman with Bunny Ears Partying","b":"1F46F-200D-2640-FE0F","c":"1F46F-200D-2640","k":[20,51]},"flag-ug":{"a":"Uganda Flag","b":"1F1FA-1F1EC","k":[5,8]},"flag-um":{"a":"U.s. Outlying Islands Flag","b":"1F1FA-1F1F2","k":[5,9]},"person_in_steamy_room":{"skin_variations":{"1F3FB":{"unified":"1F9D6-1F3FB","non_qualified":null,"image":"1f9d6-1f3fb.png","sheet_x":43,"sheet_y":41,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D6-1F3FB-200D-2642-FE0F"},"1F3FC":{"unified":"1F9D6-1F3FC","non_qualified":null,"image":"1f9d6-1f3fc.png","sheet_x":43,"sheet_y":42,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D6-1F3FC-200D-2642-FE0F"},"1F3FD":{"unified":"1F9D6-1F3FD","non_qualified":null,"image":"1f9d6-1f3fd.png","sheet_x":43,"sheet_y":43,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D6-1F3FD-200D-2642-FE0F"},"1F3FE":{"unified":"1F9D6-1F3FE","non_qualified":null,"image":"1f9d6-1f3fe.png","sheet_x":43,"sheet_y":44,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D6-1F3FE-200D-2642-FE0F"},"1F3FF":{"unified":"1F9D6-1F3FF","non_qualified":null,"image":"1f9d6-1f3ff.png","sheet_x":43,"sheet_y":45,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D6-1F3FF-200D-2642-FE0F"}},"obsoleted_by":"1F9D6-200D-2642-FE0F","a":"Person in Steamy Room","b":"1F9D6","k":[43,40],"o":10},"woman_in_steamy_room":{"skin_variations":{"1F3FB":{"unified":"1F9D6-1F3FB-200D-2640-FE0F","non_qualified":"1F9D6-1F3FB-200D-2640","image":"1f9d6-1f3fb-200d-2640-fe0f.png","sheet_x":43,"sheet_y":29,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F9D6-1F3FC-200D-2640-FE0F","non_qualified":"1F9D6-1F3FC-200D-2640","image":"1f9d6-1f3fc-200d-2640-fe0f.png","sheet_x":43,"sheet_y":30,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F9D6-1F3FD-200D-2640-FE0F","non_qualified":"1F9D6-1F3FD-200D-2640","image":"1f9d6-1f3fd-200d-2640-fe0f.png","sheet_x":43,"sheet_y":31,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F9D6-1F3FE-200D-2640-FE0F","non_qualified":"1F9D6-1F3FE-200D-2640","image":"1f9d6-1f3fe-200d-2640-fe0f.png","sheet_x":43,"sheet_y":32,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F9D6-1F3FF-200D-2640-FE0F","non_qualified":"1F9D6-1F3FF-200D-2640","image":"1f9d6-1f3ff-200d-2640-fe0f.png","sheet_x":43,"sheet_y":33,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman in Steamy Room","b":"1F9D6-200D-2640-FE0F","c":"1F9D6-200D-2640","k":[43,28],"o":10},"us":{"a":"United States Flag","b":"1F1FA-1F1F8","j":["united","states","america","flag","nation","country","banner"],"k":[5,11],"n":["flag-us"]},"man_in_steamy_room":{"skin_variations":{"1F3FB":{"unified":"1F9D6-1F3FB-200D-2642-FE0F","non_qualified":"1F9D6-1F3FB-200D-2642","image":"1f9d6-1f3fb-200d-2642-fe0f.png","sheet_x":43,"sheet_y":35,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D6-1F3FB"},"1F3FC":{"unified":"1F9D6-1F3FC-200D-2642-FE0F","non_qualified":"1F9D6-1F3FC-200D-2642","image":"1f9d6-1f3fc-200d-2642-fe0f.png","sheet_x":43,"sheet_y":36,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D6-1F3FC"},"1F3FD":{"unified":"1F9D6-1F3FD-200D-2642-FE0F","non_qualified":"1F9D6-1F3FD-200D-2642","image":"1f9d6-1f3fd-200d-2642-fe0f.png","sheet_x":43,"sheet_y":37,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D6-1F3FD"},"1F3FE":{"unified":"1F9D6-1F3FE-200D-2642-FE0F","non_qualified":"1F9D6-1F3FE-200D-2642","image":"1f9d6-1f3fe-200d-2642-fe0f.png","sheet_x":43,"sheet_y":38,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D6-1F3FE"},"1F3FF":{"unified":"1F9D6-1F3FF-200D-2642-FE0F","non_qualified":"1F9D6-1F3FF-200D-2642","image":"1f9d6-1f3ff-200d-2642-fe0f.png","sheet_x":43,"sheet_y":39,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D6-1F3FF"}},"obsoletes":"1F9D6","a":"Man in Steamy Room","b":"1F9D6-200D-2642-FE0F","c":"1F9D6-200D-2642","k":[43,34],"o":10},"person_climbing":{"skin_variations":{"1F3FB":{"unified":"1F9D7-1F3FB","non_qualified":null,"image":"1f9d7-1f3fb.png","sheet_x":44,"sheet_y":7,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D7-1F3FB-200D-2640-FE0F"},"1F3FC":{"unified":"1F9D7-1F3FC","non_qualified":null,"image":"1f9d7-1f3fc.png","sheet_x":44,"sheet_y":8,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D7-1F3FC-200D-2640-FE0F"},"1F3FD":{"unified":"1F9D7-1F3FD","non_qualified":null,"image":"1f9d7-1f3fd.png","sheet_x":44,"sheet_y":9,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D7-1F3FD-200D-2640-FE0F"},"1F3FE":{"unified":"1F9D7-1F3FE","non_qualified":null,"image":"1f9d7-1f3fe.png","sheet_x":44,"sheet_y":10,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D7-1F3FE-200D-2640-FE0F"},"1F3FF":{"unified":"1F9D7-1F3FF","non_qualified":null,"image":"1f9d7-1f3ff.png","sheet_x":44,"sheet_y":11,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D7-1F3FF-200D-2640-FE0F"}},"obsoleted_by":"1F9D7-200D-2640-FE0F","a":"Person Climbing","b":"1F9D7","k":[44,6],"o":10},"flag-uy":{"a":"Uruguay Flag","b":"1F1FA-1F1FE","k":[5,12]},"woman_climbing":{"skin_variations":{"1F3FB":{"unified":"1F9D7-1F3FB-200D-2640-FE0F","non_qualified":"1F9D7-1F3FB-200D-2640","image":"1f9d7-1f3fb-200d-2640-fe0f.png","sheet_x":43,"sheet_y":47,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D7-1F3FB"},"1F3FC":{"unified":"1F9D7-1F3FC-200D-2640-FE0F","non_qualified":"1F9D7-1F3FC-200D-2640","image":"1f9d7-1f3fc-200d-2640-fe0f.png","sheet_x":43,"sheet_y":48,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D7-1F3FC"},"1F3FD":{"unified":"1F9D7-1F3FD-200D-2640-FE0F","non_qualified":"1F9D7-1F3FD-200D-2640","image":"1f9d7-1f3fd-200d-2640-fe0f.png","sheet_x":43,"sheet_y":49,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D7-1F3FD"},"1F3FE":{"unified":"1F9D7-1F3FE-200D-2640-FE0F","non_qualified":"1F9D7-1F3FE-200D-2640","image":"1f9d7-1f3fe-200d-2640-fe0f.png","sheet_x":43,"sheet_y":50,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D7-1F3FE"},"1F3FF":{"unified":"1F9D7-1F3FF-200D-2640-FE0F","non_qualified":"1F9D7-1F3FF-200D-2640","image":"1f9d7-1f3ff-200d-2640-fe0f.png","sheet_x":43,"sheet_y":51,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D7-1F3FF"}},"obsoletes":"1F9D7","a":"Woman Climbing","b":"1F9D7-200D-2640-FE0F","c":"1F9D7-200D-2640","k":[43,46],"o":10},"flag-uz":{"a":"Uzbekistan Flag","b":"1F1FA-1F1FF","k":[5,13]},"man_climbing":{"skin_variations":{"1F3FB":{"unified":"1F9D7-1F3FB-200D-2642-FE0F","non_qualified":"1F9D7-1F3FB-200D-2642","image":"1f9d7-1f3fb-200d-2642-fe0f.png","sheet_x":44,"sheet_y":1,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F9D7-1F3FC-200D-2642-FE0F","non_qualified":"1F9D7-1F3FC-200D-2642","image":"1f9d7-1f3fc-200d-2642-fe0f.png","sheet_x":44,"sheet_y":2,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F9D7-1F3FD-200D-2642-FE0F","non_qualified":"1F9D7-1F3FD-200D-2642","image":"1f9d7-1f3fd-200d-2642-fe0f.png","sheet_x":44,"sheet_y":3,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F9D7-1F3FE-200D-2642-FE0F","non_qualified":"1F9D7-1F3FE-200D-2642","image":"1f9d7-1f3fe-200d-2642-fe0f.png","sheet_x":44,"sheet_y":4,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F9D7-1F3FF-200D-2642-FE0F","non_qualified":"1F9D7-1F3FF-200D-2642","image":"1f9d7-1f3ff-200d-2642-fe0f.png","sheet_x":44,"sheet_y":5,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Climbing","b":"1F9D7-200D-2642-FE0F","c":"1F9D7-200D-2642","k":[44,0],"o":10},"flag-va":{"a":"Vatican City Flag","b":"1F1FB-1F1E6","k":[5,14]},"person_in_lotus_position":{"skin_variations":{"1F3FB":{"unified":"1F9D8-1F3FB","non_qualified":null,"image":"1f9d8-1f3fb.png","sheet_x":44,"sheet_y":25,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D8-1F3FB-200D-2640-FE0F"},"1F3FC":{"unified":"1F9D8-1F3FC","non_qualified":null,"image":"1f9d8-1f3fc.png","sheet_x":44,"sheet_y":26,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D8-1F3FC-200D-2640-FE0F"},"1F3FD":{"unified":"1F9D8-1F3FD","non_qualified":null,"image":"1f9d8-1f3fd.png","sheet_x":44,"sheet_y":27,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D8-1F3FD-200D-2640-FE0F"},"1F3FE":{"unified":"1F9D8-1F3FE","non_qualified":null,"image":"1f9d8-1f3fe.png","sheet_x":44,"sheet_y":28,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D8-1F3FE-200D-2640-FE0F"},"1F3FF":{"unified":"1F9D8-1F3FF","non_qualified":null,"image":"1f9d8-1f3ff.png","sheet_x":44,"sheet_y":29,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false,"obsoleted_by":"1F9D8-1F3FF-200D-2640-FE0F"}},"obsoleted_by":"1F9D8-200D-2640-FE0F","a":"Person in Lotus Position","b":"1F9D8","k":[44,24],"o":10},"flag-vc":{"a":"St. Vincent & Grenadines Flag","b":"1F1FB-1F1E8","k":[5,15]},"flag-ve":{"a":"Venezuela Flag","b":"1F1FB-1F1EA","k":[5,16]},"woman_in_lotus_position":{"skin_variations":{"1F3FB":{"unified":"1F9D8-1F3FB-200D-2640-FE0F","non_qualified":"1F9D8-1F3FB-200D-2640","image":"1f9d8-1f3fb-200d-2640-fe0f.png","sheet_x":44,"sheet_y":13,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D8-1F3FB"},"1F3FC":{"unified":"1F9D8-1F3FC-200D-2640-FE0F","non_qualified":"1F9D8-1F3FC-200D-2640","image":"1f9d8-1f3fc-200d-2640-fe0f.png","sheet_x":44,"sheet_y":14,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D8-1F3FC"},"1F3FD":{"unified":"1F9D8-1F3FD-200D-2640-FE0F","non_qualified":"1F9D8-1F3FD-200D-2640","image":"1f9d8-1f3fd-200d-2640-fe0f.png","sheet_x":44,"sheet_y":15,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D8-1F3FD"},"1F3FE":{"unified":"1F9D8-1F3FE-200D-2640-FE0F","non_qualified":"1F9D8-1F3FE-200D-2640","image":"1f9d8-1f3fe-200d-2640-fe0f.png","sheet_x":44,"sheet_y":16,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D8-1F3FE"},"1F3FF":{"unified":"1F9D8-1F3FF-200D-2640-FE0F","non_qualified":"1F9D8-1F3FF-200D-2640","image":"1f9d8-1f3ff-200d-2640-fe0f.png","sheet_x":44,"sheet_y":17,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false,"obsoletes":"1F9D8-1F3FF"}},"obsoletes":"1F9D8","a":"Woman in Lotus Position","b":"1F9D8-200D-2640-FE0F","c":"1F9D8-200D-2640","k":[44,12],"o":10},"man_in_lotus_position":{"skin_variations":{"1F3FB":{"unified":"1F9D8-1F3FB-200D-2642-FE0F","non_qualified":"1F9D8-1F3FB-200D-2642","image":"1f9d8-1f3fb-200d-2642-fe0f.png","sheet_x":44,"sheet_y":19,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F9D8-1F3FC-200D-2642-FE0F","non_qualified":"1F9D8-1F3FC-200D-2642","image":"1f9d8-1f3fc-200d-2642-fe0f.png","sheet_x":44,"sheet_y":20,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F9D8-1F3FD-200D-2642-FE0F","non_qualified":"1F9D8-1F3FD-200D-2642","image":"1f9d8-1f3fd-200d-2642-fe0f.png","sheet_x":44,"sheet_y":21,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F9D8-1F3FE-200D-2642-FE0F","non_qualified":"1F9D8-1F3FE-200D-2642","image":"1f9d8-1f3fe-200d-2642-fe0f.png","sheet_x":44,"sheet_y":22,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F9D8-1F3FF-200D-2642-FE0F","non_qualified":"1F9D8-1F3FF-200D-2642","image":"1f9d8-1f3ff-200d-2642-fe0f.png","sheet_x":44,"sheet_y":23,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man in Lotus Position","b":"1F9D8-200D-2642-FE0F","c":"1F9D8-200D-2642","k":[44,18],"o":10},"flag-vg":{"a":"British Virgin Islands Flag","b":"1F1FB-1F1EC","k":[5,17]},"flag-vi":{"a":"U.s. Virgin Islands Flag","b":"1F1FB-1F1EE","k":[5,18]},"bath":{"skin_variations":{"1F3FB":{"unified":"1F6C0-1F3FB","non_qualified":null,"image":"1f6c0-1f3fb.png","sheet_x":36,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F6C0-1F3FC","non_qualified":null,"image":"1f6c0-1f3fc.png","sheet_x":36,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F6C0-1F3FD","non_qualified":null,"image":"1f6c0-1f3fd.png","sheet_x":36,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F6C0-1F3FE","non_qualified":null,"image":"1f6c0-1f3fe.png","sheet_x":36,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F6C0-1F3FF","non_qualified":null,"image":"1f6c0-1f3ff.png","sheet_x":36,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Bath","b":"1F6C0","j":["clean","shower","bathroom"],"k":[36,36]},"sleeping_accommodation":{"skin_variations":{"1F3FB":{"unified":"1F6CC-1F3FB","non_qualified":null,"image":"1f6cc-1f3fb.png","sheet_x":36,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F6CC-1F3FC","non_qualified":null,"image":"1f6cc-1f3fc.png","sheet_x":36,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F6CC-1F3FD","non_qualified":null,"image":"1f6cc-1f3fd.png","sheet_x":36,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F6CC-1F3FE","non_qualified":null,"image":"1f6cc-1f3fe.png","sheet_x":37,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F6CC-1F3FF","non_qualified":null,"image":"1f6cc-1f3ff.png","sheet_x":37,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Sleeping Accommodation","b":"1F6CC","k":[36,48],"o":7},"flag-vn":{"a":"Vietnam Flag","b":"1F1FB-1F1F3","k":[5,19]},"man_in_business_suit_levitating":{"skin_variations":{"1F3FB":{"unified":"1F574-1F3FB","non_qualified":null,"image":"1f574-1f3fb.png","sheet_x":28,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F574-1F3FC","non_qualified":null,"image":"1f574-1f3fc.png","sheet_x":28,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F574-1F3FD","non_qualified":null,"image":"1f574-1f3fd.png","sheet_x":28,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F574-1F3FE","non_qualified":null,"image":"1f574-1f3fe.png","sheet_x":28,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F574-1F3FF","non_qualified":null,"image":"1f574-1f3ff.png","sheet_x":28,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Man in Business Suit Levitating","b":"1F574-FE0F","c":"1F574","k":[28,45],"o":7},"flag-vu":{"a":"Vanuatu Flag","b":"1F1FB-1F1FA","k":[5,20]},"flag-wf":{"a":"Wallis & Futuna Flag","b":"1F1FC-1F1EB","k":[5,21]},"speaking_head_in_silhouette":{"a":"Speaking Head in Silhouette","b":"1F5E3-FE0F","c":"1F5E3","k":[30,14],"o":7},"bust_in_silhouette":{"a":"Bust in Silhouette","b":"1F464","j":["user","person","human"],"k":[15,40]},"flag-ws":{"a":"Samoa Flag","b":"1F1FC-1F1F8","k":[5,22]},"busts_in_silhouette":{"a":"Busts in Silhouette","b":"1F465","j":["user","person","human","group","team"],"k":[15,41]},"flag-xk":{"a":"Kosovo Flag","b":"1F1FD-1F1F0","k":[5,23]},"fencer":{"a":"Fencer","b":"1F93A","k":[40,48],"o":9},"flag-ye":{"a":"Yemen Flag","b":"1F1FE-1F1EA","k":[5,24]},"flag-yt":{"a":"Mayotte Flag","b":"1F1FE-1F1F9","k":[5,25]},"horse_racing":{"skin_variations":{"1F3FB":{"unified":"1F3C7-1F3FB","non_qualified":null,"image":"1f3c7-1f3fb.png","sheet_x":10,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F3C7-1F3FC","non_qualified":null,"image":"1f3c7-1f3fc.png","sheet_x":10,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F3C7-1F3FD","non_qualified":null,"image":"1f3c7-1f3fd.png","sheet_x":10,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F3C7-1F3FE","non_qualified":null,"image":"1f3c7-1f3fe.png","sheet_x":10,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F3C7-1F3FF","non_qualified":null,"image":"1f3c7-1f3ff.png","sheet_x":10,"sheet_y":25,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Horse Racing","b":"1F3C7","j":["animal","betting","competition","gambling","luck"],"k":[10,20]},"flag-za":{"a":"South Africa Flag","b":"1F1FF-1F1E6","k":[5,26]},"skier":{"a":"Skier","b":"26F7-FE0F","c":"26F7","j":["sports","winter","snow"],"k":[48,44],"o":5},"flag-zm":{"a":"Zambia Flag","b":"1F1FF-1F1F2","k":[5,27]},"snowboarder":{"skin_variations":{"1F3FB":{"unified":"1F3C2-1F3FB","non_qualified":null,"image":"1f3c2-1f3fb.png","sheet_x":9,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F3C2-1F3FC","non_qualified":null,"image":"1f3c2-1f3fc.png","sheet_x":9,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F3C2-1F3FD","non_qualified":null,"image":"1f3c2-1f3fd.png","sheet_x":9,"sheet_y":31,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F3C2-1F3FE","non_qualified":null,"image":"1f3c2-1f3fe.png","sheet_x":9,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F3C2-1F3FF","non_qualified":null,"image":"1f3c2-1f3ff.png","sheet_x":9,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Snowboarder","b":"1F3C2","j":["sports","winter"],"k":[9,28]},"golfer":{"skin_variations":{"1F3FB":{"unified":"1F3CC-1F3FB","non_qualified":null,"image":"1f3cc-1f3fb.png","sheet_x":11,"sheet_y":25,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F3CC-1F3FC","non_qualified":null,"image":"1f3cc-1f3fc.png","sheet_x":11,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F3CC-1F3FD","non_qualified":null,"image":"1f3cc-1f3fd.png","sheet_x":11,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F3CC-1F3FE","non_qualified":null,"image":"1f3cc-1f3fe.png","sheet_x":11,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F3CC-1F3FF","non_qualified":null,"image":"1f3cc-1f3ff.png","sheet_x":11,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoleted_by":"1F3CC-FE0F-200D-2642-FE0F","a":"Golfer","b":"1F3CC-FE0F","c":"1F3CC","k":[11,24],"o":7},"flag-zw":{"a":"Zimbabwe Flag","b":"1F1FF-1F1FC","k":[5,28]},"man-golfing":{"skin_variations":{"1F3FB":{"unified":"1F3CC-1F3FB-200D-2642-FE0F","non_qualified":"1F3CC-1F3FB-200D-2642","image":"1f3cc-1f3fb-200d-2642-fe0f.png","sheet_x":11,"sheet_y":19,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F3CC-1F3FC-200D-2642-FE0F","non_qualified":"1F3CC-1F3FC-200D-2642","image":"1f3cc-1f3fc-200d-2642-fe0f.png","sheet_x":11,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F3CC-1F3FD-200D-2642-FE0F","non_qualified":"1F3CC-1F3FD-200D-2642","image":"1f3cc-1f3fd-200d-2642-fe0f.png","sheet_x":11,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F3CC-1F3FE-200D-2642-FE0F","non_qualified":"1F3CC-1F3FE-200D-2642","image":"1f3cc-1f3fe-200d-2642-fe0f.png","sheet_x":11,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F3CC-1F3FF-200D-2642-FE0F","non_qualified":"1F3CC-1F3FF-200D-2642","image":"1f3cc-1f3ff-200d-2642-fe0f.png","sheet_x":11,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F3CC-FE0F","a":"Man Golfing","b":"1F3CC-FE0F-200D-2642-FE0F","k":[11,18],"o":7},"flag-england":{"a":"England Flag","b":"1F3F4-E0067-E0062-E0065-E006E-E0067-E007F","k":[12,16],"o":7},"woman-golfing":{"skin_variations":{"1F3FB":{"unified":"1F3CC-1F3FB-200D-2640-FE0F","non_qualified":"1F3CC-1F3FB-200D-2640","image":"1f3cc-1f3fb-200d-2640-fe0f.png","sheet_x":11,"sheet_y":13,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F3CC-1F3FC-200D-2640-FE0F","non_qualified":"1F3CC-1F3FC-200D-2640","image":"1f3cc-1f3fc-200d-2640-fe0f.png","sheet_x":11,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F3CC-1F3FD-200D-2640-FE0F","non_qualified":"1F3CC-1F3FD-200D-2640","image":"1f3cc-1f3fd-200d-2640-fe0f.png","sheet_x":11,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F3CC-1F3FE-200D-2640-FE0F","non_qualified":"1F3CC-1F3FE-200D-2640","image":"1f3cc-1f3fe-200d-2640-fe0f.png","sheet_x":11,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F3CC-1F3FF-200D-2640-FE0F","non_qualified":"1F3CC-1F3FF-200D-2640","image":"1f3cc-1f3ff-200d-2640-fe0f.png","sheet_x":11,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Golfing","b":"1F3CC-FE0F-200D-2640-FE0F","k":[11,12],"o":7},"flag-scotland":{"a":"Scotland Flag","b":"1F3F4-E0067-E0062-E0073-E0063-E0074-E007F","k":[12,17],"o":7},"flag-wales":{"a":"Wales Flag","b":"1F3F4-E0067-E0062-E0077-E006C-E0073-E007F","k":[12,18],"o":7},"surfer":{"skin_variations":{"1F3FB":{"unified":"1F3C4-1F3FB","non_qualified":null,"image":"1f3c4-1f3fb.png","sheet_x":10,"sheet_y":13,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F3C4-1F3FC","non_qualified":null,"image":"1f3c4-1f3fc.png","sheet_x":10,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F3C4-1F3FD","non_qualified":null,"image":"1f3c4-1f3fd.png","sheet_x":10,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F3C4-1F3FE","non_qualified":null,"image":"1f3c4-1f3fe.png","sheet_x":10,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F3C4-1F3FF","non_qualified":null,"image":"1f3c4-1f3ff.png","sheet_x":10,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F3C4-200D-2642-FE0F","a":"Surfer","b":"1F3C4","k":[10,12]},"man-surfing":{"skin_variations":{"1F3FB":{"unified":"1F3C4-1F3FB-200D-2642-FE0F","non_qualified":"1F3C4-1F3FB-200D-2642","image":"1f3c4-1f3fb-200d-2642-fe0f.png","sheet_x":10,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F3C4-1F3FC-200D-2642-FE0F","non_qualified":"1F3C4-1F3FC-200D-2642","image":"1f3c4-1f3fc-200d-2642-fe0f.png","sheet_x":10,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F3C4-1F3FD-200D-2642-FE0F","non_qualified":"1F3C4-1F3FD-200D-2642","image":"1f3c4-1f3fd-200d-2642-fe0f.png","sheet_x":10,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F3C4-1F3FE-200D-2642-FE0F","non_qualified":"1F3C4-1F3FE-200D-2642","image":"1f3c4-1f3fe-200d-2642-fe0f.png","sheet_x":10,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F3C4-1F3FF-200D-2642-FE0F","non_qualified":"1F3C4-1F3FF-200D-2642","image":"1f3c4-1f3ff-200d-2642-fe0f.png","sheet_x":10,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F3C4","a":"Man Surfing","b":"1F3C4-200D-2642-FE0F","c":"1F3C4-200D-2642","k":[10,6]},"woman-surfing":{"skin_variations":{"1F3FB":{"unified":"1F3C4-1F3FB-200D-2640-FE0F","non_qualified":"1F3C4-1F3FB-200D-2640","image":"1f3c4-1f3fb-200d-2640-fe0f.png","sheet_x":10,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F3C4-1F3FC-200D-2640-FE0F","non_qualified":"1F3C4-1F3FC-200D-2640","image":"1f3c4-1f3fc-200d-2640-fe0f.png","sheet_x":10,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F3C4-1F3FD-200D-2640-FE0F","non_qualified":"1F3C4-1F3FD-200D-2640","image":"1f3c4-1f3fd-200d-2640-fe0f.png","sheet_x":10,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F3C4-1F3FE-200D-2640-FE0F","non_qualified":"1F3C4-1F3FE-200D-2640","image":"1f3c4-1f3fe-200d-2640-fe0f.png","sheet_x":10,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F3C4-1F3FF-200D-2640-FE0F","non_qualified":"1F3C4-1F3FF-200D-2640","image":"1f3c4-1f3ff-200d-2640-fe0f.png","sheet_x":10,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Surfing","b":"1F3C4-200D-2640-FE0F","c":"1F3C4-200D-2640","k":[10,0]},"rowboat":{"skin_variations":{"1F3FB":{"unified":"1F6A3-1F3FB","non_qualified":null,"image":"1f6a3-1f3fb.png","sheet_x":35,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F6A3-1F3FC","non_qualified":null,"image":"1f6a3-1f3fc.png","sheet_x":35,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F6A3-1F3FD","non_qualified":null,"image":"1f6a3-1f3fd.png","sheet_x":35,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F6A3-1F3FE","non_qualified":null,"image":"1f6a3-1f3fe.png","sheet_x":35,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F6A3-1F3FF","non_qualified":null,"image":"1f6a3-1f3ff.png","sheet_x":35,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoleted_by":"1F6A3-200D-2642-FE0F","a":"Rowboat","b":"1F6A3","k":[35,3]},"man-rowing-boat":{"skin_variations":{"1F3FB":{"unified":"1F6A3-1F3FB-200D-2642-FE0F","non_qualified":"1F6A3-1F3FB-200D-2642","image":"1f6a3-1f3fb-200d-2642-fe0f.png","sheet_x":34,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F6A3-1F3FC-200D-2642-FE0F","non_qualified":"1F6A3-1F3FC-200D-2642","image":"1f6a3-1f3fc-200d-2642-fe0f.png","sheet_x":34,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F6A3-1F3FD-200D-2642-FE0F","non_qualified":"1F6A3-1F3FD-200D-2642","image":"1f6a3-1f3fd-200d-2642-fe0f.png","sheet_x":35,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F6A3-1F3FE-200D-2642-FE0F","non_qualified":"1F6A3-1F3FE-200D-2642","image":"1f6a3-1f3fe-200d-2642-fe0f.png","sheet_x":35,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F6A3-1F3FF-200D-2642-FE0F","non_qualified":"1F6A3-1F3FF-200D-2642","image":"1f6a3-1f3ff-200d-2642-fe0f.png","sheet_x":35,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F6A3","a":"Man Rowing Boat","b":"1F6A3-200D-2642-FE0F","c":"1F6A3-200D-2642","k":[34,49]},"woman-rowing-boat":{"skin_variations":{"1F3FB":{"unified":"1F6A3-1F3FB-200D-2640-FE0F","non_qualified":"1F6A3-1F3FB-200D-2640","image":"1f6a3-1f3fb-200d-2640-fe0f.png","sheet_x":34,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F6A3-1F3FC-200D-2640-FE0F","non_qualified":"1F6A3-1F3FC-200D-2640","image":"1f6a3-1f3fc-200d-2640-fe0f.png","sheet_x":34,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F6A3-1F3FD-200D-2640-FE0F","non_qualified":"1F6A3-1F3FD-200D-2640","image":"1f6a3-1f3fd-200d-2640-fe0f.png","sheet_x":34,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F6A3-1F3FE-200D-2640-FE0F","non_qualified":"1F6A3-1F3FE-200D-2640","image":"1f6a3-1f3fe-200d-2640-fe0f.png","sheet_x":34,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F6A3-1F3FF-200D-2640-FE0F","non_qualified":"1F6A3-1F3FF-200D-2640","image":"1f6a3-1f3ff-200d-2640-fe0f.png","sheet_x":34,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Rowing Boat","b":"1F6A3-200D-2640-FE0F","c":"1F6A3-200D-2640","k":[34,43]},"swimmer":{"skin_variations":{"1F3FB":{"unified":"1F3CA-1F3FB","non_qualified":null,"image":"1f3ca-1f3fb.png","sheet_x":10,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F3CA-1F3FC","non_qualified":null,"image":"1f3ca-1f3fc.png","sheet_x":10,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F3CA-1F3FD","non_qualified":null,"image":"1f3ca-1f3fd.png","sheet_x":10,"sheet_y":43,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F3CA-1F3FE","non_qualified":null,"image":"1f3ca-1f3fe.png","sheet_x":10,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F3CA-1F3FF","non_qualified":null,"image":"1f3ca-1f3ff.png","sheet_x":10,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F3CA-200D-2642-FE0F","a":"Swimmer","b":"1F3CA","k":[10,40]},"man-swimming":{"skin_variations":{"1F3FB":{"unified":"1F3CA-1F3FB-200D-2642-FE0F","non_qualified":"1F3CA-1F3FB-200D-2642","image":"1f3ca-1f3fb-200d-2642-fe0f.png","sheet_x":10,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F3CA-1F3FC-200D-2642-FE0F","non_qualified":"1F3CA-1F3FC-200D-2642","image":"1f3ca-1f3fc-200d-2642-fe0f.png","sheet_x":10,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F3CA-1F3FD-200D-2642-FE0F","non_qualified":"1F3CA-1F3FD-200D-2642","image":"1f3ca-1f3fd-200d-2642-fe0f.png","sheet_x":10,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F3CA-1F3FE-200D-2642-FE0F","non_qualified":"1F3CA-1F3FE-200D-2642","image":"1f3ca-1f3fe-200d-2642-fe0f.png","sheet_x":10,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F3CA-1F3FF-200D-2642-FE0F","non_qualified":"1F3CA-1F3FF-200D-2642","image":"1f3ca-1f3ff-200d-2642-fe0f.png","sheet_x":10,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F3CA","a":"Man Swimming","b":"1F3CA-200D-2642-FE0F","c":"1F3CA-200D-2642","k":[10,34]},"woman-swimming":{"skin_variations":{"1F3FB":{"unified":"1F3CA-1F3FB-200D-2640-FE0F","non_qualified":"1F3CA-1F3FB-200D-2640","image":"1f3ca-1f3fb-200d-2640-fe0f.png","sheet_x":10,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F3CA-1F3FC-200D-2640-FE0F","non_qualified":"1F3CA-1F3FC-200D-2640","image":"1f3ca-1f3fc-200d-2640-fe0f.png","sheet_x":10,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F3CA-1F3FD-200D-2640-FE0F","non_qualified":"1F3CA-1F3FD-200D-2640","image":"1f3ca-1f3fd-200d-2640-fe0f.png","sheet_x":10,"sheet_y":31,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F3CA-1F3FE-200D-2640-FE0F","non_qualified":"1F3CA-1F3FE-200D-2640","image":"1f3ca-1f3fe-200d-2640-fe0f.png","sheet_x":10,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F3CA-1F3FF-200D-2640-FE0F","non_qualified":"1F3CA-1F3FF-200D-2640","image":"1f3ca-1f3ff-200d-2640-fe0f.png","sheet_x":10,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Swimming","b":"1F3CA-200D-2640-FE0F","c":"1F3CA-200D-2640","k":[10,28]},"person_with_ball":{"skin_variations":{"1F3FB":{"unified":"26F9-1F3FB","non_qualified":null,"image":"26f9-1f3fb.png","sheet_x":49,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"26F9-1F3FC","non_qualified":null,"image":"26f9-1f3fc.png","sheet_x":49,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"26F9-1F3FD","non_qualified":null,"image":"26f9-1f3fd.png","sheet_x":49,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"26F9-1F3FE","non_qualified":null,"image":"26f9-1f3fe.png","sheet_x":49,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"26F9-1F3FF","non_qualified":null,"image":"26f9-1f3ff.png","sheet_x":49,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoleted_by":"26F9-FE0F-200D-2642-FE0F","a":"Person with Ball","b":"26F9-FE0F","c":"26F9","k":[49,6],"o":5},"man-bouncing-ball":{"skin_variations":{"1F3FB":{"unified":"26F9-1F3FB-200D-2642-FE0F","non_qualified":"26F9-1F3FB-200D-2642","image":"26f9-1f3fb-200d-2642-fe0f.png","sheet_x":49,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"26F9-1F3FC-200D-2642-FE0F","non_qualified":"26F9-1F3FC-200D-2642","image":"26f9-1f3fc-200d-2642-fe0f.png","sheet_x":49,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"26F9-1F3FD-200D-2642-FE0F","non_qualified":"26F9-1F3FD-200D-2642","image":"26f9-1f3fd-200d-2642-fe0f.png","sheet_x":49,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"26F9-1F3FE-200D-2642-FE0F","non_qualified":"26F9-1F3FE-200D-2642","image":"26f9-1f3fe-200d-2642-fe0f.png","sheet_x":49,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"26F9-1F3FF-200D-2642-FE0F","non_qualified":"26F9-1F3FF-200D-2642","image":"26f9-1f3ff-200d-2642-fe0f.png","sheet_x":49,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"26F9-FE0F","a":"Man Bouncing Ball","b":"26F9-FE0F-200D-2642-FE0F","k":[49,0],"o":5},"woman-bouncing-ball":{"skin_variations":{"1F3FB":{"unified":"26F9-1F3FB-200D-2640-FE0F","non_qualified":"26F9-1F3FB-200D-2640","image":"26f9-1f3fb-200d-2640-fe0f.png","sheet_x":48,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"26F9-1F3FC-200D-2640-FE0F","non_qualified":"26F9-1F3FC-200D-2640","image":"26f9-1f3fc-200d-2640-fe0f.png","sheet_x":48,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"26F9-1F3FD-200D-2640-FE0F","non_qualified":"26F9-1F3FD-200D-2640","image":"26f9-1f3fd-200d-2640-fe0f.png","sheet_x":48,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"26F9-1F3FE-200D-2640-FE0F","non_qualified":"26F9-1F3FE-200D-2640","image":"26f9-1f3fe-200d-2640-fe0f.png","sheet_x":48,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"26F9-1F3FF-200D-2640-FE0F","non_qualified":"26F9-1F3FF-200D-2640","image":"26f9-1f3ff-200d-2640-fe0f.png","sheet_x":48,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Bouncing Ball","b":"26F9-FE0F-200D-2640-FE0F","k":[48,46],"o":5},"weight_lifter":{"skin_variations":{"1F3FB":{"unified":"1F3CB-1F3FB","non_qualified":null,"image":"1f3cb-1f3fb.png","sheet_x":11,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F3CB-1F3FC","non_qualified":null,"image":"1f3cb-1f3fc.png","sheet_x":11,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F3CB-1F3FD","non_qualified":null,"image":"1f3cb-1f3fd.png","sheet_x":11,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F3CB-1F3FE","non_qualified":null,"image":"1f3cb-1f3fe.png","sheet_x":11,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F3CB-1F3FF","non_qualified":null,"image":"1f3cb-1f3ff.png","sheet_x":11,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoleted_by":"1F3CB-FE0F-200D-2642-FE0F","a":"Weight Lifter","b":"1F3CB-FE0F","c":"1F3CB","k":[11,6],"o":7},"man-lifting-weights":{"skin_variations":{"1F3FB":{"unified":"1F3CB-1F3FB-200D-2642-FE0F","non_qualified":"1F3CB-1F3FB-200D-2642","image":"1f3cb-1f3fb-200d-2642-fe0f.png","sheet_x":11,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F3CB-1F3FC-200D-2642-FE0F","non_qualified":"1F3CB-1F3FC-200D-2642","image":"1f3cb-1f3fc-200d-2642-fe0f.png","sheet_x":11,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F3CB-1F3FD-200D-2642-FE0F","non_qualified":"1F3CB-1F3FD-200D-2642","image":"1f3cb-1f3fd-200d-2642-fe0f.png","sheet_x":11,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F3CB-1F3FE-200D-2642-FE0F","non_qualified":"1F3CB-1F3FE-200D-2642","image":"1f3cb-1f3fe-200d-2642-fe0f.png","sheet_x":11,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F3CB-1F3FF-200D-2642-FE0F","non_qualified":"1F3CB-1F3FF-200D-2642","image":"1f3cb-1f3ff-200d-2642-fe0f.png","sheet_x":11,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F3CB-FE0F","a":"Man Lifting Weights","b":"1F3CB-FE0F-200D-2642-FE0F","k":[11,0],"o":7},"woman-lifting-weights":{"skin_variations":{"1F3FB":{"unified":"1F3CB-1F3FB-200D-2640-FE0F","non_qualified":"1F3CB-1F3FB-200D-2640","image":"1f3cb-1f3fb-200d-2640-fe0f.png","sheet_x":10,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F3CB-1F3FC-200D-2640-FE0F","non_qualified":"1F3CB-1F3FC-200D-2640","image":"1f3cb-1f3fc-200d-2640-fe0f.png","sheet_x":10,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F3CB-1F3FD-200D-2640-FE0F","non_qualified":"1F3CB-1F3FD-200D-2640","image":"1f3cb-1f3fd-200d-2640-fe0f.png","sheet_x":10,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F3CB-1F3FE-200D-2640-FE0F","non_qualified":"1F3CB-1F3FE-200D-2640","image":"1f3cb-1f3fe-200d-2640-fe0f.png","sheet_x":10,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F3CB-1F3FF-200D-2640-FE0F","non_qualified":"1F3CB-1F3FF-200D-2640","image":"1f3cb-1f3ff-200d-2640-fe0f.png","sheet_x":10,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Lifting Weights","b":"1F3CB-FE0F-200D-2640-FE0F","k":[10,46],"o":7},"bicyclist":{"skin_variations":{"1F3FB":{"unified":"1F6B4-1F3FB","non_qualified":null,"image":"1f6b4-1f3fb.png","sheet_x":35,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F6B4-1F3FC","non_qualified":null,"image":"1f6b4-1f3fc.png","sheet_x":35,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F6B4-1F3FD","non_qualified":null,"image":"1f6b4-1f3fd.png","sheet_x":35,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F6B4-1F3FE","non_qualified":null,"image":"1f6b4-1f3fe.png","sheet_x":35,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F6B4-1F3FF","non_qualified":null,"image":"1f6b4-1f3ff.png","sheet_x":35,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F6B4-200D-2642-FE0F","a":"Bicyclist","b":"1F6B4","k":[35,37]},"man-biking":{"skin_variations":{"1F3FB":{"unified":"1F6B4-1F3FB-200D-2642-FE0F","non_qualified":"1F6B4-1F3FB-200D-2642","image":"1f6b4-1f3fb-200d-2642-fe0f.png","sheet_x":35,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F6B4-1F3FC-200D-2642-FE0F","non_qualified":"1F6B4-1F3FC-200D-2642","image":"1f6b4-1f3fc-200d-2642-fe0f.png","sheet_x":35,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F6B4-1F3FD-200D-2642-FE0F","non_qualified":"1F6B4-1F3FD-200D-2642","image":"1f6b4-1f3fd-200d-2642-fe0f.png","sheet_x":35,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F6B4-1F3FE-200D-2642-FE0F","non_qualified":"1F6B4-1F3FE-200D-2642","image":"1f6b4-1f3fe-200d-2642-fe0f.png","sheet_x":35,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F6B4-1F3FF-200D-2642-FE0F","non_qualified":"1F6B4-1F3FF-200D-2642","image":"1f6b4-1f3ff-200d-2642-fe0f.png","sheet_x":35,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F6B4","a":"Man Biking","b":"1F6B4-200D-2642-FE0F","c":"1F6B4-200D-2642","k":[35,31]},"woman-biking":{"skin_variations":{"1F3FB":{"unified":"1F6B4-1F3FB-200D-2640-FE0F","non_qualified":"1F6B4-1F3FB-200D-2640","image":"1f6b4-1f3fb-200d-2640-fe0f.png","sheet_x":35,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F6B4-1F3FC-200D-2640-FE0F","non_qualified":"1F6B4-1F3FC-200D-2640","image":"1f6b4-1f3fc-200d-2640-fe0f.png","sheet_x":35,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F6B4-1F3FD-200D-2640-FE0F","non_qualified":"1F6B4-1F3FD-200D-2640","image":"1f6b4-1f3fd-200d-2640-fe0f.png","sheet_x":35,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F6B4-1F3FE-200D-2640-FE0F","non_qualified":"1F6B4-1F3FE-200D-2640","image":"1f6b4-1f3fe-200d-2640-fe0f.png","sheet_x":35,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F6B4-1F3FF-200D-2640-FE0F","non_qualified":"1F6B4-1F3FF-200D-2640","image":"1f6b4-1f3ff-200d-2640-fe0f.png","sheet_x":35,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Biking","b":"1F6B4-200D-2640-FE0F","c":"1F6B4-200D-2640","k":[35,25]},"mountain_bicyclist":{"skin_variations":{"1F3FB":{"unified":"1F6B5-1F3FB","non_qualified":null,"image":"1f6b5-1f3fb.png","sheet_x":36,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FC":{"unified":"1F6B5-1F3FC","non_qualified":null,"image":"1f6b5-1f3fc.png","sheet_x":36,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FD":{"unified":"1F6B5-1F3FD","non_qualified":null,"image":"1f6b5-1f3fd.png","sheet_x":36,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FE":{"unified":"1F6B5-1F3FE","non_qualified":null,"image":"1f6b5-1f3fe.png","sheet_x":36,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true},"1F3FF":{"unified":"1F6B5-1F3FF","non_qualified":null,"image":"1f6b5-1f3ff.png","sheet_x":36,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":true}},"obsoleted_by":"1F6B5-200D-2642-FE0F","a":"Mountain Bicyclist","b":"1F6B5","k":[36,3]},"man-mountain-biking":{"skin_variations":{"1F3FB":{"unified":"1F6B5-1F3FB-200D-2642-FE0F","non_qualified":"1F6B5-1F3FB-200D-2642","image":"1f6b5-1f3fb-200d-2642-fe0f.png","sheet_x":35,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F6B5-1F3FC-200D-2642-FE0F","non_qualified":"1F6B5-1F3FC-200D-2642","image":"1f6b5-1f3fc-200d-2642-fe0f.png","sheet_x":35,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F6B5-1F3FD-200D-2642-FE0F","non_qualified":"1F6B5-1F3FD-200D-2642","image":"1f6b5-1f3fd-200d-2642-fe0f.png","sheet_x":36,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F6B5-1F3FE-200D-2642-FE0F","non_qualified":"1F6B5-1F3FE-200D-2642","image":"1f6b5-1f3fe-200d-2642-fe0f.png","sheet_x":36,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F6B5-1F3FF-200D-2642-FE0F","non_qualified":"1F6B5-1F3FF-200D-2642","image":"1f6b5-1f3ff-200d-2642-fe0f.png","sheet_x":36,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"obsoletes":"1F6B5","a":"Man Mountain Biking","b":"1F6B5-200D-2642-FE0F","c":"1F6B5-200D-2642","k":[35,49]},"woman-mountain-biking":{"skin_variations":{"1F3FB":{"unified":"1F6B5-1F3FB-200D-2640-FE0F","non_qualified":"1F6B5-1F3FB-200D-2640","image":"1f6b5-1f3fb-200d-2640-fe0f.png","sheet_x":35,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F6B5-1F3FC-200D-2640-FE0F","non_qualified":"1F6B5-1F3FC-200D-2640","image":"1f6b5-1f3fc-200d-2640-fe0f.png","sheet_x":35,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F6B5-1F3FD-200D-2640-FE0F","non_qualified":"1F6B5-1F3FD-200D-2640","image":"1f6b5-1f3fd-200d-2640-fe0f.png","sheet_x":35,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F6B5-1F3FE-200D-2640-FE0F","non_qualified":"1F6B5-1F3FE-200D-2640","image":"1f6b5-1f3fe-200d-2640-fe0f.png","sheet_x":35,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F6B5-1F3FF-200D-2640-FE0F","non_qualified":"1F6B5-1F3FF-200D-2640","image":"1f6b5-1f3ff-200d-2640-fe0f.png","sheet_x":35,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Mountain Biking","b":"1F6B5-200D-2640-FE0F","c":"1F6B5-200D-2640","k":[35,43]},"racing_car":{"a":"Racing Car","b":"1F3CE-FE0F","c":"1F3CE","j":["sports","race","fast","formula","f1"],"k":[11,31],"o":7},"racing_motorcycle":{"a":"Racing Motorcycle","b":"1F3CD-FE0F","c":"1F3CD","k":[11,30],"o":7},"person_doing_cartwheel":{"skin_variations":{"1F3FB":{"unified":"1F938-1F3FB","non_qualified":null,"image":"1f938-1f3fb.png","sheet_x":40,"sheet_y":25,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F938-1F3FC","non_qualified":null,"image":"1f938-1f3fc.png","sheet_x":40,"sheet_y":26,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F938-1F3FD","non_qualified":null,"image":"1f938-1f3fd.png","sheet_x":40,"sheet_y":27,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F938-1F3FE","non_qualified":null,"image":"1f938-1f3fe.png","sheet_x":40,"sheet_y":28,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F938-1F3FF","non_qualified":null,"image":"1f938-1f3ff.png","sheet_x":40,"sheet_y":29,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Person Doing Cartwheel","b":"1F938","k":[40,24],"o":9},"man-cartwheeling":{"skin_variations":{"1F3FB":{"unified":"1F938-1F3FB-200D-2642-FE0F","non_qualified":"1F938-1F3FB-200D-2642","image":"1f938-1f3fb-200d-2642-fe0f.png","sheet_x":40,"sheet_y":19,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F938-1F3FC-200D-2642-FE0F","non_qualified":"1F938-1F3FC-200D-2642","image":"1f938-1f3fc-200d-2642-fe0f.png","sheet_x":40,"sheet_y":20,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F938-1F3FD-200D-2642-FE0F","non_qualified":"1F938-1F3FD-200D-2642","image":"1f938-1f3fd-200d-2642-fe0f.png","sheet_x":40,"sheet_y":21,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F938-1F3FE-200D-2642-FE0F","non_qualified":"1F938-1F3FE-200D-2642","image":"1f938-1f3fe-200d-2642-fe0f.png","sheet_x":40,"sheet_y":22,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F938-1F3FF-200D-2642-FE0F","non_qualified":"1F938-1F3FF-200D-2642","image":"1f938-1f3ff-200d-2642-fe0f.png","sheet_x":40,"sheet_y":23,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Cartwheeling","b":"1F938-200D-2642-FE0F","c":"1F938-200D-2642","k":[40,18],"o":9},"woman-cartwheeling":{"skin_variations":{"1F3FB":{"unified":"1F938-1F3FB-200D-2640-FE0F","non_qualified":"1F938-1F3FB-200D-2640","image":"1f938-1f3fb-200d-2640-fe0f.png","sheet_x":40,"sheet_y":13,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F938-1F3FC-200D-2640-FE0F","non_qualified":"1F938-1F3FC-200D-2640","image":"1f938-1f3fc-200d-2640-fe0f.png","sheet_x":40,"sheet_y":14,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F938-1F3FD-200D-2640-FE0F","non_qualified":"1F938-1F3FD-200D-2640","image":"1f938-1f3fd-200d-2640-fe0f.png","sheet_x":40,"sheet_y":15,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F938-1F3FE-200D-2640-FE0F","non_qualified":"1F938-1F3FE-200D-2640","image":"1f938-1f3fe-200d-2640-fe0f.png","sheet_x":40,"sheet_y":16,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F938-1F3FF-200D-2640-FE0F","non_qualified":"1F938-1F3FF-200D-2640","image":"1f938-1f3ff-200d-2640-fe0f.png","sheet_x":40,"sheet_y":17,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Cartwheeling","b":"1F938-200D-2640-FE0F","c":"1F938-200D-2640","k":[40,12],"o":9},"wrestlers":{"a":"Wrestlers","b":"1F93C","k":[40,51],"o":9},"man-wrestling":{"a":"Man Wrestling","b":"1F93C-200D-2642-FE0F","c":"1F93C-200D-2642","k":[40,50],"o":9},"woman-wrestling":{"a":"Woman Wrestling","b":"1F93C-200D-2640-FE0F","c":"1F93C-200D-2640","k":[40,49],"o":9},"water_polo":{"skin_variations":{"1F3FB":{"unified":"1F93D-1F3FB","non_qualified":null,"image":"1f93d-1f3fb.png","sheet_x":41,"sheet_y":13,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F93D-1F3FC","non_qualified":null,"image":"1f93d-1f3fc.png","sheet_x":41,"sheet_y":14,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F93D-1F3FD","non_qualified":null,"image":"1f93d-1f3fd.png","sheet_x":41,"sheet_y":15,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F93D-1F3FE","non_qualified":null,"image":"1f93d-1f3fe.png","sheet_x":41,"sheet_y":16,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F93D-1F3FF","non_qualified":null,"image":"1f93d-1f3ff.png","sheet_x":41,"sheet_y":17,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Water Polo","b":"1F93D","k":[41,12],"o":9},"man-playing-water-polo":{"skin_variations":{"1F3FB":{"unified":"1F93D-1F3FB-200D-2642-FE0F","non_qualified":"1F93D-1F3FB-200D-2642","image":"1f93d-1f3fb-200d-2642-fe0f.png","sheet_x":41,"sheet_y":7,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F93D-1F3FC-200D-2642-FE0F","non_qualified":"1F93D-1F3FC-200D-2642","image":"1f93d-1f3fc-200d-2642-fe0f.png","sheet_x":41,"sheet_y":8,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F93D-1F3FD-200D-2642-FE0F","non_qualified":"1F93D-1F3FD-200D-2642","image":"1f93d-1f3fd-200d-2642-fe0f.png","sheet_x":41,"sheet_y":9,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F93D-1F3FE-200D-2642-FE0F","non_qualified":"1F93D-1F3FE-200D-2642","image":"1f93d-1f3fe-200d-2642-fe0f.png","sheet_x":41,"sheet_y":10,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F93D-1F3FF-200D-2642-FE0F","non_qualified":"1F93D-1F3FF-200D-2642","image":"1f93d-1f3ff-200d-2642-fe0f.png","sheet_x":41,"sheet_y":11,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Playing Water Polo","b":"1F93D-200D-2642-FE0F","c":"1F93D-200D-2642","k":[41,6],"o":9},"woman-playing-water-polo":{"skin_variations":{"1F3FB":{"unified":"1F93D-1F3FB-200D-2640-FE0F","non_qualified":"1F93D-1F3FB-200D-2640","image":"1f93d-1f3fb-200d-2640-fe0f.png","sheet_x":41,"sheet_y":1,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F93D-1F3FC-200D-2640-FE0F","non_qualified":"1F93D-1F3FC-200D-2640","image":"1f93d-1f3fc-200d-2640-fe0f.png","sheet_x":41,"sheet_y":2,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F93D-1F3FD-200D-2640-FE0F","non_qualified":"1F93D-1F3FD-200D-2640","image":"1f93d-1f3fd-200d-2640-fe0f.png","sheet_x":41,"sheet_y":3,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F93D-1F3FE-200D-2640-FE0F","non_qualified":"1F93D-1F3FE-200D-2640","image":"1f93d-1f3fe-200d-2640-fe0f.png","sheet_x":41,"sheet_y":4,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F93D-1F3FF-200D-2640-FE0F","non_qualified":"1F93D-1F3FF-200D-2640","image":"1f93d-1f3ff-200d-2640-fe0f.png","sheet_x":41,"sheet_y":5,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Playing Water Polo","b":"1F93D-200D-2640-FE0F","c":"1F93D-200D-2640","k":[41,0],"o":9},"handball":{"skin_variations":{"1F3FB":{"unified":"1F93E-1F3FB","non_qualified":null,"image":"1f93e-1f3fb.png","sheet_x":41,"sheet_y":31,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F93E-1F3FC","non_qualified":null,"image":"1f93e-1f3fc.png","sheet_x":41,"sheet_y":32,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F93E-1F3FD","non_qualified":null,"image":"1f93e-1f3fd.png","sheet_x":41,"sheet_y":33,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F93E-1F3FE","non_qualified":null,"image":"1f93e-1f3fe.png","sheet_x":41,"sheet_y":34,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F93E-1F3FF","non_qualified":null,"image":"1f93e-1f3ff.png","sheet_x":41,"sheet_y":35,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Handball","b":"1F93E","k":[41,30],"o":9},"man-playing-handball":{"skin_variations":{"1F3FB":{"unified":"1F93E-1F3FB-200D-2642-FE0F","non_qualified":"1F93E-1F3FB-200D-2642","image":"1f93e-1f3fb-200d-2642-fe0f.png","sheet_x":41,"sheet_y":25,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F93E-1F3FC-200D-2642-FE0F","non_qualified":"1F93E-1F3FC-200D-2642","image":"1f93e-1f3fc-200d-2642-fe0f.png","sheet_x":41,"sheet_y":26,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F93E-1F3FD-200D-2642-FE0F","non_qualified":"1F93E-1F3FD-200D-2642","image":"1f93e-1f3fd-200d-2642-fe0f.png","sheet_x":41,"sheet_y":27,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F93E-1F3FE-200D-2642-FE0F","non_qualified":"1F93E-1F3FE-200D-2642","image":"1f93e-1f3fe-200d-2642-fe0f.png","sheet_x":41,"sheet_y":28,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F93E-1F3FF-200D-2642-FE0F","non_qualified":"1F93E-1F3FF-200D-2642","image":"1f93e-1f3ff-200d-2642-fe0f.png","sheet_x":41,"sheet_y":29,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Playing Handball","b":"1F93E-200D-2642-FE0F","c":"1F93E-200D-2642","k":[41,24],"o":9},"woman-playing-handball":{"skin_variations":{"1F3FB":{"unified":"1F93E-1F3FB-200D-2640-FE0F","non_qualified":"1F93E-1F3FB-200D-2640","image":"1f93e-1f3fb-200d-2640-fe0f.png","sheet_x":41,"sheet_y":19,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F93E-1F3FC-200D-2640-FE0F","non_qualified":"1F93E-1F3FC-200D-2640","image":"1f93e-1f3fc-200d-2640-fe0f.png","sheet_x":41,"sheet_y":20,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F93E-1F3FD-200D-2640-FE0F","non_qualified":"1F93E-1F3FD-200D-2640","image":"1f93e-1f3fd-200d-2640-fe0f.png","sheet_x":41,"sheet_y":21,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F93E-1F3FE-200D-2640-FE0F","non_qualified":"1F93E-1F3FE-200D-2640","image":"1f93e-1f3fe-200d-2640-fe0f.png","sheet_x":41,"sheet_y":22,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F93E-1F3FF-200D-2640-FE0F","non_qualified":"1F93E-1F3FF-200D-2640","image":"1f93e-1f3ff-200d-2640-fe0f.png","sheet_x":41,"sheet_y":23,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Playing Handball","b":"1F93E-200D-2640-FE0F","c":"1F93E-200D-2640","k":[41,18],"o":9},"juggling":{"skin_variations":{"1F3FB":{"unified":"1F939-1F3FB","non_qualified":null,"image":"1f939-1f3fb.png","sheet_x":40,"sheet_y":43,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F939-1F3FC","non_qualified":null,"image":"1f939-1f3fc.png","sheet_x":40,"sheet_y":44,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F939-1F3FD","non_qualified":null,"image":"1f939-1f3fd.png","sheet_x":40,"sheet_y":45,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F939-1F3FE","non_qualified":null,"image":"1f939-1f3fe.png","sheet_x":40,"sheet_y":46,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F939-1F3FF","non_qualified":null,"image":"1f939-1f3ff.png","sheet_x":40,"sheet_y":47,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Juggling","b":"1F939","k":[40,42],"o":9},"man-juggling":{"skin_variations":{"1F3FB":{"unified":"1F939-1F3FB-200D-2642-FE0F","non_qualified":"1F939-1F3FB-200D-2642","image":"1f939-1f3fb-200d-2642-fe0f.png","sheet_x":40,"sheet_y":37,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F939-1F3FC-200D-2642-FE0F","non_qualified":"1F939-1F3FC-200D-2642","image":"1f939-1f3fc-200d-2642-fe0f.png","sheet_x":40,"sheet_y":38,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F939-1F3FD-200D-2642-FE0F","non_qualified":"1F939-1F3FD-200D-2642","image":"1f939-1f3fd-200d-2642-fe0f.png","sheet_x":40,"sheet_y":39,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F939-1F3FE-200D-2642-FE0F","non_qualified":"1F939-1F3FE-200D-2642","image":"1f939-1f3fe-200d-2642-fe0f.png","sheet_x":40,"sheet_y":40,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F939-1F3FF-200D-2642-FE0F","non_qualified":"1F939-1F3FF-200D-2642","image":"1f939-1f3ff-200d-2642-fe0f.png","sheet_x":40,"sheet_y":41,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Man Juggling","b":"1F939-200D-2642-FE0F","c":"1F939-200D-2642","k":[40,36],"o":9},"woman-juggling":{"skin_variations":{"1F3FB":{"unified":"1F939-1F3FB-200D-2640-FE0F","non_qualified":"1F939-1F3FB-200D-2640","image":"1f939-1f3fb-200d-2640-fe0f.png","sheet_x":40,"sheet_y":31,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FC":{"unified":"1F939-1F3FC-200D-2640-FE0F","non_qualified":"1F939-1F3FC-200D-2640","image":"1f939-1f3fc-200d-2640-fe0f.png","sheet_x":40,"sheet_y":32,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FD":{"unified":"1F939-1F3FD-200D-2640-FE0F","non_qualified":"1F939-1F3FD-200D-2640","image":"1f939-1f3fd-200d-2640-fe0f.png","sheet_x":40,"sheet_y":33,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FE":{"unified":"1F939-1F3FE-200D-2640-FE0F","non_qualified":"1F939-1F3FE-200D-2640","image":"1f939-1f3fe-200d-2640-fe0f.png","sheet_x":40,"sheet_y":34,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false},"1F3FF":{"unified":"1F939-1F3FF-200D-2640-FE0F","non_qualified":"1F939-1F3FF-200D-2640","image":"1f939-1f3ff-200d-2640-fe0f.png","sheet_x":40,"sheet_y":35,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":false,"has_img_messenger":false}},"a":"Woman Juggling","b":"1F939-200D-2640-FE0F","c":"1F939-200D-2640","k":[40,30],"o":9},"couple":{"a":"Man and Woman Holding Hands","b":"1F46B","j":["pair","people","human","love","date","dating","like","affection","valentines","marriage"],"k":[20,30],"n":["man_and_woman_holding_hands"]},"two_men_holding_hands":{"a":"Two Men Holding Hands","b":"1F46C","j":["pair","couple","love","like","bromance","friendship","people","human"],"k":[20,31]},"two_women_holding_hands":{"a":"Two Women Holding Hands","b":"1F46D","j":["pair","friendship","couple","love","like","female","people","human"],"k":[20,32]},"couplekiss":{"obsoleted_by":"1F469-200D-2764-FE0F-200D-1F48B-200D-1F468","a":"Kiss","b":"1F48F","k":[24,41]},"woman-kiss-man":{"obsoletes":"1F48F","a":"Woman Kiss Man","b":"1F469-200D-2764-FE0F-200D-1F48B-200D-1F468","c":"1F469-200D-2764-200D-1F48B-200D-1F468","k":[20,21]},"man-kiss-man":{"a":"Man Kiss Man","b":"1F468-200D-2764-FE0F-200D-1F48B-200D-1F468","c":"1F468-200D-2764-200D-1F48B-200D-1F468","k":[18,10]},"woman-kiss-woman":{"a":"Woman Kiss Woman","b":"1F469-200D-2764-FE0F-200D-1F48B-200D-1F469","c":"1F469-200D-2764-200D-1F48B-200D-1F469","k":[20,22]},"couple_with_heart":{"obsoleted_by":"1F469-200D-2764-FE0F-200D-1F468","a":"Couple with Heart","b":"1F491","k":[24,43]},"woman-heart-man":{"obsoletes":"1F491","a":"Woman Heart Man","b":"1F469-200D-2764-FE0F-200D-1F468","c":"1F469-200D-2764-200D-1F468","k":[20,19]},"man-heart-man":{"a":"Man Heart Man","b":"1F468-200D-2764-FE0F-200D-1F468","c":"1F468-200D-2764-200D-1F468","k":[18,9]},"woman-heart-woman":{"a":"Woman Heart Woman","b":"1F469-200D-2764-FE0F-200D-1F469","c":"1F469-200D-2764-200D-1F469","k":[20,20]},"family":{"obsoleted_by":"1F468-200D-1F469-200D-1F466","a":"Family","b":"1F46A","k":[20,29],"n":["man-woman-boy"]},"man-woman-boy":{"obsoletes":"1F46A","a":"Man Woman Boy","b":"1F468-200D-1F469-200D-1F466","k":[17,2],"n":["family"]},"man-woman-girl":{"a":"Man Woman Girl","b":"1F468-200D-1F469-200D-1F467","k":[17,4]},"man-woman-girl-boy":{"a":"Man Woman Girl Boy","b":"1F468-200D-1F469-200D-1F467-200D-1F466","k":[17,5]},"man-woman-boy-boy":{"a":"Man Woman Boy Boy","b":"1F468-200D-1F469-200D-1F466-200D-1F466","k":[17,3]},"man-woman-girl-girl":{"a":"Man Woman Girl Girl","b":"1F468-200D-1F469-200D-1F467-200D-1F467","k":[17,6]},"man-man-boy":{"a":"Man Man Boy","b":"1F468-200D-1F468-200D-1F466","k":[16,49]},"man-man-girl":{"a":"Man Man Girl","b":"1F468-200D-1F468-200D-1F467","k":[16,51]},"man-man-girl-boy":{"a":"Man Man Girl Boy","b":"1F468-200D-1F468-200D-1F467-200D-1F466","k":[17,0]},"man-man-boy-boy":{"a":"Man Man Boy Boy","b":"1F468-200D-1F468-200D-1F466-200D-1F466","k":[16,50]},"man-man-girl-girl":{"a":"Man Man Girl Girl","b":"1F468-200D-1F468-200D-1F467-200D-1F467","k":[17,1]},"woman-woman-boy":{"a":"Woman Woman Boy","b":"1F469-200D-1F469-200D-1F466","k":[19,12]},"woman-woman-girl":{"a":"Woman Woman Girl","b":"1F469-200D-1F469-200D-1F467","k":[19,14]},"woman-woman-girl-boy":{"a":"Woman Woman Girl Boy","b":"1F469-200D-1F469-200D-1F467-200D-1F466","k":[19,15]},"woman-woman-boy-boy":{"a":"Woman Woman Boy Boy","b":"1F469-200D-1F469-200D-1F466-200D-1F466","k":[19,13]},"woman-woman-girl-girl":{"a":"Woman Woman Girl Girl","b":"1F469-200D-1F469-200D-1F467-200D-1F467","k":[19,16]},"man-boy":{"a":"Man Boy","b":"1F468-200D-1F466","k":[16,45]},"man-boy-boy":{"a":"Man Boy Boy","b":"1F468-200D-1F466-200D-1F466","k":[16,44]},"man-girl":{"a":"Man Girl","b":"1F468-200D-1F467","k":[16,48]},"man-girl-boy":{"a":"Man Girl Boy","b":"1F468-200D-1F467-200D-1F466","k":[16,46]},"man-girl-girl":{"a":"Man Girl Girl","b":"1F468-200D-1F467-200D-1F467","k":[16,47]},"woman-boy":{"a":"Woman Boy","b":"1F469-200D-1F466","k":[19,8]},"woman-boy-boy":{"a":"Woman Boy Boy","b":"1F469-200D-1F466-200D-1F466","k":[19,7]},"woman-girl":{"a":"Woman Girl","b":"1F469-200D-1F467","k":[19,11]},"woman-girl-boy":{"a":"Woman Girl Boy","b":"1F469-200D-1F467-200D-1F466","k":[19,9]},"woman-girl-girl":{"a":"Woman Girl Girl","b":"1F469-200D-1F467-200D-1F467","k":[19,10]},"selfie":{"skin_variations":{"1F3FB":{"unified":"1F933-1F3FB","non_qualified":null,"image":"1f933-1f3fb.png","sheet_x":39,"sheet_y":23,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F933-1F3FC","non_qualified":null,"image":"1f933-1f3fc.png","sheet_x":39,"sheet_y":24,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F933-1F3FD","non_qualified":null,"image":"1f933-1f3fd.png","sheet_x":39,"sheet_y":25,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F933-1F3FE","non_qualified":null,"image":"1f933-1f3fe.png","sheet_x":39,"sheet_y":26,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F933-1F3FF","non_qualified":null,"image":"1f933-1f3ff.png","sheet_x":39,"sheet_y":27,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Selfie","b":"1F933","j":["camera","phone"],"k":[39,22],"o":9},"muscle":{"skin_variations":{"1F3FB":{"unified":"1F4AA-1F3FB","non_qualified":null,"image":"1f4aa-1f3fb.png","sheet_x":25,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F4AA-1F3FC","non_qualified":null,"image":"1f4aa-1f3fc.png","sheet_x":25,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F4AA-1F3FD","non_qualified":null,"image":"1f4aa-1f3fd.png","sheet_x":25,"sheet_y":19,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F4AA-1F3FE","non_qualified":null,"image":"1f4aa-1f3fe.png","sheet_x":25,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F4AA-1F3FF","non_qualified":null,"image":"1f4aa-1f3ff.png","sheet_x":25,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Flexed Biceps","b":"1F4AA","j":["arm","flex","hand","summer","strong","biceps"],"k":[25,16]},"point_left":{"skin_variations":{"1F3FB":{"unified":"1F448-1F3FB","non_qualified":null,"image":"1f448-1f3fb.png","sheet_x":14,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F448-1F3FC","non_qualified":null,"image":"1f448-1f3fc.png","sheet_x":14,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F448-1F3FD","non_qualified":null,"image":"1f448-1f3fd.png","sheet_x":14,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F448-1F3FE","non_qualified":null,"image":"1f448-1f3fe.png","sheet_x":14,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F448-1F3FF","non_qualified":null,"image":"1f448-1f3ff.png","sheet_x":14,"sheet_y":24,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"White Left Pointing Backhand Index","b":"1F448","j":["direction","fingers","hand","left"],"k":[14,19]},"point_right":{"skin_variations":{"1F3FB":{"unified":"1F449-1F3FB","non_qualified":null,"image":"1f449-1f3fb.png","sheet_x":14,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F449-1F3FC","non_qualified":null,"image":"1f449-1f3fc.png","sheet_x":14,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F449-1F3FD","non_qualified":null,"image":"1f449-1f3fd.png","sheet_x":14,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F449-1F3FE","non_qualified":null,"image":"1f449-1f3fe.png","sheet_x":14,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F449-1F3FF","non_qualified":null,"image":"1f449-1f3ff.png","sheet_x":14,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"White Right Pointing Backhand Index","b":"1F449","j":["fingers","hand","direction","right"],"k":[14,25]},"point_up":{"skin_variations":{"1F3FB":{"unified":"261D-1F3FB","non_qualified":null,"image":"261d-1f3fb.png","sheet_x":47,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"261D-1F3FC","non_qualified":null,"image":"261d-1f3fc.png","sheet_x":47,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"261D-1F3FD","non_qualified":null,"image":"261d-1f3fd.png","sheet_x":47,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"261D-1F3FE","non_qualified":null,"image":"261d-1f3fe.png","sheet_x":47,"sheet_y":30,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"261D-1F3FF","non_qualified":null,"image":"261d-1f3ff.png","sheet_x":47,"sheet_y":31,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"White Up Pointing Index","b":"261D-FE0F","c":"261D","j":["hand","fingers","direction","up"],"k":[47,26],"o":1},"point_up_2":{"skin_variations":{"1F3FB":{"unified":"1F446-1F3FB","non_qualified":null,"image":"1f446-1f3fb.png","sheet_x":14,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F446-1F3FC","non_qualified":null,"image":"1f446-1f3fc.png","sheet_x":14,"sheet_y":9,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F446-1F3FD","non_qualified":null,"image":"1f446-1f3fd.png","sheet_x":14,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F446-1F3FE","non_qualified":null,"image":"1f446-1f3fe.png","sheet_x":14,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F446-1F3FF","non_qualified":null,"image":"1f446-1f3ff.png","sheet_x":14,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"White Up Pointing Backhand Index","b":"1F446","j":["fingers","hand","direction","up"],"k":[14,7]},"middle_finger":{"skin_variations":{"1F3FB":{"unified":"1F595-1F3FB","non_qualified":null,"image":"1f595-1f3fb.png","sheet_x":29,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F595-1F3FC","non_qualified":null,"image":"1f595-1f3fc.png","sheet_x":29,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F595-1F3FD","non_qualified":null,"image":"1f595-1f3fd.png","sheet_x":29,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F595-1F3FE","non_qualified":null,"image":"1f595-1f3fe.png","sheet_x":29,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F595-1F3FF","non_qualified":null,"image":"1f595-1f3ff.png","sheet_x":29,"sheet_y":43,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Reversed Hand with Middle Finger Extended","b":"1F595","k":[29,38],"n":["reversed_hand_with_middle_finger_extended"],"o":7},"point_down":{"skin_variations":{"1F3FB":{"unified":"1F447-1F3FB","non_qualified":null,"image":"1f447-1f3fb.png","sheet_x":14,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F447-1F3FC","non_qualified":null,"image":"1f447-1f3fc.png","sheet_x":14,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F447-1F3FD","non_qualified":null,"image":"1f447-1f3fd.png","sheet_x":14,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F447-1F3FE","non_qualified":null,"image":"1f447-1f3fe.png","sheet_x":14,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F447-1F3FF","non_qualified":null,"image":"1f447-1f3ff.png","sheet_x":14,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"White Down Pointing Backhand Index","b":"1F447","j":["fingers","hand","direction","down"],"k":[14,13]},"v":{"skin_variations":{"1F3FB":{"unified":"270C-1F3FB","non_qualified":null,"image":"270c-1f3fb.png","sheet_x":49,"sheet_y":31,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"270C-1F3FC","non_qualified":null,"image":"270c-1f3fc.png","sheet_x":49,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"270C-1F3FD","non_qualified":null,"image":"270c-1f3fd.png","sheet_x":49,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"270C-1F3FE","non_qualified":null,"image":"270c-1f3fe.png","sheet_x":49,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"270C-1F3FF","non_qualified":null,"image":"270c-1f3ff.png","sheet_x":49,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Victory Hand","b":"270C-FE0F","c":"270C","j":["fingers","ohyeah","hand","peace","victory","two"],"k":[49,30],"o":1},"crossed_fingers":{"skin_variations":{"1F3FB":{"unified":"1F91E-1F3FB","non_qualified":null,"image":"1f91e-1f3fb.png","sheet_x":38,"sheet_y":12,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F91E-1F3FC","non_qualified":null,"image":"1f91e-1f3fc.png","sheet_x":38,"sheet_y":13,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F91E-1F3FD","non_qualified":null,"image":"1f91e-1f3fd.png","sheet_x":38,"sheet_y":14,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F91E-1F3FE","non_qualified":null,"image":"1f91e-1f3fe.png","sheet_x":38,"sheet_y":15,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F91E-1F3FF","non_qualified":null,"image":"1f91e-1f3ff.png","sheet_x":38,"sheet_y":16,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Hand with Index and Middle Fingers Crossed","b":"1F91E","j":["good","lucky"],"k":[38,11],"n":["hand_with_index_and_middle_fingers_crossed"],"o":9},"spock-hand":{"skin_variations":{"1F3FB":{"unified":"1F596-1F3FB","non_qualified":null,"image":"1f596-1f3fb.png","sheet_x":29,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F596-1F3FC","non_qualified":null,"image":"1f596-1f3fc.png","sheet_x":29,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F596-1F3FD","non_qualified":null,"image":"1f596-1f3fd.png","sheet_x":29,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F596-1F3FE","non_qualified":null,"image":"1f596-1f3fe.png","sheet_x":29,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F596-1F3FF","non_qualified":null,"image":"1f596-1f3ff.png","sheet_x":29,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Raised Hand with Part Between Middle and Ring Fingers","b":"1F596","k":[29,44],"o":7},"the_horns":{"skin_variations":{"1F3FB":{"unified":"1F918-1F3FB","non_qualified":null,"image":"1f918-1f3fb.png","sheet_x":37,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F918-1F3FC","non_qualified":null,"image":"1f918-1f3fc.png","sheet_x":37,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F918-1F3FD","non_qualified":null,"image":"1f918-1f3fd.png","sheet_x":37,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F918-1F3FE","non_qualified":null,"image":"1f918-1f3fe.png","sheet_x":37,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F918-1F3FF","non_qualified":null,"image":"1f918-1f3ff.png","sheet_x":37,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Sign of the Horns","b":"1F918","k":[37,32],"n":["sign_of_the_horns"],"o":8},"call_me_hand":{"skin_variations":{"1F3FB":{"unified":"1F919-1F3FB","non_qualified":null,"image":"1f919-1f3fb.png","sheet_x":37,"sheet_y":39,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F919-1F3FC","non_qualified":null,"image":"1f919-1f3fc.png","sheet_x":37,"sheet_y":40,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F919-1F3FD","non_qualified":null,"image":"1f919-1f3fd.png","sheet_x":37,"sheet_y":41,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F919-1F3FE","non_qualified":null,"image":"1f919-1f3fe.png","sheet_x":37,"sheet_y":42,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F919-1F3FF","non_qualified":null,"image":"1f919-1f3ff.png","sheet_x":37,"sheet_y":43,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Call Me Hand","b":"1F919","j":["hands","gesture"],"k":[37,38],"o":9},"raised_hand_with_fingers_splayed":{"skin_variations":{"1F3FB":{"unified":"1F590-1F3FB","non_qualified":null,"image":"1f590-1f3fb.png","sheet_x":29,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F590-1F3FC","non_qualified":null,"image":"1f590-1f3fc.png","sheet_x":29,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F590-1F3FD","non_qualified":null,"image":"1f590-1f3fd.png","sheet_x":29,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F590-1F3FE","non_qualified":null,"image":"1f590-1f3fe.png","sheet_x":29,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F590-1F3FF","non_qualified":null,"image":"1f590-1f3ff.png","sheet_x":29,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Raised Hand with Fingers Splayed","b":"1F590-FE0F","c":"1F590","j":["hand","fingers","palm"],"k":[29,32],"o":7},"hand":{"skin_variations":{"1F3FB":{"unified":"270B-1F3FB","non_qualified":null,"image":"270b-1f3fb.png","sheet_x":49,"sheet_y":25,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"270B-1F3FC","non_qualified":null,"image":"270b-1f3fc.png","sheet_x":49,"sheet_y":26,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"270B-1F3FD","non_qualified":null,"image":"270b-1f3fd.png","sheet_x":49,"sheet_y":27,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"270B-1F3FE","non_qualified":null,"image":"270b-1f3fe.png","sheet_x":49,"sheet_y":28,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"270B-1F3FF","non_qualified":null,"image":"270b-1f3ff.png","sheet_x":49,"sheet_y":29,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Raised Hand","b":"270B","k":[49,24],"n":["raised_hand"]},"ok_hand":{"skin_variations":{"1F3FB":{"unified":"1F44C-1F3FB","non_qualified":null,"image":"1f44c-1f3fb.png","sheet_x":14,"sheet_y":44,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F44C-1F3FC","non_qualified":null,"image":"1f44c-1f3fc.png","sheet_x":14,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F44C-1F3FD","non_qualified":null,"image":"1f44c-1f3fd.png","sheet_x":14,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F44C-1F3FE","non_qualified":null,"image":"1f44c-1f3fe.png","sheet_x":14,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F44C-1F3FF","non_qualified":null,"image":"1f44c-1f3ff.png","sheet_x":14,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Ok Hand Sign","b":"1F44C","j":["fingers","limbs","perfect","ok","okay"],"k":[14,43]},"+1":{"skin_variations":{"1F3FB":{"unified":"1F44D-1F3FB","non_qualified":null,"image":"1f44d-1f3fb.png","sheet_x":14,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F44D-1F3FC","non_qualified":null,"image":"1f44d-1f3fc.png","sheet_x":14,"sheet_y":51,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F44D-1F3FD","non_qualified":null,"image":"1f44d-1f3fd.png","sheet_x":15,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F44D-1F3FE","non_qualified":null,"image":"1f44d-1f3fe.png","sheet_x":15,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F44D-1F3FF","non_qualified":null,"image":"1f44d-1f3ff.png","sheet_x":15,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Thumbs Up Sign","b":"1F44D","j":["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],"k":[14,49],"n":["thumbsup"]},"-1":{"skin_variations":{"1F3FB":{"unified":"1F44E-1F3FB","non_qualified":null,"image":"1f44e-1f3fb.png","sheet_x":15,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F44E-1F3FC","non_qualified":null,"image":"1f44e-1f3fc.png","sheet_x":15,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F44E-1F3FD","non_qualified":null,"image":"1f44e-1f3fd.png","sheet_x":15,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F44E-1F3FE","non_qualified":null,"image":"1f44e-1f3fe.png","sheet_x":15,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F44E-1F3FF","non_qualified":null,"image":"1f44e-1f3ff.png","sheet_x":15,"sheet_y":8,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Thumbs Down Sign","b":"1F44E","j":["thumbsdown","no","dislike","hand"],"k":[15,3],"n":["thumbsdown"]},"fist":{"skin_variations":{"1F3FB":{"unified":"270A-1F3FB","non_qualified":null,"image":"270a-1f3fb.png","sheet_x":49,"sheet_y":19,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"270A-1F3FC","non_qualified":null,"image":"270a-1f3fc.png","sheet_x":49,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"270A-1F3FD","non_qualified":null,"image":"270a-1f3fd.png","sheet_x":49,"sheet_y":21,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"270A-1F3FE","non_qualified":null,"image":"270a-1f3fe.png","sheet_x":49,"sheet_y":22,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"270A-1F3FF","non_qualified":null,"image":"270a-1f3ff.png","sheet_x":49,"sheet_y":23,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Raised Fist","b":"270A","j":["fingers","hand","grasp"],"k":[49,18]},"facepunch":{"skin_variations":{"1F3FB":{"unified":"1F44A-1F3FB","non_qualified":null,"image":"1f44a-1f3fb.png","sheet_x":14,"sheet_y":32,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F44A-1F3FC","non_qualified":null,"image":"1f44a-1f3fc.png","sheet_x":14,"sheet_y":33,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F44A-1F3FD","non_qualified":null,"image":"1f44a-1f3fd.png","sheet_x":14,"sheet_y":34,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F44A-1F3FE","non_qualified":null,"image":"1f44a-1f3fe.png","sheet_x":14,"sheet_y":35,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F44A-1F3FF","non_qualified":null,"image":"1f44a-1f3ff.png","sheet_x":14,"sheet_y":36,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Fisted Hand Sign","b":"1F44A","j":["angry","violence","fist","hit","attack","hand"],"k":[14,31],"n":["punch"]},"left-facing_fist":{"skin_variations":{"1F3FB":{"unified":"1F91B-1F3FB","non_qualified":null,"image":"1f91b-1f3fb.png","sheet_x":37,"sheet_y":51,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F91B-1F3FC","non_qualified":null,"image":"1f91b-1f3fc.png","sheet_x":38,"sheet_y":0,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F91B-1F3FD","non_qualified":null,"image":"1f91b-1f3fd.png","sheet_x":38,"sheet_y":1,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F91B-1F3FE","non_qualified":null,"image":"1f91b-1f3fe.png","sheet_x":38,"sheet_y":2,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F91B-1F3FF","non_qualified":null,"image":"1f91b-1f3ff.png","sheet_x":38,"sheet_y":3,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Left-Facing Fist","b":"1F91B","k":[37,50],"o":9},"right-facing_fist":{"skin_variations":{"1F3FB":{"unified":"1F91C-1F3FB","non_qualified":null,"image":"1f91c-1f3fb.png","sheet_x":38,"sheet_y":5,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F91C-1F3FC","non_qualified":null,"image":"1f91c-1f3fc.png","sheet_x":38,"sheet_y":6,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F91C-1F3FD","non_qualified":null,"image":"1f91c-1f3fd.png","sheet_x":38,"sheet_y":7,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F91C-1F3FE","non_qualified":null,"image":"1f91c-1f3fe.png","sheet_x":38,"sheet_y":8,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F91C-1F3FF","non_qualified":null,"image":"1f91c-1f3ff.png","sheet_x":38,"sheet_y":9,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Right-Facing Fist","b":"1F91C","k":[38,4],"o":9},"raised_back_of_hand":{"skin_variations":{"1F3FB":{"unified":"1F91A-1F3FB","non_qualified":null,"image":"1f91a-1f3fb.png","sheet_x":37,"sheet_y":45,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F91A-1F3FC","non_qualified":null,"image":"1f91a-1f3fc.png","sheet_x":37,"sheet_y":46,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F91A-1F3FD","non_qualified":null,"image":"1f91a-1f3fd.png","sheet_x":37,"sheet_y":47,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F91A-1F3FE","non_qualified":null,"image":"1f91a-1f3fe.png","sheet_x":37,"sheet_y":48,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F91A-1F3FF","non_qualified":null,"image":"1f91a-1f3ff.png","sheet_x":37,"sheet_y":49,"added_in":"9.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Raised Back of Hand","b":"1F91A","j":["fingers","raised","backhand"],"k":[37,44],"o":9},"wave":{"skin_variations":{"1F3FB":{"unified":"1F44B-1F3FB","non_qualified":null,"image":"1f44b-1f3fb.png","sheet_x":14,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F44B-1F3FC","non_qualified":null,"image":"1f44b-1f3fc.png","sheet_x":14,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F44B-1F3FD","non_qualified":null,"image":"1f44b-1f3fd.png","sheet_x":14,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F44B-1F3FE","non_qualified":null,"image":"1f44b-1f3fe.png","sheet_x":14,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F44B-1F3FF","non_qualified":null,"image":"1f44b-1f3ff.png","sheet_x":14,"sheet_y":42,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Waving Hand Sign","b":"1F44B","j":["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],"k":[14,37]},"i_love_you_hand_sign":{"skin_variations":{"1F3FB":{"unified":"1F91F-1F3FB","non_qualified":null,"image":"1f91f-1f3fb.png","sheet_x":38,"sheet_y":18,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F91F-1F3FC","non_qualified":null,"image":"1f91f-1f3fc.png","sheet_x":38,"sheet_y":19,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F91F-1F3FD","non_qualified":null,"image":"1f91f-1f3fd.png","sheet_x":38,"sheet_y":20,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F91F-1F3FE","non_qualified":null,"image":"1f91f-1f3fe.png","sheet_x":38,"sheet_y":21,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F91F-1F3FF","non_qualified":null,"image":"1f91f-1f3ff.png","sheet_x":38,"sheet_y":22,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"I Love You Hand Sign","b":"1F91F","k":[38,17],"o":10},"writing_hand":{"skin_variations":{"1F3FB":{"unified":"270D-1F3FB","non_qualified":null,"image":"270d-1f3fb.png","sheet_x":49,"sheet_y":37,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"270D-1F3FC","non_qualified":null,"image":"270d-1f3fc.png","sheet_x":49,"sheet_y":38,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"270D-1F3FD","non_qualified":null,"image":"270d-1f3fd.png","sheet_x":49,"sheet_y":39,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"270D-1F3FE","non_qualified":null,"image":"270d-1f3fe.png","sheet_x":49,"sheet_y":40,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"270D-1F3FF","non_qualified":null,"image":"270d-1f3ff.png","sheet_x":49,"sheet_y":41,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Writing Hand","b":"270D-FE0F","c":"270D","j":["lower_left_ballpoint_pen","stationery","write","compose"],"k":[49,36],"o":1},"clap":{"skin_variations":{"1F3FB":{"unified":"1F44F-1F3FB","non_qualified":null,"image":"1f44f-1f3fb.png","sheet_x":15,"sheet_y":10,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F44F-1F3FC","non_qualified":null,"image":"1f44f-1f3fc.png","sheet_x":15,"sheet_y":11,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F44F-1F3FD","non_qualified":null,"image":"1f44f-1f3fd.png","sheet_x":15,"sheet_y":12,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F44F-1F3FE","non_qualified":null,"image":"1f44f-1f3fe.png","sheet_x":15,"sheet_y":13,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F44F-1F3FF","non_qualified":null,"image":"1f44f-1f3ff.png","sheet_x":15,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Clapping Hands Sign","b":"1F44F","j":["hands","praise","applause","congrats","yay"],"k":[15,9]},"open_hands":{"skin_variations":{"1F3FB":{"unified":"1F450-1F3FB","non_qualified":null,"image":"1f450-1f3fb.png","sheet_x":15,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F450-1F3FC","non_qualified":null,"image":"1f450-1f3fc.png","sheet_x":15,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F450-1F3FD","non_qualified":null,"image":"1f450-1f3fd.png","sheet_x":15,"sheet_y":18,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F450-1F3FE","non_qualified":null,"image":"1f450-1f3fe.png","sheet_x":15,"sheet_y":19,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F450-1F3FF","non_qualified":null,"image":"1f450-1f3ff.png","sheet_x":15,"sheet_y":20,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Open Hands Sign","b":"1F450","j":["fingers","butterfly","hands","open"],"k":[15,15]},"raised_hands":{"skin_variations":{"1F3FB":{"unified":"1F64C-1F3FB","non_qualified":null,"image":"1f64c-1f3fb.png","sheet_x":33,"sheet_y":13,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F64C-1F3FC","non_qualified":null,"image":"1f64c-1f3fc.png","sheet_x":33,"sheet_y":14,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F64C-1F3FD","non_qualified":null,"image":"1f64c-1f3fd.png","sheet_x":33,"sheet_y":15,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F64C-1F3FE","non_qualified":null,"image":"1f64c-1f3fe.png","sheet_x":33,"sheet_y":16,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F64C-1F3FF","non_qualified":null,"image":"1f64c-1f3ff.png","sheet_x":33,"sheet_y":17,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Person Raising Both Hands in Celebration","b":"1F64C","j":["gesture","hooray","yea","celebration","hands"],"k":[33,12]},"palms_up_together":{"skin_variations":{"1F3FB":{"unified":"1F932-1F3FB","non_qualified":null,"image":"1f932-1f3fb.png","sheet_x":39,"sheet_y":17,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FC":{"unified":"1F932-1F3FC","non_qualified":null,"image":"1f932-1f3fc.png","sheet_x":39,"sheet_y":18,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FD":{"unified":"1F932-1F3FD","non_qualified":null,"image":"1f932-1f3fd.png","sheet_x":39,"sheet_y":19,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FE":{"unified":"1F932-1F3FE","non_qualified":null,"image":"1f932-1f3fe.png","sheet_x":39,"sheet_y":20,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false},"1F3FF":{"unified":"1F932-1F3FF","non_qualified":null,"image":"1f932-1f3ff.png","sheet_x":39,"sheet_y":21,"added_in":"10.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":false}},"a":"Palms Up Together","b":"1F932","k":[39,16],"o":10},"pray":{"skin_variations":{"1F3FB":{"unified":"1F64F-1F3FB","non_qualified":null,"image":"1f64f-1f3fb.png","sheet_x":34,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F64F-1F3FC","non_qualified":null,"image":"1f64f-1f3fc.png","sheet_x":34,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F64F-1F3FD","non_qualified":null,"image":"1f64f-1f3fd.png","sheet_x":34,"sheet_y":5,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F64F-1F3FE","non_qualified":null,"image":"1f64f-1f3fe.png","sheet_x":34,"sheet_y":6,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F64F-1F3FF","non_qualified":null,"image":"1f64f-1f3ff.png","sheet_x":34,"sheet_y":7,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Person with Folded Hands","b":"1F64F","j":["please","hope","wish","namaste","highfive"],"k":[34,2]},"handshake":{"a":"Handshake","b":"1F91D","j":["agreement","shake"],"k":[38,10],"o":9},"nail_care":{"skin_variations":{"1F3FB":{"unified":"1F485-1F3FB","non_qualified":null,"image":"1f485-1f3fb.png","sheet_x":23,"sheet_y":45,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F485-1F3FC","non_qualified":null,"image":"1f485-1f3fc.png","sheet_x":23,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F485-1F3FD","non_qualified":null,"image":"1f485-1f3fd.png","sheet_x":23,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F485-1F3FE","non_qualified":null,"image":"1f485-1f3fe.png","sheet_x":23,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F485-1F3FF","non_qualified":null,"image":"1f485-1f3ff.png","sheet_x":23,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Nail Polish","b":"1F485","j":["beauty","manicure","finger","fashion","nail"],"k":[23,44]},"ear":{"skin_variations":{"1F3FB":{"unified":"1F442-1F3FB","non_qualified":null,"image":"1f442-1f3fb.png","sheet_x":13,"sheet_y":46,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F442-1F3FC","non_qualified":null,"image":"1f442-1f3fc.png","sheet_x":13,"sheet_y":47,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F442-1F3FD","non_qualified":null,"image":"1f442-1f3fd.png","sheet_x":13,"sheet_y":48,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F442-1F3FE","non_qualified":null,"image":"1f442-1f3fe.png","sheet_x":13,"sheet_y":49,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F442-1F3FF","non_qualified":null,"image":"1f442-1f3ff.png","sheet_x":13,"sheet_y":50,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Ear","b":"1F442","j":["face","hear","sound","listen"],"k":[13,45]},"nose":{"skin_variations":{"1F3FB":{"unified":"1F443-1F3FB","non_qualified":null,"image":"1f443-1f3fb.png","sheet_x":14,"sheet_y":0,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FC":{"unified":"1F443-1F3FC","non_qualified":null,"image":"1f443-1f3fc.png","sheet_x":14,"sheet_y":1,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FD":{"unified":"1F443-1F3FD","non_qualified":null,"image":"1f443-1f3fd.png","sheet_x":14,"sheet_y":2,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FE":{"unified":"1F443-1F3FE","non_qualified":null,"image":"1f443-1f3fe.png","sheet_x":14,"sheet_y":3,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true},"1F3FF":{"unified":"1F443-1F3FF","non_qualified":null,"image":"1f443-1f3ff.png","sheet_x":14,"sheet_y":4,"added_in":"8.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_emojione":true,"has_img_facebook":true,"has_img_messenger":true}},"a":"Nose","b":"1F443","j":["smell","sniff"],"k":[13,51]},"footprints":{"a":"Footprints","b":"1F463","j":["feet","tracking","walking","beach"],"k":[15,39]},"eyes":{"a":"Eyes","b":"1F440","j":["look","watch","stalk","peek","see"],"k":[13,42]},"eye":{"a":"Eye","b":"1F441-FE0F","c":"1F441","j":["face","look","see","watch","stare"],"k":[13,44],"o":7},"eye-in-speech-bubble":{"a":"Eye in Speech Bubble","b":"1F441-FE0F-200D-1F5E8-FE0F","k":[13,43],"o":7},"brain":{"a":"Brain","b":"1F9E0","k":[46,22],"o":10},"tongue":{"a":"Tongue","b":"1F445","j":["mouth","playful"],"k":[14,6]},"lips":{"a":"Mouth","b":"1F444","j":["mouth","kiss"],"k":[14,5]},"kiss":{"a":"Kiss Mark","b":"1F48B","j":["face","lips","love","like","affection","valentines"],"k":[24,37]},"cupid":{"a":"Heart with Arrow","b":"1F498","j":["love","like","heart","affection","valentines"],"k":[24,50]},"heart":{"a":"Heavy Black Heart","b":"2764-FE0F","c":"2764","j":["love","like","valentines"],"k":[50,8],"l":["<3"],"m":"<3","o":1},"heartbeat":{"a":"Beating Heart","b":"1F493","j":["love","like","affection","valentines","pink","heart"],"k":[24,45]},"broken_heart":{"a":"Broken Heart","b":"1F494","j":["sad","sorry","break","heart","heartbreak"],"k":[24,46],"l":["",":->"],"n":["satisfied"],"o":2},"waving_white_flag":{"a":"Waving White Flag","b":"1F3F3-FE0F","c":"1F3F3","k":[11,12],"o":2},"safety_vest":{"a":"Safety Vest","b":"1F9BA","k":[43,54],"o":12},"sweat_smile":{"a":"Smiling Face with Open Mouth and Cold Sweat","b":"1F605","j":["face","hot","happy","laugh","sweat","smile","relief"],"k":[30,40],"o":2},"sparkles":{"a":"Sparkles","b":"2728","j":["stars","shine","shiny","cool","awesome","good","magic"],"k":[55,16],"o":2},"banana":{"a":"Banana","b":"1F34C","j":["fruit","food","monkey"],"k":[6,36],"o":2},"rainbow-flag":{"a":"Rainbow Flag","b":"1F3F3-FE0F-200D-1F308","c":"1F3F3-200D-1F308","k":[11,11],"o":4},"ok_hand":{"skin_variations":{"1F3FB":{"unified":"1F44C-1F3FB","non_qualified":null,"image":"1f44c-1f3fb.png","sheet_x":13,"sheet_y":33,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F44C-1F3FC","non_qualified":null,"image":"1f44c-1f3fc.png","sheet_x":13,"sheet_y":34,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F44C-1F3FD","non_qualified":null,"image":"1f44c-1f3fd.png","sheet_x":13,"sheet_y":35,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F44C-1F3FE","non_qualified":null,"image":"1f44c-1f3fe.png","sheet_x":13,"sheet_y":36,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F44C-1F3FF","non_qualified":null,"image":"1f44c-1f3ff.png","sheet_x":13,"sheet_y":37,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Ok Hand Sign","b":"1F44C","j":["fingers","limbs","perfect","ok","okay"],"k":[13,32],"o":2},"japan":{"a":"Silhouette of Japan","b":"1F5FE","j":["nation","country","japanese","asia"],"k":[30,33],"o":2},"dog2":{"a":"Dog","b":"1F415","j":["animal","nature","friend","doge","pet","faithful"],"k":[11,50],"o":2},"womens":{"a":"Womens Symbol","b":"1F6BA","j":["purple-square","woman","female","toilet","loo","restroom","gender"],"k":[36,11],"o":2},"necktie":{"a":"Necktie","b":"1F454","j":["shirt","suitup","formal","fashion","cloth","business"],"k":[14,8],"o":2},"pirate_flag":{"a":"Pirate Flag","b":"1F3F4-200D-2620-FE0F","c":"1F3F4-200D-2620","k":[11,13],"o":11},"guide_dog":{"a":"Guide Dog","b":"1F9AE","k":[43,2],"o":12},"restroom":{"a":"Restroom","b":"1F6BB","j":["blue-square","toilet","refresh","wc","gender"],"k":[36,12],"o":2},"compass":{"a":"Compass","b":"1F9ED","k":[51,32],"o":11},"rolling_on_the_floor_laughing":{"a":"Rolling on the Floor Laughing","b":"1F923","k":[38,20],"o":4},"balloon":{"a":"Balloon","b":"1F388","j":["party","celebration","birthday","circus"],"k":[7,44],"o":2},"pinching_hand":{"skin_variations":{"1F3FB":{"unified":"1F90F-1F3FB","non_qualified":null,"image":"1f90f-1f3fb.png","sheet_x":37,"sheet_y":18,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F90F-1F3FC","non_qualified":null,"image":"1f90f-1f3fc.png","sheet_x":37,"sheet_y":19,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F90F-1F3FD","non_qualified":null,"image":"1f90f-1f3fd.png","sheet_x":37,"sheet_y":20,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F90F-1F3FE","non_qualified":null,"image":"1f90f-1f3fe.png","sheet_x":37,"sheet_y":21,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F90F-1F3FF","non_qualified":null,"image":"1f90f-1f3ff.png","sheet_x":37,"sheet_y":22,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Pinching Hand","b":"1F90F","k":[37,17],"o":12},"pineapple":{"a":"Pineapple","b":"1F34D","j":["fruit","nature","food"],"k":[6,37],"o":2},"shirt":{"a":"T-Shirt","b":"1F455","k":[14,9],"n":["tshirt"],"o":2},"service_dog":{"a":"Service Dog","b":"1F415-200D-1F9BA","k":[11,49],"o":12},"baby_symbol":{"a":"Baby Symbol","b":"1F6BC","j":["orange-square","child"],"k":[36,13],"o":2},"joy":{"a":"Face with Tears of Joy","b":"1F602","j":["face","cry","tears","weep","happy","happytears","haha"],"k":[30,37],"o":2},"tada":{"a":"Party Popper","b":"1F389","j":["party","congratulations","birthday","magic","circus","celebration"],"k":[7,45],"o":2},"mango":{"a":"Mango","b":"1F96D","k":[42,3],"o":11},"v":{"skin_variations":{"1F3FB":{"unified":"270C-1F3FB","non_qualified":null,"image":"270c-1f3fb.png","sheet_x":54,"sheet_y":56,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"270C-1F3FC","non_qualified":null,"image":"270c-1f3fc.png","sheet_x":55,"sheet_y":0,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"270C-1F3FD","non_qualified":null,"image":"270c-1f3fd.png","sheet_x":55,"sheet_y":1,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"270C-1F3FE","non_qualified":null,"image":"270c-1f3fe.png","sheet_x":55,"sheet_y":2,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"270C-1F3FF","non_qualified":null,"image":"270c-1f3ff.png","sheet_x":55,"sheet_y":3,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Victory Hand","b":"270C-FE0F","c":"270C","j":["fingers","ohyeah","hand","peace","victory","two"],"k":[54,55],"o":2},"snow_capped_mountain":{"a":"Snow Capped Mountain","b":"1F3D4-FE0F","c":"1F3D4","k":[10,39],"o":2},"flag-ac":{"a":"Ascension Island Flag","b":"1F1E6-1F1E8","k":[0,31],"o":2},"jeans":{"a":"Jeans","b":"1F456","j":["fashion","shopping"],"k":[14,10],"o":2},"poodle":{"a":"Poodle","b":"1F429","j":["dog","animal","101","nature","pet"],"k":[12,13],"o":2},"crossed_fingers":{"skin_variations":{"1F3FB":{"unified":"1F91E-1F3FB","non_qualified":null,"image":"1f91e-1f3fb.png","sheet_x":38,"sheet_y":6,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F91E-1F3FC","non_qualified":null,"image":"1f91e-1f3fc.png","sheet_x":38,"sheet_y":7,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F91E-1F3FD","non_qualified":null,"image":"1f91e-1f3fd.png","sheet_x":38,"sheet_y":8,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F91E-1F3FE","non_qualified":null,"image":"1f91e-1f3fe.png","sheet_x":38,"sheet_y":9,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F91E-1F3FF","non_qualified":null,"image":"1f91e-1f3ff.png","sheet_x":38,"sheet_y":10,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Hand with Index and Middle Fingers Crossed","b":"1F91E","j":["good","lucky"],"k":[38,5],"n":["hand_with_index_and_middle_fingers_crossed"],"o":4},"flag-ad":{"a":"Andorra Flag","b":"1F1E6-1F1E9","k":[0,32],"o":2},"slightly_smiling_face":{"a":"Slightly Smiling Face","b":"1F642","j":["face","smile"],"k":[31,44],"l":[":)","(:",":-)"],"o":2},"apple":{"a":"Red Apple","b":"1F34E","j":["fruit","mac","school"],"k":[6,38],"o":2},"wc":{"a":"Water Closet","b":"1F6BE","j":["toilet","restroom","blue-square"],"k":[36,15],"o":2},"scarf":{"a":"Scarf","b":"1F9E3","k":[51,22],"o":5},"mountain":{"a":"Mountain","b":"26F0-FE0F","c":"26F0","j":["photo","nature","environment"],"k":[54,11],"o":2},"confetti_ball":{"a":"Confetti Ball","b":"1F38A","j":["festival","party","birthday","circus"],"k":[7,46],"o":2},"i_love_you_hand_sign":{"skin_variations":{"1F3FB":{"unified":"1F91F-1F3FB","non_qualified":null,"image":"1f91f-1f3fb.png","sheet_x":38,"sheet_y":12,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F91F-1F3FC","non_qualified":null,"image":"1f91f-1f3fc.png","sheet_x":38,"sheet_y":13,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F91F-1F3FD","non_qualified":null,"image":"1f91f-1f3fd.png","sheet_x":38,"sheet_y":14,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F91F-1F3FE","non_qualified":null,"image":"1f91f-1f3fe.png","sheet_x":38,"sheet_y":15,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F91F-1F3FF","non_qualified":null,"image":"1f91f-1f3ff.png","sheet_x":38,"sheet_y":16,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"I Love You Hand Sign","b":"1F91F","k":[38,11],"o":5},"wolf":{"a":"Wolf Face","b":"1F43A","j":["animal","nature","wild"],"k":[12,30],"o":2},"gloves":{"a":"Gloves","b":"1F9E4","k":[51,23],"o":5},"flag-ae":{"a":"United Arab Emirates Flag","b":"1F1E6-1F1EA","k":[0,33],"o":2},"upside_down_face":{"a":"Upside-Down Face","b":"1F643","j":["face","flipped","silly","smile"],"k":[31,45],"o":2},"green_apple":{"a":"Green Apple","b":"1F34F","j":["fruit","nature"],"k":[6,39],"o":2},"passport_control":{"a":"Passport Control","b":"1F6C2","j":["custom","blue-square"],"k":[36,24],"o":2},"volcano":{"a":"Volcano","b":"1F30B","j":["photo","nature","disaster"],"k":[5,30],"o":2},"tanabata_tree":{"a":"Tanabata Tree","b":"1F38B","j":["plant","nature","branch","summer"],"k":[7,47],"o":2},"customs":{"a":"Customs","b":"1F6C3","j":["passport","border","blue-square"],"k":[36,25],"o":2},"coat":{"a":"Coat","b":"1F9E5","k":[51,24],"o":5},"wink":{"a":"Winking Face","b":"1F609","j":["face","happy","mischievous","secret",";)","smile","eye"],"k":[30,44],"l":[";)",";-)"],"m":";)","o":2},"bamboo":{"a":"Pine Decoration","b":"1F38D","j":["plant","nature","vegetable","panda","pine_decoration"],"k":[7,49],"o":2},"flag-af":{"a":"Afghanistan Flag","b":"1F1E6-1F1EB","k":[0,34],"o":2},"fox_face":{"a":"Fox Face","b":"1F98A","j":["animal","nature","face"],"k":[42,28],"o":4},"pear":{"a":"Pear","b":"1F350","j":["fruit","nature","food"],"k":[6,40],"o":2},"mount_fuji":{"a":"Mount Fuji","b":"1F5FB","j":["photo","mountain","nature","japanese"],"k":[30,30],"o":2},"the_horns":{"skin_variations":{"1F3FB":{"unified":"1F918-1F3FB","non_qualified":null,"image":"1f918-1f3fb.png","sheet_x":37,"sheet_y":32,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F918-1F3FC","non_qualified":null,"image":"1f918-1f3fc.png","sheet_x":37,"sheet_y":33,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F918-1F3FD","non_qualified":null,"image":"1f918-1f3fd.png","sheet_x":37,"sheet_y":34,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F918-1F3FE","non_qualified":null,"image":"1f918-1f3fe.png","sheet_x":37,"sheet_y":35,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F918-1F3FF","non_qualified":null,"image":"1f918-1f3ff.png","sheet_x":37,"sheet_y":36,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Sign of the Horns","b":"1F918","k":[37,31],"n":["sign_of_the_horns"],"o":2},"call_me_hand":{"skin_variations":{"1F3FB":{"unified":"1F919-1F3FB","non_qualified":null,"image":"1f919-1f3fb.png","sheet_x":37,"sheet_y":38,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F919-1F3FC","non_qualified":null,"image":"1f919-1f3fc.png","sheet_x":37,"sheet_y":39,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F919-1F3FD","non_qualified":null,"image":"1f919-1f3fd.png","sheet_x":37,"sheet_y":40,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F919-1F3FE","non_qualified":null,"image":"1f919-1f3fe.png","sheet_x":37,"sheet_y":41,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F919-1F3FF","non_qualified":null,"image":"1f919-1f3ff.png","sheet_x":37,"sheet_y":42,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Call Me Hand","b":"1F919","j":["hands","gesture"],"k":[37,37],"o":4},"flag-ag":{"a":"Antigua & Barbuda Flag","b":"1F1E6-1F1EC","k":[0,35],"o":2},"raccoon":{"a":"Raccoon","b":"1F99D","k":[42,47],"o":11},"dolls":{"a":"Japanese Dolls","b":"1F38E","j":["japanese","toy","kimono"],"k":[7,50],"o":2},"blush":{"a":"Smiling Face with Smiling Eyes","b":"1F60A","j":["face","smile","happy","flushed","crush","embarrassed","shy","joy"],"k":[30,45],"m":":)","o":2},"peach":{"a":"Peach","b":"1F351","j":["fruit","nature","food"],"k":[6,41],"o":2},"baggage_claim":{"a":"Baggage Claim","b":"1F6C4","j":["blue-square","airport","transport"],"k":[36,26],"o":2},"socks":{"a":"Socks","b":"1F9E6","k":[51,25],"o":5},"camping":{"a":"Camping","b":"1F3D5-FE0F","c":"1F3D5","j":["photo","outdoors","tent"],"k":[10,40],"o":2},"dress":{"a":"Dress","b":"1F457","j":["clothes","fashion","shopping"],"k":[14,11],"o":2},"beach_with_umbrella":{"a":"Beach with Umbrella","b":"1F3D6-FE0F","c":"1F3D6","k":[10,41],"o":2},"cherries":{"a":"Cherries","b":"1F352","j":["food","fruit"],"k":[6,42],"o":2},"cat":{"a":"Cat Face","b":"1F431","j":["animal","meow","nature","pet","kitten"],"k":[12,21],"o":2},"point_left":{"skin_variations":{"1F3FB":{"unified":"1F448-1F3FB","non_qualified":null,"image":"1f448-1f3fb.png","sheet_x":13,"sheet_y":9,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F448-1F3FC","non_qualified":null,"image":"1f448-1f3fc.png","sheet_x":13,"sheet_y":10,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F448-1F3FD","non_qualified":null,"image":"1f448-1f3fd.png","sheet_x":13,"sheet_y":11,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F448-1F3FE","non_qualified":null,"image":"1f448-1f3fe.png","sheet_x":13,"sheet_y":12,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F448-1F3FF","non_qualified":null,"image":"1f448-1f3ff.png","sheet_x":13,"sheet_y":13,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"White Left Pointing Backhand Index","b":"1F448","j":["direction","fingers","hand","left"],"k":[13,8],"o":2},"left_luggage":{"a":"Left Luggage","b":"1F6C5","j":["blue-square","travel"],"k":[36,27],"o":2},"flag-ai":{"a":"Anguilla Flag","b":"1F1E6-1F1EE","k":[0,36],"o":2},"innocent":{"a":"Smiling Face with Halo","b":"1F607","j":["face","angel","heaven","halo"],"k":[30,42],"o":2},"flags":{"a":"Carp Streamer","b":"1F38F","j":["fish","japanese","koinobori","carp","banner"],"k":[7,51],"o":2},"warning":{"a":"Warning Sign","b":"26A0-FE0F","c":"26A0","j":["exclamation","wip","alert","error","problem","issue"],"k":[53,50],"o":2},"strawberry":{"a":"Strawberry","b":"1F353","j":["fruit","food","nature"],"k":[6,43],"o":2},"point_right":{"skin_variations":{"1F3FB":{"unified":"1F449-1F3FB","non_qualified":null,"image":"1f449-1f3fb.png","sheet_x":13,"sheet_y":15,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F449-1F3FC","non_qualified":null,"image":"1f449-1f3fc.png","sheet_x":13,"sheet_y":16,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F449-1F3FD","non_qualified":null,"image":"1f449-1f3fd.png","sheet_x":13,"sheet_y":17,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F449-1F3FE","non_qualified":null,"image":"1f449-1f3fe.png","sheet_x":13,"sheet_y":18,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F449-1F3FF","non_qualified":null,"image":"1f449-1f3ff.png","sheet_x":13,"sheet_y":19,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"White Right Pointing Backhand Index","b":"1F449","j":["fingers","hand","direction","right"],"k":[13,14],"o":2},"desert":{"a":"Desert","b":"1F3DC-FE0F","c":"1F3DC","j":["photo","warm","saharah"],"k":[10,47],"o":2},"kimono":{"a":"Kimono","b":"1F458","j":["dress","fashion","women","female","japanese"],"k":[14,12],"o":2},"flag-al":{"a":"Albania Flag","b":"1F1E6-1F1F1","k":[0,37],"o":2},"wind_chime":{"a":"Wind Chime","b":"1F390","j":["nature","ding","spring","bell"],"k":[7,52],"o":2},"smiling_face_with_3_hearts":{"a":"Smiling Face with Smiling Eyes and Three Hearts","b":"1F970","k":[42,6],"o":11},"cat2":{"a":"Cat","b":"1F408","j":["animal","meow","pet","cats"],"k":[11,36],"o":2},"rice_scene":{"a":"Moon Viewing Ceremony","b":"1F391","j":["photo","japan","asia","tsukimi"],"k":[7,53],"o":2},"heart_eyes":{"a":"Smiling Face with Heart-Shaped Eyes","b":"1F60D","j":["face","love","like","affection","valentines","infatuation","crush","heart"],"k":[30,48],"o":2},"sari":{"a":"Sari","b":"1F97B","k":[42,13],"o":12},"flag-am":{"a":"Armenia Flag","b":"1F1E6-1F1F2","k":[0,38],"o":2},"lion_face":{"a":"Lion Face","b":"1F981","k":[42,19],"o":2},"desert_island":{"a":"Desert Island","b":"1F3DD-FE0F","c":"1F3DD","j":["photo","tropical","mojito"],"k":[10,48],"o":2},"point_up_2":{"skin_variations":{"1F3FB":{"unified":"1F446-1F3FB","non_qualified":null,"image":"1f446-1f3fb.png","sheet_x":12,"sheet_y":54,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F446-1F3FC","non_qualified":null,"image":"1f446-1f3fc.png","sheet_x":12,"sheet_y":55,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F446-1F3FD","non_qualified":null,"image":"1f446-1f3fd.png","sheet_x":12,"sheet_y":56,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F446-1F3FE","non_qualified":null,"image":"1f446-1f3fe.png","sheet_x":13,"sheet_y":0,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F446-1F3FF","non_qualified":null,"image":"1f446-1f3ff.png","sheet_x":13,"sheet_y":1,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"White Up Pointing Backhand Index","b":"1F446","j":["fingers","hand","direction","up"],"k":[12,53],"o":2},"kiwifruit":{"a":"Kiwifruit","b":"1F95D","k":[41,44],"o":4},"children_crossing":{"a":"Children Crossing","b":"1F6B8","j":["school","warning","danger","sign","driving","yellow-diamond"],"k":[36,9],"o":2},"national_park":{"a":"National Park","b":"1F3DE-FE0F","c":"1F3DE","j":["photo","environment","nature"],"k":[10,49],"o":2},"no_entry":{"a":"No Entry","b":"26D4","j":["limit","security","privacy","bad","denied","stop","circle"],"k":[54,8],"o":2},"one-piece_swimsuit":{"a":"One-Piece Swimsuit","b":"1FA71","k":[51,52],"o":12},"tiger":{"a":"Tiger Face","b":"1F42F","j":["animal","cat","danger","wild","nature","roar"],"k":[12,19],"o":2},"red_envelope":{"a":"Red Gift Envelope","b":"1F9E7","k":[51,26],"o":11},"star-struck":{"a":"Grinning Face with Star Eyes","b":"1F929","k":[38,43],"n":["grinning_face_with_star_eyes"],"o":5},"middle_finger":{"skin_variations":{"1F3FB":{"unified":"1F595-1F3FB","non_qualified":null,"image":"1f595-1f3fb.png","sheet_x":29,"sheet_y":55,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F595-1F3FC","non_qualified":null,"image":"1f595-1f3fc.png","sheet_x":29,"sheet_y":56,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F595-1F3FD","non_qualified":null,"image":"1f595-1f3fd.png","sheet_x":30,"sheet_y":0,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F595-1F3FE","non_qualified":null,"image":"1f595-1f3fe.png","sheet_x":30,"sheet_y":1,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F595-1F3FF","non_qualified":null,"image":"1f595-1f3ff.png","sheet_x":30,"sheet_y":2,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Reversed Hand with Middle Finger Extended","b":"1F595","k":[29,54],"n":["reversed_hand_with_middle_finger_extended"],"o":2},"flag-ao":{"a":"Angola Flag","b":"1F1E6-1F1F4","k":[0,39],"o":2},"tomato":{"a":"Tomato","b":"1F345","j":["fruit","vegetable","nature","food"],"k":[6,29],"o":2},"coconut":{"a":"Coconut","b":"1F965","k":[41,52],"o":5},"ribbon":{"a":"Ribbon","b":"1F380","j":["decoration","pink","girl","bowtie"],"k":[7,31],"o":2},"no_entry_sign":{"a":"No Entry Sign","b":"1F6AB","j":["forbid","stop","limit","denied","disallow","circle"],"k":[35,2],"o":2},"point_down":{"skin_variations":{"1F3FB":{"unified":"1F447-1F3FB","non_qualified":null,"image":"1f447-1f3fb.png","sheet_x":13,"sheet_y":3,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F447-1F3FC","non_qualified":null,"image":"1f447-1f3fc.png","sheet_x":13,"sheet_y":4,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F447-1F3FD","non_qualified":null,"image":"1f447-1f3fd.png","sheet_x":13,"sheet_y":5,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F447-1F3FE","non_qualified":null,"image":"1f447-1f3fe.png","sheet_x":13,"sheet_y":6,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F447-1F3FF","non_qualified":null,"image":"1f447-1f3ff.png","sheet_x":13,"sheet_y":7,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"White Down Pointing Backhand Index","b":"1F447","j":["fingers","hand","direction","down"],"k":[13,2],"o":2},"flag-aq":{"a":"Antarctica Flag","b":"1F1E6-1F1F6","k":[0,40],"o":2},"briefs":{"a":"Briefs","b":"1FA72","k":[51,53],"o":12},"kissing_heart":{"a":"Face Throwing a Kiss","b":"1F618","j":["face","love","like","affection","valentines","infatuation","kiss"],"k":[31,2],"l":[":*",":-*"],"o":2},"tiger2":{"a":"Tiger","b":"1F405","j":["animal","nature","roar"],"k":[11,33],"o":2},"stadium":{"a":"Stadium","b":"1F3DF-FE0F","c":"1F3DF","j":["photo","place","sports","concert","venue"],"k":[10,50],"o":2},"leopard":{"a":"Leopard","b":"1F406","j":["animal","nature"],"k":[11,34],"o":2},"no_bicycles":{"a":"No Bicycles","b":"1F6B3","j":["cyclist","prohibited","circle"],"k":[35,10],"o":2},"kissing":{"a":"Kissing Face","b":"1F617","j":["love","like","face","3","valentines","infatuation","kiss"],"k":[31,1],"o":2},"flag-ar":{"a":"Argentina Flag","b":"1F1E6-1F1F7","k":[0,41],"o":2},"avocado":{"a":"Avocado","b":"1F951","j":["fruit","food"],"k":[41,32],"o":4},"point_up":{"skin_variations":{"1F3FB":{"unified":"261D-1F3FB","non_qualified":null,"image":"261d-1f3fb.png","sheet_x":53,"sheet_y":3,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"261D-1F3FC","non_qualified":null,"image":"261d-1f3fc.png","sheet_x":53,"sheet_y":4,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"261D-1F3FD","non_qualified":null,"image":"261d-1f3fd.png","sheet_x":53,"sheet_y":5,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"261D-1F3FE","non_qualified":null,"image":"261d-1f3fe.png","sheet_x":53,"sheet_y":6,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"261D-1F3FF","non_qualified":null,"image":"261d-1f3ff.png","sheet_x":53,"sheet_y":7,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"White Up Pointing Index","b":"261D-FE0F","c":"261D","j":["hand","fingers","direction","up"],"k":[53,2],"o":2},"gift":{"a":"Wrapped Present","b":"1F381","j":["present","birthday","christmas","xmas"],"k":[7,32],"o":2},"classical_building":{"a":"Classical Building","b":"1F3DB-FE0F","c":"1F3DB","j":["art","culture","history"],"k":[10,46],"o":2},"shorts":{"a":"Shorts","b":"1FA73","k":[51,54],"o":12},"+1":{"skin_variations":{"1F3FB":{"unified":"1F44D-1F3FB","non_qualified":null,"image":"1f44d-1f3fb.png","sheet_x":13,"sheet_y":39,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F44D-1F3FC","non_qualified":null,"image":"1f44d-1f3fc.png","sheet_x":13,"sheet_y":40,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F44D-1F3FD","non_qualified":null,"image":"1f44d-1f3fd.png","sheet_x":13,"sheet_y":41,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F44D-1F3FE","non_qualified":null,"image":"1f44d-1f3fe.png","sheet_x":13,"sheet_y":42,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F44D-1F3FF","non_qualified":null,"image":"1f44d-1f3ff.png","sheet_x":13,"sheet_y":43,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Thumbs Up Sign","b":"1F44D","j":["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],"k":[13,38],"n":["thumbsup"],"o":2},"horse":{"a":"Horse Face","b":"1F434","j":["animal","brown","nature"],"k":[12,24],"o":2},"bikini":{"a":"Bikini","b":"1F459","j":["swimming","female","woman","girl","fashion","beach","summer"],"k":[14,13],"o":2},"no_smoking":{"a":"No Smoking Symbol","b":"1F6AD","j":["cigarette","blue-square","smell","smoke"],"k":[35,4],"o":2},"eggplant":{"a":"Aubergine","b":"1F346","j":["vegetable","nature","food","aubergine"],"k":[6,30],"o":2},"flag-as":{"a":"American Samoa Flag","b":"1F1E6-1F1F8","k":[0,42],"o":2},"reminder_ribbon":{"a":"Reminder Ribbon","b":"1F397-FE0F","c":"1F397","j":["sports","cause","support","awareness"],"k":[8,0],"o":2},"building_construction":{"a":"Building Construction","b":"1F3D7-FE0F","c":"1F3D7","j":["wip","working","progress"],"k":[10,42],"o":2},"relaxed":{"a":"White Smiling Face","b":"263A-FE0F","c":"263A","j":["face","blush","massage","happiness"],"k":[53,17],"o":2},"kissing_closed_eyes":{"a":"Kissing Face with Closed Eyes","b":"1F61A","j":["face","love","like","affection","valentines","infatuation","kiss"],"k":[31,4],"o":2},"-1":{"skin_variations":{"1F3FB":{"unified":"1F44E-1F3FB","non_qualified":null,"image":"1f44e-1f3fb.png","sheet_x":13,"sheet_y":45,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F44E-1F3FC","non_qualified":null,"image":"1f44e-1f3fc.png","sheet_x":13,"sheet_y":46,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F44E-1F3FD","non_qualified":null,"image":"1f44e-1f3fd.png","sheet_x":13,"sheet_y":47,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F44E-1F3FE","non_qualified":null,"image":"1f44e-1f3fe.png","sheet_x":13,"sheet_y":48,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F44E-1F3FF","non_qualified":null,"image":"1f44e-1f3ff.png","sheet_x":13,"sheet_y":49,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Thumbs Down Sign","b":"1F44E","j":["thumbsdown","no","dislike","hand"],"k":[13,44],"n":["thumbsdown"],"o":2},"admission_tickets":{"a":"Admission Tickets","b":"1F39F-FE0F","c":"1F39F","k":[8,5],"o":2},"flag-at":{"a":"Austria Flag","b":"1F1E6-1F1F9","k":[0,43],"o":2},"womans_clothes":{"a":"Womans Clothes","b":"1F45A","j":["fashion","shopping_bags","female"],"k":[14,14],"o":2},"do_not_litter":{"a":"Do Not Litter Symbol","b":"1F6AF","j":["trash","bin","garbage","circle"],"k":[35,6],"o":2},"potato":{"a":"Potato","b":"1F954","j":["food","tuber","vegatable","starch"],"k":[41,35],"o":4},"racehorse":{"a":"Horse","b":"1F40E","j":["animal","gamble","luck"],"k":[11,42],"o":2},"bricks":{"a":"Brick","b":"1F9F1","k":[51,36],"o":11},"fist":{"skin_variations":{"1F3FB":{"unified":"270A-1F3FB","non_qualified":null,"image":"270a-1f3fb.png","sheet_x":54,"sheet_y":44,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"270A-1F3FC","non_qualified":null,"image":"270a-1f3fc.png","sheet_x":54,"sheet_y":45,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"270A-1F3FD","non_qualified":null,"image":"270a-1f3fd.png","sheet_x":54,"sheet_y":46,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"270A-1F3FE","non_qualified":null,"image":"270a-1f3fe.png","sheet_x":54,"sheet_y":47,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"270A-1F3FF","non_qualified":null,"image":"270a-1f3ff.png","sheet_x":54,"sheet_y":48,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Raised Fist","b":"270A","j":["fingers","hand","grasp"],"k":[54,43],"o":2},"house_buildings":{"a":"House Buildings","b":"1F3D8-FE0F","c":"1F3D8","k":[10,43],"o":2},"carrot":{"a":"Carrot","b":"1F955","j":["vegetable","food","orange"],"k":[41,36],"o":4},"ticket":{"a":"Ticket","b":"1F3AB","j":["event","concert","pass"],"k":[8,17],"o":2},"flag-au":{"a":"Australia Flag","b":"1F1E6-1F1FA","k":[0,44],"o":2},"non-potable_water":{"a":"Non-Potable Water Symbol","b":"1F6B1","j":["drink","faucet","tap","circle"],"k":[35,8],"o":2},"purse":{"a":"Purse","b":"1F45B","j":["fashion","accessories","money","sales","shopping"],"k":[14,15],"o":2},"unicorn_face":{"a":"Unicorn Face","b":"1F984","k":[42,22],"o":2},"kissing_smiling_eyes":{"a":"Kissing Face with Smiling Eyes","b":"1F619","j":["face","affection","valentines","infatuation","kiss"],"k":[31,3],"o":2},"facepunch":{"skin_variations":{"1F3FB":{"unified":"1F44A-1F3FB","non_qualified":null,"image":"1f44a-1f3fb.png","sheet_x":13,"sheet_y":21,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F44A-1F3FC","non_qualified":null,"image":"1f44a-1f3fc.png","sheet_x":13,"sheet_y":22,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F44A-1F3FD","non_qualified":null,"image":"1f44a-1f3fd.png","sheet_x":13,"sheet_y":23,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F44A-1F3FE","non_qualified":null,"image":"1f44a-1f3fe.png","sheet_x":13,"sheet_y":24,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F44A-1F3FF","non_qualified":null,"image":"1f44a-1f3ff.png","sheet_x":13,"sheet_y":25,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Fisted Hand Sign","b":"1F44A","j":["angry","violence","fist","hit","attack","hand"],"k":[13,20],"n":["punch"],"o":2},"medal":{"a":"Medal","b":"1F396-FE0F","c":"1F396","k":[7,56],"o":2},"zebra_face":{"a":"Zebra Face","b":"1F993","k":[42,37],"o":5},"handbag":{"a":"Handbag","b":"1F45C","j":["fashion","accessory","accessories","shopping"],"k":[14,16],"o":2},"derelict_house_building":{"a":"Derelict House Building","b":"1F3DA-FE0F","c":"1F3DA","k":[10,45],"o":2},"yum":{"a":"Face Savouring Delicious Food","b":"1F60B","j":["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],"k":[30,46],"o":2},"corn":{"a":"Ear of Maize","b":"1F33D","j":["food","vegetable","plant"],"k":[6,21],"o":2},"flag-aw":{"a":"Aruba Flag","b":"1F1E6-1F1FC","k":[0,45],"o":2},"no_pedestrians":{"a":"No Pedestrians","b":"1F6B7","j":["rules","crossing","walking","circle"],"k":[36,8],"o":2},"house":{"a":"House Building","b":"1F3E0","j":["building","home"],"k":[10,51],"o":2},"hot_pepper":{"a":"Hot Pepper","b":"1F336-FE0F","c":"1F336","j":["food","spicy","chilli","chili"],"k":[6,14],"o":2},"flag-ax":{"a":"Åland Islands Flag","b":"1F1E6-1F1FD","k":[0,46],"o":2},"trophy":{"a":"Trophy","b":"1F3C6","j":["win","award","contest","place","ftw","ceremony"],"k":[9,26],"o":2},"deer":{"a":"Deer","b":"1F98C","j":["animal","nature","horns","venison"],"k":[42,30],"o":4},"left-facing_fist":{"skin_variations":{"1F3FB":{"unified":"1F91B-1F3FB","non_qualified":null,"image":"1f91b-1f3fb.png","sheet_x":37,"sheet_y":50,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F91B-1F3FC","non_qualified":null,"image":"1f91b-1f3fc.png","sheet_x":37,"sheet_y":51,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F91B-1F3FD","non_qualified":null,"image":"1f91b-1f3fd.png","sheet_x":37,"sheet_y":52,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F91B-1F3FE","non_qualified":null,"image":"1f91b-1f3fe.png","sheet_x":37,"sheet_y":53,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F91B-1F3FF","non_qualified":null,"image":"1f91b-1f3ff.png","sheet_x":37,"sheet_y":54,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Left-Facing Fist","b":"1F91B","k":[37,49],"o":4},"stuck_out_tongue":{"a":"Face with Stuck-out Tongue","b":"1F61B","j":["face","prank","childish","playful","mischievous","smile","tongue"],"k":[31,5],"l":[":p",":-p",":P",":-P",":b",":-b"],"m":":p","o":2},"pouch":{"a":"Pouch","b":"1F45D","j":["bag","accessories","shopping"],"k":[14,17],"o":2},"no_mobile_phones":{"a":"No Mobile Phones","b":"1F4F5","j":["iphone","mute","circle"],"k":[27,18],"o":2},"stuck_out_tongue_winking_eye":{"a":"Face with Stuck-out Tongue and Winking Eye","b":"1F61C","j":["face","prank","childish","playful","mischievous","smile","wink","tongue"],"k":[31,6],"l":[";p",";-p",";b",";-b",";P",";-P"],"m":";p","o":2},"sports_medal":{"a":"Sports Medal","b":"1F3C5","k":[9,25],"o":2},"cucumber":{"a":"Cucumber","b":"1F952","j":["fruit","food","pickle"],"k":[41,33],"o":4},"cow":{"a":"Cow Face","b":"1F42E","j":["beef","ox","animal","nature","moo","milk"],"k":[12,18],"o":2},"underage":{"a":"No One Under Eighteen Symbol","b":"1F51E","j":["18","drink","pub","night","minor","circle"],"k":[28,1],"o":2},"flag-az":{"a":"Azerbaijan Flag","b":"1F1E6-1F1FF","k":[0,47],"o":2},"shopping_bags":{"a":"Shopping Bags","b":"1F6CD-FE0F","c":"1F6CD","k":[36,35],"o":2},"right-facing_fist":{"skin_variations":{"1F3FB":{"unified":"1F91C-1F3FB","non_qualified":null,"image":"1f91c-1f3fb.png","sheet_x":37,"sheet_y":56,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F91C-1F3FC","non_qualified":null,"image":"1f91c-1f3fc.png","sheet_x":38,"sheet_y":0,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F91C-1F3FD","non_qualified":null,"image":"1f91c-1f3fd.png","sheet_x":38,"sheet_y":1,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F91C-1F3FE","non_qualified":null,"image":"1f91c-1f3fe.png","sheet_x":38,"sheet_y":2,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F91C-1F3FF","non_qualified":null,"image":"1f91c-1f3ff.png","sheet_x":38,"sheet_y":3,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Right-Facing Fist","b":"1F91C","k":[37,55],"o":4},"house_with_garden":{"a":"House with Garden","b":"1F3E1","j":["home","plant","nature"],"k":[10,52],"o":2},"clap":{"skin_variations":{"1F3FB":{"unified":"1F44F-1F3FB","non_qualified":null,"image":"1f44f-1f3fb.png","sheet_x":13,"sheet_y":51,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F44F-1F3FC","non_qualified":null,"image":"1f44f-1f3fc.png","sheet_x":13,"sheet_y":52,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F44F-1F3FD","non_qualified":null,"image":"1f44f-1f3fd.png","sheet_x":13,"sheet_y":53,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F44F-1F3FE","non_qualified":null,"image":"1f44f-1f3fe.png","sheet_x":13,"sheet_y":54,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F44F-1F3FF","non_qualified":null,"image":"1f44f-1f3ff.png","sheet_x":13,"sheet_y":55,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Clapping Hands Sign","b":"1F44F","j":["hands","praise","applause","congrats","yay"],"k":[13,50],"o":2},"leafy_green":{"a":"Leafy Green","b":"1F96C","k":[42,2],"o":11},"office":{"a":"Office Building","b":"1F3E2","j":["building","bureau","work"],"k":[10,53],"o":2},"flag-ba":{"a":"Bosnia & Herzegovina Flag","b":"1F1E7-1F1E6","k":[0,48],"o":2},"zany_face":{"a":"Grinning Face with One Large and One Small Eye","b":"1F92A","k":[38,44],"n":["grinning_face_with_one_large_and_one_small_eye"],"o":5},"first_place_medal":{"a":"First Place Medal","b":"1F947","k":[41,22],"o":4},"ox":{"a":"Ox","b":"1F402","j":["animal","cow","beef"],"k":[11,30],"o":2},"school_satchel":{"a":"School Satchel","b":"1F392","j":["student","education","bag","backpack"],"k":[7,54],"o":2},"radioactive_sign":{"a":"Radioactive Sign","b":"2622-FE0F","c":"2622","k":[53,9],"o":2},"second_place_medal":{"a":"Second Place Medal","b":"1F948","k":[41,23],"o":4},"stuck_out_tongue_closed_eyes":{"a":"Face with Stuck-out Tongue and Tightly-Closed Eyes","b":"1F61D","j":["face","prank","playful","mischievous","smile","tongue"],"k":[31,7],"o":2},"broccoli":{"a":"Broccoli","b":"1F966","k":[41,53],"o":5},"biohazard_sign":{"a":"Biohazard Sign","b":"2623-FE0F","c":"2623","k":[53,10],"o":2},"mans_shoe":{"a":"Mans Shoe","b":"1F45E","j":["fashion","male"],"k":[14,18],"n":["shoe"],"o":2},"raised_hands":{"skin_variations":{"1F3FB":{"unified":"1F64C-1F3FB","non_qualified":null,"image":"1f64c-1f3fb.png","sheet_x":33,"sheet_y":9,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F64C-1F3FC","non_qualified":null,"image":"1f64c-1f3fc.png","sheet_x":33,"sheet_y":10,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F64C-1F3FD","non_qualified":null,"image":"1f64c-1f3fd.png","sheet_x":33,"sheet_y":11,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F64C-1F3FE","non_qualified":null,"image":"1f64c-1f3fe.png","sheet_x":33,"sheet_y":12,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F64C-1F3FF","non_qualified":null,"image":"1f64c-1f3ff.png","sheet_x":33,"sheet_y":13,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Person Raising Both Hands in Celebration","b":"1F64C","j":["gesture","hooray","yea","celebration","hands"],"k":[33,8],"o":2},"post_office":{"a":"Japanese Post Office","b":"1F3E3","j":["building","envelope","communication"],"k":[10,54],"o":2},"flag-bb":{"a":"Barbados Flag","b":"1F1E7-1F1E7","k":[0,49],"o":2},"water_buffalo":{"a":"Water Buffalo","b":"1F403","j":["animal","nature","ox","cow"],"k":[11,31],"o":2},"third_place_medal":{"a":"Third Place Medal","b":"1F949","k":[41,24],"o":4},"european_post_office":{"a":"European Post Office","b":"1F3E4","j":["building","email"],"k":[10,55],"o":2},"athletic_shoe":{"a":"Athletic Shoe","b":"1F45F","j":["shoes","sports","sneakers"],"k":[14,19],"o":2},"arrow_up":{"a":"Upwards Black Arrow","b":"2B06-FE0F","c":"2B06","j":["blue-square","continue","top","direction"],"k":[55,38],"o":2},"cow2":{"a":"Cow","b":"1F404","j":["beef","ox","animal","nature","moo","milk"],"k":[11,32],"o":2},"open_hands":{"skin_variations":{"1F3FB":{"unified":"1F450-1F3FB","non_qualified":null,"image":"1f450-1f3fb.png","sheet_x":14,"sheet_y":0,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F450-1F3FC","non_qualified":null,"image":"1f450-1f3fc.png","sheet_x":14,"sheet_y":1,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F450-1F3FD","non_qualified":null,"image":"1f450-1f3fd.png","sheet_x":14,"sheet_y":2,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F450-1F3FE","non_qualified":null,"image":"1f450-1f3fe.png","sheet_x":14,"sheet_y":3,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F450-1F3FF","non_qualified":null,"image":"1f450-1f3ff.png","sheet_x":14,"sheet_y":4,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Open Hands Sign","b":"1F450","j":["fingers","butterfly","hands","open"],"k":[13,56],"o":2},"garlic":{"a":"Garlic","b":"1F9C4","k":[44,12],"o":12},"money_mouth_face":{"a":"Money-Mouth Face","b":"1F911","j":["face","rich","dollar","money"],"k":[37,24],"o":2},"flag-bd":{"a":"Bangladesh Flag","b":"1F1E7-1F1E9","k":[0,50],"o":2},"soccer":{"a":"Soccer Ball","b":"26BD","j":["sports","football"],"k":[53,56],"o":2},"hugging_face":{"a":"Hugging Face","b":"1F917","k":[37,30],"o":2},"onion":{"a":"Onion","b":"1F9C5","k":[44,13],"o":12},"arrow_upper_right":{"a":"North East Arrow","b":"2197-FE0F","c":"2197","j":["blue-square","point","direction","diagonal","northeast"],"k":[52,17],"o":2},"palms_up_together":{"skin_variations":{"1F3FB":{"unified":"1F932-1F3FB","non_qualified":null,"image":"1f932-1f3fb.png","sheet_x":39,"sheet_y":6,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F932-1F3FC","non_qualified":null,"image":"1f932-1f3fc.png","sheet_x":39,"sheet_y":7,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F932-1F3FD","non_qualified":null,"image":"1f932-1f3fd.png","sheet_x":39,"sheet_y":8,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F932-1F3FE","non_qualified":null,"image":"1f932-1f3fe.png","sheet_x":39,"sheet_y":9,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F932-1F3FF","non_qualified":null,"image":"1f932-1f3ff.png","sheet_x":39,"sheet_y":10,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Palms Up Together","b":"1F932","k":[39,5],"o":5},"pig":{"a":"Pig Face","b":"1F437","j":["animal","oink","nature"],"k":[12,27],"o":2},"hospital":{"a":"Hospital","b":"1F3E5","j":["building","health","surgery","doctor"],"k":[10,56],"o":2},"hiking_boot":{"a":"Hiking Boot","b":"1F97E","k":[42,16],"o":11},"flag-be":{"a":"Belgium Flag","b":"1F1E7-1F1EA","k":[0,51],"o":2},"flag-bf":{"a":"Burkina Faso Flag","b":"1F1E7-1F1EB","k":[0,52],"o":2},"mushroom":{"a":"Mushroom","b":"1F344","j":["plant","vegetable"],"k":[6,28],"o":2},"pig2":{"a":"Pig","b":"1F416","j":["animal","nature"],"k":[11,51],"o":2},"baseball":{"a":"Baseball","b":"26BE","j":["sports","balls"],"k":[54,0],"o":2},"face_with_hand_over_mouth":{"a":"Smiling Face with Smiling Eyes and Hand Covering Mouth","b":"1F92D","k":[38,47],"n":["smiling_face_with_smiling_eyes_and_hand_covering_mouth"],"o":5},"handshake":{"a":"Handshake","b":"1F91D","j":["agreement","shake"],"k":[38,4],"o":4},"womans_flat_shoe":{"a":"Flat Shoe","b":"1F97F","k":[42,17],"o":11},"bank":{"a":"Bank","b":"1F3E6","j":["building","money","sales","cash","business","enterprise"],"k":[11,0],"o":2},"arrow_right":{"a":"Black Rightwards Arrow","b":"27A1-FE0F","c":"27A1","j":["blue-square","next"],"k":[55,32],"o":2},"peanuts":{"a":"Peanuts","b":"1F95C","j":["food","nut"],"k":[41,43],"o":4},"shushing_face":{"a":"Face with Finger Covering Closed Lips","b":"1F92B","k":[38,45],"n":["face_with_finger_covering_closed_lips"],"o":5},"pray":{"skin_variations":{"1F3FB":{"unified":"1F64F-1F3FB","non_qualified":null,"image":"1f64f-1f3fb.png","sheet_x":33,"sheet_y":51,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F64F-1F3FC","non_qualified":null,"image":"1f64f-1f3fc.png","sheet_x":33,"sheet_y":52,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F64F-1F3FD","non_qualified":null,"image":"1f64f-1f3fd.png","sheet_x":33,"sheet_y":53,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F64F-1F3FE","non_qualified":null,"image":"1f64f-1f3fe.png","sheet_x":33,"sheet_y":54,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F64F-1F3FF","non_qualified":null,"image":"1f64f-1f3ff.png","sheet_x":33,"sheet_y":55,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Person with Folded Hands","b":"1F64F","j":["please","hope","wish","namaste","highfive"],"k":[33,50],"o":2},"softball":{"a":"Softball","b":"1F94E","k":[41,29],"o":11},"high_heel":{"a":"High-Heeled Shoe","b":"1F460","j":["fashion","shoes","female","pumps","stiletto"],"k":[14,20],"o":2},"flag-bg":{"a":"Bulgaria Flag","b":"1F1E7-1F1EC","k":[0,53],"o":2},"arrow_lower_right":{"a":"South East Arrow","b":"2198-FE0F","c":"2198","j":["blue-square","direction","diagonal","southeast"],"k":[52,18],"o":2},"hotel":{"a":"Hotel","b":"1F3E8","j":["building","accomodation","checkin"],"k":[11,2],"o":2},"boar":{"a":"Boar","b":"1F417","j":["animal","nature"],"k":[11,52],"o":2},"sandal":{"a":"Womans Sandal","b":"1F461","j":["shoes","fashion","flip flops"],"k":[14,21],"o":2},"flag-bh":{"a":"Bahrain Flag","b":"1F1E7-1F1ED","k":[0,54],"o":2},"arrow_down":{"a":"Downwards Black Arrow","b":"2B07-FE0F","c":"2B07","j":["blue-square","direction","bottom"],"k":[55,39],"o":2},"thinking_face":{"a":"Thinking Face","b":"1F914","k":[37,27],"o":2},"writing_hand":{"skin_variations":{"1F3FB":{"unified":"270D-1F3FB","non_qualified":null,"image":"270d-1f3fb.png","sheet_x":55,"sheet_y":5,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"270D-1F3FC","non_qualified":null,"image":"270d-1f3fc.png","sheet_x":55,"sheet_y":6,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"270D-1F3FD","non_qualified":null,"image":"270d-1f3fd.png","sheet_x":55,"sheet_y":7,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"270D-1F3FE","non_qualified":null,"image":"270d-1f3fe.png","sheet_x":55,"sheet_y":8,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"270D-1F3FF","non_qualified":null,"image":"270d-1f3ff.png","sheet_x":55,"sheet_y":9,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Writing Hand","b":"270D-FE0F","c":"270D","j":["lower_left_ballpoint_pen","stationery","write","compose"],"k":[55,4],"o":2},"chestnut":{"a":"Chestnut","b":"1F330","j":["food","squirrel"],"k":[6,8],"o":2},"basketball":{"a":"Basketball and Hoop","b":"1F3C0","j":["sports","balls","NBA"],"k":[8,38],"o":2},"pig_nose":{"a":"Pig Nose","b":"1F43D","j":["animal","oink"],"k":[12,33],"o":2},"love_hotel":{"a":"Love Hotel","b":"1F3E9","j":["like","affection","dating"],"k":[11,3],"o":2},"nail_care":{"skin_variations":{"1F3FB":{"unified":"1F485-1F3FB","non_qualified":null,"image":"1f485-1f3fb.png","sheet_x":24,"sheet_y":34,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F485-1F3FC","non_qualified":null,"image":"1f485-1f3fc.png","sheet_x":24,"sheet_y":35,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F485-1F3FD","non_qualified":null,"image":"1f485-1f3fd.png","sheet_x":24,"sheet_y":36,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F485-1F3FE","non_qualified":null,"image":"1f485-1f3fe.png","sheet_x":24,"sheet_y":37,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F485-1F3FF","non_qualified":null,"image":"1f485-1f3ff.png","sheet_x":24,"sheet_y":38,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Nail Polish","b":"1F485","j":["beauty","manicure","finger","fashion","nail"],"k":[24,33],"o":2},"volleyball":{"a":"Volleyball","b":"1F3D0","j":["sports","balls"],"k":[10,35],"o":2},"flag-bi":{"a":"Burundi Flag","b":"1F1E7-1F1EE","k":[0,55],"o":2},"arrow_lower_left":{"a":"South West Arrow","b":"2199-FE0F","c":"2199","j":["blue-square","direction","diagonal","southwest"],"k":[52,19],"o":2},"ram":{"a":"Ram","b":"1F40F","j":["animal","sheep","nature"],"k":[11,43],"o":2},"ballet_shoes":{"a":"Ballet Shoes","b":"1FA70","k":[51,51],"o":12},"zipper_mouth_face":{"a":"Zipper-Mouth Face","b":"1F910","j":["face","sealed","zipper","secret"],"k":[37,23],"o":2},"bread":{"a":"Bread","b":"1F35E","j":["food","wheat","breakfast","toast"],"k":[6,54],"o":2},"convenience_store":{"a":"Convenience Store","b":"1F3EA","j":["building","shopping","groceries"],"k":[11,4],"o":2},"boot":{"a":"Womans Boots","b":"1F462","j":["shoes","fashion"],"k":[14,22],"o":2},"sheep":{"a":"Sheep","b":"1F411","j":["animal","nature","wool","shipit"],"k":[11,45],"o":2},"face_with_raised_eyebrow":{"a":"Face with One Eyebrow Raised","b":"1F928","k":[38,42],"n":["face_with_one_eyebrow_raised"],"o":5},"flag-bj":{"a":"Benin Flag","b":"1F1E7-1F1EF","k":[0,56],"o":2},"arrow_left":{"a":"Leftwards Black Arrow","b":"2B05-FE0F","c":"2B05","j":["blue-square","previous","back"],"k":[55,37],"o":2},"selfie":{"skin_variations":{"1F3FB":{"unified":"1F933-1F3FB","non_qualified":null,"image":"1f933-1f3fb.png","sheet_x":39,"sheet_y":12,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F933-1F3FC","non_qualified":null,"image":"1f933-1f3fc.png","sheet_x":39,"sheet_y":13,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F933-1F3FD","non_qualified":null,"image":"1f933-1f3fd.png","sheet_x":39,"sheet_y":14,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F933-1F3FE","non_qualified":null,"image":"1f933-1f3fe.png","sheet_x":39,"sheet_y":15,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F933-1F3FF","non_qualified":null,"image":"1f933-1f3ff.png","sheet_x":39,"sheet_y":16,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Selfie","b":"1F933","j":["camera","phone"],"k":[39,11],"o":4},"croissant":{"a":"Croissant","b":"1F950","j":["food","bread","french"],"k":[41,31],"o":4},"school":{"a":"School","b":"1F3EB","j":["building","student","education","learn","teach"],"k":[11,5],"o":2},"football":{"a":"American Football","b":"1F3C8","j":["sports","balls","NFL"],"k":[9,33],"o":2},"goat":{"a":"Goat","b":"1F410","j":["animal","nature"],"k":[11,44],"o":2},"department_store":{"a":"Department Store","b":"1F3EC","j":["building","shopping","mall"],"k":[11,6],"o":2},"flag-bl":{"a":"St. Barthélemy Flag","b":"1F1E7-1F1F1","k":[1,0],"o":2},"crown":{"a":"Crown","b":"1F451","j":["king","kod","leader","royalty","lord"],"k":[14,5],"o":2},"arrow_upper_left":{"a":"North West Arrow","b":"2196-FE0F","c":"2196","j":["blue-square","point","direction","diagonal","northwest"],"k":[52,16],"o":2},"neutral_face":{"a":"Neutral Face","b":"1F610","j":["indifference","meh",":|","neutral"],"k":[30,51],"l":[":|",":-|"],"o":2},"rugby_football":{"a":"Rugby Football","b":"1F3C9","j":["sports","team"],"k":[9,34],"o":2},"muscle":{"skin_variations":{"1F3FB":{"unified":"1F4AA-1F3FB","non_qualified":null,"image":"1f4aa-1f3fb.png","sheet_x":25,"sheet_y":53,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F4AA-1F3FC","non_qualified":null,"image":"1f4aa-1f3fc.png","sheet_x":25,"sheet_y":54,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F4AA-1F3FD","non_qualified":null,"image":"1f4aa-1f3fd.png","sheet_x":25,"sheet_y":55,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F4AA-1F3FE","non_qualified":null,"image":"1f4aa-1f3fe.png","sheet_x":25,"sheet_y":56,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F4AA-1F3FF","non_qualified":null,"image":"1f4aa-1f3ff.png","sheet_x":26,"sheet_y":0,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Flexed Biceps","b":"1F4AA","j":["arm","flex","hand","summer","strong","biceps"],"k":[25,52],"o":2},"baguette_bread":{"a":"Baguette Bread","b":"1F956","j":["food","bread","french"],"k":[41,37],"o":4},"expressionless":{"a":"Expressionless Face","b":"1F611","j":["face","indifferent","-_-","meh","deadpan"],"k":[30,52],"o":2},"womans_hat":{"a":"Womans Hat","b":"1F452","j":["fashion","accessories","female","lady","spring"],"k":[14,6],"o":2},"pretzel":{"a":"Pretzel","b":"1F968","k":[41,55],"o":5},"mechanical_arm":{"a":"Mechanical Arm","b":"1F9BE","k":[44,6],"o":12},"arrow_up_down":{"a":"Up Down Arrow","b":"2195-FE0F","c":"2195","j":["blue-square","direction","way","vertical"],"k":[52,15],"o":2},"dromedary_camel":{"a":"Dromedary Camel","b":"1F42A","j":["animal","hot","desert","hump"],"k":[12,14],"o":2},"tennis":{"a":"Tennis Racquet and Ball","b":"1F3BE","j":["sports","balls","green"],"k":[8,36],"o":2},"flag-bm":{"a":"Bermuda Flag","b":"1F1E7-1F1F2","k":[1,1],"o":2},"factory":{"a":"Factory","b":"1F3ED","j":["building","industry","pollution","smoke"],"k":[11,7],"o":2},"japanese_castle":{"a":"Japanese Castle","b":"1F3EF","j":["photo","building"],"k":[11,9],"o":2},"no_mouth":{"a":"Face Without Mouth","b":"1F636","j":["face","hellokitty"],"k":[31,32],"o":2},"mechanical_leg":{"a":"Mechanical Leg","b":"1F9BF","k":[44,7],"o":12},"bagel":{"a":"Bagel","b":"1F96F","k":[42,5],"o":11},"camel":{"a":"Bactrian Camel","b":"1F42B","j":["animal","nature","hot","desert","hump"],"k":[12,15],"o":2},"tophat":{"a":"Top Hat","b":"1F3A9","j":["magic","gentleman","classy","circus"],"k":[8,15],"o":2},"left_right_arrow":{"a":"Left Right Arrow","b":"2194-FE0F","c":"2194","j":["shape","direction","horizontal","sideways"],"k":[52,14],"o":2},"flag-bn":{"a":"Brunei Flag","b":"1F1E7-1F1F3","k":[1,2],"o":2},"flying_disc":{"a":"Flying Disc","b":"1F94F","k":[41,30],"o":11},"smirk":{"a":"Smirking Face","b":"1F60F","j":["face","smile","mean","prank","smug","sarcasm"],"k":[30,50],"o":2},"mortar_board":{"a":"Graduation Cap","b":"1F393","j":["school","college","degree","university","graduation","cap","hat","legal","learn","education"],"k":[7,55],"o":2},"european_castle":{"a":"European Castle","b":"1F3F0","j":["building","royalty","history"],"k":[11,10],"o":2},"leg":{"skin_variations":{"1F3FB":{"unified":"1F9B5-1F3FB","non_qualified":null,"image":"1f9b5-1f3fb.png","sheet_x":43,"sheet_y":6,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F9B5-1F3FC","non_qualified":null,"image":"1f9b5-1f3fc.png","sheet_x":43,"sheet_y":7,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F9B5-1F3FD","non_qualified":null,"image":"1f9b5-1f3fd.png","sheet_x":43,"sheet_y":8,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F9B5-1F3FE","non_qualified":null,"image":"1f9b5-1f3fe.png","sheet_x":43,"sheet_y":9,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F9B5-1F3FF","non_qualified":null,"image":"1f9b5-1f3ff.png","sheet_x":43,"sheet_y":10,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Leg","b":"1F9B5","k":[43,5],"o":11},"pancakes":{"a":"Pancakes","b":"1F95E","j":["food","breakfast","flapjacks","hotcakes"],"k":[41,45],"o":4},"leftwards_arrow_with_hook":{"a":"Leftwards Arrow with Hook","b":"21A9-FE0F","c":"21A9","j":["back","return","blue-square","undo","enter"],"k":[52,20],"o":2},"flag-bo":{"a":"Bolivia Flag","b":"1F1E7-1F1F4","k":[1,3],"o":2},"bowling":{"a":"Bowling","b":"1F3B3","j":["sports","fun","play"],"k":[8,25],"o":2},"llama":{"a":"Llama","b":"1F999","k":[42,43],"o":11},"arrow_right_hook":{"a":"Rightwards Arrow with Hook","b":"21AA-FE0F","c":"21AA","j":["blue-square","return","rotate","direction"],"k":[52,21],"o":2},"wedding":{"a":"Wedding","b":"1F492","j":["love","like","affection","couple","marriage","bride","groom"],"k":[25,28],"o":2},"flag-bq":{"a":"Caribbean Netherlands Flag","b":"1F1E7-1F1F6","k":[1,4],"o":2},"foot":{"skin_variations":{"1F3FB":{"unified":"1F9B6-1F3FB","non_qualified":null,"image":"1f9b6-1f3fb.png","sheet_x":43,"sheet_y":12,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F9B6-1F3FC","non_qualified":null,"image":"1f9b6-1f3fc.png","sheet_x":43,"sheet_y":13,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F9B6-1F3FD","non_qualified":null,"image":"1f9b6-1f3fd.png","sheet_x":43,"sheet_y":14,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F9B6-1F3FE","non_qualified":null,"image":"1f9b6-1f3fe.png","sheet_x":43,"sheet_y":15,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F9B6-1F3FF","non_qualified":null,"image":"1f9b6-1f3ff.png","sheet_x":43,"sheet_y":16,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Foot","b":"1F9B6","k":[43,11],"o":11},"giraffe_face":{"a":"Giraffe Face","b":"1F992","k":[42,36],"o":5},"unamused":{"a":"Unamused Face","b":"1F612","j":["indifference","bored","straight face","serious","sarcasm"],"k":[30,53],"m":":(","o":2},"billed_cap":{"a":"Billed Cap","b":"1F9E2","k":[51,21],"o":5},"waffle":{"a":"Waffle","b":"1F9C7","k":[44,15],"o":12},"cricket_bat_and_ball":{"a":"Cricket Bat and Ball","b":"1F3CF","k":[10,34],"o":2},"helmet_with_white_cross":{"a":"Helmet with White Cross","b":"26D1-FE0F","c":"26D1","k":[54,6],"o":2},"ear":{"skin_variations":{"1F3FB":{"unified":"1F442-1F3FB","non_qualified":null,"image":"1f442-1f3fb.png","sheet_x":12,"sheet_y":40,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F442-1F3FC","non_qualified":null,"image":"1f442-1f3fc.png","sheet_x":12,"sheet_y":41,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F442-1F3FD","non_qualified":null,"image":"1f442-1f3fd.png","sheet_x":12,"sheet_y":42,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F442-1F3FE","non_qualified":null,"image":"1f442-1f3fe.png","sheet_x":12,"sheet_y":43,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F442-1F3FF","non_qualified":null,"image":"1f442-1f3ff.png","sheet_x":12,"sheet_y":44,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Ear","b":"1F442","j":["face","hear","sound","listen"],"k":[12,39],"o":2},"elephant":{"a":"Elephant","b":"1F418","j":["animal","nature","nose","th","circus"],"k":[11,53],"o":2},"cheese_wedge":{"a":"Cheese Wedge","b":"1F9C0","k":[44,8],"o":2},"tokyo_tower":{"a":"Tokyo Tower","b":"1F5FC","j":["photo","japanese"],"k":[30,31],"o":2},"arrow_heading_up":{"a":"Arrow Pointing Rightwards Then Curving Upwards","b":"2934-FE0F","c":"2934","j":["blue-square","direction","top"],"k":[55,35],"o":2},"field_hockey_stick_and_ball":{"a":"Field Hockey Stick and Ball","b":"1F3D1","k":[10,36],"o":2},"flag-br":{"a":"Brazil Flag","b":"1F1E7-1F1F7","k":[1,5],"o":2},"face_with_rolling_eyes":{"a":"Face with Rolling Eyes","b":"1F644","k":[31,46],"o":2},"ear_with_hearing_aid":{"skin_variations":{"1F3FB":{"unified":"1F9BB-1F3FB","non_qualified":null,"image":"1f9bb-1f3fb.png","sheet_x":43,"sheet_y":56,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F9BB-1F3FC","non_qualified":null,"image":"1f9bb-1f3fc.png","sheet_x":44,"sheet_y":0,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F9BB-1F3FD","non_qualified":null,"image":"1f9bb-1f3fd.png","sheet_x":44,"sheet_y":1,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F9BB-1F3FE","non_qualified":null,"image":"1f9bb-1f3fe.png","sheet_x":44,"sheet_y":2,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F9BB-1F3FF","non_qualified":null,"image":"1f9bb-1f3ff.png","sheet_x":44,"sheet_y":3,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Ear with Hearing Aid","b":"1F9BB","k":[43,55],"o":12},"arrow_heading_down":{"a":"Arrow Pointing Rightwards Then Curving Downwards","b":"2935-FE0F","c":"2935","j":["blue-square","direction","bottom"],"k":[55,36],"o":2},"ice_hockey_stick_and_puck":{"a":"Ice Hockey Stick and Puck","b":"1F3D2","k":[10,37],"o":2},"meat_on_bone":{"a":"Meat on Bone","b":"1F356","j":["good","food","drumstick"],"k":[6,46],"o":2},"prayer_beads":{"a":"Prayer Beads","b":"1F4FF","j":["dhikr","religious"],"k":[27,27],"o":2},"statue_of_liberty":{"a":"Statue of Liberty","b":"1F5FD","j":["american","newyork"],"k":[30,32],"o":2},"grimacing":{"a":"Grimacing Face","b":"1F62C","j":["face","grimace","teeth"],"k":[31,22],"o":2},"flag-bs":{"a":"Bahamas Flag","b":"1F1E7-1F1F8","k":[1,6],"o":2},"rhinoceros":{"a":"Rhinoceros","b":"1F98F","j":["animal","nature","horn"],"k":[42,33],"o":4},"lacrosse":{"a":"Lacrosse Stick and Ball","b":"1F94D","k":[41,28],"o":11},"poultry_leg":{"a":"Poultry Leg","b":"1F357","j":["food","meat","drumstick","bird","chicken","turkey"],"k":[6,47],"o":2},"hippopotamus":{"a":"Hippopotamus","b":"1F99B","k":[42,45],"o":11},"nose":{"skin_variations":{"1F3FB":{"unified":"1F443-1F3FB","non_qualified":null,"image":"1f443-1f3fb.png","sheet_x":12,"sheet_y":46,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F443-1F3FC","non_qualified":null,"image":"1f443-1f3fc.png","sheet_x":12,"sheet_y":47,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F443-1F3FD","non_qualified":null,"image":"1f443-1f3fd.png","sheet_x":12,"sheet_y":48,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F443-1F3FE","non_qualified":null,"image":"1f443-1f3fe.png","sheet_x":12,"sheet_y":49,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F443-1F3FF","non_qualified":null,"image":"1f443-1f3ff.png","sheet_x":12,"sheet_y":50,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Nose","b":"1F443","j":["smell","sniff"],"k":[12,45],"o":2},"arrows_clockwise":{"a":"Clockwise Downwards and Upwards Open Circle Arrows","b":"1F503","j":["sync","cycle","round","repeat"],"k":[27,31],"o":2},"flag-bt":{"a":"Bhutan Flag","b":"1F1E7-1F1F9","k":[1,7],"o":2},"church":{"a":"Church","b":"26EA","j":["building","religion","christ"],"k":[54,10],"o":2},"lipstick":{"a":"Lipstick","b":"1F484","j":["female","girl","fashion","woman"],"k":[24,32],"o":2},"lying_face":{"a":"Lying Face","b":"1F925","j":["face","lie","pinocchio"],"k":[38,22],"o":4},"arrows_counterclockwise":{"a":"Anticlockwise Downwards and Upwards Open Circle Arrows","b":"1F504","j":["blue-square","sync","cycle"],"k":[27,32],"o":2},"flag-bv":{"a":"Bouvet Island Flag","b":"1F1E7-1F1FB","k":[1,8],"o":2},"cut_of_meat":{"a":"Cut of Meat","b":"1F969","k":[41,56],"o":5},"mosque":{"a":"Mosque","b":"1F54C","j":["islam","worship","minaret"],"k":[28,36],"o":2},"ring":{"a":"Ring","b":"1F48D","j":["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],"k":[25,23],"o":2},"brain":{"a":"Brain","b":"1F9E0","k":[51,19],"o":5},"table_tennis_paddle_and_ball":{"a":"Table Tennis Paddle and Ball","b":"1F3D3","k":[10,38],"o":2},"relieved":{"a":"Relieved Face","b":"1F60C","j":["face","relaxed","phew","massage","happiness"],"k":[30,47],"o":2},"mouse":{"a":"Mouse Face","b":"1F42D","j":["animal","nature","cheese_wedge","rodent"],"k":[12,17],"o":2},"hindu_temple":{"a":"Hindu Temple","b":"1F6D5","k":[36,41],"o":12},"back":{"a":"Back with Leftwards Arrow Above","b":"1F519","j":["arrow","words","return"],"k":[27,53],"o":2},"gem":{"a":"Gem Stone","b":"1F48E","j":["blue","ruby","diamond","jewelry"],"k":[25,24],"o":2},"pensive":{"a":"Pensive Face","b":"1F614","j":["face","sad","depressed","upset"],"k":[30,55],"o":2},"flag-bw":{"a":"Botswana Flag","b":"1F1E7-1F1FC","k":[1,9],"o":2},"mouse2":{"a":"Mouse","b":"1F401","j":["animal","nature","rodent"],"k":[11,29],"o":2},"bacon":{"a":"Bacon","b":"1F953","j":["food","breakfast","pork","pig","meat"],"k":[41,34],"o":4},"tooth":{"a":"Tooth","b":"1F9B7","k":[43,17],"o":11},"badminton_racquet_and_shuttlecock":{"a":"Badminton Racquet and Shuttlecock","b":"1F3F8","k":[11,20],"o":2},"rat":{"a":"Rat","b":"1F400","j":["animal","mouse","rodent"],"k":[11,28],"o":2},"synagogue":{"a":"Synagogue","b":"1F54D","j":["judaism","worship","temple","jewish"],"k":[28,37],"o":2},"end":{"a":"End with Leftwards Arrow Above","b":"1F51A","j":["words","arrow"],"k":[27,54],"o":2},"bone":{"a":"Bone","b":"1F9B4","k":[43,4],"o":11},"boxing_glove":{"a":"Boxing Glove","b":"1F94A","j":["sports","fighting"],"k":[41,25],"o":4},"mute":{"a":"Speaker with Cancellation Stroke","b":"1F507","j":["sound","volume","silence","quiet"],"k":[27,35],"o":2},"hamburger":{"a":"Hamburger","b":"1F354","j":["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],"k":[6,44],"o":2},"flag-by":{"a":"Belarus Flag","b":"1F1E7-1F1FE","k":[1,10],"o":2},"sleepy":{"a":"Sleepy Face","b":"1F62A","j":["face","tired","rest","nap"],"k":[31,20],"o":2},"on":{"a":"On with Exclamation Mark with Left Right Arrow Above","b":"1F51B","j":["arrow","words"],"k":[27,55],"o":2},"martial_arts_uniform":{"a":"Martial Arts Uniform","b":"1F94B","j":["judo","karate","taekwondo"],"k":[41,26],"o":4},"speaker":{"a":"Speaker","b":"1F508","j":["sound","volume","silence","broadcast"],"k":[27,36],"o":2},"drooling_face":{"a":"Drooling Face","b":"1F924","j":["face"],"k":[38,21],"o":4},"eyes":{"a":"Eyes","b":"1F440","j":["look","watch","stalk","peek","see"],"k":[12,36],"o":2},"flag-bz":{"a":"Belize Flag","b":"1F1E7-1F1FF","k":[1,11],"o":2},"hamster":{"a":"Hamster Face","b":"1F439","j":["animal","nature"],"k":[12,29],"o":2},"shinto_shrine":{"a":"Shinto Shrine","b":"26E9-FE0F","c":"26E9","j":["temple","japan","kyoto"],"k":[54,9],"o":2},"fries":{"a":"French Fries","b":"1F35F","j":["chips","snack","fast food"],"k":[6,55],"o":2},"goal_net":{"a":"Goal Net","b":"1F945","j":["sports"],"k":[41,21],"o":4},"kaaba":{"a":"Kaaba","b":"1F54B","j":["mecca","mosque","islam"],"k":[28,35],"o":2},"soon":{"a":"Soon with Rightwards Arrow Above","b":"1F51C","j":["arrow","words"],"k":[27,56],"o":2},"flag-ca":{"a":"Canada Flag","b":"1F1E8-1F1E6","k":[1,12],"o":2},"rabbit":{"a":"Rabbit Face","b":"1F430","j":["animal","nature","pet","spring","magic","bunny"],"k":[12,20],"o":2},"eye":{"a":"Eye","b":"1F441-FE0F","c":"1F441","j":["face","look","see","watch","stare"],"k":[12,38],"o":2},"sleeping":{"a":"Sleeping Face","b":"1F634","j":["face","tired","sleepy","night","zzz"],"k":[31,30],"o":2},"pizza":{"a":"Slice of Pizza","b":"1F355","j":["food","party"],"k":[6,45],"o":2},"sound":{"a":"Speaker with One Sound Wave","b":"1F509","j":["volume","speaker","broadcast"],"k":[27,37],"o":2},"rabbit2":{"a":"Rabbit","b":"1F407","j":["animal","nature","pet","magic","spring"],"k":[11,35],"o":2},"fountain":{"a":"Fountain","b":"26F2","j":["photo","summer","water","fresh"],"k":[54,13],"o":2},"golf":{"a":"Flag in Hole","b":"26F3","j":["sports","business","flag","hole","summer"],"k":[54,14],"o":2},"top":{"a":"Top with Upwards Arrow Above","b":"1F51D","j":["words","blue-square"],"k":[28,0],"o":2},"mask":{"a":"Face with Medical Mask","b":"1F637","j":["face","sick","ill","disease"],"k":[31,33],"o":2},"flag-cc":{"a":"Cocos (keeling) Islands Flag","b":"1F1E8-1F1E8","k":[1,13],"o":2},"hotdog":{"a":"Hot Dog","b":"1F32D","j":["food","frankfurter"],"k":[6,5],"o":2},"loud_sound":{"a":"Speaker with Three Sound Waves","b":"1F50A","j":["volume","noise","noisy","speaker","broadcast"],"k":[27,38],"o":2},"tongue":{"a":"Tongue","b":"1F445","j":["mouth","playful"],"k":[12,52],"o":2},"place_of_worship":{"a":"Place of Worship","b":"1F6D0","j":["religion","church","temple","prayer"],"k":[36,38],"o":2},"ice_skate":{"a":"Ice Skate","b":"26F8-FE0F","c":"26F8","j":["sports"],"k":[54,18],"o":2},"sandwich":{"a":"Sandwich","b":"1F96A","k":[42,0],"o":5},"chipmunk":{"a":"Chipmunk","b":"1F43F-FE0F","c":"1F43F","j":["animal","nature","rodent","squirrel"],"k":[12,35],"o":2},"loudspeaker":{"a":"Public Address Loudspeaker","b":"1F4E2","j":["volume","sound"],"k":[26,56],"o":2},"lips":{"a":"Mouth","b":"1F444","j":["mouth","kiss"],"k":[12,51],"o":2},"flag-cd":{"a":"Congo - Kinshasa Flag","b":"1F1E8-1F1E9","k":[1,14],"o":2},"tent":{"a":"Tent","b":"26FA","j":["photo","camping","outdoors"],"k":[54,37],"o":2},"face_with_thermometer":{"a":"Face with Thermometer","b":"1F912","j":["sick","temperature","thermometer","cold","fever"],"k":[37,25],"o":2},"taco":{"a":"Taco","b":"1F32E","j":["food","mexican"],"k":[6,6],"o":2},"foggy":{"a":"Foggy","b":"1F301","j":["photo","mountain"],"k":[5,20],"o":2},"flag-cf":{"a":"Central African Republic Flag","b":"1F1E8-1F1EB","k":[1,15],"o":2},"baby":{"skin_variations":{"1F3FB":{"unified":"1F476-1F3FB","non_qualified":null,"image":"1f476-1f3fb.png","sheet_x":23,"sheet_y":5,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F476-1F3FC","non_qualified":null,"image":"1f476-1f3fc.png","sheet_x":23,"sheet_y":6,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F476-1F3FD","non_qualified":null,"image":"1f476-1f3fd.png","sheet_x":23,"sheet_y":7,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F476-1F3FE","non_qualified":null,"image":"1f476-1f3fe.png","sheet_x":23,"sheet_y":8,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F476-1F3FF","non_qualified":null,"image":"1f476-1f3ff.png","sheet_x":23,"sheet_y":9,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Baby","b":"1F476","j":["child","boy","girl","toddler"],"k":[23,4],"o":2},"atom_symbol":{"a":"Atom Symbol","b":"269B-FE0F","c":"269B","j":["science","physics","chemistry"],"k":[53,48],"o":2},"fishing_pole_and_fish":{"a":"Fishing Pole and Fish","b":"1F3A3","j":["food","hobby","summer"],"k":[8,9],"o":2},"hedgehog":{"a":"Hedgehog","b":"1F994","k":[42,38],"o":5},"face_with_head_bandage":{"a":"Face with Head-Bandage","b":"1F915","j":["injured","clumsy","bandage","hurt"],"k":[37,28],"o":2},"mega":{"a":"Cheering Megaphone","b":"1F4E3","j":["sound","speaker","volume"],"k":[27,0],"o":2},"nauseated_face":{"a":"Nauseated Face","b":"1F922","j":["face","vomit","gross","green","sick","throw up","ill"],"k":[38,19],"o":4},"child":{"skin_variations":{"1F3FB":{"unified":"1F9D2-1F3FB","non_qualified":null,"image":"1f9d2-1f3fb.png","sheet_x":48,"sheet_y":17,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F9D2-1F3FC","non_qualified":null,"image":"1f9d2-1f3fc.png","sheet_x":48,"sheet_y":18,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F9D2-1F3FD","non_qualified":null,"image":"1f9d2-1f3fd.png","sheet_x":48,"sheet_y":19,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F9D2-1F3FE","non_qualified":null,"image":"1f9d2-1f3fe.png","sheet_x":48,"sheet_y":20,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F9D2-1F3FF","non_qualified":null,"image":"1f9d2-1f3ff.png","sheet_x":48,"sheet_y":21,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Child","b":"1F9D2","k":[48,16],"o":5},"flag-cg":{"a":"Congo - Brazzaville Flag","b":"1F1E8-1F1EC","k":[1,16],"o":2},"bat":{"a":"Bat","b":"1F987","j":["animal","nature","blind","vampire"],"k":[42,25],"o":4},"diving_mask":{"a":"Diving Mask","b":"1F93F","k":[41,15],"o":12},"burrito":{"a":"Burrito","b":"1F32F","j":["food","mexican"],"k":[6,7],"o":2},"postal_horn":{"a":"Postal Horn","b":"1F4EF","j":["instrument","music"],"k":[27,12],"o":2},"night_with_stars":{"a":"Night with Stars","b":"1F303","j":["evening","city","downtown"],"k":[5,22],"o":2},"om_symbol":{"a":"Om Symbol","b":"1F549-FE0F","c":"1F549","k":[28,33],"o":2},"star_of_david":{"a":"Star of David","b":"2721-FE0F","c":"2721","j":["judaism"],"k":[55,15],"o":2},"boy":{"skin_variations":{"1F3FB":{"unified":"1F466-1F3FB","non_qualified":null,"image":"1f466-1f3fb.png","sheet_x":14,"sheet_y":27,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F466-1F3FC","non_qualified":null,"image":"1f466-1f3fc.png","sheet_x":14,"sheet_y":28,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F466-1F3FD","non_qualified":null,"image":"1f466-1f3fd.png","sheet_x":14,"sheet_y":29,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F466-1F3FE","non_qualified":null,"image":"1f466-1f3fe.png","sheet_x":14,"sheet_y":30,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F466-1F3FF","non_qualified":null,"image":"1f466-1f3ff.png","sheet_x":14,"sheet_y":31,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Boy","b":"1F466","j":["man","male","guy","teenager"],"k":[14,26],"o":2},"bell":{"a":"Bell","b":"1F514","j":["sound","notification","christmas","xmas","chime"],"k":[27,48],"o":2},"flag-ch":{"a":"Switzerland Flag","b":"1F1E8-1F1ED","k":[1,17],"o":2},"running_shirt_with_sash":{"a":"Running Shirt with Sash","b":"1F3BD","j":["play","pageant"],"k":[8,35],"o":2},"stuffed_flatbread":{"a":"Stuffed Flatbread","b":"1F959","j":["food","flatbread","stuffed","gyro"],"k":[41,40],"o":4},"bear":{"a":"Bear Face","b":"1F43B","j":["animal","nature","wild"],"k":[12,31],"o":2},"cityscape":{"a":"Cityscape","b":"1F3D9-FE0F","c":"1F3D9","j":["photo","night life","urban"],"k":[10,44],"o":2},"face_vomiting":{"a":"Face with Open Mouth Vomiting","b":"1F92E","k":[38,48],"n":["face_with_open_mouth_vomiting"],"o":5},"wheel_of_dharma":{"a":"Wheel of Dharma","b":"2638-FE0F","c":"2638","j":["hinduism","buddhism","sikhism","jainism"],"k":[53,15],"o":2},"ski":{"a":"Ski and Ski Boot","b":"1F3BF","j":["sports","winter","cold","snow"],"k":[8,37],"o":2},"girl":{"skin_variations":{"1F3FB":{"unified":"1F467-1F3FB","non_qualified":null,"image":"1f467-1f3fb.png","sheet_x":14,"sheet_y":33,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F467-1F3FC","non_qualified":null,"image":"1f467-1f3fc.png","sheet_x":14,"sheet_y":34,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F467-1F3FD","non_qualified":null,"image":"1f467-1f3fd.png","sheet_x":14,"sheet_y":35,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F467-1F3FE","non_qualified":null,"image":"1f467-1f3fe.png","sheet_x":14,"sheet_y":36,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F467-1F3FF","non_qualified":null,"image":"1f467-1f3ff.png","sheet_x":14,"sheet_y":37,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Girl","b":"1F467","j":["female","woman","teenager"],"k":[14,32],"o":2},"falafel":{"a":"Falafel","b":"1F9C6","k":[44,14],"o":12},"sneezing_face":{"a":"Sneezing Face","b":"1F927","j":["face","gesundheit","sneeze","sick","allergy"],"k":[38,41],"o":4},"no_bell":{"a":"Bell with Cancellation Stroke","b":"1F515","j":["sound","volume","mute","quiet","silent"],"k":[27,49],"o":2},"koala":{"a":"Koala","b":"1F428","j":["animal","nature"],"k":[12,12],"o":2},"sunrise_over_mountains":{"a":"Sunrise over Mountains","b":"1F304","j":["view","vacation","photo"],"k":[5,23],"o":2},"flag-ci":{"a":"Côte D’ivoire Flag","b":"1F1E8-1F1EE","k":[1,18],"o":2},"sunrise":{"a":"Sunrise","b":"1F305","j":["morning","view","vacation","photo"],"k":[5,24],"o":2},"yin_yang":{"a":"Yin Yang","b":"262F-FE0F","c":"262F","j":["balance"],"k":[53,14],"o":2},"adult":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB","non_qualified":null,"image":"1f9d1-1f3fb.png","sheet_x":48,"sheet_y":11,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F9D1-1F3FC","non_qualified":null,"image":"1f9d1-1f3fc.png","sheet_x":48,"sheet_y":12,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F9D1-1F3FD","non_qualified":null,"image":"1f9d1-1f3fd.png","sheet_x":48,"sheet_y":13,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F9D1-1F3FE","non_qualified":null,"image":"1f9d1-1f3fe.png","sheet_x":48,"sheet_y":14,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F9D1-1F3FF","non_qualified":null,"image":"1f9d1-1f3ff.png","sheet_x":48,"sheet_y":15,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Adult","b":"1F9D1","k":[48,10],"o":5},"hot_face":{"a":"Overheated Face","b":"1F975","k":[42,10],"o":11},"musical_score":{"a":"Musical Score","b":"1F3BC","j":["treble","clef","compose"],"k":[8,34],"o":2},"sled":{"a":"Sled","b":"1F6F7","k":[36,56],"o":5},"egg":{"a":"Egg","b":"1F95A","j":["food","chicken","breakfast"],"k":[41,41],"o":4},"panda_face":{"a":"Panda Face","b":"1F43C","j":["animal","nature","panda"],"k":[12,32],"o":2},"flag-ck":{"a":"Cook Islands Flag","b":"1F1E8-1F1F0","k":[1,19],"o":2},"flag-cl":{"a":"Chile Flag","b":"1F1E8-1F1F1","k":[1,20],"o":2},"person_with_blond_hair":{"skin_variations":{"1F3FB":{"unified":"1F471-1F3FB","non_qualified":null,"image":"1f471-1f3fb.png","sheet_x":22,"sheet_y":20,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FC":{"unified":"1F471-1F3FC","non_qualified":null,"image":"1f471-1f3fc.png","sheet_x":22,"sheet_y":21,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FD":{"unified":"1F471-1F3FD","non_qualified":null,"image":"1f471-1f3fd.png","sheet_x":22,"sheet_y":22,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FE":{"unified":"1F471-1F3FE","non_qualified":null,"image":"1f471-1f3fe.png","sheet_x":22,"sheet_y":23,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FF":{"unified":"1F471-1F3FF","non_qualified":null,"image":"1f471-1f3ff.png","sheet_x":22,"sheet_y":24,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false}},"obsoleted_by":"1F471-200D-2642-FE0F","a":"Person with Blond Hair","b":"1F471","k":[22,19],"o":2},"sloth":{"a":"Sloth","b":"1F9A5","k":[42,53],"o":12},"latin_cross":{"a":"Latin Cross","b":"271D-FE0F","c":"271D","j":["christianity"],"k":[55,14],"o":2},"curling_stone":{"a":"Curling Stone","b":"1F94C","k":[41,27],"o":5},"cold_face":{"a":"Freezing Face","b":"1F976","k":[42,11],"o":11},"fried_egg":{"a":"Cooking","b":"1F373","j":["food","breakfast","kitchen","egg"],"k":[7,18],"n":["cooking"],"o":2},"city_sunset":{"a":"Cityscape at Dusk","b":"1F306","j":["photo","evening","sky","buildings"],"k":[5,25],"o":2},"musical_note":{"a":"Musical Note","b":"1F3B5","j":["score","tone","sound"],"k":[8,27],"o":2},"flag-cm":{"a":"Cameroon Flag","b":"1F1E8-1F1F2","k":[1,21],"o":2},"notes":{"a":"Multiple Musical Notes","b":"1F3B6","j":["music","score"],"k":[8,28],"o":2},"woozy_face":{"a":"Face with Uneven Eyes and Wavy Mouth","b":"1F974","k":[42,9],"o":11},"dart":{"a":"Direct Hit","b":"1F3AF","j":["game","play","bar"],"k":[8,21],"o":2},"orthodox_cross":{"a":"Orthodox Cross","b":"2626-FE0F","c":"2626","j":["suppedaneum","religion"],"k":[53,11],"o":2},"shallow_pan_of_food":{"a":"Shallow Pan of Food","b":"1F958","j":["food","cooking","casserole","paella"],"k":[41,39],"o":4},"otter":{"a":"Otter","b":"1F9A6","k":[42,54],"o":12},"man":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB","non_qualified":null,"image":"1f468-1f3fb.png","sheet_x":17,"sheet_y":23,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F468-1F3FC","non_qualified":null,"image":"1f468-1f3fc.png","sheet_x":17,"sheet_y":24,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F468-1F3FD","non_qualified":null,"image":"1f468-1f3fd.png","sheet_x":17,"sheet_y":25,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F468-1F3FE","non_qualified":null,"image":"1f468-1f3fe.png","sheet_x":17,"sheet_y":26,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F468-1F3FF","non_qualified":null,"image":"1f468-1f3ff.png","sheet_x":17,"sheet_y":27,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Man","b":"1F468","j":["mustache","father","dad","guy","classy","sir","moustache"],"k":[17,22],"o":2},"city_sunrise":{"a":"Sunset over Buildings","b":"1F307","j":["photo","good morning","dawn"],"k":[5,26],"o":2},"bearded_person":{"skin_variations":{"1F3FB":{"unified":"1F9D4-1F3FB","non_qualified":null,"image":"1f9d4-1f3fb.png","sheet_x":48,"sheet_y":29,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F9D4-1F3FC","non_qualified":null,"image":"1f9d4-1f3fc.png","sheet_x":48,"sheet_y":30,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F9D4-1F3FD","non_qualified":null,"image":"1f9d4-1f3fd.png","sheet_x":48,"sheet_y":31,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F9D4-1F3FE","non_qualified":null,"image":"1f9d4-1f3fe.png","sheet_x":48,"sheet_y":32,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F9D4-1F3FF","non_qualified":null,"image":"1f9d4-1f3ff.png","sheet_x":48,"sheet_y":33,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Bearded Person","b":"1F9D4","k":[48,28],"o":5},"skunk":{"a":"Skunk","b":"1F9A8","k":[42,56],"o":12},"stew":{"a":"Pot of Food","b":"1F372","j":["food","meat","soup"],"k":[7,17],"o":2},"cn":{"a":"China Flag","b":"1F1E8-1F1F3","j":["china","chinese","prc","flag","country","nation","banner"],"k":[1,22],"n":["flag-cn"],"o":2},"studio_microphone":{"a":"Studio Microphone","b":"1F399-FE0F","c":"1F399","j":["sing","recording","artist","talkshow"],"k":[8,1],"o":2},"star_and_crescent":{"a":"Star and Crescent","b":"262A-FE0F","c":"262A","j":["islam"],"k":[53,12],"o":2},"yo-yo":{"a":"Yo-Yo","b":"1FA80","k":[52,1],"o":12},"bridge_at_night":{"a":"Bridge at Night","b":"1F309","j":["photo","sanfrancisco"],"k":[5,28],"o":2},"dizzy_face":{"a":"Dizzy Face","b":"1F635","j":["spent","unconscious","xox","dizzy"],"k":[31,31],"o":2},"red_haired_man":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F9B0","non_qualified":null,"image":"1f468-1f3fb-200d-1f9b0.png","sheet_x":16,"sheet_y":24,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F468-1F3FC-200D-1F9B0","non_qualified":null,"image":"1f468-1f3fc-200d-1f9b0.png","sheet_x":16,"sheet_y":25,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F468-1F3FD-200D-1F9B0","non_qualified":null,"image":"1f468-1f3fd-200d-1f9b0.png","sheet_x":16,"sheet_y":26,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F468-1F3FE-200D-1F9B0","non_qualified":null,"image":"1f468-1f3fe-200d-1f9b0.png","sheet_x":16,"sheet_y":27,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F468-1F3FF-200D-1F9B0","non_qualified":null,"image":"1f468-1f3ff-200d-1f9b0.png","sheet_x":16,"sheet_y":28,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Red Haired Man","b":"1F468-200D-1F9B0","k":[16,23],"o":11},"kite":{"a":"Kite","b":"1FA81","k":[52,2],"o":12},"bowl_with_spoon":{"a":"Bowl with Spoon","b":"1F963","k":[41,50],"o":5},"flag-co":{"a":"Colombia Flag","b":"1F1E8-1F1F4","k":[1,23],"o":2},"peace_symbol":{"a":"Peace Symbol","b":"262E-FE0F","c":"262E","j":["hippie"],"k":[53,13],"o":2},"kangaroo":{"a":"Kangaroo","b":"1F998","k":[42,42],"o":11},"hotsprings":{"a":"Hot Springs","b":"2668-FE0F","c":"2668","j":["bath","warm","relax"],"k":[53,37],"o":2},"exploding_head":{"a":"Shocked Face with Exploding Head","b":"1F92F","k":[38,49],"n":["shocked_face_with_exploding_head"],"o":5},"level_slider":{"a":"Level Slider","b":"1F39A-FE0F","c":"1F39A","j":["scale"],"k":[8,2],"o":2},"badger":{"a":"Badger","b":"1F9A1","k":[42,51],"o":11},"8ball":{"a":"Billiards","b":"1F3B1","j":["pool","hobby","game","luck","magic"],"k":[8,23],"o":2},"curly_haired_man":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F9B1","non_qualified":null,"image":"1f468-1f3fb-200d-1f9b1.png","sheet_x":16,"sheet_y":30,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F468-1F3FC-200D-1F9B1","non_qualified":null,"image":"1f468-1f3fc-200d-1f9b1.png","sheet_x":16,"sheet_y":31,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F468-1F3FD-200D-1F9B1","non_qualified":null,"image":"1f468-1f3fd-200d-1f9b1.png","sheet_x":16,"sheet_y":32,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F468-1F3FE-200D-1F9B1","non_qualified":null,"image":"1f468-1f3fe-200d-1f9b1.png","sheet_x":16,"sheet_y":33,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F468-1F3FF-200D-1F9B1","non_qualified":null,"image":"1f468-1f3ff-200d-1f9b1.png","sheet_x":16,"sheet_y":34,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Curly Haired Man","b":"1F468-200D-1F9B1","k":[16,29],"o":11},"flag-cp":{"a":"Clipperton Island Flag","b":"1F1E8-1F1F5","k":[1,24],"o":2},"carousel_horse":{"a":"Carousel Horse","b":"1F3A0","j":["photo","carnival"],"k":[8,6],"o":2},"face_with_cowboy_hat":{"a":"Face with Cowboy Hat","b":"1F920","k":[38,17],"o":4},"menorah_with_nine_branches":{"a":"Menorah with Nine Branches","b":"1F54E","k":[28,38],"o":2},"green_salad":{"a":"Green Salad","b":"1F957","j":["food","healthy","lettuce"],"k":[41,38],"o":4},"control_knobs":{"a":"Control Knobs","b":"1F39B-FE0F","c":"1F39B","j":["dial"],"k":[8,3],"o":2},"popcorn":{"a":"Popcorn","b":"1F37F","j":["food","movie theater","films","snack"],"k":[7,30],"o":2},"six_pointed_star":{"a":"Six Pointed Star with Middle Dot","b":"1F52F","j":["purple-square","religion","jewish","hexagram"],"k":[28,18],"o":2},"feet":{"a":"Paw Prints","b":"1F43E","k":[12,34],"n":["paw_prints"],"o":2},"ferris_wheel":{"a":"Ferris Wheel","b":"1F3A1","j":["photo","carnival","londoneye"],"k":[8,7],"o":2},"microphone":{"a":"Microphone","b":"1F3A4","j":["sound","music","PA","sing","talkshow"],"k":[8,10],"o":2},"crystal_ball":{"a":"Crystal Ball","b":"1F52E","j":["disco","party","magic","circus","fortune_teller"],"k":[28,17],"o":2},"partying_face":{"a":"Face with Party Horn and Party Hat","b":"1F973","k":[42,8],"o":11},"flag-cr":{"a":"Costa Rica Flag","b":"1F1E8-1F1F7","k":[1,25],"o":2},"white_haired_man":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F9B3","non_qualified":null,"image":"1f468-1f3fb-200d-1f9b3.png","sheet_x":16,"sheet_y":42,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F468-1F3FC-200D-1F9B3","non_qualified":null,"image":"1f468-1f3fc-200d-1f9b3.png","sheet_x":16,"sheet_y":43,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F468-1F3FD-200D-1F9B3","non_qualified":null,"image":"1f468-1f3fd-200d-1f9b3.png","sheet_x":16,"sheet_y":44,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F468-1F3FE-200D-1F9B3","non_qualified":null,"image":"1f468-1f3fe-200d-1f9b3.png","sheet_x":16,"sheet_y":45,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F468-1F3FF-200D-1F9B3","non_qualified":null,"image":"1f468-1f3ff-200d-1f9b3.png","sheet_x":16,"sheet_y":46,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"White Haired Man","b":"1F468-200D-1F9B3","k":[16,41],"o":11},"headphones":{"a":"Headphone","b":"1F3A7","j":["music","score","gadgets"],"k":[8,13],"o":2},"bald_man":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F9B2","non_qualified":null,"image":"1f468-1f3fb-200d-1f9b2.png","sheet_x":16,"sheet_y":36,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F468-1F3FC-200D-1F9B2","non_qualified":null,"image":"1f468-1f3fc-200d-1f9b2.png","sheet_x":16,"sheet_y":37,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F468-1F3FD-200D-1F9B2","non_qualified":null,"image":"1f468-1f3fd-200d-1f9b2.png","sheet_x":16,"sheet_y":38,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F468-1F3FE-200D-1F9B2","non_qualified":null,"image":"1f468-1f3fe-200d-1f9b2.png","sheet_x":16,"sheet_y":39,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F468-1F3FF-200D-1F9B2","non_qualified":null,"image":"1f468-1f3ff-200d-1f9b2.png","sheet_x":16,"sheet_y":40,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Bald Man","b":"1F468-200D-1F9B2","k":[16,35],"o":11},"sunglasses":{"a":"Smiling Face with Sunglasses","b":"1F60E","j":["face","cool","smile","summer","beach","sunglass"],"k":[30,49],"l":["8)"],"o":2},"butter":{"a":"Butter","b":"1F9C8","k":[44,16],"o":12},"roller_coaster":{"a":"Roller Coaster","b":"1F3A2","j":["carnival","playground","photo","fun"],"k":[8,8],"o":2},"turkey":{"a":"Turkey","b":"1F983","j":["animal","bird"],"k":[42,21],"o":2},"nazar_amulet":{"a":"Nazar Amulet","b":"1F9FF","k":[51,50],"o":11},"flag-cu":{"a":"Cuba Flag","b":"1F1E8-1F1FA","k":[1,26],"o":2},"aries":{"a":"Aries","b":"2648","j":["sign","purple-square","zodiac","astrology"],"k":[53,20],"o":2},"flag-cv":{"a":"Cape Verde Flag","b":"1F1E8-1F1FB","k":[1,27],"o":2},"barber":{"a":"Barber Pole","b":"1F488","j":["hair","salon","style"],"k":[25,18],"o":2},"taurus":{"a":"Taurus","b":"2649","j":["purple-square","sign","zodiac","astrology"],"k":[53,21],"o":2},"salt":{"a":"Salt Shaker","b":"1F9C2","k":[44,10],"o":11},"woman":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB","non_qualified":null,"image":"1f469-1f3fb.png","sheet_x":20,"sheet_y":10,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F469-1F3FC","non_qualified":null,"image":"1f469-1f3fc.png","sheet_x":20,"sheet_y":11,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F469-1F3FD","non_qualified":null,"image":"1f469-1f3fd.png","sheet_x":20,"sheet_y":12,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F469-1F3FE","non_qualified":null,"image":"1f469-1f3fe.png","sheet_x":20,"sheet_y":13,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F469-1F3FF","non_qualified":null,"image":"1f469-1f3ff.png","sheet_x":20,"sheet_y":14,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Woman","b":"1F469","j":["female","girls","lady"],"k":[20,9],"o":2},"video_game":{"a":"Video Game","b":"1F3AE","j":["play","console","PS4","controller"],"k":[8,20],"o":2},"chicken":{"a":"Chicken","b":"1F414","j":["animal","cluck","nature","bird"],"k":[11,48],"o":2},"radio":{"a":"Radio","b":"1F4FB","j":["communication","music","podcast","program"],"k":[27,24],"o":2},"nerd_face":{"a":"Nerd Face","b":"1F913","j":["face","nerdy","geek","dork"],"k":[37,26],"o":2},"red_haired_woman":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F9B0","non_qualified":null,"image":"1f469-1f3fb-200d-1f9b0.png","sheet_x":19,"sheet_y":9,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F469-1F3FC-200D-1F9B0","non_qualified":null,"image":"1f469-1f3fc-200d-1f9b0.png","sheet_x":19,"sheet_y":10,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F469-1F3FD-200D-1F9B0","non_qualified":null,"image":"1f469-1f3fd-200d-1f9b0.png","sheet_x":19,"sheet_y":11,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F469-1F3FE-200D-1F9B0","non_qualified":null,"image":"1f469-1f3fe-200d-1f9b0.png","sheet_x":19,"sheet_y":12,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F469-1F3FF-200D-1F9B0","non_qualified":null,"image":"1f469-1f3ff-200d-1f9b0.png","sheet_x":19,"sheet_y":13,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Red Haired Woman","b":"1F469-200D-1F9B0","k":[19,8],"o":11},"circus_tent":{"a":"Circus Tent","b":"1F3AA","j":["festival","carnival","party"],"k":[8,16],"o":2},"face_with_monocle":{"a":"Face with Monocle","b":"1F9D0","k":[45,16],"o":5},"canned_food":{"a":"Canned Food","b":"1F96B","k":[42,1],"o":5},"flag-cw":{"a":"Curaçao Flag","b":"1F1E8-1F1FC","k":[1,28],"o":2},"gemini":{"a":"Gemini","b":"264A","j":["sign","zodiac","purple-square","astrology"],"k":[53,22],"o":2},"saxophone":{"a":"Saxophone","b":"1F3B7","j":["music","instrument","jazz","blues"],"k":[8,29],"o":2},"rooster":{"a":"Rooster","b":"1F413","j":["animal","nature","chicken"],"k":[11,47],"o":2},"joystick":{"a":"Joystick","b":"1F579-FE0F","c":"1F579","j":["game","play"],"k":[29,36],"o":2},"guitar":{"a":"Guitar","b":"1F3B8","j":["music","instrument"],"k":[8,30],"o":2},"slot_machine":{"a":"Slot Machine","b":"1F3B0","j":["bet","gamble","vegas","fruit machine","luck","casino"],"k":[8,22],"o":2},"bento":{"a":"Bento Box","b":"1F371","j":["food","japanese","box"],"k":[7,16],"o":2},"steam_locomotive":{"a":"Steam Locomotive","b":"1F682","j":["transportation","vehicle","train"],"k":[34,1],"o":2},"confused":{"a":"Confused Face","b":"1F615","j":["face","indifference","huh","weird","hmmm",":/"],"k":[30,56],"l":[":\\",":-\\",":/",":-/"],"o":2},"flag-cx":{"a":"Christmas Island Flag","b":"1F1E8-1F1FD","k":[1,29],"o":2},"hatching_chick":{"a":"Hatching Chick","b":"1F423","j":["animal","chicken","egg","born","baby","bird"],"k":[12,7],"o":2},"cancer":{"a":"Cancer","b":"264B","j":["sign","zodiac","purple-square","astrology"],"k":[53,23],"o":2},"red_haired_person":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB-200D-1F9B0","non_qualified":null,"image":"1f9d1-1f3fb-200d-1f9b0.png","sheet_x":47,"sheet_y":14,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FC":{"unified":"1F9D1-1F3FC-200D-1F9B0","non_qualified":null,"image":"1f9d1-1f3fc-200d-1f9b0.png","sheet_x":47,"sheet_y":15,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FD":{"unified":"1F9D1-1F3FD-200D-1F9B0","non_qualified":null,"image":"1f9d1-1f3fd-200d-1f9b0.png","sheet_x":47,"sheet_y":16,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FE":{"unified":"1F9D1-1F3FE-200D-1F9B0","non_qualified":null,"image":"1f9d1-1f3fe-200d-1f9b0.png","sheet_x":47,"sheet_y":17,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FF":{"unified":"1F9D1-1F3FF-200D-1F9B0","non_qualified":null,"image":"1f9d1-1f3ff-200d-1f9b0.png","sheet_x":47,"sheet_y":18,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false}},"a":"Red Haired Person","b":"1F9D1-200D-1F9B0","k":[47,13],"o":12},"flag-cy":{"a":"Cyprus Flag","b":"1F1E8-1F1FE","k":[1,30],"o":2},"worried":{"a":"Worried Face","b":"1F61F","j":["face","concern","nervous",":("],"k":[31,9],"o":2},"railway_car":{"a":"Railway Car","b":"1F683","j":["transportation","vehicle"],"k":[34,2],"o":2},"leo":{"a":"Leo","b":"264C","j":["sign","purple-square","zodiac","astrology"],"k":[53,24],"o":2},"curly_haired_woman":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F9B1","non_qualified":null,"image":"1f469-1f3fb-200d-1f9b1.png","sheet_x":19,"sheet_y":15,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F469-1F3FC-200D-1F9B1","non_qualified":null,"image":"1f469-1f3fc-200d-1f9b1.png","sheet_x":19,"sheet_y":16,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F469-1F3FD-200D-1F9B1","non_qualified":null,"image":"1f469-1f3fd-200d-1f9b1.png","sheet_x":19,"sheet_y":17,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F469-1F3FE-200D-1F9B1","non_qualified":null,"image":"1f469-1f3fe-200d-1f9b1.png","sheet_x":19,"sheet_y":18,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F469-1F3FF-200D-1F9B1","non_qualified":null,"image":"1f469-1f3ff-200d-1f9b1.png","sheet_x":19,"sheet_y":19,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Curly Haired Woman","b":"1F469-200D-1F9B1","k":[19,14],"o":11},"baby_chick":{"a":"Baby Chick","b":"1F424","j":["animal","chicken","bird"],"k":[12,8],"o":2},"musical_keyboard":{"a":"Musical Keyboard","b":"1F3B9","j":["piano","instrument","compose"],"k":[8,31],"o":2},"game_die":{"a":"Game Die","b":"1F3B2","j":["dice","random","tabletop","play","luck"],"k":[8,24],"o":2},"rice_cracker":{"a":"Rice Cracker","b":"1F358","j":["food","japanese"],"k":[6,48],"o":2},"virgo":{"a":"Virgo","b":"264D","j":["sign","zodiac","purple-square","astrology"],"k":[53,25],"o":2},"flag-cz":{"a":"Czechia Flag","b":"1F1E8-1F1FF","k":[1,31],"o":2},"curly_haired_person":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB-200D-1F9B1","non_qualified":null,"image":"1f9d1-1f3fb-200d-1f9b1.png","sheet_x":47,"sheet_y":20,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FC":{"unified":"1F9D1-1F3FC-200D-1F9B1","non_qualified":null,"image":"1f9d1-1f3fc-200d-1f9b1.png","sheet_x":47,"sheet_y":21,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FD":{"unified":"1F9D1-1F3FD-200D-1F9B1","non_qualified":null,"image":"1f9d1-1f3fd-200d-1f9b1.png","sheet_x":47,"sheet_y":22,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FE":{"unified":"1F9D1-1F3FE-200D-1F9B1","non_qualified":null,"image":"1f9d1-1f3fe-200d-1f9b1.png","sheet_x":47,"sheet_y":23,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FF":{"unified":"1F9D1-1F3FF-200D-1F9B1","non_qualified":null,"image":"1f9d1-1f3ff-200d-1f9b1.png","sheet_x":47,"sheet_y":24,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false}},"a":"Curly Haired Person","b":"1F9D1-200D-1F9B1","k":[47,19],"o":12},"rice_ball":{"a":"Rice Ball","b":"1F359","j":["food","japanese"],"k":[6,49],"o":2},"hatched_chick":{"a":"Front-Facing Baby Chick","b":"1F425","j":["animal","chicken","baby","bird"],"k":[12,9],"o":2},"jigsaw":{"a":"Jigsaw Puzzle Piece","b":"1F9E9","k":[51,28],"o":11},"trumpet":{"a":"Trumpet","b":"1F3BA","j":["music","brass"],"k":[8,32],"o":2},"slightly_frowning_face":{"a":"Slightly Frowning Face","b":"1F641","j":["face","frowning","disappointed","sad","upset"],"k":[31,43],"o":2},"bullettrain_side":{"a":"High-Speed Train","b":"1F684","j":["transportation","vehicle"],"k":[34,3],"o":2},"libra":{"a":"Libra","b":"264E","j":["sign","purple-square","zodiac","astrology"],"k":[53,26],"o":2},"de":{"a":"Germany Flag","b":"1F1E9-1F1EA","j":["german","nation","flag","country","banner"],"k":[1,32],"n":["flag-de"],"o":2},"rice":{"a":"Cooked Rice","b":"1F35A","j":["food","china","asian"],"k":[6,50],"o":2},"violin":{"a":"Violin","b":"1F3BB","j":["music","instrument","orchestra","symphony"],"k":[8,33],"o":2},"white_haired_woman":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F9B3","non_qualified":null,"image":"1f469-1f3fb-200d-1f9b3.png","sheet_x":19,"sheet_y":27,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F469-1F3FC-200D-1F9B3","non_qualified":null,"image":"1f469-1f3fc-200d-1f9b3.png","sheet_x":19,"sheet_y":28,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F469-1F3FD-200D-1F9B3","non_qualified":null,"image":"1f469-1f3fd-200d-1f9b3.png","sheet_x":19,"sheet_y":29,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F469-1F3FE-200D-1F9B3","non_qualified":null,"image":"1f469-1f3fe-200d-1f9b3.png","sheet_x":19,"sheet_y":30,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F469-1F3FF-200D-1F9B3","non_qualified":null,"image":"1f469-1f3ff-200d-1f9b3.png","sheet_x":19,"sheet_y":31,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"White Haired Woman","b":"1F469-200D-1F9B3","k":[19,26],"o":11},"bird":{"a":"Bird","b":"1F426","j":["animal","nature","fly","tweet","spring"],"k":[12,10],"o":2},"white_frowning_face":{"a":"White Frowning Face","b":"2639-FE0F","c":"2639","k":[53,16],"o":2},"bullettrain_front":{"a":"High-Speed Train with Bullet Nose","b":"1F685","j":["transportation","vehicle","speed","fast","public","travel"],"k":[34,4],"o":2},"teddy_bear":{"a":"Teddy Bear","b":"1F9F8","k":[51,43],"o":11},"white_haired_person":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB-200D-1F9B3","non_qualified":null,"image":"1f9d1-1f3fb-200d-1f9b3.png","sheet_x":47,"sheet_y":32,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FC":{"unified":"1F9D1-1F3FC-200D-1F9B3","non_qualified":null,"image":"1f9d1-1f3fc-200d-1f9b3.png","sheet_x":47,"sheet_y":33,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FD":{"unified":"1F9D1-1F3FD-200D-1F9B3","non_qualified":null,"image":"1f9d1-1f3fd-200d-1f9b3.png","sheet_x":47,"sheet_y":34,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FE":{"unified":"1F9D1-1F3FE-200D-1F9B3","non_qualified":null,"image":"1f9d1-1f3fe-200d-1f9b3.png","sheet_x":47,"sheet_y":35,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FF":{"unified":"1F9D1-1F3FF-200D-1F9B3","non_qualified":null,"image":"1f9d1-1f3ff-200d-1f9b3.png","sheet_x":47,"sheet_y":36,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false}},"a":"White Haired Person","b":"1F9D1-200D-1F9B3","k":[47,31],"o":12},"spades":{"a":"Black Spade Suit","b":"2660-FE0F","c":"2660","j":["poker","cards","suits","magic"],"k":[53,33],"o":2},"banjo":{"a":"Banjo","b":"1FA95","k":[52,9],"o":12},"train2":{"a":"Train","b":"1F686","j":["transportation","vehicle"],"k":[34,5],"o":2},"scorpius":{"a":"Scorpius","b":"264F","j":["sign","zodiac","purple-square","astrology","scorpio"],"k":[53,27],"o":2},"curry":{"a":"Curry and Rice","b":"1F35B","j":["food","spicy","hot","indian"],"k":[6,51],"o":2},"open_mouth":{"a":"Face with Open Mouth","b":"1F62E","j":["face","surprise","impressed","wow","whoa",":O"],"k":[31,24],"l":[":o",":-o",":O",":-O"],"o":2},"flag-dg":{"a":"Diego Garcia Flag","b":"1F1E9-1F1EC","k":[1,33],"o":2},"penguin":{"a":"Penguin","b":"1F427","j":["animal","nature"],"k":[12,11],"o":2},"hearts":{"a":"Black Heart Suit","b":"2665-FE0F","c":"2665","j":["poker","cards","magic","suits"],"k":[53,35],"o":2},"ramen":{"a":"Steaming Bowl","b":"1F35C","j":["food","japanese","noodle","chopsticks"],"k":[6,52],"o":2},"sagittarius":{"a":"Sagittarius","b":"2650","j":["sign","zodiac","purple-square","astrology"],"k":[53,28],"o":2},"bald_woman":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F9B2","non_qualified":null,"image":"1f469-1f3fb-200d-1f9b2.png","sheet_x":19,"sheet_y":21,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F469-1F3FC-200D-1F9B2","non_qualified":null,"image":"1f469-1f3fc-200d-1f9b2.png","sheet_x":19,"sheet_y":22,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F469-1F3FD-200D-1F9B2","non_qualified":null,"image":"1f469-1f3fd-200d-1f9b2.png","sheet_x":19,"sheet_y":23,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F469-1F3FE-200D-1F9B2","non_qualified":null,"image":"1f469-1f3fe-200d-1f9b2.png","sheet_x":19,"sheet_y":24,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F469-1F3FF-200D-1F9B2","non_qualified":null,"image":"1f469-1f3ff-200d-1f9b2.png","sheet_x":19,"sheet_y":25,"added_in":"11.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Bald Woman","b":"1F469-200D-1F9B2","k":[19,20],"o":11},"dove_of_peace":{"a":"Dove of Peace","b":"1F54A-FE0F","c":"1F54A","k":[28,34],"o":2},"hushed":{"a":"Hushed Face","b":"1F62F","j":["face","woo","shh"],"k":[31,25],"o":2},"metro":{"a":"Metro","b":"1F687","j":["transportation","blue-square","mrt","underground","tube"],"k":[34,6],"o":2},"flag-dj":{"a":"Djibouti Flag","b":"1F1E9-1F1EF","k":[1,34],"o":2},"drum_with_drumsticks":{"a":"Drum with Drumsticks","b":"1F941","k":[41,17],"o":4},"spaghetti":{"a":"Spaghetti","b":"1F35D","j":["food","italian","noodle"],"k":[6,53],"o":2},"eagle":{"a":"Eagle","b":"1F985","j":["animal","nature","bird"],"k":[42,23],"o":4},"astonished":{"a":"Astonished Face","b":"1F632","j":["face","xox","surprised","poisoned"],"k":[31,28],"o":2},"capricorn":{"a":"Capricorn","b":"2651","j":["sign","zodiac","purple-square","astrology"],"k":[53,29],"o":2},"light_rail":{"a":"Light Rail","b":"1F688","j":["transportation","vehicle"],"k":[34,7],"o":2},"flag-dk":{"a":"Denmark Flag","b":"1F1E9-1F1F0","k":[1,35],"o":2},"iphone":{"a":"Mobile Phone","b":"1F4F1","j":["technology","apple","gadgets","dial"],"k":[27,14],"o":2},"bald_person":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB-200D-1F9B2","non_qualified":null,"image":"1f9d1-1f3fb-200d-1f9b2.png","sheet_x":47,"sheet_y":26,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FC":{"unified":"1F9D1-1F3FC-200D-1F9B2","non_qualified":null,"image":"1f9d1-1f3fc-200d-1f9b2.png","sheet_x":47,"sheet_y":27,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FD":{"unified":"1F9D1-1F3FD-200D-1F9B2","non_qualified":null,"image":"1f9d1-1f3fd-200d-1f9b2.png","sheet_x":47,"sheet_y":28,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FE":{"unified":"1F9D1-1F3FE-200D-1F9B2","non_qualified":null,"image":"1f9d1-1f3fe-200d-1f9b2.png","sheet_x":47,"sheet_y":29,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FF":{"unified":"1F9D1-1F3FF-200D-1F9B2","non_qualified":null,"image":"1f9d1-1f3ff-200d-1f9b2.png","sheet_x":47,"sheet_y":30,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false}},"a":"Bald Person","b":"1F9D1-200D-1F9B2","k":[47,25],"o":12},"diamonds":{"a":"Black Diamond Suit","b":"2666-FE0F","c":"2666","j":["poker","cards","magic","suits"],"k":[53,36],"o":2},"clubs":{"a":"Black Club Suit","b":"2663-FE0F","c":"2663","j":["poker","cards","magic","suits"],"k":[53,34],"o":2},"aquarius":{"a":"Aquarius","b":"2652","j":["sign","purple-square","zodiac","astrology"],"k":[53,30],"o":2},"sweet_potato":{"a":"Roasted Sweet Potato","b":"1F360","j":["food","nature"],"k":[6,56],"o":2},"flag-dm":{"a":"Dominica Flag","b":"1F1E9-1F1F2","k":[1,36],"o":2},"duck":{"a":"Duck","b":"1F986","j":["animal","nature","bird","mallard"],"k":[42,24],"o":4},"calling":{"a":"Mobile Phone with Rightwards Arrow at Left","b":"1F4F2","j":["iphone","incoming"],"k":[27,15],"o":2},"station":{"a":"Station","b":"1F689","j":["transportation","vehicle","public"],"k":[34,8],"o":2},"blond-haired-woman":{"skin_variations":{"1F3FB":{"unified":"1F471-1F3FB-200D-2640-FE0F","non_qualified":"1F471-1F3FB-200D-2640","image":"1f471-1f3fb-200d-2640-fe0f.png","sheet_x":22,"sheet_y":8,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F471-1F3FC-200D-2640-FE0F","non_qualified":"1F471-1F3FC-200D-2640","image":"1f471-1f3fc-200d-2640-fe0f.png","sheet_x":22,"sheet_y":9,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F471-1F3FD-200D-2640-FE0F","non_qualified":"1F471-1F3FD-200D-2640","image":"1f471-1f3fd-200d-2640-fe0f.png","sheet_x":22,"sheet_y":10,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F471-1F3FE-200D-2640-FE0F","non_qualified":"1F471-1F3FE-200D-2640","image":"1f471-1f3fe-200d-2640-fe0f.png","sheet_x":22,"sheet_y":11,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F471-1F3FF-200D-2640-FE0F","non_qualified":"1F471-1F3FF-200D-2640","image":"1f471-1f3ff-200d-2640-fe0f.png","sheet_x":22,"sheet_y":12,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Blond Haired Woman","b":"1F471-200D-2640-FE0F","c":"1F471-200D-2640","k":[22,7],"o":4},"flushed":{"a":"Flushed Face","b":"1F633","j":["face","blush","shy","flattered"],"k":[31,29],"o":2},"pisces":{"a":"Pisces","b":"2653","j":["purple-square","sign","zodiac","astrology"],"k":[53,31],"o":2},"chess_pawn":{"a":"Chess Pawn","b":"265F-FE0F","c":"265F","k":[53,32],"o":11},"blond-haired-man":{"skin_variations":{"1F3FB":{"unified":"1F471-1F3FB-200D-2642-FE0F","non_qualified":"1F471-1F3FB-200D-2642","image":"1f471-1f3fb-200d-2642-fe0f.png","sheet_x":22,"sheet_y":14,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F471-1F3FC-200D-2642-FE0F","non_qualified":"1F471-1F3FC-200D-2642","image":"1f471-1f3fc-200d-2642-fe0f.png","sheet_x":22,"sheet_y":15,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F471-1F3FD-200D-2642-FE0F","non_qualified":"1F471-1F3FD-200D-2642","image":"1f471-1f3fd-200d-2642-fe0f.png","sheet_x":22,"sheet_y":16,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F471-1F3FE-200D-2642-FE0F","non_qualified":"1F471-1F3FE-200D-2642","image":"1f471-1f3fe-200d-2642-fe0f.png","sheet_x":22,"sheet_y":17,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F471-1F3FF-200D-2642-FE0F","non_qualified":"1F471-1F3FF-200D-2642","image":"1f471-1f3ff-200d-2642-fe0f.png","sheet_x":22,"sheet_y":18,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"obsoletes":"1F471","a":"Blond Haired Man","b":"1F471-200D-2642-FE0F","c":"1F471-200D-2642","k":[22,13],"o":4},"phone":{"a":"Black Telephone","b":"260E-FE0F","c":"260E","j":["technology","communication","dial","telephone"],"k":[52,54],"n":["telephone"],"o":2},"oden":{"a":"Oden","b":"1F362","j":["food","japanese"],"k":[7,1],"o":2},"flag-do":{"a":"Dominican Republic Flag","b":"1F1E9-1F1F4","k":[1,37],"o":2},"tram":{"a":"Tram","b":"1F68A","j":["transportation","vehicle"],"k":[34,9],"o":2},"swan":{"a":"Swan","b":"1F9A2","k":[42,52],"o":11},"pleading_face":{"a":"Face with Pleading Eyes","b":"1F97A","k":[42,12],"o":11},"flag-dz":{"a":"Algeria Flag","b":"1F1E9-1F1FF","k":[1,38],"o":2},"monorail":{"a":"Monorail","b":"1F69D","j":["transportation","vehicle"],"k":[34,28],"o":2},"owl":{"a":"Owl","b":"1F989","j":["animal","nature","bird","hoot"],"k":[42,27],"o":4},"sushi":{"a":"Sushi","b":"1F363","j":["food","fish","japanese","rice"],"k":[7,2],"o":2},"telephone_receiver":{"a":"Telephone Receiver","b":"1F4DE","j":["technology","communication","dial"],"k":[26,52],"o":2},"black_joker":{"a":"Playing Card Black Joker","b":"1F0CF","j":["poker","cards","game","play","magic"],"k":[0,15],"o":2},"ophiuchus":{"a":"Ophiuchus","b":"26CE","j":["sign","purple-square","constellation","astrology"],"k":[54,4],"o":2},"frowning":{"a":"Frowning Face with Open Mouth","b":"1F626","j":["face","aw","what"],"k":[31,16],"o":2},"older_adult":{"skin_variations":{"1F3FB":{"unified":"1F9D3-1F3FB","non_qualified":null,"image":"1f9d3-1f3fb.png","sheet_x":48,"sheet_y":23,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F9D3-1F3FC","non_qualified":null,"image":"1f9d3-1f3fc.png","sheet_x":48,"sheet_y":24,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F9D3-1F3FD","non_qualified":null,"image":"1f9d3-1f3fd.png","sheet_x":48,"sheet_y":25,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F9D3-1F3FE","non_qualified":null,"image":"1f9d3-1f3fe.png","sheet_x":48,"sheet_y":26,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F9D3-1F3FF","non_qualified":null,"image":"1f9d3-1f3ff.png","sheet_x":48,"sheet_y":27,"added_in":"5.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Older Adult","b":"1F9D3","k":[48,22],"o":5},"flag-ea":{"a":"Ceuta & Melilla Flag","b":"1F1EA-1F1E6","k":[1,39],"o":2},"flamingo":{"a":"Flamingo","b":"1F9A9","k":[43,0],"o":12},"pager":{"a":"Pager","b":"1F4DF","j":["bbcall","oldschool","90s"],"k":[26,53],"o":2},"mountain_railway":{"a":"Mountain Railway","b":"1F69E","j":["transportation","vehicle"],"k":[34,29],"o":2},"mahjong":{"a":"Mahjong Tile Red Dragon","b":"1F004","j":["game","play","chinese","kanji"],"k":[0,14],"o":2},"older_man":{"skin_variations":{"1F3FB":{"unified":"1F474-1F3FB","non_qualified":null,"image":"1f474-1f3fb.png","sheet_x":22,"sheet_y":50,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F474-1F3FC","non_qualified":null,"image":"1f474-1f3fc.png","sheet_x":22,"sheet_y":51,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F474-1F3FD","non_qualified":null,"image":"1f474-1f3fd.png","sheet_x":22,"sheet_y":52,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F474-1F3FE","non_qualified":null,"image":"1f474-1f3fe.png","sheet_x":22,"sheet_y":53,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F474-1F3FF","non_qualified":null,"image":"1f474-1f3ff.png","sheet_x":22,"sheet_y":54,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Older Man","b":"1F474","j":["human","male","men","old","elder","senior"],"k":[22,49],"o":2},"twisted_rightwards_arrows":{"a":"Twisted Rightwards Arrows","b":"1F500","j":["blue-square","shuffle","music","random"],"k":[27,28],"o":2},"fried_shrimp":{"a":"Fried Shrimp","b":"1F364","j":["food","animal","appetizer","summer"],"k":[7,3],"o":2},"anguished":{"a":"Anguished Face","b":"1F627","j":["face","stunned","nervous"],"k":[31,17],"l":["D:"],"o":2},"repeat":{"a":"Clockwise Rightwards and Leftwards Open Circle Arrows","b":"1F501","j":["loop","record"],"k":[27,29],"o":2},"fish_cake":{"a":"Fish Cake with Swirl Design","b":"1F365","j":["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],"k":[7,4],"o":2},"fax":{"a":"Fax Machine","b":"1F4E0","j":["communication","technology"],"k":[26,54],"o":2},"older_woman":{"skin_variations":{"1F3FB":{"unified":"1F475-1F3FB","non_qualified":null,"image":"1f475-1f3fb.png","sheet_x":22,"sheet_y":56,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F475-1F3FC","non_qualified":null,"image":"1f475-1f3fc.png","sheet_x":23,"sheet_y":0,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F475-1F3FD","non_qualified":null,"image":"1f475-1f3fd.png","sheet_x":23,"sheet_y":1,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F475-1F3FE","non_qualified":null,"image":"1f475-1f3fe.png","sheet_x":23,"sheet_y":2,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F475-1F3FF","non_qualified":null,"image":"1f475-1f3ff.png","sheet_x":23,"sheet_y":3,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Older Woman","b":"1F475","j":["human","female","women","lady","old","elder","senior"],"k":[22,55],"o":2},"flag-ec":{"a":"Ecuador Flag","b":"1F1EA-1F1E8","k":[1,40],"o":2},"peacock":{"a":"Peacock","b":"1F99A","k":[42,44],"o":11},"fearful":{"a":"Fearful Face","b":"1F628","j":["face","scared","terrified","nervous","oops","huh"],"k":[31,18],"o":2},"train":{"a":"Tram Car","b":"1F68B","j":["transportation","vehicle","carriage","public","travel"],"k":[34,10],"o":2},"flower_playing_cards":{"a":"Flower Playing Cards","b":"1F3B4","j":["game","sunset","red"],"k":[8,26],"o":2},"repeat_one":{"a":"Clockwise Rightwards and Leftwards Open Circle Arrows with Circled One Overlay","b":"1F502","j":["blue-square","loop"],"k":[27,30],"o":2},"moon_cake":{"a":"Moon Cake","b":"1F96E","k":[42,4],"o":11},"performing_arts":{"a":"Performing Arts","b":"1F3AD","j":["acting","theater","drama"],"k":[8,19],"o":2},"cold_sweat":{"a":"Face with Open Mouth and Cold Sweat","b":"1F630","j":["face","nervous","sweat"],"k":[31,26],"o":2},"person_frowning":{"skin_variations":{"1F3FB":{"unified":"1F64D-1F3FB","non_qualified":null,"image":"1f64d-1f3fb.png","sheet_x":33,"sheet_y":27,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FC":{"unified":"1F64D-1F3FC","non_qualified":null,"image":"1f64d-1f3fc.png","sheet_x":33,"sheet_y":28,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FD":{"unified":"1F64D-1F3FD","non_qualified":null,"image":"1f64d-1f3fd.png","sheet_x":33,"sheet_y":29,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FE":{"unified":"1F64D-1F3FE","non_qualified":null,"image":"1f64d-1f3fe.png","sheet_x":33,"sheet_y":30,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FF":{"unified":"1F64D-1F3FF","non_qualified":null,"image":"1f64d-1f3ff.png","sheet_x":33,"sheet_y":31,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false}},"obsoleted_by":"1F64D-200D-2640-FE0F","a":"Person Frowning","b":"1F64D","k":[33,26],"o":2},"flag-ee":{"a":"Estonia Flag","b":"1F1EA-1F1EA","k":[1,41],"o":2},"battery":{"a":"Battery","b":"1F50B","j":["power","energy","sustain"],"k":[27,39],"o":2},"parrot":{"a":"Parrot","b":"1F99C","k":[42,46],"o":11},"bus":{"a":"Bus","b":"1F68C","j":["car","vehicle","transportation"],"k":[34,11],"o":2},"flag-eg":{"a":"Egypt Flag","b":"1F1EA-1F1EC","k":[1,42],"o":2},"arrow_forward":{"a":"Black Right-Pointing Triangle","b":"25B6-FE0F","c":"25B6","j":["blue-square","right","direction","play"],"k":[52,43],"o":2},"man-frowning":{"skin_variations":{"1F3FB":{"unified":"1F64D-1F3FB-200D-2642-FE0F","non_qualified":"1F64D-1F3FB-200D-2642","image":"1f64d-1f3fb-200d-2642-fe0f.png","sheet_x":33,"sheet_y":21,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F64D-1F3FC-200D-2642-FE0F","non_qualified":"1F64D-1F3FC-200D-2642","image":"1f64d-1f3fc-200d-2642-fe0f.png","sheet_x":33,"sheet_y":22,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F64D-1F3FD-200D-2642-FE0F","non_qualified":"1F64D-1F3FD-200D-2642","image":"1f64d-1f3fd-200d-2642-fe0f.png","sheet_x":33,"sheet_y":23,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F64D-1F3FE-200D-2642-FE0F","non_qualified":"1F64D-1F3FE-200D-2642","image":"1f64d-1f3fe-200d-2642-fe0f.png","sheet_x":33,"sheet_y":24,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F64D-1F3FF-200D-2642-FE0F","non_qualified":"1F64D-1F3FF-200D-2642","image":"1f64d-1f3ff-200d-2642-fe0f.png","sheet_x":33,"sheet_y":25,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Man Frowning","b":"1F64D-200D-2642-FE0F","c":"1F64D-200D-2642","k":[33,20],"o":4},"disappointed_relieved":{"a":"Disappointed but Relieved Face","b":"1F625","j":["face","phew","sweat","nervous"],"k":[31,15],"o":2},"electric_plug":{"a":"Electric Plug","b":"1F50C","j":["charger","power"],"k":[27,40],"o":2},"frame_with_picture":{"a":"Frame with Picture","b":"1F5BC-FE0F","c":"1F5BC","k":[30,14],"o":2},"oncoming_bus":{"a":"Oncoming Bus","b":"1F68D","j":["vehicle","transportation"],"k":[34,12],"o":2},"dango":{"a":"Dango","b":"1F361","j":["food","dessert","sweet","japanese","barbecue","meat"],"k":[7,0],"o":2},"frog":{"a":"Frog Face","b":"1F438","j":["animal","nature","croak","toad"],"k":[12,28],"o":2},"computer":{"a":"Personal Computer","b":"1F4BB","j":["technology","laptop","screen","display","monitor"],"k":[26,17],"o":2},"art":{"a":"Artist Palette","b":"1F3A8","j":["design","paint","draw","colors"],"k":[8,14],"o":2},"flag-eh":{"a":"Western Sahara Flag","b":"1F1EA-1F1ED","k":[1,43],"o":2},"fast_forward":{"a":"Black Right-Pointing Double Triangle","b":"23E9","j":["blue-square","play","speed","continue"],"k":[52,26],"o":2},"cry":{"a":"Crying Face","b":"1F622","j":["face","tears","sad","depressed","upset",":'("],"k":[31,12],"l":[":'("],"m":":'(","o":2},"woman-frowning":{"skin_variations":{"1F3FB":{"unified":"1F64D-1F3FB-200D-2640-FE0F","non_qualified":"1F64D-1F3FB-200D-2640","image":"1f64d-1f3fb-200d-2640-fe0f.png","sheet_x":33,"sheet_y":15,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F64D-1F3FC-200D-2640-FE0F","non_qualified":"1F64D-1F3FC-200D-2640","image":"1f64d-1f3fc-200d-2640-fe0f.png","sheet_x":33,"sheet_y":16,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F64D-1F3FD-200D-2640-FE0F","non_qualified":"1F64D-1F3FD-200D-2640","image":"1f64d-1f3fd-200d-2640-fe0f.png","sheet_x":33,"sheet_y":17,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F64D-1F3FE-200D-2640-FE0F","non_qualified":"1F64D-1F3FE-200D-2640","image":"1f64d-1f3fe-200d-2640-fe0f.png","sheet_x":33,"sheet_y":18,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F64D-1F3FF-200D-2640-FE0F","non_qualified":"1F64D-1F3FF-200D-2640","image":"1f64d-1f3ff-200d-2640-fe0f.png","sheet_x":33,"sheet_y":19,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"obsoletes":"1F64D","a":"Woman Frowning","b":"1F64D-200D-2640-FE0F","c":"1F64D-200D-2640","k":[33,14],"o":4},"trolleybus":{"a":"Trolleybus","b":"1F68E","j":["bart","transportation","vehicle"],"k":[34,13],"o":2},"crocodile":{"a":"Crocodile","b":"1F40A","j":["animal","nature","reptile","lizard","alligator"],"k":[11,38],"o":2},"dumpling":{"a":"Dumpling","b":"1F95F","k":[41,46],"o":5},"black_right_pointing_double_triangle_with_vertical_bar":{"a":"Black Right Pointing Double Triangle with Vertical Bar","b":"23ED-FE0F","c":"23ED","k":[52,30],"o":2},"desktop_computer":{"a":"Desktop Computer","b":"1F5A5-FE0F","c":"1F5A5","j":["technology","computing","screen"],"k":[30,10],"o":2},"person_with_pouting_face":{"skin_variations":{"1F3FB":{"unified":"1F64E-1F3FB","non_qualified":null,"image":"1f64e-1f3fb.png","sheet_x":33,"sheet_y":45,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FC":{"unified":"1F64E-1F3FC","non_qualified":null,"image":"1f64e-1f3fc.png","sheet_x":33,"sheet_y":46,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FD":{"unified":"1F64E-1F3FD","non_qualified":null,"image":"1f64e-1f3fd.png","sheet_x":33,"sheet_y":47,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FE":{"unified":"1F64E-1F3FE","non_qualified":null,"image":"1f64e-1f3fe.png","sheet_x":33,"sheet_y":48,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FF":{"unified":"1F64E-1F3FF","non_qualified":null,"image":"1f64e-1f3ff.png","sheet_x":33,"sheet_y":49,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false}},"obsoleted_by":"1F64E-200D-2640-FE0F","a":"Person with Pouting Face","b":"1F64E","k":[33,44],"o":2},"turtle":{"a":"Turtle","b":"1F422","j":["animal","slow","nature","tortoise"],"k":[12,6],"o":2},"sob":{"a":"Loudly Crying Face","b":"1F62D","j":["face","cry","tears","sad","upset","depressed"],"k":[31,23],"m":":'(","o":2},"flag-er":{"a":"Eritrea Flag","b":"1F1EA-1F1F7","k":[1,44],"o":2},"thread":{"a":"Spool of Thread","b":"1F9F5","k":[51,40],"o":11},"minibus":{"a":"Minibus","b":"1F690","j":["vehicle","car","transportation"],"k":[34,15],"o":2},"fortune_cookie":{"a":"Fortune Cookie","b":"1F960","k":[41,47],"o":5},"yarn":{"a":"Ball of Yarn","b":"1F9F6","k":[51,41],"o":11},"takeout_box":{"a":"Takeout Box","b":"1F961","k":[41,48],"o":5},"man-pouting":{"skin_variations":{"1F3FB":{"unified":"1F64E-1F3FB-200D-2642-FE0F","non_qualified":"1F64E-1F3FB-200D-2642","image":"1f64e-1f3fb-200d-2642-fe0f.png","sheet_x":33,"sheet_y":39,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F64E-1F3FC-200D-2642-FE0F","non_qualified":"1F64E-1F3FC-200D-2642","image":"1f64e-1f3fc-200d-2642-fe0f.png","sheet_x":33,"sheet_y":40,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F64E-1F3FD-200D-2642-FE0F","non_qualified":"1F64E-1F3FD-200D-2642","image":"1f64e-1f3fd-200d-2642-fe0f.png","sheet_x":33,"sheet_y":41,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F64E-1F3FE-200D-2642-FE0F","non_qualified":"1F64E-1F3FE-200D-2642","image":"1f64e-1f3fe-200d-2642-fe0f.png","sheet_x":33,"sheet_y":42,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F64E-1F3FF-200D-2642-FE0F","non_qualified":"1F64E-1F3FF-200D-2642","image":"1f64e-1f3ff-200d-2642-fe0f.png","sheet_x":33,"sheet_y":43,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Man Pouting","b":"1F64E-200D-2642-FE0F","c":"1F64E-200D-2642","k":[33,38],"o":4},"printer":{"a":"Printer","b":"1F5A8-FE0F","c":"1F5A8","j":["paper","ink"],"k":[30,11],"o":2},"scream":{"a":"Face Screaming in Fear","b":"1F631","j":["face","munch","scared","omg"],"k":[31,27],"o":2},"es":{"a":"Spain Flag","b":"1F1EA-1F1F8","j":["spain","flag","nation","country","banner"],"k":[1,45],"n":["flag-es"],"o":2},"ambulance":{"a":"Ambulance","b":"1F691","j":["health","911","hospital"],"k":[34,16],"o":2},"black_right_pointing_triangle_with_double_vertical_bar":{"a":"Black Right Pointing Triangle with Double Vertical Bar","b":"23EF-FE0F","c":"23EF","k":[52,32],"o":2},"lizard":{"a":"Lizard","b":"1F98E","j":["animal","nature","reptile"],"k":[42,32],"o":4},"flag-et":{"a":"Ethiopia Flag","b":"1F1EA-1F1F9","k":[1,46],"o":2},"keyboard":{"a":"Keyboard","b":"2328-FE0F","c":"2328","j":["technology","computer","type","input","text"],"k":[52,24],"o":2},"crab":{"a":"Crab","b":"1F980","j":["animal","crustacean"],"k":[42,18],"o":2},"confounded":{"a":"Confounded Face","b":"1F616","j":["face","confused","sick","unwell","oops",":S"],"k":[31,0],"o":2},"snake":{"a":"Snake","b":"1F40D","j":["animal","evil","nature","hiss","python"],"k":[11,41],"o":2},"woman-pouting":{"skin_variations":{"1F3FB":{"unified":"1F64E-1F3FB-200D-2640-FE0F","non_qualified":"1F64E-1F3FB-200D-2640","image":"1f64e-1f3fb-200d-2640-fe0f.png","sheet_x":33,"sheet_y":33,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F64E-1F3FC-200D-2640-FE0F","non_qualified":"1F64E-1F3FC-200D-2640","image":"1f64e-1f3fc-200d-2640-fe0f.png","sheet_x":33,"sheet_y":34,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F64E-1F3FD-200D-2640-FE0F","non_qualified":"1F64E-1F3FD-200D-2640","image":"1f64e-1f3fd-200d-2640-fe0f.png","sheet_x":33,"sheet_y":35,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F64E-1F3FE-200D-2640-FE0F","non_qualified":"1F64E-1F3FE-200D-2640","image":"1f64e-1f3fe-200d-2640-fe0f.png","sheet_x":33,"sheet_y":36,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F64E-1F3FF-200D-2640-FE0F","non_qualified":"1F64E-1F3FF-200D-2640","image":"1f64e-1f3ff-200d-2640-fe0f.png","sheet_x":33,"sheet_y":37,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"obsoletes":"1F64E","a":"Woman Pouting","b":"1F64E-200D-2640-FE0F","c":"1F64E-200D-2640","k":[33,32],"o":4},"arrow_backward":{"a":"Black Left-Pointing Triangle","b":"25C0-FE0F","c":"25C0","j":["blue-square","left","direction"],"k":[52,44],"o":2},"fire_engine":{"a":"Fire Engine","b":"1F692","j":["transportation","cars","vehicle"],"k":[34,17],"o":2},"rewind":{"a":"Black Left-Pointing Double Triangle","b":"23EA","j":["play","blue-square"],"k":[52,27],"o":2},"three_button_mouse":{"a":"Three Button Mouse","b":"1F5B1-FE0F","c":"1F5B1","k":[30,12],"o":2},"no_good":{"skin_variations":{"1F3FB":{"unified":"1F645-1F3FB","non_qualified":null,"image":"1f645-1f3fb.png","sheet_x":32,"sheet_y":3,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FC":{"unified":"1F645-1F3FC","non_qualified":null,"image":"1f645-1f3fc.png","sheet_x":32,"sheet_y":4,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FD":{"unified":"1F645-1F3FD","non_qualified":null,"image":"1f645-1f3fd.png","sheet_x":32,"sheet_y":5,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FE":{"unified":"1F645-1F3FE","non_qualified":null,"image":"1f645-1f3fe.png","sheet_x":32,"sheet_y":6,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FF":{"unified":"1F645-1F3FF","non_qualified":null,"image":"1f645-1f3ff.png","sheet_x":32,"sheet_y":7,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false}},"obsoleted_by":"1F645-200D-2640-FE0F","a":"Face with No Good Gesture","b":"1F645","k":[32,2],"o":2},"police_car":{"a":"Police Car","b":"1F693","j":["vehicle","cars","transportation","law","legal","enforcement"],"k":[34,18],"o":2},"dragon_face":{"a":"Dragon Face","b":"1F432","j":["animal","myth","nature","chinese","green"],"k":[12,22],"o":2},"persevere":{"a":"Persevering Face","b":"1F623","j":["face","sick","no","upset","oops"],"k":[31,13],"o":2},"lobster":{"a":"Lobster","b":"1F99E","k":[42,48],"o":11},"flag-eu":{"a":"European Union Flag","b":"1F1EA-1F1FA","k":[1,47],"o":2},"disappointed":{"a":"Disappointed Face","b":"1F61E","j":["face","sad","upset","depressed",":("],"k":[31,8],"l":["):",":(",":-("],"m":":(","o":2},"shrimp":{"a":"Shrimp","b":"1F990","j":["animal","ocean","nature","seafood"],"k":[42,34],"o":4},"dragon":{"a":"Dragon","b":"1F409","j":["animal","myth","nature","chinese","green"],"k":[11,37],"o":2},"man-gesturing-no":{"skin_variations":{"1F3FB":{"unified":"1F645-1F3FB-200D-2642-FE0F","non_qualified":"1F645-1F3FB-200D-2642","image":"1f645-1f3fb-200d-2642-fe0f.png","sheet_x":31,"sheet_y":54,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F645-1F3FC-200D-2642-FE0F","non_qualified":"1F645-1F3FC-200D-2642","image":"1f645-1f3fc-200d-2642-fe0f.png","sheet_x":31,"sheet_y":55,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F645-1F3FD-200D-2642-FE0F","non_qualified":"1F645-1F3FD-200D-2642","image":"1f645-1f3fd-200d-2642-fe0f.png","sheet_x":31,"sheet_y":56,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F645-1F3FE-200D-2642-FE0F","non_qualified":"1F645-1F3FE-200D-2642","image":"1f645-1f3fe-200d-2642-fe0f.png","sheet_x":32,"sheet_y":0,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F645-1F3FF-200D-2642-FE0F","non_qualified":"1F645-1F3FF-200D-2642","image":"1f645-1f3ff-200d-2642-fe0f.png","sheet_x":32,"sheet_y":1,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Man Gesturing No","b":"1F645-200D-2642-FE0F","c":"1F645-200D-2642","k":[31,53],"o":4},"flag-fi":{"a":"Finland Flag","b":"1F1EB-1F1EE","k":[1,48],"o":2},"trackball":{"a":"Trackball","b":"1F5B2-FE0F","c":"1F5B2","j":["technology","trackpad"],"k":[30,13],"o":2},"black_left_pointing_double_triangle_with_vertical_bar":{"a":"Black Left Pointing Double Triangle with Vertical Bar","b":"23EE-FE0F","c":"23EE","k":[52,31],"o":2},"oncoming_police_car":{"a":"Oncoming Police Car","b":"1F694","j":["vehicle","law","legal","enforcement","911"],"k":[34,19],"o":2},"minidisc":{"a":"Minidisc","b":"1F4BD","j":["technology","record","data","disk","90s"],"k":[26,19],"o":2},"sweat":{"a":"Face with Cold Sweat","b":"1F613","j":["face","hot","sad","tired","exercise"],"k":[30,54],"o":2},"squid":{"a":"Squid","b":"1F991","j":["animal","nature","ocean","sea"],"k":[42,35],"o":4},"sauropod":{"a":"Sauropod","b":"1F995","k":[42,39],"o":5},"arrow_up_small":{"a":"Up-Pointing Small Red Triangle","b":"1F53C","j":["blue-square","triangle","direction","point","forward","top"],"k":[28,31],"o":2},"flag-fj":{"a":"Fiji Flag","b":"1F1EB-1F1EF","k":[1,49],"o":2},"woman-gesturing-no":{"skin_variations":{"1F3FB":{"unified":"1F645-1F3FB-200D-2640-FE0F","non_qualified":"1F645-1F3FB-200D-2640","image":"1f645-1f3fb-200d-2640-fe0f.png","sheet_x":31,"sheet_y":48,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F645-1F3FC-200D-2640-FE0F","non_qualified":"1F645-1F3FC-200D-2640","image":"1f645-1f3fc-200d-2640-fe0f.png","sheet_x":31,"sheet_y":49,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F645-1F3FD-200D-2640-FE0F","non_qualified":"1F645-1F3FD-200D-2640","image":"1f645-1f3fd-200d-2640-fe0f.png","sheet_x":31,"sheet_y":50,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F645-1F3FE-200D-2640-FE0F","non_qualified":"1F645-1F3FE-200D-2640","image":"1f645-1f3fe-200d-2640-fe0f.png","sheet_x":31,"sheet_y":51,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F645-1F3FF-200D-2640-FE0F","non_qualified":"1F645-1F3FF-200D-2640","image":"1f645-1f3ff-200d-2640-fe0f.png","sheet_x":31,"sheet_y":52,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"obsoletes":"1F645","a":"Woman Gesturing No","b":"1F645-200D-2640-FE0F","c":"1F645-200D-2640","k":[31,47],"o":4},"taxi":{"a":"Taxi","b":"1F695","j":["uber","vehicle","cars","transportation"],"k":[34,20],"o":2},"flag-fk":{"a":"Falkland Islands Flag","b":"1F1EB-1F1F0","k":[1,50],"o":2},"floppy_disk":{"a":"Floppy Disk","b":"1F4BE","j":["oldschool","technology","save","90s","80s"],"k":[26,20],"o":2},"t-rex":{"a":"T-Rex","b":"1F996","k":[42,40],"o":5},"oyster":{"a":"Oyster","b":"1F9AA","k":[43,1],"o":12},"arrow_double_up":{"a":"Black Up-Pointing Double Triangle","b":"23EB","j":["blue-square","direction","top"],"k":[52,28],"o":2},"oncoming_taxi":{"a":"Oncoming Taxi","b":"1F696","j":["vehicle","cars","uber"],"k":[34,21],"o":2},"ok_woman":{"skin_variations":{"1F3FB":{"unified":"1F646-1F3FB","non_qualified":null,"image":"1f646-1f3fb.png","sheet_x":32,"sheet_y":21,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FC":{"unified":"1F646-1F3FC","non_qualified":null,"image":"1f646-1f3fc.png","sheet_x":32,"sheet_y":22,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FD":{"unified":"1F646-1F3FD","non_qualified":null,"image":"1f646-1f3fd.png","sheet_x":32,"sheet_y":23,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FE":{"unified":"1F646-1F3FE","non_qualified":null,"image":"1f646-1f3fe.png","sheet_x":32,"sheet_y":24,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FF":{"unified":"1F646-1F3FF","non_qualified":null,"image":"1f646-1f3ff.png","sheet_x":32,"sheet_y":25,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false}},"obsoleted_by":"1F646-200D-2640-FE0F","a":"Face with Ok Gesture","b":"1F646","j":["women","girl","female","pink","human","woman"],"k":[32,20],"o":2},"weary":{"a":"Weary Face","b":"1F629","j":["face","tired","sleepy","sad","frustrated","upset"],"k":[31,19],"o":2},"man-gesturing-ok":{"skin_variations":{"1F3FB":{"unified":"1F646-1F3FB-200D-2642-FE0F","non_qualified":"1F646-1F3FB-200D-2642","image":"1f646-1f3fb-200d-2642-fe0f.png","sheet_x":32,"sheet_y":15,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F646-1F3FC-200D-2642-FE0F","non_qualified":"1F646-1F3FC-200D-2642","image":"1f646-1f3fc-200d-2642-fe0f.png","sheet_x":32,"sheet_y":16,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F646-1F3FD-200D-2642-FE0F","non_qualified":"1F646-1F3FD-200D-2642","image":"1f646-1f3fd-200d-2642-fe0f.png","sheet_x":32,"sheet_y":17,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F646-1F3FE-200D-2642-FE0F","non_qualified":"1F646-1F3FE-200D-2642","image":"1f646-1f3fe-200d-2642-fe0f.png","sheet_x":32,"sheet_y":18,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F646-1F3FF-200D-2642-FE0F","non_qualified":"1F646-1F3FF-200D-2642","image":"1f646-1f3ff-200d-2642-fe0f.png","sheet_x":32,"sheet_y":19,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Man Gesturing Ok","b":"1F646-200D-2642-FE0F","c":"1F646-200D-2642","k":[32,14],"o":4},"arrow_down_small":{"a":"Down-Pointing Small Red Triangle","b":"1F53D","j":["blue-square","direction","bottom"],"k":[28,32],"o":2},"tired_face":{"a":"Tired Face","b":"1F62B","j":["sick","whine","upset","frustrated"],"k":[31,21],"o":2},"car":{"a":"Automobile","b":"1F697","k":[34,22],"n":["red_car"],"o":2},"icecream":{"a":"Soft Ice Cream","b":"1F366","j":["food","hot","dessert","summer"],"k":[7,5],"o":2},"cd":{"a":"Optical Disc","b":"1F4BF","j":["technology","dvd","disk","disc","90s"],"k":[26,21],"o":2},"whale":{"a":"Spouting Whale","b":"1F433","j":["animal","nature","sea","ocean"],"k":[12,23],"o":2},"flag-fm":{"a":"Micronesia Flag","b":"1F1EB-1F1F2","k":[1,51],"o":2},"oncoming_automobile":{"a":"Oncoming Automobile","b":"1F698","j":["car","vehicle","transportation"],"k":[34,23],"o":2},"arrow_double_down":{"a":"Black Down-Pointing Double Triangle","b":"23EC","j":["blue-square","direction","bottom"],"k":[52,29],"o":2},"woman-gesturing-ok":{"skin_variations":{"1F3FB":{"unified":"1F646-1F3FB-200D-2640-FE0F","non_qualified":"1F646-1F3FB-200D-2640","image":"1f646-1f3fb-200d-2640-fe0f.png","sheet_x":32,"sheet_y":9,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F646-1F3FC-200D-2640-FE0F","non_qualified":"1F646-1F3FC-200D-2640","image":"1f646-1f3fc-200d-2640-fe0f.png","sheet_x":32,"sheet_y":10,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F646-1F3FD-200D-2640-FE0F","non_qualified":"1F646-1F3FD-200D-2640","image":"1f646-1f3fd-200d-2640-fe0f.png","sheet_x":32,"sheet_y":11,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F646-1F3FE-200D-2640-FE0F","non_qualified":"1F646-1F3FE-200D-2640","image":"1f646-1f3fe-200d-2640-fe0f.png","sheet_x":32,"sheet_y":12,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F646-1F3FF-200D-2640-FE0F","non_qualified":"1F646-1F3FF-200D-2640","image":"1f646-1f3ff-200d-2640-fe0f.png","sheet_x":32,"sheet_y":13,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"obsoletes":"1F646","a":"Woman Gesturing Ok","b":"1F646-200D-2640-FE0F","c":"1F646-200D-2640","k":[32,8],"o":4},"yawning_face":{"a":"Yawning Face","b":"1F971","k":[42,7],"o":12},"dvd":{"a":"Dvd","b":"1F4C0","j":["cd","disk","disc"],"k":[26,22],"o":2},"whale2":{"a":"Whale","b":"1F40B","j":["animal","nature","sea","ocean"],"k":[11,39],"o":2},"flag-fo":{"a":"Faroe Islands Flag","b":"1F1EB-1F1F4","k":[1,52],"o":2},"shaved_ice":{"a":"Shaved Ice","b":"1F367","j":["hot","dessert","summer"],"k":[7,6],"o":2},"double_vertical_bar":{"a":"Double Vertical Bar","b":"23F8-FE0F","c":"23F8","k":[52,37],"o":2},"information_desk_person":{"skin_variations":{"1F3FB":{"unified":"1F481-1F3FB","non_qualified":null,"image":"1f481-1f3fb.png","sheet_x":24,"sheet_y":3,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FC":{"unified":"1F481-1F3FC","non_qualified":null,"image":"1f481-1f3fc.png","sheet_x":24,"sheet_y":4,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FD":{"unified":"1F481-1F3FD","non_qualified":null,"image":"1f481-1f3fd.png","sheet_x":24,"sheet_y":5,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FE":{"unified":"1F481-1F3FE","non_qualified":null,"image":"1f481-1f3fe.png","sheet_x":24,"sheet_y":6,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FF":{"unified":"1F481-1F3FF","non_qualified":null,"image":"1f481-1f3ff.png","sheet_x":24,"sheet_y":7,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false}},"obsoleted_by":"1F481-200D-2640-FE0F","a":"Information Desk Person","b":"1F481","k":[24,2],"o":2},"dolphin":{"a":"Dolphin","b":"1F42C","j":["animal","nature","fish","sea","ocean","flipper","fins","beach"],"k":[12,16],"n":["flipper"],"o":2},"blue_car":{"a":"Recreational Vehicle","b":"1F699","j":["transportation","vehicle"],"k":[34,24],"o":2},"ice_cream":{"a":"Ice Cream","b":"1F368","j":["food","hot","dessert"],"k":[7,7],"o":2},"fr":{"a":"France Flag","b":"1F1EB-1F1F7","j":["banner","flag","nation","france","french","country"],"k":[1,53],"n":["flag-fr"],"o":2},"triumph":{"a":"Face with Look of Triumph","b":"1F624","j":["face","gas","phew","proud","pride"],"k":[31,14],"o":2},"abacus":{"a":"Abacus","b":"1F9EE","k":[51,33],"o":11},"man-tipping-hand":{"skin_variations":{"1F3FB":{"unified":"1F481-1F3FB-200D-2642-FE0F","non_qualified":"1F481-1F3FB-200D-2642","image":"1f481-1f3fb-200d-2642-fe0f.png","sheet_x":23,"sheet_y":54,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F481-1F3FC-200D-2642-FE0F","non_qualified":"1F481-1F3FC-200D-2642","image":"1f481-1f3fc-200d-2642-fe0f.png","sheet_x":23,"sheet_y":55,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F481-1F3FD-200D-2642-FE0F","non_qualified":"1F481-1F3FD-200D-2642","image":"1f481-1f3fd-200d-2642-fe0f.png","sheet_x":23,"sheet_y":56,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F481-1F3FE-200D-2642-FE0F","non_qualified":"1F481-1F3FE-200D-2642","image":"1f481-1f3fe-200d-2642-fe0f.png","sheet_x":24,"sheet_y":0,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F481-1F3FF-200D-2642-FE0F","non_qualified":"1F481-1F3FF-200D-2642","image":"1f481-1f3ff-200d-2642-fe0f.png","sheet_x":24,"sheet_y":1,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Man Tipping Hand","b":"1F481-200D-2642-FE0F","c":"1F481-200D-2642","k":[23,53],"o":4},"doughnut":{"a":"Doughnut","b":"1F369","j":["food","dessert","snack","sweet","donut"],"k":[7,8],"o":2},"fish":{"a":"Fish","b":"1F41F","j":["animal","food","nature"],"k":[12,3],"o":2},"truck":{"a":"Delivery Truck","b":"1F69A","j":["cars","transportation"],"k":[34,25],"o":2},"movie_camera":{"a":"Movie Camera","b":"1F3A5","j":["film","record"],"k":[8,11],"o":2},"flag-ga":{"a":"Gabon Flag","b":"1F1EC-1F1E6","k":[1,54],"o":2},"rage":{"a":"Pouting Face","b":"1F621","j":["angry","mad","hate","despise"],"k":[31,11],"o":2},"black_square_for_stop":{"a":"Black Square for Stop","b":"23F9-FE0F","c":"23F9","k":[52,38],"o":2},"articulated_lorry":{"a":"Articulated Lorry","b":"1F69B","j":["vehicle","cars","transportation","express"],"k":[34,26],"o":2},"angry":{"a":"Angry Face","b":"1F620","j":["mad","face","annoyed","frustrated"],"k":[31,10],"l":[">:(",">:-("],"o":2},"cookie":{"a":"Cookie","b":"1F36A","j":["food","snack","oreo","chocolate","sweet","dessert"],"k":[7,9],"o":2},"gb":{"a":"United Kingdom Flag","b":"1F1EC-1F1E7","k":[1,55],"n":["uk","flag-gb"],"o":2},"tropical_fish":{"a":"Tropical Fish","b":"1F420","j":["animal","swim","ocean","beach","nemo"],"k":[12,4],"o":2},"woman-tipping-hand":{"skin_variations":{"1F3FB":{"unified":"1F481-1F3FB-200D-2640-FE0F","non_qualified":"1F481-1F3FB-200D-2640","image":"1f481-1f3fb-200d-2640-fe0f.png","sheet_x":23,"sheet_y":48,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F481-1F3FC-200D-2640-FE0F","non_qualified":"1F481-1F3FC-200D-2640","image":"1f481-1f3fc-200d-2640-fe0f.png","sheet_x":23,"sheet_y":49,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F481-1F3FD-200D-2640-FE0F","non_qualified":"1F481-1F3FD-200D-2640","image":"1f481-1f3fd-200d-2640-fe0f.png","sheet_x":23,"sheet_y":50,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F481-1F3FE-200D-2640-FE0F","non_qualified":"1F481-1F3FE-200D-2640","image":"1f481-1f3fe-200d-2640-fe0f.png","sheet_x":23,"sheet_y":51,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F481-1F3FF-200D-2640-FE0F","non_qualified":"1F481-1F3FF-200D-2640","image":"1f481-1f3ff-200d-2640-fe0f.png","sheet_x":23,"sheet_y":52,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"obsoletes":"1F481","a":"Woman Tipping Hand","b":"1F481-200D-2640-FE0F","c":"1F481-200D-2640","k":[23,47],"o":4},"black_circle_for_record":{"a":"Black Circle for Record","b":"23FA-FE0F","c":"23FA","k":[52,39],"o":2},"film_frames":{"a":"Film Frames","b":"1F39E-FE0F","c":"1F39E","k":[8,4],"o":2},"film_projector":{"a":"Film Projector","b":"1F4FD-FE0F","c":"1F4FD","j":["video","tape","record","movie"],"k":[27,26],"o":2},"flag-gd":{"a":"Grenada Flag","b":"1F1EC-1F1E9","k":[1,56],"o":2},"blowfish":{"a":"Blowfish","b":"1F421","j":["animal","nature","food","sea","ocean"],"k":[12,5],"o":2},"face_with_symbols_on_mouth":{"a":"Serious Face with Symbols Covering Mouth","b":"1F92C","k":[38,46],"n":["serious_face_with_symbols_covering_mouth"],"o":5},"birthday":{"a":"Birthday Cake","b":"1F382","j":["food","dessert","cake"],"k":[7,33],"o":2},"eject":{"a":"Eject","b":"23CF-FE0F","c":"23CF","k":[52,25],"o":2},"raising_hand":{"skin_variations":{"1F3FB":{"unified":"1F64B-1F3FB","non_qualified":null,"image":"1f64b-1f3fb.png","sheet_x":33,"sheet_y":3,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FC":{"unified":"1F64B-1F3FC","non_qualified":null,"image":"1f64b-1f3fc.png","sheet_x":33,"sheet_y":4,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FD":{"unified":"1F64B-1F3FD","non_qualified":null,"image":"1f64b-1f3fd.png","sheet_x":33,"sheet_y":5,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FE":{"unified":"1F64B-1F3FE","non_qualified":null,"image":"1f64b-1f3fe.png","sheet_x":33,"sheet_y":6,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FF":{"unified":"1F64B-1F3FF","non_qualified":null,"image":"1f64b-1f3ff.png","sheet_x":33,"sheet_y":7,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false}},"obsoleted_by":"1F64B-200D-2640-FE0F","a":"Happy Person Raising One Hand","b":"1F64B","k":[33,2],"o":2},"tractor":{"a":"Tractor","b":"1F69C","j":["vehicle","car","farming","agriculture"],"k":[34,27],"o":2},"flag-ge":{"a":"Georgia Flag","b":"1F1EC-1F1EA","k":[2,0],"o":2},"smiling_imp":{"a":"Smiling Face with Horns","b":"1F608","j":["devil","horns"],"k":[30,43],"o":2},"racing_car":{"a":"Racing Car","b":"1F3CE-FE0F","c":"1F3CE","j":["sports","race","fast","formula","f1"],"k":[10,33],"o":2},"cinema":{"a":"Cinema","b":"1F3A6","j":["blue-square","record","film","movie","curtain","stage","theater"],"k":[8,12],"o":2},"clapper":{"a":"Clapper Board","b":"1F3AC","j":["movie","film","record"],"k":[8,18],"o":2},"shark":{"a":"Shark","b":"1F988","j":["animal","nature","fish","sea","ocean","jaws","fins","beach"],"k":[42,26],"o":4},"cake":{"a":"Shortcake","b":"1F370","j":["food","dessert"],"k":[7,15],"o":2},"man-raising-hand":{"skin_variations":{"1F3FB":{"unified":"1F64B-1F3FB-200D-2642-FE0F","non_qualified":"1F64B-1F3FB-200D-2642","image":"1f64b-1f3fb-200d-2642-fe0f.png","sheet_x":32,"sheet_y":54,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F64B-1F3FC-200D-2642-FE0F","non_qualified":"1F64B-1F3FC-200D-2642","image":"1f64b-1f3fc-200d-2642-fe0f.png","sheet_x":32,"sheet_y":55,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F64B-1F3FD-200D-2642-FE0F","non_qualified":"1F64B-1F3FD-200D-2642","image":"1f64b-1f3fd-200d-2642-fe0f.png","sheet_x":32,"sheet_y":56,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F64B-1F3FE-200D-2642-FE0F","non_qualified":"1F64B-1F3FE-200D-2642","image":"1f64b-1f3fe-200d-2642-fe0f.png","sheet_x":33,"sheet_y":0,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F64B-1F3FF-200D-2642-FE0F","non_qualified":"1F64B-1F3FF-200D-2642","image":"1f64b-1f3ff-200d-2642-fe0f.png","sheet_x":33,"sheet_y":1,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Man Raising Hand","b":"1F64B-200D-2642-FE0F","c":"1F64B-200D-2642","k":[32,53],"o":4},"octopus":{"a":"Octopus","b":"1F419","j":["animal","creature","ocean","sea","nature","beach"],"k":[11,54],"o":2},"woman-raising-hand":{"skin_variations":{"1F3FB":{"unified":"1F64B-1F3FB-200D-2640-FE0F","non_qualified":"1F64B-1F3FB-200D-2640","image":"1f64b-1f3fb-200d-2640-fe0f.png","sheet_x":32,"sheet_y":48,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F64B-1F3FC-200D-2640-FE0F","non_qualified":"1F64B-1F3FC-200D-2640","image":"1f64b-1f3fc-200d-2640-fe0f.png","sheet_x":32,"sheet_y":49,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F64B-1F3FD-200D-2640-FE0F","non_qualified":"1F64B-1F3FD-200D-2640","image":"1f64b-1f3fd-200d-2640-fe0f.png","sheet_x":32,"sheet_y":50,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F64B-1F3FE-200D-2640-FE0F","non_qualified":"1F64B-1F3FE-200D-2640","image":"1f64b-1f3fe-200d-2640-fe0f.png","sheet_x":32,"sheet_y":51,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F64B-1F3FF-200D-2640-FE0F","non_qualified":"1F64B-1F3FF-200D-2640","image":"1f64b-1f3ff-200d-2640-fe0f.png","sheet_x":32,"sheet_y":52,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"obsoletes":"1F64B","a":"Woman Raising Hand","b":"1F64B-200D-2640-FE0F","c":"1F64B-200D-2640","k":[32,47],"o":4},"flag-gf":{"a":"French Guiana Flag","b":"1F1EC-1F1EB","k":[2,1],"o":2},"tv":{"a":"Television","b":"1F4FA","j":["technology","program","oldschool","show","television"],"k":[27,23],"o":2},"imp":{"a":"Imp","b":"1F47F","j":["devil","angry","horns"],"k":[23,45],"o":2},"cupcake":{"a":"Cupcake","b":"1F9C1","k":[44,9],"o":11},"racing_motorcycle":{"a":"Racing Motorcycle","b":"1F3CD-FE0F","c":"1F3CD","k":[10,32],"o":2},"low_brightness":{"a":"Low Brightness Symbol","b":"1F505","j":["sun","afternoon","warm","summer"],"k":[27,33],"o":2},"shell":{"a":"Spiral Shell","b":"1F41A","j":["nature","sea","beach"],"k":[11,55],"o":2},"flag-gg":{"a":"Guernsey Flag","b":"1F1EC-1F1EC","k":[2,2],"o":2},"high_brightness":{"a":"High Brightness Symbol","b":"1F506","j":["sun","light"],"k":[27,34],"o":2},"deaf_person":{"skin_variations":{"1F3FB":{"unified":"1F9CF-1F3FB","non_qualified":null,"image":"1f9cf-1f3fb.png","sheet_x":45,"sheet_y":11,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F9CF-1F3FC","non_qualified":null,"image":"1f9cf-1f3fc.png","sheet_x":45,"sheet_y":12,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F9CF-1F3FD","non_qualified":null,"image":"1f9cf-1f3fd.png","sheet_x":45,"sheet_y":13,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F9CF-1F3FE","non_qualified":null,"image":"1f9cf-1f3fe.png","sheet_x":45,"sheet_y":14,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F9CF-1F3FF","non_qualified":null,"image":"1f9cf-1f3ff.png","sheet_x":45,"sheet_y":15,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Deaf Person","b":"1F9CF","k":[45,10],"o":12},"skull":{"a":"Skull","b":"1F480","j":["dead","skeleton","creepy","death"],"k":[23,46],"o":2},"motor_scooter":{"a":"Motor Scooter","b":"1F6F5","j":["vehicle","vespa","sasha"],"k":[36,54],"o":4},"camera":{"a":"Camera","b":"1F4F7","j":["gadgets","photography"],"k":[27,20],"o":2},"pie":{"a":"Pie","b":"1F967","k":[41,54],"o":5},"flag-gh":{"a":"Ghana Flag","b":"1F1EC-1F1ED","k":[2,3],"o":2},"deaf_man":{"skin_variations":{"1F3FB":{"unified":"1F9CF-1F3FB-200D-2642-FE0F","non_qualified":"1F9CF-1F3FB-200D-2642","image":"1f9cf-1f3fb-200d-2642-fe0f.png","sheet_x":45,"sheet_y":5,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F9CF-1F3FC-200D-2642-FE0F","non_qualified":"1F9CF-1F3FC-200D-2642","image":"1f9cf-1f3fc-200d-2642-fe0f.png","sheet_x":45,"sheet_y":6,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F9CF-1F3FD-200D-2642-FE0F","non_qualified":"1F9CF-1F3FD-200D-2642","image":"1f9cf-1f3fd-200d-2642-fe0f.png","sheet_x":45,"sheet_y":7,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F9CF-1F3FE-200D-2642-FE0F","non_qualified":"1F9CF-1F3FE-200D-2642","image":"1f9cf-1f3fe-200d-2642-fe0f.png","sheet_x":45,"sheet_y":8,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F9CF-1F3FF-200D-2642-FE0F","non_qualified":"1F9CF-1F3FF-200D-2642","image":"1f9cf-1f3ff-200d-2642-fe0f.png","sheet_x":45,"sheet_y":9,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Deaf Man","b":"1F9CF-200D-2642-FE0F","c":"1F9CF-200D-2642","k":[45,4],"o":12},"skull_and_crossbones":{"a":"Skull and Crossbones","b":"2620-FE0F","c":"2620","j":["poison","danger","deadly","scary","death","pirate","evil"],"k":[53,8],"o":2},"camera_with_flash":{"a":"Camera with Flash","b":"1F4F8","k":[27,21],"o":2},"signal_strength":{"a":"Antenna with Bars","b":"1F4F6","j":["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],"k":[27,19],"o":2},"chocolate_bar":{"a":"Chocolate Bar","b":"1F36B","j":["food","snack","dessert","sweet"],"k":[7,10],"o":2},"manual_wheelchair":{"a":"Manual Wheelchair","b":"1F9BD","k":[44,5],"o":12},"snail":{"a":"Snail","b":"1F40C","j":["slow","animal","shell"],"k":[11,40],"o":2},"motorized_wheelchair":{"a":"Motorized Wheelchair","b":"1F9BC","k":[44,4],"o":12},"flag-gi":{"a":"Gibraltar Flag","b":"1F1EC-1F1EE","k":[2,4],"o":2},"hankey":{"a":"Pile of Poo","b":"1F4A9","k":[25,51],"n":["poop","shit"],"o":2},"vibration_mode":{"a":"Vibration Mode","b":"1F4F3","j":["orange-square","phone"],"k":[27,16],"o":2},"deaf_woman":{"skin_variations":{"1F3FB":{"unified":"1F9CF-1F3FB-200D-2640-FE0F","non_qualified":"1F9CF-1F3FB-200D-2640","image":"1f9cf-1f3fb-200d-2640-fe0f.png","sheet_x":44,"sheet_y":56,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F9CF-1F3FC-200D-2640-FE0F","non_qualified":"1F9CF-1F3FC-200D-2640","image":"1f9cf-1f3fc-200d-2640-fe0f.png","sheet_x":45,"sheet_y":0,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F9CF-1F3FD-200D-2640-FE0F","non_qualified":"1F9CF-1F3FD-200D-2640","image":"1f9cf-1f3fd-200d-2640-fe0f.png","sheet_x":45,"sheet_y":1,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F9CF-1F3FE-200D-2640-FE0F","non_qualified":"1F9CF-1F3FE-200D-2640","image":"1f9cf-1f3fe-200d-2640-fe0f.png","sheet_x":45,"sheet_y":2,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F9CF-1F3FF-200D-2640-FE0F","non_qualified":"1F9CF-1F3FF-200D-2640","image":"1f9cf-1f3ff-200d-2640-fe0f.png","sheet_x":45,"sheet_y":3,"added_in":"12.1","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Deaf Woman","b":"1F9CF-200D-2640-FE0F","c":"1F9CF-200D-2640","k":[44,55],"o":12},"butterfly":{"a":"Butterfly","b":"1F98B","j":["animal","insect","nature","caterpillar"],"k":[42,29],"o":4},"video_camera":{"a":"Video Camera","b":"1F4F9","j":["film","record"],"k":[27,22],"o":2},"candy":{"a":"Candy","b":"1F36C","j":["snack","dessert","sweet","lolly"],"k":[7,11],"o":2},"auto_rickshaw":{"a":"Auto Rickshaw","b":"1F6FA","k":[37,2],"o":12},"bow":{"skin_variations":{"1F3FB":{"unified":"1F647-1F3FB","non_qualified":null,"image":"1f647-1f3fb.png","sheet_x":32,"sheet_y":39,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FC":{"unified":"1F647-1F3FC","non_qualified":null,"image":"1f647-1f3fc.png","sheet_x":32,"sheet_y":40,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FD":{"unified":"1F647-1F3FD","non_qualified":null,"image":"1f647-1f3fd.png","sheet_x":32,"sheet_y":41,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FE":{"unified":"1F647-1F3FE","non_qualified":null,"image":"1f647-1f3fe.png","sheet_x":32,"sheet_y":42,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FF":{"unified":"1F647-1F3FF","non_qualified":null,"image":"1f647-1f3ff.png","sheet_x":32,"sheet_y":43,"added_in":"2.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false}},"obsoleted_by":"1F647-200D-2642-FE0F","a":"Person Bowing Deeply","b":"1F647","k":[32,38],"o":2},"mobile_phone_off":{"a":"Mobile Phone off","b":"1F4F4","j":["mute","orange-square","silence","quiet"],"k":[27,17],"o":2},"clown_face":{"a":"Clown Face","b":"1F921","j":["face"],"k":[38,18],"o":4},"lollipop":{"a":"Lollipop","b":"1F36D","j":["food","snack","candy","sweet"],"k":[7,12],"o":2},"flag-gl":{"a":"Greenland Flag","b":"1F1EC-1F1F1","k":[2,5],"o":2},"vhs":{"a":"Videocassette","b":"1F4FC","j":["record","video","oldschool","90s","80s"],"k":[27,25],"o":2},"bug":{"a":"Bug","b":"1F41B","j":["animal","insect","nature","worm"],"k":[11,56],"o":2},"bike":{"a":"Bicycle","b":"1F6B2","j":["sports","bicycle","exercise","hipster"],"k":[35,9],"o":2},"man-bowing":{"skin_variations":{"1F3FB":{"unified":"1F647-1F3FB-200D-2642-FE0F","non_qualified":"1F647-1F3FB-200D-2642","image":"1f647-1f3fb-200d-2642-fe0f.png","sheet_x":32,"sheet_y":33,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F647-1F3FC-200D-2642-FE0F","non_qualified":"1F647-1F3FC-200D-2642","image":"1f647-1f3fc-200d-2642-fe0f.png","sheet_x":32,"sheet_y":34,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F647-1F3FD-200D-2642-FE0F","non_qualified":"1F647-1F3FD-200D-2642","image":"1f647-1f3fd-200d-2642-fe0f.png","sheet_x":32,"sheet_y":35,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F647-1F3FE-200D-2642-FE0F","non_qualified":"1F647-1F3FE-200D-2642","image":"1f647-1f3fe-200d-2642-fe0f.png","sheet_x":32,"sheet_y":36,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F647-1F3FF-200D-2642-FE0F","non_qualified":"1F647-1F3FF-200D-2642","image":"1f647-1f3ff-200d-2642-fe0f.png","sheet_x":32,"sheet_y":37,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"obsoletes":"1F647","a":"Man Bowing","b":"1F647-200D-2642-FE0F","c":"1F647-200D-2642","k":[32,32],"o":4},"japanese_ogre":{"a":"Japanese Ogre","b":"1F479","j":["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],"k":[23,34],"o":2},"custard":{"a":"Custard","b":"1F36E","j":["dessert","food"],"k":[7,13],"o":2},"ant":{"a":"Ant","b":"1F41C","j":["animal","insect","nature","bug"],"k":[12,0],"o":2},"mag":{"a":"Left-Pointing Magnifying Glass","b":"1F50D","j":["search","zoom","find","detective"],"k":[27,41],"o":2},"flag-gm":{"a":"Gambia Flag","b":"1F1EC-1F1F2","k":[2,6],"o":2},"honey_pot":{"a":"Honey Pot","b":"1F36F","j":["bees","sweet","kitchen"],"k":[7,14],"o":2},"woman-bowing":{"skin_variations":{"1F3FB":{"unified":"1F647-1F3FB-200D-2640-FE0F","non_qualified":"1F647-1F3FB-200D-2640","image":"1f647-1f3fb-200d-2640-fe0f.png","sheet_x":32,"sheet_y":27,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F647-1F3FC-200D-2640-FE0F","non_qualified":"1F647-1F3FC-200D-2640","image":"1f647-1f3fc-200d-2640-fe0f.png","sheet_x":32,"sheet_y":28,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F647-1F3FD-200D-2640-FE0F","non_qualified":"1F647-1F3FD-200D-2640","image":"1f647-1f3fd-200d-2640-fe0f.png","sheet_x":32,"sheet_y":29,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F647-1F3FE-200D-2640-FE0F","non_qualified":"1F647-1F3FE-200D-2640","image":"1f647-1f3fe-200d-2640-fe0f.png","sheet_x":32,"sheet_y":30,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F647-1F3FF-200D-2640-FE0F","non_qualified":"1F647-1F3FF-200D-2640","image":"1f647-1f3ff-200d-2640-fe0f.png","sheet_x":32,"sheet_y":31,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Woman Bowing","b":"1F647-200D-2640-FE0F","c":"1F647-200D-2640","k":[32,26],"o":4},"mag_right":{"a":"Right-Pointing Magnifying Glass","b":"1F50E","j":["search","zoom","find","detective"],"k":[27,42],"o":2},"japanese_goblin":{"a":"Japanese Goblin","b":"1F47A","j":["red","evil","mask","monster","scary","creepy","japanese","goblin"],"k":[23,35],"o":2},"scooter":{"a":"Scooter","b":"1F6F4","k":[36,53],"o":4},"bee":{"a":"Honeybee","b":"1F41D","k":[12,1],"n":["honeybee"],"o":2},"flag-gn":{"a":"Guinea Flag","b":"1F1EC-1F1F3","k":[2,7],"o":2},"candle":{"a":"Candle","b":"1F56F-FE0F","c":"1F56F","j":["fire","wax"],"k":[29,6],"o":2},"skateboard":{"a":"Skateboard","b":"1F6F9","k":[37,1],"o":11},"ghost":{"a":"Ghost","b":"1F47B","j":["halloween","spooky","scary"],"k":[23,36],"o":2},"beetle":{"a":"Lady Beetle","b":"1F41E","j":["animal","insect","nature","ladybug"],"k":[12,2],"o":2},"face_palm":{"skin_variations":{"1F3FB":{"unified":"1F926-1F3FB","non_qualified":null,"image":"1f926-1f3fb.png","sheet_x":38,"sheet_y":36,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FC":{"unified":"1F926-1F3FC","non_qualified":null,"image":"1f926-1f3fc.png","sheet_x":38,"sheet_y":37,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FD":{"unified":"1F926-1F3FD","non_qualified":null,"image":"1f926-1f3fd.png","sheet_x":38,"sheet_y":38,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FE":{"unified":"1F926-1F3FE","non_qualified":null,"image":"1f926-1f3fe.png","sheet_x":38,"sheet_y":39,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FF":{"unified":"1F926-1F3FF","non_qualified":null,"image":"1f926-1f3ff.png","sheet_x":38,"sheet_y":40,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false}},"a":"Face Palm","b":"1F926","k":[38,35],"o":4},"flag-gp":{"a":"Guadeloupe Flag","b":"1F1EC-1F1F5","k":[2,8],"o":2},"baby_bottle":{"a":"Baby Bottle","b":"1F37C","j":["food","container","milk"],"k":[7,27],"o":2},"infinity":{"a":"Infinity","b":"267E-FE0F","c":"267E","k":[53,39],"o":11},"glass_of_milk":{"a":"Glass of Milk","b":"1F95B","k":[41,42],"o":4},"man-facepalming":{"skin_variations":{"1F3FB":{"unified":"1F926-1F3FB-200D-2642-FE0F","non_qualified":"1F926-1F3FB-200D-2642","image":"1f926-1f3fb-200d-2642-fe0f.png","sheet_x":38,"sheet_y":30,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F926-1F3FC-200D-2642-FE0F","non_qualified":"1F926-1F3FC-200D-2642","image":"1f926-1f3fc-200d-2642-fe0f.png","sheet_x":38,"sheet_y":31,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F926-1F3FD-200D-2642-FE0F","non_qualified":"1F926-1F3FD-200D-2642","image":"1f926-1f3fd-200d-2642-fe0f.png","sheet_x":38,"sheet_y":32,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F926-1F3FE-200D-2642-FE0F","non_qualified":"1F926-1F3FE-200D-2642","image":"1f926-1f3fe-200d-2642-fe0f.png","sheet_x":38,"sheet_y":33,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F926-1F3FF-200D-2642-FE0F","non_qualified":"1F926-1F3FF-200D-2642","image":"1f926-1f3ff-200d-2642-fe0f.png","sheet_x":38,"sheet_y":34,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Man Facepalming","b":"1F926-200D-2642-FE0F","c":"1F926-200D-2642","k":[38,29],"o":4},"cricket":{"a":"Cricket","b":"1F997","j":["sports"],"k":[42,41],"o":5},"busstop":{"a":"Bus Stop","b":"1F68F","j":["transportation","wait"],"k":[34,14],"o":2},"flag-gq":{"a":"Equatorial Guinea Flag","b":"1F1EC-1F1F6","k":[2,9],"o":2},"alien":{"a":"Extraterrestrial Alien","b":"1F47D","j":["UFO","paul","weird","outer_space"],"k":[23,43],"o":2},"bulb":{"a":"Electric Light Bulb","b":"1F4A1","j":["light","electricity","idea"],"k":[25,43],"o":2},"woman-facepalming":{"skin_variations":{"1F3FB":{"unified":"1F926-1F3FB-200D-2640-FE0F","non_qualified":"1F926-1F3FB-200D-2640","image":"1f926-1f3fb-200d-2640-fe0f.png","sheet_x":38,"sheet_y":24,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F926-1F3FC-200D-2640-FE0F","non_qualified":"1F926-1F3FC-200D-2640","image":"1f926-1f3fc-200d-2640-fe0f.png","sheet_x":38,"sheet_y":25,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F926-1F3FD-200D-2640-FE0F","non_qualified":"1F926-1F3FD-200D-2640","image":"1f926-1f3fd-200d-2640-fe0f.png","sheet_x":38,"sheet_y":26,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F926-1F3FE-200D-2640-FE0F","non_qualified":"1F926-1F3FE-200D-2640","image":"1f926-1f3fe-200d-2640-fe0f.png","sheet_x":38,"sheet_y":27,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F926-1F3FF-200D-2640-FE0F","non_qualified":"1F926-1F3FF-200D-2640","image":"1f926-1f3ff-200d-2640-fe0f.png","sheet_x":38,"sheet_y":28,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Woman Facepalming","b":"1F926-200D-2640-FE0F","c":"1F926-200D-2640","k":[38,23],"o":4},"spider":{"a":"Spider","b":"1F577-FE0F","c":"1F577","j":["animal","arachnid"],"k":[29,34],"o":2},"space_invader":{"a":"Alien Monster","b":"1F47E","j":["game","arcade","play"],"k":[23,44],"o":2},"motorway":{"a":"Motorway","b":"1F6E3-FE0F","c":"1F6E3","j":["road","cupertino","interstate","highway"],"k":[36,45],"o":2},"flag-gr":{"a":"Greece Flag","b":"1F1EC-1F1F7","k":[2,10],"o":2},"recycle":{"a":"Black Universal Recycling Symbol","b":"267B-FE0F","c":"267B","j":["arrow","environment","garbage","trash"],"k":[53,38],"o":2},"coffee":{"a":"Hot Beverage","b":"2615","j":["beverage","caffeine","latte","espresso"],"k":[53,0],"o":2},"flashlight":{"a":"Electric Torch","b":"1F526","j":["dark","camping","sight","night"],"k":[28,9],"o":2},"spider_web":{"a":"Spider Web","b":"1F578-FE0F","c":"1F578","j":["animal","insect","arachnid","silk"],"k":[29,35],"o":2},"izakaya_lantern":{"a":"Izakaya Lantern","b":"1F3EE","j":["light","paper","halloween","spooky"],"k":[11,8],"n":["lantern"],"o":2},"flag-gs":{"a":"South Georgia & South Sandwich Islands Flag","b":"1F1EC-1F1F8","k":[2,11],"o":2},"shrug":{"skin_variations":{"1F3FB":{"unified":"1F937-1F3FB","non_qualified":null,"image":"1f937-1f3fb.png","sheet_x":39,"sheet_y":48,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FC":{"unified":"1F937-1F3FC","non_qualified":null,"image":"1f937-1f3fc.png","sheet_x":39,"sheet_y":49,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FD":{"unified":"1F937-1F3FD","non_qualified":null,"image":"1f937-1f3fd.png","sheet_x":39,"sheet_y":50,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FE":{"unified":"1F937-1F3FE","non_qualified":null,"image":"1f937-1f3fe.png","sheet_x":39,"sheet_y":51,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false},"1F3FF":{"unified":"1F937-1F3FF","non_qualified":null,"image":"1f937-1f3ff.png","sheet_x":39,"sheet_y":52,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":false}},"a":"Shrug","b":"1F937","k":[39,47],"o":4},"fleur_de_lis":{"a":"Fleur De Lis","b":"269C-FE0F","c":"269C","j":["decorative","scout"],"k":[53,49],"o":2},"robot_face":{"a":"Robot Face","b":"1F916","k":[37,29],"o":2},"railway_track":{"a":"Railway Track","b":"1F6E4-FE0F","c":"1F6E4","j":["train","transportation"],"k":[36,46],"o":2},"tea":{"a":"Teacup Without Handle","b":"1F375","j":["drink","bowl","breakfast","green","british"],"k":[7,20],"o":2},"flag-gt":{"a":"Guatemala Flag","b":"1F1EC-1F1F9","k":[2,12],"o":2},"oil_drum":{"a":"Oil Drum","b":"1F6E2-FE0F","c":"1F6E2","j":["barrell"],"k":[36,44],"o":2},"diya_lamp":{"a":"Diya Lamp","b":"1FA94","k":[52,8],"o":12},"sake":{"a":"Sake Bottle and Cup","b":"1F376","j":["wine","drink","drunk","beverage","japanese","alcohol","booze"],"k":[7,21],"o":2},"trident":{"a":"Trident Emblem","b":"1F531","j":["weapon","spear"],"k":[28,20],"o":2},"man-shrugging":{"skin_variations":{"1F3FB":{"unified":"1F937-1F3FB-200D-2642-FE0F","non_qualified":"1F937-1F3FB-200D-2642","image":"1f937-1f3fb-200d-2642-fe0f.png","sheet_x":39,"sheet_y":42,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F937-1F3FC-200D-2642-FE0F","non_qualified":"1F937-1F3FC-200D-2642","image":"1f937-1f3fc-200d-2642-fe0f.png","sheet_x":39,"sheet_y":43,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F937-1F3FD-200D-2642-FE0F","non_qualified":"1F937-1F3FD-200D-2642","image":"1f937-1f3fd-200d-2642-fe0f.png","sheet_x":39,"sheet_y":44,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F937-1F3FE-200D-2642-FE0F","non_qualified":"1F937-1F3FE-200D-2642","image":"1f937-1f3fe-200d-2642-fe0f.png","sheet_x":39,"sheet_y":45,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F937-1F3FF-200D-2642-FE0F","non_qualified":"1F937-1F3FF-200D-2642","image":"1f937-1f3ff-200d-2642-fe0f.png","sheet_x":39,"sheet_y":46,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Man Shrugging","b":"1F937-200D-2642-FE0F","c":"1F937-200D-2642","k":[39,41],"o":4},"smiley_cat":{"a":"Smiling Cat Face with Open Mouth","b":"1F63A","j":["animal","cats","happy","smile"],"k":[31,36],"o":2},"scorpion":{"a":"Scorpion","b":"1F982","j":["animal","arachnid"],"k":[42,20],"o":2},"woman-shrugging":{"skin_variations":{"1F3FB":{"unified":"1F937-1F3FB-200D-2640-FE0F","non_qualified":"1F937-1F3FB-200D-2640","image":"1f937-1f3fb-200d-2640-fe0f.png","sheet_x":39,"sheet_y":36,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F937-1F3FC-200D-2640-FE0F","non_qualified":"1F937-1F3FC-200D-2640","image":"1f937-1f3fc-200d-2640-fe0f.png","sheet_x":39,"sheet_y":37,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F937-1F3FD-200D-2640-FE0F","non_qualified":"1F937-1F3FD-200D-2640","image":"1f937-1f3fd-200d-2640-fe0f.png","sheet_x":39,"sheet_y":38,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F937-1F3FE-200D-2640-FE0F","non_qualified":"1F937-1F3FE-200D-2640","image":"1f937-1f3fe-200d-2640-fe0f.png","sheet_x":39,"sheet_y":39,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F937-1F3FF-200D-2640-FE0F","non_qualified":"1F937-1F3FF-200D-2640","image":"1f937-1f3ff-200d-2640-fe0f.png","sheet_x":39,"sheet_y":40,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Woman Shrugging","b":"1F937-200D-2640-FE0F","c":"1F937-200D-2640","k":[39,35],"o":4},"notebook_with_decorative_cover":{"a":"Notebook with Decorative Cover","b":"1F4D4","j":["classroom","notes","record","paper","study"],"k":[26,42],"o":2},"fuelpump":{"a":"Fuel Pump","b":"26FD","j":["gas station","petroleum"],"k":[54,38],"o":2},"name_badge":{"a":"Name Badge","b":"1F4DB","j":["fire","forbid"],"k":[26,49],"o":2},"mosquito":{"a":"Mosquito","b":"1F99F","k":[42,49],"o":11},"flag-gu":{"a":"Guam Flag","b":"1F1EC-1F1FA","k":[2,13],"o":2},"smile_cat":{"a":"Grinning Cat Face with Smiling Eyes","b":"1F638","j":["animal","cats","smile"],"k":[31,34],"o":2},"champagne":{"a":"Bottle with Popping Cork","b":"1F37E","j":["drink","wine","bottle","celebration"],"k":[7,29],"o":2},"joy_cat":{"a":"Cat Face with Tears of Joy","b":"1F639","j":["animal","cats","haha","happy","tears"],"k":[31,35],"o":2},"closed_book":{"a":"Closed Book","b":"1F4D5","j":["read","library","knowledge","textbook","learn"],"k":[26,43],"o":2},"health_worker":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB-200D-2695-FE0F","non_qualified":"1F9D1-1F3FB-200D-2695","image":"1f9d1-1f3fb-200d-2695-fe0f.png","sheet_x":47,"sheet_y":50,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FC":{"unified":"1F9D1-1F3FC-200D-2695-FE0F","non_qualified":"1F9D1-1F3FC-200D-2695","image":"1f9d1-1f3fc-200d-2695-fe0f.png","sheet_x":47,"sheet_y":51,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FD":{"unified":"1F9D1-1F3FD-200D-2695-FE0F","non_qualified":"1F9D1-1F3FD-200D-2695","image":"1f9d1-1f3fd-200d-2695-fe0f.png","sheet_x":47,"sheet_y":52,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FE":{"unified":"1F9D1-1F3FE-200D-2695-FE0F","non_qualified":"1F9D1-1F3FE-200D-2695","image":"1f9d1-1f3fe-200d-2695-fe0f.png","sheet_x":47,"sheet_y":53,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FF":{"unified":"1F9D1-1F3FF-200D-2695-FE0F","non_qualified":"1F9D1-1F3FF-200D-2695","image":"1f9d1-1f3ff-200d-2695-fe0f.png","sheet_x":47,"sheet_y":54,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false}},"a":"Health Worker","b":"1F9D1-200D-2695-FE0F","c":"1F9D1-200D-2695","k":[47,49],"o":12},"rotating_light":{"a":"Police Cars Revolving Light","b":"1F6A8","j":["police","ambulance","911","emergency","alert","error","pinged","law","legal"],"k":[34,56],"o":2},"microbe":{"a":"Microbe","b":"1F9A0","k":[42,50],"o":11},"flag-gw":{"a":"Guinea-Bissau Flag","b":"1F1EC-1F1FC","k":[2,14],"o":2},"wine_glass":{"a":"Wine Glass","b":"1F377","j":["drink","beverage","drunk","alcohol","booze"],"k":[7,22],"o":2},"beginner":{"a":"Japanese Symbol for Beginner","b":"1F530","j":["badge","shield"],"k":[28,19],"o":2},"bouquet":{"a":"Bouquet","b":"1F490","j":["flowers","nature","spring"],"k":[25,26],"o":2},"heart_eyes_cat":{"a":"Smiling Cat Face with Heart-Shaped Eyes","b":"1F63B","j":["animal","love","like","affection","cats","valentines","heart"],"k":[31,37],"o":2},"male-doctor":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-2695-FE0F","non_qualified":"1F468-1F3FB-200D-2695","image":"1f468-1f3fb-200d-2695-fe0f.png","sheet_x":17,"sheet_y":3,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F468-1F3FC-200D-2695-FE0F","non_qualified":"1F468-1F3FC-200D-2695","image":"1f468-1f3fc-200d-2695-fe0f.png","sheet_x":17,"sheet_y":4,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F468-1F3FD-200D-2695-FE0F","non_qualified":"1F468-1F3FD-200D-2695","image":"1f468-1f3fd-200d-2695-fe0f.png","sheet_x":17,"sheet_y":5,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F468-1F3FE-200D-2695-FE0F","non_qualified":"1F468-1F3FE-200D-2695","image":"1f468-1f3fe-200d-2695-fe0f.png","sheet_x":17,"sheet_y":6,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F468-1F3FF-200D-2695-FE0F","non_qualified":"1F468-1F3FF-200D-2695","image":"1f468-1f3ff-200d-2695-fe0f.png","sheet_x":17,"sheet_y":7,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Male Doctor","b":"1F468-200D-2695-FE0F","c":"1F468-200D-2695","k":[17,2],"o":4},"book":{"a":"Open Book","b":"1F4D6","k":[26,44],"n":["open_book"],"o":2},"traffic_light":{"a":"Horizontal Traffic Light","b":"1F6A5","j":["transportation","signal"],"k":[34,53],"o":2},"cocktail":{"a":"Cocktail Glass","b":"1F378","j":["drink","drunk","alcohol","beverage","booze","mojito"],"k":[7,23],"o":2},"o":{"a":"Heavy Large Circle","b":"2B55","j":["circle","round"],"k":[55,43],"o":2},"flag-gy":{"a":"Guyana Flag","b":"1F1EC-1F1FE","k":[2,15],"o":2},"female-doctor":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-2695-FE0F","non_qualified":"1F469-1F3FB-200D-2695","image":"1f469-1f3fb-200d-2695-fe0f.png","sheet_x":19,"sheet_y":45,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F469-1F3FC-200D-2695-FE0F","non_qualified":"1F469-1F3FC-200D-2695","image":"1f469-1f3fc-200d-2695-fe0f.png","sheet_x":19,"sheet_y":46,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F469-1F3FD-200D-2695-FE0F","non_qualified":"1F469-1F3FD-200D-2695","image":"1f469-1f3fd-200d-2695-fe0f.png","sheet_x":19,"sheet_y":47,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F469-1F3FE-200D-2695-FE0F","non_qualified":"1F469-1F3FE-200D-2695","image":"1f469-1f3fe-200d-2695-fe0f.png","sheet_x":19,"sheet_y":48,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F469-1F3FF-200D-2695-FE0F","non_qualified":"1F469-1F3FF-200D-2695","image":"1f469-1f3ff-200d-2695-fe0f.png","sheet_x":19,"sheet_y":49,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Female Doctor","b":"1F469-200D-2695-FE0F","c":"1F469-200D-2695","k":[19,44],"o":4},"smirk_cat":{"a":"Cat Face with Wry Smile","b":"1F63C","j":["animal","cats","smirk"],"k":[31,38],"o":2},"green_book":{"a":"Green Book","b":"1F4D7","j":["read","library","knowledge","study"],"k":[26,45],"o":2},"cherry_blossom":{"a":"Cherry Blossom","b":"1F338","j":["nature","plant","spring","flower"],"k":[6,16],"o":2},"flag-hk":{"a":"Hong Kong Sar China Flag","b":"1F1ED-1F1F0","k":[2,16],"o":2},"vertical_traffic_light":{"a":"Vertical Traffic Light","b":"1F6A6","j":["transportation","driving"],"k":[34,54],"o":2},"white_check_mark":{"a":"White Heavy Check Mark","b":"2705","j":["green-square","ok","agree","vote","election","answer","tick"],"k":[54,40],"o":2},"tropical_drink":{"a":"Tropical Drink","b":"1F379","j":["beverage","cocktail","summer","beach","alcohol","booze","mojito"],"k":[7,24],"o":2},"kissing_cat":{"a":"Kissing Cat Face with Closed Eyes","b":"1F63D","j":["animal","cats","kiss"],"k":[31,39],"o":2},"flag-hm":{"a":"Heard & Mcdonald Islands Flag","b":"1F1ED-1F1F2","k":[2,17],"o":2},"octagonal_sign":{"a":"Octagonal Sign","b":"1F6D1","k":[36,39],"o":4},"white_flower":{"a":"White Flower","b":"1F4AE","j":["japanese","spring"],"k":[26,4],"o":2},"ballot_box_with_check":{"a":"Ballot Box with Check","b":"2611-FE0F","c":"2611","j":["ok","agree","confirm","black-square","vote","election","yes","tick"],"k":[52,55],"o":2},"student":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB-200D-1F393","non_qualified":null,"image":"1f9d1-1f3fb-200d-1f393.png","sheet_x":45,"sheet_y":30,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FC":{"unified":"1F9D1-1F3FC-200D-1F393","non_qualified":null,"image":"1f9d1-1f3fc-200d-1f393.png","sheet_x":45,"sheet_y":31,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FD":{"unified":"1F9D1-1F3FD-200D-1F393","non_qualified":null,"image":"1f9d1-1f3fd-200d-1f393.png","sheet_x":45,"sheet_y":32,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FE":{"unified":"1F9D1-1F3FE-200D-1F393","non_qualified":null,"image":"1f9d1-1f3fe-200d-1f393.png","sheet_x":45,"sheet_y":33,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FF":{"unified":"1F9D1-1F3FF-200D-1F393","non_qualified":null,"image":"1f9d1-1f3ff-200d-1f393.png","sheet_x":45,"sheet_y":34,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false}},"a":"Student","b":"1F9D1-200D-1F393","k":[45,29],"o":12},"blue_book":{"a":"Blue Book","b":"1F4D8","j":["read","library","knowledge","learn","study"],"k":[26,46],"o":2},"beer":{"a":"Beer Mug","b":"1F37A","j":["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],"k":[7,25],"o":2},"construction":{"a":"Construction Sign","b":"1F6A7","j":["wip","progress","caution","warning"],"k":[34,55],"o":2},"rosette":{"a":"Rosette","b":"1F3F5-FE0F","c":"1F3F5","j":["flower","decoration","military"],"k":[11,18],"o":2},"heavy_check_mark":{"a":"Heavy Check Mark","b":"2714-FE0F","c":"2714","j":["ok","nike","answer","yes","tick"],"k":[55,12],"o":2},"scream_cat":{"a":"Weary Cat Face","b":"1F640","j":["animal","cats","munch","scared","scream"],"k":[31,42],"o":2},"orange_book":{"a":"Orange Book","b":"1F4D9","j":["read","library","knowledge","textbook","study"],"k":[26,47],"o":2},"beers":{"a":"Clinking Beer Mugs","b":"1F37B","j":["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],"k":[7,26],"o":2},"male-student":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F393","non_qualified":null,"image":"1f468-1f3fb-200d-1f393.png","sheet_x":14,"sheet_y":51,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F468-1F3FC-200D-1F393","non_qualified":null,"image":"1f468-1f3fc-200d-1f393.png","sheet_x":14,"sheet_y":52,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F468-1F3FD-200D-1F393","non_qualified":null,"image":"1f468-1f3fd-200d-1f393.png","sheet_x":14,"sheet_y":53,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F468-1F3FE-200D-1F393","non_qualified":null,"image":"1f468-1f3fe-200d-1f393.png","sheet_x":14,"sheet_y":54,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F468-1F3FF-200D-1F393","non_qualified":null,"image":"1f468-1f3ff-200d-1f393.png","sheet_x":14,"sheet_y":55,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Male Student","b":"1F468-200D-1F393","k":[14,50],"o":4},"flag-hn":{"a":"Honduras Flag","b":"1F1ED-1F1F3","k":[2,18],"o":2},"crying_cat_face":{"a":"Crying Cat Face","b":"1F63F","j":["animal","tears","weep","sad","cats","upset","cry"],"k":[31,41],"o":2},"anchor":{"a":"Anchor","b":"2693","j":["ship","ferry","sea","boat"],"k":[53,42],"o":2},"flag-hr":{"a":"Croatia Flag","b":"1F1ED-1F1F7","k":[2,19],"o":2},"heavy_multiplication_x":{"a":"Heavy Multiplication X","b":"2716-FE0F","c":"2716","j":["math","calculation"],"k":[55,13],"o":2},"female-student":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F393","non_qualified":null,"image":"1f469-1f3fb-200d-1f393.png","sheet_x":17,"sheet_y":41,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F469-1F3FC-200D-1F393","non_qualified":null,"image":"1f469-1f3fc-200d-1f393.png","sheet_x":17,"sheet_y":42,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F469-1F3FD-200D-1F393","non_qualified":null,"image":"1f469-1f3fd-200d-1f393.png","sheet_x":17,"sheet_y":43,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F469-1F3FE-200D-1F393","non_qualified":null,"image":"1f469-1f3fe-200d-1f393.png","sheet_x":17,"sheet_y":44,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F469-1F3FF-200D-1F393","non_qualified":null,"image":"1f469-1f3ff-200d-1f393.png","sheet_x":17,"sheet_y":45,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Female Student","b":"1F469-200D-1F393","k":[17,40],"o":4},"rose":{"a":"Rose","b":"1F339","j":["flowers","valentines","love","spring"],"k":[6,17],"o":2},"books":{"a":"Books","b":"1F4DA","j":["literature","library","study"],"k":[26,48],"o":2},"clinking_glasses":{"a":"Clinking Glasses","b":"1F942","j":["beverage","drink","party","alcohol","celebrate","cheers"],"k":[41,18],"o":4},"teacher":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB-200D-1F3EB","non_qualified":null,"image":"1f9d1-1f3fb-200d-1f3eb.png","sheet_x":45,"sheet_y":48,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FC":{"unified":"1F9D1-1F3FC-200D-1F3EB","non_qualified":null,"image":"1f9d1-1f3fc-200d-1f3eb.png","sheet_x":45,"sheet_y":49,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FD":{"unified":"1F9D1-1F3FD-200D-1F3EB","non_qualified":null,"image":"1f9d1-1f3fd-200d-1f3eb.png","sheet_x":45,"sheet_y":50,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FE":{"unified":"1F9D1-1F3FE-200D-1F3EB","non_qualified":null,"image":"1f9d1-1f3fe-200d-1f3eb.png","sheet_x":45,"sheet_y":51,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FF":{"unified":"1F9D1-1F3FF-200D-1F3EB","non_qualified":null,"image":"1f9d1-1f3ff-200d-1f3eb.png","sheet_x":45,"sheet_y":52,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false}},"a":"Teacher","b":"1F9D1-200D-1F3EB","k":[45,47],"o":12},"x":{"a":"Cross Mark","b":"274C","j":["no","delete","remove","cancel"],"k":[55,21],"o":2},"pouting_cat":{"a":"Pouting Cat Face","b":"1F63E","j":["animal","cats"],"k":[31,40],"o":2},"wilted_flower":{"a":"Wilted Flower","b":"1F940","j":["plant","nature","flower"],"k":[41,16],"o":4},"boat":{"a":"Sailboat","b":"26F5","k":[54,16],"n":["sailboat"],"o":2},"flag-ht":{"a":"Haiti Flag","b":"1F1ED-1F1F9","k":[2,20],"o":2},"tumbler_glass":{"a":"Tumbler Glass","b":"1F943","j":["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],"k":[41,19],"o":4},"notebook":{"a":"Notebook","b":"1F4D3","j":["stationery","record","notes","paper","study"],"k":[26,41],"o":2},"male-teacher":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F3EB","non_qualified":null,"image":"1f468-1f3fb-200d-1f3eb.png","sheet_x":15,"sheet_y":12,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F468-1F3FC-200D-1F3EB","non_qualified":null,"image":"1f468-1f3fc-200d-1f3eb.png","sheet_x":15,"sheet_y":13,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F468-1F3FD-200D-1F3EB","non_qualified":null,"image":"1f468-1f3fd-200d-1f3eb.png","sheet_x":15,"sheet_y":14,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F468-1F3FE-200D-1F3EB","non_qualified":null,"image":"1f468-1f3fe-200d-1f3eb.png","sheet_x":15,"sheet_y":15,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F468-1F3FF-200D-1F3EB","non_qualified":null,"image":"1f468-1f3ff-200d-1f3eb.png","sheet_x":15,"sheet_y":16,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Male Teacher","b":"1F468-200D-1F3EB","k":[15,11],"o":4},"ledger":{"a":"Ledger","b":"1F4D2","j":["notes","paper"],"k":[26,40],"o":2},"flag-hu":{"a":"Hungary Flag","b":"1F1ED-1F1FA","k":[2,21],"o":2},"cup_with_straw":{"a":"Cup with Straw","b":"1F964","k":[41,51],"o":5},"hibiscus":{"a":"Hibiscus","b":"1F33A","j":["plant","vegetable","flowers","beach"],"k":[6,18],"o":2},"see_no_evil":{"a":"See-No-Evil Monkey","b":"1F648","j":["monkey","animal","nature","haha"],"k":[32,44],"o":2},"canoe":{"a":"Canoe","b":"1F6F6","j":["boat","paddle","water","ship"],"k":[36,55],"o":4},"negative_squared_cross_mark":{"a":"Negative Squared Cross Mark","b":"274E","j":["x","green-square","no","deny"],"k":[55,22],"o":2},"flag-ic":{"a":"Canary Islands Flag","b":"1F1EE-1F1E8","k":[2,22],"o":2},"beverage_box":{"a":"Beverage Box","b":"1F9C3","k":[44,11],"o":12},"speedboat":{"a":"Speedboat","b":"1F6A4","j":["ship","transportation","vehicle","summer"],"k":[34,52],"o":2},"heavy_plus_sign":{"a":"Heavy Plus Sign","b":"2795","j":["math","calculation","addition","more","increase"],"k":[55,29],"o":2},"sunflower":{"a":"Sunflower","b":"1F33B","j":["nature","plant","fall"],"k":[6,19],"o":2},"page_with_curl":{"a":"Page with Curl","b":"1F4C3","j":["documents","office","paper"],"k":[26,25],"o":2},"female-teacher":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F3EB","non_qualified":null,"image":"1f469-1f3fb-200d-1f3eb.png","sheet_x":18,"sheet_y":2,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F469-1F3FC-200D-1F3EB","non_qualified":null,"image":"1f469-1f3fc-200d-1f3eb.png","sheet_x":18,"sheet_y":3,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F469-1F3FD-200D-1F3EB","non_qualified":null,"image":"1f469-1f3fd-200d-1f3eb.png","sheet_x":18,"sheet_y":4,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F469-1F3FE-200D-1F3EB","non_qualified":null,"image":"1f469-1f3fe-200d-1f3eb.png","sheet_x":18,"sheet_y":5,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F469-1F3FF-200D-1F3EB","non_qualified":null,"image":"1f469-1f3ff-200d-1f3eb.png","sheet_x":18,"sheet_y":6,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Female Teacher","b":"1F469-200D-1F3EB","k":[18,1],"o":4},"hear_no_evil":{"a":"Hear-No-Evil Monkey","b":"1F649","j":["animal","monkey","nature"],"k":[32,45],"o":2},"mate_drink":{"a":"Mate Drink","b":"1F9C9","k":[44,17],"o":12},"passenger_ship":{"a":"Passenger Ship","b":"1F6F3-FE0F","c":"1F6F3","j":["yacht","cruise","ferry"],"k":[36,52],"o":2},"judge":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB-200D-2696-FE0F","non_qualified":"1F9D1-1F3FB-200D-2696","image":"1f9d1-1f3fb-200d-2696-fe0f.png","sheet_x":47,"sheet_y":56,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FC":{"unified":"1F9D1-1F3FC-200D-2696-FE0F","non_qualified":"1F9D1-1F3FC-200D-2696","image":"1f9d1-1f3fc-200d-2696-fe0f.png","sheet_x":48,"sheet_y":0,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FD":{"unified":"1F9D1-1F3FD-200D-2696-FE0F","non_qualified":"1F9D1-1F3FD-200D-2696","image":"1f9d1-1f3fd-200d-2696-fe0f.png","sheet_x":48,"sheet_y":1,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FE":{"unified":"1F9D1-1F3FE-200D-2696-FE0F","non_qualified":"1F9D1-1F3FE-200D-2696","image":"1f9d1-1f3fe-200d-2696-fe0f.png","sheet_x":48,"sheet_y":2,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FF":{"unified":"1F9D1-1F3FF-200D-2696-FE0F","non_qualified":"1F9D1-1F3FF-200D-2696","image":"1f9d1-1f3ff-200d-2696-fe0f.png","sheet_x":48,"sheet_y":3,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false}},"a":"Judge","b":"1F9D1-200D-2696-FE0F","c":"1F9D1-200D-2696","k":[47,55],"o":12},"scroll":{"a":"Scroll","b":"1F4DC","j":["documents","ancient","history","paper"],"k":[26,50],"o":2},"blossom":{"a":"Blossom","b":"1F33C","j":["nature","flowers","yellow"],"k":[6,20],"o":2},"flag-id":{"a":"Indonesia Flag","b":"1F1EE-1F1E9","k":[2,23],"o":2},"speak_no_evil":{"a":"Speak-No-Evil Monkey","b":"1F64A","j":["monkey","animal","nature","omg"],"k":[32,46],"o":2},"heavy_minus_sign":{"a":"Heavy Minus Sign","b":"2796","j":["math","calculation","subtract","less"],"k":[55,30],"o":2},"flag-ie":{"a":"Ireland Flag","b":"1F1EE-1F1EA","k":[2,24],"o":2},"ice_cube":{"a":"Ice Cube","b":"1F9CA","k":[44,18],"o":12},"page_facing_up":{"a":"Page Facing Up","b":"1F4C4","j":["documents","office","paper","information"],"k":[26,26],"o":2},"male-judge":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-2696-FE0F","non_qualified":"1F468-1F3FB-200D-2696","image":"1f468-1f3fb-200d-2696-fe0f.png","sheet_x":17,"sheet_y":9,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F468-1F3FC-200D-2696-FE0F","non_qualified":"1F468-1F3FC-200D-2696","image":"1f468-1f3fc-200d-2696-fe0f.png","sheet_x":17,"sheet_y":10,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F468-1F3FD-200D-2696-FE0F","non_qualified":"1F468-1F3FD-200D-2696","image":"1f468-1f3fd-200d-2696-fe0f.png","sheet_x":17,"sheet_y":11,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F468-1F3FE-200D-2696-FE0F","non_qualified":"1F468-1F3FE-200D-2696","image":"1f468-1f3fe-200d-2696-fe0f.png","sheet_x":17,"sheet_y":12,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F468-1F3FF-200D-2696-FE0F","non_qualified":"1F468-1F3FF-200D-2696","image":"1f468-1f3ff-200d-2696-fe0f.png","sheet_x":17,"sheet_y":13,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Male Judge","b":"1F468-200D-2696-FE0F","c":"1F468-200D-2696","k":[17,8],"o":4},"tulip":{"a":"Tulip","b":"1F337","j":["flowers","plant","nature","summer","spring"],"k":[6,15],"o":2},"ferry":{"a":"Ferry","b":"26F4-FE0F","c":"26F4","j":["boat","ship","yacht"],"k":[54,15],"o":2},"kiss":{"a":"Kiss Mark","b":"1F48B","j":["face","lips","love","like","affection","valentines"],"k":[25,21],"o":2},"heavy_division_sign":{"a":"Heavy Division Sign","b":"2797","j":["divide","math","calculation"],"k":[55,31],"o":2},"newspaper":{"a":"Newspaper","b":"1F4F0","j":["press","headline"],"k":[27,13],"o":2},"female-judge":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-2696-FE0F","non_qualified":"1F469-1F3FB-200D-2696","image":"1f469-1f3fb-200d-2696-fe0f.png","sheet_x":19,"sheet_y":51,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F469-1F3FC-200D-2696-FE0F","non_qualified":"1F469-1F3FC-200D-2696","image":"1f469-1f3fc-200d-2696-fe0f.png","sheet_x":19,"sheet_y":52,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F469-1F3FD-200D-2696-FE0F","non_qualified":"1F469-1F3FD-200D-2696","image":"1f469-1f3fd-200d-2696-fe0f.png","sheet_x":19,"sheet_y":53,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F469-1F3FE-200D-2696-FE0F","non_qualified":"1F469-1F3FE-200D-2696","image":"1f469-1f3fe-200d-2696-fe0f.png","sheet_x":19,"sheet_y":54,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F469-1F3FF-200D-2696-FE0F","non_qualified":"1F469-1F3FF-200D-2696","image":"1f469-1f3ff-200d-2696-fe0f.png","sheet_x":19,"sheet_y":55,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Female Judge","b":"1F469-200D-2696-FE0F","c":"1F469-200D-2696","k":[19,50],"o":4},"seedling":{"a":"Seedling","b":"1F331","j":["plant","nature","grass","lawn","spring"],"k":[6,9],"o":2},"love_letter":{"a":"Love Letter","b":"1F48C","j":["email","like","affection","envelope","valentines"],"k":[25,22],"o":2},"chopsticks":{"a":"Chopsticks","b":"1F962","k":[41,49],"o":5},"motor_boat":{"a":"Motor Boat","b":"1F6E5-FE0F","c":"1F6E5","j":["ship"],"k":[36,47],"o":2},"flag-il":{"a":"Israel Flag","b":"1F1EE-1F1F1","k":[2,25],"o":2},"curly_loop":{"a":"Curly Loop","b":"27B0","j":["scribble","draw","shape","squiggle"],"k":[55,33],"o":2},"flag-im":{"a":"Isle of Man Flag","b":"1F1EE-1F1F2","k":[2,26],"o":2},"evergreen_tree":{"a":"Evergreen Tree","b":"1F332","j":["plant","nature"],"k":[6,10],"o":2},"cupid":{"a":"Heart with Arrow","b":"1F498","j":["love","like","heart","affection","valentines"],"k":[25,34],"o":2},"loop":{"a":"Double Curly Loop","b":"27BF","j":["tape","cassette"],"k":[55,34],"o":2},"ship":{"a":"Ship","b":"1F6A2","j":["transportation","titanic","deploy"],"k":[34,33],"o":2},"farmer":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB-200D-1F33E","non_qualified":null,"image":"1f9d1-1f3fb-200d-1f33e.png","sheet_x":45,"sheet_y":18,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FC":{"unified":"1F9D1-1F3FC-200D-1F33E","non_qualified":null,"image":"1f9d1-1f3fc-200d-1f33e.png","sheet_x":45,"sheet_y":19,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FD":{"unified":"1F9D1-1F3FD-200D-1F33E","non_qualified":null,"image":"1f9d1-1f3fd-200d-1f33e.png","sheet_x":45,"sheet_y":20,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FE":{"unified":"1F9D1-1F3FE-200D-1F33E","non_qualified":null,"image":"1f9d1-1f3fe-200d-1f33e.png","sheet_x":45,"sheet_y":21,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FF":{"unified":"1F9D1-1F3FF-200D-1F33E","non_qualified":null,"image":"1f9d1-1f3ff-200d-1f33e.png","sheet_x":45,"sheet_y":22,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false}},"a":"Farmer","b":"1F9D1-200D-1F33E","k":[45,17],"o":12},"rolled_up_newspaper":{"a":"Rolled Up Newspaper","b":"1F5DE-FE0F","c":"1F5DE","k":[30,23],"o":2},"knife_fork_plate":{"a":"Knife Fork Plate","b":"1F37D-FE0F","c":"1F37D","k":[7,28],"o":2},"fork_and_knife":{"a":"Fork and Knife","b":"1F374","j":["cutlery","kitchen"],"k":[7,19],"o":2},"male-farmer":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F33E","non_qualified":null,"image":"1f468-1f3fb-200d-1f33e.png","sheet_x":14,"sheet_y":39,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F468-1F3FC-200D-1F33E","non_qualified":null,"image":"1f468-1f3fc-200d-1f33e.png","sheet_x":14,"sheet_y":40,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F468-1F3FD-200D-1F33E","non_qualified":null,"image":"1f468-1f3fd-200d-1f33e.png","sheet_x":14,"sheet_y":41,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F468-1F3FE-200D-1F33E","non_qualified":null,"image":"1f468-1f3fe-200d-1f33e.png","sheet_x":14,"sheet_y":42,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F468-1F3FF-200D-1F33E","non_qualified":null,"image":"1f468-1f3ff-200d-1f33e.png","sheet_x":14,"sheet_y":43,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Male Farmer","b":"1F468-200D-1F33E","k":[14,38],"o":4},"bookmark_tabs":{"a":"Bookmark Tabs","b":"1F4D1","j":["favorite","save","order","tidy"],"k":[26,39],"o":2},"part_alternation_mark":{"a":"Part Alternation Mark","b":"303D-FE0F","c":"303D","j":["graph","presentation","stats","business","economics","bad"],"k":[55,45],"o":2},"flag-in":{"a":"India Flag","b":"1F1EE-1F1F3","k":[2,27],"o":2},"gift_heart":{"a":"Heart with Ribbon","b":"1F49D","j":["love","valentines"],"k":[25,39],"o":2},"airplane":{"a":"Airplane","b":"2708-FE0F","c":"2708","j":["vehicle","transportation","flight","fly"],"k":[54,41],"o":2},"deciduous_tree":{"a":"Deciduous Tree","b":"1F333","j":["plant","nature"],"k":[6,11],"o":2},"spoon":{"a":"Spoon","b":"1F944","j":["cutlery","kitchen","tableware"],"k":[41,20],"o":4},"flag-io":{"a":"British Indian Ocean Territory Flag","b":"1F1EE-1F1F4","k":[2,28],"o":2},"palm_tree":{"a":"Palm Tree","b":"1F334","j":["plant","vegetable","nature","summer","beach","mojito","tropical"],"k":[6,12],"o":2},"sparkling_heart":{"a":"Sparkling Heart","b":"1F496","j":["love","like","affection","valentines"],"k":[25,32],"o":2},"female-farmer":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F33E","non_qualified":null,"image":"1f469-1f3fb-200d-1f33e.png","sheet_x":17,"sheet_y":29,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F469-1F3FC-200D-1F33E","non_qualified":null,"image":"1f469-1f3fc-200d-1f33e.png","sheet_x":17,"sheet_y":30,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F469-1F3FD-200D-1F33E","non_qualified":null,"image":"1f469-1f3fd-200d-1f33e.png","sheet_x":17,"sheet_y":31,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F469-1F3FE-200D-1F33E","non_qualified":null,"image":"1f469-1f3fe-200d-1f33e.png","sheet_x":17,"sheet_y":32,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F469-1F3FF-200D-1F33E","non_qualified":null,"image":"1f469-1f3ff-200d-1f33e.png","sheet_x":17,"sheet_y":33,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Female Farmer","b":"1F469-200D-1F33E","k":[17,28],"o":4},"eight_spoked_asterisk":{"a":"Eight Spoked Asterisk","b":"2733-FE0F","c":"2733","j":["star","sparkle","green-square"],"k":[55,17],"o":2},"small_airplane":{"a":"Small Airplane","b":"1F6E9-FE0F","c":"1F6E9","j":["flight","transportation","fly","vehicle"],"k":[36,48],"o":2},"bookmark":{"a":"Bookmark","b":"1F516","j":["favorite","label","save"],"k":[27,50],"o":2},"cook":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB-200D-1F373","non_qualified":null,"image":"1f9d1-1f3fb-200d-1f373.png","sheet_x":45,"sheet_y":24,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FC":{"unified":"1F9D1-1F3FC-200D-1F373","non_qualified":null,"image":"1f9d1-1f3fc-200d-1f373.png","sheet_x":45,"sheet_y":25,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FD":{"unified":"1F9D1-1F3FD-200D-1F373","non_qualified":null,"image":"1f9d1-1f3fd-200d-1f373.png","sheet_x":45,"sheet_y":26,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FE":{"unified":"1F9D1-1F3FE-200D-1F373","non_qualified":null,"image":"1f9d1-1f3fe-200d-1f373.png","sheet_x":45,"sheet_y":27,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FF":{"unified":"1F9D1-1F3FF-200D-1F373","non_qualified":null,"image":"1f9d1-1f3ff-200d-1f373.png","sheet_x":45,"sheet_y":28,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false}},"a":"Cook","b":"1F9D1-200D-1F373","k":[45,23],"o":12},"eight_pointed_black_star":{"a":"Eight Pointed Black Star","b":"2734-FE0F","c":"2734","j":["orange-square","shape","polygon"],"k":[55,18],"o":2},"heartpulse":{"a":"Growing Heart","b":"1F497","j":["like","love","affection","valentines","pink"],"k":[25,33],"o":2},"label":{"a":"Label","b":"1F3F7-FE0F","c":"1F3F7","j":["sale","tag"],"k":[11,19],"o":2},"flag-iq":{"a":"Iraq Flag","b":"1F1EE-1F1F6","k":[2,29],"o":2},"hocho":{"a":"Hocho","b":"1F52A","j":["knife","blade","cutlery","kitchen","weapon"],"k":[28,13],"n":["knife"],"o":2},"cactus":{"a":"Cactus","b":"1F335","j":["vegetable","plant","nature"],"k":[6,13],"o":2},"airplane_departure":{"a":"Airplane Departure","b":"1F6EB","k":[36,49],"o":2},"airplane_arriving":{"a":"Airplane Arriving","b":"1F6EC","k":[36,50],"o":2},"ear_of_rice":{"a":"Ear of Rice","b":"1F33E","j":["nature","plant"],"k":[6,22],"o":2},"flag-ir":{"a":"Iran Flag","b":"1F1EE-1F1F7","k":[2,30],"o":2},"moneybag":{"a":"Money Bag","b":"1F4B0","j":["dollar","payment","coins","sale"],"k":[26,6],"o":2},"male-cook":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F373","non_qualified":null,"image":"1f468-1f3fb-200d-1f373.png","sheet_x":14,"sheet_y":45,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F468-1F3FC-200D-1F373","non_qualified":null,"image":"1f468-1f3fc-200d-1f373.png","sheet_x":14,"sheet_y":46,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F468-1F3FD-200D-1F373","non_qualified":null,"image":"1f468-1f3fd-200d-1f373.png","sheet_x":14,"sheet_y":47,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F468-1F3FE-200D-1F373","non_qualified":null,"image":"1f468-1f3fe-200d-1f373.png","sheet_x":14,"sheet_y":48,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F468-1F3FF-200D-1F373","non_qualified":null,"image":"1f468-1f3ff-200d-1f373.png","sheet_x":14,"sheet_y":49,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Male Cook","b":"1F468-200D-1F373","k":[14,44],"o":4},"heartbeat":{"a":"Beating Heart","b":"1F493","j":["love","like","affection","valentines","pink","heart"],"k":[25,29],"o":2},"sparkle":{"a":"Sparkle","b":"2747-FE0F","c":"2747","j":["stars","green-square","awesome","good","fireworks"],"k":[55,20],"o":2},"amphora":{"a":"Amphora","b":"1F3FA","j":["vase","jar"],"k":[11,22],"o":2},"yen":{"a":"Banknote with Yen Sign","b":"1F4B4","j":["money","sales","japanese","dollar","currency"],"k":[26,10],"o":2},"revolving_hearts":{"a":"Revolving Hearts","b":"1F49E","j":["love","like","affection","valentines"],"k":[25,40],"o":2},"bangbang":{"a":"Double Exclamation Mark","b":"203C-FE0F","c":"203C","j":["exclamation","surprise"],"k":[52,10],"o":2},"parachute":{"a":"Parachute","b":"1FA82","k":[52,3],"o":12},"herb":{"a":"Herb","b":"1F33F","j":["vegetable","plant","medicine","weed","grass","lawn"],"k":[6,23],"o":2},"flag-is":{"a":"Iceland Flag","b":"1F1EE-1F1F8","k":[2,31],"o":2},"female-cook":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F373","non_qualified":null,"image":"1f469-1f3fb-200d-1f373.png","sheet_x":17,"sheet_y":35,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F469-1F3FC-200D-1F373","non_qualified":null,"image":"1f469-1f3fc-200d-1f373.png","sheet_x":17,"sheet_y":36,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F469-1F3FD-200D-1F373","non_qualified":null,"image":"1f469-1f3fd-200d-1f373.png","sheet_x":17,"sheet_y":37,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F469-1F3FE-200D-1F373","non_qualified":null,"image":"1f469-1f3fe-200d-1f373.png","sheet_x":17,"sheet_y":38,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F469-1F3FF-200D-1F373","non_qualified":null,"image":"1f469-1f3ff-200d-1f373.png","sheet_x":17,"sheet_y":39,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Female Cook","b":"1F469-200D-1F373","k":[17,34],"o":4},"mechanic":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB-200D-1F527","non_qualified":null,"image":"1f9d1-1f3fb-200d-1f527.png","sheet_x":46,"sheet_y":15,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FC":{"unified":"1F9D1-1F3FC-200D-1F527","non_qualified":null,"image":"1f9d1-1f3fc-200d-1f527.png","sheet_x":46,"sheet_y":16,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FD":{"unified":"1F9D1-1F3FD-200D-1F527","non_qualified":null,"image":"1f9d1-1f3fd-200d-1f527.png","sheet_x":46,"sheet_y":17,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FE":{"unified":"1F9D1-1F3FE-200D-1F527","non_qualified":null,"image":"1f9d1-1f3fe-200d-1f527.png","sheet_x":46,"sheet_y":18,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FF":{"unified":"1F9D1-1F3FF-200D-1F527","non_qualified":null,"image":"1f9d1-1f3ff-200d-1f527.png","sheet_x":46,"sheet_y":19,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false}},"a":"Mechanic","b":"1F9D1-200D-1F527","k":[46,14],"o":12},"interrobang":{"a":"Exclamation Question Mark","b":"2049-FE0F","c":"2049","j":["wat","punctuation","surprise"],"k":[52,11],"o":2},"seat":{"a":"Seat","b":"1F4BA","j":["sit","airplane","transport","bus","flight","fly"],"k":[26,16],"o":2},"dollar":{"a":"Banknote with Dollar Sign","b":"1F4B5","j":["money","sales","bill","currency"],"k":[26,11],"o":2},"two_hearts":{"a":"Two Hearts","b":"1F495","j":["love","like","affection","valentines","heart"],"k":[25,31],"o":2},"it":{"a":"Italy Flag","b":"1F1EE-1F1F9","j":["italy","flag","nation","country","banner"],"k":[2,32],"n":["flag-it"],"o":2},"shamrock":{"a":"Shamrock","b":"2618-FE0F","c":"2618","j":["vegetable","plant","nature","irish","clover"],"k":[53,1],"o":2},"four_leaf_clover":{"a":"Four Leaf Clover","b":"1F340","j":["vegetable","plant","nature","lucky","irish"],"k":[6,24],"o":2},"euro":{"a":"Banknote with Euro Sign","b":"1F4B6","j":["money","sales","dollar","currency"],"k":[26,12],"o":2},"question":{"a":"Black Question Mark Ornament","b":"2753","j":["doubt","confused"],"k":[55,23],"o":2},"helicopter":{"a":"Helicopter","b":"1F681","j":["transportation","vehicle","fly"],"k":[34,0],"o":2},"heart_decoration":{"a":"Heart Decoration","b":"1F49F","j":["purple-square","love","like"],"k":[25,41],"o":2},"flag-je":{"a":"Jersey Flag","b":"1F1EF-1F1EA","k":[2,33],"o":2},"male-mechanic":{"skin_variations":{"1F3FB":{"unified":"1F468-1F3FB-200D-1F527","non_qualified":null,"image":"1f468-1f3fb-200d-1f527.png","sheet_x":15,"sheet_y":51,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F468-1F3FC-200D-1F527","non_qualified":null,"image":"1f468-1f3fc-200d-1f527.png","sheet_x":15,"sheet_y":52,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F468-1F3FD-200D-1F527","non_qualified":null,"image":"1f468-1f3fd-200d-1f527.png","sheet_x":15,"sheet_y":53,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F468-1F3FE-200D-1F527","non_qualified":null,"image":"1f468-1f3fe-200d-1f527.png","sheet_x":15,"sheet_y":54,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F468-1F3FF-200D-1F527","non_qualified":null,"image":"1f468-1f3ff-200d-1f527.png","sheet_x":15,"sheet_y":55,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Male Mechanic","b":"1F468-200D-1F527","k":[15,50],"o":4},"suspension_railway":{"a":"Suspension Railway","b":"1F69F","j":["vehicle","transportation"],"k":[34,30],"o":2},"heavy_heart_exclamation_mark_ornament":{"a":"Heavy Heart Exclamation Mark Ornament","b":"2763-FE0F","c":"2763","k":[55,27],"o":2},"female-mechanic":{"skin_variations":{"1F3FB":{"unified":"1F469-1F3FB-200D-1F527","non_qualified":null,"image":"1f469-1f3fb-200d-1f527.png","sheet_x":18,"sheet_y":36,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FC":{"unified":"1F469-1F3FC-200D-1F527","non_qualified":null,"image":"1f469-1f3fc-200d-1f527.png","sheet_x":18,"sheet_y":37,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FD":{"unified":"1F469-1F3FD-200D-1F527","non_qualified":null,"image":"1f469-1f3fd-200d-1f527.png","sheet_x":18,"sheet_y":38,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FE":{"unified":"1F469-1F3FE-200D-1F527","non_qualified":null,"image":"1f469-1f3fe-200d-1f527.png","sheet_x":18,"sheet_y":39,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true},"1F3FF":{"unified":"1F469-1F3FF-200D-1F527","non_qualified":null,"image":"1f469-1f3ff-200d-1f527.png","sheet_x":18,"sheet_y":40,"added_in":"4.0","has_img_apple":true,"has_img_google":true,"has_img_twitter":true,"has_img_facebook":true}},"a":"Female Mechanic","b":"1F469-200D-1F527","k":[18,35],"o":4},"flag-jm":{"a":"Jamaica Flag","b":"1F1EF-1F1F2","k":[2,34],"o":2},"grey_question":{"a":"White Question Mark Ornament","b":"2754","j":["doubts","gray","huh","confused"],"k":[55,24],"o":2},"maple_leaf":{"a":"Maple Leaf","b":"1F341","j":["nature","plant","vegetable","ca","fall"],"k":[6,25],"o":2},"pound":{"a":"Banknote with Pound Sign","b":"1F4B7","j":["british","sterling","money","sales","bills","uk","england","currency"],"k":[26,13],"o":2},"money_with_wings":{"a":"Money with Wings","b":"1F4B8","j":["dollar","bills","payment","sale"],"k":[26,14],"o":2},"flag-jo":{"a":"Jordan Flag","b":"1F1EF-1F1F4","k":[2,35],"o":2},"fallen_leaf":{"a":"Fallen Leaf","b":"1F342","j":["nature","plant","vegetable","leaves"],"k":[6,26],"o":2},"factory_worker":{"skin_variations":{"1F3FB":{"unified":"1F9D1-1F3FB-200D-1F3ED","non_qualified":null,"image":"1f9d1-1f3fb-200d-1f3ed.png","sheet_x":45,"sheet_y":54,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FC":{"unified":"1F9D1-1F3FC-200D-1F3ED","non_qualified":null,"image":"1f9d1-1f3fc-200d-1f3ed.png","sheet_x":45,"sheet_y":55,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FD":{"unified":"1F9D1-1F3FD-200D-1F3ED","non_qualified":null,"image":"1f9d1-1f3fd-200d-1f3ed.png","sheet_x":45,"sheet_y":56,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FE":{"unified":"1F9D1-1F3FE-200D-1F3ED","non_qualified":null,"image":"1f9d1-1f3fe-200d-1f3ed.png","sheet_x":46,"sheet_y":0,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false},"1F3FF":{"unified":"1F9D1-1F3FF-200D-1F3ED","non_qualified":null,"image":"1f9d1-1f3ff-200d-1f3ed.png","sheet_x":46,"sheet_y":1,"added_in":"12.1","has_img_apple":true,"has_img_google":false,"has_img_twitter":false,"has_img_facebook":false}},"a":"Factory Worker","b":"1F9D1-200D-1F3ED","k":[45,53],"o":12},"broken_heart":{"a":"Broken Heart","b":"1F494","j":["sad","sorry","break","heart","heartbreak"],"k":[25,30],"l":[" Local"; -"location_sharing_locating_user_error_title" = "%@ não pôde acessar seu local. Por favor tente de novo mais tarde."; +"location_sharing_settings_toggle_title" = "Habilitar compartilhamento de localização"; +"location_sharing_settings_header" = "Compartilhamento de localização"; +"location_sharing_invalid_authorization_error_title" = "%@ não tem permissão para acessar sua localização. Você pode habilitar acesso em Ajustes > Localização"; +"location_sharing_locating_user_error_title" = "%@ não pôde acessar sua localização. Por favor tente de novo mais tarde."; // MARK: - Location sharing -"location_sharing_title" = "Local"; +"location_sharing_title" = "Localização"; "location_sharing_open_google_maps" = "Abrir em Google Maps"; "location_sharing_open_apple_maps" = "Abrir em Apple Mapas"; "location_sharing_invalid_authorization_settings" = "Ajustes"; @@ -1576,7 +1576,7 @@ "ok" = "OK"; "onboarding_splash_page_1_message" = "Comunicação segura e independente que lhe dá o mesmo nível de privacidade que uma conversa face-a-face em sua própria casa."; "settings_enable_room_message_bubbles" = "Bolhas de mensagem"; -"onboarding_splash_page_4_message" = "Elemente também é ótimo para o lugar de trabalho. É confiado pelas organizações mais seguras do mundo."; +"onboarding_splash_page_4_message" = "Element também é ótimo para o lugar de trabalho. É confiado pelas organizações mais seguras do mundo."; "onboarding_splash_page_4_title_no_pun" = "Mensageria para seu time."; "onboarding_splash_page_3_message" = "Encriptado ponta-a-ponta e nenhum número de telefone requerido. Sem publicidade ou datamining."; "onboarding_splash_page_3_title" = "Mensageria segura."; @@ -1587,3 +1587,10 @@ // Onboarding "onboarding_splash_register_button_title" = "Criar conta"; +"poll_edit_form_poll_type_closed_description" = "Resultados são somente revelados quando você termina a sondagem"; +"poll_edit_form_poll_type_open" = "Sondagem aberta"; +"poll_edit_form_poll_type_closed" = "Sondagem fechada"; +"poll_edit_form_poll_type_open_description" = "Votantes veem resultados assim que elas(es) têm votado"; +"poll_edit_form_update_failure_subtitle" = "Por favor tente de novo"; +"poll_edit_form_update_failure_title" = "Falha para atualizar sondagem"; +"poll_edit_form_poll_type" = "Tipo de sondagem"; diff --git a/Riot/Assets/ru.lproj/InfoPlist.strings b/Riot/Assets/ru.lproj/InfoPlist.strings index 9608ff9a5..19e148ef6 100644 --- a/Riot/Assets/ru.lproj/InfoPlist.strings +++ b/Riot/Assets/ru.lproj/InfoPlist.strings @@ -5,3 +5,4 @@ "NSContactsUsageDescription" = "Element покажет ваши контакты, чтобы вы могли пригласить их в чат."; "NSCalendarsUsageDescription" = "Просматривайте запланированные встречи в приложении."; "NSFaceIDUsageDescription" = "Face ID используется для доступа к вашему приложению."; +"NSLocationWhenInUseUsageDescription" = "Когда вы делитесь с людьми своим местоположением, Element необходим доступ, чтобы показать им карту."; diff --git a/Riot/Assets/ru.lproj/Localizable.strings b/Riot/Assets/ru.lproj/Localizable.strings index e2aba3ce0..f17718aa1 100644 --- a/Riot/Assets/ru.lproj/Localizable.strings +++ b/Riot/Assets/ru.lproj/Localizable.strings @@ -116,3 +116,6 @@ /** General **/ "NOTIFICATION" = "Уведомление"; + +/* New file message from a specific person, not referencing a room. */ +"LOCATION_FROM_USER" = "%@ поделились своим местоположением"; diff --git a/Riot/Assets/ru.lproj/Vector.strings b/Riot/Assets/ru.lproj/Vector.strings index d91945d9f..46ee4ba1d 100644 --- a/Riot/Assets/ru.lproj/Vector.strings +++ b/Riot/Assets/ru.lproj/Vector.strings @@ -1341,7 +1341,7 @@ "side_menu_app_version" = "Версия %@"; "side_menu_action_feedback" = "Отзыв"; "side_menu_action_help" = "Помощь"; -"side_menu_action_settings" = "Настойки"; +"side_menu_action_settings" = "Настройки"; "side_menu_action_invite_friends" = "Пригласить друзей"; // Mark: - Side menu diff --git a/Riot/Assets/sk.lproj/Vector.strings b/Riot/Assets/sk.lproj/Vector.strings index b86434589..99bee79d5 100644 --- a/Riot/Assets/sk.lproj/Vector.strings +++ b/Riot/Assets/sk.lproj/Vector.strings @@ -1388,7 +1388,7 @@ // Unverified sessions -"key_verification_self_verify_unverified_sessions_alert_title" = "Zobraziť, kde ste prihlásený"; +"key_verification_self_verify_unverified_sessions_alert_title" = "Skontrolujte, kde ste prihlásení"; "key_verification_self_verify_current_session_alert_message" = "Ostatní používatelia jej nemusia dôverovať."; // Current session @@ -1664,3 +1664,48 @@ "onboarding_splash_page_4_title_no_pun" = "Zasielanie správ pre váš tím."; "onboarding_splash_page_4_message" = "Element je skvelý aj na pracovisku. Dôverujú mu najbezpečnejšie organizácie na svete."; "settings_enable_room_message_bubbles" = "Správy v bublinách"; +"share_extension_failed_to_encrypt" = "Nepodarilo sa odoslať. Skontrolujte v hlavnej aplikácii nastavenia šifrovania pre túto miestnosť"; +"service_terms_modal_policy_checkbox_accessibility_hint" = "Označte, či chcete prijať %@"; + +// Intro + +"key_backup_setup_intro_title" = "Nikdy neprídete o šifrované správy"; +"key_backup_setup_passphrase_setup_recovery_key_info" = "Alebo zabezpečte zálohu bezpečnostným kľúčom a uložte ju na bezpečné miesto."; +"key_verification_user_title" = "Overte ich"; +"poll_edit_form_poll_question_or_topic" = "Otázka alebo téma ankety"; +"poll_timeline_total_no_votes" = "Žiadne odovzdané hlasy"; +"poll_timeline_total_one_vote_not_voted" = "1 odovzdaný hlas. Hlasujte a pozrite si výsledky"; +"poll_timeline_total_final_results_one_vote" = "Konečný výsledok na základe 1 hlasu"; +"poll_timeline_total_final_results" = "Konečný výsledok na základe %lu hlasov"; +"poll_edit_form_poll_type" = "Typ ankety"; +"poll_edit_form_update_failure_title" = "Nepodarilo sa aktualizovať anketu"; +"poll_edit_form_update_failure_subtitle" = "Prosím, skúste to znova"; +"poll_edit_form_poll_type_open" = "Otvoriť anketu"; +"poll_edit_form_poll_type_open_description" = "Hlasujúci uvidia výsledky hneď po hlasovaní"; +"poll_edit_form_poll_type_closed_description" = "Výsledky sa zobrazia až po ukončení ankety"; +"poll_timeline_total_votes_not_voted" = "%lu odovzdaných hlasov. Hlasujte a pozrite si výsledky"; +"poll_timeline_total_votes" = "%lu odovzdaných hlasov"; +"poll_timeline_total_one_vote" = "1 odovzdaný hlas"; +"poll_edit_form_poll_type_closed" = "Uzavretá anketa"; +"poll_edit_form_post_failure_title" = "Nepodarilo sa odoslať anketu"; +"call_transfer_error_message" = "Prenos hovoru zlyhal"; +"user_verification_session_details_information_untrusted_other_user" = " sa prihlásil pomocou novej relácie:"; +"key_verification_bootstrap_not_setup_message" = "Najprv musíte zaviesť krížové podpisovanie."; +"device_verification_emoji_pin" = "Špendlík"; +"device_verification_emoji_folder" = "Fascikel"; +"secure_key_backup_setup_existing_backup_error_info" = "Odomknite to a znovu to použite v zabezpečenej zálohe alebo to vymažte a vytvorte novú zálohu správ v zabezpečenej zálohe."; + +// Share extension +"share_extension_auth_prompt" = "Prihláste sa v hlavnej aplikácii na zdieľanie obsahu"; + +// Widget Integration Manager +"widget_integration_need_to_be_able_to_invite" = "Musíte mať možnosť pozvať používateľov, aby ste to mohli urobiť."; +"bug_report_logs_description" = "Za účelom diagnostiky problémov budú spolu s týmto hlásením o chybe odoslané protokoly z tohto klienta. Ak chcete radšej posielať len vyššie uvedený text, zrušte prosím označené:"; +"call_no_stun_server_error_message_1" = "Požiadajte prosím správcu vášho domovského servera %@ o nastavenie servera TURN, aby hovory fungovali spoľahlivo."; +"call_no_stun_server_error_title" = "Hovor zlyhal z dôvodu nesprávne nastaveného servera"; +"room_details_addresses_disable_main_address_prompt_title" = "Upozornenie na hlavnú adresu"; +"manage_session_trusted" = "Dôveryhodný pre vás"; +"settings_contacts_phonebook_country" = "Krajina telefónneho zoznamu"; +"settings_ui_theme_picker_message_invert_colours" = "\"Auto\" používa nastavenia \"Invertovať farby\" vášho zariadenia"; +"external_link_confirmation_title" = "Prekontrolujte tento odkaz"; +"callbar_only_single_active_group" = "Ťuknutím sa pripojíte k skupinovému hovoru (%@)"; diff --git a/Riot/Assets/sq.lproj/Vector.strings b/Riot/Assets/sq.lproj/Vector.strings index 9c8151004..0b0f12415 100644 --- a/Riot/Assets/sq.lproj/Vector.strings +++ b/Riot/Assets/sq.lproj/Vector.strings @@ -1608,3 +1608,10 @@ // Onboarding "onboarding_splash_register_button_title" = "Krijoni llogari"; +"poll_edit_form_poll_type_open" = "Anketim i hapur"; +"poll_edit_form_poll_type_closed_description" = "Përfundimet shfaqen vetëm kur përfundoni anketimin"; +"poll_edit_form_poll_type_closed" = "Anketim i mbyllur"; +"poll_edit_form_poll_type_open_description" = "Votuesit do të shohin përfundime sapo të kenë votuar"; +"poll_edit_form_update_failure_subtitle" = "Ju lutemi, riprovoni"; +"poll_edit_form_update_failure_title" = "S’u arrit të përditësohet anketimi"; +"poll_edit_form_poll_type" = "Lloj anketimi"; diff --git a/Riot/Assets/sv.lproj/Vector.strings b/Riot/Assets/sv.lproj/Vector.strings index eacf7e0f7..88d35e629 100644 --- a/Riot/Assets/sv.lproj/Vector.strings +++ b/Riot/Assets/sv.lproj/Vector.strings @@ -276,7 +276,7 @@ "settings_ignored_users" = "IGNORERADE ANVÄNDARE"; "settings_contacts" = "ENHETSKONTAKTER"; "settings_advanced" = "AVANCERAT"; -"settings_other" = "ANNAT"; +"settings_other" = "Annat"; "settings_labs" = "EXPERIMENT"; "settings_devices" = "SESSIONER"; "settings_cryptography" = "KRYPTOGRAFI"; @@ -430,7 +430,7 @@ "room_participants_action_mention" = "Nämn"; "room_participants_security_information_room_encrypted" = "Meddelanden i det här rummet är totalsträckskrypterade.\n\nDina meddelanden är säkrade med lås och bara du och mottagaren har de unika nycklarna för att låsa upp dem."; "room_accessiblity_scroll_to_bottom" = "Scrolla till botten"; -"room_do_not_have_permission_to_post" = "Du har inte behörighet att posta till det här rummet"; +"room_do_not_have_permission_to_post" = "Du är inte behörig att posta till det här rummet"; "room_unsent_messages_notification" = "Meddelanden misslyckades att skickas."; "room_conference_call_no_power" = "Du behöver behörighet för att hantera gruppsamtal i det här rummet"; "room_prompt_resend" = "Skicka alla igen"; @@ -704,7 +704,7 @@ "event_formatter_jitsi_widget_removed_by_you" = "Du tog bort VoIP-konferens"; "public_room_section_title" = "Offentliga rum (på %@):"; "bug_report_prompt" = "Appen har kraschat förra gången. Vill du skicka en kraschrapport?"; -"camera_access_not_granted" = "%@ verkar inte ha behörighet att använda kameran, vänligen ändra integritetsinställningarna"; +"camera_access_not_granted" = "%@ verkar inte vara behörig att använda kameran, vänligen ändra integritetsinställningarna"; "photo_library_access_not_granted" = "%@ verkar inte ha åtkomst till bildbiblioteket, vänligen ändra integritetsinställningarna"; "large_badge_value_k_format" = "%.1fK"; "call_incoming_voice" = "Inkommande samtal…"; @@ -838,7 +838,7 @@ // Widget Integration Manager "widget_integration_need_to_be_able_to_invite" = "Du behöver kunna bjuda in användare för att göra det där."; "widget_integration_positive_power_level" = "Behörighetsnivå måste vara ett positivt heltal."; -"widget_integration_no_permission_in_room" = "Du har inte behörighet att göra det där i det här rummet."; +"widget_integration_no_permission_in_room" = "Du är inte behörig att göra det där i det här rummet."; "widget_integration_manager_disabled" = "Du behöver aktivera integrationshanteraren i inställningarna"; "room_widget_permission_webview_information_title" = "Att använda den kan sätta kakor och dela data med %@:\n"; "room_widget_permission_information_title" = "Att använda den kan dela data med %@:\n"; @@ -1452,7 +1452,7 @@ "space_home_show_all_rooms" = "Visa alla rum"; "space_participants_action_ban" = "Banna från det här utrymmet"; "space_participants_action_remove" = "Ta bort från det här utrymmet"; -"spaces_coming_soon_detail" = "Den här funktionen har inte bjudits in än, men den är på väg. För tillfället så kan du göra det med Element på din dator."; +"spaces_coming_soon_detail" = "Den här funktionen har inte implementerats än, men den är på väg. För tillfället så kan du göra det med %@ på din dator."; "spaces_invites_coming_soon_title" = "Inbjudningar kommer snart"; "spaces_add_rooms_coming_soon_title" = "Tilläggning av rum kommer snart"; "spaces_coming_soon_title" = "Kommer snart"; diff --git a/Riot/Assets/uk.lproj/Vector.strings b/Riot/Assets/uk.lproj/Vector.strings index e85515b74..dd0e93cac 100644 --- a/Riot/Assets/uk.lproj/Vector.strings +++ b/Riot/Assets/uk.lproj/Vector.strings @@ -1731,3 +1731,10 @@ // Onboarding "onboarding_splash_register_button_title" = "Створити обліковий запис"; +"poll_edit_form_poll_type_open_description" = "Усі, хто проголосує, побачать результати одразу після голосування"; +"poll_edit_form_poll_type_closed_description" = "Результати можна переглянути лише після завершення опитування"; +"poll_edit_form_poll_type_closed" = "Закрите опитування"; +"poll_edit_form_poll_type_open" = "Відкрити опитування"; +"poll_edit_form_update_failure_subtitle" = "Повторіть спробу"; +"poll_edit_form_update_failure_title" = "Не вдалося оновити опитування"; +"poll_edit_form_poll_type" = "Тип опитування"; diff --git a/Riot/Categories/MXKRoomBubbleTableViewCell+Riot.m b/Riot/Categories/MXKRoomBubbleTableViewCell+Riot.m index 98fde6a11..6924cf8c6 100644 --- a/Riot/Categories/MXKRoomBubbleTableViewCell+Riot.m +++ b/Riot/Categories/MXKRoomBubbleTableViewCell+Riot.m @@ -106,7 +106,7 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = CGFloat timeLabelPosX; CGFloat timeLabelPosY; - CGFloat timeLabelHeight = RoomBubbleCellLayout.timestampLabelHeight; + CGFloat timeLabelHeight = PlainRoomCellLayoutConstants.timestampLabelHeight; CGFloat timeLabelWidth; NSTextAlignment timeLabelTextAlignment; @@ -133,7 +133,7 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = } else { - timeLabelPosX = self.bubbleInfoContainer.frame.size.width - RoomBubbleCellLayout.timestampLabelWidth; + timeLabelPosX = self.bubbleInfoContainer.frame.size.width - PlainRoomCellLayoutConstants.timestampLabelWidth; if (isFirstDisplayedComponent) { @@ -148,7 +148,7 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = timeLabelPosY = component.position.y + self.msgTextViewTopConstraint.constant - timeLabelHeight - self.bubbleInfoContainerTopConstraint.constant; } - timeLabelWidth = RoomBubbleCellLayout.timestampLabelWidth; + timeLabelWidth = PlainRoomCellLayoutConstants.timestampLabelWidth; timeLabelTextAlignment = NSTextAlignmentRight; } @@ -340,7 +340,7 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = NSDate *date = bubbleData.date; if (date) { - UILabel *timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.bubbleInfoContainer.frame.size.width, RoomBubbleCellLayout.timestampLabelHeight)]; + UILabel *timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.bubbleInfoContainer.frame.size.width, PlainRoomCellLayoutConstants.timestampLabelHeight)]; timeLabel.text = [bubbleData.eventFormatter dateStringFromDate:date withTime:NO]; timeLabel.textAlignment = NSTextAlignmentRight; @@ -387,7 +387,7 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 - constant:RoomBubbleCellLayout.timestampLabelHeight]; + constant:PlainRoomCellLayoutConstants.timestampLabelHeight]; // Available on iOS 8 and later [NSLayoutConstraint activateConstraints:@[rightConstraint, topConstraint, widthConstraint, heightConstraint]]; @@ -539,7 +539,7 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = CGFloat componentBottomY = componentFrameInContentView.origin.y + componentFrameInContentView.size.height; CGFloat x = 0; - CGFloat y = componentFrameInContentView.origin.y - RoomBubbleCellLayout.timestampLabelHeight; + CGFloat y = componentFrameInContentView.origin.y - PlainRoomCellLayoutConstants.timestampLabelHeight; CGFloat width = roomBubbleTableViewCell.contentView.frame.size.width; CGFloat height = componentBottomY - y; @@ -697,7 +697,7 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = if ([bubbleData isKindOfClass:RoomBubbleCellData.class] && ((RoomBubbleCellData*)bubbleData).componentIndexOfSentMessageTick >= 0) { - UIImage *image = [UIImage imageNamed:@"sent_message_tick"]; + UIImage *image = AssetImages.sentMessageTick.image; image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; tickView = [[UIImageView alloc] initWithImage:image]; tickView.tintColor = ThemeService.shared.theme.textTertiaryColor; @@ -733,7 +733,7 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = } else { - UIImage *image = [UIImage imageNamed:@"sending_message_tick"]; + UIImage *image = AssetImages.sendingMessageTick.image; image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; tickView = [[UIImageView alloc] initWithImage:image]; tickView.tintColor = ThemeService.shared.theme.textTertiaryColor; @@ -746,7 +746,7 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = if (component.event.sentState == MXEventSentStateFailed) { - tickView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"error_message_tick"]]; + tickView = [[UIImageView alloc] initWithImage:AssetImages.errorMessageTick.image]; [statusViews addObject:tickView]; [self addTickView:tickView atIndex:index]; } @@ -798,7 +798,7 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = { CGRect componentFrame = [self componentFrameInContentViewForIndex: index]; - tickView.frame = CGRectMake(self.contentView.bounds.size.width - tickView.frame.size.width - 2 * RoomBubbleCellLayout.readReceiptsViewRightMargin, CGRectGetMaxY(componentFrame) - tickView.frame.size.height, tickView.frame.size.width, tickView.frame.size.height); + tickView.frame = CGRectMake(self.contentView.bounds.size.width - tickView.frame.size.width - 2 * PlainRoomCellLayoutConstants.readReceiptsViewRightMargin, CGRectGetMaxY(componentFrame) - tickView.frame.size.height, tickView.frame.size.width, tickView.frame.size.height); [self.contentView addSubview:tickView]; } @@ -815,8 +815,8 @@ NSString *const kMXKRoomBubbleCellKeyVerificationIncomingRequestDeclinePressed = } // Define 'Edit' button frame - UIImage *editIcon = [UIImage imageNamed:@"edit_icon"]; - CGFloat editBtnPosX = self.bubbleInfoContainer.frame.size.width - RoomBubbleCellLayout.timestampLabelWidth - 22 - editIcon.size.width / 2; + UIImage *editIcon = AssetImages.editIcon.image; + CGFloat editBtnPosX = self.bubbleInfoContainer.frame.size.width - PlainRoomCellLayoutConstants.timestampLabelWidth - 22 - editIcon.size.width / 2; CGFloat editBtnPosY = isFirstDisplayedComponent ? -13 : component.position.y + self.msgTextViewTopConstraint.constant - self.bubbleInfoContainerTopConstraint.constant - 13; UIButton *editButton = [[UIButton alloc] initWithFrame:CGRectMake(editBtnPosX, editBtnPosY, 44, 44)]; diff --git a/Riot/Categories/UIView+Toast.swift b/Riot/Categories/UIView+Toast.swift index e395578e3..b89d63ac1 100644 --- a/Riot/Categories/UIView+Toast.swift +++ b/Riot/Categories/UIView+Toast.swift @@ -60,7 +60,7 @@ extension UIView { duration: TimeInterval = Constants.defaultDuration, position: ToastPosition = Constants.defaultPosition, additionalMargin: CGFloat = 0.0) { - let view = ToastView(withMessage: message, image: image) + let view = BasicToastView(withMessage: message, image: image) vc_toast(view: view, duration: duration, position: position, additionalMargin: additionalMargin) } @@ -91,6 +91,9 @@ extension UIView { // MARK: - ToastOperation /// Async toast UI operation. Will run on the main thread. +/// +/// Note: a more recent `Activity` and `ActivityCenter` aim to achieve the same goal of abstracting away the scheduling and display +/// of visual notifications, without using `OperationQueue`. private class ToastOperation: AsyncOperation { private enum Constants { @@ -212,100 +215,3 @@ private class ToastOperation: AsyncOperation { } } - -// MARK: - ToastView - -/// Default view for a basic toast. -private class ToastView: UIView, Themable { - - private enum Constants { - static let padding: UIEdgeInsets = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16) - static let cornerRadius: CGFloat = 8.0 - } - - private lazy var imageView: UIImageView = { - let view = UIImageView() - view.translatesAutoresizingMaskIntoConstraints = false - view.backgroundColor = .clear - return view - }() - - private lazy var messageLabel: UILabel = { - let label = UILabel() - label.font = ThemeService.shared().theme.fonts.body - label.backgroundColor = .clear - label.numberOfLines = 0 - label.textAlignment = .left - label.translatesAutoresizingMaskIntoConstraints = false - return label - }() - - private lazy var stackView: UIStackView = { - let result = UIStackView() - result.axis = .horizontal - result.distribution = .fill - result.alignment = .center - result.spacing = 8.0 - result.backgroundColor = .clear - - addSubview(result) - result.translatesAutoresizingMaskIntoConstraints = false - NSLayoutConstraint.activate([ - result.leadingAnchor.constraint(equalTo: leadingAnchor, constant: Constants.padding.left), - result.topAnchor.constraint(equalTo: topAnchor, constant: Constants.padding.top), - result.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -Constants.padding.right), - result.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -Constants.padding.bottom) - ]) - - return result - }() - - init(withMessage message: String?, - image: UIImage? = nil) { - super.init(frame: .zero) - - if let image = image { - imageView.image = image - NSLayoutConstraint.activate([ - imageView.widthAnchor.constraint(equalToConstant: image.size.width), - imageView.heightAnchor.constraint(equalToConstant: image.size.height) - ]) - stackView.addArrangedSubview(imageView) - } - - messageLabel.text = message - stackView.addArrangedSubview(messageLabel) - - stackView.layoutIfNeeded() - layer.cornerRadius = Constants.cornerRadius - layer.masksToBounds = true - registerThemeServiceDidChangeThemeNotification() - themeDidChange() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func registerThemeServiceDidChangeThemeNotification() { - NotificationCenter.default.addObserver(self, - selector: #selector(themeDidChange), - name: .themeServiceDidChangeTheme, - object: nil) - } - - @objc - private func themeDidChange() { - self.update(theme: ThemeService.shared().theme) - } - - // MARK: Themable - - func update(theme: Theme) { - backgroundColor = theme.colors.quinaryContent - imageView.tintColor = theme.colors.tertiaryContent - messageLabel.textColor = theme.colors.primaryContent - messageLabel.font = theme.fonts.body - } - -} diff --git a/Riot/Categories/UIViewController+RiotSearch.h b/Riot/Categories/UIViewController+RiotSearch.h index db29e0183..ac95a4139 100644 --- a/Riot/Categories/UIViewController+RiotSearch.h +++ b/Riot/Categories/UIViewController+RiotSearch.h @@ -33,15 +33,6 @@ */ @property (nonatomic, readonly) BOOL searchBarHidden; -/** - The Riot empty search background image (champagne bubbles). - The image adapts its width to its parent view width. - Its bottom is aligned to the top of the keyboard. - */ -@property (nonatomic, readonly) UIImageView *backgroundImageView; - -@property (nonatomic, readonly) NSLayoutConstraint *backgroundImageViewBottomConstraint; - /** Show/Hide the search bar. @@ -50,18 +41,4 @@ - (void)showSearch:(BOOL)animated; - (void)hideSearch:(BOOL)animated; -/** - Initialise `backgroundImageView` and add it to the passed parent view. - - @param view the view to add `backgroundImageView` to. - */ -- (void)addBackgroundImageViewToView:(UIView*)view; - -/** - Provide the new height of the keyboard to align `backgroundImageView` - - @param keyboardHeight the keyboard height. - */ -- (void)setKeyboardHeightForBackgroundImage:(CGFloat)keyboardHeight; - @end diff --git a/Riot/Categories/UIViewController+RiotSearch.m b/Riot/Categories/UIViewController+RiotSearch.m index 09b7896b3..76d3af972 100644 --- a/Riot/Categories/UIViewController+RiotSearch.m +++ b/Riot/Categories/UIViewController+RiotSearch.m @@ -38,10 +38,6 @@ @property (nonatomic) UIBarButtonItem *backupLeftBarButtonItem; @property (nonatomic) UIBarButtonItem *backupRightBarButtonItem; -// The Riot empty search background image (champagne bubbles) -@property (nonatomic) UIImageView *backgroundImageView; -@property (nonatomic) NSLayoutConstraint *backgroundImageViewBottomConstraint; - @end @implementation UIViewControllerRiotSearchInternals @@ -70,16 +66,6 @@ return self.searchInternals.searchBarHidden; } -- (UIImageView*)backgroundImageView -{ - return self.searchInternals.backgroundImageView; -} - -- (NSLayoutConstraint *)backgroundImageViewBottomConstraint -{ - return self.searchInternals.backgroundImageViewBottomConstraint; -} - - (void)showSearch:(BOOL)animated { if (self.searchInternals.searchBarHidden) @@ -134,80 +120,6 @@ } } -- (void)addBackgroundImageViewToView:(UIView*)view -{ - UIImage *searchBgImage = [MXKTools paintImage:[UIImage imageNamed:@"search_bg"] withColor:ThemeService.shared.theme.matrixSearchBackgroundImageTintColor]; - UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:searchBgImage]; - backgroundImageView.translatesAutoresizingMaskIntoConstraints = NO; - - [view addSubview:backgroundImageView]; - - // Keep it at left - NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:view - attribute:NSLayoutAttributeLeading - relatedBy:NSLayoutRelationEqual - toItem:backgroundImageView - attribute:NSLayoutAttributeLeading - multiplier:1.0 - constant:0]; - // Same width as parent - NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:view - attribute:NSLayoutAttributeWidth - relatedBy:NSLayoutRelationEqual - toItem:backgroundImageView - attribute:NSLayoutAttributeWidth - multiplier:1.0f - constant:0.0f]; - - // Keep the image aspect ratio - NSLayoutConstraint *aspectRatioConstraint = [NSLayoutConstraint - constraintWithItem:backgroundImageView - attribute:NSLayoutAttributeHeight - relatedBy:NSLayoutRelationEqual - toItem:backgroundImageView - attribute:NSLayoutAttributeWidth - multiplier:(backgroundImageView.frame.size.height / backgroundImageView.frame.size.width) - constant:0]; - - // Set its position according to its bottom - NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:view - attribute:NSLayoutAttributeBottom - relatedBy:NSLayoutRelationEqual - toItem:backgroundImageView - attribute:NSLayoutAttributeBottom - multiplier:1.0f - constant:216]; - - [NSLayoutConstraint activateConstraints:@[leftConstraint, - widthConstraint, - aspectRatioConstraint, - bottomConstraint - ]]; - - self.searchInternals.backgroundImageView = backgroundImageView; - self.searchInternals.backgroundImageViewBottomConstraint = bottomConstraint; - - // It will be showed once the keyboard appears - backgroundImageView.hidden = YES; -} - -- (void)setKeyboardHeightForBackgroundImage:(CGFloat)keyboardHeight -{ - // keyboardHeight = 0 means no keyboard - if (keyboardHeight > 0) - { - self.searchInternals.backgroundImageView.hidden = NO; - - // 60 = 18 + 42 from the Riot design - self.searchInternals.backgroundImageViewBottomConstraint.constant = keyboardHeight - 60; - } - else - { - // Hide the search - self.searchInternals.backgroundImageView.hidden = YES; - } -} - #pragma mark - UISearchBarDelegate - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar2 diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index 6426957c9..b2ca9b9e8 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -18,8 +18,10 @@ internal typealias AssetImageTypeAlias = ImageAsset.Image // MARK: - Asset Catalogs // swiftlint:disable identifier_name line_length nesting type_body_length type_name -internal enum Asset { - internal enum Images { +@objcMembers +internal class Asset: NSObject { + @objcMembers + @objc(AssetImages) internal class Images: NSObject { internal static let analyticsCheckmark = ImageAsset(name: "AnalyticsCheckmark") internal static let analyticsLogo = ImageAsset(name: "AnalyticsLogo") internal static let socialLoginButtonApple = ImageAsset(name: "social_login_button_apple") @@ -62,6 +64,8 @@ internal enum Asset { internal static let disclosureIcon = ImageAsset(name: "disclosure_icon") internal static let errorIcon = ImageAsset(name: "error_icon") internal static let faceidIcon = ImageAsset(name: "faceid_icon") + internal static let filterOff = ImageAsset(name: "filter_off") + internal static let filterOn = ImageAsset(name: "filter_on") internal static let group = ImageAsset(name: "group") internal static let informationButton = ImageAsset(name: "information_button") internal static let monitor = ImageAsset(name: "monitor") @@ -80,6 +84,7 @@ internal enum Asset { internal static let removeIconBlue = ImageAsset(name: "remove_icon_blue") internal static let findYourContactsFacepile = ImageAsset(name: "find_your_contacts_facepile") internal static let captureAvatar = ImageAsset(name: "capture_avatar") + internal static let deleteAvatar = ImageAsset(name: "delete_avatar") internal static let e2eBlocked = ImageAsset(name: "e2e_blocked") internal static let e2eUnencrypted = ImageAsset(name: "e2e_unencrypted") internal static let e2eWarning = ImageAsset(name: "e2e_warning") @@ -119,6 +124,13 @@ internal enum Asset { internal static let onboardingSplashScreenPage3Dark = ImageAsset(name: "OnboardingSplashScreenPage3Dark") internal static let onboardingSplashScreenPage4 = ImageAsset(name: "OnboardingSplashScreenPage4") internal static let onboardingSplashScreenPage4Dark = ImageAsset(name: "OnboardingSplashScreenPage4Dark") + internal static let onboardingUseCaseCommunity = ImageAsset(name: "onboarding_use_case_community") + internal static let onboardingUseCaseCommunityDark = ImageAsset(name: "onboarding_use_case_community_dark") + internal static let onboardingUseCaseIcon = ImageAsset(name: "onboarding_use_case_icon") + internal static let onboardingUseCasePersonal = ImageAsset(name: "onboarding_use_case_personal") + internal static let onboardingUseCasePersonalDark = ImageAsset(name: "onboarding_use_case_personal_dark") + internal static let onboardingUseCaseWork = ImageAsset(name: "onboarding_use_case_work") + internal static let onboardingUseCaseWorkDark = ImageAsset(name: "onboarding_use_case_work_dark") internal static let peopleEmptyScreenArtwork = ImageAsset(name: "people_empty_screen_artwork") internal static let peopleEmptyScreenArtworkDark = ImageAsset(name: "people_empty_screen_artwork_dark") internal static let peopleFloatingAction = ImageAsset(name: "people_floating_action") @@ -205,7 +217,6 @@ internal enum Asset { internal static let fileMusicIcon = ImageAsset(name: "file_music_icon") internal static let filePhotoIcon = ImageAsset(name: "file_photo_icon") internal static let fileVideoIcon = ImageAsset(name: "file_video_icon") - internal static let searchBg = ImageAsset(name: "search_bg") internal static let searchIcon = ImageAsset(name: "search_icon") internal static let secretsRecoveryKey = ImageAsset(name: "secrets_recovery_key") internal static let secretsRecoveryPassphrase = ImageAsset(name: "secrets_recovery_passphrase") @@ -251,7 +262,8 @@ internal enum Asset { internal static let tabRooms = ImageAsset(name: "tab_rooms") internal static let launchScreenLogo = ImageAsset(name: "launch_screen_logo") } - internal enum SharedImages { + @objcMembers + @objc(AssetSharedImages) internal class SharedImages: NSObject { internal static let cancel = ImageAsset(name: "cancel") internal static let e2eVerified = ImageAsset(name: "e2e_verified") internal static let horizontalLogo = ImageAsset(name: "horizontal_logo") @@ -263,7 +275,8 @@ internal enum Asset { // MARK: - Implementation Details -internal struct ImageAsset { +@objcMembers +internal class ImageAsset: NSObject { internal fileprivate(set) var name: String #if os(macOS) @@ -289,6 +302,10 @@ internal struct ImageAsset { return result } + internal init(name: String) { + self.name = name + } + #if os(iOS) || os(tvOS) @available(iOS 8.0, tvOS 9.0, *) internal func image(compatibleWith traitCollection: UITraitCollection) -> Image { @@ -328,3 +345,4 @@ private final class BundleToken { }() } // swiftlint:enable convenience_type + diff --git a/Riot/Generated/MatrixKitStrings.swift b/Riot/Generated/MatrixKitStrings.swift index b178f6d8d..f59c7d116 100644 --- a/Riot/Generated/MatrixKitStrings.swift +++ b/Riot/Generated/MatrixKitStrings.swift @@ -467,7 +467,7 @@ public class MatrixKitL10n: NSObject { public static var inviteUser: String { return MatrixKitL10n.tr("invite_user") } - /// Kick + /// Remove from chat public static var kick: String { return MatrixKitL10n.tr("kick") } @@ -1059,11 +1059,11 @@ public class MatrixKitL10n: NSObject { public static func noticeRoomJoinRulePublicForDm(_ p1: String) -> String { return MatrixKitL10n.tr("notice_room_join_rule_public_for_dm", p1) } - /// %@ kicked %@ + /// %@ removed %@ public static func noticeRoomKick(_ p1: String, _ p2: String) -> String { return MatrixKitL10n.tr("notice_room_kick", p1, p2) } - /// You kicked %@ + /// You removed %@ public static func noticeRoomKickByYou(_ p1: String) -> String { return MatrixKitL10n.tr("notice_room_kick_by_you", p1) } diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index a693bfc3f..49c16f95c 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -119,7 +119,7 @@ public class VectorL10n: NSObject { public static var authEmailInUse: String { return VectorL10n.tr("Vector", "auth_email_in_use") } - /// No identity server is configured so you cannot add an email address in order to reset your password in the future. + /// No identity server is configured so you cannot add an email address in order to reset your Matrix account password in the future. public static var authEmailIsRequired: String { return VectorL10n.tr("Vector", "auth_email_is_required") } @@ -135,11 +135,11 @@ public class VectorL10n: NSObject { public static var authEmailValidationMessage: String { return VectorL10n.tr("Vector", "auth_email_validation_message") } - /// Forgot password? + /// Forgot Matrix account password? public static var authForgotPassword: String { return VectorL10n.tr("Vector", "auth_forgot_password") } - /// No identity server is configured: add one to reset your password. + /// No identity server is configured: add one to reset your Matrix account password. public static var authForgotPasswordErrorNoConfiguredIdentityServer: String { return VectorL10n.tr("Vector", "auth_forgot_password_error_no_configured_identity_server") } @@ -231,7 +231,7 @@ public class VectorL10n: NSObject { public static var authPhoneInUse: String { return VectorL10n.tr("Vector", "auth_phone_in_use") } - /// No identity server is configured so you cannot add a phone number in order to reset your password in the future. + /// No identity server is configured so you cannot add a phone number in order to reset your Matrix account password in the future. public static var authPhoneIsRequired: String { return VectorL10n.tr("Vector", "auth_phone_is_required") } @@ -247,7 +247,7 @@ public class VectorL10n: NSObject { public static var authRegister: String { return VectorL10n.tr("Vector", "auth_register") } - /// Confirm your new password + /// Confirm your new Matrix account password public static var authRepeatNewPasswordPlaceholder: String { return VectorL10n.tr("Vector", "auth_repeat_new_password_placeholder") } @@ -259,7 +259,7 @@ public class VectorL10n: NSObject { public static func authResetPasswordEmailValidationMessage(_ p1: String) -> String { return VectorL10n.tr("Vector", "auth_reset_password_email_validation_message", p1) } - /// No identity server is configured: add one in server options to reset your password. + /// No identity server is configured: add one in server options to reset your Matrix account password. public static var authResetPasswordErrorIsRequired: String { return VectorL10n.tr("Vector", "auth_reset_password_error_is_required") } @@ -271,7 +271,7 @@ public class VectorL10n: NSObject { public static var authResetPasswordErrorUnauthorized: String { return VectorL10n.tr("Vector", "auth_reset_password_error_unauthorized") } - /// To reset your password, enter the email address linked to your account: + /// To reset your Matrix account password, enter the email address linked to your account: public static var authResetPasswordMessage: String { return VectorL10n.tr("Vector", "auth_reset_password_message") } @@ -287,7 +287,7 @@ public class VectorL10n: NSObject { public static var authResetPasswordNextStepButton: String { return VectorL10n.tr("Vector", "auth_reset_password_next_step_button") } - /// Your password has been reset.\n\nYou have been logged out of all sessions and will no longer receive push notifications. To re-enable notifications, re-log in on each device. + /// Your Matrix account password has been reset.\n\nYou have been logged out of all sessions and will no longer receive push notifications. To re-enable notifications, re-log in on each device. public static var authResetPasswordSuccessMessage: String { return VectorL10n.tr("Vector", "auth_reset_password_success_message") } @@ -779,7 +779,7 @@ public class VectorL10n: NSObject { public static var deactivateAccountInformationsPart5: String { return VectorL10n.tr("Vector", "deactivate_account_informations_part5") } - /// To continue, please enter your password + /// To continue, please enter your Matrix account password public static var deactivateAccountPasswordAlertMessage: String { return VectorL10n.tr("Vector", "deactivate_account_password_alert_message") } @@ -1915,7 +1915,7 @@ public class VectorL10n: NSObject { public static var keyBackupSetupPassphraseConfirmPassphraseValid: String { return VectorL10n.tr("Vector", "key_backup_setup_passphrase_confirm_passphrase_valid") } - /// We'll store an encrypted copy of your keys on our server. Protect your backup with a phrase to keep it secure.\n\nFor maximum security, this should be different from your account password. + /// We'll store an encrypted copy of your keys on our server. Protect your backup with a phrase to keep it secure.\n\nFor maximum security, this should be different from your Matrix account password. public static var keyBackupSetupPassphraseInfo: String { return VectorL10n.tr("Vector", "key_backup_setup_passphrase_info") } @@ -2307,6 +2307,10 @@ public class VectorL10n: NSObject { public static var locationSharingOpenGoogleMaps: String { return VectorL10n.tr("Vector", "location_sharing_open_google_maps") } + /// Open in OpenStreetMap + public static var locationSharingOpenOpenStreetMaps: String { + return VectorL10n.tr("Vector", "location_sharing_open_open_street_maps") + } /// %@ could not send your location. Please try again later. public static func locationSharingPostFailureSubtitle(_ p1: String) -> String { return VectorL10n.tr("Vector", "location_sharing_post_failure_subtitle", p1) @@ -2487,6 +2491,42 @@ public class VectorL10n: NSObject { public static var onboardingSplashRegisterButtonTitle: String { return VectorL10n.tr("Vector", "onboarding_splash_register_button_title") } + /// Communities + public static var onboardingUseCaseCommunityMessaging: String { + return VectorL10n.tr("Vector", "onboarding_use_case_community_messaging") + } + /// Connect to server + public static var onboardingUseCaseExistingServerButton: String { + return VectorL10n.tr("Vector", "onboarding_use_case_existing_server_button") + } + /// Looking to join an existing server? + public static var onboardingUseCaseExistingServerMessage: String { + return VectorL10n.tr("Vector", "onboarding_use_case_existing_server_message") + } + /// We’ll help you get connected. + public static var onboardingUseCaseMessage: String { + return VectorL10n.tr("Vector", "onboarding_use_case_message") + } + /// Not sure yet? You can %@ + public static func onboardingUseCaseNotSureYet(_ p1: String) -> String { + return VectorL10n.tr("Vector", "onboarding_use_case_not_sure_yet", p1) + } + /// Friends and family + public static var onboardingUseCasePersonalMessaging: String { + return VectorL10n.tr("Vector", "onboarding_use_case_personal_messaging") + } + /// skip this question + public static var onboardingUseCaseSkipButton: String { + return VectorL10n.tr("Vector", "onboarding_use_case_skip_button") + } + /// Who will you chat to the most? + public static var onboardingUseCaseTitle: String { + return VectorL10n.tr("Vector", "onboarding_use_case_title") + } + /// Teams + public static var onboardingUseCaseWorkMessaging: String { + return VectorL10n.tr("Vector", "onboarding_use_case_work_messaging") + } /// Open public static var `open`: String { return VectorL10n.tr("Vector", "open") @@ -3355,7 +3395,7 @@ public class VectorL10n: NSObject { public static var roomEventActionForward: String { return VectorL10n.tr("Vector", "room_event_action_forward") } - /// Reason for kicking this user + /// Reason for removing this user public static var roomEventActionKickPromptReason: String { return VectorL10n.tr("Vector", "room_event_action_kick_prompt_reason") } @@ -4155,6 +4195,10 @@ public class VectorL10n: NSObject { public static var searchFiles: String { return VectorL10n.tr("Vector", "search_files") } + /// Filter + public static var searchFilterPlaceholder: String { + return VectorL10n.tr("Vector", "search_filter_placeholder") + } /// Searching… public static var searchInProgress: String { return VectorL10n.tr("Vector", "search_in_progress") @@ -4283,7 +4327,7 @@ public class VectorL10n: NSObject { public static var secretsRecoveryWithPassphraseTitle: String { return VectorL10n.tr("Vector", "secrets_recovery_with_passphrase_title") } - /// Enter your account password to confirm + /// Enter your Matrix account password to confirm public static var secretsResetAuthenticationMessage: String { return VectorL10n.tr("Vector", "secrets_reset_authentication_message") } @@ -4335,7 +4379,7 @@ public class VectorL10n: NSObject { public static var secretsSetupRecoveryKeyTitle: String { return VectorL10n.tr("Vector", "secrets_setup_recovery_key_title") } - /// Don't use your account password. + /// Don't use your Matrix account password. public static var secretsSetupRecoveryPassphraseAdditionalInformation: String { return VectorL10n.tr("Vector", "secrets_setup_recovery_passphrase_additional_information") } @@ -4491,7 +4535,7 @@ public class VectorL10n: NSObject { public static var securitySettingsCryptoSessions: String { return VectorL10n.tr("Vector", "security_settings_crypto_sessions") } - /// If you don’t recognise a login, change your password and reset Secure Backup. + /// If you don’t recognise a login, change your Matrix account password and reset Secure Backup. public static var securitySettingsCryptoSessionsDescription2: String { return VectorL10n.tr("Vector", "security_settings_crypto_sessions_description_2") } @@ -4543,7 +4587,7 @@ public class VectorL10n: NSObject { public static var securitySettingsTitle: String { return VectorL10n.tr("Vector", "security_settings_title") } - /// Confirm your identity by entering your account password + /// Confirm your identity by entering your Matrix account password public static var securitySettingsUserPasswordDescription: String { return VectorL10n.tr("Vector", "security_settings_user_password_description") } @@ -4615,7 +4659,7 @@ public class VectorL10n: NSObject { public static var settingsAdd3pidInvalidPasswordMessage: String { return VectorL10n.tr("Vector", "settings_add_3pid_invalid_password_message") } - /// To continue, please enter your password + /// To continue, please enter your Matrix account password public static var settingsAdd3pidPasswordMessage: String { return VectorL10n.tr("Vector", "settings_add_3pid_password_message") } @@ -4663,7 +4707,7 @@ public class VectorL10n: NSObject { public static func settingsCallsStunServerFallbackDescription(_ p1: String) -> String { return VectorL10n.tr("Vector", "settings_calls_stun_server_fallback_description", p1) } - /// Change password + /// Change Matrix account password public static var settingsChangePassword: String { return VectorL10n.tr("Vector", "settings_change_password") } @@ -4867,7 +4911,7 @@ public class VectorL10n: NSObject { public static var settingsEncryptedGroupMessages: String { return VectorL10n.tr("Vector", "settings_encrypted_group_messages") } - /// Fail to update password + /// Fail to update Matrix account password public static var settingsFailToUpdatePassword: String { return VectorL10n.tr("Vector", "settings_fail_to_update_password") } @@ -5123,7 +5167,7 @@ public class VectorL10n: NSObject { public static var settingsOther: String { return VectorL10n.tr("Vector", "settings_other") } - /// Your password has been updated + /// Your Matrix account password has been updated public static var settingsPasswordUpdated: String { return VectorL10n.tr("Vector", "settings_password_updated") } diff --git a/Riot/Managers/BugReport/RageShakeManager.m b/Riot/Managers/BugReport/RageShakeManager.m index 4ce848240..5f04baa9e 100644 --- a/Riot/Managers/BugReport/RageShakeManager.m +++ b/Riot/Managers/BugReport/RageShakeManager.m @@ -200,7 +200,7 @@ static RageShakeManager* sharedInstance = nil; UIImage *image; - AppDelegate* theDelegate = [AppDelegate theDelegate]; + LegacyAppDelegate* theDelegate = [AppDelegate theDelegate]; UIGraphicsBeginImageContextWithOptions(theDelegate.window.bounds.size, NO, [UIScreen mainScreen].scale); // Iterate over every window from back to front diff --git a/Riot/Managers/PushNotification/PushNotificationService.h b/Riot/Managers/PushNotification/PushNotificationService.h index aaec583d7..c16b65792 100644 --- a/Riot/Managers/PushNotification/PushNotificationService.h +++ b/Riot/Managers/PushNotification/PushNotificationService.h @@ -108,7 +108,6 @@ NS_ASSUME_NONNULL_BEGIN @param pushNotificationService PushNotificationService object. @param roomId Room identifier to be navigated. - @param eventId Event identifier to be navigated around. */ - (void)pushNotificationService:(PushNotificationService *)pushNotificationService shouldNavigateToRoomWithId:(NSString *)roomId; diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift index 450e63497..32bc246e4 100644 --- a/Riot/Managers/Settings/RiotSettings.swift +++ b/Riot/Managers/Settings/RiotSettings.swift @@ -99,7 +99,7 @@ final class RiotSettings: NSObject { @UserDefault(key: "userInterfaceTheme", defaultValue: nil, storage: defaults) var userInterfaceTheme - // MARK: Other + // MARK: Analytics & Rageshakes /// Whether the user was previously shown the Matomo analytics prompt. var hasSeenAnalyticsPrompt: Bool { @@ -130,6 +130,12 @@ final class RiotSettings: NSObject { @UserDefault(key: "enableRageShake", defaultValue: false, storage: defaults) var enableRageShake + // MARK: User + + /// A dictionary of dictionaries keyed by user ID for storage of the `UserSessionProperties` from any active `UserSession`s. + @UserDefault(key: "userSessionProperties", defaultValue: [:], storage: defaults) + var userSessionProperties: [String: [String: Any]] + // MARK: Labs /// Indicates if CallKit ringing is enabled for group calls. This setting does not disable the CallKit integration for group calls, only relates to ringing. diff --git a/Riot/Managers/Theme/Theme.swift b/Riot/Managers/Theme/Theme.swift index 2418cc967..f8e0a382d 100644 --- a/Riot/Managers/Theme/Theme.swift +++ b/Riot/Managers/Theme/Theme.swift @@ -112,11 +112,18 @@ import DesignKit /// - Parameter tabBar: The tab bar to customise. func applyStyle(onTabBar tabBar: UITabBar) - /// Apply the theme on a navigation bar. + /// Apply the theme on a navigation bar, without enabling the iOS 15's scroll edges appearance. /// /// - Parameter navigationBar: the navigation bar to customise. func applyStyle(onNavigationBar navigationBar: UINavigationBar) + /// Apply the theme on a navigation bar. + /// + /// - Parameter navigationBar: the navigation bar to customise. + /// - Parameter modernScrollEdgesAppearance: whether or not to use the iOS 15 style scroll edges appearance + func applyStyle(onNavigationBar navigationBar: UINavigationBar, + withModernScrollEdgesAppearance modernScrollEdgesAppearance: Bool) + /// Apply the theme on a search bar. /// /// - Parameter searchBar: the search bar to customise. diff --git a/Riot/Managers/Theme/Themes/DarkTheme.swift b/Riot/Managers/Theme/Themes/DarkTheme.swift index ebac661c8..8ec84240d 100644 --- a/Riot/Managers/Theme/Themes/DarkTheme.swift +++ b/Riot/Managers/Theme/Themes/DarkTheme.swift @@ -45,7 +45,7 @@ class DarkTheme: NSObject, Theme { var textTertiaryColor: UIColor = UIColor(rgb: 0x8E99A4) var textQuinaryColor: UIColor = UIColor(rgb: 0x394049) - var tintColor: UIColor = UIColor(displayP3Red: 0.05098039216, green: 0.7450980392, blue: 0.5450980392, alpha: 1.0) + var tintColor: UIColor = UIColor(rgb: 0x0DBD8B) var tintBackgroundColor: UIColor = UIColor(rgb: 0x1F6954) var tabBarUnselectedItemTintColor: UIColor = UIColor(rgb: 0x8E99A4) var unreadRoomIndentColor: UIColor = UIColor(rgb: 0x2E3648) @@ -112,28 +112,36 @@ class DarkTheme: NSObject, Theme { } } - // Note: We are not using UINavigationBarAppearance on iOS 13/14 because of UINavigationBar directly including UISearchBar on their titleView that cause crop issues with UINavigationController pop. + // Protocols don't support default parameter values and a protocol extension won't work for @objc func applyStyle(onNavigationBar navigationBar: UINavigationBar) { - navigationBar.tintColor = self.tintColor + applyStyle(onNavigationBar: navigationBar, withModernScrollEdgesAppearance: false) + } + + // Note: We are not using UINavigationBarAppearance on iOS 13/14 because of UINavigationBar directly including UISearchBar on their titleView that cause crop issues with UINavigationController pop. + func applyStyle(onNavigationBar navigationBar: UINavigationBar, + withModernScrollEdgesAppearance modernScrollEdgesAppearance: Bool) { + navigationBar.tintColor = tintColor // On iOS 15 use UINavigationBarAppearance to fix visual issues with the scrollEdgeAppearance style. if #available(iOS 15.0, *) { let appearance = UINavigationBarAppearance() appearance.configureWithOpaqueBackground() - appearance.backgroundColor = self.baseColor - appearance.shadowColor = nil + appearance.backgroundColor = baseColor + if !modernScrollEdgesAppearance { + appearance.shadowColor = nil + } appearance.titleTextAttributes = [ - NSAttributedString.Key.foregroundColor: self.textPrimaryColor + NSAttributedString.Key.foregroundColor: textPrimaryColor ] navigationBar.standardAppearance = appearance - navigationBar.scrollEdgeAppearance = appearance + navigationBar.scrollEdgeAppearance = modernScrollEdgesAppearance ? nil : appearance } else { navigationBar.titleTextAttributes = [ - NSAttributedString.Key.foregroundColor: self.textPrimaryColor + NSAttributedString.Key.foregroundColor: textPrimaryColor ] - navigationBar.barTintColor = self.baseColor + navigationBar.barTintColor = baseColor navigationBar.shadowImage = UIImage() // Remove bottom shadow // The navigation bar needs to be opaque so that its background color is the expected one diff --git a/Riot/Managers/Theme/Themes/DefaultTheme.swift b/Riot/Managers/Theme/Themes/DefaultTheme.swift index 2be798d23..f8f69f7a6 100644 --- a/Riot/Managers/Theme/Themes/DefaultTheme.swift +++ b/Riot/Managers/Theme/Themes/DefaultTheme.swift @@ -45,7 +45,7 @@ class DefaultTheme: NSObject, Theme { var textTertiaryColor: UIColor = UIColor(rgb: 0x8D99A5) var textQuinaryColor: UIColor = UIColor(rgb: 0xE3E8F0) - var tintColor: UIColor = UIColor(displayP3Red: 0.05098039216, green: 0.7450980392, blue: 0.5450980392, alpha: 1.0) + var tintColor: UIColor = UIColor(rgb: 0x0DBD8B) var tintBackgroundColor: UIColor = UIColor(rgb: 0xe9fff9) var tabBarUnselectedItemTintColor: UIColor = UIColor(rgb: 0xC1C6CD) var unreadRoomIndentColor: UIColor = UIColor(rgb: 0x2E3648) @@ -118,9 +118,15 @@ class DefaultTheme: NSObject, Theme { } } - // Note: We are not using UINavigationBarAppearance on iOS 13/14 because of UINavigationBar directly including UISearchBar on their titleView that cause crop issues with UINavigationController pop. + // Protocols don't support default parameter values and a protocol extension doesn't work for @objc func applyStyle(onNavigationBar navigationBar: UINavigationBar) { - navigationBar.tintColor = self.tintColor + applyStyle(onNavigationBar: navigationBar, withModernScrollEdgesAppearance: false) + } + + // Note: We are not using UINavigationBarAppearance on iOS 13/14 because of UINavigationBar directly including UISearchBar on their titleView that cause crop issues with UINavigationController pop. + func applyStyle(onNavigationBar navigationBar: UINavigationBar, + withModernScrollEdgesAppearance modernScrollEdgesAppearance: Bool) { + navigationBar.tintColor = tintColor // On iOS 15 use UINavigationBarAppearance to fix visual issues with the scrollEdgeAppearance style. if #available(iOS 15.0, *) { @@ -128,13 +134,15 @@ class DefaultTheme: NSObject, Theme { appearance.configureWithOpaqueBackground() appearance.backgroundColor = baseColor - appearance.shadowColor = nil + if !modernScrollEdgesAppearance { + appearance.shadowColor = nil + } appearance.titleTextAttributes = [ NSAttributedString.Key.foregroundColor: textPrimaryColor ] navigationBar.standardAppearance = appearance - navigationBar.scrollEdgeAppearance = appearance + navigationBar.scrollEdgeAppearance = modernScrollEdgesAppearance ? nil : appearance } else { navigationBar.titleTextAttributes = [ NSAttributedString.Key.foregroundColor: textPrimaryColor diff --git a/Riot/Managers/URLPreviews/Core Data/URLPreviewStore.swift b/Riot/Managers/URLPreviews/Core Data/URLPreviewStore.swift index da955da40..ecd152fa2 100644 --- a/Riot/Managers/URLPreviews/Core Data/URLPreviewStore.swift +++ b/Riot/Managers/URLPreviews/Core Data/URLPreviewStore.swift @@ -61,6 +61,14 @@ class URLPreviewStore { if let error = error { MXLog.error("[URLPreviewStore] Core Data container error: \(error.localizedDescription)") } + + if let url = storeDescription.url { + do { + try FileManager.default.excludeItemFromBackup(at: url) + } catch { + MXLog.error("[URLPreviewStore] Cannot exclude Core Data from backup: \(error.localizedDescription)") + } + } } } diff --git a/Riot/Managers/UserSessions/UserSession.swift b/Riot/Managers/UserSessions/UserSession.swift index 786fed88d..8795812e6 100644 --- a/Riot/Managers/UserSessions/UserSession.swift +++ b/Riot/Managers/UserSessions/UserSession.swift @@ -33,19 +33,21 @@ class UserSession: NSObject, UserSessionProtocol { let account: MXKAccount // Keep strong reference to the MXSession because account.mxSession can become nil on logout or failure let matrixSession: MXSession - - var userId: String { - guard let userId = self.account.mxCredentials.userId else { - fatalError("[UserSession] identifier: account.mxCredentials.userId should be defined") - } - return userId - } + let userId: String + /// An object that contains user specific properties. + let userProperties: UserSessionProperties // MARK: - Setup init(account: MXKAccount, matrixSession: MXSession) { + guard let userId = account.mxCredentials.userId else { + fatalError("[UserSession] identifier: account.mxCredentials.userId should be defined") + } + self.account = account self.matrixSession = matrixSession + self.userId = userId + self.userProperties = UserSessionProperties(userId: userId) super.init() } } diff --git a/Riot/Managers/UserSessions/UserSessionProperties.swift b/Riot/Managers/UserSessions/UserSessionProperties.swift new file mode 100644 index 000000000..4bac87579 --- /dev/null +++ b/Riot/Managers/UserSessions/UserSessionProperties.swift @@ -0,0 +1,86 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +/// User properties that are tied to a particular user ID. +class UserSessionProperties: NSObject { + + // MARK: - Constants + private enum Constants { + static let useCaseKey = "useCase" + } + + // MARK: - Properties + + // MARK: Private + + /// The user ID for these properties + private let userId: String + + /// The underlying dictionary for this userId from user defaults. + private var dictionary: [String: Any] { + get { + RiotSettings.shared.userSessionProperties[userId] ?? [:] + } + set { + var sharedProperties = RiotSettings.shared.userSessionProperties + sharedProperties[userId] = newValue + RiotSettings.shared.userSessionProperties = sharedProperties + } + } + + // MARK: Public + + /// The user's use case selection if this session was the one used to register the account. + var useCase: UseCase? { + get { + guard let useCaseRawValue = dictionary[Constants.useCaseKey] as? String else { return nil } + return UseCase(rawValue: useCaseRawValue) + } set { + dictionary[Constants.useCaseKey] = newValue?.rawValue + } + } + + /// Represents a selected use case for the app. + /// Note: The raw string value is used for storage. + enum UseCase: String { + case personalMessaging + case workMessaging + case communityMessaging + case skipped + } + + // MARK: - Setup + + /// Create new properties for the specified user ID. + /// - Parameter userId: The user ID to load properties for. + init(userId: String) { + self.userId = userId + super.init() + } + + // MARK: - Public + + /// Clear all of the stored properties. + func delete() { + dictionary = [:] + + var sharedProperties = RiotSettings.shared.userSessionProperties + sharedProperties[userId] = nil + RiotSettings.shared.userSessionProperties = sharedProperties + } +} diff --git a/Riot/Managers/UserSessions/UserSessionsService.swift b/Riot/Managers/UserSessions/UserSessionsService.swift index 7a68d9752..c94497161 100644 --- a/Riot/Managers/UserSessions/UserSessionsService.swift +++ b/Riot/Managers/UserSessions/UserSessionsService.swift @@ -131,6 +131,9 @@ class UserSessionsService: NSObject { NotificationCenter.default.post(name: UserSessionsService.willRemoveUserSession, object: self, userInfo: [NotificationUserInfoKey.userSession: userSession]) } + // Clear any stored user properties from this session. + userSession.userProperties.delete() + self.userSessions.removeAll { (userSession) -> Bool in return userId == userSession.userId } diff --git a/Riot/Managers/Widgets/WidgetManager.m b/Riot/Managers/Widgets/WidgetManager.m index 2b25d2e13..240d573c1 100644 --- a/Riot/Managers/Widgets/WidgetManager.m +++ b/Riot/Managers/Widgets/WidgetManager.m @@ -338,7 +338,6 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain"; Check user's power for widgets management in a room. @param room the room to check. - @return an NSError if the user cannot act on widgets in this room. Else, nil. */ - (void)checkWidgetPermissionInRoom:(MXRoom *)room success:(dispatch_block_t)success failure:(void (^)(NSError *))failure { @@ -742,6 +741,8 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain"; return configs[mxSession.myUser.userId].scalarToken; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" - (void)loadConfigs { NSUserDefaults *userDefaults = [MXKAppSettings standardAppSettings].sharedUserDefaults; @@ -787,6 +788,7 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain"; [userDefaults setObject:[NSKeyedArchiver archivedDataWithRootObject:configs] forKey:@"integrationManagerConfigs"]; } +#pragma clang diagnostic pop #pragma mark - Errors diff --git a/Riot/Modules/Analytics/Analytics.swift b/Riot/Modules/Analytics/Analytics.swift index d3b9c3ac1..48716f78e 100644 --- a/Riot/Modules/Analytics/Analytics.swift +++ b/Riot/Modules/Analytics/Analytics.swift @@ -171,6 +171,14 @@ import AnalyticsEvents // The following methods are exposed for compatibility with Objective-C as // the `capture` method and the generated events cannot be bridged from Swift. extension Analytics { + /// Updates any user properties to help with creating cohorts. + /// + /// Only non-nil properties will be updated when calling this method. + func updateUserProperties(ftueUseCase: UserSessionProperties.UseCase? = nil) { + let userProperties = AnalyticsEvent.UserProperties(ftueUseCaseSelection: ftueUseCase?.analyticsName, numSpaces: nil) + client.updateUserProperties(userProperties) + } + /// Track the presentation of a screen /// - Parameters: /// - screen: The screen that was shown. @@ -186,20 +194,21 @@ extension Analytics { trackScreen(screen, duration: nil) } - /// Track an element that has been tapped + /// Track an element that has been interacted with /// - Parameters: - /// - tap: The element that was tapped + /// - uiElement: The element that was interacted with + /// - interactionType: The way in with the element was interacted with /// - index: The index of the element, if it's in a list of elements - func trackTap(_ tap: AnalyticsUIElement, index: Int?) { - let event = AnalyticsEvent.Click(index: index, name: tap.elementName) + func trackInteraction(_ uiElement: AnalyticsUIElement, interactionType: AnalyticsEvent.Interaction.InteractionType, index: Int?) { + let event = AnalyticsEvent.Interaction(index: index, interactionType: interactionType, name: uiElement.name) client.capture(event) } /// Track an element that has been tapped without including an index /// - Parameters: - /// - tap: The element that was tapped - func trackTap(_ tap: AnalyticsUIElement) { - trackTap(tap, index: nil) + /// - uiElement: The element that was tapped + func trackInteraction(_ uiElement: AnalyticsUIElement) { + trackInteraction(uiElement, interactionType: .Touch, index: nil) } /// Track an E2EE error that occurred diff --git a/Riot/Modules/Analytics/AnalyticsClientProtocol.swift b/Riot/Modules/Analytics/AnalyticsClientProtocol.swift index af07a58fb..e16b962e5 100644 --- a/Riot/Modules/Analytics/AnalyticsClientProtocol.swift +++ b/Riot/Modules/Analytics/AnalyticsClientProtocol.swift @@ -45,4 +45,12 @@ protocol AnalyticsClientProtocol { /// Capture the supplied analytics screen event. /// - Parameter event: The screen event to capture. func screen(_ event: AnalyticsScreenProtocol) + + /// Updates any user properties to help with creating cohorts. + /// - Parameter userProperties: The user properties to be updated. + /// + /// Only non-nil properties will be updated when calling this method. There might + /// be a delay when updating user properties as these are cached to be included + /// as part of the next event that gets captured. + func updateUserProperties(_ userProperties: AnalyticsEvent.UserProperties) } diff --git a/Riot/Modules/Analytics/AnalyticsScreen.swift b/Riot/Modules/Analytics/AnalyticsScreen.swift index 86f567acd..048e484e8 100644 --- a/Riot/Modules/Analytics/AnalyticsScreen.swift +++ b/Riot/Modules/Analytics/AnalyticsScreen.swift @@ -18,6 +18,10 @@ import Foundation import AnalyticsEvents @objc enum AnalyticsScreen: Int { + case welcome + case login + case register + case forgotPassword case sidebar case home case favourites @@ -51,6 +55,14 @@ import AnalyticsEvents /// The screen name reported to the AnalyticsEvent. var screenName: AnalyticsEvent.Screen.ScreenName { switch self { + case .welcome: + return .Welcome + case .login: + return .Login + case .register: + return .Register + case .forgotPassword: + return .ForgotPassword case .sidebar: return .MobileSidebar case .home: diff --git a/Riot/Modules/Analytics/AnalyticsUIElement.swift b/Riot/Modules/Analytics/AnalyticsUIElement.swift index 93a08e7e2..5a25d453e 100644 --- a/Riot/Modules/Analytics/AnalyticsUIElement.swift +++ b/Riot/Modules/Analytics/AnalyticsUIElement.swift @@ -16,17 +16,17 @@ import AnalyticsEvents -/// A tappable UI element that can be track in Analytics. +/// A tappable UI element that can be tracked in Analytics. @objc enum AnalyticsUIElement: Int { - case sendMessageButton + case removeMe /// The element name reported to the AnalyticsEvent. - var elementName: AnalyticsEvent.Click.Name { + var name: AnalyticsEvent.Interaction.Name { switch self { // Note: This is a test element that doesn't need to be captured. - // It will likely be removed when the AnalyticsEvent.Click is updated. - case .sendMessageButton: - return .SendMessageButton + // It can be removed when some elements are added that relate to mobile. + case .removeMe: + return .WebRoomSettingsLeaveButton } } } diff --git a/Riot/Modules/Analytics/Helpers/UserSessionPropertiesUseCase+Analytics.swift b/Riot/Modules/Analytics/Helpers/UserSessionPropertiesUseCase+Analytics.swift new file mode 100644 index 000000000..c5e601b37 --- /dev/null +++ b/Riot/Modules/Analytics/Helpers/UserSessionPropertiesUseCase+Analytics.swift @@ -0,0 +1,33 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import AnalyticsEvents + +extension UserSessionProperties.UseCase { + var analyticsName: AnalyticsEvent.UserProperties.FtueUseCaseSelection { + switch self { + case .personalMessaging: + return .PersonalMessaging + case .workMessaging: + return .WorkMessaging + case .communityMessaging: + return .CommunityMessaging + case .skipped: + return .Skip + } + } +} diff --git a/Riot/Modules/Analytics/PostHogAnalyticsClient.swift b/Riot/Modules/Analytics/PostHogAnalyticsClient.swift index 1c7172112..434ce978e 100644 --- a/Riot/Modules/Analytics/PostHogAnalyticsClient.swift +++ b/Riot/Modules/Analytics/PostHogAnalyticsClient.swift @@ -22,6 +22,9 @@ class PostHogAnalyticsClient: AnalyticsClientProtocol { /// The PHGPostHog object used to report events. private var postHog: PHGPostHog? + /// Any user properties to be included with the next captured event. + private(set) var pendingUserProperties: AnalyticsEvent.UserProperties? + var isRunning: Bool { postHog?.enabled ?? false } func start() { @@ -36,11 +39,18 @@ class PostHogAnalyticsClient: AnalyticsClientProtocol { } func identify(id: String) { - postHog?.identify(id) + if let userProperties = pendingUserProperties { + // As user properties overwrite old ones, compactMap the dictionary to avoid resetting any missing properties + postHog?.identify(id, properties: userProperties.properties.compactMapValues { $0 }) + pendingUserProperties = nil + } else { + postHog?.identify(id) + } } func reset() { postHog?.reset() + pendingUserProperties = nil } func stop() { @@ -55,11 +65,38 @@ class PostHogAnalyticsClient: AnalyticsClientProtocol { } func capture(_ event: AnalyticsEventProtocol) { - postHog?.capture(event.eventName, properties: event.properties) + postHog?.capture(event.eventName, properties: attachUserProperties(to: event.properties)) } func screen(_ event: AnalyticsScreenProtocol) { - postHog?.screen(event.screenName.rawValue, properties: event.properties) + postHog?.screen(event.screenName.rawValue, properties: attachUserProperties(to: event.properties)) } + func updateUserProperties(_ userProperties: AnalyticsEvent.UserProperties) { + guard let pendingUserProperties = pendingUserProperties else { + pendingUserProperties = userProperties + return + } + + // Merge the updated user properties with the existing ones + self.pendingUserProperties = AnalyticsEvent.UserProperties(ftueUseCaseSelection: userProperties.ftueUseCaseSelection ?? pendingUserProperties.ftueUseCaseSelection, + numSpaces: userProperties.numSpaces ?? pendingUserProperties.numSpaces) + } + + // MARK: - Private + + /// Given a dictionary containing properties from an event, this method will return those properties + /// with any pending user properties included under the `$set` key. + /// - Parameter properties: A dictionary of properties from an event. + /// - Returns: The `properties` dictionary with any user properties included. + private func attachUserProperties(to properties: [String: Any]) -> [String: Any] { + guard isRunning, let userProperties = pendingUserProperties else { return properties } + + var properties = properties + + // As user properties overwrite old ones via $set, compactMap the dictionary to avoid resetting any missing properties + properties["$set"] = userProperties.properties.compactMapValues { $0 } + pendingUserProperties = nil + return properties + } } diff --git a/Riot/Modules/Application/AppAlertPresenter.swift b/Riot/Modules/Application/AppAlertPresenter.swift deleted file mode 100644 index f60a5ef34..000000000 --- a/Riot/Modules/Application/AppAlertPresenter.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// Copyright 2021 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -class AppAlertPresenter: AlertPresentable { - - // MARK: - Properties - - // swiftlint:disable weak_delegate - private let legacyAppDelegate: LegacyAppDelegate - // swiftlint:enable weak_delegate - - // MARK: - Setup - - init(legacyAppDelegate: LegacyAppDelegate) { - self.legacyAppDelegate = legacyAppDelegate - } - - // MARK: - Public - - func showError(_ error: Error, animated: Bool, completion: (() -> Void)?) { - // FIXME: Present an error on coordinator.toPresentable() - self.legacyAppDelegate.showError(asAlert: error) - } - - func show(title: String?, message: String?, animated: Bool, completion: (() -> Void)?) { - // FIXME: Present an error on coordinator.toPresentable() - self.legacyAppDelegate.showAlert(withTitle: title, message: message) - } -} diff --git a/Riot/Modules/Application/AppCoordinator.swift b/Riot/Modules/Application/AppCoordinator.swift index d60faf924..8f1b61d58 100755 --- a/Riot/Modules/Application/AppCoordinator.swift +++ b/Riot/Modules/Application/AppCoordinator.swift @@ -16,6 +16,9 @@ import Foundation import Intents +import MatrixSDK +import CommonKit +import UIKit #if DEBUG import FLEX @@ -46,7 +49,7 @@ final class AppCoordinator: NSObject, AppCoordinatorType { return AppNavigator(appCoordinator: self) }() - private weak var splitViewCoordinator: SplitViewCoordinatorType? + fileprivate weak var splitViewCoordinator: SplitViewCoordinatorType? fileprivate weak var sideMenuCoordinator: SideMenuCoordinatorType? private let userSessionsService: UserSessionsService @@ -79,6 +82,7 @@ final class AppCoordinator: NSObject, AppCoordinatorType { func start() { self.setupLogger() self.setupTheme() + self.excludeAllItemsFromBackup() // Setup navigation router store _ = NavigationRouterStore.shared @@ -129,6 +133,17 @@ final class AppCoordinator: NSObject, AppCoordinatorType { } } + private func excludeAllItemsFromBackup() { + let manager = FileManager.default + + // Individual files and directories created by the application or SDK are excluded case-by-case, + // but sometimes the lifecycle of a file is not directly controlled by the app (e.g. plists for + // UserDefaults). For that reason the app will always exclude all top-level directories as well + // as individual files. + manager.excludeAllUserDirectoriesFromBackup() + manager.excludeAllAppGroupDirectoriesFromBackup() + } + private func showAuthentication() { // TODO: Implement } @@ -275,8 +290,6 @@ fileprivate class AppNavigator: AppNavigatorProtocol { private unowned let appCoordinator: AppCoordinator - let alert: AlertPresentable - lazy var sideMenu: SideMenuPresentable = { guard let sideMenuCoordinator = appCoordinator.sideMenuCoordinator else { fatalError("sideMenuCoordinator is not initialized") @@ -285,11 +298,22 @@ fileprivate class AppNavigator: AppNavigatorProtocol { return SideMenuPresenter(sideMenuCoordinator: sideMenuCoordinator) }() + private var appNavigationVC: UINavigationController { + guard + let splitVC = appCoordinator.splitViewCoordinator?.toPresentable() as? UISplitViewController, + // Picking out the first view controller currently works only on iPhones, not iPads + let navigationVC = splitVC.viewControllers.first as? UINavigationController + else { + MXLog.error("[AppNavigator] Missing root split view controller") + return UINavigationController() + } + return navigationVC + } + // MARK: - Setup init(appCoordinator: AppCoordinator) { self.appCoordinator = appCoordinator - self.alert = AppAlertPresenter(legacyAppDelegate: appCoordinator.legacyAppDelegate) } // MARK: - Public @@ -297,4 +321,16 @@ fileprivate class AppNavigator: AppNavigatorProtocol { func navigate(to destination: AppNavigatorDestination) { self.appCoordinator.navigate(to: destination) } + + func addLoadingActivity() -> Activity { + let presenter = ActivityIndicatorToastPresenter( + text: VectorL10n.roomParticipantsSecurityLoading, + navigationController: appNavigationVC + ) + let request = ActivityRequest( + presenter: presenter, + dismissal: .manual + ) + return ActivityCenter.shared.add(request) + } } diff --git a/Riot/Modules/Application/AppNavigator.swift b/Riot/Modules/Application/AppNavigator.swift index d3b7eddf4..c33b572f4 100644 --- a/Riot/Modules/Application/AppNavigator.swift +++ b/Riot/Modules/Application/AppNavigator.swift @@ -15,6 +15,7 @@ // import Foundation +import CommonKit /// AppNavigatorProtocol abstract a navigator at app level. /// It enables to perform the navigation within the global app scope (open the side menu, open a room and so on) @@ -22,9 +23,16 @@ import Foundation protocol AppNavigatorProtocol { var sideMenu: SideMenuPresentable { get } - var alert: AlertPresentable { get } /// Navigate to a destination screen or a state /// Do not use protocol with associatedtype for the moment like presented here https://www.swiftbysundell.com/articles/navigation-in-swift/#where-to-navigator use a separate enum func navigate(to destination: AppNavigatorDestination) + + /// Add loading activity to an app-wide queue of other activitie + /// + /// If the queue is empty, the activity will be displayed immediately, otherwise it will be pending + /// until the previously added activities have completed / been cancelled. + /// + /// To remove an activity indicator, cancel or deallocate the returned `Activity` + func addLoadingActivity() -> Activity } diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index 3d62fdb16..1c74e5ede 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -232,6 +232,17 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni */ @property (nonatomic, assign, getter=isRoomListDataReady) BOOL roomListDataReady; +/** + An observer token for `RecentsViewControllerDataReadyNotification`s notifications. + */ +@property (nonatomic, nullable) id roomListDataReadyObserver; + +/** + An optional completion block that will be called when a `RecentsViewControllerDataReadyNotification` + is observed during app launch. + */ +@property (nonatomic, copy, nullable) void (^roomListDataReadyCompletion)(void); + /** Flag to indicate whether a cache clear is being performed. */ @@ -838,28 +849,28 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni } // Enable error notifications - isErrorNotificationSuspended = NO; + self->isErrorNotificationSuspended = NO; - if (noCallSupportAlert) + if (self->noCallSupportAlert) { MXLogDebug(@"[AppDelegate] restoreInitialDisplay: keep visible noCall support alert"); - [self showNotificationAlert:noCallSupportAlert]; + [self showNotificationAlert:self->noCallSupportAlert]; } - else if (cryptoDataCorruptedAlert) + else if (self->cryptoDataCorruptedAlert) { MXLogDebug(@"[AppDelegate] restoreInitialDisplay: keep visible log in again"); - [self showNotificationAlert:cryptoDataCorruptedAlert]; + [self showNotificationAlert:self->cryptoDataCorruptedAlert]; } - else if (wrongBackupVersionAlert) + else if (self->wrongBackupVersionAlert) { MXLogDebug(@"[AppDelegate] restoreInitialDisplay: keep visible wrongBackupVersionAlert"); - [self showNotificationAlert:wrongBackupVersionAlert]; + [self showNotificationAlert:self->wrongBackupVersionAlert]; } // Check whether an error notification is pending - else if (_errorNotification) + else if (self->_errorNotification) { - [self showNotificationAlert:_errorNotification]; + [self showNotificationAlert:self->_errorNotification]; } }]; @@ -876,10 +887,10 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni } // Enable error notification (Check whether a notification is pending) - isErrorNotificationSuspended = NO; - if (_errorNotification) + self->isErrorNotificationSuspended = NO; + if (self->_errorNotification) { - [self showNotificationAlert:_errorNotification]; + [self showNotificationAlert:self->_errorNotification]; } }]; } @@ -1377,6 +1388,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni event = eventFromServer; dispatch_group_leave(eventDispatchGroup); } failure:^(NSError *error) { + MXLogError(@"[LegacyAppDelegate] handleUniversalLinkWithParameters: event fetch failed: %@", error); dispatch_group_leave(eventDispatchGroup); }]; } @@ -1428,9 +1440,9 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni else { void(^findRoom)(void) = ^{ - if ([_masterTabBarController.selectedViewController conformsToProtocol:@protocol(MXKViewControllerActivityHandling)]) + if ([self->_masterTabBarController.selectedViewController conformsToProtocol:@protocol(MXKViewControllerActivityHandling)]) { - UIViewController *homeViewController = (UIViewController*)_masterTabBarController.selectedViewController; + UIViewController *homeViewController = (UIViewController*)self->_masterTabBarController.selectedViewController; [homeViewController startActivityIndicator]; @@ -1438,7 +1450,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni { // The alias may be not part of user's rooms states // Ask the HS to resolve the room alias into a room id and then retry - universalLinkFragmentPending = fragment; + self->universalLinkFragmentPending = fragment; MXKAccount* account = accountManager.activeAccounts.firstObject; [account.mxSession.matrixRestClient roomIDForRoomAlias:roomIdOrAlias success:^(NSString *roomId) { @@ -1446,7 +1458,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni [homeViewController stopActivityIndicator]; // Check that 'fragment' has not been cancelled - if ([universalLinkFragmentPending isEqualToString:fragment]) + if ([self->universalLinkFragmentPending isEqualToString:fragment]) { // Retry opening the link but with the returned room id NSString *newUniversalLinkFragment = @@ -1466,7 +1478,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni if (![newUniversalLinkFragment isEqualToString:fragment]) { - universalLinkFragmentPendingRoomAlias = @{roomId: roomIdOrAlias}; + self->universalLinkFragmentPendingRoomAlias = @{roomId: roomIdOrAlias}; UniversalLinkParameters *newParameters = [[UniversalLinkParameters alloc] initWithFragment:newUniversalLinkFragment universalLinkURL:universalLinkURL presentationParameters:presentationParameters]; @@ -1497,12 +1509,12 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni MXKAccount* account = accountManager.activeAccounts.firstObject; MXLogDebug(@"[AppDelegate] Universal link: Need to wait for the session to be sync'ed and running"); - universalLinkFragmentPending = fragment; + self->universalLinkFragmentPending = fragment; - universalLinkWaitingObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull notif) { + self->universalLinkWaitingObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull notif) { // Check that 'fragment' has not been cancelled - if ([universalLinkFragmentPending isEqualToString:fragment]) + if ([self->universalLinkFragmentPending isEqualToString:fragment]) { // Check whether the concerned session is the associated one if (notif.object == account.mxSession && account.mxSession.state == MXSessionStateRunning) @@ -1581,7 +1593,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni universalLinkWaitingObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidAddAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { // Check that 'fragment' has not been cancelled - if ([universalLinkFragmentPending isEqualToString:fragment]) + if ([self->universalLinkFragmentPending isEqualToString:fragment]) { MXLogDebug(@"[AppDelegate] Universal link: The user is now logged in. Retry the link"); [self handleUniversalLinkWithParameters:universalLinkParameters]; @@ -1646,7 +1658,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni universalLinkWaitingObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountManagerDidAddAccountNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { // Check that 'fragment' has not been cancelled - if ([universalLinkFragmentPending isEqualToString:fragment]) + if ([self->universalLinkFragmentPending isEqualToString:fragment]) { MXLogDebug(@"[AppDelegate] Universal link: The user is now logged in. Retry the link"); [self handleUniversalLinkWithParameters:universalLinkParameters]; @@ -2318,7 +2330,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni } // Return to authentication screen - [_masterTabBarController showOnboardingFlow]; + [self->_masterTabBarController showOnboardingFlow]; // Note: Keep App settings // But enforce usage of member lazy loading @@ -2373,6 +2385,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni case MXSessionStateInitialised: case MXSessionStateBackgroundSyncInProgress: self.roomListDataReady = NO; + [self listenForRoomListDataReady]; isLaunching = YES; break; case MXSessionStateStoreDataReady: @@ -2397,6 +2410,12 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni MXLogDebug(@"[AppDelegate] handleAppState: isLaunching: %@", isLaunching ? @"YES" : @"NO"); + if (self.masterTabBarController.isOnboardingInProgress) + { + MXLogDebug(@"[AppDelegate] handleAppState: Skipping LaunchLoadingView due to Onboarding."); + return; + } + if (isLaunching) { MXLogDebug(@"[AppDelegate] handleAppState: LaunchLoadingView"); @@ -2410,7 +2429,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni return; } - [self ensureRoomListDataReadyWithCompletion:^{ + void (^finishAppLaunch)(void) = ^{ [self hideLaunchAnimation]; if (self.setPinCoordinatorBridgePresenter) @@ -2442,7 +2461,17 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni // Enable listening of incoming key verification requests [self enableIncomingKeyVerificationObserver:mainSession]; } - }]; + }; + + if (self.isRoomListDataReady) + { + finishAppLaunch(); + } + else + { + // An observer has been set in didFinishLaunching that will call the stored block when ready + self.roomListDataReadyCompletion = finishAppLaunch; + } } } @@ -2598,29 +2627,31 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni [self handleAppState]; } -/** - Ensures room list data is ready. - - @param completion Completion block to be called when it's ready. Not dispatched in case the data is already ready. - */ -- (void)ensureRoomListDataReadyWithCompletion:(void(^)(void))completion +- (void)listenForRoomListDataReady { - if (self.isRoomListDataReady) + if (self.roomListDataReadyObserver) { - completion(); - } - else - { - NSNotificationCenter * __weak notificationCenter = [NSNotificationCenter defaultCenter]; - __block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:RecentsViewControllerDataReadyNotification - object:nil - queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification * _Nonnull notification) { - [notificationCenter removeObserver:observer]; - self.roomListDataReady = YES; - completion(); - }]; + return; } + + MXWeakify(self); + NSNotificationCenter * __weak notificationCenter = [NSNotificationCenter defaultCenter]; + self.roomListDataReadyObserver = [[NSNotificationCenter defaultCenter] addObserverForName:RecentsViewControllerDataReadyNotification + object:nil + queue:[NSOperationQueue mainQueue] + usingBlock:^(NSNotification * _Nonnull notification) { + MXStrongifyAndReturnIfNil(self); + + [notificationCenter removeObserver:self.roomListDataReadyObserver]; + self.roomListDataReady = YES; + self.roomListDataReadyObserver = nil; + + if (self.roomListDataReadyCompletion) + { + self.roomListDataReadyCompletion(); + self.roomListDataReadyCompletion = nil; + } + }]; } #pragma mark - @@ -2729,7 +2760,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni if ([[ruleAction.parameters valueForKey:@"set_tweak"] isEqualToString:@"sound"]) { // Play message sound - AudioServicesPlaySystemSound(_messageSound); + AudioServicesPlaySystemSound(self->_messageSound); } } } @@ -3424,9 +3455,9 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni { case MXEventTypeCallInvite: { - if (noCallSupportAlert) + if (self->noCallSupportAlert) { - [noCallSupportAlert dismissViewControllerAnimated:NO completion:nil]; + [self->noCallSupportAlert dismissViewControllerAnimated:NO completion:nil]; } MXCallInviteEventContent *callInviteEventContent = [MXCallInviteEventContent modelFromJSON:event.content]; @@ -3448,15 +3479,15 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni NSString *message = [VectorL10n noVoip:callerDisplayname :appDisplayName]; - noCallSupportAlert = [UIAlertController alertControllerWithTitle:[VectorL10n noVoipTitle] - message:message - preferredStyle:UIAlertControllerStyleAlert]; + self->noCallSupportAlert = [UIAlertController alertControllerWithTitle:[VectorL10n noVoipTitle] + message:message + preferredStyle:UIAlertControllerStyleAlert]; __weak typeof(self) weakSelf = self; - [noCallSupportAlert addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n ignore] - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) { + [self->noCallSupportAlert addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n ignore] + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { if (weakSelf) { @@ -3466,9 +3497,9 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni }]]; - [noCallSupportAlert addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n rejectCall] - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) { + [self->noCallSupportAlert addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n rejectCall] + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { // Reject the call by sending the hangup event NSDictionary *content = @{ @@ -3489,7 +3520,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni }]]; - [self showNotificationAlert:noCallSupportAlert]; + [self showNotificationAlert:self->noCallSupportAlert]; break; } @@ -3497,10 +3528,10 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni case MXEventTypeCallHangup: case MXEventTypeCallReject: // The call has ended. The alert is no more needed. - if (noCallSupportAlert) + if (self->noCallSupportAlert) { - [noCallSupportAlert dismissViewControllerAnimated:YES completion:nil]; - noCallSupportAlert = nil; + [self->noCallSupportAlert dismissViewControllerAnimated:YES completion:nil]; + self->noCallSupportAlert = nil; } break; diff --git a/Riot/Modules/Authentication/AuthenticationCoordinator.swift b/Riot/Modules/Authentication/AuthenticationCoordinator.swift index a310cdb1a..865161941 100644 --- a/Riot/Modules/Authentication/AuthenticationCoordinator.swift +++ b/Riot/Modules/Authentication/AuthenticationCoordinator.swift @@ -16,7 +16,6 @@ limitations under the License. */ -import Foundation import UIKit /// A coordinator that handles authentication, verification and setting a PIN. @@ -26,17 +25,27 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc // MARK: Private + private let navigationRouter: NavigationRouterType + private let authenticationViewController: AuthenticationViewController + private let crossSigningService = CrossSigningService() + + /// The password entered, for use when setting up cross-signing. + private var password: String? + /// The session created when successfully authenticated. + private var session: MXSession? // MARK: Public // Must be used only internally var childCoordinators: [Coordinator] = [] - var completion: (() -> Void)? + var completion: ((AuthenticationCoordinatorResult) -> Void)? // MARK: - Setup - override init() { + init(parameters: AuthenticationCoordinatorParameters) { + self.navigationRouter = parameters.navigationRouter + let authenticationViewController = AuthenticationViewController() self.authenticationViewController = authenticationViewController @@ -62,6 +71,10 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc authenticationViewController.authType = authenticationType } + func showCustomServer() { + authenticationViewController.setCustomServerFieldsVisible(true) + } + func update(externalRegistrationParameters: [AnyHashable: Any]) { authenticationViewController.externalRegistrationParameters = externalRegistrationParameters } @@ -77,11 +90,157 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc func continueSSOLogin(withToken loginToken: String, transactionID: String) -> Bool { authenticationViewController.continueSSOLogin(withToken: loginToken, txnId: transactionID) } + + // MARK: - Private + + private func showLoadingAnimation() { + let loadingViewController = LaunchLoadingViewController() + loadingViewController.modalPresentationStyle = .fullScreen + + // Replace the navigation stack with the loading animation + // as there is nothing to navigate back to. + navigationRouter.setRootModule(loadingViewController) + } + + private func presentCompleteSecurity(with session: MXSession) { + let isNewSignIn = true + let keyVerificationCoordinator = KeyVerificationCoordinator(session: session, flow: .completeSecurity(isNewSignIn)) + + keyVerificationCoordinator.delegate = self + let presentable = keyVerificationCoordinator.toPresentable() + presentable.presentationController?.delegate = self + navigationRouter.present(presentable, animated: true) + keyVerificationCoordinator.start() + add(childCoordinator: keyVerificationCoordinator) + } + + private func authenticationDidComplete() { + completion?(.didComplete(authenticationViewController.authType)) + } + + private func registerSessionStateChangeNotification(for session: MXSession) { + NotificationCenter.default.addObserver(self, selector: #selector(sessionStateDidChange), name: .mxSessionStateDidChange, object: session) + } + + private func unregisterSessionStateChangeNotification() { + NotificationCenter.default.removeObserver(self, name: .mxSessionStateDidChange, object: nil) + } + + @objc private func sessionStateDidChange(_ notification: Notification) { + guard let session = notification.object as? MXSession else { + MXLog.error("[AuthenticationCoordinator] sessionStateDidChange: Missing session in the notification") + return + } + + if session.state == .storeDataReady { + if let crypto = session.crypto, crypto.crossSigning != nil { + // Do not make key share requests while the "Complete security" is not complete. + // If the device is self-verified, the SDK will restore the existing key backup. + // Then, it will re-enable outgoing key share requests + crypto.setOutgoingKeyRequestsEnabled(false, onComplete: nil) + } + } else if session.state == .running { + unregisterSessionStateChangeNotification() + + if let crypto = session.crypto, let crossSigning = crypto.crossSigning { + crossSigning.refreshState { [weak self] stateUpdated in + guard let self = self else { return } + + MXLog.debug("[AuthenticationCoordinator] sessionStateDidChange: crossSigning.state: \(crossSigning.state)") + + switch crossSigning.state { + case .notBootstrapped: + // TODO: This is still not sure we want to disable the automatic cross-signing bootstrap + // if the admin disabled e2e by default. + // Do like riot-web for the moment + if session.vc_homeserverConfiguration().isE2EEByDefaultEnabled { + // Bootstrap cross-signing on user's account + // We do it for both registration and new login as long as cross-signing does not exist yet + if let password = self.password, !password.isEmpty { + MXLog.debug("[AuthenticationCoordinator] sessionStateDidChange: Bootstrap with password") + + crossSigning.setup(withPassword: password) { + MXLog.debug("[AuthenticationCoordinator] sessionStateDidChange: Bootstrap succeeded") + self.authenticationDidComplete() + } failure: { error in + MXLog.error("[AuthenticationCoordinator] sessionStateDidChange: Bootstrap failed. Error: \(error)") + crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil) + self.authenticationDidComplete() + } + } else { + // Try to setup cross-signing without authentication parameters in case if a grace period is enabled + self.crossSigningService.setupCrossSigningWithoutAuthentication(for: session) { + MXLog.debug("[AuthenticationCoordinator] sessionStateDidChange: Bootstrap succeeded without credentials") + self.authenticationDidComplete() + } failure: { error in + MXLog.error("[AuthenticationCoordinator] sessionStateDidChange: Do not know how to bootstrap cross-signing. Skip it.") + crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil) + self.authenticationDidComplete() + } + } + } else { + crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil) + self.authenticationDidComplete() + } + case .crossSigningExists: + MXLog.debug("[AuthenticationCoordinator] sessionStateDidChange: Complete security") + self.presentCompleteSecurity(with: session) + default: + MXLog.debug("[AuthenticationCoordinator] sessionStateDidChange: Nothing to do") + + crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil) + self.authenticationDidComplete() + } + } failure: { [weak self] error in + MXLog.error("[AuthenticationCoordinator] sessionStateDidChange: Fail to refresh crypto state with error: \(error)") + crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil) + self?.authenticationDidComplete() + } + } else { + authenticationDidComplete() + } + } + } } // MARK: - AuthenticationViewControllerDelegate extension AuthenticationCoordinator: AuthenticationViewControllerDelegate { - func authenticationViewControllerDidDismiss(_ authenticationViewController: AuthenticationViewController!) { - completion?() + func authenticationViewController(_ authenticationViewController: AuthenticationViewController!, didLoginWith session: MXSession!, andPassword password: String!) { + registerSessionStateChangeNotification(for: session) + + self.session = session + self.password = password + + self.showLoadingAnimation() + completion?(.didLogin(session)) + } +} + +// MARK: - KeyVerificationCoordinatorDelegate +extension AuthenticationCoordinator: KeyVerificationCoordinatorDelegate { + func keyVerificationCoordinatorDidComplete(_ coordinator: KeyVerificationCoordinatorType, otherUserId: String, otherDeviceId: String) { + if let crypto = session?.crypto, + !crypto.backup.hasPrivateKeyInCryptoStore || !crypto.backup.enabled { + MXLog.debug("[AuthenticationCoordinator][MXKeyVerification] requestAllPrivateKeys: Request key backup private keys") + crypto.setOutgoingKeyRequestsEnabled(true, onComplete: nil) + } + + navigationRouter.dismissModule(animated: true) { [weak self] in + self?.authenticationDidComplete() + } + } + + func keyVerificationCoordinatorDidCancel(_ coordinator: KeyVerificationCoordinatorType) { + navigationRouter.dismissModule(animated: true) { [weak self] in + self?.authenticationDidComplete() + } + } +} + +// MARK: - UIAdaptivePresentationControllerDelegate +extension AuthenticationCoordinator: UIAdaptivePresentationControllerDelegate { + func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { + // Prevent Key Verification from using swipe to dismiss + return false } } diff --git a/Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift b/Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift index 7037f9d1f..c024cddbe 100644 --- a/Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift +++ b/Riot/Modules/Authentication/AuthenticationCoordinatorProtocol.swift @@ -18,13 +18,28 @@ import Foundation +struct AuthenticationCoordinatorParameters { + let navigationRouter: NavigationRouterType +} + +enum AuthenticationCoordinatorResult { + /// The user has authenticated but key verification is yet to happen. The session value is + /// for a fresh session that still needs to load, sync etc before being ready. + case didLogin(MXSession) + /// All of the required authentication steps including key verification is complete. + case didComplete(MXKAuthenticationType) +} + /// `AuthenticationCoordinatorProtocol` is a protocol describing a Coordinator that handle's the authentication navigation flow. protocol AuthenticationCoordinatorProtocol: Coordinator, Presentable { - var completion: (() -> Void)? { get set } + var completion: ((AuthenticationCoordinatorResult) -> Void)? { get set } /// Update the screen to display registration or login. func update(authenticationType: MXKAuthenticationType) + /// Enable the custom server checkbox to allow the user to enter a homeserver URL. + func showCustomServer() + /// Force a registration process based on a predefined set of parameters from a server provisioning link. /// For more information see `AuthenticationViewController.externalRegistrationParameters`. func update(externalRegistrationParameters: [AnyHashable: Any]) diff --git a/Riot/Modules/Authentication/AuthenticationViewController.h b/Riot/Modules/Authentication/AuthenticationViewController.h index 894ea8b45..dd76303a4 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.h +++ b/Riot/Modules/Authentication/AuthenticationViewController.h @@ -37,7 +37,6 @@ @property (weak, nonatomic) IBOutlet UIButton *customServersTickButton; @property (weak, nonatomic) IBOutlet UIView *customServersContainer; @property (weak, nonatomic) IBOutlet UIView *homeServerContainer; -@property (weak, nonatomic) IBOutlet UIView *identityServerContainer; @property (weak, nonatomic) IBOutlet UIView *homeServerSeparator; @property (weak, nonatomic) IBOutlet UIView *identityServerSeparator; @@ -54,11 +53,17 @@ /// returns YES if the SSO login can be continued. - (BOOL)continueSSOLoginWithToken:(NSString*)loginToken txnId:(NSString*)txnId; +/// Show or hide the custom server textfields. +/// @param isVisible YES to show, NO to hide. +- (void)setCustomServerFieldsVisible:(BOOL)isVisible; + @end @protocol AuthenticationViewControllerDelegate -- (void)authenticationViewControllerDidDismiss:(AuthenticationViewController *)authenticationViewController; +- (void)authenticationViewController:(AuthenticationViewController *)authenticationViewController + didLoginWithSession:(MXSession *)session + andPassword:(NSString *)password; @end; diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index 4f76a029b..425fb4da6 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -28,7 +28,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; -@interface AuthenticationViewController () @@ -63,7 +63,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; } @property (nonatomic, readonly) BOOL isIdentityServerConfigured; -@property (nonatomic, strong) KeyVerificationCoordinatorBridgePresenter *keyVerificationCoordinatorBridgePresenter; @property (nonatomic, strong) SetPinCoordinatorBridgePresenter *setPinCoordinatorBridgePresenter; @property (nonatomic, strong) KeyboardAvoider *keyboardAvoider; @@ -78,8 +77,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; // Current SSO transaction id used to identify and validate the SSO authentication callback @property (nonatomic, strong) NSString *ssoCallbackTxnId; -@property (nonatomic, strong) CrossSigningService *crossSigningService; - @property (nonatomic, getter = isFirstViewAppearing) BOOL firstViewAppearing; @property (nonatomic, strong) MXKErrorAlertPresentation *errorPresenter; @@ -118,7 +115,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; _firstViewAppearing = YES; - self.crossSigningService = [CrossSigningService new]; self.errorPresenter = [MXKErrorAlertPresentation new]; } @@ -136,7 +132,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; self.defaultIdentityServerUrl = RiotSettings.shared.identityServerUrlString; - self.welcomeImageView.image = [UIImage imageNamed:@"horizontal_logo"]; + self.welcomeImageView.image = AssetSharedImages.horizontalLogo.image; [self.submitButton.layer setCornerRadius:5]; self.submitButton.clipsToBounds = YES; @@ -150,8 +146,8 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; [self.skipButton setTitle:[VectorL10n authSkip] forState:UIControlStateHighlighted]; self.skipButton.enabled = YES; - [self.customServersTickButton setImage:[UIImage imageNamed:@"selection_untick"] forState:UIControlStateNormal]; - [self.customServersTickButton setImage:[UIImage imageNamed:@"selection_untick"] forState:UIControlStateHighlighted]; + [self.customServersTickButton setImage:AssetImages.selectionUntick.image forState:UIControlStateNormal]; + [self.customServersTickButton setImage:AssetImages.selectionUntick.image forState:UIControlStateHighlighted]; if (!BuildSettings.authScreenShowRegister) { @@ -160,7 +156,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; } self.serverOptionsContainer.hidden = !BuildSettings.authScreenShowCustomServerOptions; - [self hideCustomServers:YES]; + [self setCustomServerFieldsVisible:NO]; // Soft logout section self.softLogoutClearDataButton.layer.cornerRadius = 5; @@ -214,7 +210,8 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; - (void)userInterfaceThemeDidChange { - [ThemeService.shared.theme applyStyleOnNavigationBar:self.navigationController.navigationBar]; + [ThemeService.shared.theme applyStyleOnNavigationBar:self.navigationController.navigationBar + withModernScrollEdgesAppearance:YES]; self.view.backgroundColor = ThemeService.shared.theme.backgroundColor; @@ -317,11 +314,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; { self.firstViewAppearing = NO; } - - if (self.keyVerificationCoordinatorBridgePresenter) - { - return; - } // Verify that the app does not show the authentication screen whereas // the user has already logged in. @@ -378,7 +370,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; [self.authenticationActivityIndicator removeObserver:self forKeyPath:@"hidden"]; autoDiscovery = nil; - _keyVerificationCoordinatorBridgePresenter = nil; _keyboardAvoider = nil; } @@ -556,30 +547,6 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; } } -- (void)presentCompleteSecurityWithSession:(MXSession*)session -{ - KeyVerificationCoordinatorBridgePresenter *keyVerificationCoordinatorBridgePresenter = [[KeyVerificationCoordinatorBridgePresenter alloc] initWithSession:session]; - keyVerificationCoordinatorBridgePresenter.delegate = self; - - [keyVerificationCoordinatorBridgePresenter presentCompleteSecurityFrom:self isNewSignIn:YES animated:YES]; - - self.keyVerificationCoordinatorBridgePresenter = keyVerificationCoordinatorBridgePresenter; -} - -- (void)dismiss -{ - self.userInteractionEnabled = YES; - [self.authenticationActivityIndicator stopAnimating]; - - // Dismiss (key verification) on successful login - [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; - - if (self.authVCDelegate) - { - [self.authVCDelegate authenticationViewControllerDidDismiss:self]; - } -} - - (BOOL)continueSSOLoginWithToken:(NSString*)loginToken txnId:(NSString*)txnId { // Check if transaction id is the same as expected @@ -887,7 +854,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; { if (sender == self.customServersTickButton) { - [self hideCustomServers:!self.customServersContainer.hidden]; + [self setCustomServerFieldsVisible:self.customServersContainer.hidden]; } else if (sender == self.forgotPasswordButton) { @@ -1235,14 +1202,14 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; [self.view layoutIfNeeded]; } -- (void)hideCustomServers:(BOOL)hidden +- (void)setCustomServerFieldsVisible:(BOOL)isVisible { - if (self.customServersContainer.isHidden == hidden) + if (self.customServersContainer.isHidden != isVisible) { return; } - if (hidden) + if (!isVisible) { [self.homeServerTextField resignFirstResponder]; [self.identityServerTextField resignFirstResponder]; @@ -1272,7 +1239,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; [self setHomeServerTextFieldText:self.defaultHomeServerUrl]; [self setIdentityServerTextFieldText:self.defaultIdentityServerUrl]; - [self.customServersTickButton setImage:[UIImage imageNamed:@"selection_untick"] forState:UIControlStateNormal]; + [self.customServersTickButton setImage:AssetImages.selectionUntick.image forState:UIControlStateNormal]; self.customServersContainer.hidden = YES; // Refresh content view height @@ -1296,7 +1263,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; [self setIdentityServerTextFieldText:customIdentityServerURL]; } - [self.customServersTickButton setImage:[UIImage imageNamed:@"selection_tick"] forState:UIControlStateNormal]; + [self.customServersTickButton setImage:AssetImages.selectionTick.image forState:UIControlStateNormal]; self.customServersContainer.hidden = NO; // Refresh content view height @@ -1360,7 +1327,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; [self.authenticationActivityIndicator startAnimating]; // Hide the custom server details in order to save customized inputs - [self hideCustomServers:YES]; + [self setCustomServerFieldsVisible:NO]; MXKAccount *account = [[MXKAccountManager sharedManager] accountForUserId:userId]; MXSession *session = account.mxSession; @@ -1376,119 +1343,8 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; }]; } - // Wait for session change to present complete security screen if needed - [self registerSessionStateChangeNotificationForSession:session]; -} - -- (void)registerSessionStateChangeNotificationForSession:(MXSession*)session -{ - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionStateDidChangeNotification:) name:kMXSessionStateDidChangeNotification object:session]; -} - -- (void)unregisterSessionStateChangeNotification -{ - [[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionStateDidChangeNotification object:nil]; -} - -- (void)sessionStateDidChangeNotification:(NSNotification*)notification -{ - MXSession *session = (MXSession*)notification.object; - - if (session.state == MXSessionStateStoreDataReady) - { - if (session.crypto.crossSigning) - { - // Do not make key share requests while the "Complete security" is not complete. - // If the device is self-verified, the SDK will restore the existing key backup. - // Then, it will re-enable outgoing key share requests - [session.crypto setOutgoingKeyRequestsEnabled:NO onComplete:nil]; - } - } - else if (session.state == MXSessionStateRunning) - { - [self unregisterSessionStateChangeNotification]; - - if (session.crypto.crossSigning) - { - [session.crypto.crossSigning refreshStateWithSuccess:^(BOOL stateUpdated) { - - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: crossSigning.state: %@", @(session.crypto.crossSigning.state)); - - switch (session.crypto.crossSigning.state) - { - case MXCrossSigningStateNotBootstrapped: - { - // TODO: This is still not sure we want to disable the automatic cross-signing bootstrap - // if the admin disabled e2e by default. - // Do like riot-web for the moment - if ([session vc_homeserverConfiguration].isE2EEByDefaultEnabled) - { - // Bootstrap cross-signing on user's account - // We do it for both registration and new login as long as cross-signing does not exist yet - if (self.authInputsView.password.length) - { - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Bootstrap with password"); - - [session.crypto.crossSigning setupWithPassword:self.authInputsView.password success:^{ - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Bootstrap succeeded"); - [self dismiss]; - } failure:^(NSError * _Nonnull error) { - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Bootstrap failed. Error: %@", error); - [session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil]; - [self dismiss]; - }]; - } - else - { - // Try to setup cross-signing without authentication parameters in case if a grace period is enabled - [self.crossSigningService setupCrossSigningWithoutAuthenticationFor:session success:^{ - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Bootstrap succeeded without credentials"); - [self dismiss]; - } failure:^(NSError * _Nonnull error) { - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Do not know how to bootstrap cross-signing. Skip it."); - [session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil]; - [self dismiss]; - }]; - } - } - else - { - [session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil]; - [self dismiss]; - } - break; - } - case MXCrossSigningStateCrossSigningExists: - { - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Complete security"); - - // Ask the user to verify this session - self.userInteractionEnabled = YES; - [self.authenticationActivityIndicator stopAnimating]; - - [self presentCompleteSecurityWithSession:session]; - break; - } - - default: - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Nothing to do"); - - [session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil]; - [self dismiss]; - break; - } - - } failure:^(NSError * _Nonnull error) { - MXLogDebug(@"[AuthenticationVC] sessionStateDidChange: Fail to refresh crypto state with error: %@", error); - [session.crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil]; - [self dismiss]; - }]; - } - else - { - [self dismiss]; - } - } + // Ask the coordinator to show the loading spinner whilst waiting. + [self.authVCDelegate authenticationViewController:self didLoginWithSession:session andPassword:self.authInputsView.password]; } #pragma mark - MXKAuthInputsViewDelegate @@ -1585,7 +1441,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; { // wellKnown matches with application default servers // Hide custom servers - [self hideCustomServers:YES]; + [self setCustomServerFieldsVisible:NO]; } else { @@ -1617,25 +1473,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; } // And show custom servers - [self hideCustomServers:NO]; -} - -#pragma mark - KeyVerificationCoordinatorBridgePresenterDelegate - -- (void)keyVerificationCoordinatorBridgePresenterDelegateDidComplete:(KeyVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter otherUserId:(NSString * _Nonnull)otherUserId otherDeviceId:(NSString * _Nonnull)otherDeviceId -{ - MXCrypto *crypto = coordinatorBridgePresenter.session.crypto; - if (!crypto.backup.hasPrivateKeyInCryptoStore || !crypto.backup.enabled) - { - MXLogDebug(@"[AuthenticationVC][MXKeyVerification] requestAllPrivateKeys: Request key backup private keys"); - [crypto setOutgoingKeyRequestsEnabled:YES onComplete:nil]; - } - [self dismiss]; -} - -- (void)keyVerificationCoordinatorBridgePresenterDelegateDidCancel:(KeyVerificationCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter -{ - [self dismiss]; + [self setCustomServerFieldsVisible:YES]; } #pragma mark - SetPinCoordinatorBridgePresenterDelegate diff --git a/Riot/Modules/Authentication/Views/AuthInputsView.m b/Riot/Modules/Authentication/Views/AuthInputsView.m index 43efbce8b..ea0bc4741 100644 --- a/Riot/Modules/Authentication/Views/AuthInputsView.m +++ b/Riot/Modules/Authentication/Views/AuthInputsView.m @@ -431,7 +431,7 @@ style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - inputsAlert = nil; + self->inputsAlert = nil; }]]; @@ -551,10 +551,10 @@ } // Check whether a second 3pid is available - _isThirdPartyIdentifierPending = (!self.emailContainer.isHidden && self.emailTextField.text.length && ![self isFlowCompleted:kMXLoginFlowTypeEmailIdentity]); + self->_isThirdPartyIdentifierPending = (!self.emailContainer.isHidden && self.emailTextField.text.length && ![self isFlowCompleted:kMXLoginFlowTypeEmailIdentity]); // Launch msisdn validation - NSString *e164 = [[NBPhoneNumberUtil sharedInstance] format:nbPhoneNumber numberFormat:NBEPhoneNumberFormatE164 error:nil]; + NSString *e164 = [[NBPhoneNumberUtil sharedInstance] format:self->nbPhoneNumber numberFormat:NBEPhoneNumberFormatE164 error:nil]; NSString *msisdn; if ([e164 hasPrefix:@"+"]) { @@ -564,12 +564,12 @@ { msisdn = [e164 substringFromIndex:2]; } - submittedMSISDN = [[MXK3PID alloc] initWithMedium:kMX3PIDMediumMSISDN andAddress:msisdn]; - - [submittedMSISDN requestValidationTokenWithMatrixRestClient:restClient - isDuringRegistration:YES - nextLink:nil - success:^ + self->submittedMSISDN = [[MXK3PID alloc] initWithMedium:kMX3PIDMediumMSISDN andAddress:msisdn]; + + [self->submittedMSISDN requestValidationTokenWithMatrixRestClient:restClient + isDuringRegistration:YES + nextLink:nil + success:^ { [self showValidationMSISDNDialogToPrepareParameters:callback]; @@ -763,7 +763,7 @@ { NSDictionary *parameters = @{ @"auth": @{ - @"session":currentSession.session, + @"session": self->currentSession.session, @"response": response, @"type": kMXLoginFlowTypeRecaptcha }, @@ -870,7 +870,7 @@ { // We finalize here a registration triggered from external inputs. All the required data are handled by the session id NSDictionary *parameters = @{ - @"auth": @{@"session": currentSession.session, @"response": response, @"type": kMXLoginFlowTypeRecaptcha}, + @"auth": @{@"session": self->currentSession.session, @"response": response, @"type": kMXLoginFlowTypeRecaptcha}, }; callback (parameters, nil); } @@ -1322,7 +1322,7 @@ [phoneNumberPickerNavigationController pushViewController:phoneNumberCountryPicker animated:NO]; - UIBarButtonItem *leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"back_icon"] style:UIBarButtonItemStylePlain target:self action:@selector(dismissCountryPicker)]; + UIBarButtonItem *leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:AssetImages.backIcon.image style:UIBarButtonItemStylePlain target:self action:@selector(dismissCountryPicker)]; phoneNumberCountryPicker.navigationItem.leftBarButtonItem = leftBarButtonItem; [self.delegate authInputsView:self presentViewController:phoneNumberPickerNavigationController animated:YES]; @@ -1705,7 +1705,7 @@ if (weakSelf) { typeof(self) self = weakSelf; - UITextField *textField = [inputsAlert textFields].firstObject; + UITextField *textField = [self->inputsAlert textFields].firstObject; NSString *smsCode = textField.text; self->inputsAlert = nil; @@ -1776,9 +1776,9 @@ self->inputsAlert = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert]; - [inputsAlert addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n ok] - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) { + [self->inputsAlert addAction:[UIAlertAction actionWithTitle:[MatrixKitL10n ok] + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { if (weakSelf) { diff --git a/Riot/Modules/Authentication/Views/ForgotPasswordInputsView.m b/Riot/Modules/Authentication/Views/ForgotPasswordInputsView.m index 9173043f7..386df8331 100644 --- a/Riot/Modules/Authentication/Views/ForgotPasswordInputsView.m +++ b/Riot/Modules/Authentication/Views/ForgotPasswordInputsView.m @@ -219,7 +219,7 @@ style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { - inputsAlert = nil; + self->inputsAlert = nil; }]]; diff --git a/Riot/Modules/BugReport/BugReportViewController.m b/Riot/Modules/BugReport/BugReportViewController.m index e43ec06d7..3dd714654 100644 --- a/Riot/Modules/BugReport/BugReportViewController.m +++ b/Riot/Modules/BugReport/BugReportViewController.m @@ -222,11 +222,11 @@ _sendLogs = sendLogs; if (_sendLogs) { - _sendLogsButtonImage.image = [UIImage imageNamed:@"selection_tick"]; + _sendLogsButtonImage.image = AssetImages.selectionTick.image; } else { - _sendLogsButtonImage.image = [UIImage imageNamed:@"selection_untick"]; + _sendLogsButtonImage.image = AssetImages.selectionUntick.image; } } @@ -235,11 +235,11 @@ _sendScreenshot = sendScreenshot; if (_sendScreenshot) { - _sendScreenshotButtonImage.image = [UIImage imageNamed:@"selection_tick"]; + _sendScreenshotButtonImage.image = AssetImages.selectionTick.image; } else { - _sendScreenshotButtonImage.image = [UIImage imageNamed:@"selection_untick"]; + _sendScreenshotButtonImage.image = AssetImages.selectionUntick.image; } } diff --git a/Riot/Modules/Call/CallViewController.m b/Riot/Modules/Call/CallViewController.m index 8ec636401..d4ff8d4d5 100644 --- a/Riot/Modules/Call/CallViewController.m +++ b/Riot/Modules/Call/CallViewController.m @@ -73,20 +73,20 @@ CallAudioRouteMenuViewDelegate> // Back button - UIImage *backButtonImage = [UIImage imageNamed:@"back_icon"]; + UIImage *backButtonImage = AssetImages.backIcon.image; [self.backToAppButton setImage:backButtonImage forState:UIControlStateNormal]; [self.backToAppButton setImage:backButtonImage forState:UIControlStateHighlighted]; // Camera switch - UIImage *cameraSwitchButtonImage = [UIImage imageNamed:@"camera_switch"]; + UIImage *cameraSwitchButtonImage = AssetImages.cameraSwitch.image; [self.cameraSwitchButton setImage:cameraSwitchButtonImage forState:UIControlStateNormal]; [self.cameraSwitchButton setImage:cameraSwitchButtonImage forState:UIControlStateHighlighted]; // Audio mute - UIImage *audioMuteOffButtonImage = [UIImage imageNamed:@"call_audio_mute_off_icon"]; - UIImage *audioMuteOnButtonImage = [UIImage imageNamed:@"call_audio_mute_on_icon"]; + UIImage *audioMuteOffButtonImage = AssetImages.callAudioMuteOffIcon.image; + UIImage *audioMuteOnButtonImage = AssetImages.callAudioMuteOnIcon.image; [self.audioMuteButton setImage:audioMuteOffButtonImage forState:UIControlStateNormal]; [self.audioMuteButton setImage:audioMuteOffButtonImage forState:UIControlStateHighlighted]; @@ -94,8 +94,8 @@ CallAudioRouteMenuViewDelegate> // Video mute - UIImage *videoOffButtonImage = [UIImage imageNamed:@"call_video_mute_off_icon"]; - UIImage *videoOnButtonImage = [UIImage imageNamed:@"call_video_mute_on_icon"]; + UIImage *videoOffButtonImage = AssetImages.callVideoMuteOffIcon.image; + UIImage *videoOnButtonImage = AssetImages.callVideoMuteOnIcon.image; [self.videoMuteButton setImage:videoOffButtonImage forState:UIControlStateNormal]; [self.videoMuteButton setImage:videoOffButtonImage forState:UIControlStateHighlighted]; @@ -103,14 +103,14 @@ CallAudioRouteMenuViewDelegate> // More - UIImage *moreButtonImage = [UIImage imageNamed:@"call_more_icon"]; + UIImage *moreButtonImage = AssetImages.callMoreIcon.image; [self.moreButtonForVoice setImage:moreButtonImage forState:UIControlStateNormal]; [self.moreButtonForVideo setImage:moreButtonImage forState:UIControlStateNormal]; // Hang up - UIImage *hangUpButtonImage = [UIImage imageNamed:@"call_hangup_large"]; + UIImage *hangUpButtonImage = AssetImages.callHangupLarge.image; [self.endCallButton setTitle:nil forState:UIControlStateNormal]; [self.endCallButton setTitle:nil forState:UIControlStateHighlighted]; @@ -269,17 +269,17 @@ CallAudioRouteMenuViewDelegate> switch (self.mxCall.audioOutputRouter.currentRoute.routeType) { case MXiOSAudioOutputRouteTypeBuiltIn: - [self.speakerButton setImage:[UIImage imageNamed:@"call_speaker_off_icon"] + [self.speakerButton setImage:AssetImages.callSpeakerOffIcon.image forState:UIControlStateNormal]; break; case MXiOSAudioOutputRouteTypeLoudSpeakers: - [self.speakerButton setImage:[UIImage imageNamed:@"call_speaker_on_icon"] + [self.speakerButton setImage:AssetImages.callSpeakerOnIcon.image forState:UIControlStateNormal]; break; case MXiOSAudioOutputRouteTypeExternalWired: case MXiOSAudioOutputRouteTypeExternalBluetooth: case MXiOSAudioOutputRouteTypeExternalCar: - [self.speakerButton setImage:[UIImage imageNamed:@"call_speaker_external_icon"] + [self.speakerButton setImage:AssetImages.callSpeakerExternalIcon.image forState:UIControlStateNormal]; break; } @@ -484,7 +484,7 @@ CallAudioRouteMenuViewDelegate> andFontSize:fontSize]; } - return [MXKTools paintImage:[UIImage imageNamed:@"placeholder"] + return [MXKTools paintImage:AssetImages.placeholder.image withColor:self.overriddenTheme.tintColor]; } @@ -721,7 +721,9 @@ CallAudioRouteMenuViewDelegate> { MXWeakify(self); [self.mainSession.callManager getThirdPartyUserFrom:phoneNumber success:^(MXThirdPartyUserInstance * _Nonnull user) { - MXStrongifyAndReturnIfNil(self); + if (weakself == nil) { + return; + } continueBlock(user.userId); } failure:^(NSError * _Nullable error) { diff --git a/Riot/Modules/Call/Views/IncomingCallView.h b/Riot/Modules/Call/Views/IncomingCallView.h index 3035aebb2..45f897115 100644 --- a/Riot/Modules/Call/Views/IncomingCallView.h +++ b/Riot/Modules/Call/Views/IncomingCallView.h @@ -43,9 +43,6 @@ typedef void (^IncomingCallViewAction)(void); @param mxcAvatarURI the Matrix Content URI of the caller avatar. @param mediaManager the media manager used to download this avatar if it is not cached yet. - @param placeholderImage - @param callerName - @param callInfo */ - (instancetype)initWithCallerAvatar:(NSString *)mxcAvatarURI mediaManager:(MXMediaManager *)mediaManager diff --git a/Riot/Modules/Call/Views/IncomingCallView.m b/Riot/Modules/Call/Views/IncomingCallView.m index 35500cf4e..b58145546 100644 --- a/Riot/Modules/Call/Views/IncomingCallView.m +++ b/Riot/Modules/Call/Views/IncomingCallView.m @@ -89,7 +89,7 @@ static const CGFloat kButtonSize = 80.0; UIColor *answerButtonBorderColor = ThemeService.shared.theme.tintColor; - self.answerButton = [[CircleButton alloc] initWithImage:[UIImage imageNamed:@"voice_call_hangon_icon"] + self.answerButton = [[CircleButton alloc] initWithImage:AssetImages.voiceCallHangonIcon.image borderColor:answerButtonBorderColor]; self.answerButton.defaultBackgroundColor = ThemeService.shared.theme.backgroundColor; self.answerButton.tintColor = answerButtonBorderColor; @@ -103,7 +103,7 @@ static const CGFloat kButtonSize = 80.0; UIColor *rejectButtonBorderColor = ThemeService.shared.theme.warningColor; - self.rejectButton = [[CircleButton alloc] initWithImage:[UIImage imageNamed:@"voice_call_hangup_icon"] + self.rejectButton = [[CircleButton alloc] initWithImage:AssetImages.voiceCallHangupIcon.image borderColor:rejectButtonBorderColor]; self.rejectButton.defaultBackgroundColor = ThemeService.shared.theme.backgroundColor; self.rejectButton.tintColor = rejectButtonBorderColor; diff --git a/Riot/Modules/Common/ActivityIndicator/AppActivityIndicatorPresenter.swift b/Riot/Modules/Common/ActivityIndicator/AppActivityIndicatorPresenter.swift new file mode 100644 index 000000000..53a5d2453 --- /dev/null +++ b/Riot/Modules/Common/ActivityIndicator/AppActivityIndicatorPresenter.swift @@ -0,0 +1,47 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import UIKit +import MatrixSDK +import CommonKit + +/// Presenter which displays activity / loading indicators using app-wide `AppNavigator`, thus displaying them in a unified way, +/// and `ActivityCenter`/`Activity`, which ensures that only one activity is shown at a given time. +/// +/// Note: clients can skip using `AppActivityIndicatorPresenter` and instead coordiinate with `AppNavigatorProtocol` directly. +/// The presenter exists mostly as a transition for view controllers already using `ActivityIndicatorPresenterType` and / or view controllers +/// written in objective-c. +@objc final class AppActivityIndicatorPresenter: NSObject, ActivityIndicatorPresenterType { + private let appNavigator: AppNavigatorProtocol + private var activity: Activity? + + init(appNavigator: AppNavigatorProtocol) { + self.appNavigator = appNavigator + } + + @objc func presentActivityIndicator() { + activity = appNavigator.addLoadingActivity() + } + + @objc func removeCurrentActivityIndicator(animated: Bool, completion: (() -> Void)?) { + activity = nil + } + + func presentActivityIndicator(on view: UIView, animated: Bool, completion: (() -> Void)?) { + MXLog.error("[AppActivityIndicatorPresenter] Shared activity indicator does not support presenting from custom views") + } +} diff --git a/Riot/Modules/Common/Presentation/CustomSizedPresentationController.swift b/Riot/Modules/Common/Presentation/CustomSizedPresentationController.swift index 554705d73..7c7dfb47d 100644 --- a/Riot/Modules/Common/Presentation/CustomSizedPresentationController.swift +++ b/Riot/Modules/Common/Presentation/CustomSizedPresentationController.swift @@ -86,7 +86,7 @@ class CustomSizedPresentationController: UIPresentationController { // effect calls for only the top two corners to be rounded we size // the view such that the bottom CORNER_RADIUS points lie below // the bottom edge of the screen. - let cornerViewRect = presentationWrapperView.bounds//.inset(by: UIEdgeInsets(top: 0, left: 0, bottom: -cornerRadius, right: 0)) + let cornerViewRect = presentationWrapperView.bounds// .inset(by: UIEdgeInsets(top: 0, left: 0, bottom: -cornerRadius, right: 0)) let presentationRoundedCornerView = UIView(frame: cornerViewRect) presentationRoundedCornerView.autoresizingMask = [.flexibleWidth, .flexibleHeight] diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.h b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.h index 745ab180c..8cc599eba 100644 --- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.h +++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.h @@ -142,9 +142,10 @@ extern NSString *const kRecentsDataSourceTapOnDirectoryServerChange; @param section the section index @param frame the drawing area for the header of the specified section. + @param tableView the table view @return the sticky header view. */ -- (UIView *)viewForStickyHeaderInSection:(NSInteger)section withFrame:(CGRect)frame; +- (UIView *)viewForStickyHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView*)tableView; /** Get the height of the section header view. diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m index fcd8e4eb6..1e23043df 100644 --- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m +++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m @@ -199,7 +199,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou [self.recentsListService updateSpace:currentSpace]; } -- (UIView *)viewForStickyHeaderInSection:(NSInteger)section withFrame:(CGRect)frame +- (UIView *)viewForStickyHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView*)tableView { UIView *stickyHeader; @@ -210,7 +210,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou shrinkedSectionsBitMask = RECENTSDATASOURCE_SECTION_DIRECTORY; } - stickyHeader = [self viewForHeaderInSection:section withFrame:frame]; + stickyHeader = [self viewForHeaderInSection:section withFrame:frame inTableView:tableView]; shrinkedSectionsBitMask = savedShrinkedSectionsBitMask; @@ -753,7 +753,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou return missedNotifAndUnreadBadgeBgView; } -- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame +- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView*)tableView { // No header view in key backup banner section if (section == self.secureBackupBannerSection || section == self.crossSigningBannerSection) @@ -761,8 +761,14 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou return nil; } - SectionHeaderView *sectionHeader = [[SectionHeaderView alloc] initWithFrame:frame]; - sectionHeader.backgroundColor = ThemeService.shared.theme.headerBackgroundColor; + SectionHeaderView *sectionHeader = [tableView dequeueReusableHeaderFooterViewWithIdentifier:SectionHeaderView.defaultReuseIdentifier]; + if (sectionHeader == nil) + { + sectionHeader = [[SectionHeaderView alloc] initWithReuseIdentifier:SectionHeaderView.defaultReuseIdentifier]; + } + sectionHeader.backgroundView = [UIView new]; + sectionHeader.frame = frame; + sectionHeader.backgroundView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor; sectionHeader.topViewHeight = RECENTSDATASOURCE_DEFAULT_SECTION_HEADER_HEIGHT; NSInteger sectionBitwise = 0; @@ -809,7 +815,6 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou shrinkButton.backgroundColor = [UIColor clearColor]; [shrinkButton addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; shrinkButton.tag = sectionBitwise; - [sectionHeader addSubview:shrinkButton]; sectionHeader.topSpanningView = shrinkButton; sectionHeader.userInteractionEnabled = YES; @@ -817,16 +822,15 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou UIImage *chevron; if (shrinkedSectionsBitMask & sectionBitwise) { - chevron = [UIImage imageNamed:@"disclosure_icon"]; + chevron = AssetImages.disclosureIcon.image; } else { - chevron = [UIImage imageNamed:@"shrink_icon"]; + chevron = AssetImages.shrinkIcon.image; } UIImageView *chevronView = [[UIImageView alloc] initWithImage:chevron]; chevronView.tintColor = ThemeService.shared.theme.textSecondaryColor; chevronView.contentMode = UIViewContentModeCenter; - [sectionHeader addSubview:chevronView]; sectionHeader.accessoryView = chevronView; } else if (_recentsDataSourceMode == RecentsDataSourceModeHome) @@ -836,7 +840,6 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (badgeView) { - [sectionHeader addSubview:badgeView]; sectionHeader.accessoryView = badgeView; } } @@ -846,7 +849,6 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou UILabel *headerLabel = [[UILabel alloc] initWithFrame:frame]; headerLabel.backgroundColor = [UIColor clearColor]; headerLabel.attributedText = [self attributedStringForHeaderTitleInSection:section]; - [sectionHeader addSubview:headerLabel]; sectionHeader.headerLabel = headerLabel; return sectionHeader; @@ -1470,7 +1472,7 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou - (void)recentsListServiceDidChangeData:(id)service totalCountsChanged:(BOOL)totalCountsChanged { - // no-op + [[AppDelegate theDelegate].masterTabBarController refreshTabBarBadges]; } - (void)recentsListServiceDidChangeData:(id)service diff --git a/Riot/Modules/Common/Recents/RecentsViewController.h b/Riot/Modules/Common/Recents/RecentsViewController.h index 49ad95a78..9b952b26a 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.h +++ b/Riot/Modules/Common/Recents/RecentsViewController.h @@ -19,6 +19,7 @@ @class RootTabEmptyView; @class AnalyticsScreenTimer; +@class AppActivityIndicatorPresenter; /** Notification to be posted when recents data is ready. Notification object will be the RecentsViewController instance. @@ -96,6 +97,11 @@ FOUNDATION_EXPORT NSString *const RecentsViewControllerDataReadyNotification; */ @property (nonatomic) AnalyticsScreenTimer *screenTimer; +/** + Presenter for displaying app-wide activity / loading indicators. If not set, the view controller will use legacy activity indicators + */ +@property (nonatomic, strong) AppActivityIndicatorPresenter *activityPresenter; + /** Return the sticky header for the specified section of the table view diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index 6b4d6fc62..02c1038c7 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -30,12 +30,13 @@ #import "DirectoryRecentTableViewCell.h" #import "RoomIdOrAliasTableViewCell.h" #import "TableViewCellWithCollectionView.h" +#import "SectionHeaderView.h" #import "GeneratedInterface-Swift.h" NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewControllerDataReadyNotification"; -@interface RecentsViewController () +@interface RecentsViewController () { // Tell whether a recents refresh is pending (suspended during editing mode). BOOL isRefreshPending; @@ -120,7 +121,11 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro tableSearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 600, 44)]; tableSearchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth; tableSearchBar.showsCancelButton = NO; - tableSearchBar.placeholder = [VectorL10n searchDefaultPlaceholder]; + tableSearchBar.placeholder = [VectorL10n searchFilterPlaceholder]; + [tableSearchBar setImage:AssetImages.filterOff.image + forSearchBarIcon:UISearchBarIconSearch + state:UIControlStateNormal]; + tableSearchBar.delegate = self; displayedSectionHeaders = [NSMutableArray array]; @@ -145,6 +150,9 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro // Register key verification banner cells [self.recentsTableView registerNib:CrossSigningSetupBannerCell.nib forCellReuseIdentifier:CrossSigningSetupBannerCell.defaultReuseIdentifier]; + + [self.recentsTableView registerClass:SectionHeaderView.class + forHeaderFooterViewReuseIdentifier:SectionHeaderView.defaultReuseIdentifier]; // Hide line separators of empty cells self.recentsTableView.tableFooterView = [[UIView alloc] init]; @@ -165,8 +173,11 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro }]; self.recentsSearchBar.autocapitalizationType = UITextAutocapitalizationTypeNone; - self.recentsSearchBar.placeholder = [VectorL10n searchDefaultPlaceholder]; - + self.recentsSearchBar.placeholder = [VectorL10n searchFilterPlaceholder]; + [self.recentsSearchBar setImage:AssetImages.filterOff.image + forSearchBarIcon:UISearchBarIconSearch + state:UIControlStateNormal]; + // Observe user interface theme change. kThemeServiceDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kThemeServiceDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { @@ -1018,6 +1029,18 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro TableViewCellWithCollectionView *collectionViewCell = (TableViewCellWithCollectionView *)cell; [collectionViewCell.collectionView reloadData]; cellReloaded = YES; + + CGRect headerFrame = [self.recentsTableView rectForHeaderInSection:update.sectionIndex]; + UIView *headerView = [self.recentsTableView headerViewForSection:update.sectionIndex]; + UIView *updatedHeaderView = [self.dataSource viewForHeaderInSection:update.sectionIndex withFrame:headerFrame inTableView:self.recentsTableView]; + if ([headerView isKindOfClass:SectionHeaderView.class] + && [updatedHeaderView isKindOfClass:SectionHeaderView.class]) + { + SectionHeaderView *sectionHeaderView = (SectionHeaderView *)headerView; + SectionHeaderView *updatedSectionHeaderView = (SectionHeaderView *)updatedHeaderView; + sectionHeaderView.headerLabel = updatedSectionHeaderView.headerLabel; + sectionHeaderView.accessoryView = updatedSectionHeaderView.accessoryView; + } } } } @@ -1093,7 +1116,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro }]; directChatAction.backgroundColor = actionBackgroundColor; - UIImage *directChatImage = [UIImage imageNamed:@"room_action_direct_chat"]; + UIImage *directChatImage = AssetImages.roomActionDirectChat.image; directChatImage = [directChatImage vc_tintedImageUsingColor:isDirect ? selectedColor : unselectedColor]; directChatAction.image = [directChatImage vc_notRenderedImage]; @@ -1120,13 +1143,13 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro muteAction.backgroundColor = actionBackgroundColor; UIImage *notificationImage; - if([BuildSettings showNotificationsV2]) + if([BuildSettings showNotificationsV2] && isMuted) { - notificationImage = isMuted ? [UIImage imageNamed:@"room_action_notification_muted"] : [UIImage imageNamed:@"room_action_notification"]; + notificationImage = AssetImages.roomActionNotificationMuted.image; } else { - notificationImage = [UIImage imageNamed:@"room_action_notification"]; + notificationImage = AssetImages.roomActionNotification.image; } notificationImage = [notificationImage vc_tintedImageUsingColor:isMuted ? unselectedColor : selectedColor]; @@ -1157,7 +1180,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro }]; favouriteAction.backgroundColor = actionBackgroundColor; - UIImage *favouriteImage = [UIImage imageNamed:@"room_action_favourite"]; + UIImage *favouriteImage = AssetImages.roomActionFavourite.image; favouriteImage = [favouriteImage vc_tintedImageUsingColor:isFavourite ? selectedColor : unselectedColor]; favouriteAction.image = [favouriteImage vc_notRenderedImage]; @@ -1174,7 +1197,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro }]; priorityAction.backgroundColor = actionBackgroundColor; - UIImage *priorityImage = isInLowPriority ? [UIImage imageNamed:@"room_action_priority_high"] : [UIImage imageNamed:@"room_action_priority_low"]; + UIImage *priorityImage = isInLowPriority ? AssetImages.roomActionPriorityHigh.image : AssetImages.roomActionPriorityLow.image; priorityImage = [priorityImage vc_tintedImageUsingColor:unselectedColor]; priorityAction.image = [priorityImage vc_notRenderedImage]; @@ -1188,7 +1211,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro }]; leaveAction.backgroundColor = actionBackgroundColor; - UIImage *leaveImage = [UIImage imageNamed:@"room_action_leave"]; + UIImage *leaveImage = AssetImages.roomActionLeave.image; leaveImage = [leaveImage vc_tintedImageUsingColor:unselectedColor]; leaveAction.image = [leaveImage vc_notRenderedImage]; @@ -1292,7 +1315,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro [self stopActivityIndicator]; // Leave editing mode - [self cancelEditionMode:isRefreshPending]; + [self cancelEditionMode:self->isRefreshPending]; } }]; @@ -1300,7 +1323,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro else { // Leave editing mode - [self cancelEditionMode:isRefreshPending]; + [self cancelEditionMode:self->isRefreshPending]; } } @@ -1358,7 +1381,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro [self stopActivityIndicator]; // Leave editing mode - [self cancelEditionMode:isRefreshPending]; + [self cancelEditionMode:self->isRefreshPending]; } failure:^(NSError *error) { @@ -1366,7 +1389,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro [self stopActivityIndicator]; - MXLogDebug(@"[RecentsViewController] Failed to update direct tag of the room (%@)", editedRoomId); + MXLogDebug(@"[RecentsViewController] Failed to update direct tag of the room (%@)", self->editedRoomId); // Notify the end user NSString *userId = self.mainSession.myUser.userId; // TODO: handle multi-account @@ -1375,7 +1398,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro userInfo:userId ? @{kMXKErrorUserIdKey: userId} : nil]; // Leave editing mode - [self cancelEditionMode:isRefreshPending]; + [self cancelEditionMode:self->isRefreshPending]; }]; } @@ -2182,6 +2205,16 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro [self.recentsSearchBar setShowsCancelButton:NO animated:NO]; } +- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText +{ + [super searchBar:searchBar textDidChange:searchText]; + + UIImage *filterIcon = searchText.length > 0 ? AssetImages.filterOn.image : AssetImages.filterOff.image; + [self.recentsSearchBar setImage:filterIcon + forSearchBarIcon:UISearchBarIconSearch + state:UIControlStateNormal]; +} + #pragma mark - CreateRoomCoordinatorBridgePresenterDelegate - (void)createRoomCoordinatorBridgePresenterDelegate:(CreateRoomCoordinatorBridgePresenter *)coordinatorBridgePresenter didCreateNewRoom:(MXRoom *)room @@ -2385,4 +2418,26 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro self.roomNotificationSettingsCoordinatorBridgePresenter = nil; } +#pragma mark - Activity Indicator + +- (BOOL)providesCustomActivityIndicator { + return self.activityPresenter != nil; +} + +- (void)startActivityIndicator { + if (self.activityPresenter) { + [self.activityPresenter presentActivityIndicator]; + } else { + [super startActivityIndicator]; + } +} + +- (void)stopActivityIndicator { + if (self.activityPresenter) { + [self.activityPresenter removeCurrentActivityIndicatorWithAnimated:YES completion:nil]; + } else { + [super stopActivityIndicator]; + } +} + @end diff --git a/Riot/Modules/Common/SectionHeaders/SectionHeaderView.h b/Riot/Modules/Common/SectionHeaders/SectionHeaderView.h index e4e37c25c..515ee86a4 100644 --- a/Riot/Modules/Common/SectionHeaders/SectionHeaderView.h +++ b/Riot/Modules/Common/SectionHeaders/SectionHeaderView.h @@ -20,7 +20,7 @@ /** Section header view class. Respects left and right safe area insets and layouts its subviews. */ -@interface SectionHeaderView : UIView +@interface SectionHeaderView : UITableViewHeaderFooterView /** Default value: 20.0 @@ -57,4 +57,6 @@ */ @property (nonatomic, strong) UIView *bottomView; ++ (NSString*)defaultReuseIdentifier; + @end diff --git a/Riot/Modules/Common/SectionHeaders/SectionHeaderView.m b/Riot/Modules/Common/SectionHeaders/SectionHeaderView.m index 855c4e2c0..54150ac8e 100644 --- a/Riot/Modules/Common/SectionHeaders/SectionHeaderView.m +++ b/Riot/Modules/Common/SectionHeaders/SectionHeaderView.m @@ -17,10 +17,17 @@ #import "SectionHeaderView.h" +#import "GeneratedInterface-Swift.h" + static const CGFloat kInterItemsSpaceHorizontal = 8.0; @implementation SectionHeaderView ++ (NSString*)defaultReuseIdentifier +{ + return NSStringFromClass([self class]); +} + - (void)setMinimumLeftInset:(CGFloat)minimumLeftInset { _minimumLeftInset = minimumLeftInset; @@ -41,25 +48,53 @@ static const CGFloat kInterItemsSpaceHorizontal = 8.0; - (void)setTopSpanningView:(UIView *)topSpanningView { + // remove old one + [_topSpanningView removeFromSuperview]; _topSpanningView = topSpanningView; + if (_topSpanningView) + { + // add new one + [self.contentView addSubview:_topSpanningView]; + } [self setNeedsLayout]; } - (void)setHeaderLabel:(UILabel *)headerLabel { + // remove old one + [_headerLabel removeFromSuperview]; _headerLabel = headerLabel; + if (_headerLabel) + { + // add new one + [self.contentView addSubview:_headerLabel]; + } [self setNeedsLayout]; } - (void)setAccessoryView:(UIView *)accessoryView { + // remove old one + [_accessoryView removeFromSuperview]; _accessoryView = accessoryView; + if (_accessoryView) + { + // add new one + [self.contentView addSubview:_accessoryView]; + } [self setNeedsLayout]; } - (void)setBottomView:(UIView *)bottomView { + // remove old one + [_bottomView removeFromSuperview]; _bottomView = bottomView; + if (_bottomView) + { + // add new one + [self.contentView addSubview:_bottomView]; + } [self setNeedsLayout]; } @@ -88,6 +123,15 @@ static const CGFloat kInterItemsSpaceHorizontal = 8.0; return self; } +- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier +{ + if (self = [super initWithReuseIdentifier:reuseIdentifier]) + { + [self setup]; + } + return self; +} + - (void)setup { _minimumLeftInset = 20; @@ -95,21 +139,24 @@ static const CGFloat kInterItemsSpaceHorizontal = 8.0; _topViewHeight = 30; } +- (void)prepareForReuse +{ + [self.contentView vc_removeAllSubviews]; + [super prepareForReuse]; +} + - (void)layoutSubviews { [super layoutSubviews]; CGFloat _leftInset = 0.0, _rightInset = 0.0; - - _leftInset += self.safeAreaInsets.left; - _rightInset += self.safeAreaInsets.right; - CGFloat leftMargin = MAX(_leftInset, _minimumLeftInset); - CGFloat rightMargin = MAX(_rightInset, _minimumRightInset); + CGFloat leftMargin = _minimumLeftInset; + CGFloat rightMargin = _minimumRightInset; if (_topSpanningView) { - CGRect frame = self.bounds; + CGRect frame = self.contentView.bounds; frame.size.height = _topViewHeight; _topSpanningView.frame = frame; } @@ -130,9 +177,9 @@ static const CGFloat kInterItemsSpaceHorizontal = 8.0; else { // center header label vertically - frame.origin.y = MAX(0, (self.bounds.size.height - frame.size.height)/2); + frame.origin.y = MAX(0, (self.contentView.bounds.size.height - frame.size.height)/2); } - frame.size.width = self.bounds.size.width - leftMargin - rightMargin; + frame.size.width = self.contentView.bounds.size.width - leftMargin - rightMargin; _headerLabel.frame = frame; } @@ -143,7 +190,7 @@ static const CGFloat kInterItemsSpaceHorizontal = 8.0; rightMargin = MAX(_rightInset, 20); CGRect frame = _accessoryView.frame; - frame.origin.x = self.bounds.size.width - frame.size.width - rightMargin; + frame.origin.x = self.contentView.bounds.size.width - frame.size.width - rightMargin; frame.origin.y = MAX(0, (_topViewHeight - frame.size.height)/2); _accessoryView.frame = frame; } @@ -157,8 +204,8 @@ static const CGFloat kInterItemsSpaceHorizontal = 8.0; CGRect frame = _bottomView.frame; frame.origin.x = leftMargin; frame.origin.y = CGRectGetMaxY(_headerLabel.frame); - frame.size.width = self.bounds.size.width - leftMargin - rightMargin; - frame.size.height = self.bounds.size.height - frame.origin.y; + frame.size.width = self.contentView.bounds.size.width - leftMargin - rightMargin; + frame.size.height = self.contentView.bounds.size.height - frame.origin.y; _bottomView.frame = frame; } } diff --git a/Riot/Modules/Common/SegmentedViewController/SegmentedViewController.m b/Riot/Modules/Common/SegmentedViewController/SegmentedViewController.m index 60547f8c5..883a9c416 100644 --- a/Riot/Modules/Common/SegmentedViewController/SegmentedViewController.m +++ b/Riot/Modules/Common/SegmentedViewController/SegmentedViewController.m @@ -165,6 +165,8 @@ // Adjust Top [NSLayoutConstraint deactivateConstraints:@[self.selectionContainerTopConstraint]]; + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" // it is not possible to define a constraint to the topLayoutGuide in the xib editor // so do it in the code .. self.selectionContainerTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide @@ -174,6 +176,7 @@ attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + #pragma clang diagnostic pop [NSLayoutConstraint activateConstraints:@[self.selectionContainerTopConstraint]]; diff --git a/Riot/Modules/Common/SwiftUI/VectorHostingController.swift b/Riot/Modules/Common/SwiftUI/VectorHostingController.swift index 6d54badf4..6e5699e94 100644 --- a/Riot/Modules/Common/SwiftUI/VectorHostingController.swift +++ b/Riot/Modules/Common/SwiftUI/VectorHostingController.swift @@ -30,6 +30,10 @@ class VectorHostingController: UIHostingController { var hidesBackTitleWhenPushed: Bool = false private var theme: Theme + // MARK: Public + + var enableNavigationBarScrollEdgesAppearance = false + init(rootView: Content) where Content: View { self.theme = ThemeService.shared().theme super.init(rootView: AnyView(rootView.vectorContent())) @@ -89,7 +93,7 @@ class VectorHostingController: UIHostingController { private func update(theme: Theme) { if let navigationBar = self.navigationController?.navigationBar { - theme.applyStyle(onNavigationBar: navigationBar) + theme.applyStyle(onNavigationBar: navigationBar, withModernScrollEdgesAppearance: enableNavigationBarScrollEdgesAppearance) } } } diff --git a/Riot/Modules/Common/Toasts/ActivityIndicatorToastPresenter.swift b/Riot/Modules/Common/Toasts/ActivityIndicatorToastPresenter.swift new file mode 100644 index 000000000..1c592a2a2 --- /dev/null +++ b/Riot/Modules/Common/Toasts/ActivityIndicatorToastPresenter.swift @@ -0,0 +1,76 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import UIKit +import CommonKit + +/// An `ActivityPresenter` responsible for showing / hiding a toast view for activity indicators, and managed by an `Activity`, +/// meaning the `present` and `dismiss` methods will be called when the parent `Activity` starts or completes. +class ActivityIndicatorToastPresenter: ActivityPresentable { + private let text: String + private weak var navigationController: UINavigationController? + private weak var view: UIView? + + init(text: String, navigationController: UINavigationController) { + self.text = text + self.navigationController = navigationController + } + + func present() { + guard let navigationController = navigationController else { + return + } + + let view = ActivityIndicatorToastView(text: text) + view.update(theme: ThemeService.shared().theme) + self.view = view + + view.translatesAutoresizingMaskIntoConstraints = false + navigationController.view.addSubview(view) + NSLayoutConstraint.activate([ + view.centerXAnchor.constraint(equalTo: navigationController.navigationBar.centerXAnchor), + view.topAnchor.constraint(equalTo: navigationController.navigationBar.bottomAnchor) + ]) + + view.alpha = 0 + view.transform = .init(translationX: 0, y: 5) + UIView.animate(withDuration: 0.2) { + view.alpha = 1 + view.transform = .identity + } + } + + func dismiss() { + guard let view = view, view.superview != nil else { + return + } + + // If `present` and `dismiss` are called right after each other without delay, + // the view does not correctly pick up `currentState` of alpha. Dispatching onto + // the main queue skips a few run loops, giving the system time to render + // current state. + DispatchQueue.main.async { + UIView.animate(withDuration: 0.2, delay: 0, options: .beginFromCurrentState) { + view.alpha = 0 + view.transform = .init(translationX: 0, y: -5) + } completion: { _ in + view.removeFromSuperview() + self.view = nil + } + } + } +} diff --git a/Riot/Modules/Common/Toasts/ActivityIndicatorToastView.swift b/Riot/Modules/Common/Toasts/ActivityIndicatorToastView.swift new file mode 100644 index 000000000..6964ec445 --- /dev/null +++ b/Riot/Modules/Common/Toasts/ActivityIndicatorToastView.swift @@ -0,0 +1,91 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import UIKit +import DesignKit + +class ActivityIndicatorToastView: UIView, Themable { + private struct Constants { + static let padding = UIEdgeInsets(top: 10, left: 12, bottom: 10, right: 12) + static let shadowOffset = CGSize(width: 0, height: 4) + static let shadowRadius = CGFloat(12) + static let shadowOpacity = Float(0.1) + } + + private let stackView: UIStackView = { + let stack = UIStackView() + stack.axis = .horizontal + stack.spacing = 5 + return stack + }() + + private let activityIndicator: UIActivityIndicatorView = { + let view = UIActivityIndicatorView() + view.transform = .init(scaleX: 0.75, y: 0.75) + view.startAnimating() + return view + }() + + private let label: UILabel = { + return UILabel() + }() + + init(text: String) { + super.init(frame: .zero) + setup(text: text) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setup(text: String) { + setupLayer() + setupStackView() + stackView.addArrangedSubview(activityIndicator) + stackView.addArrangedSubview(label) + label.text = text + } + + private func setupStackView() { + addSubview(stackView) + stackView.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + stackView.topAnchor.constraint(equalTo: topAnchor, constant: Constants.padding.top), + stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -Constants.padding.bottom), + stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: Constants.padding.left), + stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -Constants.padding.right) + ]) + } + + private func setupLayer() { + layer.shadowColor = UIColor.black.cgColor + layer.shadowOffset = Constants.shadowOffset + layer.shadowRadius = Constants.shadowRadius + layer.shadowOpacity = Constants.shadowOpacity + } + + override func layoutSubviews() { + super.layoutSubviews() + layer.cornerRadius = layer.frame.height / 2 + } + + func update(theme: Theme) { + backgroundColor = UIColor.white + label.font = theme.fonts.subheadline + } +} diff --git a/Riot/Modules/Common/Toasts/BasicToastView.swift b/Riot/Modules/Common/Toasts/BasicToastView.swift new file mode 100644 index 000000000..a4b9a39b6 --- /dev/null +++ b/Riot/Modules/Common/Toasts/BasicToastView.swift @@ -0,0 +1,112 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import UIKit + +class BasicToastView: UIView, Themable { + + private enum Constants { + static let padding: UIEdgeInsets = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16) + static let cornerRadius: CGFloat = 8.0 + } + + private lazy var imageView: UIImageView = { + let view = UIImageView() + view.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = .clear + return view + }() + + private lazy var messageLabel: UILabel = { + let label = UILabel() + label.font = ThemeService.shared().theme.fonts.body + label.backgroundColor = .clear + label.numberOfLines = 0 + label.textAlignment = .left + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + private lazy var stackView: UIStackView = { + let result = UIStackView() + result.axis = .horizontal + result.distribution = .fill + result.alignment = .center + result.spacing = 8.0 + result.backgroundColor = .clear + + addSubview(result) + result.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + result.leadingAnchor.constraint(equalTo: leadingAnchor, constant: Constants.padding.left), + result.topAnchor.constraint(equalTo: topAnchor, constant: Constants.padding.top), + result.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -Constants.padding.right), + result.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -Constants.padding.bottom) + ]) + + return result + }() + + init(withMessage message: String?, + image: UIImage? = nil) { + super.init(frame: .zero) + + if let image = image { + imageView.image = image + NSLayoutConstraint.activate([ + imageView.widthAnchor.constraint(equalToConstant: image.size.width), + imageView.heightAnchor.constraint(equalToConstant: image.size.height) + ]) + stackView.addArrangedSubview(imageView) + } + + messageLabel.text = message + stackView.addArrangedSubview(messageLabel) + + stackView.layoutIfNeeded() + layer.cornerRadius = Constants.cornerRadius + layer.masksToBounds = true + registerThemeServiceDidChangeThemeNotification() + themeDidChange() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func registerThemeServiceDidChangeThemeNotification() { + NotificationCenter.default.addObserver(self, + selector: #selector(themeDidChange), + name: .themeServiceDidChangeTheme, + object: nil) + } + + @objc + private func themeDidChange() { + self.update(theme: ThemeService.shared().theme) + } + + // MARK: Themable + + func update(theme: Theme) { + backgroundColor = theme.colors.quinaryContent + imageView.tintColor = theme.colors.tertiaryContent + messageLabel.textColor = theme.colors.primaryContent + messageLabel.font = theme.fonts.body + } + +} diff --git a/Riot/Modules/Communities/Home/GroupHomeViewController.h b/Riot/Modules/Communities/Home/GroupHomeViewController.h index 69b2300da..510e1dfcc 100644 --- a/Riot/Modules/Communities/Home/GroupHomeViewController.h +++ b/Riot/Modules/Communities/Home/GroupHomeViewController.h @@ -63,9 +63,6 @@ /** Set the group for which the details are displayed. Provide the related matrix session. - - @param group - @param mxSession */ - (void)setGroup:(MXGroup*)group withMatrixSession:(MXSession*)mxSession; diff --git a/Riot/Modules/Communities/Home/GroupHomeViewController.m b/Riot/Modules/Communities/Home/GroupHomeViewController.m index 6e5d5d3b5..a5a48ebba 100644 --- a/Riot/Modules/Communities/Home/GroupHomeViewController.m +++ b/Riot/Modules/Communities/Home/GroupHomeViewController.m @@ -40,7 +40,7 @@ // The options used to load long description html content. NSDictionary *options; - NSString *groupLongDescription; + NSString *groupLongDescriptionString; // The current pushed view controller UIViewController *pushedViewController; @@ -229,25 +229,25 @@ // Indeed the group update notifications are triggered by the matrix session only for the user's groups. void (^success)(void) = ^void(void) { - [self refreshDisplayWithGroup:_group]; + [self refreshDisplayWithGroup:self->_group]; }; // Trigger a refresh on the group summary. - [self.mxSession updateGroupSummary:_group success:(isPreview ? success : nil) failure:^(NSError *error) { + [self.mxSession updateGroupSummary:self->_group success:(isPreview ? success : nil) failure:^(NSError *error) { - MXLogDebug(@"[GroupHomeViewController] viewWillAppear: group summary update failed %@", _group.groupId); + MXLogDebug(@"[GroupHomeViewController] viewWillAppear: group summary update failed %@", self->_group.groupId); }]; // Trigger a refresh on the group members (ignore here the invited users). - [self.mxSession updateGroupUsers:_group success:(isPreview ? success : nil) failure:^(NSError *error) { + [self.mxSession updateGroupUsers:self->_group success:(isPreview ? success : nil) failure:^(NSError *error) { - MXLogDebug(@"[GroupHomeViewController] viewWillAppear: group members update failed %@", _group.groupId); + MXLogDebug(@"[GroupHomeViewController] viewWillAppear: group members update failed %@", self->_group.groupId); }]; // Trigger a refresh on the group rooms. - [self.mxSession updateGroupRooms:_group success:(isPreview ? success : nil) failure:^(NSError *error) { + [self.mxSession updateGroupRooms:self->_group success:(isPreview ? success : nil) failure:^(NSError *error) { - MXLogDebug(@"[GroupHomeViewController] viewWillAppear: group rooms update failed %@", _group.groupId); + MXLogDebug(@"[GroupHomeViewController] viewWillAppear: group rooms update failed %@", self->_group.groupId); }]; } @@ -523,11 +523,11 @@ { if (_group.summary.profile.longDescription.length) { - groupLongDescription = _group.summary.profile.longDescription; + groupLongDescriptionString = _group.summary.profile.longDescription; } else { - groupLongDescription = nil; + groupLongDescriptionString = nil; } [self renderGroupLongDescription]; @@ -535,13 +535,13 @@ - (void)renderGroupLongDescription { - if (groupLongDescription) + if (groupLongDescriptionString) { // Using DTCoreText, which renders static string, helps to avoid code injection attacks // that could happen with the default HTML renderer of NSAttributedString which is a // webview. // The supplied options include a callback to sanitize html tags and load image data. - NSAttributedString *attributedString = [[NSAttributedString alloc] initWithHTMLData:[groupLongDescription dataUsingEncoding:NSUTF8StringEncoding] options:options documentAttributes:NULL]; + NSAttributedString *attributedString = [[NSAttributedString alloc] initWithHTMLData:[groupLongDescriptionString dataUsingEncoding:NSUTF8StringEncoding] options:options documentAttributes:NULL]; // Apply additional treatments NSInteger mxIdsBitMask = (MXKTOOLS_USER_IDENTIFIER_BITWISE | MXKTOOLS_ROOM_IDENTIFIER_BITWISE | MXKTOOLS_ROOM_ALIAS_BITWISE | MXKTOOLS_EVENT_IDENTIFIER_BITWISE | MXKTOOLS_GROUP_IDENTIFIER_BITWISE); @@ -694,12 +694,12 @@ self->currentRequest = nil; [self stopActivityIndicator]; - [self refreshDisplayWithGroup:[_mxSession groupWithGroupId:_group.groupId]]; + [self refreshDisplayWithGroup:[self->_mxSession groupWithGroupId:self->_group.groupId]]; } } failure:^(NSError *error) { - MXLogDebug(@"[GroupDetailsViewController] join group (%@) failed", _group.groupId); + MXLogDebug(@"[GroupDetailsViewController] join group (%@) failed", self->_group.groupId); if (weakSelf) { @@ -732,7 +732,7 @@ } failure:^(NSError *error) { - MXLogDebug(@"[GroupDetailsViewController] leave group (%@) failed", _group.groupId); + MXLogDebug(@"[GroupDetailsViewController] leave group (%@) failed", self->_group.groupId); if (weakSelf) { @@ -802,6 +802,8 @@ #pragma mark - UITextView delegate +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange { BOOL shouldInteractWithURL = YES; @@ -903,5 +905,6 @@ return shouldInteractWithURL; } +#pragma clang diagnostic pop @end diff --git a/Riot/Modules/Communities/Members/GroupParticipantsViewController.h b/Riot/Modules/Communities/Members/GroupParticipantsViewController.h index 83b862664..e5b4a9ba8 100644 --- a/Riot/Modules/Communities/Members/GroupParticipantsViewController.h +++ b/Riot/Modules/Communities/Members/GroupParticipantsViewController.h @@ -76,9 +76,6 @@ /** Set the group for which the details are displayed. Provide the related matrix session. - - @param group - @param mxSession */ - (void)setGroup:(MXGroup*)group withMatrixSession:(MXSession*)mxSession; diff --git a/Riot/Modules/Communities/Members/GroupParticipantsViewController.m b/Riot/Modules/Communities/Members/GroupParticipantsViewController.m index 9a87f6562..26cf2b02d 100644 --- a/Riot/Modules/Communities/Members/GroupParticipantsViewController.m +++ b/Riot/Modules/Communities/Members/GroupParticipantsViewController.m @@ -93,6 +93,8 @@ // Adjust Top and Bottom constraints to take into account potential navBar and tabBar. [NSLayoutConstraint deactivateConstraints:@[_searchBarTopConstraint, _tableViewBottomConstraint]]; + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" _searchBarTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual @@ -108,6 +110,7 @@ attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + #pragma clang diagnostic pop [NSLayoutConstraint activateConstraints:@[_searchBarTopConstraint, _tableViewBottomConstraint]]; @@ -239,18 +242,18 @@ // Indeed the group update notifications are triggered by the matrix session only for the user's groups. void (^success)(void) = ^void(void) { - [self refreshDisplayWithGroup:_group]; + [self refreshDisplayWithGroup:self->_group]; }; // Trigger a refresh on the group members and the invited users. [self.mxSession updateGroupUsers:_group success:(isPreview ? success : nil) failure:^(NSError *error) { - MXLogDebug(@"[GroupParticipantsViewController] viewWillAppear: group members update failed %@", _group.groupId); + MXLogDebug(@"[GroupParticipantsViewController] viewWillAppear: group members update failed %@", self->_group.groupId); }]; [self.mxSession updateGroupInvitedUsers:_group success:(isPreview ? success : nil) failure:^(NSError *error) { - MXLogDebug(@"[GroupParticipantsViewController] viewWillAppear: invited users update failed %@", _group.groupId); + MXLogDebug(@"[GroupParticipantsViewController] viewWillAppear: invited users update failed %@", self->_group.groupId); }]; } @@ -305,7 +308,7 @@ [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseIn animations:^{ - tableViewMaskLayer.bounds = newBounds; + self->tableViewMaskLayer.bounds = newBounds; } completion:^(BOOL finished){ @@ -421,7 +424,7 @@ [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseIn animations:^{ - addParticipantButtonImageViewBottomConstraint.constant = keyboardHeight + 9; + self->addParticipantButtonImageViewBottomConstraint.constant = keyboardHeight + 9; // Force to render the view [self.view layoutIfNeeded]; @@ -472,7 +475,7 @@ addParticipantButtonImageView.backgroundColor = [UIColor clearColor]; addParticipantButtonImageView.contentMode = UIViewContentModeCenter; - addParticipantButtonImageView.image = [UIImage imageNamed:@"add_group_participant"]; + addParticipantButtonImageView.image = AssetImages.addGroupParticipant.image; CGFloat side = 78.0f; NSLayoutConstraint* widthConstraint = [NSLayoutConstraint constraintWithItem:addParticipantButtonImageView @@ -534,7 +537,7 @@ contactsDataSource.displaySearchInputInContactsList = YES; contactsDataSource.forceMatrixIdInDisplayName = YES; // Add a plus icon to the contact cell in the contacts picker, in order to make it more understandable for the end user. - contactsDataSource.contactCellAccessoryImage = [[UIImage imageNamed:@"plus_icon"] vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]; + contactsDataSource.contactCellAccessoryImage = [AssetImages.plusIcon.image vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]; // List all the participants matrix user id to ignore them during the contacts search. for (Contact *contact in actualParticipants) @@ -653,7 +656,7 @@ pendingMaskSpinnerView.alpha = 0; [UIView animateWithDuration:0.3 delay:0.3 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ - pendingMaskSpinnerView.alpha = 1; + self->pendingMaskSpinnerView.alpha = 1; } completion:^(BOOL finished) { }]; @@ -1075,14 +1078,14 @@ self->currentAlert = nil; [self addPendingActionMask]; - [self.mxSession leaveGroup:_group.groupId success:^{ + [self.mxSession leaveGroup:self->_group.groupId success:^{ [self withdrawViewControllerAnimated:YES completion:nil]; } failure:^(NSError *error) { [self removePendingActionMask]; - MXLogDebug(@"[GroupParticipantsVC] Leave group %@ failed", _group.groupId); + MXLogDebug(@"[GroupParticipantsVC] Leave group %@ failed", self->_group.groupId); // Alert user [[AppDelegate theDelegate] showErrorAsAlert:error]; diff --git a/Riot/Modules/Communities/Rooms/GroupRoomsViewController.h b/Riot/Modules/Communities/Rooms/GroupRoomsViewController.h index 792865b96..fe0a504a7 100644 --- a/Riot/Modules/Communities/Rooms/GroupRoomsViewController.h +++ b/Riot/Modules/Communities/Rooms/GroupRoomsViewController.h @@ -63,9 +63,6 @@ /** Set the group for which the rooms are listed. Provide the related matrix session. - - @param group - @param mxSession */ - (void)setGroup:(MXGroup*)group withMatrixSession:(MXSession*)mxSession; diff --git a/Riot/Modules/Communities/Rooms/GroupRoomsViewController.m b/Riot/Modules/Communities/Rooms/GroupRoomsViewController.m index 855c46580..4f60c4970 100644 --- a/Riot/Modules/Communities/Rooms/GroupRoomsViewController.m +++ b/Riot/Modules/Communities/Rooms/GroupRoomsViewController.m @@ -79,6 +79,8 @@ // Adjust Top and Bottom constraints to take into account potential navBar and tabBar. [NSLayoutConstraint deactivateConstraints:@[_searchBarTopConstraint, _tableViewBottomConstraint]]; + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" _searchBarTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual @@ -94,6 +96,7 @@ attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + #pragma clang diagnostic pop [NSLayoutConstraint activateConstraints:@[_searchBarTopConstraint, _tableViewBottomConstraint]]; @@ -203,13 +206,13 @@ // Indeed the group update notifications are triggered by the matrix session only for the user's groups. void (^success)(void) = ^void(void) { - [self refreshDisplayWithGroup:_group]; + [self refreshDisplayWithGroup:self->_group]; }; // Trigger a refresh on the group rooms. [self.mxSession updateGroupRooms:_group success:(isPreview ? success : nil) failure:^(NSError *error) { - MXLogDebug(@"[GroupRoomsViewController] viewWillAppear: group rooms update failed %@", _group.groupId); + MXLogDebug(@"[GroupRoomsViewController] viewWillAppear: group rooms update failed %@", self->_group.groupId); }]; } diff --git a/Riot/Modules/Communities/TabDetail/GroupDetailsViewController.h b/Riot/Modules/Communities/TabDetail/GroupDetailsViewController.h index e228101d4..faaab6b94 100644 --- a/Riot/Modules/Communities/TabDetail/GroupDetailsViewController.h +++ b/Riot/Modules/Communities/TabDetail/GroupDetailsViewController.h @@ -40,9 +40,6 @@ /** Set the group for which the details are displayed. Provide the related matrix session. - - @param group - @param mxSession */ - (void)setGroup:(MXGroup*)group withMatrixSession:(MXSession*)mxSession; diff --git a/Riot/Modules/Contacts/ContactsTableViewController.m b/Riot/Modules/Contacts/ContactsTableViewController.m index bf83b6372..badf8a085 100644 --- a/Riot/Modules/Contacts/ContactsTableViewController.m +++ b/Riot/Modules/Contacts/ContactsTableViewController.m @@ -17,6 +17,7 @@ #import #import "ContactsTableViewController.h" +#import "SectionHeaderView.h" #import "UIViewController+RiotSearch.h" @@ -95,6 +96,9 @@ self.contactsTableView.dataSource = contactsDataSource; // Note: dataSource may be nil here [self.contactsTableView registerClass:ContactTableViewCell.class forCellReuseIdentifier:ContactTableViewCell.defaultReuseIdentifier]; + + [self.contactsTableView registerClass:SectionHeaderView.class + forHeaderFooterViewReuseIdentifier:SectionHeaderView.defaultReuseIdentifier]; // Hide line separators of empty cells self.contactsTableView.tableFooterView = [[UIView alloc] init]; @@ -455,7 +459,9 @@ - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { - return [contactsDataSource viewForHeaderInSection:section withFrame:[tableView rectForHeaderInSection:section]]; + return [contactsDataSource viewForHeaderInSection:section + withFrame:[tableView rectForHeaderInSection:section] + inTableView:tableView]; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath diff --git a/Riot/Modules/Contacts/DataSources/ContactsDataSource.h b/Riot/Modules/Contacts/DataSources/ContactsDataSource.h index 5b665377e..6d6205e9b 100644 --- a/Riot/Modules/Contacts/DataSources/ContactsDataSource.h +++ b/Riot/Modules/Contacts/DataSources/ContactsDataSource.h @@ -95,18 +95,20 @@ typedef enum : NSUInteger @param section the section index @param frame the drawing area for the header of the specified section. + @param tableView the table view @return the section header. */ -- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame; +- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView *)tableView; /** Get the sticky header view for the specified section. @param section the section index @param frame the drawing area for the header of the specified section. + @param tableView the table view @return the sticky header view. */ -- (UIView *)viewForStickyHeaderInSection:(NSInteger)section withFrame:(CGRect)frame; +- (UIView *)viewForStickyHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView *)tableView; /** Refresh the contacts data source and notify its delegate. diff --git a/Riot/Modules/Contacts/DataSources/ContactsDataSource.m b/Riot/Modules/Contacts/DataSources/ContactsDataSource.m index c7d1692bd..9a2935903 100644 --- a/Riot/Modules/Contacts/DataSources/ContactsDataSource.m +++ b/Riot/Modules/Contacts/DataSources/ContactsDataSource.m @@ -791,19 +791,24 @@ return sectionTitle; } -- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame +- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView *)tableView { NSInteger sectionBitwise = 0; - SectionHeaderView *sectionHeader = [[SectionHeaderView alloc] initWithFrame:frame]; - sectionHeader.backgroundColor = ThemeService.shared.theme.headerBackgroundColor; + SectionHeaderView *sectionHeader = [tableView dequeueReusableHeaderFooterViewWithIdentifier:SectionHeaderView.defaultReuseIdentifier]; + if (sectionHeader == nil) + { + sectionHeader = [[SectionHeaderView alloc] initWithReuseIdentifier:SectionHeaderView.defaultReuseIdentifier]; + } + sectionHeader.frame = frame; + sectionHeader.backgroundView = [UIView new]; + sectionHeader.backgroundView.backgroundColor = ThemeService.shared.theme.headerBackgroundColor; sectionHeader.topViewHeight = CONTACTSDATASOURCE_DEFAULT_SECTION_HEADER_HEIGHT; frame.size.height = CONTACTSDATASOURCE_DEFAULT_SECTION_HEADER_HEIGHT - 10; UILabel *headerLabel = [[UILabel alloc] initWithFrame:frame]; headerLabel.attributedText = [self attributedStringForHeaderTitleInSection:section]; headerLabel.backgroundColor = [UIColor clearColor]; - [sectionHeader addSubview:headerLabel]; sectionHeader.headerLabel = headerLabel; if (_areSectionsShrinkable) @@ -832,7 +837,6 @@ shrinkButton.backgroundColor = [UIColor clearColor]; [shrinkButton addTarget:self action:@selector(onButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; shrinkButton.tag = sectionBitwise; - [sectionHeader addSubview:shrinkButton]; sectionHeader.topSpanningView = shrinkButton; sectionHeader.userInteractionEnabled = YES; @@ -840,16 +844,15 @@ UIImage *chevron; if (shrinkedSectionsBitMask & sectionBitwise) { - chevron = [UIImage imageNamed:@"disclosure_icon"]; + chevron = AssetImages.disclosureIcon.image; } else { - chevron = [UIImage imageNamed:@"shrink_icon"]; + chevron = AssetImages.shrinkIcon.image; } UIImageView *chevronView = [[UIImageView alloc] initWithImage:chevron]; chevronView.tintColor = ThemeService.shared.theme.textSecondaryColor; chevronView.contentMode = UIViewContentModeCenter; - [sectionHeader addSubview:chevronView]; sectionHeader.accessoryView = chevronView; } @@ -889,24 +892,23 @@ checkboxLabel.textColor = ThemeService.shared.theme.textPrimaryColor; // Set the right value of the tick box - localContactsCheckbox.image = hideNonMatrixEnabledContacts ? [UIImage imageNamed:@"selection_tick"] : [UIImage imageNamed:@"selection_untick"]; + localContactsCheckbox.image = hideNonMatrixEnabledContacts ? AssetImages.selectionTick.image : AssetImages.selectionUntick.image; localContactsCheckbox.tintColor = ThemeService.shared.theme.tintColor; // Add the check box container - [sectionHeader addSubview:localContactsCheckboxContainer]; sectionHeader.bottomView = localContactsCheckboxContainer; } return sectionHeader; } -- (UIView *)viewForStickyHeaderInSection:(NSInteger)section withFrame:(CGRect)frame +- (UIView *)viewForStickyHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView *)tableView { // Return the section header used when the section is shrinked NSInteger savedShrinkedSectionsBitMask = shrinkedSectionsBitMask; shrinkedSectionsBitMask = CONTACTSDATASOURCE_LOCALCONTACTS_BITWISE | CONTACTSDATASOURCE_USERDIRECTORY_BITWISE; - UIView *stickyHeader = [self viewForHeaderInSection:section withFrame:frame]; + UIView *stickyHeader = [self viewForHeaderInSection:section withFrame:frame inTableView:tableView]; shrinkedSectionsBitMask = savedShrinkedSectionsBitMask; diff --git a/Riot/Modules/Contacts/Details/ContactDetailsViewController.m b/Riot/Modules/Contacts/Details/ContactDetailsViewController.m index be2fe5596..fe2b2d6e1 100644 --- a/Riot/Modules/Contacts/Details/ContactDetailsViewController.m +++ b/Riot/Modules/Contacts/Details/ContactDetailsViewController.m @@ -733,7 +733,7 @@ } else { - roomCell.avatarImageView.image = [UIImage imageNamed:@"start_chat"]; + roomCell.avatarImageView.image = AssetImages.startChat.image; roomCell.avatarImageView.defaultBackgroundColor = [UIColor clearColor]; roomCell.titleLabel.text = [VectorL10n roomParticipantsActionStartNewChat]; } @@ -1084,7 +1084,7 @@ MXRoomCreationParameters *roomCreationParameters = [MXRoomCreationParameters parametersForDirectRoomWithUser:matrixId]; roomCreationRequest = [self.mainSession createRoomWithParameters:roomCreationParameters success:^(MXRoom *room) { - roomCreationRequest = nil; + self->roomCreationRequest = nil; // Delay the call in order to be sure that the room is ready dispatch_async(dispatch_get_main_queue(), ^{ @@ -1096,7 +1096,7 @@ MXLogDebug(@"[ContactDetailsViewController] Create room failed"); - roomCreationRequest = nil; + self->roomCreationRequest = nil; [self removePendingActionMask]; diff --git a/Riot/Modules/CreateRoom/EnterNewRoomDetails/Cells/ChooseAvatarTableViewCell.swift b/Riot/Modules/CreateRoom/EnterNewRoomDetails/Cells/ChooseAvatarTableViewCell.swift index bcca816cf..336e4b0fc 100644 --- a/Riot/Modules/CreateRoom/EnterNewRoomDetails/Cells/ChooseAvatarTableViewCell.swift +++ b/Riot/Modules/CreateRoom/EnterNewRoomDetails/Cells/ChooseAvatarTableViewCell.swift @@ -19,6 +19,7 @@ import Reusable protocol ChooseAvatarTableViewCellDelegate: AnyObject { func chooseAvatarTableViewCellDidTapChooseAvatar(_ cell: ChooseAvatarTableViewCell, sourceView: UIView) + func chooseAvatarTableViewCellDidTapRemoveAvatar(_ cell: ChooseAvatarTableViewCell) } class ChooseAvatarTableViewCell: UITableViewCell { @@ -29,15 +30,30 @@ class ChooseAvatarTableViewCell: UITableViewCell { } } @IBOutlet private weak var chooseAvatarButton: UIButton! + @IBOutlet private weak var removeAvatarButton: UIButton! { + didSet { + removeAvatarButton.imageView?.contentMode = .scaleAspectFit + } + } weak var delegate: ChooseAvatarTableViewCellDelegate? @IBAction private func chooseAvatarButtonTapped(_ sender: UIButton) { delegate?.chooseAvatarTableViewCellDidTapChooseAvatar(self, sourceView: sender) } + + @IBAction private func removeAvatarButtonTapped(_ sender: UIButton) { + delegate?.chooseAvatarTableViewCellDidTapRemoveAvatar(self) + } func configure(withViewModel viewModel: ChooseAvatarTableViewCellVM) { - avatarImageView.image = viewModel.avatarImage + if let image = viewModel.avatarImage { + avatarImageView.image = image + removeAvatarButton.isHidden = false + } else { + avatarImageView.image = Asset.Images.captureAvatar.image + removeAvatarButton.isHidden = true + } } } @@ -49,7 +65,6 @@ extension ChooseAvatarTableViewCell: Themable { func update(theme: Theme) { backgroundView = UIView() backgroundView?.backgroundColor = theme.backgroundColor - avatarImageView.backgroundColor = theme.tintColor } } diff --git a/Riot/Modules/CreateRoom/EnterNewRoomDetails/Cells/ChooseAvatarTableViewCell.xib b/Riot/Modules/CreateRoom/EnterNewRoomDetails/Cells/ChooseAvatarTableViewCell.xib index 72ebdf925..42afad97a 100644 --- a/Riot/Modules/CreateRoom/EnterNewRoomDetails/Cells/ChooseAvatarTableViewCell.xib +++ b/Riot/Modules/CreateRoom/EnterNewRoomDetails/Cells/ChooseAvatarTableViewCell.xib @@ -1,9 +1,9 @@ - + - + @@ -18,39 +18,45 @@ - + - - + + - - - - - - - - + + - - + - + + - @@ -64,11 +70,13 @@ + - + + diff --git a/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewAction.swift b/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewAction.swift index 93dc56de1..8833b80b9 100644 --- a/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewAction.swift +++ b/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewAction.swift @@ -16,12 +16,13 @@ limitations under the License. */ -import Foundation +import UIKit /// EnterNewRoomDetailsViewController view actions exposed to view model enum EnterNewRoomDetailsViewAction { case loadData case chooseAvatar(sourceView: UIView) + case removeAvatar case cancel case create } diff --git a/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewController.swift b/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewController.swift index aa42f667c..d0d3d20c1 100644 --- a/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewController.swift +++ b/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewController.swift @@ -31,6 +31,8 @@ final class EnterNewRoomDetailsViewController: UIViewController { static let roomNameMaximumNumberOfChars = 50 static let roomAddressMaximumNumberOfChars = 50 static let roomTopicMaximumNumberOfChars = 250 + static let chooseAvatarTableViewCellHeight: CGFloat = 140 + static let textViewTableViewCellHeight: CGFloat = 150 } // MARK: - Properties @@ -542,9 +544,9 @@ extension EnterNewRoomDetailsViewController: UITableViewDelegate { switch row.type { case .avatar: - return 100 + return Constants.chooseAvatarTableViewCellHeight case .textView: - return 150 + return Constants.textViewTableViewCellHeight default: return UITableView.automaticDimension } @@ -573,7 +575,11 @@ extension EnterNewRoomDetailsViewController: ChooseAvatarTableViewCellDelegate { func chooseAvatarTableViewCellDidTapChooseAvatar(_ cell: ChooseAvatarTableViewCell, sourceView: UIView) { viewModel.process(viewAction: .chooseAvatar(sourceView: sourceView)) } - + + func chooseAvatarTableViewCellDidTapRemoveAvatar(_ cell: ChooseAvatarTableViewCell) { + viewModel.process(viewAction: .removeAvatar) + } + } // MARK: - EnterNewRoomDetailsViewModelViewDelegate @@ -593,14 +599,6 @@ extension EnterNewRoomDetailsViewController: UITextFieldDelegate { switch textField.tag { case Constants.roomNameTextFieldTag: viewModel.roomCreationParameters.name = textField.text - if viewModel.roomCreationParameters.userSelectedAvatar == nil { - // if no image selected by the user, set initials as image - let avatar = AvatarGenerator.generateAvatar(forMatrixItem: nil, - withDisplayName: textField.text, - size: 60, - andFontSize: 30) - viewModel.roomCreationParameters.initialsAvatar = avatar - } case Constants.roomAddressTextFieldTag: viewModel.roomCreationParameters.address = textField.text default: diff --git a/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewModel.swift b/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewModel.swift index f95b531dc..33094e7c1 100644 --- a/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewModel.swift +++ b/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewModel.swift @@ -68,6 +68,8 @@ final class EnterNewRoomDetailsViewModel: EnterNewRoomDetailsViewModelType { self.loadData() case .chooseAvatar(let sourceView): self.chooseAvatar(sourceView: sourceView) + case .removeAvatar: + self.removeAvatar() case .cancel: self.cancelOperations() self.coordinatorDelegate?.enterNewRoomDetailsViewModelDidCancel(self) @@ -85,6 +87,11 @@ final class EnterNewRoomDetailsViewModel: EnterNewRoomDetailsViewModelType { private func chooseAvatar(sourceView: UIView) { self.coordinatorDelegate?.enterNewRoomDetailsViewModel(self, didTapChooseAvatar: sourceView) } + + private func removeAvatar() { + self.roomCreationParameters.userSelectedAvatar = nil + self.process(viewAction: .loadData) + } private func fixRoomAlias(alias: String?) -> String? { guard var alias = alias else { return nil } diff --git a/Riot/Modules/CreateRoom/Models/RoomCreationParameters.swift b/Riot/Modules/CreateRoom/Models/RoomCreationParameters.swift index 6ea63db13..311234c27 100644 --- a/Riot/Modules/CreateRoom/Models/RoomCreationParameters.swift +++ b/Riot/Modules/CreateRoom/Models/RoomCreationParameters.swift @@ -21,7 +21,7 @@ struct RoomCreationParameters { var topic: String? var address: String? var avatarImage: UIImage? { - return userSelectedAvatar ?? initialsAvatar + return userSelectedAvatar } var isEncrypted: Bool = false var joinRule: MXRoomJoinRule = .private { @@ -42,5 +42,4 @@ struct RoomCreationParameters { var isRoomSuggested: Bool = false var userSelectedAvatar: UIImage? - var initialsAvatar: UIImage? } diff --git a/Riot/Modules/Favorites/FavouritesViewController.m b/Riot/Modules/Favorites/FavouritesViewController.m index 23b43b856..62ef8cd8f 100644 --- a/Riot/Modules/Favorites/FavouritesViewController.m +++ b/Riot/Modules/Favorites/FavouritesViewController.m @@ -155,11 +155,11 @@ { if (ThemeService.shared.isCurrentThemeDark) { - return [UIImage imageNamed:@"favourites_empty_screen_artwork_dark"]; + return AssetImages.favouritesEmptyScreenArtworkDark.image; } else { - return [UIImage imageNamed:@"favourites_empty_screen_artwork"]; + return AssetImages.favouritesEmptyScreenArtwork.image; } } diff --git a/Riot/Modules/GlobalSearch/DataSources/UnifiedSearchRecentsDataSource.m b/Riot/Modules/GlobalSearch/DataSources/UnifiedSearchRecentsDataSource.m index 59d169d7f..94daf7c44 100644 --- a/Riot/Modules/GlobalSearch/DataSources/UnifiedSearchRecentsDataSource.m +++ b/Riot/Modules/GlobalSearch/DataSources/UnifiedSearchRecentsDataSource.m @@ -35,18 +35,6 @@ @implementation UnifiedSearchRecentsDataSource -- (instancetype)init -{ - self = [super init]; - if (self) - { - searchedRoomIdOrAliasSection = -1; - - _hideRecents = NO; - } - return self; -} - #pragma mark - - (void)setPublicRoomsDirectoryDataSource:(PublicRoomsDirectoryDataSource *)publicRoomsDirectoryDataSource @@ -148,13 +136,13 @@ return count; } -- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame +- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView*)tableView { UIView *sectionHeader = nil; if (section != searchedRoomIdOrAliasSection) { - sectionHeader = [super viewForHeaderInSection:section withFrame:frame]; + sectionHeader = [super viewForHeaderInSection:section withFrame:frame inTableView:tableView]; } return sectionHeader; diff --git a/Riot/Modules/GlobalSearch/Files/CellData/FilesSearchCellData.m b/Riot/Modules/GlobalSearch/Files/CellData/FilesSearchCellData.m index 6e509e089..5a183820f 100644 --- a/Riot/Modules/GlobalSearch/Files/CellData/FilesSearchCellData.m +++ b/Riot/Modules/GlobalSearch/Files/CellData/FilesSearchCellData.m @@ -132,19 +132,19 @@ if ([msgtype isEqualToString:kMXMessageTypeImage]) { - return [UIImage imageNamed:@"file_photo_icon"]; + return AssetImages.filePhotoIcon.image; } else if ([msgtype isEqualToString:kMXMessageTypeAudio]) { - return [UIImage imageNamed:@"file_music_icon"]; + return AssetImages.fileMusicIcon.image; } else if ([msgtype isEqualToString:kMXMessageTypeVideo]) { - return [UIImage imageNamed:@"file_video_icon"]; + return AssetImages.fileVideoIcon.image; } else if ([msgtype isEqualToString:kMXMessageTypeFile]) { - return [UIImage imageNamed:@"file_doc_icon"]; + return AssetImages.fileDocIcon.image; } return nil; diff --git a/Riot/Modules/GlobalSearch/Files/HomeFilesSearchViewController.m b/Riot/Modules/GlobalSearch/Files/HomeFilesSearchViewController.m index 5ec57f136..d51cfaa64 100644 --- a/Riot/Modules/GlobalSearch/Files/HomeFilesSearchViewController.m +++ b/Riot/Modules/GlobalSearch/Files/HomeFilesSearchViewController.m @@ -160,7 +160,7 @@ threadParameters = [[ThreadParameters alloc] initWithThreadId:event.threadId stackRoomScreen:NO]; } - else if ([self.mainSession.threadingService isEventThreadRoot:event]) + else if (event.unsignedData.relations.thread || [self.mainSession.threadingService isEventThreadRoot:event]) { threadParameters = [[ThreadParameters alloc] initWithThreadId:event.eventId stackRoomScreen:NO]; diff --git a/Riot/Modules/GlobalSearch/Files/Views/FilesSearchTableViewCell.m b/Riot/Modules/GlobalSearch/Files/Views/FilesSearchTableViewCell.m index e2633d41c..287a71a6f 100644 --- a/Riot/Modules/GlobalSearch/Files/Views/FilesSearchTableViewCell.m +++ b/Riot/Modules/GlobalSearch/Files/Views/FilesSearchTableViewCell.m @@ -107,19 +107,19 @@ switch (type) { case MXKAttachmentTypeImage: - image = [UIImage imageNamed:@"file_photo_icon"]; + image = AssetImages.filePhotoIcon.image; break; case MXKAttachmentTypeAudio: - image = [UIImage imageNamed:@"file_music_icon"]; + image = AssetImages.fileMusicIcon.image; break; case MXKAttachmentTypeVoiceMessage: - image = [UIImage imageNamed:@"file_music_icon"]; + image = AssetImages.fileMusicIcon.image; break; case MXKAttachmentTypeVideo: - image = [UIImage imageNamed:@"file_video_icon"]; + image = AssetImages.fileVideoIcon.image; break; case MXKAttachmentTypeFile: - image = [UIImage imageNamed:@"file_doc_icon"]; + image = AssetImages.fileDocIcon.image; break; default: break; diff --git a/Riot/Modules/GlobalSearch/Messages/DataSources/HomeMessagesSearchDataSource.m b/Riot/Modules/GlobalSearch/Messages/DataSources/HomeMessagesSearchDataSource.m index 14a736b36..f2f2cd406 100644 --- a/Riot/Modules/GlobalSearch/Messages/DataSources/HomeMessagesSearchDataSource.m +++ b/Riot/Modules/GlobalSearch/Messages/DataSources/HomeMessagesSearchDataSource.m @@ -89,6 +89,10 @@ { continueBlock(); } + else if (result.result.unsignedData.relations.thread) + { + continueBlock(); + } else if (room) { [room liveTimeline:^(id liveTimeline) { @@ -164,14 +168,15 @@ { if (cellData.hasThreadRoot) { - MXThread *thread = cellData.bubbleComponents.firstObject.thread; - ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread]; + id thread = cellData.bubbleComponents.firstObject.thread; + ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread + session:self.mxSession]; [bubbleCell.tmpSubviews addObject:threadSummaryView]; threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO; [bubbleCell.contentView addSubview:threadSummaryView]; - CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin; + CGFloat leftMargin = PlainRoomCellLayoutConstants.reactionsViewLeftMargin; CGFloat height = [ThreadSummaryView contentViewHeightForThread:thread fitting:cellData.maxTextViewWidth]; CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0]; @@ -182,9 +187,9 @@ [threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor constant:leftMargin], [threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor - constant:bottomPositionY + RoomBubbleCellLayout.threadSummaryViewTopMargin], + constant:bottomPositionY + PlainRoomCellLayoutConstants.threadSummaryViewTopMargin], [threadSummaryView.heightAnchor constraintEqualToConstant:height], - [threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin] + [threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-PlainRoomCellLayoutConstants.reactionsViewRightMargin] ]]; } else if (event.isInThread) @@ -195,7 +200,7 @@ fromAThreadView.translatesAutoresizingMaskIntoConstraints = NO; [bubbleCell.contentView addSubview:fromAThreadView]; - CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin; + CGFloat leftMargin = PlainRoomCellLayoutConstants.reactionsViewLeftMargin; CGFloat height = [FromAThreadView contentViewHeightForEvent:event fitting:cellData.maxTextViewWidth]; CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0]; @@ -206,9 +211,9 @@ [fromAThreadView.leadingAnchor constraintEqualToAnchor:fromAThreadView.superview.leadingAnchor constant:leftMargin], [fromAThreadView.topAnchor constraintEqualToAnchor:fromAThreadView.superview.topAnchor - constant:bottomPositionY + RoomBubbleCellLayout.fromAThreadViewTopMargin], + constant:bottomPositionY + PlainRoomCellLayoutConstants.fromAThreadViewTopMargin], [fromAThreadView.heightAnchor constraintEqualToConstant:height], - [fromAThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromAThreadView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin] + [fromAThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromAThreadView.superview.trailingAnchor constant:-PlainRoomCellLayoutConstants.reactionsViewRightMargin] ]]; } } diff --git a/Riot/Modules/GlobalSearch/Messages/HomeMessagesSearchViewController.m b/Riot/Modules/GlobalSearch/Messages/HomeMessagesSearchViewController.m index b8ba693be..8ba3d8241 100644 --- a/Riot/Modules/GlobalSearch/Messages/HomeMessagesSearchViewController.m +++ b/Riot/Modules/GlobalSearch/Messages/HomeMessagesSearchViewController.m @@ -167,7 +167,7 @@ threadParameters = [[ThreadParameters alloc] initWithThreadId:event.threadId stackRoomScreen:NO]; } - else if ([self.mainSession.threadingService isEventThreadRoot:event]) + else if (event.unsignedData.relations.thread || [self.mainSession.threadingService isEventThreadRoot:event]) { threadParameters = [[ThreadParameters alloc] initWithThreadId:event.eventId stackRoomScreen:NO]; diff --git a/Riot/Modules/GlobalSearch/UnifiedSearchViewController.m b/Riot/Modules/GlobalSearch/UnifiedSearchViewController.m index 8c1956330..f701d8b08 100644 --- a/Riot/Modules/GlobalSearch/UnifiedSearchViewController.m +++ b/Riot/Modules/GlobalSearch/UnifiedSearchViewController.m @@ -105,9 +105,6 @@ [self initWithTitles:titles viewControllers:viewControllers defaultSelected:0]; [super viewDidLoad]; - - // Add the Riot background image when search bar is empty - [self addBackgroundImageViewToView:self.view]; // Initialize here the data sources if a matrix session has been already set. [self initializeDataSources]; @@ -118,18 +115,6 @@ [super showSearch:NO]; } -- (void)userInterfaceThemeDidChange -{ - [super userInterfaceThemeDidChange]; - - UIImageView *backgroundImageView = self.backgroundImageView; - if (backgroundImageView) - { - UIImage *image = [MXKTools paintImage:backgroundImageView.image withColor:ThemeService.shared.theme.matrixSearchBackgroundImageTintColor]; - backgroundImageView.image = image; - } -} - - (void)destroy { [super destroy]; @@ -178,9 +163,6 @@ { [super viewDidAppear:animated]; - // Here the actual view size is available, check the background image display if any - [self checkAndShowBackgroundImage]; - if (self.splitViewController && !self.splitViewController.isCollapsed) { // In case of split view controller where the primary and secondary view controllers are displayed side-by-side onscreen, @@ -189,13 +171,6 @@ } } -- (void)viewDidLayoutSubviews -{ - [super viewDidLayoutSubviews]; - - [self checkAndShowBackgroundImage]; -} - - (UIStatusBarStyle)preferredStatusBarStyle { return ThemeService.shared.theme.statusBarStyle; @@ -251,7 +226,7 @@ peopleSearchDataSource.showLocalContacts = NO; peopleSearchDataSource.areSectionsShrinkable = YES; peopleSearchDataSource.displaySearchInputInContactsList = YES; - peopleSearchDataSource.contactCellAccessoryImage = [[UIImage imageNamed: @"disclosure_icon"] vc_tintedImageUsingColor:ThemeService.shared.theme.textSecondaryColor];; + peopleSearchDataSource.contactCellAccessoryImage = [AssetImages.disclosureIcon.image vc_tintedImageUsingColor:ThemeService.shared.theme.textSecondaryColor];; [peopleSearchViewController displayList:peopleSearchDataSource]; // Check whether there are others sessions @@ -326,15 +301,6 @@ #pragma mark - Override MXKViewController -- (void)setKeyboardHeight:(CGFloat)keyboardHeight -{ - [self setKeyboardHeightForBackgroundImage:keyboardHeight]; - - [super setKeyboardHeight:keyboardHeight]; - - [self checkAndShowBackgroundImage]; -} - - (void)startActivityIndicator { // Redirect the operation to the currently displayed VC @@ -352,58 +318,6 @@ } } -#pragma mark - Override UIViewController+VectorSearch - -- (void)setKeyboardHeightForBackgroundImage:(CGFloat)keyboardHeight -{ - [super setKeyboardHeightForBackgroundImage:keyboardHeight]; - - if (keyboardHeight > 0) - { - [self checkAndShowBackgroundImage]; - } -} - -// Check conditions before displaying the background -- (void)checkAndShowBackgroundImage -{ - // Note: This background is hidden when keyboard is dismissed. - // The other conditions depend on the current selected view controller. - if (self.selectedViewController == recentsViewController) - { - self.backgroundImageView.hidden = YES; - } - else if (self.selectedViewController == messagesSearchViewController) - { - self.backgroundImageView.hidden = ((messagesSearchDataSource.serverCount != 0) || !messagesSearchViewController.noResultsLabel.isHidden || (self.keyboardHeight == 0)); - } - else if (self.selectedViewController == peopleSearchViewController) - { - self.backgroundImageView.hidden = (([peopleSearchViewController.contactsTableView numberOfSections] != 0) || (self.keyboardHeight == 0)); - } - else if (self.selectedViewController == filesSearchViewController) - { - self.backgroundImageView.hidden = ((filesSearchDataSource.serverCount != 0) || !filesSearchViewController.noResultsLabel.isHidden || (self.keyboardHeight == 0)); - } - else - { - self.backgroundImageView.hidden = (self.keyboardHeight == 0); - } - - if (!self.backgroundImageView.hidden) - { - [self.backgroundImageView layoutIfNeeded]; - [self.selectedViewController.view layoutIfNeeded]; - - // Check whether there is enough space to display this background - // For example, in landscape with the iPhone 5 & 6 screen size, the backgroundImageView must be hidden. - if (self.backgroundImageView.frame.origin.y < 0 || (self.selectedViewController.view.frame.size.height - self.backgroundImageViewBottomConstraint.constant) < self.backgroundImageView.frame.size.height) - { - self.backgroundImageView.hidden = YES; - } - } -} - #pragma mark - Override SegmentedViewController - (void)setSelectedIndex:(NSUInteger)selectedIndex @@ -463,7 +377,6 @@ if (self.searchBar.text.length) { recentsDataSource.hideRecents = NO; - self.backgroundImageView.hidden = YES; // Forward the search request to the data source if (self.selectedViewController == recentsViewController) @@ -482,8 +395,8 @@ // Do it asynchronously to give time to messagesSearchViewController to be set up // so that it can display its loading wheel dispatch_async(dispatch_get_main_queue(), ^{ - [messagesSearchDataSource searchMessages:self.searchBar.text force:NO]; - messagesSearchViewController.shouldScrollToBottomOnRefresh = YES; + [self->messagesSearchDataSource searchMessages:self.searchBar.text force:NO]; + self->messagesSearchViewController.shouldScrollToBottomOnRefresh = YES; }); } } @@ -499,8 +412,8 @@ // Do it asynchronously to give time to filesSearchViewController to be set up // so that it can display its loading wheel dispatch_async(dispatch_get_main_queue(), ^{ - [filesSearchDataSource searchMessages:self.searchBar.text force:NO]; - filesSearchViewController.shouldScrollToBottomOnRefresh = YES; + [self->filesSearchDataSource searchMessages:self.searchBar.text force:NO]; + self->filesSearchViewController.shouldScrollToBottomOnRefresh = YES; }); } } @@ -524,8 +437,6 @@ [filesSearchDataSource searchMessages:nil force:NO]; } } - - [self checkAndShowBackgroundImage]; } #pragma mark - UISearchBarDelegate diff --git a/Riot/Modules/GlobalSearch/Views/RoomIdOrAliasTableViewCell.m b/Riot/Modules/GlobalSearch/Views/RoomIdOrAliasTableViewCell.m index 0a798aefc..820f2ac03 100644 --- a/Riot/Modules/GlobalSearch/Views/RoomIdOrAliasTableViewCell.m +++ b/Riot/Modules/GlobalSearch/Views/RoomIdOrAliasTableViewCell.m @@ -49,7 +49,7 @@ } else { - self.avatarImageView.image = [MXKTools paintImage:[UIImage imageNamed:@"placeholder"] + self.avatarImageView.image = [MXKTools paintImage:AssetImages.placeholder.image withColor:ThemeService.shared.theme.tintColor]; } diff --git a/Riot/Modules/Home/Fallback/AuthFallBackViewController.m b/Riot/Modules/Home/Fallback/AuthFallBackViewController.m index 93a770610..50f7b5f5c 100644 --- a/Riot/Modules/Home/Fallback/AuthFallBackViewController.m +++ b/Riot/Modules/Home/Fallback/AuthFallBackViewController.m @@ -157,7 +157,7 @@ NSString *FallBackViewControllerJavascriptOnLogin = @"window.matrixLogin.onLogin if ([urlString hasPrefix:@"js:"]) { // Listen only to scheme of the JS-WKWebView bridge - NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding]; + NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; NSError *error; diff --git a/Riot/Modules/Home/HomeViewController.m b/Riot/Modules/Home/HomeViewController.m index 8e49c205a..35abd9598 100644 --- a/Riot/Modules/Home/HomeViewController.m +++ b/Riot/Modules/Home/HomeViewController.m @@ -89,7 +89,7 @@ self.recentsTableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; // Add the (+) button programmatically - plusButtonImageView = [self vc_addFABWithImage:[UIImage imageNamed:@"plus_floating_action"] + plusButtonImageView = [self vc_addFABWithImage:AssetImages.plusFloatingAction.image target:self action:@selector(onPlusButtonPressed)]; @@ -380,19 +380,19 @@ // Update the edition menu content (Use the button tag to store the current value). tableViewCell.directChatButton.tag = room.isDirect; [tableViewCell.directChatButton addTarget:self action:@selector(onDirectChatButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - tableViewCell.directChatImageView.image = [UIImage imageNamed:@"room_action_direct_chat"]; + tableViewCell.directChatImageView.image = AssetImages.roomActionDirectChat.image; tableViewCell.directChatImageView.tintColor = room.isDirect ? selectedColor : unselectedColor; tableViewCell.notificationsButton.tag = room.isMute || room.isMentionsOnly; [tableViewCell.notificationsButton addTarget:self action:@selector(onNotificationsButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - if ([BuildSettings showNotificationsV2]) + if ([BuildSettings showNotificationsV2] && tableViewCell.notificationsButton.tag) { - tableViewCell.notificationsImageView.image = tableViewCell.notificationsButton.tag ? [UIImage imageNamed:@"room_action_notification_muted"] : [UIImage imageNamed:@"room_action_notification"]; + tableViewCell.notificationsImageView.image = AssetImages.roomActionNotificationMuted.image; } else { - tableViewCell.notificationsImageView.image = [UIImage imageNamed:@"room_action_notification"]; + tableViewCell.notificationsImageView.image = AssetImages.roomActionNotification.image; } tableViewCell.notificationsImageView.tintColor = tableViewCell.notificationsButton.tag ? unselectedColor : selectedColor; @@ -410,16 +410,16 @@ tableViewCell.favouriteButton.tag = (currentTag && [kMXRoomTagFavourite isEqualToString:currentTag.name]); [tableViewCell.favouriteButton addTarget:self action:@selector(onFavouriteButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - tableViewCell.favouriteImageView.image = [UIImage imageNamed:@"room_action_favourite"]; + tableViewCell.favouriteImageView.image = AssetImages.roomActionFavourite.image; tableViewCell.favouriteImageView.tintColor = tableViewCell.favouriteButton.tag ? selectedColor : unselectedColor; tableViewCell.priorityButton.tag = (currentTag && [kMXRoomTagLowPriority isEqualToString:currentTag.name]); [tableViewCell.priorityButton addTarget:self action:@selector(onPriorityButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - tableViewCell.priorityImageView.image = tableViewCell.priorityButton.tag ? [UIImage imageNamed:@"room_action_priority_high"] : [UIImage imageNamed:@"room_action_priority_low"]; + tableViewCell.priorityImageView.image = tableViewCell.priorityButton.tag ? AssetImages.roomActionPriorityHigh.image : AssetImages.roomActionPriorityLow.image; tableViewCell.priorityImageView.tintColor = unselectedColor; [tableViewCell.leaveButton addTarget:self action:@selector(onLeaveButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - tableViewCell.leaveImageView.image = [UIImage imageNamed:@"room_action_leave"]; + tableViewCell.leaveImageView.image = AssetImages.roomActionLeave.image; tableViewCell.leaveImageView.tintColor = unselectedColor; } } @@ -1012,11 +1012,11 @@ { if (ThemeService.shared.isCurrentThemeDark) { - return [UIImage imageNamed:@"home_empty_screen_artwork_dark"]; + return AssetImages.homeEmptyScreenArtworkDark.image; } else { - return [UIImage imageNamed:@"home_empty_screen_artwork"]; + return AssetImages.homeEmptyScreenArtwork.image; } } diff --git a/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift b/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift index 764dc2d59..1c6c24173 100644 --- a/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift +++ b/Riot/Modules/Home/VersionCheck/HomeViewControllerWithBannerWrapperViewController.swift @@ -95,6 +95,10 @@ class HomeViewControllerWithBannerWrapperViewController: UIViewController, MXKVi homeViewController.activityIndicator = newValue } } + + var providesCustomActivityIndicator: Bool { + return homeViewController.providesCustomActivityIndicator + } func startActivityIndicator() { homeViewController.startActivityIndicator() diff --git a/Riot/Modules/Home/Views/AccessibleCollectionView.swift b/Riot/Modules/Home/Views/AccessibleCollectionView.swift new file mode 100644 index 000000000..9ac0d1f16 --- /dev/null +++ b/Riot/Modules/Home/Views/AccessibleCollectionView.swift @@ -0,0 +1,37 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit + +/// A collection view that returns an accessibility element count equal to the number of +/// items in its first section. This allows voiceover user to swipe through the entire collection. +class AccessibleCollectionView: UICollectionView { + private var numberOfItemsInFirstSection = 0 + + override func accessibilityElementCount() -> Int { + return numberOfItemsInFirstSection + } + + override func numberOfItems(inSection section: Int) -> Int { + let numberOfItems = super.numberOfItems(inSection: section) + + if section == 0 { + numberOfItemsInFirstSection = numberOfItems + } + + return numberOfItems + } +} diff --git a/Riot/Modules/Home/Views/RoomCollectionViewCell.m b/Riot/Modules/Home/Views/RoomCollectionViewCell.m index f13d7bc3b..a6e115192 100644 --- a/Riot/Modules/Home/Views/RoomCollectionViewCell.m +++ b/Riot/Modules/Home/Views/RoomCollectionViewCell.m @@ -52,6 +52,8 @@ [path closePath]; // arrow top side arrowMaskLayer.path = path.CGPath; self.editionArrowView.layer.mask = arrowMaskLayer; + + self.isAccessibilityElement = YES; } - (void)customizeCollectionViewCellRendering @@ -86,6 +88,8 @@ self.roomTitle1.hidden = YES; self.roomTitle2.hidden = YES; + NSMutableString *accessibilityLabel = [self.roomTitle.text mutableCopy]; + // Check whether the room display name is an alias to keep visible the HS. if ([MXTools isMatrixRoomAlias:roomCellData.roomDisplayname]) { @@ -97,6 +101,7 @@ self.roomTitle1.text = [roomCellData.roomDisplayname substringToIndex:range.location + 1]; self.roomTitle2.hidden = NO; self.roomTitle2.text = [roomCellData.roomDisplayname substringFromIndex:range.location + 1]; + accessibilityLabel = [[NSString stringWithFormat:@"%@, %@", self.roomTitle1.text, self.roomTitle2.text] mutableCopy]; } } @@ -118,6 +123,10 @@ self.badgeLabel.hidden = NO; self.badgeLabel.badgeColor = roomCellData.highlightCount ? ThemeService.shared.theme.noticeColor : ThemeService.shared.theme.noticeSecondaryColor; self.badgeLabel.text = roomCellData.notificationCountStringValue; + + NSUInteger count = roomCellData.notificationCount; + NSString *newMessagesLabel = count == 1 ? [VectorL10n roomNewMessageNotification:count] : [VectorL10n roomNewMessagesNotification:count]; + [accessibilityLabel appendFormat:@", %@", newMessagesLabel]; } // Use bold font for the room title @@ -130,6 +139,8 @@ } + self.accessibilityLabel = accessibilityLabel; + [self.roomAvatar vc_setRoomAvatarImageWith:roomCellData.avatarUrl roomId:roomCellData.roomIdentifier displayName:roomCellData.roomDisplayname diff --git a/Riot/Modules/Home/Views/TableViewCellWithCollectionView.m b/Riot/Modules/Home/Views/TableViewCellWithCollectionView.m index 4da67b857..694a55089 100644 --- a/Riot/Modules/Home/Views/TableViewCellWithCollectionView.m +++ b/Riot/Modules/Home/Views/TableViewCellWithCollectionView.m @@ -30,6 +30,11 @@ static CGFloat const kEditionViewCornerRadius = 10.0; self.editionViewBottomConstraint.constant = 0; self.editionView.layer.masksToBounds = YES; + + // Hide both the cell and its collection view from voiceover. + // Instead we expose the individual cells as accessibility elements. + self.isAccessibilityElement = NO; + self.collectionView.isAccessibilityElement = NO; } - (void)customizeTableViewCellRendering diff --git a/Riot/Modules/Home/Views/TableViewCellWithCollectionView.xib b/Riot/Modules/Home/Views/TableViewCellWithCollectionView.xib index 2031df16a..518de25d1 100644 --- a/Riot/Modules/Home/Views/TableViewCellWithCollectionView.xib +++ b/Riot/Modules/Home/Views/TableViewCellWithCollectionView.xib @@ -1,9 +1,9 @@ - + - + @@ -16,7 +16,7 @@ - + @@ -83,7 +83,7 @@ - + @@ -155,5 +155,8 @@ + + + diff --git a/Riot/Modules/Integrations/WidgetPermission/WidgetPermissionViewController.swift b/Riot/Modules/Integrations/WidgetPermission/WidgetPermissionViewController.swift index 2bb3a48bd..fbee5bb4b 100644 --- a/Riot/Modules/Integrations/WidgetPermission/WidgetPermissionViewController.swift +++ b/Riot/Modules/Integrations/WidgetPermission/WidgetPermissionViewController.swift @@ -218,8 +218,6 @@ extension WidgetPermissionViewController: SlidingModalPresentable { let widthConstraint = sizingViewContollerView.widthAnchor.constraint(equalToConstant: width) widthConstraint.isActive = true WidgetPermissionViewController.Sizing.widthConstraint = widthConstraint - - sizingViewContollerView.heightAnchor.constraint(equalToConstant: 0) } sizingViewContollerView.layoutIfNeeded() diff --git a/Riot/Modules/Integrations/Widgets/WidgetViewController.m b/Riot/Modules/Integrations/Widgets/WidgetViewController.m index a5e93b152..77056bcb0 100644 --- a/Riot/Modules/Integrations/Widgets/WidgetViewController.m +++ b/Riot/Modules/Integrations/Widgets/WidgetViewController.m @@ -60,7 +60,7 @@ NSString *const kJavascriptSendResponseToPostMessageAPI = @"riotIOS.sendResponse { self.navigationItem.title = widget.name ? widget.name : widget.type; - UIBarButtonItem *menuButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"room_context_menu_more"] style:UIBarButtonItemStylePlain target:self action:@selector(onMenuButtonPressed:)]; + UIBarButtonItem *menuButton = [[UIBarButtonItem alloc] initWithImage:AssetImages.roomContextMenuMore.image style:UIBarButtonItemStylePlain target:self action:@selector(onMenuButtonPressed:)]; self.navigationItem.rightBarButtonItem = menuButton; } diff --git a/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromRecoveryKeyViewController.swift b/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromRecoveryKeyViewController.swift index 0c33c5915..fd2ab986a 100644 --- a/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromRecoveryKeyViewController.swift +++ b/Riot/Modules/KeyBackup/Setup/Success/KeyBackupSetupSuccessFromRecoveryKeyViewController.swift @@ -143,7 +143,7 @@ final class KeyBackupSetupSuccessFromRecoveryKeyViewController: UIViewController private func shareRecoveryKey() { // Set up activity view controller - let activityItems: [Any] = [ self.recoveryKey ] + let activityItems: [Any] = [ self.recoveryKey as Any ] let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) activityViewController.completionWithItemsHandler = { (activityType, completed, returnedItems, error) in diff --git a/Riot/Modules/LaunchLoading/LaunchLoadingViewController.swift b/Riot/Modules/LaunchLoading/LaunchLoadingViewController.swift new file mode 100644 index 000000000..bd7dba409 --- /dev/null +++ b/Riot/Modules/LaunchLoading/LaunchLoadingViewController.swift @@ -0,0 +1,38 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit +import Reusable + +class LaunchLoadingViewController: UIViewController, Reusable { + + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + init() { + super.init(nibName: "LaunchLoadingViewController", bundle: nil) + + let launchLoadingView = LaunchLoadingView.instantiate() + launchLoadingView.update(theme: ThemeService.shared().theme) + view.vc_addSubViewMatchingParent(launchLoadingView) + + // The launch time isn't profiled for analytics as it's presentation length + // will be artificially changed based on other views in the flow. + } + + override func viewWillAppear(_ animated: Bool) { + navigationController?.setNavigationBarHidden(true, animated: false) + } +} diff --git a/Riot/Modules/LaunchLoading/LaunchLoadingViewController.xib b/Riot/Modules/LaunchLoading/LaunchLoadingViewController.xib new file mode 100644 index 000000000..19628372f --- /dev/null +++ b/Riot/Modules/LaunchLoading/LaunchLoadingViewController.xib @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Riot/Modules/LaunchLoading/LoadingAnimation/ElementView.swift b/Riot/Modules/LaunchLoading/LoadingAnimation/ElementView.swift index f65e8a124..2e80a9c6f 100644 --- a/Riot/Modules/LaunchLoading/LoadingAnimation/ElementView.swift +++ b/Riot/Modules/LaunchLoading/LoadingAnimation/ElementView.swift @@ -102,7 +102,7 @@ public class ElementView: UIView { path.layer.bounds = CGRect(x: 0, y: 0, width: 55.2, height: 55.2) path.layer.masksToBounds = false path.shapeLayer.fillRule = CAShapeLayerFillRule.evenOdd - path.shapeLayer.fillColor = UIColor(displayP3Red: 0.052, green: 0.743, blue: 0.543, alpha: 1).cgColor + path.shapeLayer.fillColor = UIColor(rgb: 0x0DBD8B).cgColor path.shapeLayer.lineDashPattern = [] path.shapeLayer.lineDashPhase = 0 path.shapeLayer.lineWidth = 0 @@ -120,7 +120,7 @@ public class ElementView: UIView { path_1.layer.bounds = CGRect(x: 0, y: 0, width: 55.2, height: 55.2) path_1.layer.masksToBounds = false path_1.shapeLayer.fillRule = CAShapeLayerFillRule.evenOdd - path_1.shapeLayer.fillColor = UIColor(displayP3Red: 0.052, green: 0.743, blue: 0.543, alpha: 1).cgColor + path_1.shapeLayer.fillColor = UIColor(rgb: 0x0DBD8B).cgColor path_1.shapeLayer.lineDashPattern = [] path_1.shapeLayer.lineDashPhase = 0 path_1.shapeLayer.lineWidth = 0 @@ -138,7 +138,7 @@ public class ElementView: UIView { path_2.layer.bounds = CGRect(x: 0, y: 0, width: 55.2, height: 55.2) path_2.layer.masksToBounds = false path_2.shapeLayer.fillRule = CAShapeLayerFillRule.evenOdd - path_2.shapeLayer.fillColor = UIColor(displayP3Red: 0.052, green: 0.743, blue: 0.543, alpha: 1).cgColor + path_2.shapeLayer.fillColor = UIColor(rgb: 0x0DBD8B).cgColor path_2.shapeLayer.lineDashPattern = [] path_2.shapeLayer.lineDashPhase = 0 path_2.shapeLayer.lineWidth = 0 @@ -156,7 +156,7 @@ public class ElementView: UIView { path_3.layer.bounds = CGRect(x: 0, y: 0, width: 55.2, height: 55.2) path_3.layer.masksToBounds = false path_3.shapeLayer.fillRule = CAShapeLayerFillRule.evenOdd - path_3.shapeLayer.fillColor = UIColor(displayP3Red: 0.052, green: 0.743, blue: 0.543, alpha: 1).cgColor + path_3.shapeLayer.fillColor = UIColor(rgb: 0x0DBD8B).cgColor path_3.shapeLayer.lineDashPattern = [] path_3.shapeLayer.lineDashPhase = 0 path_3.shapeLayer.lineWidth = 0 diff --git a/Riot/Modules/MajorUpdate/MajorUpdateViewController.swift b/Riot/Modules/MajorUpdate/MajorUpdateViewController.swift index 0b57526ef..e10c7e715 100644 --- a/Riot/Modules/MajorUpdate/MajorUpdateViewController.swift +++ b/Riot/Modules/MajorUpdate/MajorUpdateViewController.swift @@ -165,8 +165,6 @@ extension MajorUpdateViewController: SlidingModalPresentable { let widthConstraint = sizingViewContollerView.widthAnchor.constraint(equalToConstant: width) widthConstraint.isActive = true MajorUpdateViewController.Sizing.widthConstraint = widthConstraint - - sizingViewContollerView.heightAnchor.constraint(equalToConstant: 0) } sizingViewContollerView.layoutIfNeeded() diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/de.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/de.lproj/MatrixKit.strings index dfa373dc7..df701a6b6 100644 --- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/de.lproj/MatrixKit.strings +++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/de.lproj/MatrixKit.strings @@ -125,7 +125,7 @@ "notice_room_history_visible_to_members_from_joined_point" = "%@ hat den zukünftigen Raumverlauf für alle Raumteilnehmer ab deren Einladung sichtbar gemacht."; "notice_room_history_visible_to_members_from_joined_point_for_dm" = "%@ hat den zukünftigen Verlauf für alle Raumteilnehmer ab deren Einladung sichtbar gemacht."; "notice_crypto_unable_to_decrypt" = "** Entschlüsselung nicht möglich: %@ **"; -"notice_crypto_error_unknown_inbound_session_id" = "Die Sitzung des Absenders hat uns keine Schlüssel für diese Nachricht gesendet."; +"notice_crypto_error_unknown_inbound_session_id" = "Die absendende Sitzung hat uns keine Schlüssel für diese Nachricht gesendet."; "notice_sticker" = "Aufkleber"; "notice_in_reply_to" = "Als Antwort auf"; // room display name diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/en.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/en.lproj/MatrixKit.strings index b7937f194..1b6c229ac 100644 --- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/en.lproj/MatrixKit.strings +++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/en.lproj/MatrixKit.strings @@ -367,7 +367,7 @@ "notice_room_join" = "%@ joined"; "notice_room_leave" = "%@ left"; "notice_room_reject" = "%@ rejected the invitation"; -"notice_room_kick" = "%@ kicked %@"; +"notice_room_kick" = "%@ removed %@"; "notice_room_unban" = "%@ unbanned %@"; "notice_room_ban" = "%@ banned %@"; "notice_room_withdraw" = "%@ withdrew %@'s invitation"; @@ -399,7 +399,7 @@ "notice_room_join_by_you" = "You joined"; "notice_room_leave_by_you" = "You left"; "notice_room_reject_by_you" = "You rejected the invitation"; -"notice_room_kick_by_you" = "You kicked %@"; +"notice_room_kick_by_you" = "You removed %@"; "notice_room_unban_by_you" = "You unbanned %@"; "notice_room_ban_by_you" = "You banned %@"; "notice_room_withdraw_by_you" = "You withdrew %@'s invitation"; @@ -479,7 +479,7 @@ "num_members_one" = "%@ user"; "num_members_other" = "%@ users"; "invite" = "Invite"; -"kick" = "Kick"; +"kick" = "Remove from chat"; "ban" = "Ban"; "unban" = "Un-ban"; "message_unsaved_changes" = "There are unsaved changes. Leaving will discard them."; diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/pt_BR.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/pt_BR.lproj/MatrixKit.strings index 9ddeb7793..969f59541 100644 --- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/pt_BR.lproj/MatrixKit.strings +++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/pt_BR.lproj/MatrixKit.strings @@ -99,7 +99,7 @@ "notice_image_attachment" = "anexo de imagem"; "notice_audio_attachment" = "anexo de áudio"; "notice_video_attachment" = "anexo de vídeo"; -"notice_location_attachment" = "anexo de local"; +"notice_location_attachment" = "anexo de localização"; "notice_file_attachment" = "anexo de arquivo"; "notice_invalid_attachment" = "anexo inválido"; "notice_unsupported_attachment" = "Anexo insuportado: %@"; diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/ru.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/ru.lproj/MatrixKit.strings index 53403ae12..43914e9ca 100644 --- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/ru.lproj/MatrixKit.strings +++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/ru.lproj/MatrixKit.strings @@ -476,3 +476,6 @@ "auth_username_in_use" = "Имя пользователя занято"; "rename" = "Переименовать"; "room_displayname_all_other_members_left" = "%@ (Вышел)"; +"attachment_unsupported_preview_message" = "Этот тип файла не поддерживается."; +"attachment_unsupported_preview_title" = "Не удалось показать предварительный просмотр"; +"message_reply_to_sender_sent_their_location" = "поделились своим местоположением."; diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sk.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sk.lproj/MatrixKit.strings index fec99d96b..7bd5de0d0 100644 --- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sk.lproj/MatrixKit.strings +++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sk.lproj/MatrixKit.strings @@ -119,9 +119,9 @@ // Others "user_id_title" = "ID používateľa:"; -"e2e_passphrase_create" = "Vytvoriť heslo"; -"e2e_passphrase_confirm" = "Potvrďte heslo"; -"e2e_passphrase_enter" = "Zadajte heslo"; +"e2e_passphrase_create" = "Vytvoriť prístupovú frázu"; +"e2e_passphrase_confirm" = "Potvrďte prístupovú frázu"; +"e2e_passphrase_enter" = "Zadajte prístupovú frázu"; // Search "search_no_results" = "Žiadne výsledky"; @@ -547,3 +547,4 @@ "account_link_email" = "Prepojený email"; "account_linked_emails" = "Prepojené e-maily"; "room_event_encryption_info_event_fingerprint_key" = "Deklarovaný kľúč odtlačkov prstov Ed25519\n"; +"notification_settings_notify_all_other" = "Oznámiť pre všetky ostatné správy/miestnosti"; diff --git a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sv.lproj/MatrixKit.strings b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sv.lproj/MatrixKit.strings index d030f2d6e..ecadb738e 100644 --- a/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sv.lproj/MatrixKit.strings +++ b/Riot/Modules/MatrixKit/Assets/MatrixKitAssets.bundle/sv.lproj/MatrixKit.strings @@ -259,9 +259,9 @@ "user_id_placeholder" = "t.ex.: @sven:hemserver"; "ssl_homeserver_url" = "Hemserver-URL: %@"; // Permissions -"camera_access_not_granted_for_call" = "Videosamtal kräver åtkomst till kameran men %@ har inte behörighet att använda den"; -"microphone_access_not_granted_for_call" = "Samtal kräver åtkomst till mikrofonen men %@ har inte behörighet att använda den"; -"local_contacts_access_not_granted" = "Upptäckt av användare från lokala kontakter kräver åtkomst till dina kontakter men %@ har inte behörighet att komma åt dem"; +"camera_access_not_granted_for_call" = "Videosamtal kräver åtkomst till kameran men %@ är inte behörig att använda den"; +"microphone_access_not_granted_for_call" = "Samtal kräver åtkomst till mikrofonen men %@ är inte behörig att använda den"; +"local_contacts_access_not_granted" = "Upptäckt av användare från lokala kontakter kräver åtkomst till dina kontakter men %@ är inte behörig att komma åt dem"; "local_contacts_access_discovery_warning_title" = "Användarupptäckt"; "local_contacts_access_discovery_warning" = "För att upptäcka kontakter som redan använder Matrix kan %@ skicka e-postadresser och telefonnummer i din adressbok till din valda Matrixidentitetsserver. Där det stöds hashas personuppgifter innan de skickas - kontrollera din identitetsservers integritetspolicy för mer information."; // Country picker @@ -462,7 +462,7 @@ "call_voice_with_user" = "Röstsamtal med %@"; "call_ringing" = "Ringer…"; "e2e_passphrase_too_short" = "Lösenfras för kort (den måste vara minst %d tecken långt)"; -"microphone_access_not_granted_for_voice_message" = "Röstmeddelanden kräver åtkomst till mikrofonen, men %@ har inte behörighet att använda den"; +"microphone_access_not_granted_for_voice_message" = "Röstmeddelanden kräver åtkomst till mikrofonen, men %@ är inte behörig att använda den"; "message_reply_to_sender_sent_a_voice_message" = "skickade ett röstmeddelande."; "attachment_large_with_resolution" = "Stor %@ (~%@)"; "attachment_medium_with_resolution" = "Mellan %@ (~%@)"; diff --git a/Riot/Modules/MatrixKit/Controllers/MXKActivityHandlingViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKActivityHandlingViewController.m index 5628c7396..97cce741e 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKActivityHandlingViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKActivityHandlingViewController.m @@ -29,6 +29,11 @@ { [super viewDidLoad]; + if ([self providesCustomActivityIndicator]) { + // If a subclass provides custom activity indicator, the default one will not even be initialized. + return; + } + // Add default activity indicator activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; activityIndicator.backgroundColor = [UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:1.0]; @@ -56,9 +61,13 @@ #pragma mark - Activity indicator +- (BOOL)providesCustomActivityIndicator { + return NO; +} + - (void)startActivityIndicator { - if (activityIndicator) + if (activityIndicator && ![self providesCustomActivityIndicator]) { [self.view bringSubviewToFront:activityIndicator]; [activityIndicator startAnimating]; @@ -79,5 +88,4 @@ [activityIndicator stopAnimating]; } - @end diff --git a/Riot/Modules/MatrixKit/Controllers/MXKAttachmentsViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKAttachmentsViewController.m index a21fbc396..06df81822 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKAttachmentsViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKAttachmentsViewController.m @@ -175,7 +175,11 @@ _attachmentsCollection.hidden = YES; // Display collection cell in full screen + + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" self.automaticallyAdjustsScrollViewInsets = NO; + #pragma clang diagnostic pop } - (BOOL)prefersStatusBarHidden diff --git a/Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m index 3465c136b..f51004ede 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKAuthenticationViewController.m @@ -215,6 +215,8 @@ // and report the inputAccessoryView.superview of the firstResponder in self.keyboardView. } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" - (void)setKeyboardHeight:(CGFloat)keyboardHeight { // Deduce the bottom inset for the scroll view (Don't forget the potential tabBar) @@ -229,6 +231,7 @@ insets.bottom = scrollViewInsetBottom; self.authenticationScrollView.contentInset = insets; } +#pragma clang diagnostic pop - (void)destroy { @@ -981,7 +984,10 @@ { // Trigger here a register request in order to associate the filled userId and password to the current session id // This will check the availability of the userId at the same time - NSDictionary *parameters = @{@"auth": @{}, + NSDictionary *parameters = @{@"auth": @{ + @"session": self.authInputsView.authSession.session, + @"type": kMXLoginFlowTypeDummy + }, @"username": self.authInputsView.userId, @"password": self.authInputsView.password, @"bind_email": @(NO), diff --git a/Riot/Modules/MatrixKit/Controllers/MXKCallViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKCallViewController.m index 5744e75ed..6c138160d 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKCallViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKCallViewController.m @@ -1422,29 +1422,31 @@ static const CGFloat kLocalPreviewMargin = 20; } } -- (void)updateProximityAndSleep -{ - BOOL inCall = (mxCall.state == MXCallStateConnected || mxCall.state == MXCallStateRinging || mxCall.state == MXCallStateInviteSent || mxCall.state == MXCallStateConnecting || mxCall.state == MXCallStateCreateOffer || mxCall.state == MXCallStateCreateAnswer); - - if (inCall) - { - BOOL isBuiltInReceiverUsed = self.isBuiltInReceiverAudioOuput; - - // Enable the proximity monitoring when the built in receiver is used as the audio output. - BOOL enableProxMonitoring = isBuiltInReceiverUsed; - [[UIDevice currentDevice] setProximityMonitoringEnabled:enableProxMonitoring]; - - // Disable the idle timer during a video call, or during a voice call which is performed with the built-in receiver. - // Note: if the device is locked, VoIP calling get dropped if an incoming GSM call is received. - BOOL disableIdleTimer = mxCall.isVideoCall || isBuiltInReceiverUsed; - - UIApplication *sharedApplication = [UIApplication performSelector:@selector(sharedApplication)]; - if (sharedApplication) - { - sharedApplication.idleTimerDisabled = disableIdleTimer; - } - } -} + - (void)updateProximityAndSleep + { + BOOL inCall = (mxCall.state == MXCallStateConnected || mxCall.state == MXCallStateRinging || mxCall.state == MXCallStateInviteSent || mxCall.state == MXCallStateConnecting || mxCall.state == MXCallStateCreateOffer || mxCall.state == MXCallStateCreateAnswer); + + BOOL isBuiltInReceiverUsed = self.isBuiltInReceiverAudioOuput; + + // Enable the proximity monitoring when the built in receiver is used as the audio output. + BOOL enableProxMonitoring = inCall && isBuiltInReceiverUsed; + + UIDevice *device = [UIDevice currentDevice]; + if (device && device.isProximityMonitoringEnabled != enableProxMonitoring) + { + [device setProximityMonitoringEnabled:enableProxMonitoring]; + } + + // Disable the idle timer during a video call, or during a voice call which is performed with the built-in receiver. + // Note: if the device is locked, VoIP calling get dropped if an incoming GSM call is received. + BOOL disableIdleTimer = inCall && (mxCall.isVideoCall || isBuiltInReceiverUsed); + + UIApplication *sharedApplication = [UIApplication performSelector:@selector(sharedApplication)]; + if (sharedApplication && sharedApplication.isIdleTimerDisabled != disableIdleTimer) + { + sharedApplication.idleTimerDisabled = disableIdleTimer; + } + } - (UIView *)createIncomingCallView { diff --git a/Riot/Modules/MatrixKit/Controllers/MXKCountryPickerViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKCountryPickerViewController.m index 273046244..80ea288f7 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKCountryPickerViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKCountryPickerViewController.m @@ -152,7 +152,7 @@ NSString* const kMXKCountryPickerViewControllerCountryCellId = @"kMXKCountryPick { UISearchController *searchController = [[UISearchController alloc] initWithSearchResultsController:nil]; - searchController.dimsBackgroundDuringPresentation = NO; + searchController.obscuresBackgroundDuringPresentation = NO; searchController.hidesNavigationBarDuringPresentation = NO; searchController.searchResultsUpdater = self; diff --git a/Riot/Modules/MatrixKit/Controllers/MXKGroupListViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKGroupListViewController.m index e9950fa3f..b23a55720 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKGroupListViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKGroupListViewController.m @@ -92,6 +92,8 @@ [[[self class] nib] instantiateWithOwner:self options:nil]; } + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" // Adjust search bar Top constraint to take into account potential navBar. if (_groupsSearchBarTopConstraint) { @@ -123,6 +125,7 @@ [NSLayoutConstraint activateConstraints:@[_groupsTableViewBottomConstraint]]; } + #pragma clang diagnostic pop // Hide search bar by default [self hideSearchBar:YES]; @@ -209,6 +212,8 @@ self.keyboardView = _groupsSearchBar.inputAccessoryView.superview; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" - (void)setKeyboardHeight:(CGFloat)keyboardHeight { // Deduce the bottom constraint for the table view (Don't forget the potential tabBar) @@ -225,6 +230,7 @@ // Force layout immediately to take into account new constraint [self.view layoutIfNeeded]; } +#pragma clang diagnostic pop - (void)destroy { diff --git a/Riot/Modules/MatrixKit/Controllers/MXKLanguagePickerViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKLanguagePickerViewController.m index 92d1a065c..b1c796356 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKLanguagePickerViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKLanguagePickerViewController.m @@ -160,7 +160,7 @@ NSString* const kMXKLanguagePickerCellDataKeyLanguage = @"language"; { UISearchController *searchController = [[UISearchController alloc] initWithSearchResultsController:nil]; - searchController.dimsBackgroundDuringPresentation = NO; + searchController.obscuresBackgroundDuringPresentation = NO; searchController.hidesNavigationBarDuringPresentation = NO; searchController.searchResultsUpdater = self; diff --git a/Riot/Modules/MatrixKit/Controllers/MXKRecentListViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKRecentListViewController.m index 828f84825..25b50ee61 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKRecentListViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKRecentListViewController.m @@ -97,6 +97,8 @@ [[[self class] nib] instantiateWithOwner:self options:nil]; } + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" // Adjust search bar Top constraint to take into account potential navBar. if (_recentsSearchBarTopConstraint) { @@ -126,6 +128,7 @@ _recentsTableViewBottomConstraint.active = YES; } + #pragma clang diagnostic pop // Hide search bar by default [self hideSearchBar:YES]; @@ -217,7 +220,7 @@ if ([MXKRoomDataSourceManager sharedManagerForMatrixSession:mxSession].isServerSyncInProgress) { // sync is in progress for at least one data source, keep running the loading wheel - [self.activityIndicator startAnimating]; + [self startActivityIndicator]; break; } } @@ -229,6 +232,8 @@ self.keyboardView = _recentsSearchBar.inputAccessoryView.superview; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" - (void)setKeyboardHeight:(CGFloat)keyboardHeight { // Deduce the bottom constraint for the table view (Don't forget the potential tabBar) @@ -245,6 +250,7 @@ // Force layout immediately to take into account new constraint [self.view layoutIfNeeded]; } +#pragma clang diagnostic pop - (void)destroy { @@ -421,7 +427,9 @@ - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { // Let dataSource provide the section header. - return [dataSource viewForHeaderInSection:section withFrame:[tableView rectForHeaderInSection:section]]; + return [dataSource viewForHeaderInSection:section + withFrame:[tableView rectForHeaderInSection:section] + inTableView:tableView]; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath diff --git a/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberListViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberListViewController.m index 217fb4758..f53ccc57a 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberListViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKRoomMemberListViewController.m @@ -105,6 +105,8 @@ // Adjust Top and Bottom constraints to take into account potential navBar and tabBar. [NSLayoutConstraint deactivateConstraints:@[_membersSearchBarTopConstraint, _membersTableViewBottomConstraint]]; + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" _membersSearchBarTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual @@ -120,6 +122,7 @@ attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + #pragma clang diagnostic pop [NSLayoutConstraint activateConstraints:@[_membersSearchBarTopConstraint, _membersTableViewBottomConstraint]]; @@ -225,6 +228,8 @@ self.keyboardView = _membersSearchBar.inputAccessoryView.superview; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" - (void)setKeyboardHeight:(CGFloat)keyboardHeight { // Deduce the bottom constraint for the table view (Don't forget the potential tabBar) @@ -241,6 +246,7 @@ // Force layout immediately to take into account new constraint [self.view layoutIfNeeded]; } +#pragma clang diagnostic pop - (void)destroy { diff --git a/Riot/Modules/MatrixKit/Controllers/MXKSearchViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKSearchViewController.m index 7ac637b33..8d6a03b18 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKSearchViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKSearchViewController.m @@ -76,6 +76,8 @@ // Adjust Top and Bottom constraints to take into account potential navBar and tabBar. [NSLayoutConstraint deactivateConstraints:@[_searchSearchBarTopConstraint, _searchTableViewBottomConstraint]]; + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" _searchSearchBarTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual @@ -91,6 +93,7 @@ attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + #pragma clang diagnostic pop [NSLayoutConstraint activateConstraints:@[_searchSearchBarTopConstraint, _searchTableViewBottomConstraint]]; @@ -140,6 +143,8 @@ self.keyboardView = _searchSearchBar.inputAccessoryView.superview; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" - (void)setKeyboardHeight:(CGFloat)keyboardHeight { // Deduce the bottom constraint for the table view (Don't forget the potential tabBar) @@ -156,6 +161,7 @@ // Force layout immediately to take into account new constraint [self.view layoutIfNeeded]; } +#pragma clang diagnostic pop - (void)destroy { diff --git a/Riot/Modules/MatrixKit/Controllers/MXKViewControllerActivityHandling.h b/Riot/Modules/MatrixKit/Controllers/MXKViewControllerActivityHandling.h index 299071230..f80d2990d 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKViewControllerActivityHandling.h +++ b/Riot/Modules/MatrixKit/Controllers/MXKViewControllerActivityHandling.h @@ -35,6 +35,14 @@ */ @property (nonatomic) UIActivityIndicatorView *activityIndicator; +/** + A view controller may choose to implement a completely custom activity indicator (e.g. shared toast notification), + + In this case the default `activityIndicator` will be hidden, and the view controller is responsible for overriding + `startActivityIndicator` and `stopActivityIndicator` methods to show / hide the custom activity indicator. + */ +@property (nonatomic, readonly) BOOL providesCustomActivityIndicator; + /** Bring the activity indicator to the front and start it. */ diff --git a/Riot/Modules/MatrixKit/Controllers/MXKWebViewViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKWebViewViewController.m index 07c23b452..b96fe3bd5 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKWebViewViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKWebViewViewController.m @@ -133,6 +133,9 @@ NSString *const kMXKWebViewViewControllerJavaScriptEnableLog = multiplier:1.0 constant:0]; // Force webview in full height + + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:webView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual @@ -147,6 +150,7 @@ NSString *const kMXKWebViewViewControllerJavaScriptEnableLog = attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]; + #pragma clang diagnostic pop [NSLayoutConstraint activateConstraints:@[leftConstraint, rightConstraint, topConstraint, bottomConstraint]]; diff --git a/Riot/Modules/MatrixKit/Libs/SwiftUTI/UTI.swift b/Riot/Modules/MatrixKit/Libs/SwiftUTI/UTI.swift index c3d66c481..4ea8ea88d 100644 --- a/Riot/Modules/MatrixKit/Libs/SwiftUTI/UTI.swift +++ b/Riot/Modules/MatrixKit/Libs/SwiftUTI/UTI.swift @@ -104,7 +104,9 @@ public class UTI: RawRepresentable, Equatable { // UTTypeCreatePreferredIdentifierForTag only returns nil if the tag class is unknwown, which can't happen to us since we use an // enum of known values. Hence we can force-cast the result. + // swiftlint:disable force_unwrapping let identifier = (unmanagedIdentifier?.takeRetainedValue() as String?)! + // swiftlint:enable force_unwrapping self.init(rawValue: identifier) } @@ -122,7 +124,7 @@ public class UTI: RawRepresentable, Equatable { public convenience init(withExtension fileExtension: String, conformingTo conforming: UTI? = nil) { - self.init(withTagClass:.fileExtension, value: fileExtension, conformingTo: conforming) + self.init(withTagClass: .fileExtension, value: fileExtension, conformingTo: conforming) } /** @@ -138,7 +140,7 @@ public class UTI: RawRepresentable, Equatable { public convenience init(withMimeType mimeType: String, conformingTo conforming: UTI? = nil) { - self.init(withTagClass:.mimeType, value: mimeType, conformingTo: conforming) + self.init(withTagClass: .mimeType, value: mimeType, conformingTo: conforming) } #if os(macOS) @@ -146,7 +148,9 @@ public class UTI: RawRepresentable, Equatable { /** Initialize an UTI with a pasteboard type. - - Important: **This function is de-facto deprecated!** The old cocoa pasteboard types ( `NSStringPboardType`, `NSPDFPboardType`, etc) have been deprecated in favour of actual UTIs, and the constants are not available anymore in Swift. This function only works correctly with the values of these old constants, but _not_ with the replacement values (like `NSPasteboardTypeString` etc), since these already are UTIs. + - Important: **This function is de-facto deprecated!** The old cocoa pasteboard types ( `NSStringPboardType`, `NSPDFPboardType`, etc) have been deprecated in favour of actual UTIs, and the + constants are not available anymore in Swift. This function only works correctly with the values of these old constants, but _not_ with the replacement values (like `NSPasteboardTypeString` etc), since these + already are UTIs. - Parameters: - pbType: The pasteboard type (e.g. NSPDFPboardType). - conformingTo: If specified, the returned UTI must conform to this UTI. If nil is specified, this parameter is ignored. The default is nil. @@ -155,7 +159,7 @@ public class UTI: RawRepresentable, Equatable { */ public convenience init(withPBType pbType: String, conformingTo conforming: UTI? = nil) { - self.init(withTagClass:.pbType, value: pbType, conformingTo: conforming) + self.init(withTagClass: .pbType, value: pbType, conformingTo: conforming) } /** @@ -172,7 +176,7 @@ public class UTI: RawRepresentable, Equatable { public convenience init(withOSType osType: String, conformingTo conforming: UTI? = nil) { - self.init(withTagClass:.osType, value: osType, conformingTo: conforming) + self.init(withTagClass: .osType, value: osType, conformingTo: conforming) } #endif @@ -297,7 +301,7 @@ public class UTI: RawRepresentable, Equatable { return UTTypeConformsTo(self.rawCFValue, otherUTI.rawCFValue) as Bool } - public static func ==(lhs: UTI, rhs: UTI) -> Bool { + public static func == (lhs: UTI, rhs: UTI) -> Bool { return UTTypeEqual(lhs.rawCFValue, rhs.rawCFValue) as Bool } @@ -319,11 +323,11 @@ public class UTI: RawRepresentable, Equatable { /// Returns a uniform type’s declaration as a Dictionary, or nil if if no declaration for that type can be found. - public var declaration: [AnyHashable:Any]? { + public var declaration: [AnyHashable: Any]? { let unmanagedDeclaration = UTTypeCopyDeclaration(self.rawCFValue) - guard let declaration = unmanagedDeclaration?.takeRetainedValue() as? [AnyHashable:Any] else { + guard let declaration = unmanagedDeclaration?.takeRetainedValue() as? [AnyHashable: Any] else { return nil } @@ -356,137 +360,137 @@ public class UTI: RawRepresentable, Equatable { public extension UTI { - static let item = UTI(rawValue: kUTTypeItem as String) - static let content = UTI(rawValue: kUTTypeContent as String) - static let compositeContent = UTI(rawValue: kUTTypeCompositeContent as String) - static let message = UTI(rawValue: kUTTypeMessage as String) - static let contact = UTI(rawValue: kUTTypeContact as String) - static let archive = UTI(rawValue: kUTTypeArchive as String) - static let diskImage = UTI(rawValue: kUTTypeDiskImage as String) - static let data = UTI(rawValue: kUTTypeData as String) - static let directory = UTI(rawValue: kUTTypeDirectory as String) - static let resolvable = UTI(rawValue: kUTTypeResolvable as String) - static let symLink = UTI(rawValue: kUTTypeSymLink as String) - static let executable = UTI(rawValue: kUTTypeExecutable as String) - static let mountPoint = UTI(rawValue: kUTTypeMountPoint as String) - static let aliasFile = UTI(rawValue: kUTTypeAliasFile as String) - static let aliasRecord = UTI(rawValue: kUTTypeAliasRecord as String) - static let urlBookmarkData = UTI(rawValue: kUTTypeURLBookmarkData as String) - static let url = UTI(rawValue: kUTTypeURL as String) - static let fileURL = UTI(rawValue: kUTTypeFileURL as String) - static let text = UTI(rawValue: kUTTypeText as String) - static let plainText = UTI(rawValue: kUTTypePlainText as String) - static let utf8PlainText = UTI(rawValue: kUTTypeUTF8PlainText as String) - static let utf16ExternalPlainText = UTI(rawValue: kUTTypeUTF16ExternalPlainText as String) - static let utf16PlainText = UTI(rawValue: kUTTypeUTF16PlainText as String) - static let delimitedText = UTI(rawValue: kUTTypeDelimitedText as String) - static let commaSeparatedText = UTI(rawValue: kUTTypeCommaSeparatedText as String) - static let tabSeparatedText = UTI(rawValue: kUTTypeTabSeparatedText as String) - static let utf8TabSeparatedText = UTI(rawValue: kUTTypeUTF8TabSeparatedText as String) - static let rtf = UTI(rawValue: kUTTypeRTF as String) - static let html = UTI(rawValue: kUTTypeHTML as String) - static let xml = UTI(rawValue: kUTTypeXML as String) - static let sourceCode = UTI(rawValue: kUTTypeSourceCode as String) - static let assemblyLanguageSource = UTI(rawValue: kUTTypeAssemblyLanguageSource as String) - static let cSource = UTI(rawValue: kUTTypeCSource as String) - static let objectiveCSource = UTI(rawValue: kUTTypeObjectiveCSource as String) + static let item = UTI(rawValue: kUTTypeItem as String) + static let content = UTI(rawValue: kUTTypeContent as String) + static let compositeContent = UTI(rawValue: kUTTypeCompositeContent as String) + static let message = UTI(rawValue: kUTTypeMessage as String) + static let contact = UTI(rawValue: kUTTypeContact as String) + static let archive = UTI(rawValue: kUTTypeArchive as String) + static let diskImage = UTI(rawValue: kUTTypeDiskImage as String) + static let data = UTI(rawValue: kUTTypeData as String) + static let directory = UTI(rawValue: kUTTypeDirectory as String) + static let resolvable = UTI(rawValue: kUTTypeResolvable as String) + static let symLink = UTI(rawValue: kUTTypeSymLink as String) + static let executable = UTI(rawValue: kUTTypeExecutable as String) + static let mountPoint = UTI(rawValue: kUTTypeMountPoint as String) + static let aliasFile = UTI(rawValue: kUTTypeAliasFile as String) + static let aliasRecord = UTI(rawValue: kUTTypeAliasRecord as String) + static let urlBookmarkData = UTI(rawValue: kUTTypeURLBookmarkData as String) + static let url = UTI(rawValue: kUTTypeURL as String) + static let fileURL = UTI(rawValue: kUTTypeFileURL as String) + static let text = UTI(rawValue: kUTTypeText as String) + static let plainText = UTI(rawValue: kUTTypePlainText as String) + static let utf8PlainText = UTI(rawValue: kUTTypeUTF8PlainText as String) + static let utf16ExternalPlainText = UTI(rawValue: kUTTypeUTF16ExternalPlainText as String) + static let utf16PlainText = UTI(rawValue: kUTTypeUTF16PlainText as String) + static let delimitedText = UTI(rawValue: kUTTypeDelimitedText as String) + static let commaSeparatedText = UTI(rawValue: kUTTypeCommaSeparatedText as String) + static let tabSeparatedText = UTI(rawValue: kUTTypeTabSeparatedText as String) + static let utf8TabSeparatedText = UTI(rawValue: kUTTypeUTF8TabSeparatedText as String) + static let rtf = UTI(rawValue: kUTTypeRTF as String) + static let html = UTI(rawValue: kUTTypeHTML as String) + static let xml = UTI(rawValue: kUTTypeXML as String) + static let sourceCode = UTI(rawValue: kUTTypeSourceCode as String) + static let assemblyLanguageSource = UTI(rawValue: kUTTypeAssemblyLanguageSource as String) + static let cSource = UTI(rawValue: kUTTypeCSource as String) + static let objectiveCSource = UTI(rawValue: kUTTypeObjectiveCSource as String) @available( OSX 10.11, iOS 9.0, * ) - static let swiftSource = UTI(rawValue: kUTTypeSwiftSource as String) - static let cPlusPlusSource = UTI(rawValue: kUTTypeCPlusPlusSource as String) - static let objectiveCPlusPlusSource = UTI(rawValue: kUTTypeObjectiveCPlusPlusSource as String) - static let cHeader = UTI(rawValue: kUTTypeCHeader as String) - static let cPlusPlusHeader = UTI(rawValue: kUTTypeCPlusPlusHeader as String) - static let javaSource = UTI(rawValue: kUTTypeJavaSource as String) - static let script = UTI(rawValue: kUTTypeScript as String) - static let appleScript = UTI(rawValue: kUTTypeAppleScript as String) - static let osaScript = UTI(rawValue: kUTTypeOSAScript as String) - static let osaScriptBundle = UTI(rawValue: kUTTypeOSAScriptBundle as String) - static let javaScript = UTI(rawValue: kUTTypeJavaScript as String) - static let shellScript = UTI(rawValue: kUTTypeShellScript as String) - static let perlScript = UTI(rawValue: kUTTypePerlScript as String) - static let pythonScript = UTI(rawValue: kUTTypePythonScript as String) - static let rubyScript = UTI(rawValue: kUTTypeRubyScript as String) - static let phpScript = UTI(rawValue: kUTTypePHPScript as String) - static let json = UTI(rawValue: kUTTypeJSON as String) - static let propertyList = UTI(rawValue: kUTTypePropertyList as String) - static let xmlPropertyList = UTI(rawValue: kUTTypeXMLPropertyList as String) - static let binaryPropertyList = UTI(rawValue: kUTTypeBinaryPropertyList as String) - static let pdf = UTI(rawValue: kUTTypePDF as String) - static let rtfd = UTI(rawValue: kUTTypeRTFD as String) - static let flatRTFD = UTI(rawValue: kUTTypeFlatRTFD as String) - static let txnTextAndMultimediaData = UTI(rawValue: kUTTypeTXNTextAndMultimediaData as String) - static let webArchive = UTI(rawValue: kUTTypeWebArchive as String) - static let image = UTI(rawValue: kUTTypeImage as String) - static let jpeg = UTI(rawValue: kUTTypeJPEG as String) - static let jpeg2000 = UTI(rawValue: kUTTypeJPEG2000 as String) - static let tiff = UTI(rawValue: kUTTypeTIFF as String) - static let pict = UTI(rawValue: kUTTypePICT as String) - static let gif = UTI(rawValue: kUTTypeGIF as String) - static let png = UTI(rawValue: kUTTypePNG as String) - static let quickTimeImage = UTI(rawValue: kUTTypeQuickTimeImage as String) - static let appleICNS = UTI(rawValue: kUTTypeAppleICNS as String) - static let bmp = UTI(rawValue: kUTTypeBMP as String) - static let ico = UTI(rawValue: kUTTypeICO as String) - static let rawImage = UTI(rawValue: kUTTypeRawImage as String) - static let scalableVectorGraphics = UTI(rawValue: kUTTypeScalableVectorGraphics as String) + static let swiftSource = UTI(rawValue: kUTTypeSwiftSource as String) + static let cPlusPlusSource = UTI(rawValue: kUTTypeCPlusPlusSource as String) + static let objectiveCPlusPlusSource = UTI(rawValue: kUTTypeObjectiveCPlusPlusSource as String) + static let cHeader = UTI(rawValue: kUTTypeCHeader as String) + static let cPlusPlusHeader = UTI(rawValue: kUTTypeCPlusPlusHeader as String) + static let javaSource = UTI(rawValue: kUTTypeJavaSource as String) + static let script = UTI(rawValue: kUTTypeScript as String) + static let appleScript = UTI(rawValue: kUTTypeAppleScript as String) + static let osaScript = UTI(rawValue: kUTTypeOSAScript as String) + static let osaScriptBundle = UTI(rawValue: kUTTypeOSAScriptBundle as String) + static let javaScript = UTI(rawValue: kUTTypeJavaScript as String) + static let shellScript = UTI(rawValue: kUTTypeShellScript as String) + static let perlScript = UTI(rawValue: kUTTypePerlScript as String) + static let pythonScript = UTI(rawValue: kUTTypePythonScript as String) + static let rubyScript = UTI(rawValue: kUTTypeRubyScript as String) + static let phpScript = UTI(rawValue: kUTTypePHPScript as String) + static let json = UTI(rawValue: kUTTypeJSON as String) + static let propertyList = UTI(rawValue: kUTTypePropertyList as String) + static let xmlPropertyList = UTI(rawValue: kUTTypeXMLPropertyList as String) + static let binaryPropertyList = UTI(rawValue: kUTTypeBinaryPropertyList as String) + static let pdf = UTI(rawValue: kUTTypePDF as String) + static let rtfd = UTI(rawValue: kUTTypeRTFD as String) + static let flatRTFD = UTI(rawValue: kUTTypeFlatRTFD as String) + static let txnTextAndMultimediaData = UTI(rawValue: kUTTypeTXNTextAndMultimediaData as String) + static let webArchive = UTI(rawValue: kUTTypeWebArchive as String) + static let image = UTI(rawValue: kUTTypeImage as String) + static let jpeg = UTI(rawValue: kUTTypeJPEG as String) + static let jpeg2000 = UTI(rawValue: kUTTypeJPEG2000 as String) + static let tiff = UTI(rawValue: kUTTypeTIFF as String) + static let pict = UTI(rawValue: kUTTypePICT as String) + static let gif = UTI(rawValue: kUTTypeGIF as String) + static let png = UTI(rawValue: kUTTypePNG as String) + static let quickTimeImage = UTI(rawValue: kUTTypeQuickTimeImage as String) + static let appleICNS = UTI(rawValue: kUTTypeAppleICNS as String) + static let bmp = UTI(rawValue: kUTTypeBMP as String) + static let ico = UTI(rawValue: kUTTypeICO as String) + static let rawImage = UTI(rawValue: kUTTypeRawImage as String) + static let scalableVectorGraphics = UTI(rawValue: kUTTypeScalableVectorGraphics as String) @available(OSX 10.12, iOS 9.1, watchOS 2.1, *) - static let livePhoto = UTI(rawValue: kUTTypeLivePhoto as String) + static let livePhoto = UTI(rawValue: kUTTypeLivePhoto as String) @available(OSX 10.12, iOS 9.1, *) - static let audiovisualContent = UTI(rawValue: kUTTypeAudiovisualContent as String) - static let movie = UTI(rawValue: kUTTypeMovie as String) - static let video = UTI(rawValue: kUTTypeVideo as String) - static let audio = UTI(rawValue: kUTTypeAudio as String) - static let quickTimeMovie = UTI(rawValue: kUTTypeQuickTimeMovie as String) - static let mpeg = UTI(rawValue: kUTTypeMPEG as String) - static let mpeg2Video = UTI(rawValue: kUTTypeMPEG2Video as String) - static let mpeg2TransportStream = UTI(rawValue: kUTTypeMPEG2TransportStream as String) - static let mp3 = UTI(rawValue: kUTTypeMP3 as String) - static let mpeg4 = UTI(rawValue: kUTTypeMPEG4 as String) - static let mpeg4Audio = UTI(rawValue: kUTTypeMPEG4Audio as String) - static let appleProtectedMPEG4Audio = UTI(rawValue: kUTTypeAppleProtectedMPEG4Audio as String) - static let appleProtectedMPEG4Video = UTI(rawValue: kUTTypeAppleProtectedMPEG4Video as String) - static let aviMovie = UTI(rawValue: kUTTypeAVIMovie as String) - static let audioInterchangeFileFormat = UTI(rawValue: kUTTypeAudioInterchangeFileFormat as String) - static let waveformAudio = UTI(rawValue: kUTTypeWaveformAudio as String) - static let midiAudio = UTI(rawValue: kUTTypeMIDIAudio as String) - static let playlist = UTI(rawValue: kUTTypePlaylist as String) - static let m3UPlaylist = UTI(rawValue: kUTTypeM3UPlaylist as String) - static let folder = UTI(rawValue: kUTTypeFolder as String) - static let volume = UTI(rawValue: kUTTypeVolume as String) - static let package = UTI(rawValue: kUTTypePackage as String) - static let bundle = UTI(rawValue: kUTTypeBundle as String) - static let pluginBundle = UTI(rawValue: kUTTypePluginBundle as String) - static let spotlightImporter = UTI(rawValue: kUTTypeSpotlightImporter as String) - static let quickLookGenerator = UTI(rawValue: kUTTypeQuickLookGenerator as String) - static let xpcService = UTI(rawValue: kUTTypeXPCService as String) - static let framework = UTI(rawValue: kUTTypeFramework as String) - static let application = UTI(rawValue: kUTTypeApplication as String) - static let applicationBundle = UTI(rawValue: kUTTypeApplicationBundle as String) - static let applicationFile = UTI(rawValue: kUTTypeApplicationFile as String) - static let unixExecutable = UTI(rawValue: kUTTypeUnixExecutable as String) - static let windowsExecutable = UTI(rawValue: kUTTypeWindowsExecutable as String) - static let javaClass = UTI(rawValue: kUTTypeJavaClass as String) - static let javaArchive = UTI(rawValue: kUTTypeJavaArchive as String) - static let systemPreferencesPane = UTI(rawValue: kUTTypeSystemPreferencesPane as String) - static let gnuZipArchive = UTI(rawValue: kUTTypeGNUZipArchive as String) - static let bzip2Archive = UTI(rawValue: kUTTypeBzip2Archive as String) - static let zipArchive = UTI(rawValue: kUTTypeZipArchive as String) - static let spreadsheet = UTI(rawValue: kUTTypeSpreadsheet as String) - static let presentation = UTI(rawValue: kUTTypePresentation as String) - static let database = UTI(rawValue: kUTTypeDatabase as String) - static let vCard = UTI(rawValue: kUTTypeVCard as String) - static let toDoItem = UTI(rawValue: kUTTypeToDoItem as String) - static let calendarEvent = UTI(rawValue: kUTTypeCalendarEvent as String) - static let emailMessage = UTI(rawValue: kUTTypeEmailMessage as String) - static let internetLocation = UTI(rawValue: kUTTypeInternetLocation as String) - static let inkText = UTI(rawValue: kUTTypeInkText as String) - static let font = UTI(rawValue: kUTTypeFont as String) - static let bookmark = UTI(rawValue: kUTTypeBookmark as String) - static let _3DContent = UTI(rawValue: kUTType3DContent as String) - static let pkcs12 = UTI(rawValue: kUTTypePKCS12 as String) - static let x509Certificate = UTI(rawValue: kUTTypeX509Certificate as String) - static let electronicPublication = UTI(rawValue: kUTTypeElectronicPublication as String) - static let log = UTI(rawValue: kUTTypeLog as String) + static let audiovisualContent = UTI(rawValue: kUTTypeAudiovisualContent as String) + static let movie = UTI(rawValue: kUTTypeMovie as String) + static let video = UTI(rawValue: kUTTypeVideo as String) + static let audio = UTI(rawValue: kUTTypeAudio as String) + static let quickTimeMovie = UTI(rawValue: kUTTypeQuickTimeMovie as String) + static let mpeg = UTI(rawValue: kUTTypeMPEG as String) + static let mpeg2Video = UTI(rawValue: kUTTypeMPEG2Video as String) + static let mpeg2TransportStream = UTI(rawValue: kUTTypeMPEG2TransportStream as String) + static let mp3 = UTI(rawValue: kUTTypeMP3 as String) + static let mpeg4 = UTI(rawValue: kUTTypeMPEG4 as String) + static let mpeg4Audio = UTI(rawValue: kUTTypeMPEG4Audio as String) + static let appleProtectedMPEG4Audio = UTI(rawValue: kUTTypeAppleProtectedMPEG4Audio as String) + static let appleProtectedMPEG4Video = UTI(rawValue: kUTTypeAppleProtectedMPEG4Video as String) + static let aviMovie = UTI(rawValue: kUTTypeAVIMovie as String) + static let audioInterchangeFileFormat = UTI(rawValue: kUTTypeAudioInterchangeFileFormat as String) + static let waveformAudio = UTI(rawValue: kUTTypeWaveformAudio as String) + static let midiAudio = UTI(rawValue: kUTTypeMIDIAudio as String) + static let playlist = UTI(rawValue: kUTTypePlaylist as String) + static let m3UPlaylist = UTI(rawValue: kUTTypeM3UPlaylist as String) + static let folder = UTI(rawValue: kUTTypeFolder as String) + static let volume = UTI(rawValue: kUTTypeVolume as String) + static let package = UTI(rawValue: kUTTypePackage as String) + static let bundle = UTI(rawValue: kUTTypeBundle as String) + static let pluginBundle = UTI(rawValue: kUTTypePluginBundle as String) + static let spotlightImporter = UTI(rawValue: kUTTypeSpotlightImporter as String) + static let quickLookGenerator = UTI(rawValue: kUTTypeQuickLookGenerator as String) + static let xpcService = UTI(rawValue: kUTTypeXPCService as String) + static let framework = UTI(rawValue: kUTTypeFramework as String) + static let application = UTI(rawValue: kUTTypeApplication as String) + static let applicationBundle = UTI(rawValue: kUTTypeApplicationBundle as String) + static let applicationFile = UTI(rawValue: kUTTypeApplicationFile as String) + static let unixExecutable = UTI(rawValue: kUTTypeUnixExecutable as String) + static let windowsExecutable = UTI(rawValue: kUTTypeWindowsExecutable as String) + static let javaClass = UTI(rawValue: kUTTypeJavaClass as String) + static let javaArchive = UTI(rawValue: kUTTypeJavaArchive as String) + static let systemPreferencesPane = UTI(rawValue: kUTTypeSystemPreferencesPane as String) + static let gnuZipArchive = UTI(rawValue: kUTTypeGNUZipArchive as String) + static let bzip2Archive = UTI(rawValue: kUTTypeBzip2Archive as String) + static let zipArchive = UTI(rawValue: kUTTypeZipArchive as String) + static let spreadsheet = UTI(rawValue: kUTTypeSpreadsheet as String) + static let presentation = UTI(rawValue: kUTTypePresentation as String) + static let database = UTI(rawValue: kUTTypeDatabase as String) + static let vCard = UTI(rawValue: kUTTypeVCard as String) + static let toDoItem = UTI(rawValue: kUTTypeToDoItem as String) + static let calendarEvent = UTI(rawValue: kUTTypeCalendarEvent as String) + static let emailMessage = UTI(rawValue: kUTTypeEmailMessage as String) + static let internetLocation = UTI(rawValue: kUTTypeInternetLocation as String) + static let inkText = UTI(rawValue: kUTTypeInkText as String) + static let font = UTI(rawValue: kUTTypeFont as String) + static let bookmark = UTI(rawValue: kUTTypeBookmark as String) + static let _3DContent = UTI(rawValue: kUTType3DContent as String) + static let pkcs12 = UTI(rawValue: kUTTypePKCS12 as String) + static let x509Certificate = UTI(rawValue: kUTTypeX509Certificate as String) + static let electronicPublication = UTI(rawValue: kUTTypeElectronicPublication as String) + static let log = UTI(rawValue: kUTTypeLog as String) } #if os(OSX) diff --git a/Riot/Modules/MatrixKit/MatrixKit.h b/Riot/Modules/MatrixKit/MatrixKit.h index b6e5806f4..d9cf57cf0 100644 --- a/Riot/Modules/MatrixKit/MatrixKit.h +++ b/Riot/Modules/MatrixKit/MatrixKit.h @@ -69,7 +69,6 @@ #import "MXKRoomCreationView.h" #import "MXKRoomInputToolbarView.h" -#import "MXKRoomInputToolbarViewWithHPGrowingText.h" #import "MXKRoomDataSourceManager.h" diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m index cd5f5d784..f3a00e1db 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccount.m @@ -75,10 +75,7 @@ static NSArray *initialSyncSilentErrorsHTTPStatusCodes; // Internal list of ignored rooms NSMutableArray* ignoredRooms; - - // If a server sync is in progress, the pause is delayed at the end of sync (except if resume is called). - BOOL isPauseRequested; - + // Background sync management MXOnBackgroundSyncDone backgroundSyncDone; MXOnBackgroundSyncFail backgroundSyncFails; @@ -91,7 +88,9 @@ static NSArray *initialSyncSilentErrorsHTTPStatusCodes; id NSCurrentLocaleDidChangeNotificationObserver; } -@property (nonatomic, strong) id backgroundTask; +/// Will be true if the session is not in a pauseable state or we requested for the session to pause but not finished yet. Will be reverted to false again after `resume` called. +@property (nonatomic, assign, getter=isPauseRequested) BOOL pauseRequested; +@property (nonatomic, strong) id pauseBackgroundTask; @property (nonatomic, strong) id backgroundSyncBgTask; @end @@ -515,6 +514,32 @@ static NSArray *initialSyncSilentErrorsHTTPStatusCodes; return _others; } +- (void)setPauseRequested:(BOOL)pauseRequested +{ + if (_pauseRequested != pauseRequested) + { + _pauseRequested = pauseRequested; + + if (_pauseRequested) + { + // Make sure the SDK finish its work before the app goes sleeping in background + id handler = [MXSDKOptions sharedInstance].backgroundModeHandler; + if (handler) + { + if (!self.pauseBackgroundTask.isRunning) + { + self.pauseBackgroundTask = [handler startBackgroundTaskWithName:@"[MXKAccount] pauseInBackgroundTask" + expirationHandler:nil]; + } + } + } + else + { + [self cancelPauseBackgroundTask]; + } + } +} + #pragma mark - Matrix user's profile - (void)setUserDisplayName:(NSString*)displayname success:(void (^)(void))success failure:(void (^)(NSError *error))failure @@ -966,38 +991,25 @@ static NSArray *initialSyncSilentErrorsHTTPStatusCodes; - (void)pauseInBackgroundTask { - // Reset internal flag - isPauseRequested = NO; - - if (mxSession && mxSession.isPauseable) + if (mxSession == nil) + { + // no session to pause + return; + } + + // mark that we want to pause when possible + self.pauseRequested = YES; + + if (mxSession.isPauseable) { - id handler = [MXSDKOptions sharedInstance].backgroundModeHandler; - if (handler) - { - if (!self.backgroundTask.isRunning) - { - self.backgroundTask = [handler startBackgroundTaskWithName:@"[MXKAccount] pauseInBackgroundTask" expirationHandler:nil]; - } - } - // Pause SDK [mxSession pause]; // Update user presence - __weak typeof(self) weakSelf = self; + MXWeakify(self); [self setUserPresence:MXPresenceUnavailable andStatusMessage:nil completion:^{ - - if (weakSelf) - { - typeof(self) self = weakSelf; - - if (self.backgroundTask.isRunning) - { - [self.backgroundTask stop]; - self.backgroundTask = nil; - } - } - + MXStrongifyAndReturnIfNil(self); + [self cancelPauseBackgroundTask]; }]; } else @@ -1007,65 +1019,61 @@ static NSArray *initialSyncSilentErrorsHTTPStatusCodes; reachabilityObserver = nil; [initialServerSyncTimer invalidate]; initialServerSyncTimer = nil; - - if (mxSession.state == MXSessionStateSyncInProgress || mxSession.state == MXSessionStateInitialised || mxSession.state == MXSessionStateStoreDataReady) - { - // Make sure the SDK finish its work before the app goes sleeping in background - id handler = [MXSDKOptions sharedInstance].backgroundModeHandler; - if (handler) - { - if (!self.backgroundTask.isRunning) - { - self.backgroundTask = [handler startBackgroundTaskWithName:@"[MXKAccount] pauseInBackgroundTask" expirationHandler:nil]; - } - } - - MXLogDebug(@"[MXKAccount] Pause is delayed at the end of sync (current state %tu)", mxSession.state); - isPauseRequested = YES; - } + + MXLogDebug(@"[MXKAccount] Pause is delayed due to the session state: %@", [MXTools readableSessionState: mxSession.state]); } } - (void)resume { - isPauseRequested = NO; - - if (mxSession) + if (mxSession == nil) { - MXLogVerbose(@"[MXKAccount] resume with session state: %tu", mxSession.state); - - [self cancelBackgroundSync]; - - if (mxSession.state == MXSessionStatePaused || mxSession.state == MXSessionStatePauseRequested) + // no session to resume + return; + } + + // mark that we don't want to pause anymore + self.pauseRequested = NO; + + MXLogVerbose(@"[MXKAccount] resume: with session state: %@", [MXTools readableSessionState:mxSession.state]); + + [self cancelBackgroundSync]; + + switch (mxSession.state) + { + case MXSessionStatePaused: + case MXSessionStatePauseRequested: { // Resume SDK and update user presence [mxSession resume:^{ [self setUserPresence:MXPresenceOnline andStatusMessage:nil completion:nil]; - + [self refreshAPNSPusher]; [self refreshPushKitPusher]; }]; + + break; } - else if (mxSession.state == MXSessionStateStoreDataReady || mxSession.state == MXSessionStateInitialSyncFailed) + case MXSessionStateStoreDataReady: + case MXSessionStateInitialSyncFailed: { // The session initialisation was uncompleted, we try to complete it here. [self launchInitialServerSync]; - + [self refreshAPNSPusher]; [self refreshPushKitPusher]; + + break; } - else if (mxSession.state == MXSessionStateSyncInProgress) + case MXSessionStateSyncInProgress: { [self refreshAPNSPusher]; [self refreshPushKitPusher]; + + break; } - - // Cancel background task - if (self.backgroundTask.isRunning) - { - [self.backgroundTask stop]; - self.backgroundTask = nil; - } + default: + break; } } @@ -1616,16 +1624,16 @@ static NSArray *initialSyncSilentErrorsHTTPStatusCodes; - (void)onMatrixSessionStateChange { + // Check if pause has been requested + if (self.isPauseRequested && mxSession.isPauseable) + { + MXLogDebug(@"[MXKAccount] Apply the pending pause."); + [self pauseInBackgroundTask]; + return; + } + if (mxSession.state == MXSessionStateRunning) { - // Check if pause has been requested - if (isPauseRequested) - { - MXLogDebug(@"[MXKAccount] Apply the pending pause."); - [self pauseInBackgroundTask]; - return; - } - // Check whether the session was not already running if (!userUpdateListener) { @@ -1662,7 +1670,7 @@ static NSArray *initialSyncSilentErrorsHTTPStatusCodes; } else if (mxSession.state == MXSessionStatePaused) { - isPauseRequested = NO; + self.pauseRequested = NO; } } @@ -1754,6 +1762,7 @@ static NSArray *initialSyncSilentErrorsHTTPStatusCodes; dispatch_group_leave(dispatchGroup); } failure:^(NSError *error) { + MXLogError(@"[MXKAccount] onDateTimeFormatUpdate: event fetch failed: %@", error); dispatch_group_leave(dispatchGroup); }]; } @@ -1774,6 +1783,16 @@ static NSArray *initialSyncSilentErrorsHTTPStatusCodes; } } +- (void)cancelPauseBackgroundTask +{ + // Cancel background task + if (self.pauseBackgroundTask.isRunning) + { + [self.pauseBackgroundTask stop]; + self.pauseBackgroundTask = nil; + } +} + #pragma mark - Crypto - (void)resetDeviceId { @@ -1890,7 +1909,7 @@ static NSArray *initialSyncSilentErrorsHTTPStatusCodes; } else { - MXLogDebug(@"[MXKAccount] cannot start background Sync (invalid state %tu)", mxSession.state); + MXLogDebug(@"[MXKAccount] cannot start background Sync (invalid state %@)", [MXTools readableSessionState:mxSession.state]); failure([NSError errorWithDomain:kMXKAccountErrorDomain code:0 userInfo:nil]); } } diff --git a/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m b/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m index 9c37c1696..352e0ad6e 100644 --- a/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m +++ b/Riot/Modules/MatrixKit/Models/Account/MXKAccountManager.m @@ -104,6 +104,8 @@ NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDa } } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" - (void)saveAccounts { NSDate *startDate = [NSDate date]; @@ -123,6 +125,7 @@ NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDa MXLogDebug(@"[MXKAccountManager] saveAccounts. Done (result: %@) in %.0fms", @(result), [[NSDate date] timeIntervalSinceDate:startDate] * 1000); } +#pragma clang diagnostic pop - (void)addAccount:(MXKAccount *)account andOpenSession:(BOOL)openSession { @@ -608,6 +611,8 @@ NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDa return [matrixKitCacheFolder stringByAppendingPathComponent:kMXKAccountsKey]; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" - (void)loadAccounts { MXLogDebug(@"[MXKAccountManager] loadAccounts"); @@ -675,6 +680,7 @@ NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDa mxAccounts = [NSMutableArray array]; } } +#pragma clang diagnostic pop - (NSData*)encryptData:(NSData*)data { @@ -708,6 +714,8 @@ NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDa return data; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" - (void)migrateAccounts { NSString *pathOld = [[MXKAppSettings cacheFolder] stringByAppendingPathComponent:kMXKAccountsKeyOld]; @@ -727,6 +735,7 @@ NSString *const MXKAccountManagerDataType = @"org.matrix.kit.MXKAccountManagerDa [fileManager removeItemAtPath:pathOld error:nil]; } } +#pragma clang diagnostic pop - (void)readAndWriteCredentials:(void (^)(NSArray * _Nullable readData, void (^completion)(BOOL didUpdateCredentials)))readAnWriteHandler { diff --git a/Riot/Modules/MatrixKit/Models/Contact/MXKContact.h b/Riot/Modules/MatrixKit/Models/Contact/MXKContact.h index 3d8e8af24..a927577e9 100644 --- a/Riot/Modules/MatrixKit/Models/Contact/MXKContact.h +++ b/Riot/Modules/MatrixKit/Models/Contact/MXKContact.h @@ -93,6 +93,8 @@ extern NSString *const kMXKContactDefaultContactPrefixId; */ - (void)resetMatrixThumbnail; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" /** The contact ID from native phonebook record */ @@ -105,6 +107,7 @@ extern NSString *const kMXKContactDefaultContactPrefixId; @return MXKContact instance */ - (id)initLocalContactWithABRecord:(ABRecordRef)record; +#pragma clang diagnostic pop /** Create a matrix contact with the dedicated info diff --git a/Riot/Modules/MatrixKit/Models/Contact/MXKContact.m b/Riot/Modules/MatrixKit/Models/Contact/MXKContact.m index 2b1e57727..f949b3a9b 100644 --- a/Riot/Modules/MatrixKit/Models/Contact/MXKContact.m +++ b/Riot/Modules/MatrixKit/Models/Contact/MXKContact.m @@ -40,6 +40,8 @@ NSString *const kMXKContactDefaultContactPrefixId = @"Default_"; @implementation MXKContact @synthesize isMatrixContact, isThirdPartyInvite; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + (NSString*)contactID:(ABRecordRef)record { return [NSString stringWithFormat:@"%@%d", kMXKContactLocalContactPrefixId, ABRecordGetRecordID(record)]; @@ -217,6 +219,7 @@ NSString *const kMXKContactDefaultContactPrefixId = @"Default_"; } return self; } +#pragma clang diagnostic pop - (id)initMatrixContactWithDisplayName:(NSString*)displayName andMatrixID:(NSString*)matrixID { diff --git a/Riot/Modules/MatrixKit/Models/Contact/MXKContactManager.m b/Riot/Modules/MatrixKit/Models/Contact/MXKContactManager.m index 52ac60a68..3226deef8 100644 --- a/Riot/Modules/MatrixKit/Models/Contact/MXKContactManager.m +++ b/Riot/Modules/MatrixKit/Models/Contact/MXKContactManager.m @@ -537,6 +537,8 @@ NSString *const MXKContactManagerDataType = @"org.matrix.kit.MXKContactManagerDa } } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" - (void)refreshLocalContacts { MXLogDebug(@"[MXKContactManager] refreshLocalContacts : Started"); @@ -721,6 +723,7 @@ NSString *const MXKContactManagerDataType = @"org.matrix.kit.MXKContactManagerDa }); } } +#pragma clang diagnostic pop - (void)updateMatrixIDsForLocalContact:(MXKContact *)contact { @@ -1582,6 +1585,9 @@ static NSString *matrixIDsDictFile = @"matrixIDsDictV2"; static NSString *localContactsFile = @"localContactsV2"; static NSString *contactsBookInfoFile = @"contactsV2"; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + - (NSString*)dataFilePathForComponent:(NSString*)component { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); @@ -1857,6 +1863,8 @@ static NSString *contactsBookInfoFile = @"contactsV2"; } } +#pragma clang diagnostic pop + - (BOOL)encryptAndSaveData:(NSData*)data toFile:(NSString*)fileName { NSError *error = nil; @@ -1865,6 +1873,10 @@ static NSString *contactsBookInfoFile = @"contactsV2"; if (error == nil) { [cipher writeToFile:[self dataFilePathForComponent:fileName] atomically:YES]; + [[NSFileManager defaultManager] excludeItemFromBackupAt:[NSURL fileURLWithPath:fileName] error:&error]; + if (error) { + MXLogDebug(@"[MXKContactManager] Cannot exclude item from backup %@", error.localizedDescription); + } } else { diff --git a/Riot/Modules/MatrixKit/Models/MXK3PID.m b/Riot/Modules/MatrixKit/Models/MXK3PID.m index 5c4657cfa..0ccf5c702 100644 --- a/Riot/Modules/MatrixKit/Models/MXK3PID.m +++ b/Riot/Modules/MatrixKit/Models/MXK3PID.m @@ -29,6 +29,10 @@ @property (nonatomic) NSString *sid; @property (nonatomic) MXIdentityService *identityService; @property (nonatomic) NSString *submitUrl; +/** + HTTP client dedicated to sending MSISDN token to custom URLs. + */ +@property (nonatomic, strong) MXHTTPClient *msisdnSubmissionHttpClient; @end @@ -255,14 +259,23 @@ @"token": token }; - MXHTTPClient *httpClient = [[MXHTTPClient alloc] initWithBaseURL:nil andOnUnrecognizedCertificateBlock:nil]; - return [httpClient requestWithMethod:@"POST" - path:url - parameters:parameters - success:^(NSDictionary *JSONResponse) { - success(); - } - failure:failure]; + self.msisdnSubmissionHttpClient = [[MXHTTPClient alloc] initWithBaseURL:nil andOnUnrecognizedCertificateBlock:nil]; + + MXWeakify(self); + return [self.msisdnSubmissionHttpClient requestWithMethod:@"POST" + path:url + parameters:parameters + success:^(NSDictionary *JSONResponse) { + success(); + MXStrongifyAndReturnIfNil(self); + self.msisdnSubmissionHttpClient = nil; + } + failure:^(NSError *error) { + failure(error); + MXStrongifyAndReturnIfNil(self); + self.msisdnSubmissionHttpClient = nil; + }]; + } - (void)add3PIDToUser:(BOOL)bind diff --git a/Riot/Modules/MatrixKit/Models/MXKAppSettings.m b/Riot/Modules/MatrixKit/Models/MXKAppSettings.m index 88aa527f7..b31fc0658 100644 --- a/Riot/Modules/MatrixKit/Models/MXKAppSettings.m +++ b/Riot/Modules/MatrixKit/Models/MXKAppSettings.m @@ -19,6 +19,7 @@ #import "MXKAppSettings.h" #import "MXKTools.h" +@import MatrixSDK; // get ISO country name @@ -66,11 +67,10 @@ static NSString *const kMXAppGroupID = @"group.org.matrix"; { NSString *cacheFolder; - // Check for a potential application group id - NSString *applicationGroupIdentifier = [MXSDKOptions sharedInstance].applicationGroupIdentifier; - if (applicationGroupIdentifier) + // Check for a potential application group container + NSURL *sharedContainerURL = [[NSFileManager defaultManager] applicationGroupContainerURL]; + if (sharedContainerURL) { - NSURL *sharedContainerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:applicationGroupIdentifier]; cacheFolder = [sharedContainerURL path]; } else @@ -86,7 +86,7 @@ static NSString *const kMXAppGroupID = @"group.org.matrix"; if (cacheFolder && ![[NSFileManager defaultManager] fileExistsAtPath:cacheFolder]) { NSError *error; - [[NSFileManager defaultManager] createDirectoryAtPath:cacheFolder withIntermediateDirectories:YES attributes:nil error:&error]; + [[NSFileManager defaultManager] createDirectoryExcludedFromBackupAtPath:cacheFolder error:&error]; if (error) { MXLogDebug(@"[MXKAppSettings] cacheFolder: Error: Cannot create MatrixKit folder at %@. Error: %@", cacheFolder, error); @@ -670,6 +670,8 @@ static NSString *const kMXAppGroupID = @"group.org.matrix"; } } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" - (NSString*)phonebookCountryCode { NSString* res = phonebookCountryCode; @@ -699,6 +701,7 @@ static NSString *const kMXAppGroupID = @"group.org.matrix"; return res; } +#pragma clang diagnostic pop - (void)setPhonebookCountryCode:(NSString *)stringValue { diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.h b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.h index eba99595c..275c25f7f 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.h +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.h @@ -46,6 +46,11 @@ */ NSAttributedString *attributedTextMessage; + /** + Same as attributedTextMessage but without vertical positioning vertical blank space. + */ + NSAttributedString *attributedTextMessageWithoutPositioningSpace; + /** The optional text pattern to be highlighted in the body of the message. */ diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m index dc658e680..4eefae18d 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m @@ -28,7 +28,7 @@ @implementation MXKRoomBubbleCellData @synthesize senderId, targetId, roomId, senderDisplayName, senderAvatarUrl, senderAvatarPlaceholder, targetDisplayName, targetAvatarUrl, targetAvatarPlaceholder, isEncryptedRoom, isPaginationFirstBubble, shouldHideSenderInformation, date, isIncoming, isAttachmentWithThumbnail, isAttachmentWithIcon, attachment, senderFlair; -@synthesize textMessage, attributedTextMessage; +@synthesize textMessage, attributedTextMessage, attributedTextMessageWithoutPositioningSpace; @synthesize shouldHideSenderName, isTyping, showBubbleDateTime, showBubbleReceipts, useCustomDateTimeLabel, useCustomReceipts, useCustomUnsentButton, hasNoDisplay; @synthesize tag; @synthesize collapsable, collapsed, collapsedAttributedTextMessage, prevCollapsableCellData, nextCollapsableCellData, collapseState; diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellDataStoring.h b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellDataStoring.h index 9f227b79a..5ec4b9cb7 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellDataStoring.h +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellDataStoring.h @@ -163,6 +163,10 @@ */ @property (nonatomic) NSAttributedString *attributedTextMessage; +/** + Same as attributedTextMessage but without vertical positioning blank space + */ +@property (nonatomic) NSAttributedString *attributedTextMessageWithoutPositioningSpace; /** The raw text message (without attributes) */ diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.h b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.h index b778785e6..6ec53437e 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.h +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.h @@ -19,7 +19,7 @@ #import "MXKEventFormatter.h" #import "MXKURLPreviewDataProtocol.h" -@class MXThread; +@protocol MXThreadProtocol; /** Flags to indicate if a fix is required at the display time. @@ -108,7 +108,7 @@ typedef enum : NSUInteger { /** Thread for the bubble component. Should only exist for thread root events. */ -@property (nonatomic, readonly) MXThread *thread; +@property (nonatomic, readonly) id thread; /** Create a new `MXKRoomBubbleComponent` object based on a `MXEvent` instance. diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.m index 9a244040e..25560044b 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.m @@ -22,7 +22,7 @@ @interface MXKRoomBubbleComponent () -@property (nonatomic, readwrite) MXThread *thread; +@property (nonatomic, readwrite) id thread; @end @@ -69,8 +69,17 @@ _showEncryptionBadge = [self shouldShowWarningBadgeForEvent:event roomState:(MXRoomState*)roomState session:session]; [self updateLinkWithRoomState:roomState]; - - self.thread = [session.threadingService threadWithId:event.eventId]; + + if (event.unsignedData.relations.thread) + { + self.thread = [[MXThreadModel alloc] initWithRootEvent:event + notificationCount:0 + highlightCount:0]; + } + else + { + self.thread = [session.threadingService threadWithId:event.eventId]; + } } return self; } diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m index 88bd02a44..099d358d2 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomDataSource.m @@ -1448,6 +1448,16 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) { return NO; } } + + if (!USE_THREAD_TIMELINE && direction == MXTimelineDirectionBackwards && self.threadId) + { + // when not using a thread timeline, data source will desperately fill the screen with events by filtering them locally. + // we can stop when we see the thread root event when paginating backwards + if ([event.eventId isEqualToString:self.threadId]) + { + self.shouldStopBackPagination = YES; + } + } return YES; } diff --git a/Riot/Modules/MatrixKit/Models/RoomList/MXKInterleavedRecentsDataSource.m b/Riot/Modules/MatrixKit/Models/RoomList/MXKInterleavedRecentsDataSource.m index 28bb4c6ae..b9b34b566 100644 --- a/Riot/Modules/MatrixKit/Models/RoomList/MXKInterleavedRecentsDataSource.m +++ b/Riot/Modules/MatrixKit/Models/RoomList/MXKInterleavedRecentsDataSource.m @@ -56,7 +56,7 @@ #pragma mark - Override MXKRecentsDataSource -- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame +- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView*)tableView { UIView *sectionHeader = nil; diff --git a/Riot/Modules/MatrixKit/Models/RoomList/MXKRecentsDataSource.h b/Riot/Modules/MatrixKit/Models/RoomList/MXKRecentsDataSource.h index b9de69b4a..f37147425 100644 --- a/Riot/Modules/MatrixKit/Models/RoomList/MXKRecentsDataSource.h +++ b/Riot/Modules/MatrixKit/Models/RoomList/MXKRecentsDataSource.h @@ -88,9 +88,10 @@ @param section the section index @param frame the drawing area for the header of the specified section. + @param tableView the table view @return the section header. */ -- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame; +- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView*)tableView; /** Get the data for the cell at the given index path. diff --git a/Riot/Modules/MatrixKit/Models/RoomList/MXKRecentsDataSource.m b/Riot/Modules/MatrixKit/Models/RoomList/MXKRecentsDataSource.m index 0da982a1d..fa6480b85 100644 --- a/Riot/Modules/MatrixKit/Models/RoomList/MXKRecentsDataSource.m +++ b/Riot/Modules/MatrixKit/Models/RoomList/MXKRecentsDataSource.m @@ -257,7 +257,7 @@ } } -- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame +- (UIView *)viewForHeaderInSection:(NSInteger)section withFrame:(CGRect)frame inTableView:(UITableView*)tableView { UIView *sectionHeader = nil; diff --git a/Riot/Modules/MatrixKit/Models/RoomList/MXKSessionRecentsDataSource.h b/Riot/Modules/MatrixKit/Models/RoomList/MXKSessionRecentsDataSource.h index 0748f1e62..c03c4c4de 100644 --- a/Riot/Modules/MatrixKit/Models/RoomList/MXKSessionRecentsDataSource.h +++ b/Riot/Modules/MatrixKit/Models/RoomList/MXKSessionRecentsDataSource.h @@ -30,8 +30,8 @@ extern NSString *const kMXKRecentCellIdentifier; /** The recents data source based on a unique matrix session. + Deprecated: Please see MXSession.roomListDataManager */ -MXK_DEPRECATED_ATTRIBUTE_WITH_MSG("See MXSession.roomListDataManager") @interface MXKSessionRecentsDataSource : MXKDataSource { @protected diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m index 94ee3fa09..adb2b45af 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m @@ -955,7 +955,7 @@ static NSString *const kHTMLATagRegexPattern = @"([^<]*)"; } if (event.content[@"kick"]) { - displayText = [NSString stringWithFormat:@"%@\n\u2022 kick: %@", displayText, event.content[@"kick"]]; + displayText = [NSString stringWithFormat:@"%@\n\u2022 remove: %@", displayText, event.content[@"kick"]]; } if (event.content[@"redact"]) { diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MarkdownToHTMLRenderer.swift b/Riot/Modules/MatrixKit/Utils/EventFormatter/MarkdownToHTMLRenderer.swift index 820928fb2..392e900dd 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MarkdownToHTMLRenderer.swift +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MarkdownToHTMLRenderer.swift @@ -36,7 +36,17 @@ public class MarkdownToHTMLRenderer: NSObject { extension MarkdownToHTMLRenderer: MarkdownToHTMLRendererProtocol { public func renderToHTML(markdown: String) -> String? { - return try? Down(markdownString: markdown).toHTML(options) + do { + let ast = try DownASTRenderer.stringToAST(markdown, options: options) + defer { + cmark_node_free(ast) + } + ast.repairLinks() + return try DownHTMLRenderer.astToHTML(ast, options: options) + } catch { + MXLog.error("[MarkdownToHTMLRenderer] renderToHTML failed with string: \(markdown)") + return nil + } } } @@ -50,3 +60,116 @@ public class MarkdownToHTMLRendererHardBreaks: MarkdownToHTMLRenderer { } } + +// MARK: - AST-handling private extensions +private extension CMarkNode { + /// Formatting symbol associated with given note type + /// Note: this is only defined for node types that are handled in repairLinks + var formattingSymbol: String { + switch self.type { + case CMARK_NODE_EMPH: + return "_" + case CMARK_NODE_STRONG: + return "__" + default: + return "" + } + } + + /// Repairs links that were broken down by markdown formatting. + /// Should be used on the first node of libcmark's AST + /// (e.g. the object returned by DownASTRenderer.stringToAST). + func repairLinks() { + let iterator = cmark_iter_new(self) + var text = "" + var isInParagraph = false + var previousNode: CMarkNode? + var orphanNodes: [CMarkNode] = [] + var shouldUnlinkFormattingMode = false + var event: cmark_event_type? + while event != CMARK_EVENT_DONE { + event = cmark_iter_next(iterator) + + guard let node = cmark_iter_get_node(iterator) else { return } + + if node.type == CMARK_NODE_PARAGRAPH { + if event == CMARK_EVENT_ENTER { + isInParagraph = true + } else { + isInParagraph = false + text = "" + } + } + + if isInParagraph { + switch node.type { + case CMARK_NODE_SOFTBREAK, + CMARK_NODE_LINEBREAK: + text = "" + case CMARK_NODE_TEXT: + if let literal = node.literal { + text += literal + // Reset text if it ends up with a whitespace. + if text.last?.isWhitespace == true { + text = "" + } + // Only the last part could be a link conflicting with next node. + text = String(text.split(separator: " ").last ?? "") + } + case CMARK_NODE_EMPH where previousNode?.type == CMARK_NODE_TEXT, + CMARK_NODE_STRONG where previousNode?.type == CMARK_NODE_TEXT: + if event == CMARK_EVENT_ENTER { + if !text.containedUrls.isEmpty, + let childLiteral = node.pointee.first_child.literal { + // If current text is a link, the formatted text is reverted back to a + // plain text as a part of the link. + let symbol = node.formattingSymbol + let nonFormattedText = "\(symbol)\(childLiteral)\(symbol)" + let replacementTextNode = cmark_node_new(CMARK_NODE_TEXT) + cmark_node_set_literal(replacementTextNode, nonFormattedText) + cmark_node_insert_after(previousNode, replacementTextNode) + // Set child literal to empty string so we dont read it. + // This avoids having to re-create the main + // iterator in the middle of the process. + cmark_node_set_literal(node.pointee.first_child, "") + let newIterator = cmark_iter_new(node) + _ = cmark_iter_next(newIterator) + cmark_node_unlink(node) + orphanNodes.append(node) + let nextNode = cmark_iter_get_node(newIterator) + cmark_node_insert_after(previousNode, nextNode) + shouldUnlinkFormattingMode = true + } + } else { + if shouldUnlinkFormattingMode { + cmark_node_unlink(node) + orphanNodes.append(node) + shouldUnlinkFormattingMode = false + } + } + default: + break + } + } + previousNode = node + } + + // Free all nodes removed from the AST. + // This is done as a last step to avoid messing + // up with the main itertor. + for orphanNode in orphanNodes { + cmark_node_free(orphanNode) + } + } +} + +private extension String { + /// Returns array of URLs detected inside the String. + var containedUrls: [NSTextCheckingResult] { + guard let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else { + return [] + } + + return detector.matches(in: self, options: [], range: NSRange(location: 0, length: self.utf16.count)) + } +} diff --git a/Riot/Modules/MatrixKit/Utils/MXKConstants.h b/Riot/Modules/MatrixKit/Utils/MXKConstants.h index b580d234e..7a5659b8c 100644 --- a/Riot/Modules/MatrixKit/Utils/MXKConstants.h +++ b/Riot/Modules/MatrixKit/Utils/MXKConstants.h @@ -17,9 +17,6 @@ #import -#define MXK_DEPRECATED_ATTRIBUTE __attribute__((deprecated)) -#define MXK_DEPRECATED_ATTRIBUTE_WITH_MSG(msg) __attribute((deprecated((msg)))) - /** The Matrix iOS Kit version. */ diff --git a/Riot/Modules/MatrixKit/Utils/MXKDocumentPickerPresenter.swift b/Riot/Modules/MatrixKit/Utils/MXKDocumentPickerPresenter.swift index 1f9b9c89c..0ff493e30 100644 --- a/Riot/Modules/MatrixKit/Utils/MXKDocumentPickerPresenter.swift +++ b/Riot/Modules/MatrixKit/Utils/MXKDocumentPickerPresenter.swift @@ -24,7 +24,8 @@ import MobileCoreServices /// MXKDocumentPickerPresenter presents a controller that provides access to documents or destinations outside the app’s sandbox. /// Internally presents a UIDocumentPickerViewController in UIDocumentPickerMode.import. -/// Note: You must turn on the iCloud Documents capabilities in Xcode (see https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/DocumentPickerProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40014451) +/// Note: You must turn on the iCloud Documents capabilities in Xcode +/// (see https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/DocumentPickerProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40014451) @objcMembers public class MXKDocumentPickerPresenter: NSObject { diff --git a/Riot/Modules/MatrixKit/Utils/MXKTools.m b/Riot/Modules/MatrixKit/Utils/MXKTools.m index c941fbc98..7e3231324 100644 --- a/Riot/Modules/MatrixKit/Utils/MXKTools.m +++ b/Riot/Modules/MatrixKit/Utils/MXKTools.m @@ -1112,7 +1112,7 @@ manualChangeMessageForVideo:(NSString*)manualChangeMessageForVideo // Caution: We need here to escape the non-ASCII characters (like '#' in room alias) // to convert the link into a legal URL string. NSString *link = [attributedString.string substringWithRange:match.range]; - link = [link stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + link = [link stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; [*mutableAttributedString addAttribute:NSLinkAttributeName value:link range:match.range]; } }]; diff --git a/Riot/Modules/MatrixKit/Utils/MXKUTI.swift b/Riot/Modules/MatrixKit/Utils/MXKUTI.swift index 911beec65..87822cd7d 100644 --- a/Riot/Modules/MatrixKit/Utils/MXKUTI.swift +++ b/Riot/Modules/MatrixKit/Utils/MXKUTI.swift @@ -20,7 +20,7 @@ import MobileCoreServices // We do not use the SwiftUTI pod anymore // The library is embedded in MatrixKit. See Libs/SwiftUTI/README.md for more details -//import SwiftUTI +// import SwiftUTI /// MXKUTI represents a Universal Type Identifier (e.g. kUTTypePNG). /// See https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/understanding_utis/understand_utis_conc/understand_utis_conc.html#//apple_ref/doc/uid/TP40001319-CH202-SW5 for more information. @@ -134,6 +134,8 @@ extension MXKUTI { self.init(rawValue: uti as String) } + // swiftlint:disable unused_optional_binding + /// Initialize with local file URL. /// This method is currently applicable only to URLs for file system resources. /// @@ -153,6 +155,8 @@ extension MXKUTI { } } + // swiftlint:enable unused_optional_binding + public convenience init?(localFileURL: URL) { self.init(localFileURL: localFileURL, loadResourceValues: true) } @@ -173,6 +177,8 @@ extension MXKUTI { } } +// swiftlint:disable force_unwrapping + // MARK: - Some system defined UTIs extension MXKUTI { public static let data = MXKUTI(cfRawValue: kUTTypeData)! @@ -190,6 +196,8 @@ extension MXKUTI { public static let xml = MXKUTI(cfRawValue: kUTTypeXML)! } +// swiftlint:enable force_unwrapping + // MARK: - Convenience static methods extension MXKUTI { diff --git a/Riot/Modules/MatrixKit/Views/Authentication/MXKAuthenticationFallbackWebView.m b/Riot/Modules/MatrixKit/Views/Authentication/MXKAuthenticationFallbackWebView.m index 09c50ffc6..ad44e34d8 100644 --- a/Riot/Modules/MatrixKit/Views/Authentication/MXKAuthenticationFallbackWebView.m +++ b/Riot/Modules/MatrixKit/Views/Authentication/MXKAuthenticationFallbackWebView.m @@ -120,7 +120,7 @@ sendObjectMessage({ \ MXLogDebug(@"[MXKAuthenticationFallbackWebView] URL has js: prefix"); // Listen only to scheme of the JS-WKWebView bridge - NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding]; + NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByRemovingPercentEncoding]; NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; NSError *error; diff --git a/Riot/Modules/MatrixKit/Views/Authentication/MXKAuthenticationRecaptchaWebView.m b/Riot/Modules/MatrixKit/Views/Authentication/MXKAuthenticationRecaptchaWebView.m index 8e3bfa6fa..776214b30 100644 --- a/Riot/Modules/MatrixKit/Views/Authentication/MXKAuthenticationRecaptchaWebView.m +++ b/Riot/Modules/MatrixKit/Views/Authentication/MXKAuthenticationRecaptchaWebView.m @@ -102,7 +102,7 @@ var onloadCallback = function() { \ if ([urlString hasPrefix:@"js:"]) { // Listen only to scheme of the JS-WKWebView bridge - NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding]; + NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByRemovingPercentEncoding]; NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; NSError *error; diff --git a/Riot/Modules/MatrixKit/Views/EncryptionInfoView/MXKEncryptionInfoView.m b/Riot/Modules/MatrixKit/Views/EncryptionInfoView/MXKEncryptionInfoView.m index a6537cbd5..cc6c3175e 100644 --- a/Riot/Modules/MatrixKit/Views/EncryptionInfoView/MXKEncryptionInfoView.m +++ b/Riot/Modules/MatrixKit/Views/EncryptionInfoView/MXKEncryptionInfoView.m @@ -417,7 +417,7 @@ static NSAttributedString *verticalWhitespace = nil; [_mxSession.crypto setDeviceVerification:MXDeviceVerified forDevice:_mxDeviceInfo.deviceId ofUser:_mxDeviceInfo.userId success:^{ // Refresh data - _mxDeviceInfo = [self.mxSession.crypto eventDeviceInfo:self.mxEvent]; + self->_mxDeviceInfo = [self.mxSession.crypto eventDeviceInfo:self.mxEvent]; if (self->_delegate) { [self->_delegate encryptionInfoView:self didDeviceInfoVerifiedChange:self.mxDeviceInfo]; @@ -473,7 +473,7 @@ static NSAttributedString *verticalWhitespace = nil; [_mxSession.crypto setDeviceVerification:verificationStatus forDevice:_mxDeviceInfo.deviceId ofUser:_mxDeviceInfo.userId success:^{ // Refresh data - _mxDeviceInfo = [self.mxSession.crypto eventDeviceInfo:self.mxEvent]; + self->_mxDeviceInfo = [self.mxSession.crypto eventDeviceInfo:self.mxEvent]; if (self->_delegate) { diff --git a/Riot/Modules/MatrixKit/Views/MXKCellRendering.h b/Riot/Modules/MatrixKit/Views/MXKCellRendering.h index 60d712910..22ebca772 100644 --- a/Riot/Modules/MatrixKit/Views/MXKCellRendering.h +++ b/Riot/Modules/MatrixKit/Views/MXKCellRendering.h @@ -75,11 +75,9 @@ - (MXKCellData*)renderedCellData; /** - Reset the cell. + Stop processes no more needed when cell is not visible. - The cell is no more displayed. This is time to release resources and removing listeners. - In case of UITableViewCell or UIContentViewCell object, the cell must reset in a state - that it can be reusable. + The cell is no more displayed but still recycled. This is time to stop animation. */ - (void)didEndDisplay; diff --git a/Riot/Modules/MatrixKit/Views/RoomInputToolbar/MXKRoomInputToolbarViewWithHPGrowingText.h b/Riot/Modules/MatrixKit/Views/RoomInputToolbar/MXKRoomInputToolbarViewWithHPGrowingText.h deleted file mode 100644 index b10b54fa6..000000000 --- a/Riot/Modules/MatrixKit/Views/RoomInputToolbar/MXKRoomInputToolbarViewWithHPGrowingText.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright 2015 OpenMarket Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#import "MXKRoomInputToolbarView.h" - -#import - -/** - `MXKRoomInputToolbarViewWithHPGrowingText` is a MXKRoomInputToolbarView-inherited class in which message - composer is based on `HPGrowingTextView`. - - Toolbar buttons are not overridden by this class. We keep the default implementation. - */ -@interface MXKRoomInputToolbarViewWithHPGrowingText : MXKRoomInputToolbarView -{ -@protected - HPGrowingTextView *growingTextView; -} - -@end diff --git a/Riot/Modules/MatrixKit/Views/RoomInputToolbar/MXKRoomInputToolbarViewWithHPGrowingText.m b/Riot/Modules/MatrixKit/Views/RoomInputToolbar/MXKRoomInputToolbarViewWithHPGrowingText.m deleted file mode 100644 index fe5f87ff7..000000000 --- a/Riot/Modules/MatrixKit/Views/RoomInputToolbar/MXKRoomInputToolbarViewWithHPGrowingText.m +++ /dev/null @@ -1,187 +0,0 @@ -/* - Copyright 2015 OpenMarket Ltd - Copyright 2017 Vector Creations Ltd - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -#import "MXKRoomInputToolbarViewWithHPGrowingText.h" - -@interface MXKRoomInputToolbarViewWithHPGrowingText() -{ - // HPGrowingTextView triggers growingTextViewDidChange event when it recomposes itself - // Save the last edited text to prevent unexpected typing events - NSString* lastEditedText; -} - -/** - Message composer defined in `messageComposerContainer`. - */ -@property (nonatomic) IBOutlet HPGrowingTextView *growingTextView; - -@end - -@implementation MXKRoomInputToolbarViewWithHPGrowingText -@synthesize growingTextView; - -+ (UINib *)nib -{ - return [UINib nibWithNibName:NSStringFromClass([MXKRoomInputToolbarViewWithHPGrowingText class]) - bundle:[NSBundle bundleForClass:[MXKRoomInputToolbarViewWithHPGrowingText class]]]; -} - -- (void)awakeFromNib -{ - [super awakeFromNib]; - - // Handle message composer based on HPGrowingTextView use - growingTextView.delegate = self; - - [growingTextView setTranslatesAutoresizingMaskIntoConstraints: NO]; - - // Add an accessory view to the text view in order to retrieve keyboard view. - inputAccessoryView = [[UIView alloc] initWithFrame:CGRectZero]; - growingTextView.internalTextView.inputAccessoryView = self.inputAccessoryView; - - // on IOS 8, the growing textview animation could trigger weird UI animations - // indeed, the messages tableView can be refreshed while its height is updated (e.g. when setting a message) - growingTextView.animateHeightChange = NO; - - lastEditedText = nil; -} - -- (void)dealloc -{ - [self destroy]; -} - --(void)customizeViewRendering -{ - [super customizeViewRendering]; - - // set text input font - growingTextView.font = [UIFont systemFontOfSize:14]; - - // draw a rounded border around the textView - growingTextView.layer.cornerRadius = 5; - growingTextView.layer.borderWidth = 1; - growingTextView.layer.borderColor = [UIColor lightGrayColor].CGColor; - growingTextView.clipsToBounds = YES; - growingTextView.backgroundColor = [UIColor whiteColor]; -} - -- (void)destroy -{ - if (growingTextView) - { - growingTextView.delegate = nil; - growingTextView = nil; - } - - [super destroy]; -} - -- (void)setMaxHeight:(CGFloat)maxHeight -{ - growingTextView.maxHeight = maxHeight - (self.messageComposerContainerTopConstraint.constant + self.messageComposerContainerBottomConstraint.constant); - [growingTextView refreshHeight]; - - super.maxHeight = maxHeight; -} - -- (NSString*)textMessage -{ - return growingTextView.text; -} - -- (void)setTextMessage:(NSString *)textMessage -{ - growingTextView.text = textMessage; - self.rightInputToolbarButton.enabled = textMessage.length; -} - -- (void)pasteText:(NSString *)text -{ - self.textMessage = [growingTextView.text stringByReplacingCharactersInRange:growingTextView.selectedRange withString:text]; -} - -- (void)setPlaceholder:(NSString *)inPlaceholder -{ - [super setPlaceholder:inPlaceholder]; - growingTextView.placeholder = inPlaceholder; -} - -- (BOOL)becomeFirstResponder -{ - return [growingTextView becomeFirstResponder]; -} - -- (void)dismissKeyboard -{ - [growingTextView resignFirstResponder]; -} - -#pragma mark - HPGrowingTextView delegate - -- (void)growingTextViewDidEndEditing:(HPGrowingTextView *)sender -{ - if ([self.delegate respondsToSelector:@selector(roomInputToolbarView:isTyping:)]) - { - [self.delegate roomInputToolbarView:self isTyping:NO]; - } -} - -- (void)growingTextViewDidChange:(HPGrowingTextView *)sender -{ - NSString *msg = growingTextView.text; - - // HPGrowingTextView triggers growingTextViewDidChange event when it recomposes itself. - // Save the last edited text to prevent unexpected typing events - if (![lastEditedText isEqualToString:msg]) - { - lastEditedText = msg; - if (msg.length) - { - if ([self.delegate respondsToSelector:@selector(roomInputToolbarView:isTyping:)]) - { - [self.delegate roomInputToolbarView:self isTyping:YES]; - } - self.rightInputToolbarButton.enabled = YES; - } - else - { - if ([self.delegate respondsToSelector:@selector(roomInputToolbarView:isTyping:)]) - { - [self.delegate roomInputToolbarView:self isTyping:NO]; - } - self.rightInputToolbarButton.enabled = NO; - } - } -} - -- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height -{ - // Update growing text's superview (toolbar view) - CGFloat updatedHeight = height + (self.messageComposerContainerTopConstraint.constant + self.messageComposerContainerBottomConstraint.constant); - if ([self.delegate respondsToSelector:@selector(roomInputToolbarView:heightDidChanged:completion:)]) - { - [self.delegate roomInputToolbarView:self heightDidChanged:updatedHeight completion:nil]; - } -} - -- (BOOL)growingTextView:(HPGrowingTextView *)growingTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text -{ - return self.isEditable; -} - -@end diff --git a/Riot/Modules/MatrixKit/Views/RoomInputToolbar/MXKRoomInputToolbarViewWithHPGrowingText.xib b/Riot/Modules/MatrixKit/Views/RoomInputToolbar/MXKRoomInputToolbarViewWithHPGrowingText.xib deleted file mode 100644 index 3f4117499..000000000 --- a/Riot/Modules/MatrixKit/Views/RoomInputToolbar/MXKRoomInputToolbarViewWithHPGrowingText.xib +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Riot/Modules/MediaPicker/Library/MediaAlbumContentViewController.m b/Riot/Modules/MediaPicker/Library/MediaAlbumContentViewController.m index c01c845e6..440aeb027 100644 --- a/Riot/Modules/MediaPicker/Library/MediaAlbumContentViewController.m +++ b/Riot/Modules/MediaPicker/Library/MediaAlbumContentViewController.m @@ -268,10 +268,10 @@ }]; - cell.bottomLeftIcon.image = [UIImage imageNamed:@"video_icon"]; + cell.bottomLeftIcon.image = AssetImages.videoIcon.image; cell.bottomLeftIcon.hidden = (asset.mediaType == PHAssetMediaTypeImage); - cell.bottomRightIcon.image = [UIImage imageNamed:@"selection_tick"]; + cell.bottomRightIcon.image = AssetImages.selectionTick.image; cell.bottomRightIcon.tintColor = ThemeService.shared.theme.tintColor; cell.bottomRightIcon.hidden = !selectedAssets || (NSNotFound == [selectedAssets indexOfObject:asset]); diff --git a/Riot/Modules/MediaPicker/MediaPickerViewController.m b/Riot/Modules/MediaPicker/MediaPickerViewController.m index 48ff40d19..8905b926b 100644 --- a/Riot/Modules/MediaPicker/MediaPickerViewController.m +++ b/Riot/Modules/MediaPicker/MediaPickerViewController.m @@ -729,8 +729,8 @@ videoPlayerControl = [UIButton buttonWithType:UIButtonTypeCustom]; [videoPlayerControl addTarget:self action:@selector(controlVideoPlayer) forControlEvents:UIControlEventTouchUpInside]; videoPlayerControl.frame = CGRectMake(0, 0, 44, 44); - [videoPlayerControl setImage:[UIImage imageNamed:@"camera_play"] forState:UIControlStateNormal]; - [videoPlayerControl setImage:[UIImage imageNamed:@"camera_play"] forState:UIControlStateHighlighted]; + [videoPlayerControl setImage:AssetImages.cameraPlay.image forState:UIControlStateNormal]; + [videoPlayerControl setImage:AssetImages.cameraPlay.image forState:UIControlStateHighlighted]; [validationView addSubview:videoPlayerControl]; videoPlayerControl.center = validationView.imageView.center; @@ -796,8 +796,8 @@ [videoPlayer.player seekToTime:kCMTimeZero]; [videoPlayer.view removeFromSuperview]; - [videoPlayerControl setImage:[UIImage imageNamed:@"camera_play"] forState:UIControlStateNormal]; - [videoPlayerControl setImage:[UIImage imageNamed:@"camera_play"] forState:UIControlStateHighlighted]; + [videoPlayerControl setImage:AssetImages.cameraPlay.image forState:UIControlStateNormal]; + [videoPlayerControl setImage:AssetImages.cameraPlay.image forState:UIControlStateHighlighted]; } else { @@ -815,8 +815,8 @@ [videoPlayer.player play]; - [videoPlayerControl setImage:[UIImage imageNamed:@"camera_stop"] forState:UIControlStateNormal]; - [videoPlayerControl setImage:[UIImage imageNamed:@"camera_stop"] forState:UIControlStateHighlighted]; + [videoPlayerControl setImage:AssetImages.cameraStop.image forState:UIControlStateNormal]; + [videoPlayerControl setImage:AssetImages.cameraStop.image forState:UIControlStateHighlighted]; [validationView bringSubviewToFront:videoPlayerControl]; } } @@ -860,7 +860,7 @@ }]; - cell.bottomLeftIcon.image = [UIImage imageNamed:@"video_icon"]; + cell.bottomLeftIcon.image = AssetImages.videoIcon.image; cell.bottomLeftIcon.hidden = (asset.mediaType == PHAssetMediaTypeImage); // Disable user interaction in mxkImageView, in order to let collection handle user selection @@ -968,7 +968,7 @@ if (collection.assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumVideos) { - cell.bottomLeftIcon.image = [UIImage imageNamed:@"video_icon"]; + cell.bottomLeftIcon.image = AssetImages.videoIcon.image; cell.bottomLeftIcon.hidden = NO; } else diff --git a/Riot/Modules/Onboarding/OnboardingCoordinator.swift b/Riot/Modules/Onboarding/OnboardingCoordinator.swift index 8a6dcc7c4..dd7f088e7 100644 --- a/Riot/Modules/Onboarding/OnboardingCoordinator.swift +++ b/Riot/Modules/Onboarding/OnboardingCoordinator.swift @@ -54,12 +54,13 @@ final class OnboardingCoordinator: NSObject, OnboardingCoordinatorProtocol { private var navigationRouter: NavigationRouterType { parameters.router } - // Keep a strong ref as we need to init authVC early to preload its view (it is *really* slow to do in realtime) - private var authenticationCoordinator: AuthenticationCoordinatorProtocol = AuthenticationCoordinator() + // Keep a strong ref as we need to init authVC early to preload its view + private let authenticationCoordinator: AuthenticationCoordinatorProtocol private var isShowingAuthentication = false // MARK: Screen results private var splashScreenResult: OnboardingSplashScreenViewModelResult? + private var useCaseResult: OnboardingUseCaseViewModelResult? // MARK: Public @@ -71,6 +72,11 @@ final class OnboardingCoordinator: NSObject, OnboardingCoordinatorProtocol { init(parameters: OnboardingCoordinatorParameters) { self.parameters = parameters + + // Preload the authVC (it is *really* slow to load in realtime) + let authenticationParameters = AuthenticationCoordinatorParameters(navigationRouter: parameters.router) + authenticationCoordinator = AuthenticationCoordinator(parameters: authenticationParameters) + super.init() } @@ -126,9 +132,47 @@ final class OnboardingCoordinator: NSObject, OnboardingCoordinatorProtocol { self.navigationRouter.setRootModule(coordinator, popCompletion: nil) } + @available(iOS 14.0, *) /// Displays the next view in the flow after the splash screen. private func splashScreenCoordinator(_ coordinator: OnboardingSplashScreenCoordinator, didCompleteWith result: OnboardingSplashScreenViewModelResult) { splashScreenResult = result + + // Set the auth type early to allow network requests to finish during display of the use case screen. + let mxkAuthenticationType = splashScreenResult == .register ? MXKAuthenticationTypeRegister : MXKAuthenticationTypeLogin + authenticationCoordinator.update(authenticationType: mxkAuthenticationType) + + switch result { + case .register: + showUseCaseSelectionScreen() + case .login: + showAuthenticationScreen() + } + } + + @available(iOS 14.0, *) + /// Show the use case screen for new users. + private func showUseCaseSelectionScreen() { + let coordinator = OnboardingUseCaseSelectionCoordinator() + coordinator.completion = { [weak self, weak coordinator] result in + guard let self = self, let coordinator = coordinator else { return } + self.useCaseSelectionCoordinator(coordinator, didCompleteWith: result) + } + + coordinator.start() + add(childCoordinator: coordinator) + + if self.navigationRouter.modules.isEmpty { + self.navigationRouter.setRootModule(coordinator, popCompletion: nil) + } else { + self.navigationRouter.push(coordinator, animated: true) { [weak self] in + self?.remove(childCoordinator: coordinator) + } + } + } + + /// Displays the next view in the flow after the use case screen. + private func useCaseSelectionCoordinator(_ coordinator: OnboardingUseCaseSelectionCoordinator, didCompleteWith result: OnboardingUseCaseViewModelResult) { + useCaseResult = result showAuthenticationScreen() } @@ -139,28 +183,35 @@ final class OnboardingCoordinator: NSObject, OnboardingCoordinatorProtocol { MXLog.debug("[OnboardingCoordinator] showAuthenticationScreen") let coordinator = authenticationCoordinator - coordinator.completion = { [weak self, weak coordinator] in + coordinator.completion = { [weak self, weak coordinator] result in guard let self = self, let coordinator = coordinator else { return } - self.authenticationCoordinatorDidComplete(coordinator) + + switch result { + case .didLogin(let session): + self.authenticationCoordinator(coordinator, didLoginWith: session) + case .didComplete(let authenticationType): + self.authenticationCoordinator(coordinator, didCompleteWith: authenticationType) + } + } // Due to needing to preload the authVC, this breaks the Coordinator init/start pattern. // This can be re-assessed once we re-write a native flow for authentication. - // Set authType first as registration parameters or soft logout credentials will modify this. - let mxkAuthenticationType = splashScreenResult == .register ? MXKAuthenticationTypeRegister : MXKAuthenticationTypeLogin - coordinator.update(authenticationType: mxkAuthenticationType) - if let externalRegistrationParameters = externalRegistrationParameters { coordinator.update(externalRegistrationParameters: externalRegistrationParameters) } + + if useCaseResult == .customServer { + coordinator.showCustomServer() + } + if let softLogoutCredentials = parameters.softLogoutCredentials { coordinator.update(softLogoutCredentials: softLogoutCredentials) } coordinator.start() add(childCoordinator: coordinator) - authenticationCoordinator = coordinator if customHomeserver != nil || customIdentityServer != nil { coordinator.updateHomeserver(customHomeserver, andIdentityServer: customIdentityServer) @@ -177,9 +228,43 @@ final class OnboardingCoordinator: NSObject, OnboardingCoordinatorProtocol { isShowingAuthentication = true } + private func authenticationCoordinator(_ coordinator: AuthenticationCoordinatorProtocol, didLoginWith session: MXSession) { + // TODO: Show next screens whilst waiting for the everything to load. + // May need to move the spinner and key verification up to here in order to coordinate properly. + } + /// Displays the next view in the flow after the authentication screen. - private func authenticationCoordinatorDidComplete(_ coordinator: AuthenticationCoordinatorProtocol) { + private func authenticationCoordinator(_ coordinator: AuthenticationCoordinatorProtocol, didCompleteWith authenticationType: MXKAuthenticationType) { completion?() isShowingAuthentication = false + + // Handle the chosen use case where applicable + if authenticationType == MXKAuthenticationTypeRegister, + let useCase = useCaseResult?.userSessionPropertyValue, + let userSession = UserSessionsService.shared.mainUserSession { + // Store the value in the user's session + userSession.userProperties.useCase = useCase + + // Update the analytics user properties with the use case + Analytics.shared.updateUserProperties(ftueUseCase: useCase) + } + } +} + +extension OnboardingUseCaseViewModelResult { + /// The result converted into the type stored in the user session. + var userSessionPropertyValue: UserSessionProperties.UseCase? { + switch self { + case .personalMessaging: + return .personalMessaging + case .workMessaging: + return .workMessaging + case .communityMessaging: + return .communityMessaging + case .skipped: + return .skipped + case .customServer: + return nil + } } } diff --git a/Riot/Modules/Onboarding/OnboardingCoordinatorBridgePresenter.swift b/Riot/Modules/Onboarding/OnboardingCoordinatorBridgePresenter.swift index 9cc43c1b1..32f433936 100644 --- a/Riot/Modules/Onboarding/OnboardingCoordinatorBridgePresenter.swift +++ b/Riot/Modules/Onboarding/OnboardingCoordinatorBridgePresenter.swift @@ -28,7 +28,8 @@ class OnboardingCoordinatorBridgePresenterParameters: NSObject { /// OnboardingCoordinatorBridgePresenter enables to start OnboardingCoordinator from a view controller. /// This bridge is used while waiting for global usage of coordinator pattern. -/// **WARNING**: This class breaks the Coordinator abstraction and it has been introduced for **Objective-C compatibility only** (mainly for integration in legacy view controllers). Each bridge should be removed once the underlying Coordinator has been integrated by another Coordinator. +/// **WARNING**: This class breaks the Coordinator abstraction and it has been introduced for **Objective-C compatibility only** (mainly for integration in legacy view controllers). Each bridge should be removed +/// once the underlying Coordinator has been integrated by another Coordinator. @objcMembers final class OnboardingCoordinatorBridgePresenter: NSObject { diff --git a/Riot/Modules/People/PeopleViewController.m b/Riot/Modules/People/PeopleViewController.m index 20a704fec..05dbd6ab7 100644 --- a/Riot/Modules/People/PeopleViewController.m +++ b/Riot/Modules/People/PeopleViewController.m @@ -68,7 +68,7 @@ // This will be used by the shared RecentsDataSource instance for sanity checks (see UITableViewDataSource methods). self.recentsTableView.tag = RecentsDataSourceModePeople; - UIImage *fabImage = self.dataSource.currentSpace == nil ? [UIImage imageNamed:@"people_floating_action"] : [UIImage imageNamed:@"add_member_floating_action"]; + UIImage *fabImage = self.dataSource.currentSpace == nil ? AssetImages.peopleFloatingAction.image : AssetImages.addMemberFloatingAction.image; // Add the (+) button programmatically plusButtonImageView = [self vc_addFABWithImage:fabImage target:self @@ -178,11 +178,11 @@ { if (ThemeService.shared.isCurrentThemeDark) { - return [UIImage imageNamed:@"people_empty_screen_artwork_dark"]; + return AssetImages.peopleEmptyScreenArtworkDark.image; } else { - return [UIImage imageNamed:@"people_empty_screen_artwork"]; + return AssetImages.peopleEmptyScreenArtwork.image; } } diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.m b/Riot/Modules/Room/CellData/RoomBubbleCellData.m index c58e14554..085bc137d 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.m +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.m @@ -241,30 +241,18 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat - (NSAttributedString*)attributedTextMessage { - @synchronized(bubbleComponents) - { - if (self.hasAttributedTextMessage && !attributedTextMessage.length) - { - // Attributed text message depends on the room read receipts which must be retrieved on the main thread to prevent us from race conditions. - // Check here the current thread, this is just a sanity check because the attributed text message - // is requested during the rendering step which takes place on the main thread. - if ([NSThread currentThread] != [NSThread mainThread]) - { - MXLogDebug(@"[RoomBubbleCellData] attributedTextMessage called on wrong thread"); - dispatch_sync(dispatch_get_main_queue(), ^{ - self.attributedTextMessage = [self makeAttributedString]; - }); - } - else - { - self.attributedTextMessage = [self makeAttributedString]; - } - } - } + [self buildAttributedStringIfNeeded]; return attributedTextMessage; } +- (NSAttributedString*)attributedTextMessageWithoutPositioningSpace +{ + [self buildAttributedStringIfNeeded]; + + return attributedTextMessageWithoutPositioningSpace; +} + - (BOOL)hasNoDisplay { if (self.tag == RoomBubbleCellDataTagKeyVerificationNoDisplay) @@ -378,18 +366,25 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat [self setNeedsUpdateAdditionalContentHeight]; } -- (NSAttributedString*)makeAttributedString +- (void)buildAttributedString { // CAUTION: This method must be called on the main thread. // Return the collapsed string only for cells series header if (self.collapsed && self.collapsedAttributedTextMessage && self.nextCollapsableCellData) { - return super.collapsedAttributedTextMessage; + NSAttributedString *attributedString = super.collapsedAttributedTextMessage; + + self.attributedTextMessage = attributedString; + self.attributedTextMessageWithoutPositioningSpace = attributedString; + + return; } NSMutableAttributedString *currentAttributedTextMsg; + NSMutableAttributedString *currentAttributedTextMsgWithoutVertSpace = [NSMutableAttributedString new]; + NSInteger selectedComponentIndex = self.selectedComponentIndex; NSInteger lastMessageIndex = self.containsLastMessage ? self.mostRecentComponentIndex : NSNotFound; @@ -416,11 +411,15 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat { currentAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:[RoomBubbleCellData timestampVerticalWhitespace]]; [currentAttributedTextMsg appendAttributedString:componentString]; + + [currentAttributedTextMsgWithoutVertSpace appendAttributedString:componentString]; } else { // Init attributed string with the first text component currentAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:componentString]; + + [currentAttributedTextMsgWithoutVertSpace appendAttributedString:componentString]; } [self addVerticalWhitespaceToString:currentAttributedTextMsg forEvent:component.event.eventId]; @@ -456,10 +455,45 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat [currentAttributedTextMsg appendAttributedString:componentString]; [self addVerticalWhitespaceToString:currentAttributedTextMsg forEvent:component.event.eventId]; + + [currentAttributedTextMsgWithoutVertSpace appendAttributedString:componentString]; } } - return currentAttributedTextMsg; + // With bubbles the text is truncated with quote messages containing vertical border view + // Add horizontal space to fix the issue + if (self.displayFix & MXKRoomBubbleComponentDisplayFixHtmlBlockquote) + { + [currentAttributedTextMsgWithoutVertSpace appendString:@" "]; + } + + self.attributedTextMessage = currentAttributedTextMsg; + + self.attributedTextMessageWithoutPositioningSpace = currentAttributedTextMsgWithoutVertSpace; +} + +- (void)buildAttributedStringIfNeeded +{ + @synchronized(bubbleComponents) + { + if (self.hasAttributedTextMessage && !attributedTextMessage.length) + { + // Attributed text message depends on the room read receipts which must be retrieved on the main thread to prevent us from race conditions. + // Check here the current thread, this is just a sanity check because the attributed text message + // is requested during the rendering step which takes place on the main thread. + if ([NSThread currentThread] != [NSThread mainThread]) + { + MXLogDebug(@"[RoomBubbleCellData] attributedTextMessage called on wrong thread"); + dispatch_sync(dispatch_get_main_queue(), ^{ + [self buildAttributedString]; + }); + } + else + { + [self buildAttributedString]; + } + } + } } - (NSInteger)firstVisibleComponentIndex @@ -667,7 +701,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat // component is not a thread root return 0; } - return RoomBubbleCellLayout.threadSummaryViewTopMargin + + return PlainRoomCellLayoutConstants.threadSummaryViewTopMargin + [ThreadSummaryView contentViewHeightForThread:component.thread fitting:self.maxTextViewWidth]; } @@ -694,7 +728,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat // event is not in a thread return 0; } - return RoomBubbleCellLayout.fromAThreadViewTopMargin + + return PlainRoomCellLayoutConstants.fromAThreadViewTopMargin + [FromAThreadView contentViewHeightForEvent:component.event fitting:self.maxTextViewWidth]; } @@ -706,7 +740,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat return 0; } - return RoomBubbleCellLayout.urlPreviewViewTopMargin + [URLPreviewView contentViewHeightFor:component.urlPreviewData + return PlainRoomCellLayoutConstants.urlPreviewViewTopMargin + [URLPreviewView contentViewHeightFor:component.urlPreviewData fitting:self.maxTextViewWidth]; } @@ -731,7 +765,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat BOOL showAllReactions = [self.eventsToShowAllReactions containsObject:eventId]; BubbleReactionsViewModel *viewModel = [[BubbleReactionsViewModel alloc] initWithAggregatedReactions:aggregatedReactions eventId:eventId showAll:showAllReactions]; - height = [bubbleReactionsViewSizer heightForViewModel:viewModel fittingWidth:bubbleReactionsViewWidth] + RoomBubbleCellLayout.reactionsViewTopMargin; + height = [bubbleReactionsViewSizer heightForViewModel:viewModel fittingWidth:bubbleReactionsViewWidth] + PlainRoomCellLayoutConstants.reactionsViewTopMargin; } return height; @@ -743,7 +777,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat if (self.readReceipts[eventId].count) { - height = RoomBubbleCellLayout.readReceiptsViewHeight + RoomBubbleCellLayout.readReceiptsViewTopMargin; + height = PlainRoomCellLayoutConstants.readReceiptsViewHeight + PlainRoomCellLayoutConstants.readReceiptsViewTopMargin; } return height; diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.h b/Riot/Modules/Room/DataSources/RoomDataSource.h index 76d55375e..1ce04fc08 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.h +++ b/Riot/Modules/Room/DataSources/RoomDataSource.h @@ -130,6 +130,6 @@ @param roomDataSource room data source instance */ - (void)roomDataSource:(RoomDataSource * _Nonnull)roomDataSource - didTapThread:(MXThread * _Nonnull)thread; + didTapThread:(id _Nonnull)thread; @end diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m index 721d40b8f..2341e692a 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.m +++ b/Riot/Modules/Room/DataSources/RoomDataSource.m @@ -466,7 +466,8 @@ const CGFloat kTypingCellHeight = 24; // display thread summary view if the component has a thread in the room timeline if (RiotSettings.shared.enableThreads && component.thread && !self.threadId) { - threadSummaryView = [[ThreadSummaryView alloc] initWithThread:component.thread]; + threadSummaryView = [[ThreadSummaryView alloc] initWithThread:component.thread + session:self.mxSession]; threadSummaryView.delegate = self; threadSummaryView.tag = index; @@ -512,7 +513,7 @@ const CGFloat kTypingCellHeight = 24; if (roomMembers.count) { // Define the read receipts container, positioned on the right border of the bubble cell (Note the right margin 6 pts). - avatarsContainer = [[MXKReceiptSendersContainer alloc] initWithFrame:CGRectMake(bubbleCell.frame.size.width - RoomBubbleCellLayout.readReceiptsViewWidth + RoomBubbleCellLayout.readReceiptsViewRightMargin, bottomPositionY + RoomBubbleCellLayout.readReceiptsViewTopMargin, RoomBubbleCellLayout.readReceiptsViewWidth, RoomBubbleCellLayout.readReceiptsViewHeight) andMediaManager:self.mxSession.mediaManager]; + avatarsContainer = [[MXKReceiptSendersContainer alloc] initWithFrame:CGRectMake(bubbleCell.frame.size.width - PlainRoomCellLayoutConstants.readReceiptsViewWidth + PlainRoomCellLayoutConstants.readReceiptsViewRightMargin, bottomPositionY + PlainRoomCellLayoutConstants.readReceiptsViewTopMargin, PlainRoomCellLayoutConstants.readReceiptsViewWidth, PlainRoomCellLayoutConstants.readReceiptsViewHeight) andMediaManager:self.mxSession.mediaManager]; // Custom avatar display avatarsContainer.maxDisplayedAvatars = 5; @@ -557,48 +558,17 @@ const CGFloat kTypingCellHeight = 24; if ([componentEventId isEqualToString:self.room.accountData.readMarkerEventId]) { - bubbleCell.readMarkerView = [[UIView alloc] initWithFrame:CGRectMake(0, bottomPositionY - RoomBubbleCellLayout.readMarkerViewHeight, bubbleCell.bubbleOverlayContainer.frame.size.width, RoomBubbleCellLayout.readMarkerViewHeight)]; - bubbleCell.readMarkerView.backgroundColor = ThemeService.shared.theme.tintColor; + UIView *readMarkerView = [[UIView alloc] initWithFrame:CGRectMake(0, bottomPositionY - PlainRoomCellLayoutConstants.readMarkerViewHeight, bubbleCell.bubbleOverlayContainer.frame.size.width, PlainRoomCellLayoutConstants.readMarkerViewHeight)]; + readMarkerView.backgroundColor = ThemeService.shared.theme.tintColor; // Hide by default the marker, it will be shown and animated when the cell will be rendered. - bubbleCell.readMarkerView.hidden = YES; - bubbleCell.readMarkerView.tag = index; + readMarkerView.hidden = YES; + readMarkerView.tag = index; + readMarkerView.accessibilityIdentifier = @"readMarker"; - bubbleCell.readMarkerView.translatesAutoresizingMaskIntoConstraints = NO; - bubbleCell.readMarkerView.accessibilityIdentifier = @"readMarker"; - [bubbleCell.bubbleOverlayContainer addSubview:bubbleCell.readMarkerView]; - - // Force read marker constraints - bubbleCell.readMarkerViewTopConstraint = [NSLayoutConstraint constraintWithItem:bubbleCell.readMarkerView - attribute:NSLayoutAttributeTop - relatedBy:NSLayoutRelationEqual - toItem:bubbleCell.bubbleOverlayContainer - attribute:NSLayoutAttributeTop - multiplier:1.0 - constant:bottomPositionY - RoomBubbleCellLayout.readMarkerViewHeight]; - bubbleCell.readMarkerViewLeadingConstraint = [NSLayoutConstraint constraintWithItem:bubbleCell.readMarkerView - attribute:NSLayoutAttributeLeading - relatedBy:NSLayoutRelationEqual - toItem:bubbleCell.bubbleOverlayContainer - attribute:NSLayoutAttributeLeading - multiplier:1.0 - constant:0]; - bubbleCell.readMarkerViewTrailingConstraint = [NSLayoutConstraint constraintWithItem:bubbleCell.bubbleOverlayContainer - attribute:NSLayoutAttributeTrailing - relatedBy:NSLayoutRelationEqual - toItem:bubbleCell.readMarkerView - attribute:NSLayoutAttributeTrailing - multiplier:1.0 - constant:0]; - - bubbleCell.readMarkerViewHeightConstraint = [NSLayoutConstraint constraintWithItem:bubbleCell.readMarkerView - attribute:NSLayoutAttributeHeight - relatedBy:NSLayoutRelationEqual - toItem:nil - attribute:NSLayoutAttributeNotAnAttribute - multiplier:1.0 - constant:RoomBubbleCellLayout.readMarkerViewHeight]; - - [NSLayoutConstraint activateConstraints:@[bubbleCell.readMarkerViewTopConstraint, bubbleCell.readMarkerViewLeadingConstraint, bubbleCell.readMarkerViewTrailingConstraint, bubbleCell.readMarkerViewHeightConstraint]]; + [cellDecorator addReadMarkerView:readMarkerView + toCell:bubbleCell + cellData:cellData + contentViewPositionY:bottomPositionY]; } } } @@ -668,6 +638,13 @@ const CGFloat kTypingCellHeight = 24; // Make extra cell layout updates if needed [self updateCellLayoutIfNeeded:bubbleCell withCellData:cellData]; } + + if ([cell conformsToProtocol:@protocol(Themable)]) + { + id cellThemable = (id)cell; + + [cellThemable updateWithTheme:ThemeService.shared.theme]; + } return cell; } @@ -1000,6 +977,11 @@ const CGFloat kTypingCellHeight = 24; - (void)newThreadCreated:(NSNotification *)notification { + if (self.threadId) + { + // no need to reload the thread screen + return; + } NSUInteger count = 0; @synchronized (bubbles) { diff --git a/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift b/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift index 1e0dab2f8..b908e5cb0 100644 --- a/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift +++ b/Riot/Modules/Room/EditHistory/EditHistoryCoordinatorBridgePresenter.swift @@ -58,7 +58,6 @@ final class EditHistoryCoordinatorBridgePresenter: NSObject { func present(from viewController: UIViewController, animated: Bool) { guard let formatter = self.createEventFormatter(session: self.session) else { - //s das return } diff --git a/Riot/Modules/Room/EmojiPicker/Data/EmojiMart/EmojiMartService.swift b/Riot/Modules/Room/EmojiPicker/Data/EmojiMart/EmojiMartService.swift index 962114635..98444fad5 100644 --- a/Riot/Modules/Room/EmojiPicker/Data/EmojiMart/EmojiMartService.swift +++ b/Riot/Modules/Room/EmojiPicker/Data/EmojiMart/EmojiMartService.swift @@ -41,9 +41,13 @@ final class EmojiMartService: EmojiServiceType { let emojiJSONData = try self.getEmojisJSONData() let emojiJSONStore: EmojiMartStore = try self.serializationService.deserialize(emojiJSONData) let emojiCategories = self.emojiCategories(from: emojiJSONStore) - completion(MXResponse.success(emojiCategories)) + DispatchQueue.main.async { + completion(MXResponse.success(emojiCategories)) + } } catch { - completion(MXResponse.failure(error)) + DispatchQueue.main.async { + completion(MXResponse.failure(error)) + } } } } diff --git a/Riot/Modules/Room/EmojiPicker/Data/EmojiServiceType.swift b/Riot/Modules/Room/EmojiPicker/Data/EmojiServiceType.swift index 80a0b3456..cb5a24153 100644 --- a/Riot/Modules/Room/EmojiPicker/Data/EmojiServiceType.swift +++ b/Riot/Modules/Room/EmojiPicker/Data/EmojiServiceType.swift @@ -17,5 +17,7 @@ import Foundation protocol EmojiServiceType { + + /// Returns all available emoji categories. The completion will always be called on the main queue. func getEmojiCategories(completion: @escaping (MXResponse<[EmojiCategory]>) -> Void) } diff --git a/Riot/Modules/Room/EmojiPicker/EmojiPickerViewController.swift b/Riot/Modules/Room/EmojiPicker/EmojiPickerViewController.swift index 47349e326..b9d2beb85 100644 --- a/Riot/Modules/Room/EmojiPicker/EmojiPickerViewController.swift +++ b/Riot/Modules/Room/EmojiPicker/EmojiPickerViewController.swift @@ -164,7 +164,7 @@ final class EmojiPickerViewController: UIViewController { private func setupSearchController() { let searchController = UISearchController(searchResultsController: nil) - searchController.dimsBackgroundDuringPresentation = false + searchController.obscuresBackgroundDuringPresentation = false searchController.searchResultsUpdater = self searchController.searchBar.placeholder = VectorL10n.searchDefaultPlaceholder searchController.hidesNavigationBarDuringPresentation = false diff --git a/Riot/Modules/Room/EmojiPicker/EmojiPickerViewModel.swift b/Riot/Modules/Room/EmojiPicker/EmojiPickerViewModel.swift index 514ab365b..8bb771284 100644 --- a/Riot/Modules/Room/EmojiPicker/EmojiPickerViewModel.swift +++ b/Riot/Modules/Room/EmojiPicker/EmojiPickerViewModel.swift @@ -88,13 +88,9 @@ final class EmojiPickerViewModel: EmojiPickerViewModelType { self.emojiStore.set(emojiCategories) let emojiCatagoryViewDataList = self.emojiCatagoryViewDataList(from: emojiCategories) - DispatchQueue.main.async { - self.update(viewState: .loaded(emojiCategories: emojiCatagoryViewDataList)) - } + self.update(viewState: .loaded(emojiCategories: emojiCatagoryViewDataList)) case .failure(let error): - DispatchQueue.main.async { - self.update(viewState: .error(error)) - } + self.update(viewState: .error(error)) } } } diff --git a/Riot/Modules/Room/Location/RoomTimelineLocationView.swift b/Riot/Modules/Room/Location/RoomTimelineLocationView.swift index 882a277c9..5ffb88e15 100644 --- a/Riot/Modules/Room/Location/RoomTimelineLocationView.swift +++ b/Riot/Modules/Room/Location/RoomTimelineLocationView.swift @@ -35,6 +35,7 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat @IBOutlet private var descriptionContainerView: UIView! @IBOutlet private var descriptionLabel: UILabel! @IBOutlet private var descriptionIcon: UIImageView! + @IBOutlet private var attributionLabel: UILabel! private var mapView: MGLMapView! private var annotationView: LocationMarkerView? @@ -101,6 +102,7 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat descriptionLabel.textColor = theme.colors.primaryContent descriptionLabel.font = theme.fonts.footnote descriptionIcon.tintColor = theme.colors.accent + attributionLabel.textColor = theme.colors.accent layer.borderColor = theme.colors.quinaryContent.cgColor } diff --git a/Riot/Modules/Room/Location/RoomTimelineLocationView.xib b/Riot/Modules/Room/Location/RoomTimelineLocationView.xib index acc469b74..fb2e22a29 100644 --- a/Riot/Modules/Room/Location/RoomTimelineLocationView.xib +++ b/Riot/Modules/Room/Location/RoomTimelineLocationView.xib @@ -1,9 +1,9 @@ - + - + @@ -15,48 +15,72 @@ - - + + - - + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + - - - + + + + diff --git a/Riot/Modules/Room/MXKRoomViewController.h b/Riot/Modules/Room/MXKRoomViewController.h index 45ad325b5..5eb96dd3e 100644 --- a/Riot/Modules/Room/MXKRoomViewController.h +++ b/Riot/Modules/Room/MXKRoomViewController.h @@ -438,10 +438,17 @@ typedef NS_ENUM(NSUInteger, MXKRoomViewControllerJoinRoomResult) { - (void)setBubbleTableViewContentOffset:(CGPoint)contentOffset animated:(BOOL)animated; /** - Handle typing notification. + Sends a typing notification with the specified timeout. @param typing Flag indicating whether the user is typing or not. + @param notificationTimeoutMS The length of time the typing notification is valid for */ -- (void)handleTypingNotification:(BOOL)typing; +- (void)sendTypingNotification:(BOOL)typing timeout:(NSUInteger)notificationTimeoutMS; + + +/** + Share encryption keys in this room. + */ +- (void)shareEncryptionKeys; @end diff --git a/Riot/Modules/Room/MXKRoomViewController.m b/Riot/Modules/Room/MXKRoomViewController.m index 0028f45f3..a4a0f7dcf 100644 --- a/Riot/Modules/Room/MXKRoomViewController.m +++ b/Riot/Modules/Room/MXKRoomViewController.m @@ -228,6 +228,8 @@ [[[self class] nib] instantiateWithOwner:self options:nil]; } + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" // Adjust bottom constraint of the input toolbar container in order to take into account potential tabBar _roomInputToolbarContainerBottomConstraint.active = NO; _roomInputToolbarContainerBottomConstraint = [NSLayoutConstraint constraintWithItem:self.bottomLayoutGuide @@ -237,6 +239,8 @@ attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + #pragma clang diagnostic pop + _roomInputToolbarContainerBottomConstraint.active = YES; [self.view setNeedsUpdateConstraints]; @@ -419,6 +423,8 @@ }); } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" // The 2 following methods are deprecated since iOS 8 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { @@ -446,6 +452,7 @@ self->isSizeTransitionInProgress = NO; }); } +#pragma clang diagnostic pop - (void)viewDidLayoutSubviews { @@ -488,6 +495,8 @@ self.keyboardView = keyboardView; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" - (void)setKeyboardHeight:(CGFloat)keyboardHeight { // Deduce the bottom constraint for the input toolbar view (Don't forget the potential tabBar) @@ -531,6 +540,7 @@ super.keyboardHeight = keyboardHeight; } +#pragma clang diagnostic pop - (void)destroy { @@ -1046,7 +1056,7 @@ [titleView destroy]; } - titleView = self.navigationItem.titleView = [roomTitleViewClass roomTitleView]; + self.navigationItem.titleView = titleView = [roomTitleViewClass roomTitleView]; titleView.delegate = self; // Define directly the navigation titleView with the custom title view instance. Do not use anymore a container. @@ -2116,6 +2126,8 @@ self->eventDetailsView = eventDetailsView; + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" [self.view addConstraint:[NSLayoutConstraint constraintWithItem:eventDetailsView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual @@ -2131,6 +2143,7 @@ attribute:NSLayoutAttributeTop multiplier:1.0f constant:-10.0f]]; + #pragma clang diagnostic pop [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeLeading @@ -3299,7 +3312,7 @@ roomDataSource.partialTextMessage = inputToolbarView.textMessage; } - [self handleTypingNotification:typing]; + [self handleTypingState:typing]; } - (void)roomInputToolbarView:(MXKRoomInputToolbarView*)toolbarView heightDidChanged:(CGFloat)height completion:(void (^)(BOOL finished))completion @@ -3420,7 +3433,7 @@ } # pragma mark - Typing notification -- (void)handleTypingNotification:(BOOL)typing +- (void)handleTypingState:(BOOL)typing { NSUInteger notificationTimeoutMS = -1; if (typing) @@ -3482,6 +3495,11 @@ lastTypingDate = nil; } + [self sendTypingNotification:typing timeout:notificationTimeoutMS]; +} + +- (void)sendTypingNotification:(BOOL)typing timeout:(NSUInteger)notificationTimeoutMS +{ MXWeakify(self); // Send typing notification to server @@ -3512,7 +3530,7 @@ // Check whether a new typing event has been observed BOOL typing = (lastTypingDate != nil); // Post a new typing notification - [self handleTypingNotification:typing]; + [self handleTypingState:typing]; } diff --git a/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m b/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m index 687587dfe..b5928f009 100644 --- a/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m +++ b/Riot/Modules/Room/Members/Detail/RoomMemberDetailsViewController.m @@ -350,7 +350,7 @@ return [AvatarGenerator generateAvatarForMatrixItem:self.mxRoomMember.userId withDisplayName:self.mxRoomMember.displayname]; } - return [MXKTools paintImage:[UIImage imageNamed:@"placeholder"] + return [MXKTools paintImage:AssetImages.placeholder.image withColor:ThemeService.shared.theme.tintColor]; } @@ -984,7 +984,7 @@ } else { - roomCell.avatarImageView.image = [UIImage imageNamed:@"start_chat"]; + roomCell.avatarImageView.image = AssetImages.startChat.image; roomCell.avatarImageView.defaultBackgroundColor = [UIColor clearColor]; roomCell.avatarImageView.userInteractionEnabled = NO; roomCell.titleLabel.text = [VectorL10n roomParticipantsActionStartNewChat]; diff --git a/Riot/Modules/Room/Members/RoomParticipantsViewController.m b/Riot/Modules/Room/Members/RoomParticipantsViewController.m index 1957592c0..cde6a04d2 100644 --- a/Riot/Modules/Room/Members/RoomParticipantsViewController.m +++ b/Riot/Modules/Room/Members/RoomParticipantsViewController.m @@ -104,6 +104,8 @@ // Adjust Top and Bottom constraints to take into account potential navBar and tabBar. [NSLayoutConstraint deactivateConstraints:@[_searchBarTopConstraint]]; + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" _searchBarTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual @@ -111,6 +113,7 @@ attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + #pragma clang diagnostic pop [NSLayoutConstraint activateConstraints:@[_searchBarTopConstraint]]; @@ -145,7 +148,7 @@ if (_showInviteUserFab) { // Add invite members button programmatically - [self vc_addFABWithImage:[UIImage imageNamed:@"add_member_floating_action"] + [self vc_addFABWithImage:AssetImages.addMemberFloatingAction.image target:self action:@selector(onAddParticipantButtonPressed)]; } @@ -807,7 +810,7 @@ pendingMaskSpinnerView.alpha = 0; [UIView animateWithDuration:0.3 delay:0.3 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ - pendingMaskSpinnerView.alpha = 1; + self->pendingMaskSpinnerView.alpha = 1; } completion:^(BOOL finished) { }]; diff --git a/Riot/Modules/Room/RoomCoordinatorBridgePresenter.swift b/Riot/Modules/Room/RoomCoordinatorBridgePresenter.swift index 9433baedd..0410f63d6 100644 --- a/Riot/Modules/Room/RoomCoordinatorBridgePresenter.swift +++ b/Riot/Modules/Room/RoomCoordinatorBridgePresenter.swift @@ -73,7 +73,8 @@ class RoomCoordinatorBridgePresenterParameters: NSObject { /// RoomCoordinatorBridgePresenter enables to start RoomCoordinator from a view controller. /// This bridge is used while waiting for global usage of coordinator pattern. -/// **WARNING**: This class breaks the Coordinator abstraction and it has been introduced for **Objective-C compatibility only** (mainly for integration in legacy view controllers). Each bridge should be removed once the underlying Coordinator has been integrated by another Coordinator. +/// **WARNING**: This class breaks the Coordinator abstraction and it has been introduced for **Objective-C compatibility only** (mainly for integration in legacy view controllers). Each bridge should be removed +/// once the underlying Coordinator has been integrated by another Coordinator. @objcMembers final class RoomCoordinatorBridgePresenter: NSObject { diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 6fcc01886..c2822c603 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -90,7 +90,7 @@ NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNo NSNotificationName const RoomGroupCallTileTappedNotification = @"RoomGroupCallTileTappedNotification"; const NSTimeInterval kResizeComposerAnimationDuration = .05; -@interface RoomViewController () @@ -443,7 +443,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; if (ThemeService.shared.isCurrentThemeDark) { - [self.scrollToBottomButton setImage:[UIImage imageNamed:@"scrolldown_dark"] forState:UIControlStateNormal]; + [self.scrollToBottomButton setImage:AssetImages.scrolldownDark.image forState:UIControlStateNormal]; self.jumpToLastUnreadBanner.backgroundColor = ThemeService.shared.theme.colors.navigation; [self.jumpToLastUnreadBanner vc_removeShadow]; @@ -451,7 +451,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } else { - [self.scrollToBottomButton setImage:[UIImage imageNamed:@"scrolldown"] forState:UIControlStateNormal]; + [self.scrollToBottomButton setImage:AssetImages.scrolldown.image forState:UIControlStateNormal]; self.jumpToLastUnreadBanner.backgroundColor = ThemeService.shared.theme.colors.background; [self.jumpToLastUnreadBanner vc_addShadowWithColor:ThemeService.shared.theme.shadowColor @@ -1436,7 +1436,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; - (UIBarButtonItem *)videoCallBarButtonItem { - UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"video_call"] + UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:AssetImages.videoCall.image style:UIBarButtonItemStylePlain target:self action:@selector(onVideoCallPressed:)]; @@ -1447,7 +1447,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; - (UIBarButtonItem *)threadMoreBarButtonItem { - UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"room_context_menu_more"] + UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:AssetImages.roomContextMenuMore.image style:UIBarButtonItemStylePlain target:self action:@selector(onButtonPressed:)]; @@ -1459,7 +1459,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; - (BadgedBarButtonItem *)threadListBarButtonItem { UIButton *button = [UIButton new]; - UIImage *icon = [[UIImage imageNamed:@"threads_icon"] vc_resizedWith:CGSizeMake(21, 21)]; + UIImage *icon = [AssetImages.threadsIcon.image vc_resizedWith:CGSizeMake(21, 21)]; button.contentEdgeInsets = UIEdgeInsetsMake(4, 8, 4, 8); [button setImage:icon forState:UIControlStateNormal]; @@ -1616,7 +1616,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; if (self.roomDataSource.room.summary.membersCount.joined == 2 && self.roomDataSource.room.isDirect) { // voice call button for Matrix call - UIBarButtonItem *itemVoice = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"voice_call_hangon_icon"] + UIBarButtonItem *itemVoice = [[UIBarButtonItem alloc] initWithImage:AssetImages.voiceCallHangonIcon.image style:UIBarButtonItemStylePlain target:self action:@selector(onVoiceCallPressed:)]; @@ -1645,7 +1645,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; { // show Join button CallTileActionButton *button = [CallTileActionButton new]; - [button setImage:[UIImage imageNamed:@"call_video_icon"] + [button setImage:AssetImages.callVideoIcon.image forState:UIControlStateNormal]; [button setTitle:[VectorL10n roomJoinGroupCall] forState:UIControlStateNormal]; @@ -1667,7 +1667,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; UIBarButtonItem *item = [self videoCallBarButtonItem]; if (!self.canEditJitsiWidget) { - item.image = [[UIImage imageNamed:@"video_call"] vc_withAlpha:0.3]; + item.image = [AssetImages.videoCall.image vc_withAlpha:0.3]; } [rightBarButtonItems addObject:item]; } @@ -1676,7 +1676,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; if ([self widgetsCount:NO]) { - UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"integrations_icon"] + UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:AssetImages.integrationsIcon.image style:UIBarButtonItemStylePlain target:self action:@selector(onIntegrationsPressed:)]; @@ -1995,7 +1995,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; NSMutableArray *actionItems = [NSMutableArray new]; if (RiotSettings.shared.roomScreenAllowMediaLibraryAction) { - [actionItems addObject:[[RoomActionItem alloc] initWithImage:[UIImage imageNamed:@"action_media_library"] andAction:^{ + [actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionMediaLibrary.image andAction:^{ MXStrongifyAndReturnIfNil(self); if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class]) { ((RoomInputToolbarView *) self.inputToolbarView).actionMenuOpened = NO; @@ -2005,7 +2005,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } if (RiotSettings.shared.roomScreenAllowStickerAction) { - [actionItems addObject:[[RoomActionItem alloc] initWithImage:[UIImage imageNamed:@"action_sticker"] andAction:^{ + [actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionSticker.image andAction:^{ MXStrongifyAndReturnIfNil(self); if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class]) { ((RoomInputToolbarView *) self.inputToolbarView).actionMenuOpened = NO; @@ -2015,7 +2015,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } if (RiotSettings.shared.roomScreenAllowFilesAction) { - [actionItems addObject:[[RoomActionItem alloc] initWithImage:[UIImage imageNamed:@"action_file"] andAction:^{ + [actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionFile.image andAction:^{ MXStrongifyAndReturnIfNil(self); if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class]) { ((RoomInputToolbarView *) self.inputToolbarView).actionMenuOpened = NO; @@ -2025,7 +2025,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } if (BuildSettings.pollsEnabled && self.displayConfiguration.sendingPollsEnabled) { - [actionItems addObject:[[RoomActionItem alloc] initWithImage:[UIImage imageNamed:@"action_poll"] andAction:^{ + [actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionPoll.image andAction:^{ MXStrongifyAndReturnIfNil(self); if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class]) { ((RoomInputToolbarView *) self.inputToolbarView).actionMenuOpened = NO; @@ -2035,7 +2035,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } if (BuildSettings.locationSharingEnabled) { - [actionItems addObject:[[RoomActionItem alloc] initWithImage:[UIImage imageNamed:@"action_location"] andAction:^{ + [actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionLocation.image andAction:^{ MXStrongifyAndReturnIfNil(self); if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class]) { ((RoomInputToolbarView *) self.inputToolbarView).actionMenuOpened = NO; @@ -2045,7 +2045,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } if (RiotSettings.shared.roomScreenAllowCameraAction) { - [actionItems addObject:[[RoomActionItem alloc] initWithImage:[UIImage imageNamed:@"action_camera"] andAction:^{ + [actionItems addObject:[[RoomActionItem alloc] initWithImage:AssetImages.actionCamera.image andAction:^{ MXStrongifyAndReturnIfNil(self); if ([self.inputToolbarView isKindOfClass:RoomInputToolbarView.class]) { ((RoomInputToolbarView *) self.inputToolbarView).actionMenuOpened = NO; @@ -2562,7 +2562,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } else { - previewHeader.roomAvatarPlaceholder = [MXKTools paintImage:[UIImage imageNamed:@"placeholder"] + previewHeader.roomAvatarPlaceholder = [MXKTools paintImage:AssetImages.placeholder.image withColor:ThemeService.shared.theme.tintColor]; } } @@ -2594,7 +2594,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; self.bubblesTableViewTopConstraint.constant = self.previewHeaderContainerHeightConstraint.constant - self.bubblesTableView.adjustedContentInset.top; - previewHeader.roomAvatar.alpha = 1; + self->previewHeader.roomAvatar.alpha = 1; // Force to render the view [self forceLayoutRefresh]; @@ -2758,17 +2758,35 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } else if (bubbleData.tag == RoomBubbleCellDataTagPoll) { - if (bubbleData.isPaginationFirstBubble) + if (bubbleData.isIncoming) { - cellIdentifier = RoomTimelineCellIdentifierPollWithPaginationTitle; - } - else if (bubbleData.shouldHideSenderInformation) - { - cellIdentifier = RoomTimelineCellIdentifierPollWithoutSenderInfo; + if (bubbleData.isPaginationFirstBubble) + { + cellIdentifier = RoomTimelineCellIdentifierIncomingPollWithPaginationTitle; + } + else if (bubbleData.shouldHideSenderInformation) + { + cellIdentifier = RoomTimelineCellIdentifierIncomingPollWithoutSenderInfo; + } + else + { + cellIdentifier = RoomTimelineCellIdentifierIncomingPoll; + } } else { - cellIdentifier = RoomTimelineCellIdentifierPoll; + if (bubbleData.isPaginationFirstBubble) + { + cellIdentifier = RoomTimelineCellIdentifierOutgoingPollWithPaginationTitle; + } + else if (bubbleData.shouldHideSenderInformation) + { + cellIdentifier = RoomTimelineCellIdentifierOutgoingPollWithoutSenderInfo; + } + else + { + cellIdentifier = RoomTimelineCellIdentifierOutgoingPoll; + } } } else if (bubbleData.tag == RoomBubbleCellDataTagLocation) @@ -2804,6 +2822,61 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; } } } + else if (roomBubbleCellData.getFirstBubbleComponentWithDisplay.event.isEmote) + { + if (bubbleData.isIncoming) + { + if (bubbleData.isPaginationFirstBubble) + { + if (bubbleData.shouldHideSenderName) + { + cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingEmoteEncryptedWithPaginationTitleWithoutSenderName : RoomTimelineCellIdentifierIncomingEmoteWithPaginationTitleWithoutSenderName; + } + else + { + cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingEmoteEncryptedWithPaginationTitle : RoomTimelineCellIdentifierIncomingEmoteWithPaginationTitle; + } + } + else if (bubbleData.shouldHideSenderInformation) + { + cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingEmoteEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierIncomingEmoteWithoutSenderInfo; + } + else if (bubbleData.shouldHideSenderName) + { + cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingEmoteEncryptedWithoutSenderName : RoomTimelineCellIdentifierIncomingEmoteWithoutSenderName; + } + else + { + cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierIncomingEmoteEncrypted : RoomTimelineCellIdentifierIncomingEmote; + } + } + else + { + if (bubbleData.isPaginationFirstBubble) + { + if (bubbleData.shouldHideSenderName) + { + cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingEmoteEncryptedWithPaginationTitleWithoutSenderName : RoomTimelineCellIdentifierOutgoingEmoteWithPaginationTitleWithoutSenderName; + } + else + { + cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingEmoteEncryptedWithPaginationTitle : RoomTimelineCellIdentifierOutgoingEmoteWithPaginationTitle; + } + } + else if (bubbleData.shouldHideSenderInformation) + { + cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingEmoteEncryptedWithoutSenderInfo : RoomTimelineCellIdentifierOutgoingEmoteWithoutSenderInfo; + } + else if (bubbleData.shouldHideSenderName) + { + cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingEmoteEncryptedWithoutSenderName : RoomTimelineCellIdentifierOutgoingEmoteWithoutSenderName; + } + else + { + cellIdentifier = showEncryptionBadge ? RoomTimelineCellIdentifierOutgoingEmoteEncrypted : RoomTimelineCellIdentifierOutgoingEmote; + } + } + } else if (bubbleData.isIncoming) { if (bubbleData.isAttachmentWithThumbnail) @@ -3653,7 +3726,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; { MXKPasteboardManager.shared.pasteboard.URL = url; [self.view vc_toastWithMessage:VectorL10n.roomEventCopyLinkInfo - image:[UIImage imageNamed:@"link_icon"] + image:AssetImages.linkIcon.image duration:2.0 position:ToastPositionBottom additionalMargin:self.roomInputToolbarContainerHeightConstraint.constant]; @@ -4219,7 +4292,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; [self updateTitleViewEncryptionDecoration]; } -- (void)roomDataSource:(RoomDataSource *)roomDataSource didTapThread:(MXThread *)thread +- (void)roomDataSource:(RoomDataSource *)roomDataSource didTapThread:(id)thread { [self openThreadWithId:thread.id]; } @@ -4500,6 +4573,15 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; [self.userSuggestionCoordinator processTextMessage:toolbarView.textMessage]; } +- (void)roomInputToolbarViewDidOpenActionMenu:(MXKRoomInputToolbarView*)toolbarView +{ + // Consider opening the action menu as beginning to type and share encryption keys if requested. + if ([MXKAppSettings standardAppSettings].outboundGroupSessionKeyPreSharingStrategy == MXKKeyPreSharingWhenTyping) + { + [self shareEncryptionKeys]; + } +} + #pragma mark - MXKRoomMemberDetailsViewControllerDelegate - (void)roomMemberDetailsViewController:(MXKRoomMemberDetailsViewController *)roomMemberDetailsViewController startChatWithMemberId:(NSString *)matrixId completion:(void (^)(void))completion @@ -5671,6 +5753,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; self->encryptionInfoView = encryptionInfoView; + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdeprecated" [self.view addConstraint:[NSLayoutConstraint constraintWithItem:encryptionInfoView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual @@ -5686,6 +5770,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; attribute:NSLayoutAttributeTop multiplier:1.0f constant:-10.0f]]; + #pragma clang diagnostic pop [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeLeading @@ -5745,44 +5830,23 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05; - (void)animateReadMarkerView { // Check whether the cell with the read marker is known and if the marker is not animated yet. - if (readMarkerTableViewCell && readMarkerTableViewCell.readMarkerView.isHidden) + + if (!readMarkerTableViewCell || readMarkerTableViewCell.readMarkerView.isHidden == NO) { - RoomBubbleCellData *cellData = (RoomBubbleCellData*)readMarkerTableViewCell.bubbleData; - - // Do not display the marker if this is the last message. - if (cellData.containsLastMessage && readMarkerTableViewCell.readMarkerView.tag == cellData.mostRecentComponentIndex) - { - readMarkerTableViewCell.readMarkerView.hidden = YES; - readMarkerTableViewCell = nil; - } - else - { - readMarkerTableViewCell.readMarkerView.hidden = NO; - - // Animate the layout to hide the read marker - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - - [UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseIn - animations:^{ - - readMarkerTableViewCell.readMarkerViewLeadingConstraint.constant = readMarkerTableViewCell.readMarkerViewTrailingConstraint.constant = readMarkerTableViewCell.bubbleOverlayContainer.frame.size.width / 2; - readMarkerTableViewCell.readMarkerView.alpha = 0; - - // Force to render the view - [readMarkerTableViewCell.bubbleOverlayContainer layoutIfNeeded]; - - } - completion:^(BOOL finished){ - - readMarkerTableViewCell.readMarkerView.hidden = YES; - readMarkerTableViewCell.readMarkerView.alpha = 1; - - readMarkerTableViewCell = nil; - }]; - - }); - } + return; } + + RoomBubbleCellData *cellData = (RoomBubbleCellData*)readMarkerTableViewCell.bubbleData; + + id cellDecorator = [RoomTimelineConfiguration shared].currentStyle.cellDecorator; + + [cellDecorator dissmissReadMarkerViewForCell:readMarkerTableViewCell + cellData:cellData + animated:YES + completion:^{ + + self->readMarkerTableViewCell = nil; + }]; } - (void)refreshRemoveJitsiWidgetView diff --git a/Riot/Modules/Room/Search/DataSources/RoomSearchDataSource.m b/Riot/Modules/Room/Search/DataSources/RoomSearchDataSource.m index 5b99eea2d..8be145b51 100644 --- a/Riot/Modules/Room/Search/DataSources/RoomSearchDataSource.m +++ b/Riot/Modules/Room/Search/DataSources/RoomSearchDataSource.m @@ -96,6 +96,10 @@ { continueBlock(); } + else if (result.result.unsignedData.relations.thread) + { + continueBlock(); + } else { [roomDataSource.room liveTimeline:^(id liveTimeline) { @@ -143,14 +147,15 @@ { if (cellData.hasThreadRoot) { - MXThread *thread = cellData.bubbleComponents.firstObject.thread; - ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread]; + id thread = cellData.bubbleComponents.firstObject.thread; + ThreadSummaryView *threadSummaryView = [[ThreadSummaryView alloc] initWithThread:thread + session:self.mxSession]; [bubbleCell.tmpSubviews addObject:threadSummaryView]; threadSummaryView.translatesAutoresizingMaskIntoConstraints = NO; [bubbleCell.contentView addSubview:threadSummaryView]; - CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin; + CGFloat leftMargin = PlainRoomCellLayoutConstants.reactionsViewLeftMargin; CGFloat height = [ThreadSummaryView contentViewHeightForThread:thread fitting:cellData.maxTextViewWidth]; CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0]; @@ -161,9 +166,9 @@ [threadSummaryView.leadingAnchor constraintEqualToAnchor:threadSummaryView.superview.leadingAnchor constant:leftMargin], [threadSummaryView.topAnchor constraintEqualToAnchor:threadSummaryView.superview.topAnchor - constant:bottomPositionY + RoomBubbleCellLayout.threadSummaryViewTopMargin], + constant:bottomPositionY + PlainRoomCellLayoutConstants.threadSummaryViewTopMargin], [threadSummaryView.heightAnchor constraintEqualToConstant:height], - [threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin] + [threadSummaryView.trailingAnchor constraintLessThanOrEqualToAnchor:threadSummaryView.superview.trailingAnchor constant:-PlainRoomCellLayoutConstants.reactionsViewRightMargin] ]]; } else if (event.isInThread) @@ -174,7 +179,7 @@ fromAThreadView.translatesAutoresizingMaskIntoConstraints = NO; [bubbleCell.contentView addSubview:fromAThreadView]; - CGFloat leftMargin = RoomBubbleCellLayout.reactionsViewLeftMargin; + CGFloat leftMargin = PlainRoomCellLayoutConstants.reactionsViewLeftMargin; CGFloat height = [FromAThreadView contentViewHeightForEvent:event fitting:cellData.maxTextViewWidth]; CGRect bubbleComponentFrame = [bubbleCell componentFrameInContentViewForIndex:0]; @@ -185,9 +190,9 @@ [fromAThreadView.leadingAnchor constraintEqualToAnchor:fromAThreadView.superview.leadingAnchor constant:leftMargin], [fromAThreadView.topAnchor constraintEqualToAnchor:fromAThreadView.superview.topAnchor - constant:bottomPositionY + RoomBubbleCellLayout.fromAThreadViewTopMargin], + constant:bottomPositionY + PlainRoomCellLayoutConstants.fromAThreadViewTopMargin], [fromAThreadView.heightAnchor constraintEqualToConstant:height], - [fromAThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromAThreadView.superview.trailingAnchor constant:-RoomBubbleCellLayout.reactionsViewRightMargin] + [fromAThreadView.trailingAnchor constraintLessThanOrEqualToAnchor:fromAThreadView.superview.trailingAnchor constant:-PlainRoomCellLayoutConstants.reactionsViewRightMargin] ]]; } } diff --git a/Riot/Modules/Room/Search/RoomSearchViewController.m b/Riot/Modules/Room/Search/RoomSearchViewController.m index 7d830ecb3..8a16c463d 100644 --- a/Riot/Modules/Room/Search/RoomSearchViewController.m +++ b/Riot/Modules/Room/Search/RoomSearchViewController.m @@ -73,10 +73,7 @@ [self initWithTitles:titles viewControllers:viewControllers defaultSelected:0]; [super viewDidLoad]; - - // Add the Riot background image when search bar is empty - [self addBackgroundImageViewToView:self.view]; - + // Initialize here the data sources if a matrix session has been already set. [self initializeDataSources]; @@ -87,13 +84,6 @@ { [super userInterfaceThemeDidChange]; - UIImageView *backgroundImageView = self.backgroundImageView; - if (backgroundImageView) - { - UIImage *image = [MXKTools paintImage:backgroundImageView.image withColor:ThemeService.shared.theme.matrixSearchBackgroundImageTintColor]; - backgroundImageView.image = image; - } - // Match the search bar color to the navigation bar color as it extends slightly outside the frame. self.searchBar.backgroundColor = ThemeService.shared.theme.baseColor; } @@ -165,7 +155,7 @@ threadParameters = [[ThreadParameters alloc] initWithThreadId:event.threadId stackRoomScreen:NO]; } - else if ([self.mainSession.threadingService isEventThreadRoot:event]) + else if (event.unsignedData.relations.thread || [self.mainSession.threadingService isEventThreadRoot:event]) { threadParameters = [[ThreadParameters alloc] initWithThreadId:event.eventId stackRoomScreen:NO]; @@ -227,15 +217,6 @@ #pragma mark - Override MXKViewController -- (void)setKeyboardHeight:(CGFloat)keyboardHeight -{ - [self setKeyboardHeightForBackgroundImage:keyboardHeight]; - - [super setKeyboardHeight:keyboardHeight]; - - [self checkAndShowBackgroundImage]; -} - - (void)startActivityIndicator { // Redirect the operation to the currently displayed VC @@ -283,48 +264,6 @@ [self.navigationController popViewControllerAnimated:YES]; } -- (void)setKeyboardHeightForBackgroundImage:(CGFloat)keyboardHeight -{ - [super setKeyboardHeightForBackgroundImage:keyboardHeight]; - - if (keyboardHeight > 0) - { - [self checkAndShowBackgroundImage]; - } -} - -// Check conditions before displaying the background -- (void)checkAndShowBackgroundImage -{ - // Note: This background is hidden when keyboard is dismissed. - // The other conditions depend on the current selected view controller. - if (self.selectedViewController == messagesSearchViewController) - { - self.backgroundImageView.hidden = ((messagesSearchDataSource.serverCount != 0) || !messagesSearchViewController.noResultsLabel.isHidden || (self.keyboardHeight == 0)); - } - else if (self.selectedViewController == filesSearchViewController) - { - self.backgroundImageView.hidden = ((filesSearchDataSource.serverCount != 0) || !filesSearchViewController.noResultsLabel.isHidden || (self.keyboardHeight == 0)); - } - else - { - self.backgroundImageView.hidden = (self.keyboardHeight == 0); - } - - if (!self.backgroundImageView.hidden) - { - [self.backgroundImageView layoutIfNeeded]; - [self.selectedViewController.view layoutIfNeeded]; - - // Check whether there is enough space to display this background - // For example, in landscape with the iPhone 5 & 6 screen size, the backgroundImageView must be hidden. - if (self.backgroundImageView.frame.origin.y < 0 || (self.selectedViewController.view.frame.size.height - self.backgroundImageViewBottomConstraint.constant) < self.backgroundImageView.frame.size.height) - { - self.backgroundImageView.hidden = YES; - } - } -} - #pragma mark - Override SegmentedViewController - (void)setSelectedIndex:(NSUInteger)selectedIndex @@ -341,8 +280,6 @@ { if (self.searchBar.text.length) { - self.backgroundImageView.hidden = YES; - // Forward the search request to the data source if (self.selectedViewController == messagesSearchViewController) { @@ -352,8 +289,8 @@ // Do it asynchronously to give time to messagesSearchViewController to be set up // so that it can display its loading wheel dispatch_async(dispatch_get_main_queue(), ^{ - [messagesSearchDataSource searchMessages:self.searchBar.text force:NO]; - messagesSearchViewController.shouldScrollToBottomOnRefresh = YES; + [self->messagesSearchDataSource searchMessages:self.searchBar.text force:NO]; + self->messagesSearchViewController.shouldScrollToBottomOnRefresh = YES; }); } } @@ -365,8 +302,8 @@ // Do it asynchronously to give time to filesSearchViewController to be set up // so that it can display its loading wheel dispatch_async(dispatch_get_main_queue(), ^{ - [filesSearchDataSource searchMessages:self.searchBar.text force:NO]; - filesSearchViewController.shouldScrollToBottomOnRefresh = YES; + [self->filesSearchDataSource searchMessages:self.searchBar.text force:NO]; + self->filesSearchViewController.shouldScrollToBottomOnRefresh = YES; }); } } @@ -383,8 +320,6 @@ [filesSearchDataSource searchMessages:nil force:NO]; } } - - [self checkAndShowBackgroundImage]; } @end diff --git a/Riot/Modules/Room/Settings/RoomSettingsViewController.m b/Riot/Modules/Room/Settings/RoomSettingsViewController.m index e3f6f47dc..64b2e6a0e 100644 --- a/Riot/Modules/Room/Settings/RoomSettingsViewController.m +++ b/Riot/Modules/Room/Settings/RoomSettingsViewController.m @@ -172,9 +172,6 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti // The pending http operation MXHTTPOperation* pendingOperation; - // the updating spinner - UIActivityIndicatorView* updatingSpinner; - UIAlertController *currentAlert; // listen to more events than the mother class @@ -1091,7 +1088,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti { MXKPasteboardManager.shared.pasteboard.URL = url; [self.view vc_toastWithMessage:VectorL10n.roomEventCopyLinkInfo - image:[UIImage imageNamed:@"link_icon"] + image:AssetImages.linkIcon.image duration:2.0 position:ToastPositionBottom additionalMargin:0.0]; @@ -2767,7 +2764,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti addAddressCell.mxkLabel.text = nil; addAddressCell.accessoryType = UITableViewCellAccessoryNone; - addAddressCell.accessoryView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"plus_icon"] vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]]; + addAddressCell.accessoryView = [[UIImageView alloc] initWithImage:[AssetImages.plusIcon.image vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]]; addAddressTextField = addAddressCell.mxkTextField; addAddressTextField.placeholder = [VectorL10n roomDetailsNewAddressPlaceholder:self.mainSession.matrixRestClient.homeserverSuffix]; @@ -2844,7 +2841,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti { if ([alias isEqualToString:canonicalAlias]) { - addressCell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"main_alias_icon"]]; + addressCell.accessoryView = [[UIImageView alloc] initWithImage:AssetImages.mainAliasIcon.image]; } } } @@ -2868,7 +2865,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti addCommunityCell.mxkLabel.text = nil; addCommunityCell.accessoryType = UITableViewCellAccessoryNone; - addCommunityCell.accessoryView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"plus_icon"] vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]]; + addCommunityCell.accessoryView = [[UIImageView alloc] initWithImage:[AssetImages.plusIcon.image vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor]]; addGroupTextField = addCommunityCell.mxkTextField; addGroupTextField.placeholder = [VectorL10n roomDetailsNewFlairPlaceholder:self.mainSession.matrixRestClient.homeserverSuffix]; @@ -3408,7 +3405,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti completionHandler(YES); }]; removeAddressAction.backgroundColor = ThemeService.shared.theme.headerBackgroundColor; - removeAddressAction.image = [[UIImage imageNamed:@"remove_icon"] vc_notRenderedImage]; + removeAddressAction.image = [AssetImages.removeIcon.image vc_notRenderedImage]; // Create swipe action configuration @@ -3429,7 +3426,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti completionHandler(YES); }]; removeAddressAction.backgroundColor = ThemeService.shared.theme.headerBackgroundColor; - removeAddressAction.image = [[UIImage imageNamed:@"remove_icon"] vc_notRenderedImage]; + removeAddressAction.image = [AssetImages.removeIcon.image vc_notRenderedImage]; // Create swipe action configuration diff --git a/Riot/Modules/Room/Settings/Views/TableViewCellWithCheckBoxAndLabel.m b/Riot/Modules/Room/Settings/Views/TableViewCellWithCheckBoxAndLabel.m index b623ffc7d..718cce122 100644 --- a/Riot/Modules/Room/Settings/Views/TableViewCellWithCheckBoxAndLabel.m +++ b/Riot/Modules/Room/Settings/Views/TableViewCellWithCheckBoxAndLabel.m @@ -34,11 +34,11 @@ { if (enabled) { - _checkBox.image = [UIImage imageNamed:@"selection_tick"]; + _checkBox.image = AssetImages.selectionTick.image; } else { - _checkBox.image = [UIImage imageNamed:@"selection_untick"]; + _checkBox.image = AssetImages.selectionUntick.image; } _enabled = enabled; diff --git a/Riot/Modules/Room/Settings/Views/TableViewCellWithCheckBoxes.m b/Riot/Modules/Room/Settings/Views/TableViewCellWithCheckBoxes.m index 9504214a1..c3a683e7c 100644 --- a/Riot/Modules/Room/Settings/Views/TableViewCellWithCheckBoxes.m +++ b/Riot/Modules/Room/Settings/Views/TableViewCellWithCheckBoxes.m @@ -131,7 +131,7 @@ [checkboxContainer addSubview:checkbox]; // Store the new check box unselected by default - checkbox.image = [UIImage imageNamed:@"selection_untick"]; + checkbox.image = AssetImages.selectionUntick.image; checkbox.tintColor = ThemeService.shared.theme.tintColor; checkbox.tag = 0; [checkBoxesArray addObject:checkbox]; @@ -263,7 +263,7 @@ if (isSelected && !checkBox.tag) { - checkBox.image = [UIImage imageNamed:@"selection_tick"]; + checkBox.image = AssetImages.selectionTick.image; checkBox.tag = 1; if (!self.allowsMultipleSelection) @@ -276,7 +276,7 @@ checkBox = checkBoxesArray[k]; if (checkBox.tag) { - checkBox.image = [UIImage imageNamed:@"selection_untick"]; + checkBox.image = AssetImages.selectionUntick.image; checkBox.tag = 0; } } @@ -285,7 +285,7 @@ } else if (!isSelected && checkBox.tag) { - checkBox.image = [UIImage imageNamed:@"selection_untick"]; + checkBox.image = AssetImages.selectionUntick.image; checkBox.tag = 0; } } diff --git a/Riot/Modules/Room/TimelineCells/BaseRoomCell/BaseRoomCell.swift b/Riot/Modules/Room/TimelineCells/BaseRoomCell/BaseRoomCell.swift new file mode 100644 index 000000000..f3a9ddbea --- /dev/null +++ b/Riot/Modules/Room/TimelineCells/BaseRoomCell/BaseRoomCell.swift @@ -0,0 +1,420 @@ +/* +Copyright 2020 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import UIKit + +@objc protocol BaseRoomCellProtocol: Themable { + var roomCellContentView: RoomCellContentView? { get } +} + +/// `BaseRoomCell` allows a room cell that inherits from this class to embed and manage the default room message outer views and add an inner content view. +@objcMembers +class BaseRoomCell: MXKRoomBubbleTableViewCell, BaseRoomCellProtocol { + + // MARK: - Constants + + // MARK: - Properties + + private var areViewsSetup: Bool = false + + // MARK: Public + + weak var roomCellContentView: RoomCellContentView? + + private(set) var theme: Theme? + + // Overrides + + override var bubbleInfoContainer: UIView! { + get { + guard let infoContainer = self.roomCellContentView?.bubbleInfoContainer else { + fatalError("[BaseRoomCell] bubbleInfoContainer should not be used before set") + } + return infoContainer + } + set { + super.bubbleInfoContainer = newValue + } + } + + override var bubbleOverlayContainer: UIView! { + get { + guard let overlayContainer = self.roomCellContentView?.bubbleOverlayContainer else { + fatalError("[BaseRoomCell] bubbleOverlayContainer should not be used before set") + } + return overlayContainer + } + set { + super.bubbleInfoContainer = newValue + } + } + + override var bubbleInfoContainerTopConstraint: NSLayoutConstraint! { + get { + guard let infoContainerTopConstraint = self.roomCellContentView?.bubbleInfoContainerTopConstraint else { + fatalError("[BaseRoomCell] bubbleInfoContainerTopConstraint should not be used before set") + } + return infoContainerTopConstraint + } + set { + super.bubbleInfoContainerTopConstraint = newValue + } + } + + override var pictureView: MXKImageView! { + get { + guard let roomCellContentView = self.roomCellContentView, + roomCellContentView.showSenderAvatar else { + return nil + } + + guard let pictureView = self.roomCellContentView?.avatarImageView else { + fatalError("[BaseRoomCell] pictureView should not be used before set") + } + return pictureView + } + set { + super.pictureView = newValue + } + } + + override var userNameLabel: UILabel! { + get { + guard let roomCellContentView = self.roomCellContentView, roomCellContentView.showSenderName else { + return nil + } + + guard let userNameLabel = roomCellContentView.userNameLabel else { + fatalError("[BaseRoomCell] userNameLabel should not be used before set") + } + return userNameLabel + } + set { + super.userNameLabel = newValue + } + } + + override var userNameTapGestureMaskView: UIView! { + get { + guard let roomCellContentView = self.roomCellContentView, + roomCellContentView.showSenderName else { + return nil + } + + guard let userNameTapGestureMaskView = self.roomCellContentView?.userNameTouchMaskView else { + fatalError("[BaseRoomCell] userNameTapGestureMaskView should not be used before set") + } + return userNameTapGestureMaskView + } + set { + super.userNameTapGestureMaskView = newValue + } + } + + override var readMarkerViewLeadingConstraint: NSLayoutConstraint! { + get { + if self is RoomCellReadMarkerDisplayable { + return self.roomCellContentView?.readMarkerViewLeadingConstraint + } else { + return super.readMarkerViewLeadingConstraint + } + } + set { + if self is RoomCellReadMarkerDisplayable { + self.roomCellContentView?.readMarkerViewLeadingConstraint = newValue + } else { + super.readMarkerViewLeadingConstraint = newValue + } + } + } + + override var readMarkerViewTrailingConstraint: NSLayoutConstraint! { + get { + if self is RoomCellReadMarkerDisplayable { + return self.roomCellContentView?.readMarkerViewTrailingConstraint + } else { + return super.readMarkerViewTrailingConstraint + } + } + set { + if self is RoomCellReadMarkerDisplayable { + self.roomCellContentView?.readMarkerViewTrailingConstraint = newValue + } else { + super.readMarkerViewTrailingConstraint = newValue + } + } + } + + // MARK: - Setup + + required override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + self.commonInit() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.commonInit() + } + + private func commonInit() { + self.selectionStyle = .none + self.setupContentView() + self.update(theme: ThemeService.shared().theme) + } + + // MARK: - Public + + func removeDecorationViews() { + if let roomCellReadReceiptsDisplayable = self as? RoomCellReadReceiptsDisplayable { + roomCellReadReceiptsDisplayable.removeReadReceiptsView() + } + + if let roomCellReactionsDisplayable = self as? RoomCellReactionsDisplayable { + roomCellReactionsDisplayable.removeReactionsView() + } + + if let roomCellThreadSummaryDisplayable = self as? RoomCellThreadSummaryDisplayable { + roomCellThreadSummaryDisplayable.removeThreadSummaryView() + } + + if let timestampDisplayable = self as? TimestampDisplayable { + timestampDisplayable.removeTimestampView() + } + + if let urlPreviewDisplayable = self as? RoomCellURLPreviewDisplayable { + urlPreviewDisplayable.removeURLPreviewView() + } + } + + // MARK: - Overrides + + override var isTextViewNeedsPositioningVerticalSpace: Bool { + return false + } + + override func setupViews() { + super.setupViews() + + let showEncryptionStatus = roomCellContentView?.showEncryptionStatus ?? false + + if showEncryptionStatus { + self.setupEncryptionStatusViewTapGestureRecognizer() + } + } + + override func setupSenderNameLabel() { + + guard let userNameTouchMaskView = self.roomCellContentView?.userNameTouchMaskView else { + return + } + + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onSenderNameTap(_:))) + tapGesture.numberOfTouchesRequired = 1 + tapGesture.numberOfTapsRequired = 1 + tapGesture.delegate = self + + userNameTouchMaskView.addGestureRecognizer(tapGesture) + } + + override func setupAvatarView() { + + guard let avatarImageView = self.roomCellContentView?.avatarImageView else { + return + } + + avatarImageView.mediaFolder = kMXMediaManagerAvatarThumbnailFolder + + // Listen to avatar tap + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onAvatarTap(_:))) + tapGesture.numberOfTouchesRequired = 1 + tapGesture.numberOfTapsRequired = 1 + tapGesture.delegate = self + avatarImageView.addGestureRecognizer(tapGesture) + avatarImageView.isUserInteractionEnabled = true + + // Add a long gesture recognizer on avatar (in order to display for example the member details) + let longPress = UILongPressGestureRecognizer(target: self, action: #selector(onLongPressGesture(_:))) + avatarImageView.addGestureRecognizer(longPress) + } + + override class func defaultReuseIdentifier() -> String! { + return String(describing: self) + } + + override func prepareForReuse() { + super.prepareForReuse() + + self.removeDecorationViews() + } + + override func render(_ cellData: MXKCellData!) { + // In `MXKRoomBubbleTableViewCell` setupViews() is called in awakeFromNib() that is not called here, so call it only on first render() call + self.setupViewsIfNeeded() + + super.render(cellData) + + guard let roomCellContentView = self.roomCellContentView else { + return + } + + if let bubbleData = self.bubbleData, + let paginationDate = bubbleData.date, + roomCellContentView.showPaginationTitle { + roomCellContentView.paginationLabel.text = bubbleData.eventFormatter.dateString(from: paginationDate, withTime: false)?.uppercased() + } + + if roomCellContentView.showEncryptionStatus { + self.updateEncryptionStatusViewImage() + } + + self.updateUserNameColor() + } + + override func customizeRendering() { + super.customizeRendering() + self.updateUserNameColor() + } + + // MARK: - Themable + + func update(theme: Theme) { + self.theme = theme + self.roomCellContentView?.update(theme: theme) + } + + // MARK: - Private + + private func setupViewsIfNeeded() { + guard self.areViewsSetup == false else { + return + } + self.setupViews() + self.areViewsSetup = true + } + + private func setupContentView() { + guard self.roomCellContentView == nil else { + return + } + let roomCellContentView = RoomCellContentView.instantiate() + self.contentView.vc_addSubViewMatchingParent(roomCellContentView) + self.roomCellContentView = roomCellContentView + } + + // MARK: - RoomCellURLPreviewDisplayable + // Cannot use default implementation with ObjC protocol, if self conforms to RoomCellURLPreviewDisplayable method below will be used + + func addURLPreviewView(_ urlPreviewView: UIView) { + self.roomCellContentView?.addURLPreviewView(urlPreviewView) + + // tmpSubviews is used for touch detection in MXKRoomBubbleTableViewCell + self.addTemporarySubview(urlPreviewView) + } + + func removeURLPreviewView() { + self.roomCellContentView?.removeURLPreviewView() + } + + // MARK: - RoomCellReadReceiptsDisplayable + // Cannot use default implementation with ObjC protocol, if self conforms to RoomCellReadReceiptsDisplayable method below will be used + + func addReadReceiptsView(_ readReceiptsView: UIView) { + self.roomCellContentView?.addReadReceiptsView(readReceiptsView) + + // tmpSubviews is used for touch detection in MXKRoomBubbleTableViewCell + self.addTemporarySubview(readReceiptsView) + } + + func removeReadReceiptsView() { + self.roomCellContentView?.removeReadReceiptsView() + } + + // MARK: - RoomCellReactionsDisplayable + // Cannot use default implementation with ObjC protocol, if self conforms to RoomCellReactionsDisplayable method below will be used + + func addReactionsView(_ reactionsView: UIView) { + self.roomCellContentView?.addReactionsView(reactionsView) + + // tmpSubviews is used for touch detection in MXKRoomBubbleTableViewCell + self.addTemporarySubview(reactionsView) + } + + func removeReactionsView() { + self.roomCellContentView?.removeReactionsView() + } + + // MARK: - RoomCellThreadSummaryDisplayable + + func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView) { + self.roomCellContentView?.addThreadSummaryView(threadSummaryView) + + // tmpSubviews is used for touch detection in MXKRoomBubbleTableViewCell + self.addTemporarySubview(threadSummaryView) + } + + func removeThreadSummaryView() { + self.roomCellContentView?.removeThreadSummaryView() + } + + // MARK: - RoomCellReadMarkerDisplayable + + func addReadMarkerView(_ readMarkerView: UIView) { + self.roomCellContentView?.addReadMarkerView(readMarkerView) + self.readMarkerView = readMarkerView + } + + override func removeReadMarkerView() { + self.roomCellContentView?.removeReadMarkerView() + + super.removeReadMarkerView() + } + + // Encryption status + + private func updateEncryptionStatusViewImage() { + guard let component = self.bubbleData.getFirstBubbleComponentWithDisplay() else { + return + } + self.roomCellContentView?.encryptionImageView.image = RoomEncryptedDataBubbleCell.encryptionIcon(for: component) + } + + private func setupEncryptionStatusViewTapGestureRecognizer() { + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleEncryptionStatusContainerViewTap(_:))) + tapGestureRecognizer.delegate = self + self.roomCellContentView?.encryptionImageView.isUserInteractionEnabled = true + } + + @objc private func handleEncryptionStatusContainerViewTap(_ gestureRecognizer: UITapGestureRecognizer) { + guard let delegate = self.delegate else { + return + } + + guard let component = self.bubbleData.getFirstBubbleComponentWithDisplay() else { + return + } + + let userInfo: [AnyHashable: Any]? + + if let tappedEvent = component.event { + userInfo = [kMXKRoomBubbleCellEventKey: tappedEvent] + } else { + userInfo = nil + } + + delegate.cell(self, didRecognizeAction: kRoomEncryptedDataBubbleCellTapOnEncryptionIcon, userInfo: userInfo) + } +} diff --git a/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellContentView.swift b/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellContentView.swift new file mode 100644 index 000000000..e8cc17639 --- /dev/null +++ b/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellContentView.swift @@ -0,0 +1,368 @@ +/* + Copyright 2019 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import UIKit +import Reusable + +/// `RoomCellContentView` is a container view that display the default room message outer views and enables to manage them. Like pagination title, sender info, read receipts, reactions, encryption status. +@objcMembers +final class RoomCellContentView: UIView, NibLoadable { + + // MARK: - Properties + + // MARK: Outlets + + @IBOutlet weak var paginationTitleContainerView: UIView! + @IBOutlet weak var paginationLabel: UILabel! + @IBOutlet weak var paginationSeparatorView: UIView! + + @IBOutlet weak var userNameContainerView: UIView! + @IBOutlet weak var userNameLabel: UILabel! + @IBOutlet weak var userNameTouchMaskView: UIView! + + @IBOutlet weak var userNameLabelTopConstraint: NSLayoutConstraint! + @IBOutlet weak var userNameLabelBottomConstraint: NSLayoutConstraint! + + @IBOutlet weak var avatarContainerView: UIView! + @IBOutlet weak var avatarImageView: MXKImageView! + + @IBOutlet weak var innerContentView: UIView! + + @IBOutlet weak var innerContentViewTopConstraint: NSLayoutConstraint! + @IBOutlet weak var innerContentViewLeadingConstraint: NSLayoutConstraint! + @IBOutlet weak var innerContentViewTrailingConstraint: NSLayoutConstraint! + @IBOutlet weak var innerContentViewBottomContraint: NSLayoutConstraint! + + @IBOutlet weak var encryptionStatusContainerView: UIView! + @IBOutlet weak var encryptionImageView: UIImageView! + + @IBOutlet weak var bubbleInfoContainer: UIView! + @IBOutlet weak var bubbleInfoContainerTopConstraint: NSLayoutConstraint! + + @IBOutlet weak var urlPreviewContainerView: UIView! + @IBOutlet weak var urlPreviewContentView: UIView! + @IBOutlet weak var urlPreviewContentViewLeadingConstraint: NSLayoutConstraint! + @IBOutlet weak var urlPreviewContentViewTrailingConstraint: NSLayoutConstraint! + + @IBOutlet weak var readReceiptsContainerView: UIView! + @IBOutlet weak var readReceiptsContentView: UIView! + + @IBOutlet weak var readMarkerContainerView: UIView! + @IBOutlet weak var readMarkerContentView: UIView! + + var readMarkerViewLeadingConstraint: NSLayoutConstraint? + var readMarkerViewTrailingConstraint: NSLayoutConstraint? + + @IBOutlet weak var reactionsContainerView: UIView! + @IBOutlet weak var reactionsContentView: UIView! + @IBOutlet weak var reactionsContentViewLeadingConstraint: NSLayoutConstraint! + @IBOutlet weak var reactionsContentViewTrailingConstraint: NSLayoutConstraint! + + @IBOutlet weak var threadSummaryContainerView: UIView! + @IBOutlet weak var threadSummaryContentView: UIView! + @IBOutlet weak var threadSummaryContentViewLeadingConstraint: NSLayoutConstraint! + @IBOutlet weak var threadSummaryContentViewTrailingConstraint: NSLayoutConstraint! + @IBOutlet weak var threadSummaryContentViewBottomConstraint: NSLayoutConstraint! + + @IBOutlet weak var bubbleOverlayContainer: UIView! + + // MARK: Private + + private var showURLPreview: Bool { + get { + return !self.urlPreviewContainerView.isHidden + } + set { + self.urlPreviewContainerView.isHidden = !newValue + } + } + + private var showReadReceipts: Bool { + get { + return !self.readReceiptsContainerView.isHidden + } + set { + self.readReceiptsContainerView.isHidden = !newValue + } + } + + private var showReactions: Bool { + get { + return !self.reactionsContainerView.isHidden + } + set { + self.reactionsContainerView.isHidden = !newValue + } + } + + private var showThreadSummary: Bool { + get { + return !self.threadSummaryContainerView.isHidden + } set { + self.threadSummaryContainerView.isHidden = !newValue + } + } + + // MARK: Public + + var showPaginationTitle: Bool { + get { + return !self.paginationTitleContainerView.isHidden + } + set { + self.paginationTitleContainerView.isHidden = !newValue + } + } + + var showSenderInfo: Bool { + get { + return self.showSenderAvatar && self.showSenderName + } + set { + self.showSenderAvatar = newValue + self.showSenderName = newValue + } + } + + var showSenderAvatar: Bool { + get { + return !self.avatarContainerView.isHidden + } + set { + self.avatarContainerView.isHidden = !newValue + } + } + + var showSenderName: Bool { + get { + return !self.userNameContainerView.isHidden + } + set { + self.userNameContainerView.isHidden = !newValue + } + } + + var showEncryptionStatus: Bool { + get { + return !self.encryptionStatusContainerView.isHidden + } + set { + self.encryptionStatusContainerView.isHidden = !newValue + } + } + + var showReadMarker: Bool { + get { + return !self.readMarkerContainerView.isHidden + } + set { + self.readMarkerContainerView.isHidden = !newValue + } + } + + var decorationViewsAlignment: RoomCellDecorationAlignment = .left + + // MARK: - Setup + + class func instantiate() -> RoomCellContentView { + return RoomCellContentView.loadFromNib() + } + + // MARK: - Public + + func update(theme: Theme) { + self.backgroundColor = theme.backgroundColor + self.paginationLabel.textColor = theme.tintColor + self.paginationSeparatorView.backgroundColor = theme.tintColor + } +} + +// MARK: - RoomCellReadReceiptsDisplayable +extension RoomCellContentView: RoomCellReadReceiptsDisplayable { + + func addReadReceiptsView(_ readReceiptsView: UIView) { + self.readReceiptsContentView.vc_removeAllSubviews() + self.readReceiptsContentView.vc_addSubViewMatchingParent(readReceiptsView) + self.showReadReceipts = true + } + + func removeReadReceiptsView() { + self.showReadReceipts = false + self.readReceiptsContentView.vc_removeAllSubviews() + } +} + +// MARK: - RoomCellReactionsDisplayable +extension RoomCellContentView: RoomCellReactionsDisplayable { + + func addReactionsView(_ reactionsView: UIView) { + self.reactionsContentView.vc_removeAllSubviews() + + // Update reactions alignment according to current decoration alignment + if let bubbleReactionsView = reactionsView as? BubbleReactionsView { + + let reactionsAlignment: BubbleReactionsViewAlignment + + switch self.decorationViewsAlignment { + case .left: + reactionsAlignment = .left + case .right: + reactionsAlignment = .right + } + + bubbleReactionsView.alignment = reactionsAlignment + } + + self.reactionsContentView.vc_addSubViewMatchingParent(reactionsView) + + self.showReactions = true + } + + func removeReactionsView() { + self.showReactions = false + self.reactionsContentView.vc_removeAllSubviews() + } +} + +// MARK: - RoomCellThreadSummaryDisplayable +extension RoomCellContentView: RoomCellThreadSummaryDisplayable { + + func addThreadSummaryView(_ threadSummaryView: ThreadSummaryView) { + + guard let containerView = self.threadSummaryContentView else { + return + } + + containerView.vc_removeAllSubviews() + + containerView.translatesAutoresizingMaskIntoConstraints = false + containerView.addSubview(threadSummaryView) + + let leadingConstraint: NSLayoutConstraint + let trailingConstraint: NSLayoutConstraint + + if self.decorationViewsAlignment == .right { + leadingConstraint = threadSummaryView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor) + trailingConstraint = threadSummaryView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor) + } else { + leadingConstraint = threadSummaryView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor) + trailingConstraint = threadSummaryView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor) + } + + NSLayoutConstraint.activate([ + leadingConstraint, + threadSummaryView.topAnchor.constraint(equalTo: containerView.topAnchor), + threadSummaryView.heightAnchor.constraint(equalToConstant: PlainRoomCellLayoutConstants.threadSummaryViewHeight), + threadSummaryView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), + trailingConstraint + ]) + + self.showThreadSummary = true + } + + func removeThreadSummaryView() { + self.showThreadSummary = false + self.threadSummaryContentView.vc_removeAllSubviews() + } +} + +// MARK: - RoomCellURLPreviewDisplayable +extension RoomCellContentView: RoomCellURLPreviewDisplayable { + + func addURLPreviewView(_ urlPreviewView: UIView) { + + guard let containerView = self.urlPreviewContentView else { + return + } + + containerView.vc_removeAllSubviews() + + containerView.translatesAutoresizingMaskIntoConstraints = false + containerView.addSubview(urlPreviewView) + + if let urlPreviewView = urlPreviewView as? URLPreviewView { + urlPreviewView.availableWidth = containerView.frame.width + } + + let leadingConstraint: NSLayoutConstraint + let trailingConstraint: NSLayoutConstraint + + if self.decorationViewsAlignment == .right { + leadingConstraint = urlPreviewView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor) + trailingConstraint = urlPreviewView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor) + } else { + leadingConstraint = urlPreviewView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor) + trailingConstraint = urlPreviewView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor) + } + + NSLayoutConstraint.activate([ + leadingConstraint, + urlPreviewView.topAnchor.constraint(equalTo: containerView.topAnchor), + urlPreviewView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), + trailingConstraint + ]) + + self.showURLPreview = true + } + + func removeURLPreviewView() { + self.showURLPreview = false + self.urlPreviewContentView.vc_removeAllSubviews() + } +} + +// MARK: - RoomCellReadMarkerDisplayable +extension RoomCellContentView: RoomCellReadMarkerDisplayable { + + func addReadMarkerView(_ readMarkerView: UIView) { + guard let containerView = self.readMarkerContainerView else { + return + } + + self.readMarkerContentView.vc_removeAllSubviews() + + readMarkerView.translatesAutoresizingMaskIntoConstraints = false + + self.readMarkerContentView.addSubview(readMarkerView) + + // Force read marker constraints + let topConstraint = readMarkerView.topAnchor.constraint(equalTo: containerView.topAnchor) + + let leadingConstraint = readMarkerView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor) + + let trailingConstraint = readMarkerView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor) + + let heightConstraint = readMarkerView.heightAnchor.constraint(equalToConstant: PlainRoomCellLayoutConstants.readMarkerViewHeight) + + let bottomContraint = readMarkerView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor) + + NSLayoutConstraint.activate([topConstraint, + leadingConstraint, + trailingConstraint, + heightConstraint, + bottomContraint]) + + self.readMarkerViewLeadingConstraint = leadingConstraint + self.readMarkerViewTrailingConstraint = trailingConstraint + + self.showReadMarker = true + } + + func removeReadMarkerView() { + self.showReadMarker = false + self.readMarkerContentView.vc_removeAllSubviews() + } +} diff --git a/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellContentView.xib b/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellContentView.xib similarity index 73% rename from Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellContentView.xib rename to Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellContentView.xib index 999546651..c05e9823a 100644 --- a/Riot/Modules/Room/Views/BubbleCells/BaseBubbleCell/BubbleCellContentView.xib +++ b/Riot/Modules/Room/TimelineCells/BaseRoomCell/RoomCellContentView.xib @@ -9,7 +9,7 @@ - + @@ -17,7 +17,7 @@ - + -