diff --git a/.air.conf b/.air.conf new file mode 100644 index 000000000..7b5a5cb86 --- /dev/null +++ b/.air.conf @@ -0,0 +1,9 @@ +root = "." +tmp_dir = ".air" + +[build] +cmd = "make backend" +bin = "gitea" +include_ext = ["go", "tmpl"] +exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata"] +include_dir = ["cmd", "models", "modules", "options", "routers", "services", "templates"] diff --git a/.drone.yml b/.drone.yml index a18839a49..2ef466fe7 100644 --- a/.drone.yml +++ b/.drone.yml @@ -154,7 +154,7 @@ steps: - name: tag-pre-condition pull: always - image: alpine/git + image: drone/git commands: - git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA} @@ -360,7 +360,7 @@ steps: - name: update pull: default - image: alpine:3.11 + image: alpine:3.12 commands: - ./build/update-locales.sh diff --git a/.editorconfig b/.editorconfig index 5b3a4ff79..6059fa100 100644 --- a/.editorconfig +++ b/.editorconfig @@ -23,3 +23,6 @@ indent_size = 2 [Makefile] indent_style = tab + +[*.svg] +insert_final_newline = false diff --git a/.eslintrc b/.eslintrc index 8f337baec..0adfb7e04 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,15 +1,17 @@ root: true - -extends: - - eslint-config-airbnb-base - - eslint:recommended +reportUnusedDisableDirectives: true ignorePatterns: - /web_src/js/vendor parserOptions: + sourceType: module ecmaVersion: 2020 +plugins: + - eslint-plugin-unicorn + - eslint-plugin-import + env: browser: true es6: true @@ -25,48 +27,361 @@ globals: Tribute: false overrides: - - files: ["web_src/**/*.worker.js"] + - files: ["web_src/**/*worker.js"] env: worker: true rules: - no-restricted-globals: [0] + no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top] + - files: ["build/generate-images.js"] + rules: + import/no-unresolved: [0] + import/no-extraneous-dependencies: [0] rules: + accessor-pairs: [2] + array-bracket-newline: [0] + array-bracket-spacing: [2, never] + array-callback-return: [0] + array-element-newline: [0] arrow-body-style: [0] arrow-parens: [2, always] + arrow-spacing: [2, {before: true, after: true}] + block-scoped-var: [2] + brace-style: [2, 1tbs, {allowSingleLine: true}] camelcase: [0] + capitalized-comments: [0] + class-methods-use-this: [0] comma-dangle: [2, only-multiline] + comma-spacing: [2, {before: false, after: true}] + comma-style: [2, last] + complexity: [0] + computed-property-spacing: [2, never] consistent-return: [0] + consistent-this: [0] + constructor-super: [2] + curly: [0] + default-case-last: [2] default-case: [0] + default-param-last: [0] + dot-location: [2, property] + dot-notation: [0] + eol-last: [2] + eqeqeq: [2] + for-direction: [2] + func-call-spacing: [2, never] + func-name-matching: [2] func-names: [0] + func-style: [0] + function-call-argument-newline: [0] + function-paren-newline: [0] + generator-star-spacing: [0] + getter-return: [2] + grouped-accessor-pairs: [2] + guard-for-in: [0] + id-blacklist: [0] + id-length: [0] + id-match: [0] + implicit-arrow-linebreak: [0] + import/default: [0] + import/dynamic-import-chunkname: [0] + import/export: [2] + import/exports-last: [0] import/extensions: [2, always, {ignorePackages: true}] + import/first: [2] + import/group-exports: [0] + import/max-dependencies: [0] + import/named: [2] + import/namespace: [0] + import/newline-after-import: [0] + import/no-absolute-path: [0] + import/no-amd: [0] + import/no-anonymous-default-export: [0] + import/no-commonjs: [0] + import/no-cycle: [0] + import/no-default-export: [0] + import/no-deprecated: [0] + import/no-dynamic-require: [0] + import/no-extraneous-dependencies: [2] + import/no-internal-modules: [0] + import/no-mutable-exports: [2] + import/no-named-as-default-member: [0] + import/no-named-as-default: [2] + import/no-named-default: [0] + import/no-named-export: [0] + import/no-namespace: [0] + import/no-nodejs-modules: [0] + import/no-relative-parent-imports: [0] + import/no-restricted-paths: [0] + import/no-self-import: [2] + import/no-unassigned-import: [0] + import/no-unresolved: [2, {commonjs: true}] + import/no-unused-modules: [0] + import/no-useless-path-segments: [2, {commonjs: true}] + import/no-webpack-loader-syntax: [2] + import/order: [0] import/prefer-default-export: [0] + import/unambiguous: [0] + indent: [2, 2, {SwitchCase: 1}] + init-declarations: [0] + key-spacing: [2] + keyword-spacing: [2] + line-comment-position: [0] + linebreak-style: [2, unix] + lines-around-comment: [0] + lines-between-class-members: [0] + max-classes-per-file: [0] + max-depth: [0] max-len: [0] + max-lines-per-function: [0] + max-lines: [0] + max-nested-callbacks: [0] + max-params: [0] + max-statements-per-line: [0] + max-statements: [0] multiline-comment-style: [2, separate-lines] + multiline-ternary: [0] + new-cap: [0] + new-parens: [2] newline-per-chained-call: [0] no-alert: [0] + no-array-constructor: [2] + no-async-promise-executor: [2] + no-await-in-loop: [0] + no-bitwise: [0] + no-buffer-constructor: [0] + no-caller: [2] + no-case-declarations: [2] + no-class-assign: [2] + no-compare-neg-zero: [2] no-cond-assign: [2, except-parens] + no-confusing-arrow: [0] no-console: [1, {allow: [info, warn, error]}] + no-const-assign: [2] + no-constant-condition: [0] + no-constructor-return: [2] no-continue: [0] + no-control-regex: [0] + no-debugger: [1] + no-delete-var: [2] + no-div-regex: [0] + no-dupe-args: [2] + no-dupe-class-members: [2] + no-dupe-else-if: [2] + no-dupe-keys: [2] + no-duplicate-case: [2] + no-duplicate-imports: [2] + no-else-return: [2] + no-empty-character-class: [2] + no-empty-function: [0] + no-empty-pattern: [2] + no-empty: [2, {allowEmptyCatch: true}] no-eq-null: [2] + no-eval: [2] + no-ex-assign: [2] + no-extend-native: [2] + no-extra-bind: [2] + no-extra-boolean-cast: [2] + no-extra-label: [0] + no-extra-parens: [0] + no-extra-semi: [2] + no-fallthrough: [2] + no-floating-decimal: [0] + no-func-assign: [2] + no-global-assign: [2] + no-implicit-coercion: [0] + no-implicit-globals: [0] + no-implied-eval: [2] + no-import-assign: [2] + no-inline-comments: [0] + no-inner-declarations: [2] + no-invalid-regexp: [2] + no-invalid-this: [0] + no-irregular-whitespace: [2] + no-iterator: [2] + no-label-var: [2] + no-labels: [2] + no-lone-blocks: [2] + no-lonely-if: [0] + no-loop-func: [0] + no-loss-of-precision: [2] + no-magic-numbers: [0] + no-misleading-character-class: [2] no-mixed-operators: [0] + no-mixed-spaces-and-tabs: [2] no-multi-assign: [0] + no-multi-spaces: [2, {ignoreEOLComments: true, exceptions: {Property: true, VariableDeclarator: true}}] + no-multi-str: [2] + no-negated-condition: [0] + no-nested-ternary: [0] + no-new-func: [2] + no-new-object: [2] + no-new-symbol: [2] + no-new-wrappers: [2] no-new: [0] + no-obj-calls: [2] + no-octal-escape: [2] + no-octal: [2] no-param-reassign: [0] no-plusplus: [0] - no-restricted-syntax: [0] + no-promise-executor-return: [0] + no-proto: [2] + no-prototype-builtins: [2] + no-redeclare: [2] + no-regex-spaces: [2] + no-restricted-exports: [0] + no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top] + no-restricted-imports: [0] + no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement] + no-return-assign: [0] no-return-await: [0] + no-script-url: [2] + no-self-assign: [2, {props: true}] + no-self-compare: [2] + no-sequences: [2] + no-setter-return: [2] + no-shadow-restricted-names: [2] no-shadow: [0] - no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, ignoreRestSiblings: true}] - no-use-before-define: [0] + no-sparse-arrays: [2] + no-tabs: [2] + no-template-curly-in-string: [2] + no-ternary: [0] + no-this-before-super: [2] + no-throw-literal: [2] + no-trailing-spaces: [2] + no-undef-init: [2] + no-undef: [2, {typeof: true}] + no-undefined: [0] + no-underscore-dangle: [0] + no-unexpected-multiline: [2] + no-unmodified-loop-condition: [2] + no-unneeded-ternary: [0] + no-unreachable-loop: [2] + no-unreachable: [2] + no-unsafe-finally: [2] + no-unsafe-negation: [2] + no-unused-expressions: [2] + no-unused-labels: [2] + no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, ignoreRestSiblings: false}] + no-use-before-define: [2, nofunc] + no-useless-backreference: [0] + no-useless-call: [2] + no-useless-catch: [2] + no-useless-computed-key: [2] + no-useless-concat: [2] + no-useless-constructor: [2] + no-useless-escape: [2] + no-useless-rename: [2] + no-useless-return: [2] no-var: [2] + no-void: [2] + no-warning-comments: [0] + no-whitespace-before-property: [2] + no-with: [2] + nonblock-statement-body-position: [2] object-curly-newline: [0] object-curly-spacing: [2, never] + object-shorthand: [2, always] one-var-declaration-per-line: [0] one-var: [0] + operator-assignment: [2, always] operator-linebreak: [2, after] + padded-blocks: [2, never] + padding-line-between-statements: [0] + prefer-arrow-callback: [2, {allowNamedFunctions: true, allowUnboundThis: true}] prefer-const: [2, {destructuring: all}] prefer-destructuring: [0] + prefer-exponentiation-operator: [2] + prefer-named-capture-group: [0] + prefer-numeric-literals: [2] + prefer-object-spread: [0] + prefer-promise-reject-errors: [2, {allowEmptyReject: false}] + prefer-regex-literals: [2] + prefer-rest-params: [2] + prefer-spread: [2] + prefer-template: [2] + quote-props: [0] quotes: [2, single, {avoidEscape: true, allowTemplateLiterals: true}] radix: [2, as-needed] + require-atomic-updates: [0] + require-await: [0] + require-unicode-regexp: [0] + require-yield: [2] + rest-spread-spacing: [2, never] + semi-spacing: [2, {before: false, after: true}] + semi-style: [2, last] semi: [2, always, {omitLastInOneLineBlock: true}] + sort-imports: [0] + sort-keys: [0] + sort-vars: [0] + space-before-blocks: [2, always] + space-in-parens: [2, never] + space-infix-ops: [2] + space-unary-ops: [2] + spaced-comment: [2, always] + strict: [0] + switch-colon-spacing: [2] + symbol-description: [2] + template-curly-spacing: [2, never] + template-tag-spacing: [2, never] + unicode-bom: [2, never] + unicorn/better-regex: [0] + unicorn/catch-error-name: [0] + unicorn/consistent-function-scoping: [2] + unicorn/custom-error-definition: [0] + unicorn/error-message: [0] + unicorn/escape-case: [0] + unicorn/expiring-todo-comments: [0] + unicorn/explicit-length-check: [0] + unicorn/filename-case: [0] + unicorn/import-index: [0] + unicorn/new-for-builtins: [2] + unicorn/no-abusive-eslint-disable: [0] + unicorn/no-array-instanceof: [0] + unicorn/no-console-spaces: [0] + unicorn/no-fn-reference-in-iterator: [0] + unicorn/no-for-loop: [0] + unicorn/no-hex-escape: [0] + unicorn/no-keyword-prefix: [0] + unicorn/no-nested-ternary: [0] + unicorn/no-new-buffer: [0] + unicorn/no-null: [0] + unicorn/no-object-as-default-parameter: [2] + unicorn/no-process-exit: [0] + unicorn/no-reduce: [2] + unicorn/no-unreadable-array-destructuring: [0] + unicorn/no-unsafe-regex: [0] + unicorn/no-unused-properties: [2] + unicorn/no-useless-undefined: [0] + unicorn/no-zero-fractions: [2] + unicorn/number-literal-case: [0] + unicorn/prefer-add-event-listener: [2] + unicorn/prefer-array-find: [2] + unicorn/prefer-dataset: [2] + unicorn/prefer-event-key: [2] + unicorn/prefer-includes: [2] + unicorn/prefer-modern-dom-apis: [0] + unicorn/prefer-negative-index: [2] + unicorn/prefer-node-append: [0] + unicorn/prefer-node-remove: [0] + unicorn/prefer-number-properties: [0] + unicorn/prefer-optional-catch-binding: [2] + unicorn/prefer-query-selector: [0] + unicorn/prefer-reflect-apply: [0] + unicorn/prefer-replace-all: [0] + unicorn/prefer-set-has: [0] + unicorn/prefer-spread: [0] + unicorn/prefer-starts-ends-with: [2] + unicorn/prefer-string-slice: [0] + unicorn/prefer-text-content: [2] + unicorn/prefer-trim-start-end: [2] + unicorn/prefer-type-error: [0] + unicorn/prevent-abbreviations: [0] + unicorn/string-content: [0] + unicorn/throw-new-error: [2] + use-isnan: [2] + valid-typeof: [2, {requireStringLiterals: true}] + vars-on-top: [0] + wrap-iife: [2, inside] + wrap-regex: [0] + yield-star-spacing: [2, after] + yoda: [2, never] diff --git a/.gitattributes b/.gitattributes index f76f5a638..67f7f5237 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,10 +1,3 @@ * text=auto eol=lf -/vendor/** -text -eol -/public/vendor/** -text -eol - -conf/* linguist-vendored -docker/* linguist-vendored -options/* linguist-vendored -public/* linguist-vendored -build/* linguist-vendored -templates/* linguist-vendored +/vendor/** -text -eol linguist-vendored +/public/vendor/** -text -eol linguist-vendored diff --git a/.gitignore b/.gitignore index d14544c72..af522a53c 100644 --- a/.gitignore +++ b/.gitignore @@ -53,7 +53,7 @@ coverage.all /custom/* !/custom/conf /custom/conf/* -!/custom/conf/app.ini.sample +!/custom/conf/app.example.ini /data /indexers /log @@ -76,11 +76,13 @@ coverage.all /node_modules /yarn.lock /public/js +/public/serviceworker.js /public/css /public/fonts -/public/fomantic -/public/img/svg +/public/img/webpack +/web_src/fomantic/build /VERSION +/.air # Snapcraft snap/.snapcraft/ diff --git a/.ignore b/.ignore index cb51f92f7..7decea94e 100644 --- a/.ignore +++ b/.ignore @@ -1,6 +1,5 @@ /vendor /public/vendor/plugins -/public/vendor/assets /modules/options/bindata.go /modules/public/bindata.go /modules/templates/bindata.go diff --git a/.stylelintrc b/.stylelintrc index be1c15bfa..102b90f1f 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -14,3 +14,4 @@ rules: number-leading-zero: never rule-empty-line-before: null selector-pseudo-element-colon-notation: null + shorthand-property-no-redundant-values: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 8147fd00b..351749f94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,16 +4,63 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). -## [1.12.0-rc1](https://github.com/go-gitea/gitea/releases/tag/v1.12.0-rc1) - 2020-05-18 +## [1.12.3](https://github.com/go-gitea/gitea/releases/tag/v1.12.3) - 2020-07-28 + +* BUGFIXES + * Don't change creation date when updating Release (#12343) (#12351) + * Show 404 page when release not found (#12328) (#12332) + * Fix emoji detection in certain cases (#12320) (#12327) + * Reduce emoji size (#12317) (#12327) + * Fix double-indirection bug in logging IDs (#12294) (#12308) + * Link to pull list page on sidebar when view pr (#12256) (#12263) + * Extend Notifications API and return pinned notifications by default (#12164) (#12232) + +## [1.12.2](https://github.com/go-gitea/gitea/releases/tag/v1.12.2) - 2020-07-11 + +* BUGFIXES + * When deleting repository decrese user repository count in cache (#11954) (#12188) + * Return full commit message instead of summary in commits API (#12186) (#12187) + * Properly set HEAD when a repo is created with a default branch that is not named 'master' (#12135) (#12182) + * Ensure GPG Subkeys are verified (#12155) (#12168) + * Fix failing to cache last commit with key being to long (#12151) (#12161) + * Multiple small admin dashboard fixes (#12153) (#12156) + * Remove spurious logging of " Delete all repository archives" at startup (#12139) (#12148) + * Fix repository setup instructions when default branch is not named 'master' (#12122) (#12147) + * Move EventSource to SharedWorker (#12095) (#12130) + * Fix ui bug in wiki commit page (#12089) (#12125) + * Fix gitgraph branch continues after merge (#12044) (#12105) + * Set the base url when migrating from Gitlab using access token or username without password (#11852) (#12104) + * Ensure BlameReaders close at end of request (#12102) (#12103) + * Fix panic when adding review comment (#12058) +* ENHANCEMENTS + * Disable dropzone's timeout for file uploads (#12024) (#12032) + +## [1.12.1](https://github.com/go-gitea/gitea/releases/tag/v1.12.1) - 2020-06-21 + +* BUGFIXES + * Handle multiple merges in gitgraph.js (#11996) (#12000) + * Add serviceworker.js to KnownPublicEntries (#11992) (#11994) + * For language detection do not try to analyze big files by content (#11971) (#11975) +* ENHANCEMENTS + * Fix scrollable header on dropdowns (#11893) (#11965) + +## [1.11.8](https://github.com/go-gitea/gitea/releases/tag/v1.11.8) - 2020-06-21 + +* BUGFIXES + * Really fix __webpack_public_path__ for 1.11 (#11961) + +## [1.12.0](https://github.com/go-gitea/gitea/releases/tag/v1.12.0) - 2020-06-17 * BREAKING - * Remove migration support from versions earlier than 1.6.0 (#10026) + * When using API CreateRelease set created_unix to the tag commit time (#11218) * Enable ENABLE_HARD_LINE_BREAK by default for rendering markdown (#11162) * Fix sanitizer config - multiple rules (#11133) - * When using API CreateRelease set created_unix to the tag commit time (#11218) * Remove check on username when using AccessToken authentication for the API (#11015) * Return 404 from Contents API when items don't exist (#10323) * Notification API should always return a JSON object with the current count of notifications (#10059) + * Remove migration support from versions earlier than 1.6.0 (#10026) +* SECURITY + * Use -1 to disable key algorithm type in ssh.minimum_key_sizes (#11635) (#11662) * FEATURES * Improve config logging when WrappedQueue times out (#11174) * Add branch delete to API (#11112) @@ -55,6 +102,53 @@ been added to each release, please refer to the [blog](https://blog.gitea.io). * Language statistics bar for repositories (#8037) * Restricted users (#6274) * BUGFIXES + * Fix commenting on non-utf8 encoded files (#11916) (#11950) + * Use google/uuid to instead satori/go.uuid (#11943) (#11946) + * Align show/hide outdated button on code review block (#11932) (#11944) + * Update to go-git v5.1.0 (#11936) (#11941) + * Use ID or Where to instead directly use Get when load object from database (#11925) (#11934) + * Update CommitsAhead CommitsBehind on Pull BaseBranch Change too (#11912) (#11915) + * Invalidate comments when file is shortened (#11882) (#11884) + * Rework api/user/repos for pagination (#11827) (#11877) + * Handle more pathological branch and tag names (#11843) (#11863) + * Add doctor check to set IsArchived false if it is null (partial #11853) (#11859) + * Prevent panic on empty HOST for mysql (#11850) (#11856) + * Use DEFAULT_PAGING_NUM instead of MAX_RESPONSE_ITEMS in ListOptions (#11831) (#11836) + * Fix reply octicon (#11821) (#11822) + * Honor DEFAULT_PAGING_NUM for API (#11805) (#11813) + * Ensure rejected push to refs/pull/index/head fails nicely (#11724) (#11809) + * In File Create/Update API return 404 if Branch does not exist (#11791) (#11795) + * Fix doer of rename repo (#11789) (#11794) + * Initialize SimpleMDE when making a code comment (#11749) (#11785) + * Fix timezone on issue deadline (#11697) (#11784) + * Fix to allow comment poster to edit or delete his own comments (#11671) (#11774) + * Show full 500 error in API when Gitea in dev mode (#11641) (#11753) + * Add missing templates for Matrix system webhooks (#11729) (#11748) + * Fix verification of subkeys of default gpg key (#11713) (#11747) + * Fix styling for commiter on diff view (#11715) (#11744) + * Properly truncate system notices (#11714) (#11742) + * Handle expected errors in FileCreate & FileUpdate API (#11643) (#11718) + * Fix missing authorization check on pull for public repos of private/limited org (#11656) (#11682) + * Doctor check & fix db consistency (#11111) (#11676) + * Exclude generated files from language statistics (#11653) (#11670) + * Return json on 500 error from API (#11574) (#11659) + * When must change password only show Signout (#11600) (#11637) + * Backport various styling fixes (#11619) + * Fix wrong milestone in webhook message (#11596) (#11611) + * Fix serviceworker output file and misc improvements (#11562) (#11610) + * When initialising repositories ensure that the user doing the creation is the initializer (#11601) (#11608) + * Prevent empty query parameter being set on dashboard (#11561) (#11604) + * Fix images in wiki edit preview (#11546) (#11602) + * Prevent (caught) panic on login (#11590) (#11597) + * Prevent transferring repos to invisible orgs (#11517) (#11549) + * Move serviceworker to workbox and fix SSE interference (#11538) (#11547) + * API PullReviewComment HTMLPullURL should return the HTMLURL (#11501) (#11533) + * Fix repo-list private and total count bugs (#11500) (#11532) + * Fix form action template substitutions on admin pages (backport #11519) (#11531) + * Fix a bug where the reaction emoji doesn't disappear. (#11489) (#11530) + * TrimSpace when reading InternalToken from a file (#11502) (#11524) + * Fix selected line color in arc-green (#11492) (#11520) + * Make localstorage read ssh or https correctly (#11483) (#11490) * Check branch protection on IsUserAllowedToUpdate (#11448) * Fix margin on attached segment headers when they are separated by other element (#11425) * Fix webhook template when validation errors occur (#11421) @@ -122,6 +216,22 @@ been added to each release, please refer to the [blog](https://blog.gitea.io). * Fix wrong original git service type on a migrated repository (#9693) * Fix ref links in issue overviews for tags (#8742) * ENHANCEMENTS + * Fix search form button overlap (#11840) (#11864) + * Make tabular menu styling consistent for arc-green (#11570) (#11798) + * Add option to API to update PullRequest base branch (#11666) (#11796) + * Increase maximum SQLite variables count to 32766 (#11696) (#11783) + * Update emoji dataset with skin tone variants (#11678) (#11763) + * Add logging to long migrations (#11647) (#11691) + * Change language statistics to save size instead of percentage (#11681) (#11690) + * Allow different HardBreaks settings for documents and comments (#11515) (#11599) + * Fix alignment for commits on dashboard (#11595) (#11680) + * Default MSSQL port 0 to allow automatic detection by default (#11642) (#11673) + * Handle expected errors in AddGPGkey API (#11644) (#11661) + * Close EventSource before unloading the page (#11539) (#11557) + * Ensure emoji render with regular font-weight (#11541) (#11545) + * Fix webpack chunk loading with STATIC_URL_PREFIX (#11526) (#11542) + * Tweak reaction buttons (#11516) + * Use more toned colors for selected line (#11493) (#11511) * Increase width for authors on commit view (#11441) * Hide archived repos by default in repo-list (#11440) * Better styling for code review comment textarea (#11428) @@ -284,6 +394,36 @@ been added to each release, please refer to the [blog](https://blog.gitea.io). * Fix queue log param (#10733) * Add warning when using relative path to app.ini (#10104) +## [1.11.7](https://github.com/go-gitea/gitea/releases/tag/v1.11.7) - 2020-06-18 + +* BUGFIXES + * Use ID or Where to instead directly use Get when load object from database (#11925) (#11935) + * Fix __webpack_public_path__ for 1.11 (#11907) + * Fix verification of subkeys of default gpg key (#11713) (#11902) + * Remove unnecessary parentheses in wiki/view template (#11781) + * Doctor fix xorm.Count nil on sqlite error (#11741) + +## [1.11.6](https://github.com/go-gitea/gitea/releases/tag/v1.11.6) - 2020-05-30 + +* SECURITY + * Fix missing authorization check on pull for public repos of private/limited org (#11656) (#11683) + * Use session for retrieving org teams (#11438) (#11439) +* BUGFIXES + * Return json on 500 error from API (#11574) (#11660) + * Fix wrong milestone in webhook message (#11596) (#11612) + * Prevent (caught) panic on login (#11590) (#11598) + * Fix commit page js error (#11527) + * Use media links for img in post-process (#10515) (#11504) + * Ensure public repositories in private organizations are visible and fix admin organizations list (#11465) (#11475) + * Set correct Content-Type value for Gogs/Gitea webhooks (#9504) (#10456) (#11461) + * Allow all members of private orgs to see public repos (#11442) (#11459) + * Whenever the ctx.Session is updated, release it to save it before sending the redirect (#11456) (#11457) + * Forcibly clean and destroy the session on logout (#11447) (#11451) + * Fix /api/v1/orgs/* endpoints by changing parameter to :org from :orgname (#11381) + * Add tracked time fix to doctor (part of #11111) (#11138) + * Fix webpack chunk loading with STATIC_URL_PREFIX (#11526) (#11544) + * Remove unnecessary parentheses in wiki/revision.tmpl to allow 1.11 to build on go1.14 (#11481) + ## [1.11.5](https://github.com/go-gitea/gitea/releases/tag/v1.11.5) - 2020-05-09 * BUGFIXES diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f6aa05351..2b5ca5620 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -293,25 +293,25 @@ and lead the development of Gitea. To honor the past owners, here's the history of the owners and the time they served: -* 2016-11-04 ~ 2017-12-31 - * [Lunny Xiao](https://github.com/lunny) - * [Thomas Boerger](https://github.com/tboerger) - * [Kim Carlbäcker](https://github.com/bkcsoft) +* 2020-01-01 ~ 2020-12-31 - https://github.com/go-gitea/gitea/issues/9230 + * [Lunny Xiao](https://gitea.com/lunny) + * [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) + * [Matti Ranta](https://gitea.com/techknowlogick) -* 2018-01-01 ~ 2018-12-31 - * [Lunny Xiao](https://github.com/lunny) - * [Lauris Bukšis-Haberkorns](https://github.com/lafriks) - * [Kim Carlbäcker](https://github.com/bkcsoft) - -* 2019-01-01 ~ 2019-12-31 +* 2019-01-01 ~ 2019-12-31 - https://github.com/go-gitea/gitea/issues/5572 * [Lunny Xiao](https://github.com/lunny) * [Lauris Bukšis-Haberkorns](https://github.com/lafriks) * [Matti Ranta](https://github.com/techknowlogick) -* 2020-01-01 ~ 2020-12-31 - * [Lunny Xiao](https://gitea.com/lunny) - * [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) - * [Matti Ranta](https://gitea.com/techknowlogick) +* 2018-01-01 ~ 2018-12-31 - https://github.com/go-gitea/gitea/issues/3255 + * [Lunny Xiao](https://github.com/lunny) + * [Lauris Bukšis-Haberkorns](https://github.com/lafriks) + * [Kim Carlbäcker](https://github.com/bkcsoft) + +* 2016-11-04 ~ 2017-12-31 + * [Lunny Xiao](https://github.com/lunny) + * [Thomas Boerger](https://github.com/tboerger) + * [Kim Carlbäcker](https://github.com/bkcsoft) ## Versions diff --git a/Dockerfile b/Dockerfile index 809385360..a04324c94 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ ################################### #Build stage -FROM golang:1.14-alpine3.11 AS build-env +FROM golang:1.14-alpine3.12 AS build-env ARG GOPROXY ENV GOPROXY ${GOPROXY:-direct} @@ -9,6 +9,7 @@ ENV GOPROXY ${GOPROXY:-direct} ARG GITEA_VERSION ARG TAGS="sqlite sqlite_unlock_notify" ENV TAGS "bindata $TAGS" +ARG CGO_EXTRA_CFLAGS #Build deps RUN apk --no-cache add build-base git nodejs npm @@ -21,7 +22,7 @@ WORKDIR ${GOPATH}/src/code.gitea.io/gitea RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \ && make clean-all build -FROM alpine:3.11 +FROM alpine:3.12 LABEL maintainer="maintainers@gitea.io" EXPOSE 22 3000 diff --git a/MAINTAINERS b/MAINTAINERS index 5ea720032..d805520fd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -36,3 +36,4 @@ Mura Li (@typeless) 6543 <6543@obermui.de> (@6543) jaqra (@jaqra) David Svantesson (@davidsvantesson) +CirnoT (@CirnoT) diff --git a/Makefile b/Makefile index 37c9a46d8..890332fde 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,6 @@ IMPORT := code.gitea.io/gitea export GO111MODULE=on GO ?= go -SED_INPLACE := sed -i SHASUM ?= shasum -a 256 HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" ) COMMA := , @@ -30,23 +29,28 @@ XGO_VERSION := go-1.14.x MIN_GO_VERSION := 001012000 MIN_NODE_VERSION := 010013000 +DOCKER_IMAGE ?= gitea/gitea +DOCKER_TAG ?= latest +DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG) + ifeq ($(HAS_GO), GO) GOPATH ?= $(shell $(GO) env GOPATH) export PATH := $(GOPATH)/bin:$(PATH) -endif + CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766 + CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS) +endif ifeq ($(OS), Windows_NT) EXECUTABLE ?= gitea.exe else EXECUTABLE ?= gitea - UNAME_S := $(shell uname -s) - ifeq ($(UNAME_S),Darwin) - SED_INPLACE := sed -i '' - endif - ifeq ($(UNAME_S),FreeBSD) - SED_INPLACE := sed -i '' - endif +endif + +ifeq ($(shell sed --version 2>/dev/null | grep -q GNU && echo gnu),gnu) + SED_INPLACE := sed -i +else + SED_INPLACE := sed -i '' endif GOFMT ?= gofmt -s @@ -85,14 +89,22 @@ LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(G GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/integrations/migration-test,$(filter-out code.gitea.io/gitea/integrations,$(shell $(GO) list -mod=vendor ./... | grep -v /vendor/))) -WEBPACK_SOURCES := $(shell find web_src/js web_src/less -type f) +FOMANTIC_CONFIGS := semantic.json web_src/fomantic/theme.config.less web_src/fomantic/_site/globals/site.variables +FOMANTIC_DEST := web_src/fomantic/build/semantic.js web_src/fomantic/build/semantic.css +FOMANTIC_DEST_DIR := web_src/fomantic/build + +WEBPACK_SOURCES := $(shell find web_src/js web_src/less -type f) $(FOMANTIC_DEST) WEBPACK_CONFIGS := webpack.config.js WEBPACK_DEST := public/js/index.js public/css/index.css -WEBPACK_DEST_DIRS := public/js public/css public/fonts +WEBPACK_DEST_ENTRIES := public/js public/css public/fonts public/img/webpack public/serviceworker.js BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST)) +SVG_DEST_DIR := public/img/svg + +AIR_TMP_DIR := .air + TAGS ?= TAGS_SPLIT := $(subst $(COMMA), ,$(TAGS)) TAGS_EVIDENCE := $(MAKE_EVIDENCE_DIR)/tags @@ -107,10 +119,6 @@ endif GO_SOURCES_OWN := $(filter-out vendor/% %/bindata.go, $(GO_SOURCES)) -FOMANTIC_CONFIGS := semantic.json web_src/fomantic/theme.config.less web_src/fomantic/_site/globals/site.variables web_src/fomantic/css.js -FOMANTIC_DEST := public/fomantic/semantic.min.js public/fomantic/semantic.min.css -FOMANTIC_DEST_DIR := public/fomantic - #To update swagger use: GO111MODULE=on go get -u github.com/go-swagger/go-swagger/cmd/swagger@v0.20.1 SWAGGER := $(GO) run -mod=vendor github.com/go-swagger/go-swagger/cmd/swagger SWAGGER_SPEC := templates/swagger/v1_json.tmpl @@ -139,8 +147,6 @@ TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1 .PHONY: all all: build -include docker/Makefile - .PHONY: help help: @echo "Make Routines:" @@ -154,7 +160,9 @@ help: @echo " - lint-frontend lint frontend files" @echo " - lint-backend lint backend files" @echo " - watch-frontend watch frontend files and continuously rebuild" + @echo " - watch-backend watch backend files and continuously rebuild" @echo " - webpack build webpack files" + @echo " - svg build svg files" @echo " - fomantic build fomantic files" @echo " - generate run \"go generate\"" @echo " - fmt format the Go code" @@ -194,7 +202,7 @@ node-check: .PHONY: clean-all clean-all: clean - rm -rf $(WEBPACK_DEST_DIRS) $(FOMANTIC_DEST_DIR) + rm -rf $(WEBPACK_DEST_ENTRIES) $(FOMANTIC_DEST_DIR) .PHONY: clean clean: @@ -250,7 +258,7 @@ swagger-validate: .PHONY: errcheck errcheck: @hash errcheck > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u github.com/kisielk/errcheck; \ + GO111MODULE=off $(GO) get -u github.com/kisielk/errcheck; \ fi errcheck $(GO_PACKAGES) @@ -261,14 +269,14 @@ revive: .PHONY: misspell-check misspell-check: @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u github.com/client9/misspell/cmd/misspell; \ + GO111MODULE=off $(GO) get -u github.com/client9/misspell/cmd/misspell; \ fi misspell -error -i unknwon,destory $(GO_SOURCES_OWN) .PHONY: misspell misspell: @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u github.com/client9/misspell/cmd/misspell; \ + GO111MODULE=off $(GO) get -u github.com/client9/misspell/cmd/misspell; \ fi misspell -w -i unknwon $(GO_SOURCES_OWN) @@ -289,14 +297,22 @@ lint: lint-backend lint-frontend lint-backend: golangci-lint revive vet swagger-check swagger-validate test-vendor .PHONY: lint-frontend -lint-frontend: node_modules - npx eslint web_src/js webpack.config.js +lint-frontend: node_modules svg-check + npx eslint web_src/js build webpack.config.js npx stylelint web_src/less .PHONY: watch-frontend -watch-frontend: node_modules +watch-frontend: node-check $(FOMANTIC_DEST) node_modules + rm -rf $(WEBPACK_DEST_ENTRIES) NODE_ENV=development npx webpack --hide-modules --display-entrypoints=false --watch --progress +.PHONY: watch-backend +watch-backend: go-check + @hash air > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ + GO111MODULE=off $(GO) get -u github.com/cosmtrek/air; \ + fi + air -c .air.conf + .PHONY: test test: $(GO) test $(GOTESTFLAGS) -mod=vendor -tags='sqlite sqlite_unlock_notify' $(GO_PACKAGES) @@ -498,7 +514,7 @@ check: test .PHONY: install $(TAGS_PREREQ) install: $(wildcard *.go) - $(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' .PHONY: build build: frontend backend @@ -514,10 +530,10 @@ generate: $(TAGS_PREREQ) CC= GOOS= GOARCH= $(GO) generate -mod=vendor -tags '$(TAGS)' $(GO_PACKAGES) $(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ) - $(GO) build -mod=vendor $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@ + CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build -mod=vendor $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@ .PHONY: release -release: frontend generate release-windows release-linux release-darwin release-copy release-compress release-sources release-check +release: frontend generate release-windows release-linux release-darwin release-copy release-compress release-sources release-docs release-check $(DIST_DIRS): mkdir -p $(DIST_DIRS) @@ -525,9 +541,9 @@ $(DIST_DIRS): .PHONY: release-windows release-windows: | $(DIST_DIRS) @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u src.techknowlogick.com/xgo; \ + GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \ fi - GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) . + CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) . ifeq ($(CI),drone) cp /build/* $(DIST)/binaries endif @@ -535,9 +551,9 @@ endif .PHONY: release-linux release-linux: | $(DIST_DIRS) @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u src.techknowlogick.com/xgo; \ + GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \ fi - GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/mips64le,linux/mips,linux/mipsle' -out gitea-$(VERSION) . + CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/mips64le,linux/mips,linux/mipsle' -out gitea-$(VERSION) . ifeq ($(CI),drone) cp /build/* $(DIST)/binaries endif @@ -545,9 +561,9 @@ endif .PHONY: release-darwin release-darwin: | $(DIST_DIRS) @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - $(GO) get -u src.techknowlogick.com/xgo; \ + GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \ fi - GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/*' -out gitea-$(VERSION) . + CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/*' -out gitea-$(VERSION) . ifeq ($(CI),drone) cp /build/* $(DIST)/binaries endif @@ -570,9 +586,20 @@ release-compress: | $(DIST_DIRS) .PHONY: release-sources release-sources: | $(DIST_DIRS) node_modules echo $(VERSION) > $(STORED_VERSION_FILE) - tar --exclude=./$(DIST) --exclude=./.git --exclude=./$(MAKE_EVIDENCE_DIR) --exclude=./node_modules/.cache -czf $(DIST)/release/gitea-src-$(VERSION).tar.gz . + tar --exclude=./$(DIST) --exclude=./.git --exclude=./$(MAKE_EVIDENCE_DIR) --exclude=./node_modules/.cache --exclude=./$(AIR_TMP_DIR) -czf $(DIST)/release/gitea-src-$(VERSION).tar.gz . rm -f $(STORED_VERSION_FILE) +.PHONY: release-docs +release-docs: | $(DIST_DIRS) docs + tar -czf $(DIST)/release/gitea-docs-$(VERSION).tar.gz -C ./docs/public . + +.PHONY: docs +docs: + @hash hugo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ + $(GO) get -u github.com/gohugoio/hugo; \ + fi + cd docs; make trans-copy clean build-offline; + node_modules: package-lock.json npm install --no-save @touch node_modules @@ -582,15 +609,15 @@ npm-update: node-check | node_modules npx updates -cu rm -rf node_modules package-lock.json npm install --package-lock + @touch node_modules .PHONY: fomantic fomantic: $(FOMANTIC_DEST) -$(FOMANTIC_DEST): $(FOMANTIC_CONFIGS) package-lock.json | node_modules +$(FOMANTIC_DEST): $(FOMANTIC_CONFIGS) | node_modules rm -rf $(FOMANTIC_DEST_DIR) cp web_src/fomantic/theme.config.less node_modules/fomantic-ui/src/theme.config cp -r web_src/fomantic/_site/* node_modules/fomantic-ui/src/_site/ - cp web_src/fomantic/css.js node_modules/fomantic-ui/tasks/build/css.js npx gulp -f node_modules/fomantic-ui/gulpfile.js build @touch $(FOMANTIC_DEST) @@ -598,10 +625,25 @@ $(FOMANTIC_DEST): $(FOMANTIC_CONFIGS) package-lock.json | node_modules webpack: $(WEBPACK_DEST) $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json | node_modules - rm -rf $(WEBPACK_DEST_DIRS) + rm -rf $(WEBPACK_DEST_ENTRIES) npx webpack --hide-modules --display-entrypoints=false @touch $(WEBPACK_DEST) +.PHONY: svg +svg: node-check | node_modules + rm -rf $(SVG_DEST_DIR) + node build/generate-svg.js + +.PHONY: svg-check +svg-check: svg + @git add $(SVG_DEST_DIR) + @diff=$$(git diff --cached $(SVG_DEST_DIR)); \ + if [ -n "$$diff" ]; then \ + echo "Please run 'make svg' and 'git add $(SVG_DEST_DIR)' and commit the result:"; \ + echo "$${diff}"; \ + exit 1; \ + fi; + .PHONY: update-translations update-translations: mkdir -p ./translations @@ -614,34 +656,8 @@ update-translations: .PHONY: generate-images generate-images: - $(eval TMPDIR := $(shell mktemp -d 2>/dev/null || mktemp -d -t 'gitea-temp')) - mkdir -p $(TMPDIR)/images - inkscape -f $(PWD)/assets/logo.svg -w 880 -h 880 -e $(PWD)/public/img/gitea-lg.png - inkscape -f $(PWD)/assets/logo.svg -w 512 -h 512 -e $(PWD)/public/img/gitea-512.png - inkscape -f $(PWD)/assets/logo.svg -w 192 -h 192 -e $(PWD)/public/img/gitea-192.png - inkscape -f $(PWD)/assets/logo.svg -w 120 -h 120 -jC -i layer1 -e $(TMPDIR)/images/sm-1.png - inkscape -f $(PWD)/assets/logo.svg -w 120 -h 120 -jC -i layer2 -e $(TMPDIR)/images/sm-2.png - composite -compose atop $(TMPDIR)/images/sm-2.png $(TMPDIR)/images/sm-1.png $(PWD)/public/img/gitea-sm.png - inkscape -f $(PWD)/assets/logo.svg -w 200 -h 200 -e $(PWD)/public/img/avatar_default.png - inkscape -f $(PWD)/assets/logo.svg -w 180 -h 180 -e $(PWD)/public/img/favicon.png - inkscape -f $(PWD)/assets/logo.svg -w 128 -h 128 -e $(TMPDIR)/images/128-raw.png - inkscape -f $(PWD)/assets/logo.svg -w 64 -h 64 -e $(TMPDIR)/images/64-raw.png - inkscape -f $(PWD)/assets/logo.svg -w 32 -h 32 -jC -i layer1 -e $(TMPDIR)/images/32-1.png - inkscape -f $(PWD)/assets/logo.svg -w 32 -h 32 -jC -i layer2 -e $(TMPDIR)/images/32-2.png - composite -compose atop $(TMPDIR)/images/32-2.png $(TMPDIR)/images/32-1.png $(TMPDIR)/images/32-raw.png - inkscape -f $(PWD)/assets/logo.svg -w 16 -h 16 -jC -i layer1 -e $(TMPDIR)/images/16-raw.png - zopflipng -m -y $(TMPDIR)/images/128-raw.png $(TMPDIR)/images/128.png - zopflipng -m -y $(TMPDIR)/images/64-raw.png $(TMPDIR)/images/64.png - zopflipng -m -y $(TMPDIR)/images/32-raw.png $(TMPDIR)/images/32.png - zopflipng -m -y $(TMPDIR)/images/16-raw.png $(TMPDIR)/images/16.png - rm -f $(TMPDIR)/images/*-*.png - convert $(TMPDIR)/images/16.png $(TMPDIR)/images/32.png \ - $(TMPDIR)/images/64.png $(TMPDIR)/images/128.png \ - $(PWD)/public/img/favicon.ico - convert -flatten $(PWD)/public/img/favicon.png $(PWD)/public/img/apple-touch-icon.png - - rm -rf $(TMPDIR)/images - $(foreach file, $(shell find public/img -type f -name '*.png' ! -name 'loading.png'),zopflipng -m -y $(file) $(file);) + npm install --no-save --no-package-lock xmldom fabric imagemin-zopfli + node build/generate-images.js .PHONY: pr\#% pr\#%: clean-all @@ -655,5 +671,14 @@ golangci-lint: fi golangci-lint run --timeout 5m +.PHONY: docker +docker: + docker build --disable-content-trust=false -t $(DOCKER_REF) . +# support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify" . + +.PHONY: docker-build +docker-build: + docker run -ti --rm -v $(CURDIR):/srv/app/src/code.gitea.io/gitea -w /srv/app/src/code.gitea.io/gitea -e TAGS="bindata $(TAGS)" LDFLAGS="$(LDFLAGS)" CGO_EXTRA_CFLAGS="$(CGO_EXTRA_CFLAGS)" webhippie/golang:edge make clean build + # This endif closes the if at the top of the file endif diff --git a/README.md b/README.md index f5aeaf3ca..7b5c8406b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

logo Gitea - Git with a cup of tea

-[![Build Status](https://drone.gitea.io/api/badges/go-gitea/gitea/status.svg)](https://drone.gitea.io/go-gitea/gitea) +[![Build Status](https://drone.gitea.io/api/badges/go-gitea/gitea/status.svg?ref=refs/heads/master)](https://drone.gitea.io/go-gitea/gitea) [![Join the Discord chat at https://discord.gg/Gitea](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/Gitea) [![](https://images.microbadger.com/badges/image/gitea/gitea.svg)](https://microbadger.com/images/gitea/gitea "Get your own image badge on microbadger.com") [![codecov](https://codecov.io/gh/go-gitea/gitea/branch/master/graph/badge.svg)](https://codecov.io/gh/go-gitea/gitea) @@ -13,6 +13,7 @@ [![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backers/badge.svg?label=backers&color=brightgreen)](https://opencollective.com/gitea) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea) +[![TODOs](https://badgen.net/https/api.tickgit.com/badgen/github.com/go-gitea/gitea)](https://www.tickgit.com/browse?repo=github.com/go-gitea/gitea) ## Purpose diff --git a/assets/emoji.json b/assets/emoji.json index c31490c2c..d28c33cff 100644 --- a/assets/emoji.json +++ b/assets/emoji.json @@ -1 +1 @@ -[{"emoji":"👍","aliases":["+1","thumbsup"]},{"emoji":"👎","aliases":["-1","thumbsdown"]},{"emoji":"💯","aliases":["100"]},{"emoji":"🔢","aliases":["1234"]},{"emoji":"🥇","aliases":["1st_place_medal"]},{"emoji":"🥈","aliases":["2nd_place_medal"]},{"emoji":"🥉","aliases":["3rd_place_medal"]},{"emoji":"🎱","aliases":["8ball"]},{"emoji":"🅰️","aliases":["a"]},{"emoji":"🆎","aliases":["ab"]},{"emoji":"🧮","aliases":["abacus"]},{"emoji":"🔤","aliases":["abc"]},{"emoji":"🔡","aliases":["abcd"]},{"emoji":"🉑","aliases":["accept"]},{"emoji":"🩹","aliases":["adhesive_bandage"]},{"emoji":"🧑","aliases":["adult"]},{"emoji":"🚡","aliases":["aerial_tramway"]},{"emoji":"🇦🇫","aliases":["afghanistan"]},{"emoji":"✈️","aliases":["airplane"]},{"emoji":"🇦🇽","aliases":["aland_islands"]},{"emoji":"⏰","aliases":["alarm_clock"]},{"emoji":"🇦🇱","aliases":["albania"]},{"emoji":"⚗️","aliases":["alembic"]},{"emoji":"🇩🇿","aliases":["algeria"]},{"emoji":"👽","aliases":["alien"]},{"emoji":"🚑","aliases":["ambulance"]},{"emoji":"🇦🇸","aliases":["american_samoa"]},{"emoji":"🏺","aliases":["amphora"]},{"emoji":"⚓","aliases":["anchor"]},{"emoji":"🇦🇩","aliases":["andorra"]},{"emoji":"👼","aliases":["angel"]},{"emoji":"💢","aliases":["anger"]},{"emoji":"🇦🇴","aliases":["angola"]},{"emoji":"😠","aliases":["angry"]},{"emoji":"🇦🇮","aliases":["anguilla"]},{"emoji":"😧","aliases":["anguished"]},{"emoji":"🐜","aliases":["ant"]},{"emoji":"🇦🇶","aliases":["antarctica"]},{"emoji":"🇦🇬","aliases":["antigua_barbuda"]},{"emoji":"🍎","aliases":["apple"]},{"emoji":"♒","aliases":["aquarius"]},{"emoji":"🇦🇷","aliases":["argentina"]},{"emoji":"♈","aliases":["aries"]},{"emoji":"🇦🇲","aliases":["armenia"]},{"emoji":"◀️","aliases":["arrow_backward"]},{"emoji":"⏬","aliases":["arrow_double_down"]},{"emoji":"⏫","aliases":["arrow_double_up"]},{"emoji":"⬇️","aliases":["arrow_down"]},{"emoji":"🔽","aliases":["arrow_down_small"]},{"emoji":"▶️","aliases":["arrow_forward"]},{"emoji":"⤵️","aliases":["arrow_heading_down"]},{"emoji":"⤴️","aliases":["arrow_heading_up"]},{"emoji":"⬅️","aliases":["arrow_left"]},{"emoji":"↙️","aliases":["arrow_lower_left"]},{"emoji":"↘️","aliases":["arrow_lower_right"]},{"emoji":"➡️","aliases":["arrow_right"]},{"emoji":"↪️","aliases":["arrow_right_hook"]},{"emoji":"⬆️","aliases":["arrow_up"]},{"emoji":"↕️","aliases":["arrow_up_down"]},{"emoji":"🔼","aliases":["arrow_up_small"]},{"emoji":"↖️","aliases":["arrow_upper_left"]},{"emoji":"↗️","aliases":["arrow_upper_right"]},{"emoji":"🔃","aliases":["arrows_clockwise"]},{"emoji":"🔄","aliases":["arrows_counterclockwise"]},{"emoji":"🎨","aliases":["art"]},{"emoji":"🚛","aliases":["articulated_lorry"]},{"emoji":"🛰️","aliases":["artificial_satellite"]},{"emoji":"🧑‍🎨","aliases":["artist"]},{"emoji":"🇦🇼","aliases":["aruba"]},{"emoji":"🇦🇨","aliases":["ascension_island"]},{"emoji":"😲","aliases":["astonished"]},{"emoji":"🧑‍🚀","aliases":["astronaut"]},{"emoji":"👟","aliases":["athletic_shoe"]},{"emoji":"🏧","aliases":["atm"]},{"emoji":"⚛️","aliases":["atom_symbol"]},{"emoji":"🇦🇺","aliases":["australia"]},{"emoji":"🇦🇹","aliases":["austria"]},{"emoji":"🛺","aliases":["auto_rickshaw"]},{"emoji":"🥑","aliases":["avocado"]},{"emoji":"🪓","aliases":["axe"]},{"emoji":"🇦🇿","aliases":["azerbaijan"]},{"emoji":"🅱️","aliases":["b"]},{"emoji":"👶","aliases":["baby"]},{"emoji":"🍼","aliases":["baby_bottle"]},{"emoji":"🐤","aliases":["baby_chick"]},{"emoji":"🚼","aliases":["baby_symbol"]},{"emoji":"🔙","aliases":["back"]},{"emoji":"🥓","aliases":["bacon"]},{"emoji":"🦡","aliases":["badger"]},{"emoji":"🏸","aliases":["badminton"]},{"emoji":"🥯","aliases":["bagel"]},{"emoji":"🛄","aliases":["baggage_claim"]},{"emoji":"🥖","aliases":["baguette_bread"]},{"emoji":"🇧🇸","aliases":["bahamas"]},{"emoji":"🇧🇭","aliases":["bahrain"]},{"emoji":"⚖️","aliases":["balance_scale"]},{"emoji":"👨‍🦲","aliases":["bald_man"]},{"emoji":"👩‍🦲","aliases":["bald_woman"]},{"emoji":"🩰","aliases":["ballet_shoes"]},{"emoji":"🎈","aliases":["balloon"]},{"emoji":"🗳️","aliases":["ballot_box"]},{"emoji":"☑️","aliases":["ballot_box_with_check"]},{"emoji":"🎍","aliases":["bamboo"]},{"emoji":"🍌","aliases":["banana"]},{"emoji":"‼️","aliases":["bangbang"]},{"emoji":"🇧🇩","aliases":["bangladesh"]},{"emoji":"🪕","aliases":["banjo"]},{"emoji":"🏦","aliases":["bank"]},{"emoji":"📊","aliases":["bar_chart"]},{"emoji":"🇧🇧","aliases":["barbados"]},{"emoji":"💈","aliases":["barber"]},{"emoji":"⚾","aliases":["baseball"]},{"emoji":"🧺","aliases":["basket"]},{"emoji":"🏀","aliases":["basketball"]},{"emoji":"🦇","aliases":["bat"]},{"emoji":"🛀","aliases":["bath"]},{"emoji":"🛁","aliases":["bathtub"]},{"emoji":"🔋","aliases":["battery"]},{"emoji":"🏖️","aliases":["beach_umbrella"]},{"emoji":"🐻","aliases":["bear"]},{"emoji":"🧔","aliases":["bearded_person"]},{"emoji":"🛏️","aliases":["bed"]},{"emoji":"🐝","aliases":["bee","honeybee"]},{"emoji":"🍺","aliases":["beer"]},{"emoji":"🍻","aliases":["beers"]},{"emoji":"🔰","aliases":["beginner"]},{"emoji":"🇧🇾","aliases":["belarus"]},{"emoji":"🇧🇪","aliases":["belgium"]},{"emoji":"🇧🇿","aliases":["belize"]},{"emoji":"🔔","aliases":["bell"]},{"emoji":"🛎️","aliases":["bellhop_bell"]},{"emoji":"🇧🇯","aliases":["benin"]},{"emoji":"🍱","aliases":["bento"]},{"emoji":"🇧🇲","aliases":["bermuda"]},{"emoji":"🧃","aliases":["beverage_box"]},{"emoji":"🇧🇹","aliases":["bhutan"]},{"emoji":"🚴","aliases":["bicyclist"]},{"emoji":"🚲","aliases":["bike"]},{"emoji":"🚴‍♂️","aliases":["biking_man"]},{"emoji":"🚴‍♀️","aliases":["biking_woman"]},{"emoji":"👙","aliases":["bikini"]},{"emoji":"🧢","aliases":["billed_cap"]},{"emoji":"☣️","aliases":["biohazard"]},{"emoji":"🐦","aliases":["bird"]},{"emoji":"🎂","aliases":["birthday"]},{"emoji":"⚫","aliases":["black_circle"]},{"emoji":"🏴","aliases":["black_flag"]},{"emoji":"🖤","aliases":["black_heart"]},{"emoji":"🃏","aliases":["black_joker"]},{"emoji":"⬛","aliases":["black_large_square"]},{"emoji":"◾","aliases":["black_medium_small_square"]},{"emoji":"◼️","aliases":["black_medium_square"]},{"emoji":"✒️","aliases":["black_nib"]},{"emoji":"▪️","aliases":["black_small_square"]},{"emoji":"🔲","aliases":["black_square_button"]},{"emoji":"👱‍♂️","aliases":["blond_haired_man"]},{"emoji":"👱","aliases":["blond_haired_person"]},{"emoji":"👱‍♀️","aliases":["blond_haired_woman","blonde_woman"]},{"emoji":"🌼","aliases":["blossom"]},{"emoji":"🐡","aliases":["blowfish"]},{"emoji":"📘","aliases":["blue_book"]},{"emoji":"🚙","aliases":["blue_car"]},{"emoji":"💙","aliases":["blue_heart"]},{"emoji":"🟦","aliases":["blue_square"]},{"emoji":"😊","aliases":["blush"]},{"emoji":"🐗","aliases":["boar"]},{"emoji":"⛵","aliases":["boat","sailboat"]},{"emoji":"🇧🇴","aliases":["bolivia"]},{"emoji":"💣","aliases":["bomb"]},{"emoji":"🦴","aliases":["bone"]},{"emoji":"📖","aliases":["book","open_book"]},{"emoji":"🔖","aliases":["bookmark"]},{"emoji":"📑","aliases":["bookmark_tabs"]},{"emoji":"📚","aliases":["books"]},{"emoji":"💥","aliases":["boom","collision"]},{"emoji":"👢","aliases":["boot"]},{"emoji":"🇧🇦","aliases":["bosnia_herzegovina"]},{"emoji":"🇧🇼","aliases":["botswana"]},{"emoji":"⛹️‍♂️","aliases":["bouncing_ball_man","basketball_man"]},{"emoji":"⛹️","aliases":["bouncing_ball_person"]},{"emoji":"⛹️‍♀️","aliases":["bouncing_ball_woman","basketball_woman"]},{"emoji":"💐","aliases":["bouquet"]},{"emoji":"🇧🇻","aliases":["bouvet_island"]},{"emoji":"🙇","aliases":["bow"]},{"emoji":"🏹","aliases":["bow_and_arrow"]},{"emoji":"🙇‍♂️","aliases":["bowing_man"]},{"emoji":"🙇‍♀️","aliases":["bowing_woman"]},{"emoji":"🥣","aliases":["bowl_with_spoon"]},{"emoji":"🎳","aliases":["bowling"]},{"emoji":"🥊","aliases":["boxing_glove"]},{"emoji":"👦","aliases":["boy"]},{"emoji":"🧠","aliases":["brain"]},{"emoji":"🇧🇷","aliases":["brazil"]},{"emoji":"🍞","aliases":["bread"]},{"emoji":"🤱","aliases":["breast_feeding"]},{"emoji":"🧱","aliases":["bricks"]},{"emoji":"🌉","aliases":["bridge_at_night"]},{"emoji":"💼","aliases":["briefcase"]},{"emoji":"🇮🇴","aliases":["british_indian_ocean_territory"]},{"emoji":"🇻🇬","aliases":["british_virgin_islands"]},{"emoji":"🥦","aliases":["broccoli"]},{"emoji":"💔","aliases":["broken_heart"]},{"emoji":"🧹","aliases":["broom"]},{"emoji":"🟤","aliases":["brown_circle"]},{"emoji":"🤎","aliases":["brown_heart"]},{"emoji":"🟫","aliases":["brown_square"]},{"emoji":"🇧🇳","aliases":["brunei"]},{"emoji":"🐛","aliases":["bug"]},{"emoji":"🏗️","aliases":["building_construction"]},{"emoji":"💡","aliases":["bulb"]},{"emoji":"🇧🇬","aliases":["bulgaria"]},{"emoji":"🚅","aliases":["bullettrain_front"]},{"emoji":"🚄","aliases":["bullettrain_side"]},{"emoji":"🇧🇫","aliases":["burkina_faso"]},{"emoji":"🌯","aliases":["burrito"]},{"emoji":"🇧🇮","aliases":["burundi"]},{"emoji":"🚌","aliases":["bus"]},{"emoji":"🕴️","aliases":["business_suit_levitating"]},{"emoji":"🚏","aliases":["busstop"]},{"emoji":"👤","aliases":["bust_in_silhouette"]},{"emoji":"👥","aliases":["busts_in_silhouette"]},{"emoji":"🧈","aliases":["butter"]},{"emoji":"🦋","aliases":["butterfly"]},{"emoji":"🌵","aliases":["cactus"]},{"emoji":"🍰","aliases":["cake"]},{"emoji":"📆","aliases":["calendar"]},{"emoji":"🤙","aliases":["call_me_hand"]},{"emoji":"📲","aliases":["calling"]},{"emoji":"🇰🇭","aliases":["cambodia"]},{"emoji":"🐫","aliases":["camel"]},{"emoji":"📷","aliases":["camera"]},{"emoji":"📸","aliases":["camera_flash"]},{"emoji":"🇨🇲","aliases":["cameroon"]},{"emoji":"🏕️","aliases":["camping"]},{"emoji":"🇨🇦","aliases":["canada"]},{"emoji":"🇮🇨","aliases":["canary_islands"]},{"emoji":"♋","aliases":["cancer"]},{"emoji":"🕯️","aliases":["candle"]},{"emoji":"🍬","aliases":["candy"]},{"emoji":"🥫","aliases":["canned_food"]},{"emoji":"🛶","aliases":["canoe"]},{"emoji":"🇨🇻","aliases":["cape_verde"]},{"emoji":"🔠","aliases":["capital_abcd"]},{"emoji":"♑","aliases":["capricorn"]},{"emoji":"🚗","aliases":["car","red_car"]},{"emoji":"🗃️","aliases":["card_file_box"]},{"emoji":"📇","aliases":["card_index"]},{"emoji":"🗂️","aliases":["card_index_dividers"]},{"emoji":"🇧🇶","aliases":["caribbean_netherlands"]},{"emoji":"🎠","aliases":["carousel_horse"]},{"emoji":"🥕","aliases":["carrot"]},{"emoji":"🤸","aliases":["cartwheeling"]},{"emoji":"🐱","aliases":["cat"]},{"emoji":"🐈","aliases":["cat2"]},{"emoji":"🇰🇾","aliases":["cayman_islands"]},{"emoji":"💿","aliases":["cd"]},{"emoji":"🇨🇫","aliases":["central_african_republic"]},{"emoji":"🇪🇦","aliases":["ceuta_melilla"]},{"emoji":"🇹🇩","aliases":["chad"]},{"emoji":"⛓️","aliases":["chains"]},{"emoji":"🪑","aliases":["chair"]},{"emoji":"🍾","aliases":["champagne"]},{"emoji":"💹","aliases":["chart"]},{"emoji":"📉","aliases":["chart_with_downwards_trend"]},{"emoji":"📈","aliases":["chart_with_upwards_trend"]},{"emoji":"🏁","aliases":["checkered_flag"]},{"emoji":"🧀","aliases":["cheese"]},{"emoji":"🍒","aliases":["cherries"]},{"emoji":"🌸","aliases":["cherry_blossom"]},{"emoji":"♟️","aliases":["chess_pawn"]},{"emoji":"🌰","aliases":["chestnut"]},{"emoji":"🐔","aliases":["chicken"]},{"emoji":"🧒","aliases":["child"]},{"emoji":"🚸","aliases":["children_crossing"]},{"emoji":"🇨🇱","aliases":["chile"]},{"emoji":"🐿️","aliases":["chipmunk"]},{"emoji":"🍫","aliases":["chocolate_bar"]},{"emoji":"🥢","aliases":["chopsticks"]},{"emoji":"🇨🇽","aliases":["christmas_island"]},{"emoji":"🎄","aliases":["christmas_tree"]},{"emoji":"⛪","aliases":["church"]},{"emoji":"🎦","aliases":["cinema"]},{"emoji":"🎪","aliases":["circus_tent"]},{"emoji":"🌇","aliases":["city_sunrise"]},{"emoji":"🌆","aliases":["city_sunset"]},{"emoji":"🏙️","aliases":["cityscape"]},{"emoji":"🆑","aliases":["cl"]},{"emoji":"🗜️","aliases":["clamp"]},{"emoji":"👏","aliases":["clap"]},{"emoji":"🎬","aliases":["clapper"]},{"emoji":"🏛️","aliases":["classical_building"]},{"emoji":"🧗","aliases":["climbing"]},{"emoji":"🧗‍♂️","aliases":["climbing_man"]},{"emoji":"🧗‍♀️","aliases":["climbing_woman"]},{"emoji":"🥂","aliases":["clinking_glasses"]},{"emoji":"📋","aliases":["clipboard"]},{"emoji":"🇨🇵","aliases":["clipperton_island"]},{"emoji":"🕐","aliases":["clock1"]},{"emoji":"🕙","aliases":["clock10"]},{"emoji":"🕥","aliases":["clock1030"]},{"emoji":"🕚","aliases":["clock11"]},{"emoji":"🕦","aliases":["clock1130"]},{"emoji":"🕛","aliases":["clock12"]},{"emoji":"🕧","aliases":["clock1230"]},{"emoji":"🕜","aliases":["clock130"]},{"emoji":"🕑","aliases":["clock2"]},{"emoji":"🕝","aliases":["clock230"]},{"emoji":"🕒","aliases":["clock3"]},{"emoji":"🕞","aliases":["clock330"]},{"emoji":"🕓","aliases":["clock4"]},{"emoji":"🕟","aliases":["clock430"]},{"emoji":"🕔","aliases":["clock5"]},{"emoji":"🕠","aliases":["clock530"]},{"emoji":"🕕","aliases":["clock6"]},{"emoji":"🕡","aliases":["clock630"]},{"emoji":"🕖","aliases":["clock7"]},{"emoji":"🕢","aliases":["clock730"]},{"emoji":"🕗","aliases":["clock8"]},{"emoji":"🕣","aliases":["clock830"]},{"emoji":"🕘","aliases":["clock9"]},{"emoji":"🕤","aliases":["clock930"]},{"emoji":"📕","aliases":["closed_book"]},{"emoji":"🔐","aliases":["closed_lock_with_key"]},{"emoji":"🌂","aliases":["closed_umbrella"]},{"emoji":"☁️","aliases":["cloud"]},{"emoji":"🌩️","aliases":["cloud_with_lightning"]},{"emoji":"⛈️","aliases":["cloud_with_lightning_and_rain"]},{"emoji":"🌧️","aliases":["cloud_with_rain"]},{"emoji":"🌨️","aliases":["cloud_with_snow"]},{"emoji":"🤡","aliases":["clown_face"]},{"emoji":"♣️","aliases":["clubs"]},{"emoji":"🇨🇳","aliases":["cn"]},{"emoji":"🧥","aliases":["coat"]},{"emoji":"🍸","aliases":["cocktail"]},{"emoji":"🥥","aliases":["coconut"]},{"emoji":"🇨🇨","aliases":["cocos_islands"]},{"emoji":"☕","aliases":["coffee"]},{"emoji":"⚰️","aliases":["coffin"]},{"emoji":"🥶","aliases":["cold_face"]},{"emoji":"😰","aliases":["cold_sweat"]},{"emoji":"🇨🇴","aliases":["colombia"]},{"emoji":"☄️","aliases":["comet"]},{"emoji":"🇰🇲","aliases":["comoros"]},{"emoji":"🧭","aliases":["compass"]},{"emoji":"💻","aliases":["computer"]},{"emoji":"🖱️","aliases":["computer_mouse"]},{"emoji":"🎊","aliases":["confetti_ball"]},{"emoji":"😖","aliases":["confounded"]},{"emoji":"😕","aliases":["confused"]},{"emoji":"🇨🇬","aliases":["congo_brazzaville"]},{"emoji":"🇨🇩","aliases":["congo_kinshasa"]},{"emoji":"㊗️","aliases":["congratulations"]},{"emoji":"🚧","aliases":["construction"]},{"emoji":"👷","aliases":["construction_worker"]},{"emoji":"👷‍♂️","aliases":["construction_worker_man"]},{"emoji":"👷‍♀️","aliases":["construction_worker_woman"]},{"emoji":"🎛️","aliases":["control_knobs"]},{"emoji":"🏪","aliases":["convenience_store"]},{"emoji":"🧑‍🍳","aliases":["cook"]},{"emoji":"🇨🇰","aliases":["cook_islands"]},{"emoji":"🍪","aliases":["cookie"]},{"emoji":"🆒","aliases":["cool"]},{"emoji":"🌽","aliases":["corn"]},{"emoji":"🇨🇷","aliases":["costa_rica"]},{"emoji":"🇨🇮","aliases":["cote_divoire"]},{"emoji":"🛋️","aliases":["couch_and_lamp"]},{"emoji":"👫","aliases":["couple"]},{"emoji":"💑","aliases":["couple_with_heart"]},{"emoji":"👨‍❤️‍👨","aliases":["couple_with_heart_man_man"]},{"emoji":"👩‍❤️‍👨","aliases":["couple_with_heart_woman_man"]},{"emoji":"👩‍❤️‍👩","aliases":["couple_with_heart_woman_woman"]},{"emoji":"💏","aliases":["couplekiss"]},{"emoji":"👨‍❤️‍💋‍👨","aliases":["couplekiss_man_man"]},{"emoji":"👩‍❤️‍💋‍👨","aliases":["couplekiss_man_woman"]},{"emoji":"👩‍❤️‍💋‍👩","aliases":["couplekiss_woman_woman"]},{"emoji":"🐮","aliases":["cow"]},{"emoji":"🐄","aliases":["cow2"]},{"emoji":"🤠","aliases":["cowboy_hat_face"]},{"emoji":"🦀","aliases":["crab"]},{"emoji":"🖍️","aliases":["crayon"]},{"emoji":"💳","aliases":["credit_card"]},{"emoji":"🌙","aliases":["crescent_moon"]},{"emoji":"🦗","aliases":["cricket"]},{"emoji":"🏏","aliases":["cricket_game"]},{"emoji":"🇭🇷","aliases":["croatia"]},{"emoji":"🐊","aliases":["crocodile"]},{"emoji":"🥐","aliases":["croissant"]},{"emoji":"🤞","aliases":["crossed_fingers"]},{"emoji":"🎌","aliases":["crossed_flags"]},{"emoji":"⚔️","aliases":["crossed_swords"]},{"emoji":"👑","aliases":["crown"]},{"emoji":"😢","aliases":["cry"]},{"emoji":"😿","aliases":["crying_cat_face"]},{"emoji":"🔮","aliases":["crystal_ball"]},{"emoji":"🇨🇺","aliases":["cuba"]},{"emoji":"🥒","aliases":["cucumber"]},{"emoji":"🥤","aliases":["cup_with_straw"]},{"emoji":"🧁","aliases":["cupcake"]},{"emoji":"💘","aliases":["cupid"]},{"emoji":"🇨🇼","aliases":["curacao"]},{"emoji":"🥌","aliases":["curling_stone"]},{"emoji":"👨‍🦱","aliases":["curly_haired_man"]},{"emoji":"👩‍🦱","aliases":["curly_haired_woman"]},{"emoji":"➰","aliases":["curly_loop"]},{"emoji":"💱","aliases":["currency_exchange"]},{"emoji":"🍛","aliases":["curry"]},{"emoji":"🤬","aliases":["cursing_face"]},{"emoji":"🍮","aliases":["custard"]},{"emoji":"🛃","aliases":["customs"]},{"emoji":"🥩","aliases":["cut_of_meat"]},{"emoji":"🌀","aliases":["cyclone"]},{"emoji":"🇨🇾","aliases":["cyprus"]},{"emoji":"🇨🇿","aliases":["czech_republic"]},{"emoji":"🗡️","aliases":["dagger"]},{"emoji":"👯","aliases":["dancers"]},{"emoji":"👯‍♂️","aliases":["dancing_men"]},{"emoji":"👯‍♀️","aliases":["dancing_women"]},{"emoji":"🍡","aliases":["dango"]},{"emoji":"🕶️","aliases":["dark_sunglasses"]},{"emoji":"🎯","aliases":["dart"]},{"emoji":"💨","aliases":["dash"]},{"emoji":"📅","aliases":["date"]},{"emoji":"🇩🇪","aliases":["de"]},{"emoji":"🧏‍♂️","aliases":["deaf_man"]},{"emoji":"🧏","aliases":["deaf_person"]},{"emoji":"🧏‍♀️","aliases":["deaf_woman"]},{"emoji":"🌳","aliases":["deciduous_tree"]},{"emoji":"🦌","aliases":["deer"]},{"emoji":"🇩🇰","aliases":["denmark"]},{"emoji":"🏬","aliases":["department_store"]},{"emoji":"🏚️","aliases":["derelict_house"]},{"emoji":"🏜️","aliases":["desert"]},{"emoji":"🏝️","aliases":["desert_island"]},{"emoji":"🖥️","aliases":["desktop_computer"]},{"emoji":"🕵️","aliases":["detective"]},{"emoji":"💠","aliases":["diamond_shape_with_a_dot_inside"]},{"emoji":"♦️","aliases":["diamonds"]},{"emoji":"🇩🇬","aliases":["diego_garcia"]},{"emoji":"😞","aliases":["disappointed"]},{"emoji":"😥","aliases":["disappointed_relieved"]},{"emoji":"🤿","aliases":["diving_mask"]},{"emoji":"🪔","aliases":["diya_lamp"]},{"emoji":"💫","aliases":["dizzy"]},{"emoji":"😵","aliases":["dizzy_face"]},{"emoji":"🇩🇯","aliases":["djibouti"]},{"emoji":"🧬","aliases":["dna"]},{"emoji":"🚯","aliases":["do_not_litter"]},{"emoji":"🐶","aliases":["dog"]},{"emoji":"🐕","aliases":["dog2"]},{"emoji":"💵","aliases":["dollar"]},{"emoji":"🎎","aliases":["dolls"]},{"emoji":"🐬","aliases":["dolphin","flipper"]},{"emoji":"🇩🇲","aliases":["dominica"]},{"emoji":"🇩🇴","aliases":["dominican_republic"]},{"emoji":"🚪","aliases":["door"]},{"emoji":"🍩","aliases":["doughnut"]},{"emoji":"🕊️","aliases":["dove"]},{"emoji":"🐉","aliases":["dragon"]},{"emoji":"🐲","aliases":["dragon_face"]},{"emoji":"👗","aliases":["dress"]},{"emoji":"🐪","aliases":["dromedary_camel"]},{"emoji":"🤤","aliases":["drooling_face"]},{"emoji":"🩸","aliases":["drop_of_blood"]},{"emoji":"💧","aliases":["droplet"]},{"emoji":"🥁","aliases":["drum"]},{"emoji":"🦆","aliases":["duck"]},{"emoji":"🥟","aliases":["dumpling"]},{"emoji":"📀","aliases":["dvd"]},{"emoji":"📧","aliases":["e-mail"]},{"emoji":"🦅","aliases":["eagle"]},{"emoji":"👂","aliases":["ear"]},{"emoji":"🌾","aliases":["ear_of_rice"]},{"emoji":"🦻","aliases":["ear_with_hearing_aid"]},{"emoji":"🌍","aliases":["earth_africa"]},{"emoji":"🌎","aliases":["earth_americas"]},{"emoji":"🌏","aliases":["earth_asia"]},{"emoji":"🇪🇨","aliases":["ecuador"]},{"emoji":"🥚","aliases":["egg"]},{"emoji":"🍆","aliases":["eggplant"]},{"emoji":"🇪🇬","aliases":["egypt"]},{"emoji":"✴️","aliases":["eight_pointed_black_star"]},{"emoji":"✳️","aliases":["eight_spoked_asterisk"]},{"emoji":"⏏️","aliases":["eject_button"]},{"emoji":"🇸🇻","aliases":["el_salvador"]},{"emoji":"🔌","aliases":["electric_plug"]},{"emoji":"🐘","aliases":["elephant"]},{"emoji":"🧝","aliases":["elf"]},{"emoji":"🧝‍♂️","aliases":["elf_man"]},{"emoji":"🧝‍♀️","aliases":["elf_woman"]},{"emoji":"✉️","aliases":["email","envelope"]},{"emoji":"🔚","aliases":["end"]},{"emoji":"🏴󠁧󠁢󠁥󠁮󠁧󠁿","aliases":["england"]},{"emoji":"📩","aliases":["envelope_with_arrow"]},{"emoji":"🇬🇶","aliases":["equatorial_guinea"]},{"emoji":"🇪🇷","aliases":["eritrea"]},{"emoji":"🇪🇸","aliases":["es"]},{"emoji":"🇪🇪","aliases":["estonia"]},{"emoji":"🇪🇹","aliases":["ethiopia"]},{"emoji":"🇪🇺","aliases":["eu","european_union"]},{"emoji":"💶","aliases":["euro"]},{"emoji":"🏰","aliases":["european_castle"]},{"emoji":"🏤","aliases":["european_post_office"]},{"emoji":"🌲","aliases":["evergreen_tree"]},{"emoji":"❗","aliases":["exclamation","heavy_exclamation_mark"]},{"emoji":"🤯","aliases":["exploding_head"]},{"emoji":"😑","aliases":["expressionless"]},{"emoji":"👁️","aliases":["eye"]},{"emoji":"👁️‍🗨️","aliases":["eye_speech_bubble"]},{"emoji":"👓","aliases":["eyeglasses"]},{"emoji":"👀","aliases":["eyes"]},{"emoji":"🤕","aliases":["face_with_head_bandage"]},{"emoji":"🤒","aliases":["face_with_thermometer"]},{"emoji":"🤦","aliases":["facepalm"]},{"emoji":"🏭","aliases":["factory"]},{"emoji":"🧑‍🏭","aliases":["factory_worker"]},{"emoji":"🧚","aliases":["fairy"]},{"emoji":"🧚‍♂️","aliases":["fairy_man"]},{"emoji":"🧚‍♀️","aliases":["fairy_woman"]},{"emoji":"🧆","aliases":["falafel"]},{"emoji":"🇫🇰","aliases":["falkland_islands"]},{"emoji":"🍂","aliases":["fallen_leaf"]},{"emoji":"👪","aliases":["family"]},{"emoji":"👨‍👦","aliases":["family_man_boy"]},{"emoji":"👨‍👦‍👦","aliases":["family_man_boy_boy"]},{"emoji":"👨‍👧","aliases":["family_man_girl"]},{"emoji":"👨‍👧‍👦","aliases":["family_man_girl_boy"]},{"emoji":"👨‍👧‍👧","aliases":["family_man_girl_girl"]},{"emoji":"👨‍👨‍👦","aliases":["family_man_man_boy"]},{"emoji":"👨‍👨‍👦‍👦","aliases":["family_man_man_boy_boy"]},{"emoji":"👨‍👨‍👧","aliases":["family_man_man_girl"]},{"emoji":"👨‍👨‍👧‍👦","aliases":["family_man_man_girl_boy"]},{"emoji":"👨‍👨‍👧‍👧","aliases":["family_man_man_girl_girl"]},{"emoji":"👨‍👩‍👦","aliases":["family_man_woman_boy"]},{"emoji":"👨‍👩‍👦‍👦","aliases":["family_man_woman_boy_boy"]},{"emoji":"👨‍👩‍👧","aliases":["family_man_woman_girl"]},{"emoji":"👨‍👩‍👧‍👦","aliases":["family_man_woman_girl_boy"]},{"emoji":"👨‍👩‍👧‍👧","aliases":["family_man_woman_girl_girl"]},{"emoji":"👩‍👦","aliases":["family_woman_boy"]},{"emoji":"👩‍👦‍👦","aliases":["family_woman_boy_boy"]},{"emoji":"👩‍👧","aliases":["family_woman_girl"]},{"emoji":"👩‍👧‍👦","aliases":["family_woman_girl_boy"]},{"emoji":"👩‍👧‍👧","aliases":["family_woman_girl_girl"]},{"emoji":"👩‍👩‍👦","aliases":["family_woman_woman_boy"]},{"emoji":"👩‍👩‍👦‍👦","aliases":["family_woman_woman_boy_boy"]},{"emoji":"👩‍👩‍👧","aliases":["family_woman_woman_girl"]},{"emoji":"👩‍👩‍👧‍👦","aliases":["family_woman_woman_girl_boy"]},{"emoji":"👩‍👩‍👧‍👧","aliases":["family_woman_woman_girl_girl"]},{"emoji":"🧑‍🌾","aliases":["farmer"]},{"emoji":"🇫🇴","aliases":["faroe_islands"]},{"emoji":"⏩","aliases":["fast_forward"]},{"emoji":"📠","aliases":["fax"]},{"emoji":"😨","aliases":["fearful"]},{"emoji":"🐾","aliases":["feet","paw_prints"]},{"emoji":"🕵️‍♀️","aliases":["female_detective"]},{"emoji":"♀️","aliases":["female_sign"]},{"emoji":"🎡","aliases":["ferris_wheel"]},{"emoji":"⛴️","aliases":["ferry"]},{"emoji":"🏑","aliases":["field_hockey"]},{"emoji":"🇫🇯","aliases":["fiji"]},{"emoji":"🗄️","aliases":["file_cabinet"]},{"emoji":"📁","aliases":["file_folder"]},{"emoji":"📽️","aliases":["film_projector"]},{"emoji":"🎞️","aliases":["film_strip"]},{"emoji":"🇫🇮","aliases":["finland"]},{"emoji":"🔥","aliases":["fire"]},{"emoji":"🚒","aliases":["fire_engine"]},{"emoji":"🧯","aliases":["fire_extinguisher"]},{"emoji":"🧨","aliases":["firecracker"]},{"emoji":"🧑‍🚒","aliases":["firefighter"]},{"emoji":"🎆","aliases":["fireworks"]},{"emoji":"🌓","aliases":["first_quarter_moon"]},{"emoji":"🌛","aliases":["first_quarter_moon_with_face"]},{"emoji":"🐟","aliases":["fish"]},{"emoji":"🍥","aliases":["fish_cake"]},{"emoji":"🎣","aliases":["fishing_pole_and_fish"]},{"emoji":"🤛","aliases":["fist_left"]},{"emoji":"👊","aliases":["fist_oncoming","facepunch","punch"]},{"emoji":"✊","aliases":["fist_raised","fist"]},{"emoji":"🤜","aliases":["fist_right"]},{"emoji":"🎏","aliases":["flags"]},{"emoji":"🦩","aliases":["flamingo"]},{"emoji":"🔦","aliases":["flashlight"]},{"emoji":"🥿","aliases":["flat_shoe"]},{"emoji":"⚜️","aliases":["fleur_de_lis"]},{"emoji":"🛬","aliases":["flight_arrival"]},{"emoji":"🛫","aliases":["flight_departure"]},{"emoji":"💾","aliases":["floppy_disk"]},{"emoji":"🎴","aliases":["flower_playing_cards"]},{"emoji":"😳","aliases":["flushed"]},{"emoji":"🥏","aliases":["flying_disc"]},{"emoji":"🛸","aliases":["flying_saucer"]},{"emoji":"🌫️","aliases":["fog"]},{"emoji":"🌁","aliases":["foggy"]},{"emoji":"🦶","aliases":["foot"]},{"emoji":"🏈","aliases":["football"]},{"emoji":"👣","aliases":["footprints"]},{"emoji":"🍴","aliases":["fork_and_knife"]},{"emoji":"🥠","aliases":["fortune_cookie"]},{"emoji":"⛲","aliases":["fountain"]},{"emoji":"🖋️","aliases":["fountain_pen"]},{"emoji":"🍀","aliases":["four_leaf_clover"]},{"emoji":"🦊","aliases":["fox_face"]},{"emoji":"🇫🇷","aliases":["fr"]},{"emoji":"🖼️","aliases":["framed_picture"]},{"emoji":"🆓","aliases":["free"]},{"emoji":"🇬🇫","aliases":["french_guiana"]},{"emoji":"🇵🇫","aliases":["french_polynesia"]},{"emoji":"🇹🇫","aliases":["french_southern_territories"]},{"emoji":"🍳","aliases":["fried_egg"]},{"emoji":"🍤","aliases":["fried_shrimp"]},{"emoji":"🍟","aliases":["fries"]},{"emoji":"🐸","aliases":["frog"]},{"emoji":"😦","aliases":["frowning"]},{"emoji":"☹️","aliases":["frowning_face"]},{"emoji":"🙍‍♂️","aliases":["frowning_man"]},{"emoji":"🙍","aliases":["frowning_person"]},{"emoji":"🙍‍♀️","aliases":["frowning_woman"]},{"emoji":"⛽","aliases":["fuelpump"]},{"emoji":"🌕","aliases":["full_moon"]},{"emoji":"🌝","aliases":["full_moon_with_face"]},{"emoji":"⚱️","aliases":["funeral_urn"]},{"emoji":"🇬🇦","aliases":["gabon"]},{"emoji":"🇬🇲","aliases":["gambia"]},{"emoji":"🎲","aliases":["game_die"]},{"emoji":"🧄","aliases":["garlic"]},{"emoji":"🇬🇧","aliases":["gb","uk"]},{"emoji":"⚙️","aliases":["gear"]},{"emoji":"💎","aliases":["gem"]},{"emoji":"♊","aliases":["gemini"]},{"emoji":"🧞","aliases":["genie"]},{"emoji":"🧞‍♂️","aliases":["genie_man"]},{"emoji":"🧞‍♀️","aliases":["genie_woman"]},{"emoji":"🇬🇪","aliases":["georgia"]},{"emoji":"🇬🇭","aliases":["ghana"]},{"emoji":"👻","aliases":["ghost"]},{"emoji":"🇬🇮","aliases":["gibraltar"]},{"emoji":"🎁","aliases":["gift"]},{"emoji":"💝","aliases":["gift_heart"]},{"emoji":"🦒","aliases":["giraffe"]},{"emoji":"👧","aliases":["girl"]},{"emoji":"🌐","aliases":["globe_with_meridians"]},{"emoji":"🧤","aliases":["gloves"]},{"emoji":"🥅","aliases":["goal_net"]},{"emoji":"🐐","aliases":["goat"]},{"emoji":"🥽","aliases":["goggles"]},{"emoji":"⛳","aliases":["golf"]},{"emoji":"🏌️","aliases":["golfing"]},{"emoji":"🏌️‍♂️","aliases":["golfing_man"]},{"emoji":"🏌️‍♀️","aliases":["golfing_woman"]},{"emoji":"🦍","aliases":["gorilla"]},{"emoji":"🍇","aliases":["grapes"]},{"emoji":"🇬🇷","aliases":["greece"]},{"emoji":"🍏","aliases":["green_apple"]},{"emoji":"📗","aliases":["green_book"]},{"emoji":"🟢","aliases":["green_circle"]},{"emoji":"💚","aliases":["green_heart"]},{"emoji":"🥗","aliases":["green_salad"]},{"emoji":"🟩","aliases":["green_square"]},{"emoji":"🇬🇱","aliases":["greenland"]},{"emoji":"🇬🇩","aliases":["grenada"]},{"emoji":"❕","aliases":["grey_exclamation"]},{"emoji":"❔","aliases":["grey_question"]},{"emoji":"😬","aliases":["grimacing"]},{"emoji":"😁","aliases":["grin"]},{"emoji":"😀","aliases":["grinning"]},{"emoji":"🇬🇵","aliases":["guadeloupe"]},{"emoji":"🇬🇺","aliases":["guam"]},{"emoji":"💂","aliases":["guard"]},{"emoji":"💂‍♂️","aliases":["guardsman"]},{"emoji":"💂‍♀️","aliases":["guardswoman"]},{"emoji":"🇬🇹","aliases":["guatemala"]},{"emoji":"🇬🇬","aliases":["guernsey"]},{"emoji":"🦮","aliases":["guide_dog"]},{"emoji":"🇬🇳","aliases":["guinea"]},{"emoji":"🇬🇼","aliases":["guinea_bissau"]},{"emoji":"🎸","aliases":["guitar"]},{"emoji":"🔫","aliases":["gun"]},{"emoji":"🇬🇾","aliases":["guyana"]},{"emoji":"💇","aliases":["haircut"]},{"emoji":"💇‍♂️","aliases":["haircut_man"]},{"emoji":"💇‍♀️","aliases":["haircut_woman"]},{"emoji":"🇭🇹","aliases":["haiti"]},{"emoji":"🍔","aliases":["hamburger"]},{"emoji":"🔨","aliases":["hammer"]},{"emoji":"⚒️","aliases":["hammer_and_pick"]},{"emoji":"🛠️","aliases":["hammer_and_wrench"]},{"emoji":"🐹","aliases":["hamster"]},{"emoji":"✋","aliases":["hand","raised_hand"]},{"emoji":"🤭","aliases":["hand_over_mouth"]},{"emoji":"👜","aliases":["handbag"]},{"emoji":"🤾","aliases":["handball_person"]},{"emoji":"🤝","aliases":["handshake"]},{"emoji":"💩","aliases":["hankey","poop","shit"]},{"emoji":"🐥","aliases":["hatched_chick"]},{"emoji":"🐣","aliases":["hatching_chick"]},{"emoji":"🎧","aliases":["headphones"]},{"emoji":"🧑‍⚕️","aliases":["health_worker"]},{"emoji":"🙉","aliases":["hear_no_evil"]},{"emoji":"🇭🇲","aliases":["heard_mcdonald_islands"]},{"emoji":"❤️","aliases":["heart"]},{"emoji":"💟","aliases":["heart_decoration"]},{"emoji":"😍","aliases":["heart_eyes"]},{"emoji":"😻","aliases":["heart_eyes_cat"]},{"emoji":"💓","aliases":["heartbeat"]},{"emoji":"💗","aliases":["heartpulse"]},{"emoji":"♥️","aliases":["hearts"]},{"emoji":"✔️","aliases":["heavy_check_mark"]},{"emoji":"➗","aliases":["heavy_division_sign"]},{"emoji":"💲","aliases":["heavy_dollar_sign"]},{"emoji":"❣️","aliases":["heavy_heart_exclamation"]},{"emoji":"➖","aliases":["heavy_minus_sign"]},{"emoji":"✖️","aliases":["heavy_multiplication_x"]},{"emoji":"➕","aliases":["heavy_plus_sign"]},{"emoji":"🦔","aliases":["hedgehog"]},{"emoji":"🚁","aliases":["helicopter"]},{"emoji":"🌿","aliases":["herb"]},{"emoji":"🌺","aliases":["hibiscus"]},{"emoji":"🔆","aliases":["high_brightness"]},{"emoji":"👠","aliases":["high_heel"]},{"emoji":"🥾","aliases":["hiking_boot"]},{"emoji":"🛕","aliases":["hindu_temple"]},{"emoji":"🦛","aliases":["hippopotamus"]},{"emoji":"🔪","aliases":["hocho","knife"]},{"emoji":"🕳️","aliases":["hole"]},{"emoji":"🇭🇳","aliases":["honduras"]},{"emoji":"🍯","aliases":["honey_pot"]},{"emoji":"🇭🇰","aliases":["hong_kong"]},{"emoji":"🐴","aliases":["horse"]},{"emoji":"🏇","aliases":["horse_racing"]},{"emoji":"🏥","aliases":["hospital"]},{"emoji":"🥵","aliases":["hot_face"]},{"emoji":"🌶️","aliases":["hot_pepper"]},{"emoji":"🌭","aliases":["hotdog"]},{"emoji":"🏨","aliases":["hotel"]},{"emoji":"♨️","aliases":["hotsprings"]},{"emoji":"⌛","aliases":["hourglass"]},{"emoji":"⏳","aliases":["hourglass_flowing_sand"]},{"emoji":"🏠","aliases":["house"]},{"emoji":"🏡","aliases":["house_with_garden"]},{"emoji":"🏘️","aliases":["houses"]},{"emoji":"🤗","aliases":["hugs"]},{"emoji":"🇭🇺","aliases":["hungary"]},{"emoji":"😯","aliases":["hushed"]},{"emoji":"🍨","aliases":["ice_cream"]},{"emoji":"🧊","aliases":["ice_cube"]},{"emoji":"🏒","aliases":["ice_hockey"]},{"emoji":"⛸️","aliases":["ice_skate"]},{"emoji":"🍦","aliases":["icecream"]},{"emoji":"🇮🇸","aliases":["iceland"]},{"emoji":"🆔","aliases":["id"]},{"emoji":"🉐","aliases":["ideograph_advantage"]},{"emoji":"👿","aliases":["imp"]},{"emoji":"📥","aliases":["inbox_tray"]},{"emoji":"📨","aliases":["incoming_envelope"]},{"emoji":"🇮🇳","aliases":["india"]},{"emoji":"🇮🇩","aliases":["indonesia"]},{"emoji":"♾️","aliases":["infinity"]},{"emoji":"ℹ️","aliases":["information_source"]},{"emoji":"😇","aliases":["innocent"]},{"emoji":"⁉️","aliases":["interrobang"]},{"emoji":"📱","aliases":["iphone"]},{"emoji":"🇮🇷","aliases":["iran"]},{"emoji":"🇮🇶","aliases":["iraq"]},{"emoji":"🇮🇪","aliases":["ireland"]},{"emoji":"🇮🇲","aliases":["isle_of_man"]},{"emoji":"🇮🇱","aliases":["israel"]},{"emoji":"🇮🇹","aliases":["it"]},{"emoji":"🏮","aliases":["izakaya_lantern","lantern"]},{"emoji":"🎃","aliases":["jack_o_lantern"]},{"emoji":"🇯🇲","aliases":["jamaica"]},{"emoji":"🗾","aliases":["japan"]},{"emoji":"🏯","aliases":["japanese_castle"]},{"emoji":"👺","aliases":["japanese_goblin"]},{"emoji":"👹","aliases":["japanese_ogre"]},{"emoji":"👖","aliases":["jeans"]},{"emoji":"🇯🇪","aliases":["jersey"]},{"emoji":"🧩","aliases":["jigsaw"]},{"emoji":"🇯🇴","aliases":["jordan"]},{"emoji":"😂","aliases":["joy"]},{"emoji":"😹","aliases":["joy_cat"]},{"emoji":"🕹️","aliases":["joystick"]},{"emoji":"🇯🇵","aliases":["jp"]},{"emoji":"🧑‍⚖️","aliases":["judge"]},{"emoji":"🤹","aliases":["juggling_person"]},{"emoji":"🕋","aliases":["kaaba"]},{"emoji":"🦘","aliases":["kangaroo"]},{"emoji":"🇰🇿","aliases":["kazakhstan"]},{"emoji":"🇰🇪","aliases":["kenya"]},{"emoji":"🔑","aliases":["key"]},{"emoji":"⌨️","aliases":["keyboard"]},{"emoji":"🛴","aliases":["kick_scooter"]},{"emoji":"👘","aliases":["kimono"]},{"emoji":"🇰🇮","aliases":["kiribati"]},{"emoji":"💋","aliases":["kiss"]},{"emoji":"😗","aliases":["kissing"]},{"emoji":"😽","aliases":["kissing_cat"]},{"emoji":"😚","aliases":["kissing_closed_eyes"]},{"emoji":"😘","aliases":["kissing_heart"]},{"emoji":"😙","aliases":["kissing_smiling_eyes"]},{"emoji":"🪁","aliases":["kite"]},{"emoji":"🥝","aliases":["kiwi_fruit"]},{"emoji":"🧎‍♂️","aliases":["kneeling_man"]},{"emoji":"🧎","aliases":["kneeling_person"]},{"emoji":"🧎‍♀️","aliases":["kneeling_woman"]},{"emoji":"🐨","aliases":["koala"]},{"emoji":"🈁","aliases":["koko"]},{"emoji":"🇽🇰","aliases":["kosovo"]},{"emoji":"🇰🇷","aliases":["kr"]},{"emoji":"🇰🇼","aliases":["kuwait"]},{"emoji":"🇰🇬","aliases":["kyrgyzstan"]},{"emoji":"🥼","aliases":["lab_coat"]},{"emoji":"🏷️","aliases":["label"]},{"emoji":"🥍","aliases":["lacrosse"]},{"emoji":"🐞","aliases":["lady_beetle"]},{"emoji":"🇱🇦","aliases":["laos"]},{"emoji":"🔵","aliases":["large_blue_circle"]},{"emoji":"🔷","aliases":["large_blue_diamond"]},{"emoji":"🔶","aliases":["large_orange_diamond"]},{"emoji":"🌗","aliases":["last_quarter_moon"]},{"emoji":"🌜","aliases":["last_quarter_moon_with_face"]},{"emoji":"✝️","aliases":["latin_cross"]},{"emoji":"🇱🇻","aliases":["latvia"]},{"emoji":"😆","aliases":["laughing","satisfied","laugh"]},{"emoji":"🥬","aliases":["leafy_green"]},{"emoji":"🍃","aliases":["leaves"]},{"emoji":"🇱🇧","aliases":["lebanon"]},{"emoji":"📒","aliases":["ledger"]},{"emoji":"🛅","aliases":["left_luggage"]},{"emoji":"↔️","aliases":["left_right_arrow"]},{"emoji":"🗨️","aliases":["left_speech_bubble"]},{"emoji":"↩️","aliases":["leftwards_arrow_with_hook"]},{"emoji":"🦵","aliases":["leg"]},{"emoji":"🍋","aliases":["lemon"]},{"emoji":"♌","aliases":["leo"]},{"emoji":"🐆","aliases":["leopard"]},{"emoji":"🇱🇸","aliases":["lesotho"]},{"emoji":"🎚️","aliases":["level_slider"]},{"emoji":"🇱🇷","aliases":["liberia"]},{"emoji":"♎","aliases":["libra"]},{"emoji":"🇱🇾","aliases":["libya"]},{"emoji":"🇱🇮","aliases":["liechtenstein"]},{"emoji":"🚈","aliases":["light_rail"]},{"emoji":"🔗","aliases":["link"]},{"emoji":"🦁","aliases":["lion"]},{"emoji":"👄","aliases":["lips"]},{"emoji":"💄","aliases":["lipstick"]},{"emoji":"🇱🇹","aliases":["lithuania"]},{"emoji":"🦎","aliases":["lizard"]},{"emoji":"🦙","aliases":["llama"]},{"emoji":"🦞","aliases":["lobster"]},{"emoji":"🔒","aliases":["lock"]},{"emoji":"🔏","aliases":["lock_with_ink_pen"]},{"emoji":"🍭","aliases":["lollipop"]},{"emoji":"➿","aliases":["loop"]},{"emoji":"🧴","aliases":["lotion_bottle"]},{"emoji":"🧘","aliases":["lotus_position"]},{"emoji":"🧘‍♂️","aliases":["lotus_position_man"]},{"emoji":"🧘‍♀️","aliases":["lotus_position_woman"]},{"emoji":"🔊","aliases":["loud_sound"]},{"emoji":"📢","aliases":["loudspeaker"]},{"emoji":"🏩","aliases":["love_hotel"]},{"emoji":"💌","aliases":["love_letter"]},{"emoji":"🤟","aliases":["love_you_gesture"]},{"emoji":"🔅","aliases":["low_brightness"]},{"emoji":"🧳","aliases":["luggage"]},{"emoji":"🇱🇺","aliases":["luxembourg"]},{"emoji":"🤥","aliases":["lying_face"]},{"emoji":"Ⓜ️","aliases":["m"]},{"emoji":"🇲🇴","aliases":["macau"]},{"emoji":"🇲🇰","aliases":["macedonia"]},{"emoji":"🇲🇬","aliases":["madagascar"]},{"emoji":"🔍","aliases":["mag"]},{"emoji":"🔎","aliases":["mag_right"]},{"emoji":"🧙","aliases":["mage"]},{"emoji":"🧙‍♂️","aliases":["mage_man"]},{"emoji":"🧙‍♀️","aliases":["mage_woman"]},{"emoji":"🧲","aliases":["magnet"]},{"emoji":"🀄","aliases":["mahjong"]},{"emoji":"📫","aliases":["mailbox"]},{"emoji":"📪","aliases":["mailbox_closed"]},{"emoji":"📬","aliases":["mailbox_with_mail"]},{"emoji":"📭","aliases":["mailbox_with_no_mail"]},{"emoji":"🇲🇼","aliases":["malawi"]},{"emoji":"🇲🇾","aliases":["malaysia"]},{"emoji":"🇲🇻","aliases":["maldives"]},{"emoji":"🕵️‍♂️","aliases":["male_detective"]},{"emoji":"♂️","aliases":["male_sign"]},{"emoji":"🇲🇱","aliases":["mali"]},{"emoji":"🇲🇹","aliases":["malta"]},{"emoji":"👨","aliases":["man"]},{"emoji":"👨‍🎨","aliases":["man_artist"]},{"emoji":"👨‍🚀","aliases":["man_astronaut"]},{"emoji":"🤸‍♂️","aliases":["man_cartwheeling"]},{"emoji":"👨‍🍳","aliases":["man_cook"]},{"emoji":"🕺","aliases":["man_dancing"]},{"emoji":"🤦‍♂️","aliases":["man_facepalming"]},{"emoji":"👨‍🏭","aliases":["man_factory_worker"]},{"emoji":"👨‍🌾","aliases":["man_farmer"]},{"emoji":"👨‍🚒","aliases":["man_firefighter"]},{"emoji":"👨‍⚕️","aliases":["man_health_worker"]},{"emoji":"👨‍🦽","aliases":["man_in_manual_wheelchair"]},{"emoji":"👨‍🦼","aliases":["man_in_motorized_wheelchair"]},{"emoji":"👨‍⚖️","aliases":["man_judge"]},{"emoji":"🤹‍♂️","aliases":["man_juggling"]},{"emoji":"👨‍🔧","aliases":["man_mechanic"]},{"emoji":"👨‍💼","aliases":["man_office_worker"]},{"emoji":"👨‍✈️","aliases":["man_pilot"]},{"emoji":"🤾‍♂️","aliases":["man_playing_handball"]},{"emoji":"🤽‍♂️","aliases":["man_playing_water_polo"]},{"emoji":"👨‍🔬","aliases":["man_scientist"]},{"emoji":"🤷‍♂️","aliases":["man_shrugging"]},{"emoji":"👨‍🎤","aliases":["man_singer"]},{"emoji":"👨‍🎓","aliases":["man_student"]},{"emoji":"👨‍🏫","aliases":["man_teacher"]},{"emoji":"👨‍💻","aliases":["man_technologist"]},{"emoji":"👲","aliases":["man_with_gua_pi_mao"]},{"emoji":"👨‍🦯","aliases":["man_with_probing_cane"]},{"emoji":"👳‍♂️","aliases":["man_with_turban"]},{"emoji":"🥭","aliases":["mango"]},{"emoji":"👞","aliases":["mans_shoe","shoe"]},{"emoji":"🕰️","aliases":["mantelpiece_clock"]},{"emoji":"🦽","aliases":["manual_wheelchair"]},{"emoji":"🍁","aliases":["maple_leaf"]},{"emoji":"🇲🇭","aliases":["marshall_islands"]},{"emoji":"🥋","aliases":["martial_arts_uniform"]},{"emoji":"🇲🇶","aliases":["martinique"]},{"emoji":"😷","aliases":["mask"]},{"emoji":"💆","aliases":["massage"]},{"emoji":"💆‍♂️","aliases":["massage_man"]},{"emoji":"💆‍♀️","aliases":["massage_woman"]},{"emoji":"🧉","aliases":["mate"]},{"emoji":"🇲🇷","aliases":["mauritania"]},{"emoji":"🇲🇺","aliases":["mauritius"]},{"emoji":"🇾🇹","aliases":["mayotte"]},{"emoji":"🍖","aliases":["meat_on_bone"]},{"emoji":"🧑‍🔧","aliases":["mechanic"]},{"emoji":"🦾","aliases":["mechanical_arm"]},{"emoji":"🦿","aliases":["mechanical_leg"]},{"emoji":"🎖️","aliases":["medal_military"]},{"emoji":"🏅","aliases":["medal_sports"]},{"emoji":"⚕️","aliases":["medical_symbol"]},{"emoji":"📣","aliases":["mega"]},{"emoji":"🍈","aliases":["melon"]},{"emoji":"📝","aliases":["memo","pencil"]},{"emoji":"🤼‍♂️","aliases":["men_wrestling"]},{"emoji":"🕎","aliases":["menorah"]},{"emoji":"🚹","aliases":["mens"]},{"emoji":"🧜‍♀️","aliases":["mermaid"]},{"emoji":"🧜‍♂️","aliases":["merman"]},{"emoji":"🧜","aliases":["merperson"]},{"emoji":"🤘","aliases":["metal"]},{"emoji":"🚇","aliases":["metro"]},{"emoji":"🇲🇽","aliases":["mexico"]},{"emoji":"🦠","aliases":["microbe"]},{"emoji":"🇫🇲","aliases":["micronesia"]},{"emoji":"🎤","aliases":["microphone"]},{"emoji":"🔬","aliases":["microscope"]},{"emoji":"🖕","aliases":["middle_finger","fu"]},{"emoji":"🥛","aliases":["milk_glass"]},{"emoji":"🌌","aliases":["milky_way"]},{"emoji":"🚐","aliases":["minibus"]},{"emoji":"💽","aliases":["minidisc"]},{"emoji":"📴","aliases":["mobile_phone_off"]},{"emoji":"🇲🇩","aliases":["moldova"]},{"emoji":"🇲🇨","aliases":["monaco"]},{"emoji":"🤑","aliases":["money_mouth_face"]},{"emoji":"💸","aliases":["money_with_wings"]},{"emoji":"💰","aliases":["moneybag"]},{"emoji":"🇲🇳","aliases":["mongolia"]},{"emoji":"🐒","aliases":["monkey"]},{"emoji":"🐵","aliases":["monkey_face"]},{"emoji":"🧐","aliases":["monocle_face"]},{"emoji":"🚝","aliases":["monorail"]},{"emoji":"🇲🇪","aliases":["montenegro"]},{"emoji":"🇲🇸","aliases":["montserrat"]},{"emoji":"🌔","aliases":["moon","waxing_gibbous_moon"]},{"emoji":"🥮","aliases":["moon_cake"]},{"emoji":"🇲🇦","aliases":["morocco"]},{"emoji":"🎓","aliases":["mortar_board"]},{"emoji":"🕌","aliases":["mosque"]},{"emoji":"🦟","aliases":["mosquito"]},{"emoji":"🛥️","aliases":["motor_boat"]},{"emoji":"🛵","aliases":["motor_scooter"]},{"emoji":"🏍️","aliases":["motorcycle"]},{"emoji":"🦼","aliases":["motorized_wheelchair"]},{"emoji":"🛣️","aliases":["motorway"]},{"emoji":"🗻","aliases":["mount_fuji"]},{"emoji":"⛰️","aliases":["mountain"]},{"emoji":"🚵","aliases":["mountain_bicyclist"]},{"emoji":"🚵‍♂️","aliases":["mountain_biking_man"]},{"emoji":"🚵‍♀️","aliases":["mountain_biking_woman"]},{"emoji":"🚠","aliases":["mountain_cableway"]},{"emoji":"🚞","aliases":["mountain_railway"]},{"emoji":"🏔️","aliases":["mountain_snow"]},{"emoji":"🐭","aliases":["mouse"]},{"emoji":"🐁","aliases":["mouse2"]},{"emoji":"🎥","aliases":["movie_camera"]},{"emoji":"🗿","aliases":["moyai"]},{"emoji":"🇲🇿","aliases":["mozambique"]},{"emoji":"🤶","aliases":["mrs_claus"]},{"emoji":"💪","aliases":["muscle"]},{"emoji":"🍄","aliases":["mushroom"]},{"emoji":"🎹","aliases":["musical_keyboard"]},{"emoji":"🎵","aliases":["musical_note"]},{"emoji":"🎼","aliases":["musical_score"]},{"emoji":"🔇","aliases":["mute"]},{"emoji":"🇲🇲","aliases":["myanmar"]},{"emoji":"💅","aliases":["nail_care"]},{"emoji":"📛","aliases":["name_badge"]},{"emoji":"🇳🇦","aliases":["namibia"]},{"emoji":"🏞️","aliases":["national_park"]},{"emoji":"🇳🇷","aliases":["nauru"]},{"emoji":"🤢","aliases":["nauseated_face"]},{"emoji":"🧿","aliases":["nazar_amulet"]},{"emoji":"👔","aliases":["necktie"]},{"emoji":"❎","aliases":["negative_squared_cross_mark"]},{"emoji":"🇳🇵","aliases":["nepal"]},{"emoji":"🤓","aliases":["nerd_face"]},{"emoji":"🇳🇱","aliases":["netherlands"]},{"emoji":"😐","aliases":["neutral_face"]},{"emoji":"🆕","aliases":["new"]},{"emoji":"🇳🇨","aliases":["new_caledonia"]},{"emoji":"🌑","aliases":["new_moon"]},{"emoji":"🌚","aliases":["new_moon_with_face"]},{"emoji":"🇳🇿","aliases":["new_zealand"]},{"emoji":"📰","aliases":["newspaper"]},{"emoji":"🗞️","aliases":["newspaper_roll"]},{"emoji":"⏭️","aliases":["next_track_button"]},{"emoji":"🆖","aliases":["ng"]},{"emoji":"🇳🇮","aliases":["nicaragua"]},{"emoji":"🇳🇪","aliases":["niger"]},{"emoji":"🇳🇬","aliases":["nigeria"]},{"emoji":"🌃","aliases":["night_with_stars"]},{"emoji":"🇳🇺","aliases":["niue"]},{"emoji":"🔕","aliases":["no_bell"]},{"emoji":"🚳","aliases":["no_bicycles"]},{"emoji":"⛔","aliases":["no_entry"]},{"emoji":"🚫","aliases":["no_entry_sign"]},{"emoji":"🙅","aliases":["no_good"]},{"emoji":"🙅‍♂️","aliases":["no_good_man","ng_man"]},{"emoji":"🙅‍♀️","aliases":["no_good_woman","ng_woman"]},{"emoji":"📵","aliases":["no_mobile_phones"]},{"emoji":"😶","aliases":["no_mouth"]},{"emoji":"🚷","aliases":["no_pedestrians"]},{"emoji":"🚭","aliases":["no_smoking"]},{"emoji":"🚱","aliases":["non-potable_water"]},{"emoji":"🇳🇫","aliases":["norfolk_island"]},{"emoji":"🇰🇵","aliases":["north_korea"]},{"emoji":"🇲🇵","aliases":["northern_mariana_islands"]},{"emoji":"🇳🇴","aliases":["norway"]},{"emoji":"👃","aliases":["nose"]},{"emoji":"📓","aliases":["notebook"]},{"emoji":"📔","aliases":["notebook_with_decorative_cover"]},{"emoji":"🎶","aliases":["notes"]},{"emoji":"🔩","aliases":["nut_and_bolt"]},{"emoji":"⭕","aliases":["o"]},{"emoji":"🅾️","aliases":["o2"]},{"emoji":"🌊","aliases":["ocean"]},{"emoji":"🐙","aliases":["octopus"]},{"emoji":"🍢","aliases":["oden"]},{"emoji":"🏢","aliases":["office"]},{"emoji":"🧑‍💼","aliases":["office_worker"]},{"emoji":"🛢️","aliases":["oil_drum"]},{"emoji":"🆗","aliases":["ok"]},{"emoji":"👌","aliases":["ok_hand"]},{"emoji":"🙆‍♂️","aliases":["ok_man"]},{"emoji":"🙆","aliases":["ok_person"]},{"emoji":"🙆‍♀️","aliases":["ok_woman"]},{"emoji":"🗝️","aliases":["old_key"]},{"emoji":"🧓","aliases":["older_adult"]},{"emoji":"👴","aliases":["older_man"]},{"emoji":"👵","aliases":["older_woman"]},{"emoji":"🕉️","aliases":["om"]},{"emoji":"🇴🇲","aliases":["oman"]},{"emoji":"🔛","aliases":["on"]},{"emoji":"🚘","aliases":["oncoming_automobile"]},{"emoji":"🚍","aliases":["oncoming_bus"]},{"emoji":"🚔","aliases":["oncoming_police_car"]},{"emoji":"🚖","aliases":["oncoming_taxi"]},{"emoji":"🩱","aliases":["one_piece_swimsuit"]},{"emoji":"🧅","aliases":["onion"]},{"emoji":"📂","aliases":["open_file_folder"]},{"emoji":"👐","aliases":["open_hands"]},{"emoji":"😮","aliases":["open_mouth"]},{"emoji":"☂️","aliases":["open_umbrella"]},{"emoji":"⛎","aliases":["ophiuchus"]},{"emoji":"📙","aliases":["orange_book"]},{"emoji":"🟠","aliases":["orange_circle"]},{"emoji":"🧡","aliases":["orange_heart"]},{"emoji":"🟧","aliases":["orange_square"]},{"emoji":"🦧","aliases":["orangutan"]},{"emoji":"☦️","aliases":["orthodox_cross"]},{"emoji":"🦦","aliases":["otter"]},{"emoji":"📤","aliases":["outbox_tray"]},{"emoji":"🦉","aliases":["owl"]},{"emoji":"🐂","aliases":["ox"]},{"emoji":"🦪","aliases":["oyster"]},{"emoji":"📦","aliases":["package"]},{"emoji":"📄","aliases":["page_facing_up"]},{"emoji":"📃","aliases":["page_with_curl"]},{"emoji":"📟","aliases":["pager"]},{"emoji":"🖌️","aliases":["paintbrush"]},{"emoji":"🇵🇰","aliases":["pakistan"]},{"emoji":"🇵🇼","aliases":["palau"]},{"emoji":"🇵🇸","aliases":["palestinian_territories"]},{"emoji":"🌴","aliases":["palm_tree"]},{"emoji":"🤲","aliases":["palms_up_together"]},{"emoji":"🇵🇦","aliases":["panama"]},{"emoji":"🥞","aliases":["pancakes"]},{"emoji":"🐼","aliases":["panda_face"]},{"emoji":"📎","aliases":["paperclip"]},{"emoji":"🖇️","aliases":["paperclips"]},{"emoji":"🇵🇬","aliases":["papua_new_guinea"]},{"emoji":"🪂","aliases":["parachute"]},{"emoji":"🇵🇾","aliases":["paraguay"]},{"emoji":"⛱️","aliases":["parasol_on_ground"]},{"emoji":"🅿️","aliases":["parking"]},{"emoji":"🦜","aliases":["parrot"]},{"emoji":"〽️","aliases":["part_alternation_mark"]},{"emoji":"⛅","aliases":["partly_sunny"]},{"emoji":"🥳","aliases":["partying_face"]},{"emoji":"🛳️","aliases":["passenger_ship"]},{"emoji":"🛂","aliases":["passport_control"]},{"emoji":"⏸️","aliases":["pause_button"]},{"emoji":"☮️","aliases":["peace_symbol"]},{"emoji":"🍑","aliases":["peach"]},{"emoji":"🦚","aliases":["peacock"]},{"emoji":"🥜","aliases":["peanuts"]},{"emoji":"🍐","aliases":["pear"]},{"emoji":"🖊️","aliases":["pen"]},{"emoji":"✏️","aliases":["pencil2"]},{"emoji":"🐧","aliases":["penguin"]},{"emoji":"😔","aliases":["pensive"]},{"emoji":"🧑‍🤝‍🧑","aliases":["people_holding_hands"]},{"emoji":"🎭","aliases":["performing_arts"]},{"emoji":"😣","aliases":["persevere"]},{"emoji":"🧑‍🦲","aliases":["person_bald"]},{"emoji":"🧑‍🦱","aliases":["person_curly_hair"]},{"emoji":"🤺","aliases":["person_fencing"]},{"emoji":"🧑‍🦽","aliases":["person_in_manual_wheelchair"]},{"emoji":"🧑‍🦼","aliases":["person_in_motorized_wheelchair"]},{"emoji":"🤵","aliases":["person_in_tuxedo"]},{"emoji":"🧑‍🦰","aliases":["person_red_hair"]},{"emoji":"🧑‍🦳","aliases":["person_white_hair"]},{"emoji":"🧑‍🦯","aliases":["person_with_probing_cane"]},{"emoji":"👳","aliases":["person_with_turban"]},{"emoji":"👰","aliases":["person_with_veil"]},{"emoji":"🇵🇪","aliases":["peru"]},{"emoji":"🧫","aliases":["petri_dish"]},{"emoji":"🇵🇭","aliases":["philippines"]},{"emoji":"☎️","aliases":["phone","telephone"]},{"emoji":"⛏️","aliases":["pick"]},{"emoji":"🥧","aliases":["pie"]},{"emoji":"🐷","aliases":["pig"]},{"emoji":"🐖","aliases":["pig2"]},{"emoji":"🐽","aliases":["pig_nose"]},{"emoji":"💊","aliases":["pill"]},{"emoji":"🧑‍✈️","aliases":["pilot"]},{"emoji":"🤏","aliases":["pinching_hand"]},{"emoji":"🍍","aliases":["pineapple"]},{"emoji":"🏓","aliases":["ping_pong"]},{"emoji":"🏴‍☠️","aliases":["pirate_flag"]},{"emoji":"♓","aliases":["pisces"]},{"emoji":"🇵🇳","aliases":["pitcairn_islands"]},{"emoji":"🍕","aliases":["pizza"]},{"emoji":"🛐","aliases":["place_of_worship"]},{"emoji":"🍽️","aliases":["plate_with_cutlery"]},{"emoji":"⏯️","aliases":["play_or_pause_button"]},{"emoji":"🥺","aliases":["pleading_face"]},{"emoji":"👇","aliases":["point_down"]},{"emoji":"👈","aliases":["point_left"]},{"emoji":"👉","aliases":["point_right"]},{"emoji":"☝️","aliases":["point_up"]},{"emoji":"👆","aliases":["point_up_2"]},{"emoji":"🇵🇱","aliases":["poland"]},{"emoji":"🚓","aliases":["police_car"]},{"emoji":"👮","aliases":["police_officer","cop"]},{"emoji":"👮‍♂️","aliases":["policeman"]},{"emoji":"👮‍♀️","aliases":["policewoman"]},{"emoji":"🐩","aliases":["poodle"]},{"emoji":"🍿","aliases":["popcorn"]},{"emoji":"🇵🇹","aliases":["portugal"]},{"emoji":"🏣","aliases":["post_office"]},{"emoji":"📯","aliases":["postal_horn"]},{"emoji":"📮","aliases":["postbox"]},{"emoji":"🚰","aliases":["potable_water"]},{"emoji":"🥔","aliases":["potato"]},{"emoji":"👝","aliases":["pouch"]},{"emoji":"🍗","aliases":["poultry_leg"]},{"emoji":"💷","aliases":["pound"]},{"emoji":"😾","aliases":["pouting_cat"]},{"emoji":"🙎","aliases":["pouting_face"]},{"emoji":"🙎‍♂️","aliases":["pouting_man"]},{"emoji":"🙎‍♀️","aliases":["pouting_woman"]},{"emoji":"🙏","aliases":["pray"]},{"emoji":"📿","aliases":["prayer_beads"]},{"emoji":"🤰","aliases":["pregnant_woman"]},{"emoji":"🥨","aliases":["pretzel"]},{"emoji":"⏮️","aliases":["previous_track_button"]},{"emoji":"🤴","aliases":["prince"]},{"emoji":"👸","aliases":["princess"]},{"emoji":"🖨️","aliases":["printer"]},{"emoji":"🦯","aliases":["probing_cane"]},{"emoji":"🇵🇷","aliases":["puerto_rico"]},{"emoji":"🟣","aliases":["purple_circle"]},{"emoji":"💜","aliases":["purple_heart"]},{"emoji":"🟪","aliases":["purple_square"]},{"emoji":"👛","aliases":["purse"]},{"emoji":"📌","aliases":["pushpin"]},{"emoji":"🚮","aliases":["put_litter_in_its_place"]},{"emoji":"🇶🇦","aliases":["qatar"]},{"emoji":"❓","aliases":["question"]},{"emoji":"🐰","aliases":["rabbit"]},{"emoji":"🐇","aliases":["rabbit2"]},{"emoji":"🦝","aliases":["raccoon"]},{"emoji":"🐎","aliases":["racehorse"]},{"emoji":"🏎️","aliases":["racing_car"]},{"emoji":"📻","aliases":["radio"]},{"emoji":"🔘","aliases":["radio_button"]},{"emoji":"☢️","aliases":["radioactive"]},{"emoji":"😡","aliases":["rage","pout"]},{"emoji":"🚃","aliases":["railway_car"]},{"emoji":"🛤️","aliases":["railway_track"]},{"emoji":"🌈","aliases":["rainbow"]},{"emoji":"🏳️‍🌈","aliases":["rainbow_flag"]},{"emoji":"🤚","aliases":["raised_back_of_hand"]},{"emoji":"🤨","aliases":["raised_eyebrow"]},{"emoji":"🖐️","aliases":["raised_hand_with_fingers_splayed"]},{"emoji":"🙌","aliases":["raised_hands"]},{"emoji":"🙋","aliases":["raising_hand"]},{"emoji":"🙋‍♂️","aliases":["raising_hand_man"]},{"emoji":"🙋‍♀️","aliases":["raising_hand_woman"]},{"emoji":"🐏","aliases":["ram"]},{"emoji":"🍜","aliases":["ramen"]},{"emoji":"🐀","aliases":["rat"]},{"emoji":"🪒","aliases":["razor"]},{"emoji":"🧾","aliases":["receipt"]},{"emoji":"⏺️","aliases":["record_button"]},{"emoji":"♻️","aliases":["recycle"]},{"emoji":"🔴","aliases":["red_circle"]},{"emoji":"🧧","aliases":["red_envelope"]},{"emoji":"👨‍🦰","aliases":["red_haired_man"]},{"emoji":"👩‍🦰","aliases":["red_haired_woman"]},{"emoji":"🟥","aliases":["red_square"]},{"emoji":"☺️","aliases":["relaxed"]},{"emoji":"😌","aliases":["relieved"]},{"emoji":"🎗️","aliases":["reminder_ribbon"]},{"emoji":"🔁","aliases":["repeat"]},{"emoji":"🔂","aliases":["repeat_one"]},{"emoji":"⛑️","aliases":["rescue_worker_helmet"]},{"emoji":"🚻","aliases":["restroom"]},{"emoji":"🇷🇪","aliases":["reunion"]},{"emoji":"💞","aliases":["revolving_hearts"]},{"emoji":"⏪","aliases":["rewind"]},{"emoji":"🦏","aliases":["rhinoceros"]},{"emoji":"🎀","aliases":["ribbon"]},{"emoji":"🍚","aliases":["rice"]},{"emoji":"🍙","aliases":["rice_ball"]},{"emoji":"🍘","aliases":["rice_cracker"]},{"emoji":"🎑","aliases":["rice_scene"]},{"emoji":"🗯️","aliases":["right_anger_bubble"]},{"emoji":"💍","aliases":["ring"]},{"emoji":"🪐","aliases":["ringed_planet"]},{"emoji":"🤖","aliases":["robot"]},{"emoji":"🚀","aliases":["rocket"]},{"emoji":"🤣","aliases":["rofl"]},{"emoji":"🙄","aliases":["roll_eyes"]},{"emoji":"🧻","aliases":["roll_of_paper"]},{"emoji":"🎢","aliases":["roller_coaster"]},{"emoji":"🇷🇴","aliases":["romania"]},{"emoji":"🐓","aliases":["rooster"]},{"emoji":"🌹","aliases":["rose"]},{"emoji":"🏵️","aliases":["rosette"]},{"emoji":"🚨","aliases":["rotating_light"]},{"emoji":"📍","aliases":["round_pushpin"]},{"emoji":"🚣","aliases":["rowboat"]},{"emoji":"🚣‍♂️","aliases":["rowing_man"]},{"emoji":"🚣‍♀️","aliases":["rowing_woman"]},{"emoji":"🇷🇺","aliases":["ru"]},{"emoji":"🏉","aliases":["rugby_football"]},{"emoji":"🏃","aliases":["runner","running"]},{"emoji":"🏃‍♂️","aliases":["running_man"]},{"emoji":"🎽","aliases":["running_shirt_with_sash"]},{"emoji":"🏃‍♀️","aliases":["running_woman"]},{"emoji":"🇷🇼","aliases":["rwanda"]},{"emoji":"🈂️","aliases":["sa"]},{"emoji":"🧷","aliases":["safety_pin"]},{"emoji":"🦺","aliases":["safety_vest"]},{"emoji":"♐","aliases":["sagittarius"]},{"emoji":"🍶","aliases":["sake"]},{"emoji":"🧂","aliases":["salt"]},{"emoji":"🇼🇸","aliases":["samoa"]},{"emoji":"🇸🇲","aliases":["san_marino"]},{"emoji":"👡","aliases":["sandal"]},{"emoji":"🥪","aliases":["sandwich"]},{"emoji":"🎅","aliases":["santa"]},{"emoji":"🇸🇹","aliases":["sao_tome_principe"]},{"emoji":"🥻","aliases":["sari"]},{"emoji":"📡","aliases":["satellite"]},{"emoji":"🇸🇦","aliases":["saudi_arabia"]},{"emoji":"🧖‍♂️","aliases":["sauna_man"]},{"emoji":"🧖","aliases":["sauna_person"]},{"emoji":"🧖‍♀️","aliases":["sauna_woman"]},{"emoji":"🦕","aliases":["sauropod"]},{"emoji":"🎷","aliases":["saxophone"]},{"emoji":"🧣","aliases":["scarf"]},{"emoji":"🏫","aliases":["school"]},{"emoji":"🎒","aliases":["school_satchel"]},{"emoji":"🧑‍🔬","aliases":["scientist"]},{"emoji":"✂️","aliases":["scissors"]},{"emoji":"🦂","aliases":["scorpion"]},{"emoji":"♏","aliases":["scorpius"]},{"emoji":"🏴󠁧󠁢󠁳󠁣󠁴󠁿","aliases":["scotland"]},{"emoji":"😱","aliases":["scream"]},{"emoji":"🙀","aliases":["scream_cat"]},{"emoji":"📜","aliases":["scroll"]},{"emoji":"💺","aliases":["seat"]},{"emoji":"㊙️","aliases":["secret"]},{"emoji":"🙈","aliases":["see_no_evil"]},{"emoji":"🌱","aliases":["seedling"]},{"emoji":"🤳","aliases":["selfie"]},{"emoji":"🇸🇳","aliases":["senegal"]},{"emoji":"🇷🇸","aliases":["serbia"]},{"emoji":"🐕‍🦺","aliases":["service_dog"]},{"emoji":"🇸🇨","aliases":["seychelles"]},{"emoji":"🥘","aliases":["shallow_pan_of_food"]},{"emoji":"☘️","aliases":["shamrock"]},{"emoji":"🦈","aliases":["shark"]},{"emoji":"🍧","aliases":["shaved_ice"]},{"emoji":"🐑","aliases":["sheep"]},{"emoji":"🐚","aliases":["shell"]},{"emoji":"🛡️","aliases":["shield"]},{"emoji":"⛩️","aliases":["shinto_shrine"]},{"emoji":"🚢","aliases":["ship"]},{"emoji":"👕","aliases":["shirt","tshirt"]},{"emoji":"🛍️","aliases":["shopping"]},{"emoji":"🛒","aliases":["shopping_cart"]},{"emoji":"🩳","aliases":["shorts"]},{"emoji":"🚿","aliases":["shower"]},{"emoji":"🦐","aliases":["shrimp"]},{"emoji":"🤷","aliases":["shrug"]},{"emoji":"🤫","aliases":["shushing_face"]},{"emoji":"🇸🇱","aliases":["sierra_leone"]},{"emoji":"📶","aliases":["signal_strength"]},{"emoji":"🇸🇬","aliases":["singapore"]},{"emoji":"🧑‍🎤","aliases":["singer"]},{"emoji":"🇸🇽","aliases":["sint_maarten"]},{"emoji":"🔯","aliases":["six_pointed_star"]},{"emoji":"🛹","aliases":["skateboard"]},{"emoji":"🎿","aliases":["ski"]},{"emoji":"⛷️","aliases":["skier"]},{"emoji":"💀","aliases":["skull"]},{"emoji":"☠️","aliases":["skull_and_crossbones"]},{"emoji":"🦨","aliases":["skunk"]},{"emoji":"🛷","aliases":["sled"]},{"emoji":"😴","aliases":["sleeping"]},{"emoji":"🛌","aliases":["sleeping_bed"]},{"emoji":"😪","aliases":["sleepy"]},{"emoji":"🙁","aliases":["slightly_frowning_face"]},{"emoji":"🙂","aliases":["slightly_smiling_face"]},{"emoji":"🎰","aliases":["slot_machine"]},{"emoji":"🦥","aliases":["sloth"]},{"emoji":"🇸🇰","aliases":["slovakia"]},{"emoji":"🇸🇮","aliases":["slovenia"]},{"emoji":"🛩️","aliases":["small_airplane"]},{"emoji":"🔹","aliases":["small_blue_diamond"]},{"emoji":"🔸","aliases":["small_orange_diamond"]},{"emoji":"🔺","aliases":["small_red_triangle"]},{"emoji":"🔻","aliases":["small_red_triangle_down"]},{"emoji":"😄","aliases":["smile"]},{"emoji":"😸","aliases":["smile_cat"]},{"emoji":"😃","aliases":["smiley"]},{"emoji":"😺","aliases":["smiley_cat"]},{"emoji":"🥰","aliases":["smiling_face_with_three_hearts"]},{"emoji":"😈","aliases":["smiling_imp"]},{"emoji":"😏","aliases":["smirk"]},{"emoji":"😼","aliases":["smirk_cat"]},{"emoji":"🚬","aliases":["smoking"]},{"emoji":"🐌","aliases":["snail"]},{"emoji":"🐍","aliases":["snake"]},{"emoji":"🤧","aliases":["sneezing_face"]},{"emoji":"🏂","aliases":["snowboarder"]},{"emoji":"❄️","aliases":["snowflake"]},{"emoji":"⛄","aliases":["snowman"]},{"emoji":"☃️","aliases":["snowman_with_snow"]},{"emoji":"🧼","aliases":["soap"]},{"emoji":"😭","aliases":["sob"]},{"emoji":"⚽","aliases":["soccer"]},{"emoji":"🧦","aliases":["socks"]},{"emoji":"🥎","aliases":["softball"]},{"emoji":"🇸🇧","aliases":["solomon_islands"]},{"emoji":"🇸🇴","aliases":["somalia"]},{"emoji":"🔜","aliases":["soon"]},{"emoji":"🆘","aliases":["sos"]},{"emoji":"🔉","aliases":["sound"]},{"emoji":"🇿🇦","aliases":["south_africa"]},{"emoji":"🇬🇸","aliases":["south_georgia_south_sandwich_islands"]},{"emoji":"🇸🇸","aliases":["south_sudan"]},{"emoji":"👾","aliases":["space_invader"]},{"emoji":"♠️","aliases":["spades"]},{"emoji":"🍝","aliases":["spaghetti"]},{"emoji":"❇️","aliases":["sparkle"]},{"emoji":"🎇","aliases":["sparkler"]},{"emoji":"✨","aliases":["sparkles"]},{"emoji":"💖","aliases":["sparkling_heart"]},{"emoji":"🙊","aliases":["speak_no_evil"]},{"emoji":"🔈","aliases":["speaker"]},{"emoji":"🗣️","aliases":["speaking_head"]},{"emoji":"💬","aliases":["speech_balloon"]},{"emoji":"🚤","aliases":["speedboat"]},{"emoji":"🕷️","aliases":["spider"]},{"emoji":"🕸️","aliases":["spider_web"]},{"emoji":"🗓️","aliases":["spiral_calendar"]},{"emoji":"🗒️","aliases":["spiral_notepad"]},{"emoji":"🧽","aliases":["sponge"]},{"emoji":"🥄","aliases":["spoon"]},{"emoji":"🦑","aliases":["squid"]},{"emoji":"🇱🇰","aliases":["sri_lanka"]},{"emoji":"🇧🇱","aliases":["st_barthelemy"]},{"emoji":"🇸🇭","aliases":["st_helena"]},{"emoji":"🇰🇳","aliases":["st_kitts_nevis"]},{"emoji":"🇱🇨","aliases":["st_lucia"]},{"emoji":"🇲🇫","aliases":["st_martin"]},{"emoji":"🇵🇲","aliases":["st_pierre_miquelon"]},{"emoji":"🇻🇨","aliases":["st_vincent_grenadines"]},{"emoji":"🏟️","aliases":["stadium"]},{"emoji":"🧍‍♂️","aliases":["standing_man"]},{"emoji":"🧍","aliases":["standing_person"]},{"emoji":"🧍‍♀️","aliases":["standing_woman"]},{"emoji":"⭐","aliases":["star"]},{"emoji":"🌟","aliases":["star2"]},{"emoji":"☪️","aliases":["star_and_crescent"]},{"emoji":"✡️","aliases":["star_of_david"]},{"emoji":"🤩","aliases":["star_struck"]},{"emoji":"🌠","aliases":["stars"]},{"emoji":"🚉","aliases":["station"]},{"emoji":"🗽","aliases":["statue_of_liberty"]},{"emoji":"🚂","aliases":["steam_locomotive"]},{"emoji":"🩺","aliases":["stethoscope"]},{"emoji":"🍲","aliases":["stew"]},{"emoji":"⏹️","aliases":["stop_button"]},{"emoji":"🛑","aliases":["stop_sign"]},{"emoji":"⏱️","aliases":["stopwatch"]},{"emoji":"📏","aliases":["straight_ruler"]},{"emoji":"🍓","aliases":["strawberry"]},{"emoji":"😛","aliases":["stuck_out_tongue"]},{"emoji":"😝","aliases":["stuck_out_tongue_closed_eyes"]},{"emoji":"😜","aliases":["stuck_out_tongue_winking_eye"]},{"emoji":"🧑‍🎓","aliases":["student"]},{"emoji":"🎙️","aliases":["studio_microphone"]},{"emoji":"🥙","aliases":["stuffed_flatbread"]},{"emoji":"🇸🇩","aliases":["sudan"]},{"emoji":"🌥️","aliases":["sun_behind_large_cloud"]},{"emoji":"🌦️","aliases":["sun_behind_rain_cloud"]},{"emoji":"🌤️","aliases":["sun_behind_small_cloud"]},{"emoji":"🌞","aliases":["sun_with_face"]},{"emoji":"🌻","aliases":["sunflower"]},{"emoji":"😎","aliases":["sunglasses"]},{"emoji":"☀️","aliases":["sunny"]},{"emoji":"🌅","aliases":["sunrise"]},{"emoji":"🌄","aliases":["sunrise_over_mountains"]},{"emoji":"🦸","aliases":["superhero"]},{"emoji":"🦸‍♂️","aliases":["superhero_man"]},{"emoji":"🦸‍♀️","aliases":["superhero_woman"]},{"emoji":"🦹","aliases":["supervillain"]},{"emoji":"🦹‍♂️","aliases":["supervillain_man"]},{"emoji":"🦹‍♀️","aliases":["supervillain_woman"]},{"emoji":"🏄","aliases":["surfer"]},{"emoji":"🏄‍♂️","aliases":["surfing_man"]},{"emoji":"🏄‍♀️","aliases":["surfing_woman"]},{"emoji":"🇸🇷","aliases":["suriname"]},{"emoji":"🍣","aliases":["sushi"]},{"emoji":"🚟","aliases":["suspension_railway"]},{"emoji":"🇸🇯","aliases":["svalbard_jan_mayen"]},{"emoji":"🦢","aliases":["swan"]},{"emoji":"🇸🇿","aliases":["swaziland"]},{"emoji":"😓","aliases":["sweat"]},{"emoji":"💦","aliases":["sweat_drops"]},{"emoji":"😅","aliases":["sweat_smile"]},{"emoji":"🇸🇪","aliases":["sweden"]},{"emoji":"🍠","aliases":["sweet_potato"]},{"emoji":"🩲","aliases":["swim_brief"]},{"emoji":"🏊","aliases":["swimmer"]},{"emoji":"🏊‍♂️","aliases":["swimming_man"]},{"emoji":"🏊‍♀️","aliases":["swimming_woman"]},{"emoji":"🇨🇭","aliases":["switzerland"]},{"emoji":"🔣","aliases":["symbols"]},{"emoji":"🕍","aliases":["synagogue"]},{"emoji":"🇸🇾","aliases":["syria"]},{"emoji":"💉","aliases":["syringe"]},{"emoji":"🦖","aliases":["t-rex"]},{"emoji":"🌮","aliases":["taco"]},{"emoji":"🎉","aliases":["tada","hooray"]},{"emoji":"🇹🇼","aliases":["taiwan"]},{"emoji":"🇹🇯","aliases":["tajikistan"]},{"emoji":"🥡","aliases":["takeout_box"]},{"emoji":"🎋","aliases":["tanabata_tree"]},{"emoji":"🍊","aliases":["tangerine","orange","mandarin"]},{"emoji":"🇹🇿","aliases":["tanzania"]},{"emoji":"♉","aliases":["taurus"]},{"emoji":"🚕","aliases":["taxi"]},{"emoji":"🍵","aliases":["tea"]},{"emoji":"🧑‍🏫","aliases":["teacher"]},{"emoji":"🧑‍💻","aliases":["technologist"]},{"emoji":"🧸","aliases":["teddy_bear"]},{"emoji":"📞","aliases":["telephone_receiver"]},{"emoji":"🔭","aliases":["telescope"]},{"emoji":"🎾","aliases":["tennis"]},{"emoji":"⛺","aliases":["tent"]},{"emoji":"🧪","aliases":["test_tube"]},{"emoji":"🇹🇭","aliases":["thailand"]},{"emoji":"🌡️","aliases":["thermometer"]},{"emoji":"🤔","aliases":["thinking"]},{"emoji":"💭","aliases":["thought_balloon"]},{"emoji":"🧵","aliases":["thread"]},{"emoji":"🎫","aliases":["ticket"]},{"emoji":"🎟️","aliases":["tickets"]},{"emoji":"🐯","aliases":["tiger"]},{"emoji":"🐅","aliases":["tiger2"]},{"emoji":"⏲️","aliases":["timer_clock"]},{"emoji":"🇹🇱","aliases":["timor_leste"]},{"emoji":"💁‍♂️","aliases":["tipping_hand_man","sassy_man"]},{"emoji":"💁","aliases":["tipping_hand_person","information_desk_person"]},{"emoji":"💁‍♀️","aliases":["tipping_hand_woman","sassy_woman"]},{"emoji":"😫","aliases":["tired_face"]},{"emoji":"™️","aliases":["tm"]},{"emoji":"🇹🇬","aliases":["togo"]},{"emoji":"🚽","aliases":["toilet"]},{"emoji":"🇹🇰","aliases":["tokelau"]},{"emoji":"🗼","aliases":["tokyo_tower"]},{"emoji":"🍅","aliases":["tomato"]},{"emoji":"🇹🇴","aliases":["tonga"]},{"emoji":"👅","aliases":["tongue"]},{"emoji":"🧰","aliases":["toolbox"]},{"emoji":"🦷","aliases":["tooth"]},{"emoji":"🔝","aliases":["top"]},{"emoji":"🎩","aliases":["tophat"]},{"emoji":"🌪️","aliases":["tornado"]},{"emoji":"🇹🇷","aliases":["tr"]},{"emoji":"🖲️","aliases":["trackball"]},{"emoji":"🚜","aliases":["tractor"]},{"emoji":"🚥","aliases":["traffic_light"]},{"emoji":"🚋","aliases":["train"]},{"emoji":"🚆","aliases":["train2"]},{"emoji":"🚊","aliases":["tram"]},{"emoji":"🚩","aliases":["triangular_flag_on_post"]},{"emoji":"📐","aliases":["triangular_ruler"]},{"emoji":"🔱","aliases":["trident"]},{"emoji":"🇹🇹","aliases":["trinidad_tobago"]},{"emoji":"🇹🇦","aliases":["tristan_da_cunha"]},{"emoji":"😤","aliases":["triumph"]},{"emoji":"🚎","aliases":["trolleybus"]},{"emoji":"🏆","aliases":["trophy"]},{"emoji":"🍹","aliases":["tropical_drink"]},{"emoji":"🐠","aliases":["tropical_fish"]},{"emoji":"🚚","aliases":["truck"]},{"emoji":"🎺","aliases":["trumpet"]},{"emoji":"🌷","aliases":["tulip"]},{"emoji":"🥃","aliases":["tumbler_glass"]},{"emoji":"🇹🇳","aliases":["tunisia"]},{"emoji":"🦃","aliases":["turkey"]},{"emoji":"🇹🇲","aliases":["turkmenistan"]},{"emoji":"🇹🇨","aliases":["turks_caicos_islands"]},{"emoji":"🐢","aliases":["turtle"]},{"emoji":"🇹🇻","aliases":["tuvalu"]},{"emoji":"📺","aliases":["tv"]},{"emoji":"🔀","aliases":["twisted_rightwards_arrows"]},{"emoji":"💕","aliases":["two_hearts"]},{"emoji":"👬","aliases":["two_men_holding_hands"]},{"emoji":"👭","aliases":["two_women_holding_hands"]},{"emoji":"🈹","aliases":["u5272"]},{"emoji":"🈴","aliases":["u5408"]},{"emoji":"🈺","aliases":["u55b6"]},{"emoji":"🈯","aliases":["u6307"]},{"emoji":"🈷️","aliases":["u6708"]},{"emoji":"🈶","aliases":["u6709"]},{"emoji":"🈵","aliases":["u6e80"]},{"emoji":"🈚","aliases":["u7121"]},{"emoji":"🈸","aliases":["u7533"]},{"emoji":"🈲","aliases":["u7981"]},{"emoji":"🈳","aliases":["u7a7a"]},{"emoji":"🇺🇬","aliases":["uganda"]},{"emoji":"🇺🇦","aliases":["ukraine"]},{"emoji":"☔","aliases":["umbrella"]},{"emoji":"😒","aliases":["unamused"]},{"emoji":"🔞","aliases":["underage"]},{"emoji":"🦄","aliases":["unicorn"]},{"emoji":"🇦🇪","aliases":["united_arab_emirates"]},{"emoji":"🇺🇳","aliases":["united_nations"]},{"emoji":"🔓","aliases":["unlock"]},{"emoji":"🆙","aliases":["up"]},{"emoji":"🙃","aliases":["upside_down_face"]},{"emoji":"🇺🇾","aliases":["uruguay"]},{"emoji":"🇺🇸","aliases":["us"]},{"emoji":"🇺🇲","aliases":["us_outlying_islands"]},{"emoji":"🇻🇮","aliases":["us_virgin_islands"]},{"emoji":"🇺🇿","aliases":["uzbekistan"]},{"emoji":"✌️","aliases":["v"]},{"emoji":"🧛","aliases":["vampire"]},{"emoji":"🧛‍♂️","aliases":["vampire_man"]},{"emoji":"🧛‍♀️","aliases":["vampire_woman"]},{"emoji":"🇻🇺","aliases":["vanuatu"]},{"emoji":"🇻🇦","aliases":["vatican_city"]},{"emoji":"🇻🇪","aliases":["venezuela"]},{"emoji":"🚦","aliases":["vertical_traffic_light"]},{"emoji":"📼","aliases":["vhs"]},{"emoji":"📳","aliases":["vibration_mode"]},{"emoji":"📹","aliases":["video_camera"]},{"emoji":"🎮","aliases":["video_game"]},{"emoji":"🇻🇳","aliases":["vietnam"]},{"emoji":"🎻","aliases":["violin"]},{"emoji":"♍","aliases":["virgo"]},{"emoji":"🌋","aliases":["volcano"]},{"emoji":"🏐","aliases":["volleyball"]},{"emoji":"🤮","aliases":["vomiting_face"]},{"emoji":"🆚","aliases":["vs"]},{"emoji":"🖖","aliases":["vulcan_salute"]},{"emoji":"🧇","aliases":["waffle"]},{"emoji":"🏴󠁧󠁢󠁷󠁬󠁳󠁿","aliases":["wales"]},{"emoji":"🚶","aliases":["walking"]},{"emoji":"🚶‍♂️","aliases":["walking_man"]},{"emoji":"🚶‍♀️","aliases":["walking_woman"]},{"emoji":"🇼🇫","aliases":["wallis_futuna"]},{"emoji":"🌘","aliases":["waning_crescent_moon"]},{"emoji":"🌖","aliases":["waning_gibbous_moon"]},{"emoji":"⚠️","aliases":["warning"]},{"emoji":"🗑️","aliases":["wastebasket"]},{"emoji":"⌚","aliases":["watch"]},{"emoji":"🐃","aliases":["water_buffalo"]},{"emoji":"🤽","aliases":["water_polo"]},{"emoji":"🍉","aliases":["watermelon"]},{"emoji":"👋","aliases":["wave"]},{"emoji":"〰️","aliases":["wavy_dash"]},{"emoji":"🌒","aliases":["waxing_crescent_moon"]},{"emoji":"🚾","aliases":["wc"]},{"emoji":"😩","aliases":["weary"]},{"emoji":"💒","aliases":["wedding"]},{"emoji":"🏋️","aliases":["weight_lifting"]},{"emoji":"🏋️‍♂️","aliases":["weight_lifting_man"]},{"emoji":"🏋️‍♀️","aliases":["weight_lifting_woman"]},{"emoji":"🇪🇭","aliases":["western_sahara"]},{"emoji":"🐳","aliases":["whale"]},{"emoji":"🐋","aliases":["whale2"]},{"emoji":"☸️","aliases":["wheel_of_dharma"]},{"emoji":"♿","aliases":["wheelchair"]},{"emoji":"✅","aliases":["white_check_mark"]},{"emoji":"⚪","aliases":["white_circle"]},{"emoji":"🏳️","aliases":["white_flag"]},{"emoji":"💮","aliases":["white_flower"]},{"emoji":"👨‍🦳","aliases":["white_haired_man"]},{"emoji":"👩‍🦳","aliases":["white_haired_woman"]},{"emoji":"🤍","aliases":["white_heart"]},{"emoji":"⬜","aliases":["white_large_square"]},{"emoji":"◽","aliases":["white_medium_small_square"]},{"emoji":"◻️","aliases":["white_medium_square"]},{"emoji":"▫️","aliases":["white_small_square"]},{"emoji":"🔳","aliases":["white_square_button"]},{"emoji":"🥀","aliases":["wilted_flower"]},{"emoji":"🎐","aliases":["wind_chime"]},{"emoji":"🌬️","aliases":["wind_face"]},{"emoji":"🍷","aliases":["wine_glass"]},{"emoji":"😉","aliases":["wink"]},{"emoji":"🐺","aliases":["wolf"]},{"emoji":"👩","aliases":["woman"]},{"emoji":"👩‍🎨","aliases":["woman_artist"]},{"emoji":"👩‍🚀","aliases":["woman_astronaut"]},{"emoji":"🤸‍♀️","aliases":["woman_cartwheeling"]},{"emoji":"👩‍🍳","aliases":["woman_cook"]},{"emoji":"💃","aliases":["woman_dancing","dancer"]},{"emoji":"🤦‍♀️","aliases":["woman_facepalming"]},{"emoji":"👩‍🏭","aliases":["woman_factory_worker"]},{"emoji":"👩‍🌾","aliases":["woman_farmer"]},{"emoji":"👩‍🚒","aliases":["woman_firefighter"]},{"emoji":"👩‍⚕️","aliases":["woman_health_worker"]},{"emoji":"👩‍🦽","aliases":["woman_in_manual_wheelchair"]},{"emoji":"👩‍🦼","aliases":["woman_in_motorized_wheelchair"]},{"emoji":"👩‍⚖️","aliases":["woman_judge"]},{"emoji":"🤹‍♀️","aliases":["woman_juggling"]},{"emoji":"👩‍🔧","aliases":["woman_mechanic"]},{"emoji":"👩‍💼","aliases":["woman_office_worker"]},{"emoji":"👩‍✈️","aliases":["woman_pilot"]},{"emoji":"🤾‍♀️","aliases":["woman_playing_handball"]},{"emoji":"🤽‍♀️","aliases":["woman_playing_water_polo"]},{"emoji":"👩‍🔬","aliases":["woman_scientist"]},{"emoji":"🤷‍♀️","aliases":["woman_shrugging"]},{"emoji":"👩‍🎤","aliases":["woman_singer"]},{"emoji":"👩‍🎓","aliases":["woman_student"]},{"emoji":"👩‍🏫","aliases":["woman_teacher"]},{"emoji":"👩‍💻","aliases":["woman_technologist"]},{"emoji":"🧕","aliases":["woman_with_headscarf"]},{"emoji":"👩‍🦯","aliases":["woman_with_probing_cane"]},{"emoji":"👳‍♀️","aliases":["woman_with_turban"]},{"emoji":"👚","aliases":["womans_clothes"]},{"emoji":"👒","aliases":["womans_hat"]},{"emoji":"🤼‍♀️","aliases":["women_wrestling"]},{"emoji":"🚺","aliases":["womens"]},{"emoji":"🥴","aliases":["woozy_face"]},{"emoji":"🗺️","aliases":["world_map"]},{"emoji":"😟","aliases":["worried"]},{"emoji":"🔧","aliases":["wrench"]},{"emoji":"🤼","aliases":["wrestling"]},{"emoji":"✍️","aliases":["writing_hand"]},{"emoji":"❌","aliases":["x"]},{"emoji":"🧶","aliases":["yarn"]},{"emoji":"🥱","aliases":["yawning_face"]},{"emoji":"🟡","aliases":["yellow_circle"]},{"emoji":"💛","aliases":["yellow_heart"]},{"emoji":"🟨","aliases":["yellow_square"]},{"emoji":"🇾🇪","aliases":["yemen"]},{"emoji":"💴","aliases":["yen"]},{"emoji":"☯️","aliases":["yin_yang"]},{"emoji":"🪀","aliases":["yo_yo"]},{"emoji":"😋","aliases":["yum"]},{"emoji":"🇿🇲","aliases":["zambia"]},{"emoji":"🤪","aliases":["zany_face"]},{"emoji":"⚡","aliases":["zap"]},{"emoji":"🦓","aliases":["zebra"]},{"emoji":"🇿🇼","aliases":["zimbabwe"]},{"emoji":"🤐","aliases":["zipper_mouth_face"]},{"emoji":"🧟","aliases":["zombie"]},{"emoji":"🧟‍♂️","aliases":["zombie_man"]},{"emoji":"🧟‍♀️","aliases":["zombie_woman"]},{"emoji":"💤","aliases":["zzz"]}] \ No newline at end of file +[{"emoji":"👍","aliases":["+1","thumbsup"]},{"emoji":"👎","aliases":["-1","thumbsdown"]},{"emoji":"💯","aliases":["100"]},{"emoji":"🔢","aliases":["1234"]},{"emoji":"🥇","aliases":["1st_place_medal"]},{"emoji":"🥈","aliases":["2nd_place_medal"]},{"emoji":"🥉","aliases":["3rd_place_medal"]},{"emoji":"🎱","aliases":["8ball"]},{"emoji":"🅰️","aliases":["a"]},{"emoji":"🆎","aliases":["ab"]},{"emoji":"🧮","aliases":["abacus"]},{"emoji":"🔤","aliases":["abc"]},{"emoji":"🔡","aliases":["abcd"]},{"emoji":"🉑","aliases":["accept"]},{"emoji":"🩹","aliases":["adhesive_bandage"]},{"emoji":"🧑","aliases":["adult"]},{"emoji":"🚡","aliases":["aerial_tramway"]},{"emoji":"🇦🇫","aliases":["afghanistan"]},{"emoji":"✈️","aliases":["airplane"]},{"emoji":"🇦🇽","aliases":["aland_islands"]},{"emoji":"⏰","aliases":["alarm_clock"]},{"emoji":"🇦🇱","aliases":["albania"]},{"emoji":"⚗️","aliases":["alembic"]},{"emoji":"🇩🇿","aliases":["algeria"]},{"emoji":"👽","aliases":["alien"]},{"emoji":"🚑","aliases":["ambulance"]},{"emoji":"🇦🇸","aliases":["american_samoa"]},{"emoji":"🏺","aliases":["amphora"]},{"emoji":"⚓","aliases":["anchor"]},{"emoji":"🇦🇩","aliases":["andorra"]},{"emoji":"👼","aliases":["angel"]},{"emoji":"💢","aliases":["anger"]},{"emoji":"🇦🇴","aliases":["angola"]},{"emoji":"😠","aliases":["angry"]},{"emoji":"🇦🇮","aliases":["anguilla"]},{"emoji":"😧","aliases":["anguished"]},{"emoji":"🐜","aliases":["ant"]},{"emoji":"🇦🇶","aliases":["antarctica"]},{"emoji":"🇦🇬","aliases":["antigua_barbuda"]},{"emoji":"🍎","aliases":["apple"]},{"emoji":"♒","aliases":["aquarius"]},{"emoji":"🇦🇷","aliases":["argentina"]},{"emoji":"♈","aliases":["aries"]},{"emoji":"🇦🇲","aliases":["armenia"]},{"emoji":"◀️","aliases":["arrow_backward"]},{"emoji":"⏬","aliases":["arrow_double_down"]},{"emoji":"⏫","aliases":["arrow_double_up"]},{"emoji":"⬇️","aliases":["arrow_down"]},{"emoji":"🔽","aliases":["arrow_down_small"]},{"emoji":"▶️","aliases":["arrow_forward"]},{"emoji":"⤵️","aliases":["arrow_heading_down"]},{"emoji":"⤴️","aliases":["arrow_heading_up"]},{"emoji":"⬅️","aliases":["arrow_left"]},{"emoji":"↙️","aliases":["arrow_lower_left"]},{"emoji":"↘️","aliases":["arrow_lower_right"]},{"emoji":"➡️","aliases":["arrow_right"]},{"emoji":"↪️","aliases":["arrow_right_hook"]},{"emoji":"⬆️","aliases":["arrow_up"]},{"emoji":"↕️","aliases":["arrow_up_down"]},{"emoji":"🔼","aliases":["arrow_up_small"]},{"emoji":"↖️","aliases":["arrow_upper_left"]},{"emoji":"↗️","aliases":["arrow_upper_right"]},{"emoji":"🔃","aliases":["arrows_clockwise"]},{"emoji":"🔄","aliases":["arrows_counterclockwise"]},{"emoji":"🎨","aliases":["art"]},{"emoji":"🚛","aliases":["articulated_lorry"]},{"emoji":"🛰️","aliases":["artificial_satellite"]},{"emoji":"🧑‍🎨","aliases":["artist"]},{"emoji":"🇦🇼","aliases":["aruba"]},{"emoji":"🇦🇨","aliases":["ascension_island"]},{"emoji":"*️⃣","aliases":["asterisk"]},{"emoji":"😲","aliases":["astonished"]},{"emoji":"🧑‍🚀","aliases":["astronaut"]},{"emoji":"👟","aliases":["athletic_shoe"]},{"emoji":"🏧","aliases":["atm"]},{"emoji":"⚛️","aliases":["atom_symbol"]},{"emoji":"🇦🇺","aliases":["australia"]},{"emoji":"🇦🇹","aliases":["austria"]},{"emoji":"🛺","aliases":["auto_rickshaw"]},{"emoji":"🥑","aliases":["avocado"]},{"emoji":"🪓","aliases":["axe"]},{"emoji":"🇦🇿","aliases":["azerbaijan"]},{"emoji":"🅱️","aliases":["b"]},{"emoji":"👶","aliases":["baby"]},{"emoji":"🍼","aliases":["baby_bottle"]},{"emoji":"🐤","aliases":["baby_chick"]},{"emoji":"🚼","aliases":["baby_symbol"]},{"emoji":"🔙","aliases":["back"]},{"emoji":"🥓","aliases":["bacon"]},{"emoji":"🦡","aliases":["badger"]},{"emoji":"🏸","aliases":["badminton"]},{"emoji":"🥯","aliases":["bagel"]},{"emoji":"🛄","aliases":["baggage_claim"]},{"emoji":"🥖","aliases":["baguette_bread"]},{"emoji":"🇧🇸","aliases":["bahamas"]},{"emoji":"🇧🇭","aliases":["bahrain"]},{"emoji":"⚖️","aliases":["balance_scale"]},{"emoji":"👨‍🦲","aliases":["bald_man"]},{"emoji":"👩‍🦲","aliases":["bald_woman"]},{"emoji":"🩰","aliases":["ballet_shoes"]},{"emoji":"🎈","aliases":["balloon"]},{"emoji":"🗳️","aliases":["ballot_box"]},{"emoji":"☑️","aliases":["ballot_box_with_check"]},{"emoji":"🎍","aliases":["bamboo"]},{"emoji":"🍌","aliases":["banana"]},{"emoji":"‼️","aliases":["bangbang"]},{"emoji":"🇧🇩","aliases":["bangladesh"]},{"emoji":"🪕","aliases":["banjo"]},{"emoji":"🏦","aliases":["bank"]},{"emoji":"📊","aliases":["bar_chart"]},{"emoji":"🇧🇧","aliases":["barbados"]},{"emoji":"💈","aliases":["barber"]},{"emoji":"⚾","aliases":["baseball"]},{"emoji":"🧺","aliases":["basket"]},{"emoji":"🏀","aliases":["basketball"]},{"emoji":"🦇","aliases":["bat"]},{"emoji":"🛀","aliases":["bath"]},{"emoji":"🛁","aliases":["bathtub"]},{"emoji":"🔋","aliases":["battery"]},{"emoji":"🏖️","aliases":["beach_umbrella"]},{"emoji":"🐻","aliases":["bear"]},{"emoji":"🧔","aliases":["bearded_person"]},{"emoji":"🛏️","aliases":["bed"]},{"emoji":"🐝","aliases":["bee","honeybee"]},{"emoji":"🍺","aliases":["beer"]},{"emoji":"🍻","aliases":["beers"]},{"emoji":"🔰","aliases":["beginner"]},{"emoji":"🇧🇾","aliases":["belarus"]},{"emoji":"🇧🇪","aliases":["belgium"]},{"emoji":"🇧🇿","aliases":["belize"]},{"emoji":"🔔","aliases":["bell"]},{"emoji":"🛎️","aliases":["bellhop_bell"]},{"emoji":"🇧🇯","aliases":["benin"]},{"emoji":"🍱","aliases":["bento"]},{"emoji":"🇧🇲","aliases":["bermuda"]},{"emoji":"🧃","aliases":["beverage_box"]},{"emoji":"🇧🇹","aliases":["bhutan"]},{"emoji":"🚴","aliases":["bicyclist"]},{"emoji":"🚲","aliases":["bike"]},{"emoji":"🚴‍♂️","aliases":["biking_man"]},{"emoji":"🚴‍♀️","aliases":["biking_woman"]},{"emoji":"👙","aliases":["bikini"]},{"emoji":"🧢","aliases":["billed_cap"]},{"emoji":"☣️","aliases":["biohazard"]},{"emoji":"🐦","aliases":["bird"]},{"emoji":"🎂","aliases":["birthday"]},{"emoji":"⚫","aliases":["black_circle"]},{"emoji":"🏴","aliases":["black_flag"]},{"emoji":"🖤","aliases":["black_heart"]},{"emoji":"🃏","aliases":["black_joker"]},{"emoji":"⬛","aliases":["black_large_square"]},{"emoji":"◾","aliases":["black_medium_small_square"]},{"emoji":"◼️","aliases":["black_medium_square"]},{"emoji":"✒️","aliases":["black_nib"]},{"emoji":"▪️","aliases":["black_small_square"]},{"emoji":"🔲","aliases":["black_square_button"]},{"emoji":"👱‍♂️","aliases":["blond_haired_man"]},{"emoji":"👱","aliases":["blond_haired_person"]},{"emoji":"👱‍♀️","aliases":["blond_haired_woman","blonde_woman"]},{"emoji":"🌼","aliases":["blossom"]},{"emoji":"🐡","aliases":["blowfish"]},{"emoji":"📘","aliases":["blue_book"]},{"emoji":"🚙","aliases":["blue_car"]},{"emoji":"💙","aliases":["blue_heart"]},{"emoji":"🟦","aliases":["blue_square"]},{"emoji":"😊","aliases":["blush"]},{"emoji":"🐗","aliases":["boar"]},{"emoji":"⛵","aliases":["boat","sailboat"]},{"emoji":"🇧🇴","aliases":["bolivia"]},{"emoji":"💣","aliases":["bomb"]},{"emoji":"🦴","aliases":["bone"]},{"emoji":"📖","aliases":["book","open_book"]},{"emoji":"🔖","aliases":["bookmark"]},{"emoji":"📑","aliases":["bookmark_tabs"]},{"emoji":"📚","aliases":["books"]},{"emoji":"💥","aliases":["boom","collision"]},{"emoji":"👢","aliases":["boot"]},{"emoji":"🇧🇦","aliases":["bosnia_herzegovina"]},{"emoji":"🇧🇼","aliases":["botswana"]},{"emoji":"⛹️‍♂️","aliases":["bouncing_ball_man","basketball_man"]},{"emoji":"⛹️","aliases":["bouncing_ball_person"]},{"emoji":"⛹️‍♀️","aliases":["bouncing_ball_woman","basketball_woman"]},{"emoji":"💐","aliases":["bouquet"]},{"emoji":"🇧🇻","aliases":["bouvet_island"]},{"emoji":"🙇","aliases":["bow"]},{"emoji":"🏹","aliases":["bow_and_arrow"]},{"emoji":"🙇‍♂️","aliases":["bowing_man"]},{"emoji":"🙇‍♀️","aliases":["bowing_woman"]},{"emoji":"🥣","aliases":["bowl_with_spoon"]},{"emoji":"🎳","aliases":["bowling"]},{"emoji":"🥊","aliases":["boxing_glove"]},{"emoji":"👦","aliases":["boy"]},{"emoji":"🧠","aliases":["brain"]},{"emoji":"🇧🇷","aliases":["brazil"]},{"emoji":"🍞","aliases":["bread"]},{"emoji":"🤱","aliases":["breast_feeding"]},{"emoji":"🧱","aliases":["bricks"]},{"emoji":"🌉","aliases":["bridge_at_night"]},{"emoji":"💼","aliases":["briefcase"]},{"emoji":"🇮🇴","aliases":["british_indian_ocean_territory"]},{"emoji":"🇻🇬","aliases":["british_virgin_islands"]},{"emoji":"🥦","aliases":["broccoli"]},{"emoji":"💔","aliases":["broken_heart"]},{"emoji":"🧹","aliases":["broom"]},{"emoji":"🟤","aliases":["brown_circle"]},{"emoji":"🤎","aliases":["brown_heart"]},{"emoji":"🟫","aliases":["brown_square"]},{"emoji":"🇧🇳","aliases":["brunei"]},{"emoji":"🐛","aliases":["bug"]},{"emoji":"🏗️","aliases":["building_construction"]},{"emoji":"💡","aliases":["bulb"]},{"emoji":"🇧🇬","aliases":["bulgaria"]},{"emoji":"🚅","aliases":["bullettrain_front"]},{"emoji":"🚄","aliases":["bullettrain_side"]},{"emoji":"🇧🇫","aliases":["burkina_faso"]},{"emoji":"🌯","aliases":["burrito"]},{"emoji":"🇧🇮","aliases":["burundi"]},{"emoji":"🚌","aliases":["bus"]},{"emoji":"🕴️","aliases":["business_suit_levitating"]},{"emoji":"🚏","aliases":["busstop"]},{"emoji":"👤","aliases":["bust_in_silhouette"]},{"emoji":"👥","aliases":["busts_in_silhouette"]},{"emoji":"🧈","aliases":["butter"]},{"emoji":"🦋","aliases":["butterfly"]},{"emoji":"🌵","aliases":["cactus"]},{"emoji":"🍰","aliases":["cake"]},{"emoji":"📆","aliases":["calendar"]},{"emoji":"🤙","aliases":["call_me_hand"]},{"emoji":"📲","aliases":["calling"]},{"emoji":"🇰🇭","aliases":["cambodia"]},{"emoji":"🐫","aliases":["camel"]},{"emoji":"📷","aliases":["camera"]},{"emoji":"📸","aliases":["camera_flash"]},{"emoji":"🇨🇲","aliases":["cameroon"]},{"emoji":"🏕️","aliases":["camping"]},{"emoji":"🇨🇦","aliases":["canada"]},{"emoji":"🇮🇨","aliases":["canary_islands"]},{"emoji":"♋","aliases":["cancer"]},{"emoji":"🕯️","aliases":["candle"]},{"emoji":"🍬","aliases":["candy"]},{"emoji":"🥫","aliases":["canned_food"]},{"emoji":"🛶","aliases":["canoe"]},{"emoji":"🇨🇻","aliases":["cape_verde"]},{"emoji":"🔠","aliases":["capital_abcd"]},{"emoji":"♑","aliases":["capricorn"]},{"emoji":"🚗","aliases":["car","red_car"]},{"emoji":"🗃️","aliases":["card_file_box"]},{"emoji":"📇","aliases":["card_index"]},{"emoji":"🗂️","aliases":["card_index_dividers"]},{"emoji":"🇧🇶","aliases":["caribbean_netherlands"]},{"emoji":"🎠","aliases":["carousel_horse"]},{"emoji":"🥕","aliases":["carrot"]},{"emoji":"🤸","aliases":["cartwheeling"]},{"emoji":"🐱","aliases":["cat"]},{"emoji":"🐈","aliases":["cat2"]},{"emoji":"🇰🇾","aliases":["cayman_islands"]},{"emoji":"💿","aliases":["cd"]},{"emoji":"🇨🇫","aliases":["central_african_republic"]},{"emoji":"🇪🇦","aliases":["ceuta_melilla"]},{"emoji":"🇹🇩","aliases":["chad"]},{"emoji":"⛓️","aliases":["chains"]},{"emoji":"🪑","aliases":["chair"]},{"emoji":"🍾","aliases":["champagne"]},{"emoji":"💹","aliases":["chart"]},{"emoji":"📉","aliases":["chart_with_downwards_trend"]},{"emoji":"📈","aliases":["chart_with_upwards_trend"]},{"emoji":"🏁","aliases":["checkered_flag"]},{"emoji":"🧀","aliases":["cheese"]},{"emoji":"🍒","aliases":["cherries"]},{"emoji":"🌸","aliases":["cherry_blossom"]},{"emoji":"♟️","aliases":["chess_pawn"]},{"emoji":"🌰","aliases":["chestnut"]},{"emoji":"🐔","aliases":["chicken"]},{"emoji":"🧒","aliases":["child"]},{"emoji":"🚸","aliases":["children_crossing"]},{"emoji":"🇨🇱","aliases":["chile"]},{"emoji":"🐿️","aliases":["chipmunk"]},{"emoji":"🍫","aliases":["chocolate_bar"]},{"emoji":"🥢","aliases":["chopsticks"]},{"emoji":"🇨🇽","aliases":["christmas_island"]},{"emoji":"🎄","aliases":["christmas_tree"]},{"emoji":"⛪","aliases":["church"]},{"emoji":"🎦","aliases":["cinema"]},{"emoji":"🎪","aliases":["circus_tent"]},{"emoji":"🌇","aliases":["city_sunrise"]},{"emoji":"🌆","aliases":["city_sunset"]},{"emoji":"🏙️","aliases":["cityscape"]},{"emoji":"🆑","aliases":["cl"]},{"emoji":"🗜️","aliases":["clamp"]},{"emoji":"👏","aliases":["clap"]},{"emoji":"🎬","aliases":["clapper"]},{"emoji":"🏛️","aliases":["classical_building"]},{"emoji":"🧗","aliases":["climbing"]},{"emoji":"🧗‍♂️","aliases":["climbing_man"]},{"emoji":"🧗‍♀️","aliases":["climbing_woman"]},{"emoji":"🥂","aliases":["clinking_glasses"]},{"emoji":"📋","aliases":["clipboard"]},{"emoji":"🇨🇵","aliases":["clipperton_island"]},{"emoji":"🕐","aliases":["clock1"]},{"emoji":"🕙","aliases":["clock10"]},{"emoji":"🕥","aliases":["clock1030"]},{"emoji":"🕚","aliases":["clock11"]},{"emoji":"🕦","aliases":["clock1130"]},{"emoji":"🕛","aliases":["clock12"]},{"emoji":"🕧","aliases":["clock1230"]},{"emoji":"🕜","aliases":["clock130"]},{"emoji":"🕑","aliases":["clock2"]},{"emoji":"🕝","aliases":["clock230"]},{"emoji":"🕒","aliases":["clock3"]},{"emoji":"🕞","aliases":["clock330"]},{"emoji":"🕓","aliases":["clock4"]},{"emoji":"🕟","aliases":["clock430"]},{"emoji":"🕔","aliases":["clock5"]},{"emoji":"🕠","aliases":["clock530"]},{"emoji":"🕕","aliases":["clock6"]},{"emoji":"🕡","aliases":["clock630"]},{"emoji":"🕖","aliases":["clock7"]},{"emoji":"🕢","aliases":["clock730"]},{"emoji":"🕗","aliases":["clock8"]},{"emoji":"🕣","aliases":["clock830"]},{"emoji":"🕘","aliases":["clock9"]},{"emoji":"🕤","aliases":["clock930"]},{"emoji":"📕","aliases":["closed_book"]},{"emoji":"🔐","aliases":["closed_lock_with_key"]},{"emoji":"🌂","aliases":["closed_umbrella"]},{"emoji":"☁️","aliases":["cloud"]},{"emoji":"🌩️","aliases":["cloud_with_lightning"]},{"emoji":"⛈️","aliases":["cloud_with_lightning_and_rain"]},{"emoji":"🌧️","aliases":["cloud_with_rain"]},{"emoji":"🌨️","aliases":["cloud_with_snow"]},{"emoji":"🤡","aliases":["clown_face"]},{"emoji":"♣️","aliases":["clubs"]},{"emoji":"🇨🇳","aliases":["cn"]},{"emoji":"🧥","aliases":["coat"]},{"emoji":"🍸","aliases":["cocktail"]},{"emoji":"🥥","aliases":["coconut"]},{"emoji":"🇨🇨","aliases":["cocos_islands"]},{"emoji":"☕","aliases":["coffee"]},{"emoji":"⚰️","aliases":["coffin"]},{"emoji":"🥶","aliases":["cold_face"]},{"emoji":"😰","aliases":["cold_sweat"]},{"emoji":"🇨🇴","aliases":["colombia"]},{"emoji":"☄️","aliases":["comet"]},{"emoji":"🇰🇲","aliases":["comoros"]},{"emoji":"🧭","aliases":["compass"]},{"emoji":"💻","aliases":["computer"]},{"emoji":"🖱️","aliases":["computer_mouse"]},{"emoji":"🎊","aliases":["confetti_ball"]},{"emoji":"😖","aliases":["confounded"]},{"emoji":"😕","aliases":["confused"]},{"emoji":"🇨🇬","aliases":["congo_brazzaville"]},{"emoji":"🇨🇩","aliases":["congo_kinshasa"]},{"emoji":"㊗️","aliases":["congratulations"]},{"emoji":"🚧","aliases":["construction"]},{"emoji":"👷","aliases":["construction_worker"]},{"emoji":"👷‍♂️","aliases":["construction_worker_man"]},{"emoji":"👷‍♀️","aliases":["construction_worker_woman"]},{"emoji":"🎛️","aliases":["control_knobs"]},{"emoji":"🏪","aliases":["convenience_store"]},{"emoji":"🧑‍🍳","aliases":["cook"]},{"emoji":"🇨🇰","aliases":["cook_islands"]},{"emoji":"🍪","aliases":["cookie"]},{"emoji":"🆒","aliases":["cool"]},{"emoji":"©️","aliases":["copyright"]},{"emoji":"🌽","aliases":["corn"]},{"emoji":"🇨🇷","aliases":["costa_rica"]},{"emoji":"🇨🇮","aliases":["cote_divoire"]},{"emoji":"🛋️","aliases":["couch_and_lamp"]},{"emoji":"👫","aliases":["couple"]},{"emoji":"💑","aliases":["couple_with_heart"]},{"emoji":"👨‍❤️‍👨","aliases":["couple_with_heart_man_man"]},{"emoji":"👩‍❤️‍👨","aliases":["couple_with_heart_woman_man"]},{"emoji":"👩‍❤️‍👩","aliases":["couple_with_heart_woman_woman"]},{"emoji":"💏","aliases":["couplekiss"]},{"emoji":"👨‍❤️‍💋‍👨","aliases":["couplekiss_man_man"]},{"emoji":"👩‍❤️‍💋‍👨","aliases":["couplekiss_man_woman"]},{"emoji":"👩‍❤️‍💋‍👩","aliases":["couplekiss_woman_woman"]},{"emoji":"🐮","aliases":["cow"]},{"emoji":"🐄","aliases":["cow2"]},{"emoji":"🤠","aliases":["cowboy_hat_face"]},{"emoji":"🦀","aliases":["crab"]},{"emoji":"🖍️","aliases":["crayon"]},{"emoji":"💳","aliases":["credit_card"]},{"emoji":"🌙","aliases":["crescent_moon"]},{"emoji":"🦗","aliases":["cricket"]},{"emoji":"🏏","aliases":["cricket_game"]},{"emoji":"🇭🇷","aliases":["croatia"]},{"emoji":"🐊","aliases":["crocodile"]},{"emoji":"🥐","aliases":["croissant"]},{"emoji":"🤞","aliases":["crossed_fingers"]},{"emoji":"🎌","aliases":["crossed_flags"]},{"emoji":"⚔️","aliases":["crossed_swords"]},{"emoji":"👑","aliases":["crown"]},{"emoji":"😢","aliases":["cry"]},{"emoji":"😿","aliases":["crying_cat_face"]},{"emoji":"🔮","aliases":["crystal_ball"]},{"emoji":"🇨🇺","aliases":["cuba"]},{"emoji":"🥒","aliases":["cucumber"]},{"emoji":"🥤","aliases":["cup_with_straw"]},{"emoji":"🧁","aliases":["cupcake"]},{"emoji":"💘","aliases":["cupid"]},{"emoji":"🇨🇼","aliases":["curacao"]},{"emoji":"🥌","aliases":["curling_stone"]},{"emoji":"👨‍🦱","aliases":["curly_haired_man"]},{"emoji":"👩‍🦱","aliases":["curly_haired_woman"]},{"emoji":"➰","aliases":["curly_loop"]},{"emoji":"💱","aliases":["currency_exchange"]},{"emoji":"🍛","aliases":["curry"]},{"emoji":"🤬","aliases":["cursing_face"]},{"emoji":"🍮","aliases":["custard"]},{"emoji":"🛃","aliases":["customs"]},{"emoji":"🥩","aliases":["cut_of_meat"]},{"emoji":"🌀","aliases":["cyclone"]},{"emoji":"🇨🇾","aliases":["cyprus"]},{"emoji":"🇨🇿","aliases":["czech_republic"]},{"emoji":"🗡️","aliases":["dagger"]},{"emoji":"👯","aliases":["dancers"]},{"emoji":"👯‍♂️","aliases":["dancing_men"]},{"emoji":"👯‍♀️","aliases":["dancing_women"]},{"emoji":"🍡","aliases":["dango"]},{"emoji":"🕶️","aliases":["dark_sunglasses"]},{"emoji":"🎯","aliases":["dart"]},{"emoji":"💨","aliases":["dash"]},{"emoji":"📅","aliases":["date"]},{"emoji":"🇩🇪","aliases":["de"]},{"emoji":"🧏‍♂️","aliases":["deaf_man"]},{"emoji":"🧏","aliases":["deaf_person"]},{"emoji":"🧏‍♀️","aliases":["deaf_woman"]},{"emoji":"🌳","aliases":["deciduous_tree"]},{"emoji":"🦌","aliases":["deer"]},{"emoji":"🇩🇰","aliases":["denmark"]},{"emoji":"🏬","aliases":["department_store"]},{"emoji":"🏚️","aliases":["derelict_house"]},{"emoji":"🏜️","aliases":["desert"]},{"emoji":"🏝️","aliases":["desert_island"]},{"emoji":"🖥️","aliases":["desktop_computer"]},{"emoji":"🕵️","aliases":["detective"]},{"emoji":"💠","aliases":["diamond_shape_with_a_dot_inside"]},{"emoji":"♦️","aliases":["diamonds"]},{"emoji":"🇩🇬","aliases":["diego_garcia"]},{"emoji":"😞","aliases":["disappointed"]},{"emoji":"😥","aliases":["disappointed_relieved"]},{"emoji":"🤿","aliases":["diving_mask"]},{"emoji":"🪔","aliases":["diya_lamp"]},{"emoji":"💫","aliases":["dizzy"]},{"emoji":"😵","aliases":["dizzy_face"]},{"emoji":"🇩🇯","aliases":["djibouti"]},{"emoji":"🧬","aliases":["dna"]},{"emoji":"🚯","aliases":["do_not_litter"]},{"emoji":"🐶","aliases":["dog"]},{"emoji":"🐕","aliases":["dog2"]},{"emoji":"💵","aliases":["dollar"]},{"emoji":"🎎","aliases":["dolls"]},{"emoji":"🐬","aliases":["dolphin","flipper"]},{"emoji":"🇩🇲","aliases":["dominica"]},{"emoji":"🇩🇴","aliases":["dominican_republic"]},{"emoji":"🚪","aliases":["door"]},{"emoji":"🍩","aliases":["doughnut"]},{"emoji":"🕊️","aliases":["dove"]},{"emoji":"🐉","aliases":["dragon"]},{"emoji":"🐲","aliases":["dragon_face"]},{"emoji":"👗","aliases":["dress"]},{"emoji":"🐪","aliases":["dromedary_camel"]},{"emoji":"🤤","aliases":["drooling_face"]},{"emoji":"🩸","aliases":["drop_of_blood"]},{"emoji":"💧","aliases":["droplet"]},{"emoji":"🥁","aliases":["drum"]},{"emoji":"🦆","aliases":["duck"]},{"emoji":"🥟","aliases":["dumpling"]},{"emoji":"📀","aliases":["dvd"]},{"emoji":"📧","aliases":["e-mail"]},{"emoji":"🦅","aliases":["eagle"]},{"emoji":"👂","aliases":["ear"]},{"emoji":"🌾","aliases":["ear_of_rice"]},{"emoji":"🦻","aliases":["ear_with_hearing_aid"]},{"emoji":"🌍","aliases":["earth_africa"]},{"emoji":"🌎","aliases":["earth_americas"]},{"emoji":"🌏","aliases":["earth_asia"]},{"emoji":"🇪🇨","aliases":["ecuador"]},{"emoji":"🥚","aliases":["egg"]},{"emoji":"🍆","aliases":["eggplant"]},{"emoji":"🇪🇬","aliases":["egypt"]},{"emoji":"8️⃣","aliases":["eight"]},{"emoji":"✴️","aliases":["eight_pointed_black_star"]},{"emoji":"✳️","aliases":["eight_spoked_asterisk"]},{"emoji":"⏏️","aliases":["eject_button"]},{"emoji":"🇸🇻","aliases":["el_salvador"]},{"emoji":"🔌","aliases":["electric_plug"]},{"emoji":"🐘","aliases":["elephant"]},{"emoji":"🧝","aliases":["elf"]},{"emoji":"🧝‍♂️","aliases":["elf_man"]},{"emoji":"🧝‍♀️","aliases":["elf_woman"]},{"emoji":"✉️","aliases":["email","envelope"]},{"emoji":"🔚","aliases":["end"]},{"emoji":"🏴󠁧󠁢󠁥󠁮󠁧󠁿","aliases":["england"]},{"emoji":"📩","aliases":["envelope_with_arrow"]},{"emoji":"🇬🇶","aliases":["equatorial_guinea"]},{"emoji":"🇪🇷","aliases":["eritrea"]},{"emoji":"🇪🇸","aliases":["es"]},{"emoji":"🇪🇪","aliases":["estonia"]},{"emoji":"🇪🇹","aliases":["ethiopia"]},{"emoji":"🇪🇺","aliases":["eu","european_union"]},{"emoji":"💶","aliases":["euro"]},{"emoji":"🏰","aliases":["european_castle"]},{"emoji":"🏤","aliases":["european_post_office"]},{"emoji":"🌲","aliases":["evergreen_tree"]},{"emoji":"❗","aliases":["exclamation","heavy_exclamation_mark"]},{"emoji":"🤯","aliases":["exploding_head"]},{"emoji":"😑","aliases":["expressionless"]},{"emoji":"👁️","aliases":["eye"]},{"emoji":"👁️‍🗨️","aliases":["eye_speech_bubble"]},{"emoji":"👓","aliases":["eyeglasses"]},{"emoji":"👀","aliases":["eyes"]},{"emoji":"🤕","aliases":["face_with_head_bandage"]},{"emoji":"🤒","aliases":["face_with_thermometer"]},{"emoji":"🤦","aliases":["facepalm"]},{"emoji":"🏭","aliases":["factory"]},{"emoji":"🧑‍🏭","aliases":["factory_worker"]},{"emoji":"🧚","aliases":["fairy"]},{"emoji":"🧚‍♂️","aliases":["fairy_man"]},{"emoji":"🧚‍♀️","aliases":["fairy_woman"]},{"emoji":"🧆","aliases":["falafel"]},{"emoji":"🇫🇰","aliases":["falkland_islands"]},{"emoji":"🍂","aliases":["fallen_leaf"]},{"emoji":"👪","aliases":["family"]},{"emoji":"👨‍👦","aliases":["family_man_boy"]},{"emoji":"👨‍👦‍👦","aliases":["family_man_boy_boy"]},{"emoji":"👨‍👧","aliases":["family_man_girl"]},{"emoji":"👨‍👧‍👦","aliases":["family_man_girl_boy"]},{"emoji":"👨‍👧‍👧","aliases":["family_man_girl_girl"]},{"emoji":"👨‍👨‍👦","aliases":["family_man_man_boy"]},{"emoji":"👨‍👨‍👦‍👦","aliases":["family_man_man_boy_boy"]},{"emoji":"👨‍👨‍👧","aliases":["family_man_man_girl"]},{"emoji":"👨‍👨‍👧‍👦","aliases":["family_man_man_girl_boy"]},{"emoji":"👨‍👨‍👧‍👧","aliases":["family_man_man_girl_girl"]},{"emoji":"👨‍👩‍👦","aliases":["family_man_woman_boy"]},{"emoji":"👨‍👩‍👦‍👦","aliases":["family_man_woman_boy_boy"]},{"emoji":"👨‍👩‍👧","aliases":["family_man_woman_girl"]},{"emoji":"👨‍👩‍👧‍👦","aliases":["family_man_woman_girl_boy"]},{"emoji":"👨‍👩‍👧‍👧","aliases":["family_man_woman_girl_girl"]},{"emoji":"👩‍👦","aliases":["family_woman_boy"]},{"emoji":"👩‍👦‍👦","aliases":["family_woman_boy_boy"]},{"emoji":"👩‍👧","aliases":["family_woman_girl"]},{"emoji":"👩‍👧‍👦","aliases":["family_woman_girl_boy"]},{"emoji":"👩‍👧‍👧","aliases":["family_woman_girl_girl"]},{"emoji":"👩‍👩‍👦","aliases":["family_woman_woman_boy"]},{"emoji":"👩‍👩‍👦‍👦","aliases":["family_woman_woman_boy_boy"]},{"emoji":"👩‍👩‍👧","aliases":["family_woman_woman_girl"]},{"emoji":"👩‍👩‍👧‍👦","aliases":["family_woman_woman_girl_boy"]},{"emoji":"👩‍👩‍👧‍👧","aliases":["family_woman_woman_girl_girl"]},{"emoji":"🧑‍🌾","aliases":["farmer"]},{"emoji":"🇫🇴","aliases":["faroe_islands"]},{"emoji":"⏩","aliases":["fast_forward"]},{"emoji":"📠","aliases":["fax"]},{"emoji":"😨","aliases":["fearful"]},{"emoji":"🐾","aliases":["feet","paw_prints"]},{"emoji":"🕵️‍♀️","aliases":["female_detective"]},{"emoji":"♀️","aliases":["female_sign"]},{"emoji":"🎡","aliases":["ferris_wheel"]},{"emoji":"⛴️","aliases":["ferry"]},{"emoji":"🏑","aliases":["field_hockey"]},{"emoji":"🇫🇯","aliases":["fiji"]},{"emoji":"🗄️","aliases":["file_cabinet"]},{"emoji":"📁","aliases":["file_folder"]},{"emoji":"📽️","aliases":["film_projector"]},{"emoji":"🎞️","aliases":["film_strip"]},{"emoji":"🇫🇮","aliases":["finland"]},{"emoji":"🔥","aliases":["fire"]},{"emoji":"🚒","aliases":["fire_engine"]},{"emoji":"🧯","aliases":["fire_extinguisher"]},{"emoji":"🧨","aliases":["firecracker"]},{"emoji":"🧑‍🚒","aliases":["firefighter"]},{"emoji":"🎆","aliases":["fireworks"]},{"emoji":"🌓","aliases":["first_quarter_moon"]},{"emoji":"🌛","aliases":["first_quarter_moon_with_face"]},{"emoji":"🐟","aliases":["fish"]},{"emoji":"🍥","aliases":["fish_cake"]},{"emoji":"🎣","aliases":["fishing_pole_and_fish"]},{"emoji":"🤛","aliases":["fist_left"]},{"emoji":"👊","aliases":["fist_oncoming","facepunch","punch"]},{"emoji":"✊","aliases":["fist_raised","fist"]},{"emoji":"🤜","aliases":["fist_right"]},{"emoji":"5️⃣","aliases":["five"]},{"emoji":"🎏","aliases":["flags"]},{"emoji":"🦩","aliases":["flamingo"]},{"emoji":"🔦","aliases":["flashlight"]},{"emoji":"🥿","aliases":["flat_shoe"]},{"emoji":"⚜️","aliases":["fleur_de_lis"]},{"emoji":"🛬","aliases":["flight_arrival"]},{"emoji":"🛫","aliases":["flight_departure"]},{"emoji":"💾","aliases":["floppy_disk"]},{"emoji":"🎴","aliases":["flower_playing_cards"]},{"emoji":"😳","aliases":["flushed"]},{"emoji":"🥏","aliases":["flying_disc"]},{"emoji":"🛸","aliases":["flying_saucer"]},{"emoji":"🌫️","aliases":["fog"]},{"emoji":"🌁","aliases":["foggy"]},{"emoji":"🦶","aliases":["foot"]},{"emoji":"🏈","aliases":["football"]},{"emoji":"👣","aliases":["footprints"]},{"emoji":"🍴","aliases":["fork_and_knife"]},{"emoji":"🥠","aliases":["fortune_cookie"]},{"emoji":"⛲","aliases":["fountain"]},{"emoji":"🖋️","aliases":["fountain_pen"]},{"emoji":"4️⃣","aliases":["four"]},{"emoji":"🍀","aliases":["four_leaf_clover"]},{"emoji":"🦊","aliases":["fox_face"]},{"emoji":"🇫🇷","aliases":["fr"]},{"emoji":"🖼️","aliases":["framed_picture"]},{"emoji":"🆓","aliases":["free"]},{"emoji":"🇬🇫","aliases":["french_guiana"]},{"emoji":"🇵🇫","aliases":["french_polynesia"]},{"emoji":"🇹🇫","aliases":["french_southern_territories"]},{"emoji":"🍳","aliases":["fried_egg"]},{"emoji":"🍤","aliases":["fried_shrimp"]},{"emoji":"🍟","aliases":["fries"]},{"emoji":"🐸","aliases":["frog"]},{"emoji":"😦","aliases":["frowning"]},{"emoji":"☹️","aliases":["frowning_face"]},{"emoji":"🙍‍♂️","aliases":["frowning_man"]},{"emoji":"🙍","aliases":["frowning_person"]},{"emoji":"🙍‍♀️","aliases":["frowning_woman"]},{"emoji":"⛽","aliases":["fuelpump"]},{"emoji":"🌕","aliases":["full_moon"]},{"emoji":"🌝","aliases":["full_moon_with_face"]},{"emoji":"⚱️","aliases":["funeral_urn"]},{"emoji":"🇬🇦","aliases":["gabon"]},{"emoji":"🇬🇲","aliases":["gambia"]},{"emoji":"🎲","aliases":["game_die"]},{"emoji":"🧄","aliases":["garlic"]},{"emoji":"🇬🇧","aliases":["gb","uk"]},{"emoji":"⚙️","aliases":["gear"]},{"emoji":"💎","aliases":["gem"]},{"emoji":"♊","aliases":["gemini"]},{"emoji":"🧞","aliases":["genie"]},{"emoji":"🧞‍♂️","aliases":["genie_man"]},{"emoji":"🧞‍♀️","aliases":["genie_woman"]},{"emoji":"🇬🇪","aliases":["georgia"]},{"emoji":"🇬🇭","aliases":["ghana"]},{"emoji":"👻","aliases":["ghost"]},{"emoji":"🇬🇮","aliases":["gibraltar"]},{"emoji":"🎁","aliases":["gift"]},{"emoji":"💝","aliases":["gift_heart"]},{"emoji":"🦒","aliases":["giraffe"]},{"emoji":"👧","aliases":["girl"]},{"emoji":"🌐","aliases":["globe_with_meridians"]},{"emoji":"🧤","aliases":["gloves"]},{"emoji":"🥅","aliases":["goal_net"]},{"emoji":"🐐","aliases":["goat"]},{"emoji":"🥽","aliases":["goggles"]},{"emoji":"⛳","aliases":["golf"]},{"emoji":"🏌️","aliases":["golfing"]},{"emoji":"🏌️‍♂️","aliases":["golfing_man"]},{"emoji":"🏌️‍♀️","aliases":["golfing_woman"]},{"emoji":"🦍","aliases":["gorilla"]},{"emoji":"🍇","aliases":["grapes"]},{"emoji":"🇬🇷","aliases":["greece"]},{"emoji":"🍏","aliases":["green_apple"]},{"emoji":"📗","aliases":["green_book"]},{"emoji":"🟢","aliases":["green_circle"]},{"emoji":"💚","aliases":["green_heart"]},{"emoji":"🥗","aliases":["green_salad"]},{"emoji":"🟩","aliases":["green_square"]},{"emoji":"🇬🇱","aliases":["greenland"]},{"emoji":"🇬🇩","aliases":["grenada"]},{"emoji":"❕","aliases":["grey_exclamation"]},{"emoji":"❔","aliases":["grey_question"]},{"emoji":"😬","aliases":["grimacing"]},{"emoji":"😁","aliases":["grin"]},{"emoji":"😀","aliases":["grinning"]},{"emoji":"🇬🇵","aliases":["guadeloupe"]},{"emoji":"🇬🇺","aliases":["guam"]},{"emoji":"💂","aliases":["guard"]},{"emoji":"💂‍♂️","aliases":["guardsman"]},{"emoji":"💂‍♀️","aliases":["guardswoman"]},{"emoji":"🇬🇹","aliases":["guatemala"]},{"emoji":"🇬🇬","aliases":["guernsey"]},{"emoji":"🦮","aliases":["guide_dog"]},{"emoji":"🇬🇳","aliases":["guinea"]},{"emoji":"🇬🇼","aliases":["guinea_bissau"]},{"emoji":"🎸","aliases":["guitar"]},{"emoji":"🔫","aliases":["gun"]},{"emoji":"🇬🇾","aliases":["guyana"]},{"emoji":"💇","aliases":["haircut"]},{"emoji":"💇‍♂️","aliases":["haircut_man"]},{"emoji":"💇‍♀️","aliases":["haircut_woman"]},{"emoji":"🇭🇹","aliases":["haiti"]},{"emoji":"🍔","aliases":["hamburger"]},{"emoji":"🔨","aliases":["hammer"]},{"emoji":"⚒️","aliases":["hammer_and_pick"]},{"emoji":"🛠️","aliases":["hammer_and_wrench"]},{"emoji":"🐹","aliases":["hamster"]},{"emoji":"✋","aliases":["hand","raised_hand"]},{"emoji":"🤭","aliases":["hand_over_mouth"]},{"emoji":"👜","aliases":["handbag"]},{"emoji":"🤾","aliases":["handball_person"]},{"emoji":"🤝","aliases":["handshake"]},{"emoji":"💩","aliases":["hankey","poop","shit"]},{"emoji":"#️⃣","aliases":["hash"]},{"emoji":"🐥","aliases":["hatched_chick"]},{"emoji":"🐣","aliases":["hatching_chick"]},{"emoji":"🎧","aliases":["headphones"]},{"emoji":"🧑‍⚕️","aliases":["health_worker"]},{"emoji":"🙉","aliases":["hear_no_evil"]},{"emoji":"🇭🇲","aliases":["heard_mcdonald_islands"]},{"emoji":"❤️","aliases":["heart"]},{"emoji":"💟","aliases":["heart_decoration"]},{"emoji":"😍","aliases":["heart_eyes"]},{"emoji":"😻","aliases":["heart_eyes_cat"]},{"emoji":"💓","aliases":["heartbeat"]},{"emoji":"💗","aliases":["heartpulse"]},{"emoji":"♥️","aliases":["hearts"]},{"emoji":"✔️","aliases":["heavy_check_mark"]},{"emoji":"➗","aliases":["heavy_division_sign"]},{"emoji":"💲","aliases":["heavy_dollar_sign"]},{"emoji":"❣️","aliases":["heavy_heart_exclamation"]},{"emoji":"➖","aliases":["heavy_minus_sign"]},{"emoji":"✖️","aliases":["heavy_multiplication_x"]},{"emoji":"➕","aliases":["heavy_plus_sign"]},{"emoji":"🦔","aliases":["hedgehog"]},{"emoji":"🚁","aliases":["helicopter"]},{"emoji":"🌿","aliases":["herb"]},{"emoji":"🌺","aliases":["hibiscus"]},{"emoji":"🔆","aliases":["high_brightness"]},{"emoji":"👠","aliases":["high_heel"]},{"emoji":"🥾","aliases":["hiking_boot"]},{"emoji":"🛕","aliases":["hindu_temple"]},{"emoji":"🦛","aliases":["hippopotamus"]},{"emoji":"🔪","aliases":["hocho","knife"]},{"emoji":"🕳️","aliases":["hole"]},{"emoji":"🇭🇳","aliases":["honduras"]},{"emoji":"🍯","aliases":["honey_pot"]},{"emoji":"🇭🇰","aliases":["hong_kong"]},{"emoji":"🐴","aliases":["horse"]},{"emoji":"🏇","aliases":["horse_racing"]},{"emoji":"🏥","aliases":["hospital"]},{"emoji":"🥵","aliases":["hot_face"]},{"emoji":"🌶️","aliases":["hot_pepper"]},{"emoji":"🌭","aliases":["hotdog"]},{"emoji":"🏨","aliases":["hotel"]},{"emoji":"♨️","aliases":["hotsprings"]},{"emoji":"⌛","aliases":["hourglass"]},{"emoji":"⏳","aliases":["hourglass_flowing_sand"]},{"emoji":"🏠","aliases":["house"]},{"emoji":"🏡","aliases":["house_with_garden"]},{"emoji":"🏘️","aliases":["houses"]},{"emoji":"🤗","aliases":["hugs"]},{"emoji":"🇭🇺","aliases":["hungary"]},{"emoji":"😯","aliases":["hushed"]},{"emoji":"🍨","aliases":["ice_cream"]},{"emoji":"🧊","aliases":["ice_cube"]},{"emoji":"🏒","aliases":["ice_hockey"]},{"emoji":"⛸️","aliases":["ice_skate"]},{"emoji":"🍦","aliases":["icecream"]},{"emoji":"🇮🇸","aliases":["iceland"]},{"emoji":"🆔","aliases":["id"]},{"emoji":"🉐","aliases":["ideograph_advantage"]},{"emoji":"👿","aliases":["imp"]},{"emoji":"📥","aliases":["inbox_tray"]},{"emoji":"📨","aliases":["incoming_envelope"]},{"emoji":"🇮🇳","aliases":["india"]},{"emoji":"🇮🇩","aliases":["indonesia"]},{"emoji":"♾️","aliases":["infinity"]},{"emoji":"ℹ️","aliases":["information_source"]},{"emoji":"😇","aliases":["innocent"]},{"emoji":"⁉️","aliases":["interrobang"]},{"emoji":"📱","aliases":["iphone"]},{"emoji":"🇮🇷","aliases":["iran"]},{"emoji":"🇮🇶","aliases":["iraq"]},{"emoji":"🇮🇪","aliases":["ireland"]},{"emoji":"🇮🇲","aliases":["isle_of_man"]},{"emoji":"🇮🇱","aliases":["israel"]},{"emoji":"🇮🇹","aliases":["it"]},{"emoji":"🏮","aliases":["izakaya_lantern","lantern"]},{"emoji":"🎃","aliases":["jack_o_lantern"]},{"emoji":"🇯🇲","aliases":["jamaica"]},{"emoji":"🗾","aliases":["japan"]},{"emoji":"🏯","aliases":["japanese_castle"]},{"emoji":"👺","aliases":["japanese_goblin"]},{"emoji":"👹","aliases":["japanese_ogre"]},{"emoji":"👖","aliases":["jeans"]},{"emoji":"🇯🇪","aliases":["jersey"]},{"emoji":"🧩","aliases":["jigsaw"]},{"emoji":"🇯🇴","aliases":["jordan"]},{"emoji":"😂","aliases":["joy"]},{"emoji":"😹","aliases":["joy_cat"]},{"emoji":"🕹️","aliases":["joystick"]},{"emoji":"🇯🇵","aliases":["jp"]},{"emoji":"🧑‍⚖️","aliases":["judge"]},{"emoji":"🤹","aliases":["juggling_person"]},{"emoji":"🕋","aliases":["kaaba"]},{"emoji":"🦘","aliases":["kangaroo"]},{"emoji":"🇰🇿","aliases":["kazakhstan"]},{"emoji":"🇰🇪","aliases":["kenya"]},{"emoji":"🔑","aliases":["key"]},{"emoji":"⌨️","aliases":["keyboard"]},{"emoji":"🔟","aliases":["keycap_ten"]},{"emoji":"🛴","aliases":["kick_scooter"]},{"emoji":"👘","aliases":["kimono"]},{"emoji":"🇰🇮","aliases":["kiribati"]},{"emoji":"💋","aliases":["kiss"]},{"emoji":"😗","aliases":["kissing"]},{"emoji":"😽","aliases":["kissing_cat"]},{"emoji":"😚","aliases":["kissing_closed_eyes"]},{"emoji":"😘","aliases":["kissing_heart"]},{"emoji":"😙","aliases":["kissing_smiling_eyes"]},{"emoji":"🪁","aliases":["kite"]},{"emoji":"🥝","aliases":["kiwi_fruit"]},{"emoji":"🧎‍♂️","aliases":["kneeling_man"]},{"emoji":"🧎","aliases":["kneeling_person"]},{"emoji":"🧎‍♀️","aliases":["kneeling_woman"]},{"emoji":"🐨","aliases":["koala"]},{"emoji":"🈁","aliases":["koko"]},{"emoji":"🇽🇰","aliases":["kosovo"]},{"emoji":"🇰🇷","aliases":["kr"]},{"emoji":"🇰🇼","aliases":["kuwait"]},{"emoji":"🇰🇬","aliases":["kyrgyzstan"]},{"emoji":"🥼","aliases":["lab_coat"]},{"emoji":"🏷️","aliases":["label"]},{"emoji":"🥍","aliases":["lacrosse"]},{"emoji":"🐞","aliases":["lady_beetle"]},{"emoji":"🇱🇦","aliases":["laos"]},{"emoji":"🔵","aliases":["large_blue_circle"]},{"emoji":"🔷","aliases":["large_blue_diamond"]},{"emoji":"🔶","aliases":["large_orange_diamond"]},{"emoji":"🌗","aliases":["last_quarter_moon"]},{"emoji":"🌜","aliases":["last_quarter_moon_with_face"]},{"emoji":"✝️","aliases":["latin_cross"]},{"emoji":"🇱🇻","aliases":["latvia"]},{"emoji":"😆","aliases":["laughing","satisfied","laugh"]},{"emoji":"🥬","aliases":["leafy_green"]},{"emoji":"🍃","aliases":["leaves"]},{"emoji":"🇱🇧","aliases":["lebanon"]},{"emoji":"📒","aliases":["ledger"]},{"emoji":"🛅","aliases":["left_luggage"]},{"emoji":"↔️","aliases":["left_right_arrow"]},{"emoji":"🗨️","aliases":["left_speech_bubble"]},{"emoji":"↩️","aliases":["leftwards_arrow_with_hook"]},{"emoji":"🦵","aliases":["leg"]},{"emoji":"🍋","aliases":["lemon"]},{"emoji":"♌","aliases":["leo"]},{"emoji":"🐆","aliases":["leopard"]},{"emoji":"🇱🇸","aliases":["lesotho"]},{"emoji":"🎚️","aliases":["level_slider"]},{"emoji":"🇱🇷","aliases":["liberia"]},{"emoji":"♎","aliases":["libra"]},{"emoji":"🇱🇾","aliases":["libya"]},{"emoji":"🇱🇮","aliases":["liechtenstein"]},{"emoji":"🚈","aliases":["light_rail"]},{"emoji":"🔗","aliases":["link"]},{"emoji":"🦁","aliases":["lion"]},{"emoji":"👄","aliases":["lips"]},{"emoji":"💄","aliases":["lipstick"]},{"emoji":"🇱🇹","aliases":["lithuania"]},{"emoji":"🦎","aliases":["lizard"]},{"emoji":"🦙","aliases":["llama"]},{"emoji":"🦞","aliases":["lobster"]},{"emoji":"🔒","aliases":["lock"]},{"emoji":"🔏","aliases":["lock_with_ink_pen"]},{"emoji":"🍭","aliases":["lollipop"]},{"emoji":"➿","aliases":["loop"]},{"emoji":"🧴","aliases":["lotion_bottle"]},{"emoji":"🧘","aliases":["lotus_position"]},{"emoji":"🧘‍♂️","aliases":["lotus_position_man"]},{"emoji":"🧘‍♀️","aliases":["lotus_position_woman"]},{"emoji":"🔊","aliases":["loud_sound"]},{"emoji":"📢","aliases":["loudspeaker"]},{"emoji":"🏩","aliases":["love_hotel"]},{"emoji":"💌","aliases":["love_letter"]},{"emoji":"🤟","aliases":["love_you_gesture"]},{"emoji":"🔅","aliases":["low_brightness"]},{"emoji":"🧳","aliases":["luggage"]},{"emoji":"🇱🇺","aliases":["luxembourg"]},{"emoji":"🤥","aliases":["lying_face"]},{"emoji":"Ⓜ️","aliases":["m"]},{"emoji":"🇲🇴","aliases":["macau"]},{"emoji":"🇲🇰","aliases":["macedonia"]},{"emoji":"🇲🇬","aliases":["madagascar"]},{"emoji":"🔍","aliases":["mag"]},{"emoji":"🔎","aliases":["mag_right"]},{"emoji":"🧙","aliases":["mage"]},{"emoji":"🧙‍♂️","aliases":["mage_man"]},{"emoji":"🧙‍♀️","aliases":["mage_woman"]},{"emoji":"🧲","aliases":["magnet"]},{"emoji":"🀄","aliases":["mahjong"]},{"emoji":"📫","aliases":["mailbox"]},{"emoji":"📪","aliases":["mailbox_closed"]},{"emoji":"📬","aliases":["mailbox_with_mail"]},{"emoji":"📭","aliases":["mailbox_with_no_mail"]},{"emoji":"🇲🇼","aliases":["malawi"]},{"emoji":"🇲🇾","aliases":["malaysia"]},{"emoji":"🇲🇻","aliases":["maldives"]},{"emoji":"🕵️‍♂️","aliases":["male_detective"]},{"emoji":"♂️","aliases":["male_sign"]},{"emoji":"🇲🇱","aliases":["mali"]},{"emoji":"🇲🇹","aliases":["malta"]},{"emoji":"👨","aliases":["man"]},{"emoji":"👨‍🎨","aliases":["man_artist"]},{"emoji":"👨‍🚀","aliases":["man_astronaut"]},{"emoji":"🤸‍♂️","aliases":["man_cartwheeling"]},{"emoji":"👨‍🍳","aliases":["man_cook"]},{"emoji":"🕺","aliases":["man_dancing"]},{"emoji":"🤦‍♂️","aliases":["man_facepalming"]},{"emoji":"👨‍🏭","aliases":["man_factory_worker"]},{"emoji":"👨‍🌾","aliases":["man_farmer"]},{"emoji":"👨‍🚒","aliases":["man_firefighter"]},{"emoji":"👨‍⚕️","aliases":["man_health_worker"]},{"emoji":"👨‍🦽","aliases":["man_in_manual_wheelchair"]},{"emoji":"👨‍🦼","aliases":["man_in_motorized_wheelchair"]},{"emoji":"👨‍⚖️","aliases":["man_judge"]},{"emoji":"🤹‍♂️","aliases":["man_juggling"]},{"emoji":"👨‍🔧","aliases":["man_mechanic"]},{"emoji":"👨‍💼","aliases":["man_office_worker"]},{"emoji":"👨‍✈️","aliases":["man_pilot"]},{"emoji":"🤾‍♂️","aliases":["man_playing_handball"]},{"emoji":"🤽‍♂️","aliases":["man_playing_water_polo"]},{"emoji":"👨‍🔬","aliases":["man_scientist"]},{"emoji":"🤷‍♂️","aliases":["man_shrugging"]},{"emoji":"👨‍🎤","aliases":["man_singer"]},{"emoji":"👨‍🎓","aliases":["man_student"]},{"emoji":"👨‍🏫","aliases":["man_teacher"]},{"emoji":"👨‍💻","aliases":["man_technologist"]},{"emoji":"👲","aliases":["man_with_gua_pi_mao"]},{"emoji":"👨‍🦯","aliases":["man_with_probing_cane"]},{"emoji":"👳‍♂️","aliases":["man_with_turban"]},{"emoji":"🥭","aliases":["mango"]},{"emoji":"👞","aliases":["mans_shoe","shoe"]},{"emoji":"🕰️","aliases":["mantelpiece_clock"]},{"emoji":"🦽","aliases":["manual_wheelchair"]},{"emoji":"🍁","aliases":["maple_leaf"]},{"emoji":"🇲🇭","aliases":["marshall_islands"]},{"emoji":"🥋","aliases":["martial_arts_uniform"]},{"emoji":"🇲🇶","aliases":["martinique"]},{"emoji":"😷","aliases":["mask"]},{"emoji":"💆","aliases":["massage"]},{"emoji":"💆‍♂️","aliases":["massage_man"]},{"emoji":"💆‍♀️","aliases":["massage_woman"]},{"emoji":"🧉","aliases":["mate"]},{"emoji":"🇲🇷","aliases":["mauritania"]},{"emoji":"🇲🇺","aliases":["mauritius"]},{"emoji":"🇾🇹","aliases":["mayotte"]},{"emoji":"🍖","aliases":["meat_on_bone"]},{"emoji":"🧑‍🔧","aliases":["mechanic"]},{"emoji":"🦾","aliases":["mechanical_arm"]},{"emoji":"🦿","aliases":["mechanical_leg"]},{"emoji":"🎖️","aliases":["medal_military"]},{"emoji":"🏅","aliases":["medal_sports"]},{"emoji":"⚕️","aliases":["medical_symbol"]},{"emoji":"📣","aliases":["mega"]},{"emoji":"🍈","aliases":["melon"]},{"emoji":"📝","aliases":["memo","pencil"]},{"emoji":"🤼‍♂️","aliases":["men_wrestling"]},{"emoji":"🕎","aliases":["menorah"]},{"emoji":"🚹","aliases":["mens"]},{"emoji":"🧜‍♀️","aliases":["mermaid"]},{"emoji":"🧜‍♂️","aliases":["merman"]},{"emoji":"🧜","aliases":["merperson"]},{"emoji":"🤘","aliases":["metal"]},{"emoji":"🚇","aliases":["metro"]},{"emoji":"🇲🇽","aliases":["mexico"]},{"emoji":"🦠","aliases":["microbe"]},{"emoji":"🇫🇲","aliases":["micronesia"]},{"emoji":"🎤","aliases":["microphone"]},{"emoji":"🔬","aliases":["microscope"]},{"emoji":"🖕","aliases":["middle_finger","fu"]},{"emoji":"🥛","aliases":["milk_glass"]},{"emoji":"🌌","aliases":["milky_way"]},{"emoji":"🚐","aliases":["minibus"]},{"emoji":"💽","aliases":["minidisc"]},{"emoji":"📴","aliases":["mobile_phone_off"]},{"emoji":"🇲🇩","aliases":["moldova"]},{"emoji":"🇲🇨","aliases":["monaco"]},{"emoji":"🤑","aliases":["money_mouth_face"]},{"emoji":"💸","aliases":["money_with_wings"]},{"emoji":"💰","aliases":["moneybag"]},{"emoji":"🇲🇳","aliases":["mongolia"]},{"emoji":"🐒","aliases":["monkey"]},{"emoji":"🐵","aliases":["monkey_face"]},{"emoji":"🧐","aliases":["monocle_face"]},{"emoji":"🚝","aliases":["monorail"]},{"emoji":"🇲🇪","aliases":["montenegro"]},{"emoji":"🇲🇸","aliases":["montserrat"]},{"emoji":"🌔","aliases":["moon","waxing_gibbous_moon"]},{"emoji":"🥮","aliases":["moon_cake"]},{"emoji":"🇲🇦","aliases":["morocco"]},{"emoji":"🎓","aliases":["mortar_board"]},{"emoji":"🕌","aliases":["mosque"]},{"emoji":"🦟","aliases":["mosquito"]},{"emoji":"🛥️","aliases":["motor_boat"]},{"emoji":"🛵","aliases":["motor_scooter"]},{"emoji":"🏍️","aliases":["motorcycle"]},{"emoji":"🦼","aliases":["motorized_wheelchair"]},{"emoji":"🛣️","aliases":["motorway"]},{"emoji":"🗻","aliases":["mount_fuji"]},{"emoji":"⛰️","aliases":["mountain"]},{"emoji":"🚵","aliases":["mountain_bicyclist"]},{"emoji":"🚵‍♂️","aliases":["mountain_biking_man"]},{"emoji":"🚵‍♀️","aliases":["mountain_biking_woman"]},{"emoji":"🚠","aliases":["mountain_cableway"]},{"emoji":"🚞","aliases":["mountain_railway"]},{"emoji":"🏔️","aliases":["mountain_snow"]},{"emoji":"🐭","aliases":["mouse"]},{"emoji":"🐁","aliases":["mouse2"]},{"emoji":"🎥","aliases":["movie_camera"]},{"emoji":"🗿","aliases":["moyai"]},{"emoji":"🇲🇿","aliases":["mozambique"]},{"emoji":"🤶","aliases":["mrs_claus"]},{"emoji":"💪","aliases":["muscle"]},{"emoji":"🍄","aliases":["mushroom"]},{"emoji":"🎹","aliases":["musical_keyboard"]},{"emoji":"🎵","aliases":["musical_note"]},{"emoji":"🎼","aliases":["musical_score"]},{"emoji":"🔇","aliases":["mute"]},{"emoji":"🇲🇲","aliases":["myanmar"]},{"emoji":"💅","aliases":["nail_care"]},{"emoji":"📛","aliases":["name_badge"]},{"emoji":"🇳🇦","aliases":["namibia"]},{"emoji":"🏞️","aliases":["national_park"]},{"emoji":"🇳🇷","aliases":["nauru"]},{"emoji":"🤢","aliases":["nauseated_face"]},{"emoji":"🧿","aliases":["nazar_amulet"]},{"emoji":"👔","aliases":["necktie"]},{"emoji":"❎","aliases":["negative_squared_cross_mark"]},{"emoji":"🇳🇵","aliases":["nepal"]},{"emoji":"🤓","aliases":["nerd_face"]},{"emoji":"🇳🇱","aliases":["netherlands"]},{"emoji":"😐","aliases":["neutral_face"]},{"emoji":"🆕","aliases":["new"]},{"emoji":"🇳🇨","aliases":["new_caledonia"]},{"emoji":"🌑","aliases":["new_moon"]},{"emoji":"🌚","aliases":["new_moon_with_face"]},{"emoji":"🇳🇿","aliases":["new_zealand"]},{"emoji":"📰","aliases":["newspaper"]},{"emoji":"🗞️","aliases":["newspaper_roll"]},{"emoji":"⏭️","aliases":["next_track_button"]},{"emoji":"🆖","aliases":["ng"]},{"emoji":"🇳🇮","aliases":["nicaragua"]},{"emoji":"🇳🇪","aliases":["niger"]},{"emoji":"🇳🇬","aliases":["nigeria"]},{"emoji":"🌃","aliases":["night_with_stars"]},{"emoji":"9️⃣","aliases":["nine"]},{"emoji":"🇳🇺","aliases":["niue"]},{"emoji":"🔕","aliases":["no_bell"]},{"emoji":"🚳","aliases":["no_bicycles"]},{"emoji":"⛔","aliases":["no_entry"]},{"emoji":"🚫","aliases":["no_entry_sign"]},{"emoji":"🙅","aliases":["no_good"]},{"emoji":"🙅‍♂️","aliases":["no_good_man","ng_man"]},{"emoji":"🙅‍♀️","aliases":["no_good_woman","ng_woman"]},{"emoji":"📵","aliases":["no_mobile_phones"]},{"emoji":"😶","aliases":["no_mouth"]},{"emoji":"🚷","aliases":["no_pedestrians"]},{"emoji":"🚭","aliases":["no_smoking"]},{"emoji":"🚱","aliases":["non-potable_water"]},{"emoji":"🇳🇫","aliases":["norfolk_island"]},{"emoji":"🇰🇵","aliases":["north_korea"]},{"emoji":"🇲🇵","aliases":["northern_mariana_islands"]},{"emoji":"🇳🇴","aliases":["norway"]},{"emoji":"👃","aliases":["nose"]},{"emoji":"📓","aliases":["notebook"]},{"emoji":"📔","aliases":["notebook_with_decorative_cover"]},{"emoji":"🎶","aliases":["notes"]},{"emoji":"🔩","aliases":["nut_and_bolt"]},{"emoji":"⭕","aliases":["o"]},{"emoji":"🅾️","aliases":["o2"]},{"emoji":"🌊","aliases":["ocean"]},{"emoji":"🐙","aliases":["octopus"]},{"emoji":"🍢","aliases":["oden"]},{"emoji":"🏢","aliases":["office"]},{"emoji":"🧑‍💼","aliases":["office_worker"]},{"emoji":"🛢️","aliases":["oil_drum"]},{"emoji":"🆗","aliases":["ok"]},{"emoji":"👌","aliases":["ok_hand"]},{"emoji":"🙆‍♂️","aliases":["ok_man"]},{"emoji":"🙆","aliases":["ok_person"]},{"emoji":"🙆‍♀️","aliases":["ok_woman"]},{"emoji":"🗝️","aliases":["old_key"]},{"emoji":"🧓","aliases":["older_adult"]},{"emoji":"👴","aliases":["older_man"]},{"emoji":"👵","aliases":["older_woman"]},{"emoji":"🕉️","aliases":["om"]},{"emoji":"🇴🇲","aliases":["oman"]},{"emoji":"🔛","aliases":["on"]},{"emoji":"🚘","aliases":["oncoming_automobile"]},{"emoji":"🚍","aliases":["oncoming_bus"]},{"emoji":"🚔","aliases":["oncoming_police_car"]},{"emoji":"🚖","aliases":["oncoming_taxi"]},{"emoji":"1️⃣","aliases":["one"]},{"emoji":"🩱","aliases":["one_piece_swimsuit"]},{"emoji":"🧅","aliases":["onion"]},{"emoji":"📂","aliases":["open_file_folder"]},{"emoji":"👐","aliases":["open_hands"]},{"emoji":"😮","aliases":["open_mouth"]},{"emoji":"☂️","aliases":["open_umbrella"]},{"emoji":"⛎","aliases":["ophiuchus"]},{"emoji":"📙","aliases":["orange_book"]},{"emoji":"🟠","aliases":["orange_circle"]},{"emoji":"🧡","aliases":["orange_heart"]},{"emoji":"🟧","aliases":["orange_square"]},{"emoji":"🦧","aliases":["orangutan"]},{"emoji":"☦️","aliases":["orthodox_cross"]},{"emoji":"🦦","aliases":["otter"]},{"emoji":"📤","aliases":["outbox_tray"]},{"emoji":"🦉","aliases":["owl"]},{"emoji":"🐂","aliases":["ox"]},{"emoji":"🦪","aliases":["oyster"]},{"emoji":"📦","aliases":["package"]},{"emoji":"📄","aliases":["page_facing_up"]},{"emoji":"📃","aliases":["page_with_curl"]},{"emoji":"📟","aliases":["pager"]},{"emoji":"🖌️","aliases":["paintbrush"]},{"emoji":"🇵🇰","aliases":["pakistan"]},{"emoji":"🇵🇼","aliases":["palau"]},{"emoji":"🇵🇸","aliases":["palestinian_territories"]},{"emoji":"🌴","aliases":["palm_tree"]},{"emoji":"🤲","aliases":["palms_up_together"]},{"emoji":"🇵🇦","aliases":["panama"]},{"emoji":"🥞","aliases":["pancakes"]},{"emoji":"🐼","aliases":["panda_face"]},{"emoji":"📎","aliases":["paperclip"]},{"emoji":"🖇️","aliases":["paperclips"]},{"emoji":"🇵🇬","aliases":["papua_new_guinea"]},{"emoji":"🪂","aliases":["parachute"]},{"emoji":"🇵🇾","aliases":["paraguay"]},{"emoji":"⛱️","aliases":["parasol_on_ground"]},{"emoji":"🅿️","aliases":["parking"]},{"emoji":"🦜","aliases":["parrot"]},{"emoji":"〽️","aliases":["part_alternation_mark"]},{"emoji":"⛅","aliases":["partly_sunny"]},{"emoji":"🥳","aliases":["partying_face"]},{"emoji":"🛳️","aliases":["passenger_ship"]},{"emoji":"🛂","aliases":["passport_control"]},{"emoji":"⏸️","aliases":["pause_button"]},{"emoji":"☮️","aliases":["peace_symbol"]},{"emoji":"🍑","aliases":["peach"]},{"emoji":"🦚","aliases":["peacock"]},{"emoji":"🥜","aliases":["peanuts"]},{"emoji":"🍐","aliases":["pear"]},{"emoji":"🖊️","aliases":["pen"]},{"emoji":"✏️","aliases":["pencil2"]},{"emoji":"🐧","aliases":["penguin"]},{"emoji":"😔","aliases":["pensive"]},{"emoji":"🧑‍🤝‍🧑","aliases":["people_holding_hands"]},{"emoji":"🎭","aliases":["performing_arts"]},{"emoji":"😣","aliases":["persevere"]},{"emoji":"🧑‍🦲","aliases":["person_bald"]},{"emoji":"🧑‍🦱","aliases":["person_curly_hair"]},{"emoji":"🤺","aliases":["person_fencing"]},{"emoji":"🧑‍🦽","aliases":["person_in_manual_wheelchair"]},{"emoji":"🧑‍🦼","aliases":["person_in_motorized_wheelchair"]},{"emoji":"🤵","aliases":["person_in_tuxedo"]},{"emoji":"🧑‍🦰","aliases":["person_red_hair"]},{"emoji":"🧑‍🦳","aliases":["person_white_hair"]},{"emoji":"🧑‍🦯","aliases":["person_with_probing_cane"]},{"emoji":"👳","aliases":["person_with_turban"]},{"emoji":"👰","aliases":["person_with_veil"]},{"emoji":"🇵🇪","aliases":["peru"]},{"emoji":"🧫","aliases":["petri_dish"]},{"emoji":"🇵🇭","aliases":["philippines"]},{"emoji":"☎️","aliases":["phone","telephone"]},{"emoji":"⛏️","aliases":["pick"]},{"emoji":"🥧","aliases":["pie"]},{"emoji":"🐷","aliases":["pig"]},{"emoji":"🐖","aliases":["pig2"]},{"emoji":"🐽","aliases":["pig_nose"]},{"emoji":"💊","aliases":["pill"]},{"emoji":"🧑‍✈️","aliases":["pilot"]},{"emoji":"🤏","aliases":["pinching_hand"]},{"emoji":"🍍","aliases":["pineapple"]},{"emoji":"🏓","aliases":["ping_pong"]},{"emoji":"🏴‍☠️","aliases":["pirate_flag"]},{"emoji":"♓","aliases":["pisces"]},{"emoji":"🇵🇳","aliases":["pitcairn_islands"]},{"emoji":"🍕","aliases":["pizza"]},{"emoji":"🛐","aliases":["place_of_worship"]},{"emoji":"🍽️","aliases":["plate_with_cutlery"]},{"emoji":"⏯️","aliases":["play_or_pause_button"]},{"emoji":"🥺","aliases":["pleading_face"]},{"emoji":"👇","aliases":["point_down"]},{"emoji":"👈","aliases":["point_left"]},{"emoji":"👉","aliases":["point_right"]},{"emoji":"☝️","aliases":["point_up"]},{"emoji":"👆","aliases":["point_up_2"]},{"emoji":"🇵🇱","aliases":["poland"]},{"emoji":"🚓","aliases":["police_car"]},{"emoji":"👮","aliases":["police_officer","cop"]},{"emoji":"👮‍♂️","aliases":["policeman"]},{"emoji":"👮‍♀️","aliases":["policewoman"]},{"emoji":"🐩","aliases":["poodle"]},{"emoji":"🍿","aliases":["popcorn"]},{"emoji":"🇵🇹","aliases":["portugal"]},{"emoji":"🏣","aliases":["post_office"]},{"emoji":"📯","aliases":["postal_horn"]},{"emoji":"📮","aliases":["postbox"]},{"emoji":"🚰","aliases":["potable_water"]},{"emoji":"🥔","aliases":["potato"]},{"emoji":"👝","aliases":["pouch"]},{"emoji":"🍗","aliases":["poultry_leg"]},{"emoji":"💷","aliases":["pound"]},{"emoji":"😾","aliases":["pouting_cat"]},{"emoji":"🙎","aliases":["pouting_face"]},{"emoji":"🙎‍♂️","aliases":["pouting_man"]},{"emoji":"🙎‍♀️","aliases":["pouting_woman"]},{"emoji":"🙏","aliases":["pray"]},{"emoji":"📿","aliases":["prayer_beads"]},{"emoji":"🤰","aliases":["pregnant_woman"]},{"emoji":"🥨","aliases":["pretzel"]},{"emoji":"⏮️","aliases":["previous_track_button"]},{"emoji":"🤴","aliases":["prince"]},{"emoji":"👸","aliases":["princess"]},{"emoji":"🖨️","aliases":["printer"]},{"emoji":"🦯","aliases":["probing_cane"]},{"emoji":"🇵🇷","aliases":["puerto_rico"]},{"emoji":"🟣","aliases":["purple_circle"]},{"emoji":"💜","aliases":["purple_heart"]},{"emoji":"🟪","aliases":["purple_square"]},{"emoji":"👛","aliases":["purse"]},{"emoji":"📌","aliases":["pushpin"]},{"emoji":"🚮","aliases":["put_litter_in_its_place"]},{"emoji":"🇶🇦","aliases":["qatar"]},{"emoji":"❓","aliases":["question"]},{"emoji":"🐰","aliases":["rabbit"]},{"emoji":"🐇","aliases":["rabbit2"]},{"emoji":"🦝","aliases":["raccoon"]},{"emoji":"🐎","aliases":["racehorse"]},{"emoji":"🏎️","aliases":["racing_car"]},{"emoji":"📻","aliases":["radio"]},{"emoji":"🔘","aliases":["radio_button"]},{"emoji":"☢️","aliases":["radioactive"]},{"emoji":"😡","aliases":["rage","pout"]},{"emoji":"🚃","aliases":["railway_car"]},{"emoji":"🛤️","aliases":["railway_track"]},{"emoji":"🌈","aliases":["rainbow"]},{"emoji":"🏳️‍🌈","aliases":["rainbow_flag"]},{"emoji":"🤚","aliases":["raised_back_of_hand"]},{"emoji":"🤨","aliases":["raised_eyebrow"]},{"emoji":"🖐️","aliases":["raised_hand_with_fingers_splayed"]},{"emoji":"🙌","aliases":["raised_hands"]},{"emoji":"🙋","aliases":["raising_hand"]},{"emoji":"🙋‍♂️","aliases":["raising_hand_man"]},{"emoji":"🙋‍♀️","aliases":["raising_hand_woman"]},{"emoji":"🐏","aliases":["ram"]},{"emoji":"🍜","aliases":["ramen"]},{"emoji":"🐀","aliases":["rat"]},{"emoji":"🪒","aliases":["razor"]},{"emoji":"🧾","aliases":["receipt"]},{"emoji":"⏺️","aliases":["record_button"]},{"emoji":"♻️","aliases":["recycle"]},{"emoji":"🔴","aliases":["red_circle"]},{"emoji":"🧧","aliases":["red_envelope"]},{"emoji":"👨‍🦰","aliases":["red_haired_man"]},{"emoji":"👩‍🦰","aliases":["red_haired_woman"]},{"emoji":"🟥","aliases":["red_square"]},{"emoji":"®️","aliases":["registered"]},{"emoji":"☺️","aliases":["relaxed"]},{"emoji":"😌","aliases":["relieved"]},{"emoji":"🎗️","aliases":["reminder_ribbon"]},{"emoji":"🔁","aliases":["repeat"]},{"emoji":"🔂","aliases":["repeat_one"]},{"emoji":"⛑️","aliases":["rescue_worker_helmet"]},{"emoji":"🚻","aliases":["restroom"]},{"emoji":"🇷🇪","aliases":["reunion"]},{"emoji":"💞","aliases":["revolving_hearts"]},{"emoji":"⏪","aliases":["rewind"]},{"emoji":"🦏","aliases":["rhinoceros"]},{"emoji":"🎀","aliases":["ribbon"]},{"emoji":"🍚","aliases":["rice"]},{"emoji":"🍙","aliases":["rice_ball"]},{"emoji":"🍘","aliases":["rice_cracker"]},{"emoji":"🎑","aliases":["rice_scene"]},{"emoji":"🗯️","aliases":["right_anger_bubble"]},{"emoji":"💍","aliases":["ring"]},{"emoji":"🪐","aliases":["ringed_planet"]},{"emoji":"🤖","aliases":["robot"]},{"emoji":"🚀","aliases":["rocket"]},{"emoji":"🤣","aliases":["rofl"]},{"emoji":"🙄","aliases":["roll_eyes"]},{"emoji":"🧻","aliases":["roll_of_paper"]},{"emoji":"🎢","aliases":["roller_coaster"]},{"emoji":"🇷🇴","aliases":["romania"]},{"emoji":"🐓","aliases":["rooster"]},{"emoji":"🌹","aliases":["rose"]},{"emoji":"🏵️","aliases":["rosette"]},{"emoji":"🚨","aliases":["rotating_light"]},{"emoji":"📍","aliases":["round_pushpin"]},{"emoji":"🚣","aliases":["rowboat"]},{"emoji":"🚣‍♂️","aliases":["rowing_man"]},{"emoji":"🚣‍♀️","aliases":["rowing_woman"]},{"emoji":"🇷🇺","aliases":["ru"]},{"emoji":"🏉","aliases":["rugby_football"]},{"emoji":"🏃","aliases":["runner","running"]},{"emoji":"🏃‍♂️","aliases":["running_man"]},{"emoji":"🎽","aliases":["running_shirt_with_sash"]},{"emoji":"🏃‍♀️","aliases":["running_woman"]},{"emoji":"🇷🇼","aliases":["rwanda"]},{"emoji":"🈂️","aliases":["sa"]},{"emoji":"🧷","aliases":["safety_pin"]},{"emoji":"🦺","aliases":["safety_vest"]},{"emoji":"♐","aliases":["sagittarius"]},{"emoji":"🍶","aliases":["sake"]},{"emoji":"🧂","aliases":["salt"]},{"emoji":"🇼🇸","aliases":["samoa"]},{"emoji":"🇸🇲","aliases":["san_marino"]},{"emoji":"👡","aliases":["sandal"]},{"emoji":"🥪","aliases":["sandwich"]},{"emoji":"🎅","aliases":["santa"]},{"emoji":"🇸🇹","aliases":["sao_tome_principe"]},{"emoji":"🥻","aliases":["sari"]},{"emoji":"📡","aliases":["satellite"]},{"emoji":"🇸🇦","aliases":["saudi_arabia"]},{"emoji":"🧖‍♂️","aliases":["sauna_man"]},{"emoji":"🧖","aliases":["sauna_person"]},{"emoji":"🧖‍♀️","aliases":["sauna_woman"]},{"emoji":"🦕","aliases":["sauropod"]},{"emoji":"🎷","aliases":["saxophone"]},{"emoji":"🧣","aliases":["scarf"]},{"emoji":"🏫","aliases":["school"]},{"emoji":"🎒","aliases":["school_satchel"]},{"emoji":"🧑‍🔬","aliases":["scientist"]},{"emoji":"✂️","aliases":["scissors"]},{"emoji":"🦂","aliases":["scorpion"]},{"emoji":"♏","aliases":["scorpius"]},{"emoji":"🏴󠁧󠁢󠁳󠁣󠁴󠁿","aliases":["scotland"]},{"emoji":"😱","aliases":["scream"]},{"emoji":"🙀","aliases":["scream_cat"]},{"emoji":"📜","aliases":["scroll"]},{"emoji":"💺","aliases":["seat"]},{"emoji":"㊙️","aliases":["secret"]},{"emoji":"🙈","aliases":["see_no_evil"]},{"emoji":"🌱","aliases":["seedling"]},{"emoji":"🤳","aliases":["selfie"]},{"emoji":"🇸🇳","aliases":["senegal"]},{"emoji":"🇷🇸","aliases":["serbia"]},{"emoji":"🐕‍🦺","aliases":["service_dog"]},{"emoji":"7️⃣","aliases":["seven"]},{"emoji":"🇸🇨","aliases":["seychelles"]},{"emoji":"🥘","aliases":["shallow_pan_of_food"]},{"emoji":"☘️","aliases":["shamrock"]},{"emoji":"🦈","aliases":["shark"]},{"emoji":"🍧","aliases":["shaved_ice"]},{"emoji":"🐑","aliases":["sheep"]},{"emoji":"🐚","aliases":["shell"]},{"emoji":"🛡️","aliases":["shield"]},{"emoji":"⛩️","aliases":["shinto_shrine"]},{"emoji":"🚢","aliases":["ship"]},{"emoji":"👕","aliases":["shirt","tshirt"]},{"emoji":"🛍️","aliases":["shopping"]},{"emoji":"🛒","aliases":["shopping_cart"]},{"emoji":"🩳","aliases":["shorts"]},{"emoji":"🚿","aliases":["shower"]},{"emoji":"🦐","aliases":["shrimp"]},{"emoji":"🤷","aliases":["shrug"]},{"emoji":"🤫","aliases":["shushing_face"]},{"emoji":"🇸🇱","aliases":["sierra_leone"]},{"emoji":"📶","aliases":["signal_strength"]},{"emoji":"🇸🇬","aliases":["singapore"]},{"emoji":"🧑‍🎤","aliases":["singer"]},{"emoji":"🇸🇽","aliases":["sint_maarten"]},{"emoji":"6️⃣","aliases":["six"]},{"emoji":"🔯","aliases":["six_pointed_star"]},{"emoji":"🛹","aliases":["skateboard"]},{"emoji":"🎿","aliases":["ski"]},{"emoji":"⛷️","aliases":["skier"]},{"emoji":"💀","aliases":["skull"]},{"emoji":"☠️","aliases":["skull_and_crossbones"]},{"emoji":"🦨","aliases":["skunk"]},{"emoji":"🛷","aliases":["sled"]},{"emoji":"😴","aliases":["sleeping"]},{"emoji":"🛌","aliases":["sleeping_bed"]},{"emoji":"😪","aliases":["sleepy"]},{"emoji":"🙁","aliases":["slightly_frowning_face"]},{"emoji":"🙂","aliases":["slightly_smiling_face"]},{"emoji":"🎰","aliases":["slot_machine"]},{"emoji":"🦥","aliases":["sloth"]},{"emoji":"🇸🇰","aliases":["slovakia"]},{"emoji":"🇸🇮","aliases":["slovenia"]},{"emoji":"🛩️","aliases":["small_airplane"]},{"emoji":"🔹","aliases":["small_blue_diamond"]},{"emoji":"🔸","aliases":["small_orange_diamond"]},{"emoji":"🔺","aliases":["small_red_triangle"]},{"emoji":"🔻","aliases":["small_red_triangle_down"]},{"emoji":"😄","aliases":["smile"]},{"emoji":"😸","aliases":["smile_cat"]},{"emoji":"😃","aliases":["smiley"]},{"emoji":"😺","aliases":["smiley_cat"]},{"emoji":"🥰","aliases":["smiling_face_with_three_hearts"]},{"emoji":"😈","aliases":["smiling_imp"]},{"emoji":"😏","aliases":["smirk"]},{"emoji":"😼","aliases":["smirk_cat"]},{"emoji":"🚬","aliases":["smoking"]},{"emoji":"🐌","aliases":["snail"]},{"emoji":"🐍","aliases":["snake"]},{"emoji":"🤧","aliases":["sneezing_face"]},{"emoji":"🏂","aliases":["snowboarder"]},{"emoji":"❄️","aliases":["snowflake"]},{"emoji":"⛄","aliases":["snowman"]},{"emoji":"☃️","aliases":["snowman_with_snow"]},{"emoji":"🧼","aliases":["soap"]},{"emoji":"😭","aliases":["sob"]},{"emoji":"⚽","aliases":["soccer"]},{"emoji":"🧦","aliases":["socks"]},{"emoji":"🥎","aliases":["softball"]},{"emoji":"🇸🇧","aliases":["solomon_islands"]},{"emoji":"🇸🇴","aliases":["somalia"]},{"emoji":"🔜","aliases":["soon"]},{"emoji":"🆘","aliases":["sos"]},{"emoji":"🔉","aliases":["sound"]},{"emoji":"🇿🇦","aliases":["south_africa"]},{"emoji":"🇬🇸","aliases":["south_georgia_south_sandwich_islands"]},{"emoji":"🇸🇸","aliases":["south_sudan"]},{"emoji":"👾","aliases":["space_invader"]},{"emoji":"♠️","aliases":["spades"]},{"emoji":"🍝","aliases":["spaghetti"]},{"emoji":"❇️","aliases":["sparkle"]},{"emoji":"🎇","aliases":["sparkler"]},{"emoji":"✨","aliases":["sparkles"]},{"emoji":"💖","aliases":["sparkling_heart"]},{"emoji":"🙊","aliases":["speak_no_evil"]},{"emoji":"🔈","aliases":["speaker"]},{"emoji":"🗣️","aliases":["speaking_head"]},{"emoji":"💬","aliases":["speech_balloon"]},{"emoji":"🚤","aliases":["speedboat"]},{"emoji":"🕷️","aliases":["spider"]},{"emoji":"🕸️","aliases":["spider_web"]},{"emoji":"🗓️","aliases":["spiral_calendar"]},{"emoji":"🗒️","aliases":["spiral_notepad"]},{"emoji":"🧽","aliases":["sponge"]},{"emoji":"🥄","aliases":["spoon"]},{"emoji":"🦑","aliases":["squid"]},{"emoji":"🇱🇰","aliases":["sri_lanka"]},{"emoji":"🇧🇱","aliases":["st_barthelemy"]},{"emoji":"🇸🇭","aliases":["st_helena"]},{"emoji":"🇰🇳","aliases":["st_kitts_nevis"]},{"emoji":"🇱🇨","aliases":["st_lucia"]},{"emoji":"🇲🇫","aliases":["st_martin"]},{"emoji":"🇵🇲","aliases":["st_pierre_miquelon"]},{"emoji":"🇻🇨","aliases":["st_vincent_grenadines"]},{"emoji":"🏟️","aliases":["stadium"]},{"emoji":"🧍‍♂️","aliases":["standing_man"]},{"emoji":"🧍","aliases":["standing_person"]},{"emoji":"🧍‍♀️","aliases":["standing_woman"]},{"emoji":"⭐","aliases":["star"]},{"emoji":"🌟","aliases":["star2"]},{"emoji":"☪️","aliases":["star_and_crescent"]},{"emoji":"✡️","aliases":["star_of_david"]},{"emoji":"🤩","aliases":["star_struck"]},{"emoji":"🌠","aliases":["stars"]},{"emoji":"🚉","aliases":["station"]},{"emoji":"🗽","aliases":["statue_of_liberty"]},{"emoji":"🚂","aliases":["steam_locomotive"]},{"emoji":"🩺","aliases":["stethoscope"]},{"emoji":"🍲","aliases":["stew"]},{"emoji":"⏹️","aliases":["stop_button"]},{"emoji":"🛑","aliases":["stop_sign"]},{"emoji":"⏱️","aliases":["stopwatch"]},{"emoji":"📏","aliases":["straight_ruler"]},{"emoji":"🍓","aliases":["strawberry"]},{"emoji":"😛","aliases":["stuck_out_tongue"]},{"emoji":"😝","aliases":["stuck_out_tongue_closed_eyes"]},{"emoji":"😜","aliases":["stuck_out_tongue_winking_eye"]},{"emoji":"🧑‍🎓","aliases":["student"]},{"emoji":"🎙️","aliases":["studio_microphone"]},{"emoji":"🥙","aliases":["stuffed_flatbread"]},{"emoji":"🇸🇩","aliases":["sudan"]},{"emoji":"🌥️","aliases":["sun_behind_large_cloud"]},{"emoji":"🌦️","aliases":["sun_behind_rain_cloud"]},{"emoji":"🌤️","aliases":["sun_behind_small_cloud"]},{"emoji":"🌞","aliases":["sun_with_face"]},{"emoji":"🌻","aliases":["sunflower"]},{"emoji":"😎","aliases":["sunglasses"]},{"emoji":"☀️","aliases":["sunny"]},{"emoji":"🌅","aliases":["sunrise"]},{"emoji":"🌄","aliases":["sunrise_over_mountains"]},{"emoji":"🦸","aliases":["superhero"]},{"emoji":"🦸‍♂️","aliases":["superhero_man"]},{"emoji":"🦸‍♀️","aliases":["superhero_woman"]},{"emoji":"🦹","aliases":["supervillain"]},{"emoji":"🦹‍♂️","aliases":["supervillain_man"]},{"emoji":"🦹‍♀️","aliases":["supervillain_woman"]},{"emoji":"🏄","aliases":["surfer"]},{"emoji":"🏄‍♂️","aliases":["surfing_man"]},{"emoji":"🏄‍♀️","aliases":["surfing_woman"]},{"emoji":"🇸🇷","aliases":["suriname"]},{"emoji":"🍣","aliases":["sushi"]},{"emoji":"🚟","aliases":["suspension_railway"]},{"emoji":"🇸🇯","aliases":["svalbard_jan_mayen"]},{"emoji":"🦢","aliases":["swan"]},{"emoji":"🇸🇿","aliases":["swaziland"]},{"emoji":"😓","aliases":["sweat"]},{"emoji":"💦","aliases":["sweat_drops"]},{"emoji":"😅","aliases":["sweat_smile"]},{"emoji":"🇸🇪","aliases":["sweden"]},{"emoji":"🍠","aliases":["sweet_potato"]},{"emoji":"🩲","aliases":["swim_brief"]},{"emoji":"🏊","aliases":["swimmer"]},{"emoji":"🏊‍♂️","aliases":["swimming_man"]},{"emoji":"🏊‍♀️","aliases":["swimming_woman"]},{"emoji":"🇨🇭","aliases":["switzerland"]},{"emoji":"🔣","aliases":["symbols"]},{"emoji":"🕍","aliases":["synagogue"]},{"emoji":"🇸🇾","aliases":["syria"]},{"emoji":"💉","aliases":["syringe"]},{"emoji":"🦖","aliases":["t-rex"]},{"emoji":"🌮","aliases":["taco"]},{"emoji":"🎉","aliases":["tada","hooray"]},{"emoji":"🇹🇼","aliases":["taiwan"]},{"emoji":"🇹🇯","aliases":["tajikistan"]},{"emoji":"🥡","aliases":["takeout_box"]},{"emoji":"🎋","aliases":["tanabata_tree"]},{"emoji":"🍊","aliases":["tangerine","orange","mandarin"]},{"emoji":"🇹🇿","aliases":["tanzania"]},{"emoji":"♉","aliases":["taurus"]},{"emoji":"🚕","aliases":["taxi"]},{"emoji":"🍵","aliases":["tea"]},{"emoji":"🧑‍🏫","aliases":["teacher"]},{"emoji":"🧑‍💻","aliases":["technologist"]},{"emoji":"🧸","aliases":["teddy_bear"]},{"emoji":"📞","aliases":["telephone_receiver"]},{"emoji":"🔭","aliases":["telescope"]},{"emoji":"🎾","aliases":["tennis"]},{"emoji":"⛺","aliases":["tent"]},{"emoji":"🧪","aliases":["test_tube"]},{"emoji":"🇹🇭","aliases":["thailand"]},{"emoji":"🌡️","aliases":["thermometer"]},{"emoji":"🤔","aliases":["thinking"]},{"emoji":"💭","aliases":["thought_balloon"]},{"emoji":"🧵","aliases":["thread"]},{"emoji":"3️⃣","aliases":["three"]},{"emoji":"🎫","aliases":["ticket"]},{"emoji":"🎟️","aliases":["tickets"]},{"emoji":"🐯","aliases":["tiger"]},{"emoji":"🐅","aliases":["tiger2"]},{"emoji":"⏲️","aliases":["timer_clock"]},{"emoji":"🇹🇱","aliases":["timor_leste"]},{"emoji":"💁‍♂️","aliases":["tipping_hand_man","sassy_man"]},{"emoji":"💁","aliases":["tipping_hand_person","information_desk_person"]},{"emoji":"💁‍♀️","aliases":["tipping_hand_woman","sassy_woman"]},{"emoji":"😫","aliases":["tired_face"]},{"emoji":"™️","aliases":["tm"]},{"emoji":"🇹🇬","aliases":["togo"]},{"emoji":"🚽","aliases":["toilet"]},{"emoji":"🇹🇰","aliases":["tokelau"]},{"emoji":"🗼","aliases":["tokyo_tower"]},{"emoji":"🍅","aliases":["tomato"]},{"emoji":"🇹🇴","aliases":["tonga"]},{"emoji":"👅","aliases":["tongue"]},{"emoji":"🧰","aliases":["toolbox"]},{"emoji":"🦷","aliases":["tooth"]},{"emoji":"🔝","aliases":["top"]},{"emoji":"🎩","aliases":["tophat"]},{"emoji":"🌪️","aliases":["tornado"]},{"emoji":"🇹🇷","aliases":["tr"]},{"emoji":"🖲️","aliases":["trackball"]},{"emoji":"🚜","aliases":["tractor"]},{"emoji":"🚥","aliases":["traffic_light"]},{"emoji":"🚋","aliases":["train"]},{"emoji":"🚆","aliases":["train2"]},{"emoji":"🚊","aliases":["tram"]},{"emoji":"🚩","aliases":["triangular_flag_on_post"]},{"emoji":"📐","aliases":["triangular_ruler"]},{"emoji":"🔱","aliases":["trident"]},{"emoji":"🇹🇹","aliases":["trinidad_tobago"]},{"emoji":"🇹🇦","aliases":["tristan_da_cunha"]},{"emoji":"😤","aliases":["triumph"]},{"emoji":"🚎","aliases":["trolleybus"]},{"emoji":"🏆","aliases":["trophy"]},{"emoji":"🍹","aliases":["tropical_drink"]},{"emoji":"🐠","aliases":["tropical_fish"]},{"emoji":"🚚","aliases":["truck"]},{"emoji":"🎺","aliases":["trumpet"]},{"emoji":"🌷","aliases":["tulip"]},{"emoji":"🥃","aliases":["tumbler_glass"]},{"emoji":"🇹🇳","aliases":["tunisia"]},{"emoji":"🦃","aliases":["turkey"]},{"emoji":"🇹🇲","aliases":["turkmenistan"]},{"emoji":"🇹🇨","aliases":["turks_caicos_islands"]},{"emoji":"🐢","aliases":["turtle"]},{"emoji":"🇹🇻","aliases":["tuvalu"]},{"emoji":"📺","aliases":["tv"]},{"emoji":"🔀","aliases":["twisted_rightwards_arrows"]},{"emoji":"2️⃣","aliases":["two"]},{"emoji":"💕","aliases":["two_hearts"]},{"emoji":"👬","aliases":["two_men_holding_hands"]},{"emoji":"👭","aliases":["two_women_holding_hands"]},{"emoji":"🈹","aliases":["u5272"]},{"emoji":"🈴","aliases":["u5408"]},{"emoji":"🈺","aliases":["u55b6"]},{"emoji":"🈯","aliases":["u6307"]},{"emoji":"🈷️","aliases":["u6708"]},{"emoji":"🈶","aliases":["u6709"]},{"emoji":"🈵","aliases":["u6e80"]},{"emoji":"🈚","aliases":["u7121"]},{"emoji":"🈸","aliases":["u7533"]},{"emoji":"🈲","aliases":["u7981"]},{"emoji":"🈳","aliases":["u7a7a"]},{"emoji":"🇺🇬","aliases":["uganda"]},{"emoji":"🇺🇦","aliases":["ukraine"]},{"emoji":"☔","aliases":["umbrella"]},{"emoji":"😒","aliases":["unamused"]},{"emoji":"🔞","aliases":["underage"]},{"emoji":"🦄","aliases":["unicorn"]},{"emoji":"🇦🇪","aliases":["united_arab_emirates"]},{"emoji":"🇺🇳","aliases":["united_nations"]},{"emoji":"🔓","aliases":["unlock"]},{"emoji":"🆙","aliases":["up"]},{"emoji":"🙃","aliases":["upside_down_face"]},{"emoji":"🇺🇾","aliases":["uruguay"]},{"emoji":"🇺🇸","aliases":["us"]},{"emoji":"🇺🇲","aliases":["us_outlying_islands"]},{"emoji":"🇻🇮","aliases":["us_virgin_islands"]},{"emoji":"🇺🇿","aliases":["uzbekistan"]},{"emoji":"✌️","aliases":["v"]},{"emoji":"🧛","aliases":["vampire"]},{"emoji":"🧛‍♂️","aliases":["vampire_man"]},{"emoji":"🧛‍♀️","aliases":["vampire_woman"]},{"emoji":"🇻🇺","aliases":["vanuatu"]},{"emoji":"🇻🇦","aliases":["vatican_city"]},{"emoji":"🇻🇪","aliases":["venezuela"]},{"emoji":"🚦","aliases":["vertical_traffic_light"]},{"emoji":"📼","aliases":["vhs"]},{"emoji":"📳","aliases":["vibration_mode"]},{"emoji":"📹","aliases":["video_camera"]},{"emoji":"🎮","aliases":["video_game"]},{"emoji":"🇻🇳","aliases":["vietnam"]},{"emoji":"🎻","aliases":["violin"]},{"emoji":"♍","aliases":["virgo"]},{"emoji":"🌋","aliases":["volcano"]},{"emoji":"🏐","aliases":["volleyball"]},{"emoji":"🤮","aliases":["vomiting_face"]},{"emoji":"🆚","aliases":["vs"]},{"emoji":"🖖","aliases":["vulcan_salute"]},{"emoji":"🧇","aliases":["waffle"]},{"emoji":"🏴󠁧󠁢󠁷󠁬󠁳󠁿","aliases":["wales"]},{"emoji":"🚶","aliases":["walking"]},{"emoji":"🚶‍♂️","aliases":["walking_man"]},{"emoji":"🚶‍♀️","aliases":["walking_woman"]},{"emoji":"🇼🇫","aliases":["wallis_futuna"]},{"emoji":"🌘","aliases":["waning_crescent_moon"]},{"emoji":"🌖","aliases":["waning_gibbous_moon"]},{"emoji":"⚠️","aliases":["warning"]},{"emoji":"🗑️","aliases":["wastebasket"]},{"emoji":"⌚","aliases":["watch"]},{"emoji":"🐃","aliases":["water_buffalo"]},{"emoji":"🤽","aliases":["water_polo"]},{"emoji":"🍉","aliases":["watermelon"]},{"emoji":"👋","aliases":["wave"]},{"emoji":"〰️","aliases":["wavy_dash"]},{"emoji":"🌒","aliases":["waxing_crescent_moon"]},{"emoji":"🚾","aliases":["wc"]},{"emoji":"😩","aliases":["weary"]},{"emoji":"💒","aliases":["wedding"]},{"emoji":"🏋️","aliases":["weight_lifting"]},{"emoji":"🏋️‍♂️","aliases":["weight_lifting_man"]},{"emoji":"🏋️‍♀️","aliases":["weight_lifting_woman"]},{"emoji":"🇪🇭","aliases":["western_sahara"]},{"emoji":"🐳","aliases":["whale"]},{"emoji":"🐋","aliases":["whale2"]},{"emoji":"☸️","aliases":["wheel_of_dharma"]},{"emoji":"♿","aliases":["wheelchair"]},{"emoji":"✅","aliases":["white_check_mark"]},{"emoji":"⚪","aliases":["white_circle"]},{"emoji":"🏳️","aliases":["white_flag"]},{"emoji":"💮","aliases":["white_flower"]},{"emoji":"👨‍🦳","aliases":["white_haired_man"]},{"emoji":"👩‍🦳","aliases":["white_haired_woman"]},{"emoji":"🤍","aliases":["white_heart"]},{"emoji":"⬜","aliases":["white_large_square"]},{"emoji":"◽","aliases":["white_medium_small_square"]},{"emoji":"◻️","aliases":["white_medium_square"]},{"emoji":"▫️","aliases":["white_small_square"]},{"emoji":"🔳","aliases":["white_square_button"]},{"emoji":"🥀","aliases":["wilted_flower"]},{"emoji":"🎐","aliases":["wind_chime"]},{"emoji":"🌬️","aliases":["wind_face"]},{"emoji":"🍷","aliases":["wine_glass"]},{"emoji":"😉","aliases":["wink"]},{"emoji":"🐺","aliases":["wolf"]},{"emoji":"👩","aliases":["woman"]},{"emoji":"👩‍🎨","aliases":["woman_artist"]},{"emoji":"👩‍🚀","aliases":["woman_astronaut"]},{"emoji":"🤸‍♀️","aliases":["woman_cartwheeling"]},{"emoji":"👩‍🍳","aliases":["woman_cook"]},{"emoji":"💃","aliases":["woman_dancing","dancer"]},{"emoji":"🤦‍♀️","aliases":["woman_facepalming"]},{"emoji":"👩‍🏭","aliases":["woman_factory_worker"]},{"emoji":"👩‍🌾","aliases":["woman_farmer"]},{"emoji":"👩‍🚒","aliases":["woman_firefighter"]},{"emoji":"👩‍⚕️","aliases":["woman_health_worker"]},{"emoji":"👩‍🦽","aliases":["woman_in_manual_wheelchair"]},{"emoji":"👩‍🦼","aliases":["woman_in_motorized_wheelchair"]},{"emoji":"👩‍⚖️","aliases":["woman_judge"]},{"emoji":"🤹‍♀️","aliases":["woman_juggling"]},{"emoji":"👩‍🔧","aliases":["woman_mechanic"]},{"emoji":"👩‍💼","aliases":["woman_office_worker"]},{"emoji":"👩‍✈️","aliases":["woman_pilot"]},{"emoji":"🤾‍♀️","aliases":["woman_playing_handball"]},{"emoji":"🤽‍♀️","aliases":["woman_playing_water_polo"]},{"emoji":"👩‍🔬","aliases":["woman_scientist"]},{"emoji":"🤷‍♀️","aliases":["woman_shrugging"]},{"emoji":"👩‍🎤","aliases":["woman_singer"]},{"emoji":"👩‍🎓","aliases":["woman_student"]},{"emoji":"👩‍🏫","aliases":["woman_teacher"]},{"emoji":"👩‍💻","aliases":["woman_technologist"]},{"emoji":"🧕","aliases":["woman_with_headscarf"]},{"emoji":"👩‍🦯","aliases":["woman_with_probing_cane"]},{"emoji":"👳‍♀️","aliases":["woman_with_turban"]},{"emoji":"👚","aliases":["womans_clothes"]},{"emoji":"👒","aliases":["womans_hat"]},{"emoji":"🤼‍♀️","aliases":["women_wrestling"]},{"emoji":"🚺","aliases":["womens"]},{"emoji":"🥴","aliases":["woozy_face"]},{"emoji":"🗺️","aliases":["world_map"]},{"emoji":"😟","aliases":["worried"]},{"emoji":"🔧","aliases":["wrench"]},{"emoji":"🤼","aliases":["wrestling"]},{"emoji":"✍️","aliases":["writing_hand"]},{"emoji":"❌","aliases":["x"]},{"emoji":"🧶","aliases":["yarn"]},{"emoji":"🥱","aliases":["yawning_face"]},{"emoji":"🟡","aliases":["yellow_circle"]},{"emoji":"💛","aliases":["yellow_heart"]},{"emoji":"🟨","aliases":["yellow_square"]},{"emoji":"🇾🇪","aliases":["yemen"]},{"emoji":"💴","aliases":["yen"]},{"emoji":"☯️","aliases":["yin_yang"]},{"emoji":"🪀","aliases":["yo_yo"]},{"emoji":"😋","aliases":["yum"]},{"emoji":"🇿🇲","aliases":["zambia"]},{"emoji":"🤪","aliases":["zany_face"]},{"emoji":"⚡","aliases":["zap"]},{"emoji":"🦓","aliases":["zebra"]},{"emoji":"0️⃣","aliases":["zero"]},{"emoji":"🇿🇼","aliases":["zimbabwe"]},{"emoji":"🤐","aliases":["zipper_mouth_face"]},{"emoji":"🧟","aliases":["zombie"]},{"emoji":"🧟‍♂️","aliases":["zombie_man"]},{"emoji":"🧟‍♀️","aliases":["zombie_woman"]},{"emoji":"💤","aliases":["zzz"]}] \ No newline at end of file diff --git a/assets/logo.svg b/assets/logo.svg index ac1594adb..bfd50a0c9 100644 --- a/assets/logo.svg +++ b/assets/logo.svg @@ -115,6 +115,7 @@ - + \ No newline at end of file diff --git a/build/generate-emoji.go b/build/generate-emoji.go index 6b1b6643c..00d60acac 100644 --- a/build/generate-emoji.go +++ b/build/generate-emoji.go @@ -19,6 +19,7 @@ import ( "sort" "strconv" "strings" + "unicode/utf8" ) const ( @@ -39,6 +40,7 @@ type Emoji struct { Description string `json:"description,omitempty"` Aliases []string `json:"aliases"` UnicodeVersion string `json:"unicode_version,omitempty"` + SkinTones bool `json:"skin_tones,omitempty"` } // Don't include some fields in JSON @@ -47,6 +49,7 @@ func (e Emoji) MarshalJSON() ([]byte, error) { x := emoji(e) x.UnicodeVersion = "" x.Description = "" + x.SkinTones = false return json.Marshal(x) } @@ -75,6 +78,7 @@ var replacer = strings.NewReplacer( ", Description:", ", ", ", Aliases:", ", ", ", UnicodeVersion:", ", ", + ", SkinTones:", ", ", ) var emojiRE = regexp.MustCompile(`\{Emoji:"([^"]*)"`) @@ -102,18 +106,20 @@ func generate() ([]byte, error) { return nil, err } - var re = regexp.MustCompile(`keycap|registered|copyright`) - tmp := data[:0] + var skinTones = make(map[string]string) - // filter out emoji that require greater than max unicode version + skinTones["\U0001f3fb"] = "Light Skin Tone" + skinTones["\U0001f3fc"] = "Medium-Light Skin Tone" + skinTones["\U0001f3fd"] = "Medium Skin Tone" + skinTones["\U0001f3fe"] = "Medium-Dark Skin Tone" + skinTones["\U0001f3ff"] = "Dark Skin Tone" + + var tmp Gemoji + + //filter out emoji that require greater than max unicode version for i := range data { val, _ := strconv.ParseFloat(data[i].UnicodeVersion, 64) if int(val) <= maxUnicodeVersion { - // remove these keycaps for now they really complicate matching since - // they include normal letters in them - if re.MatchString(data[i].Description) { - continue - } tmp = append(tmp, data[i]) } } @@ -123,7 +129,6 @@ func generate() ([]byte, error) { return data[i].Aliases[0] < data[j].Aliases[0] }) - aliasPairs := make([]string, 0) aliasMap := make(map[string]int, len(data)) for i, e := range data { @@ -135,7 +140,6 @@ func generate() ([]byte, error) { continue } aliasMap[a] = i - aliasPairs = append(aliasPairs, ":"+a+":", e.Emoji) } } @@ -149,6 +153,43 @@ func generate() ([]byte, error) { data[i].Aliases = append(data[i].Aliases, "laugh") } + // write a JSON file to use with tribute (write before adding skin tones since we can't support them there yet) + file, _ := json.Marshal(data) + _ = ioutil.WriteFile("assets/emoji.json", file, 0644) + + // Add skin tones to emoji that support it + var ( + s []string + newEmoji string + newDescription string + newData Emoji + ) + + for i := range data { + if data[i].SkinTones { + for k, v := range skinTones { + s = strings.Split(data[i].Emoji, "") + + if utf8.RuneCountInString(data[i].Emoji) == 1 { + s = append(s, k) + } else { + // insert into slice after first element because all emoji that support skin tones + // have that modifer placed at this spot + s = append(s, "") + copy(s[2:], s[1:]) + s[1] = k + } + + newEmoji = strings.Join(s, "") + newDescription = data[i].Description + ": " + v + newAlias := data[i].Aliases[0] + "_" + strings.ReplaceAll(v, " ", "_") + + newData = Emoji{newEmoji, newDescription, []string{newAlias}, "12.0", false} + data = append(data, newData) + } + } + } + // add header str := replacer.Replace(fmt.Sprintf(hdr, gemojiURL, data)) @@ -162,10 +203,6 @@ func generate() ([]byte, error) { return "{" + strconv.QuoteToASCII(s) }) - // write a JSON file to use with tribute - file, _ := json.Marshal(data) - _ = ioutil.WriteFile("assets/emoji.json", file, 0644) - // format return format.Source([]byte(str)) } diff --git a/build/generate-images.js b/build/generate-images.js new file mode 100755 index 000000000..7a00395a5 --- /dev/null +++ b/build/generate-images.js @@ -0,0 +1,80 @@ +#!/usr/bin/env node +'use strict'; + +const imageminZopfli = require('imagemin-zopfli'); +const {fabric} = require('fabric'); +const {DOMParser, XMLSerializer} = require('xmldom'); +const {readFile, writeFile} = require('fs').promises; +const {resolve} = require('path'); + +function exit(err) { + if (err) console.error(err); + process.exit(err ? 1 : 0); +} + +function loadSvg(svg) { + return new Promise((resolve) => { + fabric.loadSVGFromString(svg, (objects, options) => { + resolve({objects, options}); + }); + }); +} + +async function generate(svg, outputFile, {size, bg, removeDetail} = {}) { + const parser = new DOMParser(); + const serializer = new XMLSerializer(); + const document = parser.parseFromString(svg); + + if (removeDetail) { + for (const el of Array.from(document.getElementsByTagName('g') || [])) { + for (const attribute of Array.from(el.attributes || [])) { + if (attribute.name === 'class' && attribute.value === 'detail-remove') { + el.parentNode.removeChild(el); + } + } + } + } + + svg = serializer.serializeToString(document); + + const {objects, options} = await loadSvg(svg); + const canvas = new fabric.Canvas(); + canvas.setDimensions({width: size, height: size}); + const ctx = canvas.getContext('2d'); + ctx.scale(options.width ? (size / options.width) : 1, options.height ? (size / options.height) : 1); + + if (bg) { + canvas.add(new fabric.Rect({ + left: 0, + top: 0, + height: size * (1 / (size / options.height)), + width: size * (1 / (size / options.width)), + fill: 'white', + })); + } + + canvas.add(fabric.util.groupSVGElements(objects, options)); + canvas.renderAll(); + + let png = Buffer.from([]); + for await (const chunk of canvas.createPNGStream()) { + png = Buffer.concat([png, chunk]); + } + + png = await imageminZopfli({more: true})(png); + await writeFile(outputFile, png); +} + +async function main() { + const svg = await readFile(resolve(__dirname, '../assets/logo.svg'), 'utf8'); + await generate(svg, resolve(__dirname, '../public/img/gitea-lg.png'), {size: 880}); + await generate(svg, resolve(__dirname, '../public/img/gitea-512.png'), {size: 512}); + await generate(svg, resolve(__dirname, '../public/img/gitea-192.png'), {size: 192}); + await generate(svg, resolve(__dirname, '../public/img/gitea-sm.png'), {size: 120}); + await generate(svg, resolve(__dirname, '../public/img/avatar_default.png'), {size: 200}); + await generate(svg, resolve(__dirname, '../public/img/favicon.png'), {size: 180, removeDetail: true}); + await generate(svg, resolve(__dirname, '../public/img/apple-touch-icon.png'), {size: 180, bg: true}); +} + +main().then(exit).catch(exit); + diff --git a/build/generate-svg.js b/build/generate-svg.js new file mode 100755 index 000000000..96a4f5fad --- /dev/null +++ b/build/generate-svg.js @@ -0,0 +1,65 @@ +#!/usr/bin/env node +'use strict'; + +const fastGlob = require('fast-glob'); +const Svgo = require('svgo'); +const {resolve, parse} = require('path'); +const {readFile, writeFile, mkdir} = require('fs').promises; + +const glob = (pattern) => fastGlob.sync(pattern, {cwd: resolve(__dirname), absolute: true}); +const outputDir = resolve(__dirname, '../public/img/svg'); + +function exit(err) { + if (err) console.error(err); + process.exit(err ? 1 : 0); +} + +async function processFile(file, {prefix = ''} = {}) { + let name = parse(file).name; + if (prefix) name = `${prefix}-${name}`; + if (prefix === 'octicon') name = name.replace(/-[0-9]+$/, ''); // chop of '-16' on octicons + + const svgo = new Svgo({ + plugins: [ + {removeXMLNS: true}, + {removeDimensions: true}, + { + addClassesToSVGElement: { + classNames: [ + 'svg', + name, + ], + }, + }, + { + addAttributesToSVGElement: { + attributes: [ + {'width': '16'}, + {'height': '16'}, + {'aria-hidden': 'true'}, + ], + }, + }, + ], + }); + + const {data} = await svgo.optimize(await readFile(file, 'utf8')); + await writeFile(resolve(outputDir, `${name}.svg`), data); +} + +async function main() { + try { + await mkdir(outputDir); + } catch {} + + for (const file of glob('../node_modules/@primer/octicons/build/svg/*-16.svg')) { + await processFile(file, {prefix: 'octicon'}); + } + + for (const file of glob('../web_src/svg/*.svg')) { + await processFile(file); + } +} + +main().then(exit).catch(exit); + diff --git a/cmd/doctor.go b/cmd/doctor.go index f469496cf..48fd3158a 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -85,10 +85,16 @@ var checklist = []check{ }, { title: "Check Database Version", - name: "check-db", + name: "check-db-version", isDefault: true, f: runDoctorCheckDBVersion, - abortIfFailed: true, + abortIfFailed: false, + }, + { + title: "Check consistency of database", + name: "check-db-consistency", + isDefault: false, + f: runDoctorCheckDBConsistency, }, { title: "Check if OpenSSH authorized_keys file is up-to-date", @@ -114,6 +120,12 @@ var checklist = []check{ isDefault: false, f: runDoctorPRMergeBase, }, + { + title: "Recalculate Stars number for all user", + name: "recalculate_stars_number", + isDefault: false, + f: runDoctorUserStarNum, + }, // more checks please append here } @@ -488,6 +500,10 @@ func runDoctorPRMergeBase(ctx *cli.Context) ([]string, error) { return results, err } +func runDoctorUserStarNum(ctx *cli.Context) ([]string, error) { + return nil, models.DoctorUserStarNum() +} + func runDoctorScriptType(ctx *cli.Context) ([]string, error) { path, err := exec.LookPath(setting.ScriptType) if err != nil { @@ -495,3 +511,96 @@ func runDoctorScriptType(ctx *cli.Context) ([]string, error) { } return []string{fmt.Sprintf("ScriptType %s is on the current PATH at %s", setting.ScriptType, path)}, nil } + +func runDoctorCheckDBConsistency(ctx *cli.Context) ([]string, error) { + var results []string + + // make sure DB version is uptodate + if err := models.NewEngine(context.Background(), migrations.EnsureUpToDate); err != nil { + return nil, fmt.Errorf("model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded") + } + + //find labels without existing repo or org + count, err := models.CountOrphanedLabels() + if err != nil { + return nil, err + } + if count > 0 { + if ctx.Bool("fix") { + if err = models.DeleteOrphanedLabels(); err != nil { + return nil, err + } + results = append(results, fmt.Sprintf("%d labels without existing repository/organisation deleted", count)) + } else { + results = append(results, fmt.Sprintf("%d labels without existing repository/organisation", count)) + } + } + + //find issues without existing repository + count, err = models.CountOrphanedIssues() + if err != nil { + return nil, err + } + if count > 0 { + if ctx.Bool("fix") { + if err = models.DeleteOrphanedIssues(); err != nil { + return nil, err + } + results = append(results, fmt.Sprintf("%d issues without existing repository deleted", count)) + } else { + results = append(results, fmt.Sprintf("%d issues without existing repository", count)) + } + } + + //find pulls without existing issues + count, err = models.CountOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id") + if err != nil { + return nil, err + } + if count > 0 { + if ctx.Bool("fix") { + if err = models.DeleteOrphanedObjects("pull_request", "issue", "pull_request.issue_id=issue.id"); err != nil { + return nil, err + } + results = append(results, fmt.Sprintf("%d pull requests without existing issue deleted", count)) + } else { + results = append(results, fmt.Sprintf("%d pull requests without existing issue", count)) + } + } + + //find tracked times without existing issues/pulls + count, err = models.CountOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id") + if err != nil { + return nil, err + } + if count > 0 { + if ctx.Bool("fix") { + if err = models.DeleteOrphanedObjects("tracked_time", "issue", "tracked_time.issue_id=issue.id"); err != nil { + return nil, err + } + results = append(results, fmt.Sprintf("%d tracked times without existing issue deleted", count)) + } else { + results = append(results, fmt.Sprintf("%d tracked times without existing issue", count)) + } + } + + count, err = models.CountNullArchivedRepository() + if err != nil { + return nil, err + } + if count > 0 { + if ctx.Bool("fix") { + updatedCount, err := models.FixNullArchivedRepository() + if err != nil { + return nil, err + } + results = append(results, fmt.Sprintf("%d repositories with null is_archived updated", updatedCount)) + } else { + results = append(results, fmt.Sprintf("%d repositories with null is_archived", count)) + } + } + + //ToDo: function to recalc all counters + + return results, nil +} diff --git a/cmd/dump.go b/cmd/dump.go index 774b1d5d5..dd259575f 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -6,22 +6,120 @@ package cmd import ( + "encoding/json" "fmt" "io/ioutil" "os" "path" "path/filepath" + "strings" "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - "github.com/unknwon/cae/zip" + "gitea.com/macaron/session" + archiver "github.com/mholt/archiver/v3" "github.com/unknwon/com" "github.com/urfave/cli" ) +func addFile(w archiver.Writer, filePath string, absPath string, verbose bool) error { + if verbose { + log.Info("Adding file %s\n", filePath) + } + file, err := os.Open(absPath) + if err != nil { + return err + } + defer file.Close() + fileInfo, err := file.Stat() + if err != nil { + return err + } + + return w.Write(archiver.File{ + FileInfo: archiver.FileInfo{ + FileInfo: fileInfo, + CustomName: filePath, + }, + ReadCloser: file, + }) +} + +func addRecursive(w archiver.Writer, dirPath string, absPath string, verbose bool) error { + if verbose { + log.Info("Adding dir %s\n", dirPath) + } + dir, err := os.Open(absPath) + if err != nil { + return fmt.Errorf("Could not open directory %s: %s", absPath, err) + } + files, err := dir.Readdir(0) + if err != nil { + return fmt.Errorf("Unable to list files in %s: %s", absPath, err) + } + + if err := addFile(w, dirPath, absPath, false); err != nil { + return err + } + + for _, fileInfo := range files { + if fileInfo.IsDir() { + err = addRecursive(w, filepath.Join(dirPath, fileInfo.Name()), filepath.Join(absPath, fileInfo.Name()), verbose) + } else { + err = addFile(w, filepath.Join(dirPath, fileInfo.Name()), filepath.Join(absPath, fileInfo.Name()), verbose) + } + if err != nil { + return err + } + } + return nil +} + +func isSubdir(upper string, lower string) (bool, error) { + if relPath, err := filepath.Rel(upper, lower); err != nil { + return false, err + } else if relPath == "." || !strings.HasPrefix(relPath, ".") { + return true, nil + } + return false, nil +} + +type outputType struct { + Enum []string + Default string + selected string +} + +func (o outputType) Join() string { + return strings.Join(o.Enum, ", ") +} + +func (o *outputType) Set(value string) error { + for _, enum := range o.Enum { + if enum == value { + o.selected = value + return nil + } + } + + return fmt.Errorf("allowed values are %s", o.Join()) +} + +func (o outputType) String() string { + if o.selected == "" { + return o.Default + } + return o.selected +} + +var outputTypeEnum = &outputType{ + Enum: []string{"zip", "tar", "tar.gz", "tar.xz", "tar.bz2"}, + Default: "zip", +} + // CmdDump represents the available dump sub-command. var CmdDump = cli.Command{ Name: "dump", @@ -33,7 +131,7 @@ It can be used for backup and capture Gitea server image to send to maintainer`, cli.StringFlag{ Name: "file, f", Value: fmt.Sprintf("gitea-dump-%d.zip", time.Now().Unix()), - Usage: "Name of the dump file which will be created.", + Usage: "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.", }, cli.BoolFlag{ Name: "verbose, V", @@ -56,6 +154,11 @@ It can be used for backup and capture Gitea server image to send to maintainer`, Name: "skip-log, L", Usage: "Skip the log dumping", }, + cli.GenericFlag{ + Name: "type", + Value: outputTypeEnum, + Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()), + }, }, } @@ -65,7 +168,23 @@ func fatal(format string, args ...interface{}) { } func runDump(ctx *cli.Context) error { + var file *os.File + fileName := ctx.String("file") + if fileName == "-" { + file = os.Stdout + err := log.DelLogger("console") + if err != nil { + fatal("Deleting default logger failed. Can not write to stdout: %v", err) + } + } setting.NewContext() + // make sure we are logging to the console no matter what the configuration tells us do to + if _, err := setting.Cfg.Section("log").NewKey("MODE", "console"); err != nil { + fatal("Setting logging mode to console failed: %v", err) + } + if _, err := setting.Cfg.Section("log.console").NewKey("STDERR", "true"); err != nil { + fatal("Setting console logger to stderr failed: %v", err) + } setting.NewServices() // cannot access session settings otherwise err := models.SetEngine() @@ -73,45 +192,59 @@ func runDump(ctx *cli.Context) error { return err } - tmpDir := ctx.String("tempdir") - if _, err := os.Stat(tmpDir); os.IsNotExist(err) { - fatal("Path does not exist: %s", tmpDir) + if file == nil { + file, err = os.Create(fileName) + if err != nil { + fatal("Unable to open %s: %v", fileName, err) + } + } + defer file.Close() + + verbose := ctx.Bool("verbose") + outType := ctx.String("type") + var iface interface{} + if fileName == "-" { + iface, err = archiver.ByExtension(fmt.Sprintf(".%s", outType)) + } else { + iface, err = archiver.ByExtension(fileName) } - tmpWorkDir, err := ioutil.TempDir(tmpDir, "gitea-dump-") if err != nil { - fatal("Failed to create tmp work directory: %v", err) - } - log.Info("Creating tmp work dir: %s", tmpWorkDir) - - // work-around #1103 - if os.Getenv("TMPDIR") == "" { - os.Setenv("TMPDIR", tmpWorkDir) + fatal("Unable to get archiver for extension: %v", err) } - dbDump := path.Join(tmpWorkDir, "gitea-db.sql") - - fileName := ctx.String("file") - log.Info("Packing dump files...") - z, err := zip.Create(fileName) - if err != nil { - fatal("Failed to create %s: %v", fileName, err) + w, _ := iface.(archiver.Writer) + if err := w.Create(file); err != nil { + fatal("Creating archiver.Writer failed: %v", err) } - - zip.Verbose = ctx.Bool("verbose") + defer w.Close() if ctx.IsSet("skip-repository") && ctx.Bool("skip-repository") { log.Info("Skip dumping local repositories") } else { - log.Info("Dumping local repositories...%s", setting.RepoRootPath) - reposDump := path.Join(tmpWorkDir, "gitea-repo.zip") - if err := zip.PackTo(setting.RepoRootPath, reposDump, true); err != nil { - fatal("Failed to dump local repositories: %v", err) + log.Info("Dumping local repositories... %s", setting.RepoRootPath) + if err := addRecursive(w, "repos", setting.RepoRootPath, verbose); err != nil { + fatal("Failed to include repositories: %v", err) } - if err := z.AddFile("gitea-repo.zip", reposDump); err != nil { - fatal("Failed to include gitea-repo.zip: %v", err) + + if _, err := os.Stat(setting.LFS.ContentPath); !os.IsNotExist(err) { + log.Info("Dumping lfs... %s", setting.LFS.ContentPath) + if err := addRecursive(w, "lfs", setting.LFS.ContentPath, verbose); err != nil { + fatal("Failed to include lfs: %v", err) + } } } + tmpDir := ctx.String("tempdir") + if _, err := os.Stat(tmpDir); os.IsNotExist(err) { + fatal("Path does not exist: %s", tmpDir) + } + + dbDump, err := ioutil.TempFile(tmpDir, "gitea-db.sql") + if err != nil { + fatal("Failed to create tmp file: %v", err) + } + defer os.Remove(dbDump.Name()) + targetDBType := ctx.String("database") if len(targetDBType) > 0 && targetDBType != setting.Database.Type { log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType) @@ -119,25 +252,29 @@ func runDump(ctx *cli.Context) error { log.Info("Dumping database...") } - if err := models.DumpDatabase(dbDump, targetDBType); err != nil { + if err := models.DumpDatabase(dbDump.Name(), targetDBType); err != nil { fatal("Failed to dump database: %v", err) } - if err := z.AddFile("gitea-db.sql", dbDump); err != nil { + if err := addFile(w, "gitea-db.sql", dbDump.Name(), verbose); err != nil { fatal("Failed to include gitea-db.sql: %v", err) } if len(setting.CustomConf) > 0 { log.Info("Adding custom configuration file from %s", setting.CustomConf) - if err := z.AddFile("app.ini", setting.CustomConf); err != nil { + if err := addFile(w, "app.ini", setting.CustomConf, verbose); err != nil { fatal("Failed to include specified app.ini: %v", err) } } customDir, err := os.Stat(setting.CustomPath) if err == nil && customDir.IsDir() { - if err := z.AddDir("custom", setting.CustomPath); err != nil { - fatal("Failed to include custom: %v", err) + if is, _ := isSubdir(setting.AppDataPath, setting.CustomPath); !is { + if err := addRecursive(w, "custom", setting.CustomPath, verbose); err != nil { + fatal("Failed to include custom: %v", err) + } + } else { + log.Info("Custom dir %s is inside data dir %s, skipped", setting.CustomPath, setting.AppDataPath) } } else { log.Info("Custom dir %s doesn't exist, skipped", setting.CustomPath) @@ -146,11 +283,19 @@ func runDump(ctx *cli.Context) error { if com.IsExist(setting.AppDataPath) { log.Info("Packing data directory...%s", setting.AppDataPath) - var sessionAbsPath string - if setting.SessionConfig.Provider == "file" { - sessionAbsPath = setting.SessionConfig.ProviderConfig + var excludes []string + if setting.Cfg.Section("session").Key("PROVIDER").Value() == "file" { + var opts session.Options + if err = json.Unmarshal([]byte(setting.SessionConfig.ProviderConfig), &opts); err != nil { + return err + } + excludes = append(excludes, opts.ProviderConfig) } - if err := zipAddDirectoryExclude(z, "data", setting.AppDataPath, sessionAbsPath); err != nil { + + excludes = append(excludes, setting.RepoRootPath) + excludes = append(excludes, setting.LFS.ContentPath) + excludes = append(excludes, setting.LogRootPath) + if err := addRecursiveExclude(w, "data", setting.AppDataPath, excludes, verbose); err != nil { fatal("Failed to include data directory: %v", err) } } @@ -161,32 +306,42 @@ func runDump(ctx *cli.Context) error { if ctx.IsSet("skip-log") && ctx.Bool("skip-log") { log.Info("Skip dumping log files") } else if com.IsExist(setting.LogRootPath) { - if err := z.AddDir("log", setting.LogRootPath); err != nil { + if err := addRecursive(w, "log", setting.LogRootPath, verbose); err != nil { fatal("Failed to include log: %v", err) } } - if err = z.Close(); err != nil { - _ = os.Remove(fileName) - fatal("Failed to save %s: %v", fileName, err) + if fileName != "-" { + if err = w.Close(); err != nil { + _ = os.Remove(fileName) + fatal("Failed to save %s: %v", fileName, err) + } + + if err := os.Chmod(fileName, 0600); err != nil { + log.Info("Can't change file access permissions mask to 0600: %v", err) + } } - if err := os.Chmod(fileName, 0600); err != nil { - log.Info("Can't change file access permissions mask to 0600: %v", err) + if fileName != "-" { + log.Info("Finish dumping in file %s", fileName) + } else { + log.Info("Finish dumping to stdout") } - log.Info("Removing tmp work dir: %s", tmpWorkDir) - - if err := os.RemoveAll(tmpWorkDir); err != nil { - fatal("Failed to remove %s: %v", tmpWorkDir, err) - } - log.Info("Finish dumping in file %s", fileName) - return nil } -// zipAddDirectoryExclude zips absPath to specified zipPath inside z excluding excludeAbsPath -func zipAddDirectoryExclude(zip *zip.ZipArchive, zipPath, absPath string, excludeAbsPath string) error { +func contains(slice []string, s string) bool { + for _, v := range slice { + if v == s { + return true + } + } + return false +} + +// addRecursiveExclude zips absPath to specified insidePath inside writer excluding excludeAbsPath +func addRecursiveExclude(w archiver.Writer, insidePath, absPath string, excludeAbsPath []string, verbose bool) error { absPath, err := filepath.Abs(absPath) if err != nil { return err @@ -197,24 +352,24 @@ func zipAddDirectoryExclude(zip *zip.ZipArchive, zipPath, absPath string, exclud } defer dir.Close() - zip.AddEmptyDir(zipPath) - files, err := dir.Readdir(0) if err != nil { return err } for _, file := range files { currentAbsPath := path.Join(absPath, file.Name()) - currentZipPath := path.Join(zipPath, file.Name()) + currentInsidePath := path.Join(insidePath, file.Name()) if file.IsDir() { - if currentAbsPath != excludeAbsPath { - if err = zipAddDirectoryExclude(zip, currentZipPath, currentAbsPath, excludeAbsPath); err != nil { + if !contains(excludeAbsPath, currentAbsPath) { + if err := addFile(w, currentInsidePath, currentAbsPath, false); err != nil { + return err + } + if err = addRecursiveExclude(w, currentInsidePath, currentAbsPath, excludeAbsPath, verbose); err != nil { return err } } - } else { - if err = zip.AddFile(currentZipPath, currentAbsPath); err != nil { + if err = addFile(w, currentInsidePath, currentAbsPath, verbose); err != nil { return err } } diff --git a/cmd/generate.go b/cmd/generate.go index 4e91b1d3f..13a99c94f 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -7,9 +7,11 @@ package cmd import ( "fmt" + "os" "code.gitea.io/gitea/modules/generate" + "github.com/mattn/go-isatty" "github.com/urfave/cli" ) @@ -59,7 +61,12 @@ func runGenerateInternalToken(c *cli.Context) error { return err } - fmt.Printf("%s\n", internalToken) + fmt.Printf("%s", internalToken) + + if isatty.IsTerminal(os.Stdout.Fd()) { + fmt.Printf("\n") + } + return nil } @@ -69,7 +76,12 @@ func runGenerateLfsJwtSecret(c *cli.Context) error { return err } - fmt.Printf("%s\n", JWTSecretBase64) + fmt.Printf("%s", JWTSecretBase64) + + if isatty.IsTerminal(os.Stdout.Fd()) { + fmt.Printf("\n") + } + return nil } @@ -79,6 +91,11 @@ func runGenerateSecretKey(c *cli.Context) error { return err } - fmt.Printf("%s\n", secretKey) + fmt.Printf("%s", secretKey) + + if isatty.IsTerminal(os.Stdout.Fd()) { + fmt.Printf("\n") + } + return nil } diff --git a/cmd/hook.go b/cmd/hook.go index fa932087f..f5658de7c 100644 --- a/cmd/hook.go +++ b/cmd/hook.go @@ -46,18 +46,33 @@ var ( Usage: "Delegate pre-receive Git hook", Description: "This command should only be called by Git", Action: runHookPreReceive, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, } subcmdHookUpdate = cli.Command{ Name: "update", Usage: "Delegate update Git hook", Description: "This command should only be called by Git", Action: runHookUpdate, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, } subcmdHookPostReceive = cli.Command{ Name: "post-receive", Usage: "Delegate post-receive Git hook", Description: "This command should only be called by Git", Action: runHookPostReceive, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, } ) @@ -138,7 +153,7 @@ func runHookPreReceive(c *cli.Context) error { return nil } - setup("hooks/pre-receive.log", false) + setup("hooks/pre-receive.log", c.Bool("debug")) if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 { if setting.OnlyAllowPushIfGiteaEnvironmentSet { @@ -273,7 +288,7 @@ func runHookPostReceive(c *cli.Context) error { return nil } - setup("hooks/post-receive.log", false) + setup("hooks/post-receive.log", c.Bool("debug")) if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 { if setting.OnlyAllowPushIfGiteaEnvironmentSet { diff --git a/cmd/manager.go b/cmd/manager.go index eed0a9e82..20c785868 100644 --- a/cmd/manager.go +++ b/cmd/manager.go @@ -10,6 +10,7 @@ import ( "os" "time" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/private" "github.com/urfave/cli" @@ -25,16 +26,27 @@ var ( subcmdShutdown, subcmdRestart, subcmdFlushQueues, + subcmdLogging, }, } subcmdShutdown = cli.Command{ - Name: "shutdown", - Usage: "Gracefully shutdown the running process", + Name: "shutdown", + Usage: "Gracefully shutdown the running process", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, Action: runShutdown, } subcmdRestart = cli.Command{ - Name: "restart", - Usage: "Gracefully restart the running process - (not implemented for windows servers)", + Name: "restart", + Usage: "Gracefully restart the running process - (not implemented for windows servers)", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, Action: runRestart, } subcmdFlushQueues = cli.Command{ @@ -46,17 +58,331 @@ var ( Name: "timeout", Value: 60 * time.Second, Usage: "Timeout for the flushing process", - }, - cli.BoolFlag{ + }, cli.BoolFlag{ Name: "non-blocking", Usage: "Set to true to not wait for flush to complete before returning", }, + cli.BoolFlag{ + Name: "debug", + }, + }, + } + defaultLoggingFlags = []cli.Flag{ + cli.StringFlag{ + Name: "group, g", + Usage: "Group to add logger to - will default to \"default\"", + }, cli.StringFlag{ + Name: "name, n", + Usage: "Name of the new logger - will default to mode", + }, cli.StringFlag{ + Name: "level, l", + Usage: "Logging level for the new logger", + }, cli.StringFlag{ + Name: "stacktrace-level, L", + Usage: "Stacktrace logging level", + }, cli.StringFlag{ + Name: "flags, F", + Usage: "Flags for the logger", + }, cli.StringFlag{ + Name: "expression, e", + Usage: "Matching expression for the logger", + }, cli.StringFlag{ + Name: "prefix, p", + Usage: "Prefix for the logger", + }, cli.BoolFlag{ + Name: "color", + Usage: "Use color in the logs", + }, cli.BoolFlag{ + Name: "debug", + }, + } + subcmdLogging = cli.Command{ + Name: "logging", + Usage: "Adjust logging commands", + Subcommands: []cli.Command{ + { + Name: "pause", + Usage: "Pause logging (Gitea will buffer logs up to a certain point and will drop them after that point)", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, + Action: runPauseLogging, + }, { + Name: "resume", + Usage: "Resume logging", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, + Action: runResumeLogging, + }, { + Name: "release-and-reopen", + Usage: "Cause Gitea to release and re-open files used for logging", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, + }, + Action: runReleaseReopenLogging, + }, { + Name: "remove", + Usage: "Remove a logger", + ArgsUsage: "[name] Name of logger to remove", + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "debug", + }, cli.StringFlag{ + Name: "group, g", + Usage: "Group to add logger to - will default to \"default\"", + }, + }, + Action: runRemoveLogger, + }, { + Name: "add", + Usage: "Add a logger", + Subcommands: []cli.Command{ + { + Name: "console", + Usage: "Add a console logger", + Flags: append(defaultLoggingFlags, + cli.BoolFlag{ + Name: "stderr", + Usage: "Output console logs to stderr - only relevant for console", + }), + Action: runAddConsoleLogger, + }, { + Name: "file", + Usage: "Add a file logger", + Flags: append(defaultLoggingFlags, []cli.Flag{ + cli.StringFlag{ + Name: "filename, f", + Usage: "Filename for the logger - this must be set.", + }, cli.BoolTFlag{ + Name: "rotate, r", + Usage: "Rotate logs", + }, cli.Int64Flag{ + Name: "max-size, s", + Usage: "Maximum size in bytes before rotation", + }, cli.BoolTFlag{ + Name: "daily, d", + Usage: "Rotate logs daily", + }, cli.IntFlag{ + Name: "max-days, D", + Usage: "Maximum number of daily logs to keep", + }, cli.BoolTFlag{ + Name: "compress, z", + Usage: "Compress rotated logs", + }, cli.IntFlag{ + Name: "compression-level, Z", + Usage: "Compression level to use", + }, + }...), + Action: runAddFileLogger, + }, { + Name: "conn", + Usage: "Add a net conn logger", + Flags: append(defaultLoggingFlags, []cli.Flag{ + cli.BoolFlag{ + Name: "reconnect-on-message, R", + Usage: "Reconnect to host for every message", + }, cli.BoolFlag{ + Name: "reconnect, r", + Usage: "Reconnect to host when connection is dropped", + }, cli.StringFlag{ + Name: "protocol, P", + Usage: "Set protocol to use: tcp, unix, or udp (defaults to tcp)", + }, cli.StringFlag{ + Name: "address, a", + Usage: "Host address and port to connect to (defaults to :7020)", + }, + }...), + Action: runAddConnLogger, + }, { + Name: "smtp", + Usage: "Add an SMTP logger", + Flags: append(defaultLoggingFlags, []cli.Flag{ + cli.StringFlag{ + Name: "username, u", + Usage: "Mail server username", + }, cli.StringFlag{ + Name: "password, P", + Usage: "Mail server password", + }, cli.StringFlag{ + Name: "host, H", + Usage: "Mail server host (defaults to: 127.0.0.1:25)", + }, cli.StringSliceFlag{ + Name: "send-to, s", + Usage: "Email address(es) to send to", + }, cli.StringFlag{ + Name: "subject, S", + Usage: "Subject header of sent emails", + }, + }...), + Action: runAddSMTPLogger, + }, + }, + }, }, } ) +func runRemoveLogger(c *cli.Context) error { + setup("manager", c.Bool("debug")) + group := c.String("group") + if len(group) == 0 { + group = log.DEFAULT + } + name := c.Args().First() + statusCode, msg := private.RemoveLogger(group, name) + switch statusCode { + case http.StatusInternalServerError: + fail("InternalServerError", msg) + } + + fmt.Fprintln(os.Stdout, msg) + return nil +} + +func runAddSMTPLogger(c *cli.Context) error { + setup("manager", c.Bool("debug")) + vals := map[string]interface{}{} + mode := "smtp" + if c.IsSet("host") { + vals["host"] = c.String("host") + } else { + vals["host"] = "127.0.0.1:25" + } + + if c.IsSet("username") { + vals["username"] = c.String("username") + } + if c.IsSet("password") { + vals["password"] = c.String("password") + } + + if !c.IsSet("send-to") { + return fmt.Errorf("Some recipients must be provided") + } + vals["sendTos"] = c.StringSlice("send-to") + + if c.IsSet("subject") { + vals["subject"] = c.String("subject") + } else { + vals["subject"] = "Diagnostic message from Gitea" + } + + return commonAddLogger(c, mode, vals) +} + +func runAddConnLogger(c *cli.Context) error { + setup("manager", c.Bool("debug")) + vals := map[string]interface{}{} + mode := "conn" + vals["net"] = "tcp" + if c.IsSet("protocol") { + switch c.String("protocol") { + case "udp": + vals["net"] = "udp" + case "unix": + vals["net"] = "unix" + } + } + if c.IsSet("address") { + vals["address"] = c.String("address") + } else { + vals["address"] = ":7020" + } + if c.IsSet("reconnect") { + vals["reconnect"] = c.Bool("reconnect") + } + if c.IsSet("reconnect-on-message") { + vals["reconnectOnMsg"] = c.Bool("reconnect-on-message") + } + return commonAddLogger(c, mode, vals) +} + +func runAddFileLogger(c *cli.Context) error { + setup("manager", c.Bool("debug")) + vals := map[string]interface{}{} + mode := "file" + if c.IsSet("filename") { + vals["filename"] = c.String("filename") + } else { + return fmt.Errorf("filename must be set when creating a file logger") + } + if c.IsSet("rotate") { + vals["rotate"] = c.Bool("rotate") + } + if c.IsSet("max-size") { + vals["maxsize"] = c.Int64("max-size") + } + if c.IsSet("daily") { + vals["daily"] = c.Bool("daily") + } + if c.IsSet("max-days") { + vals["maxdays"] = c.Int("max-days") + } + if c.IsSet("compress") { + vals["compress"] = c.Bool("compress") + } + if c.IsSet("compression-level") { + vals["compressionLevel"] = c.Int("compression-level") + } + return commonAddLogger(c, mode, vals) +} + +func runAddConsoleLogger(c *cli.Context) error { + setup("manager", c.Bool("debug")) + vals := map[string]interface{}{} + mode := "console" + if c.IsSet("stderr") && c.Bool("stderr") { + vals["stderr"] = c.Bool("stderr") + } + return commonAddLogger(c, mode, vals) +} + +func commonAddLogger(c *cli.Context, mode string, vals map[string]interface{}) error { + if len(c.String("level")) > 0 { + vals["level"] = log.FromString(c.String("level")).String() + } + if len(c.String("stacktrace-level")) > 0 { + vals["stacktraceLevel"] = log.FromString(c.String("stacktrace-level")).String() + } + if len(c.String("expression")) > 0 { + vals["expression"] = c.String("expression") + } + if len(c.String("prefix")) > 0 { + vals["prefix"] = c.String("prefix") + } + if len(c.String("flags")) > 0 { + vals["flags"] = log.FlagsFromString(c.String("flags")) + } + if c.IsSet("color") { + vals["colorize"] = c.Bool("color") + } + group := "default" + if c.IsSet("group") { + group = c.String("group") + } + name := mode + if c.IsSet("name") { + name = c.String("name") + } + statusCode, msg := private.AddLogger(group, name, mode, vals) + switch statusCode { + case http.StatusInternalServerError: + fail("InternalServerError", msg) + } + + fmt.Fprintln(os.Stdout, msg) + return nil +} + func runShutdown(c *cli.Context) error { - setup("manager", false) + setup("manager", c.Bool("debug")) statusCode, msg := private.Shutdown() switch statusCode { case http.StatusInternalServerError: @@ -68,7 +394,7 @@ func runShutdown(c *cli.Context) error { } func runRestart(c *cli.Context) error { - setup("manager", false) + setup("manager", c.Bool("debug")) statusCode, msg := private.Restart() switch statusCode { case http.StatusInternalServerError: @@ -80,7 +406,7 @@ func runRestart(c *cli.Context) error { } func runFlushQueues(c *cli.Context) error { - setup("manager", false) + setup("manager", c.Bool("debug")) statusCode, msg := private.FlushQueues(c.Duration("timeout"), c.Bool("non-blocking")) switch statusCode { case http.StatusInternalServerError: @@ -90,3 +416,39 @@ func runFlushQueues(c *cli.Context) error { fmt.Fprintln(os.Stdout, msg) return nil } + +func runPauseLogging(c *cli.Context) error { + setup("manager", c.Bool("debug")) + statusCode, msg := private.PauseLogging() + switch statusCode { + case http.StatusInternalServerError: + fail("InternalServerError", msg) + } + + fmt.Fprintln(os.Stdout, msg) + return nil +} + +func runResumeLogging(c *cli.Context) error { + setup("manager", c.Bool("debug")) + statusCode, msg := private.ResumeLogging() + switch statusCode { + case http.StatusInternalServerError: + fail("InternalServerError", msg) + } + + fmt.Fprintln(os.Stdout, msg) + return nil +} + +func runReleaseReopenLogging(c *cli.Context) error { + setup("manager", c.Bool("debug")) + statusCode, msg := private.ReleaseReopenLogging() + switch statusCode { + case http.StatusInternalServerError: + fail("InternalServerError", msg) + } + + fmt.Fprintln(os.Stdout, msg) + return nil +} diff --git a/cmd/web.go b/cmd/web.go index 243b9a410..6efadb941 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -7,6 +7,7 @@ package cmd import ( "context" "fmt" + "net" "net/http" _ "net/http/pprof" // Used for debugging if enabled and a web server is running "os" @@ -156,7 +157,7 @@ func runWeb(ctx *cli.Context) error { listenAddr := setting.HTTPAddr if setting.Protocol != setting.UnixSocket && setting.Protocol != setting.FCGIUnix { - listenAddr += ":" + setting.HTTPPort + listenAddr = net.JoinHostPort(listenAddr, setting.HTTPPort) } log.Info("Listen: %v://%s%s", setting.Protocol, listenAddr, setting.AppSubURL) diff --git a/contrib/legal/privacy.html.sample b/contrib/legal/privacy.html.sample index 3abec9514..22fc40fa3 100644 --- a/contrib/legal/privacy.html.sample +++ b/contrib/legal/privacy.html.sample @@ -7,7 +7,7 @@

Privacy Policy

-

Last updated: December 28, 2019

+

Last updated: January 29, 2020

Who We Are?

@@ -191,6 +191,6 @@

COPYING

-

This document is licensed under CC0 Public Domain license.

+

This document is licensed under CC0 Public Domain License. See full legal code here.

diff --git a/contrib/legal/tos.html.sample b/contrib/legal/tos.html.sample index 1c63bd8bb..d39082909 100644 --- a/contrib/legal/tos.html.sample +++ b/contrib/legal/tos.html.sample @@ -7,7 +7,7 @@

Terms of Service

-

Last updated: December 31, 2019

+

Last updated: January 29, 2020

Thank you for choosing Your Gitea Instance! Before you use it, please read this Terms of Service agreement carefully, which contains important contract between us and our users.

@@ -130,7 +130,7 @@

If you'd like to use our trademarks, you must follow all of our trademark guidelines.

-

This Agreement is licensed under CCO Public Domain License.

+

This Agreement is licensed under CCO Public Domain License.

API Terms

diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index 5085f0a67..e55fa735d 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -37,7 +37,6 @@ import ( "github.com/go-git/go-git/v5/plumbing" context2 "github.com/gorilla/context" "github.com/unknwon/com" - "gopkg.in/testfixtures.v2" "xorm.io/xorm" ) @@ -96,14 +95,12 @@ func runPR() { setting.Database.LogSQL = true //x, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared") - var helper testfixtures.Helper = &testfixtures.SQLite{} models.NewEngine(context.Background(), func(_ *xorm.Engine) error { return nil }) models.HasEngine = true //x.ShowSQL(true) err = models.InitFixtures( - helper, path.Join(curDir, "models/fixtures/"), ) if err != nil { diff --git a/custom/conf/app.ini.sample b/custom/conf/app.example.ini similarity index 94% rename from custom/conf/app.ini.sample rename to custom/conf/app.example.ini index c8797ca56..a15b9be54 100644 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.example.ini @@ -14,7 +14,12 @@ RUN_MODE = dev [repository] ROOT = SCRIPT_TYPE = bash -; Default ANSI charset +; DETECTED_CHARSETS_ORDER tie-break order for detected charsets. +; If the charsets have equal confidence, tie-breaking will be done by order in this list +; with charsets earlier in the list chosen in preference to those later. +; Adding "defaults" will place the unused charsets at that position. +DETECTED_CHARSETS_ORDER=UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE, ISO-8859, windows-1252, ISO-8859, windows-1250, ISO-8859, ISO-8859, ISO-8859, windows-1253, ISO-8859, windows-1255, ISO-8859, windows-1251, windows-1256, KOI8-R, ISO-8859, windows-1254, Shift_JIS, GB18030, EUC-JP, EUC-KR, Big5, ISO-2022, ISO-2022, ISO-2022, IBM424_rtl, IBM424_ltr, IBM420_rtl, IBM420_ltr +; Default ANSI charset to override non-UTF-8 charsets to ANSI_CHARSET = ; Force every new repository to be private FORCE_PRIVATE = false @@ -50,6 +55,10 @@ DISABLED_REPO_UNITS = DEFAULT_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki ; Prefix archive files by placing them in a directory named after the repository PREFIX_ARCHIVE_FILES = true +; Disable the creation of new mirrors. Pre-existing mirrors remain valid. +DISABLE_MIRRORS = false +; The default branch name of new repositories +DEFAULT_BRANCH=master [repository.editor] ; List of file extensions for which lines should be wrapped in the Monaco editor @@ -209,14 +218,17 @@ MIN_TIMEOUT = 10s MAX_TIMEOUT = 60s TIMEOUT_STEP = 10s ; This setting determines how often the db is queried to get the latest notification counts. -; If the browser client supports EventSource, it will be used in preference to polling notification. +; If the browser client supports EventSource and SharedWorker, a SharedWorker will be used in preference to polling notification. Set to -1 to disable the EventSource EVENT_SOURCE_UPDATE_TIME = 10s [markdown] ; Render soft line breaks as hard line breaks, which means a single newline character between ; paragraphs will cause a line break and adding trailing whitespace to paragraphs is not ; necessary to force a line break. -ENABLE_HARD_LINE_BREAK = true +; Render soft line breaks as hard line breaks for comments +ENABLE_HARD_LINE_BREAK_IN_COMMENTS = true +; Render soft line breaks as hard line breaks for markdown documents +ENABLE_HARD_LINE_BREAK_IN_DOCUMENTS = false ; Comma separated list of custom URL-Schemes that are allowed as links when rendering Markdown ; for example git,magnet,ftp (more at https://en.wikipedia.org/wiki/List_of_URI_schemes) ; URLs starting with http and https are always displayed, whatever is put in this entry. @@ -363,9 +375,9 @@ SCHEMA = ; For Postgres, either "disable" (default), "require", or "verify-full" ; For MySQL, either "false" (default), "true", or "skip-verify" SSL_MODE = disable -; For MySQL only, either "utf8" or "utf8mb4", default is "utf8". +; For MySQL only, either "utf8" or "utf8mb4", default is "utf8mb4". ; NOTICE: for "utf8mb4" you must use MySQL InnoDB > 5.6. Gitea is unable to check this. -CHARSET = utf8 +CHARSET = utf8mb4 ; For "sqlite3" and "tidb", use an absolute path when you start gitea as service PATH = data/gitea.db ; For "sqlite3" only. Query timeout @@ -624,23 +636,26 @@ SUBJECT_PREFIX = ; Mail server ; Gmail: smtp.gmail.com:587 ; QQ: smtp.qq.com:465 -; Note, if the port ends with "465", SMTPS will be used. Using STARTTLS on port 587 is recommended per RFC 6409. If the server supports STARTTLS it will always be used. +; Using STARTTLS on port 587 is recommended per RFC 6409. +; Note, if the port ends with "465", SMTPS will be used. HOST = ; Disable HELO operation when hostnames are different. DISABLE_HELO = ; Custom hostname for HELO operation, if no value is provided, one is retrieved from system. HELO_HOSTNAME = -; Do not verify the certificate of the server. Only use this for self-signed certificates -SKIP_VERIFY = +; Whether or not to skip verification of certificates; `true` to disable verification. This option is unsafe. Consider adding the certificate to the system trust store instead. +SKIP_VERIFY = false ; Use client certificate USE_CERTIFICATE = false CERT_FILE = custom/mailer/cert.pem KEY_FILE = custom/mailer/key.pem -; Should SMTP connection use TLS +; Should SMTP connect with TLS, (if port ends with 465 TLS will always be used.) +; If this is false but STARTTLS is supported the connection will be upgraded to TLS opportunistically. IS_TLS_ENABLED = false ; Mail from address, RFC 5322. This can be just an email address, or the `"Name" ` format FROM = ; Mailer user name and password +; Please Note: Authentication is only supported when the SMTP server communication is encrypted with TLS (this can be via STARTTLS) or `HOST=localhost`. USER = ; Use PASSWD = `your password` for quoting if you use special characters in the password. PASSWD = @@ -934,33 +949,8 @@ JWT_SECRET=Bk0yK7Y9g_p56v86KaHqjSbxvNvu3SbKoOdOt2ZcXvU MAX_TOKEN_LENGTH=32767 [i18n] -LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR -NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,Українська,日本語,español,português do Brasil,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어 - -; Used for datetimepicker -[i18n.datelang] -en-US = en -zh-CN = zh -zh-HK = zh-HK -zh-TW = zh-TW -de-DE = de -fr-FR = fr -nl-NL = nl -lv-LV = lv -ru-RU = ru -uk-UA = uk -ja-JP = ja -es-ES = es -pt-BR = pt-BR -pl-PL = pl -bg-BG = bg -it-IT = it -fi-FI = fi -tr-TR = tr -cs-CZ = cs-CZ -sr-SP = sr -sv-SE = sv -ko-KR = ko +LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR +NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,Українська,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어 [U2F] ; NOTE: THE DEFAULT VALUES HERE WILL NEED TO BE CHANGED diff --git a/docker/Makefile b/docker/Makefile deleted file mode 100644 index 7824847e5..000000000 --- a/docker/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -#Makefile related to docker - -DOCKER_IMAGE ?= gitea/gitea -DOCKER_TAG ?= latest -DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG) - -.PHONY: docker -docker: - docker build --disable-content-trust=false -t $(DOCKER_REF) . -# support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify" . - -.PHONY: docker-build -docker-build: - docker run -ti --rm -v $(CURDIR):/srv/app/src/code.gitea.io/gitea -w /srv/app/src/code.gitea.io/gitea -e TAGS="bindata $(TAGS)" LDFLAGS="$(LDFLAGS)" webhippie/golang:edge make clean build diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 000000000..ef05032ee --- /dev/null +++ b/docker/README.md @@ -0,0 +1,7 @@ +# Gitea - Docker + +Dockerfile is found in root of repository. + +Docker image can be found on [docker hub](https://hub.docker.com/r/gitea/gitea) + +Documentation on using docker image can be found on [Gitea Docs site](https://docs.gitea.io/en-us/install-with-docker/) diff --git a/docs/Makefile b/docs/Makefile index 78de2d396..487e16cf6 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -21,6 +21,10 @@ server: $(THEME) build: $(THEME) hugo --cleanDestinationDir +.PHONY: build-offline +build-offline: $(THEME) + hugo --baseURL="/" --cleanDestinationDir + .PHONY: update update: $(THEME) diff --git a/docs/config.yaml b/docs/config.yaml index 1e6abb07e..8b7560a59 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -18,7 +18,7 @@ params: description: Git with a cup of tea author: The Gitea Authors website: https://docs.gitea.io - version: 1.11.5 + version: 1.12.2 minGoVersion: 1.12 goVersion: 1.14 minNodeVersion: 10.13 @@ -312,3 +312,50 @@ languages: url: https://discourse.gitea.io/ weight: 80 pre: group + + pt-pt: + weight: 6 + languageName: Português de Portugal + menu: + page: + - name: Página inicial + url: https://gitea.io/pt-pt/ + weight: 10 + pre: home + - name: Documentação + url: /pt-pt/ + weight: 20 + pre: question + post: active + - name: API + url: https://try.gitea.io/api/swagger + weight: 45 + pre: plug + - name: Blog + url: https://blog.gitea.io/ + weight: 30 + pre: rss + - name: Código-fonte + url: https://code.gitea.io/ + weight: 40 + pre: code + - name: Tradução + url: https://crowdin.com/project/gitea + weight: 41 + pre: language + - name: Descarregamentos + url: https://dl.gitea.io/ + weight: 50 + pre: download + - name: GitHub + url: https://github.com/go-gitea/ + weight: 60 + pre: github + - name: Discussão no Discord + url: https://discord.gg/Gitea + weight: 70 + pre: comment + - name: Fórum + url: https://discourse.gitea.io/ + weight: 80 + pre: group diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 3ad24776f..b659b5daa 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -23,7 +23,7 @@ or any corresponding location. When installing from a distribution, this will typically be found at `/etc/gitea/conf/app.ini`. The defaults provided here are best-effort (not built automatically). They are -accurately recorded in [app.ini.sample](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.ini.sample) +accurately recorded in [app.example.ini](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini) (s/master/\). Any string in the format `%(X)s` is a feature powered by [ini](https://github.com/go-ini/ini/#recursive-values), for reading values recursively. @@ -46,7 +46,8 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. an absolute path. - `SCRIPT_TYPE`: **bash**: The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available. -- `ANSI_CHARSET`: **\**: The default charset for an unrecognized charset. +- `DETECTED_CHARSETS_ORDER`: **UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE, ISO-8859, windows-1252, ISO-8859, windows-1250, ISO-8859, ISO-8859, ISO-8859, windows-1253, ISO-8859, windows-1255, ISO-8859, windows-1251, windows-1256, KOI8-R, ISO-8859, windows-1254, Shift_JIS, GB18030, EUC-JP, EUC-KR, Big5, ISO-2022, ISO-2022, ISO-2022, IBM424_rtl, IBM424_ltr, IBM420_rtl, IBM420_ltr**: Tie-break order of detected charsets - if the detected charsets have equal confidence, charsets earlier in the list will be chosen in preference to those later. Adding `defaults` will place the unnamed charsets at that point. +- `ANSI_CHARSET`: **\**: Default ANSI charset to override non-UTF-8 charsets to. - `FORCE_PRIVATE`: **false**: Force every new repository to be private. - `DEFAULT_PRIVATE`: **last**: Default private when creating a new repository. \[last, private, public\] @@ -69,6 +70,8 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `ENABLE_PUSH_CREATE_USER`: **false**: Allow users to push local repositories to Gitea and have them automatically created for a user. - `ENABLE_PUSH_CREATE_ORG`: **false**: Allow users to push local repositories to Gitea and have them automatically created for an org. - `PREFIX_ARCHIVE_FILES`: **true**: Prefix archive files by placing them in a directory named after the repository. +- `DISABLE_MIRRORS`: **false**: Disable the creation of **new** mirrors. Pre-existing mirrors remain valid. +- `DEFAULT_BRANCH`: **master**: Default branch name of all repositories. ### Repository - Pull Request (`repository.pull-request`) @@ -147,12 +150,14 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `MIN_TIMEOUT`: **10s**: These options control how often notification endpoint is polled to update the notification count. On page load the notification count will be checked after `MIN_TIMEOUT`. The timeout will increase to `MAX_TIMEOUT` by `TIMEOUT_STEP` if the notification count is unchanged. Set MIN_TIMEOUT to 0 to turn off. - `MAX_TIMEOUT`: **60s**. - `TIMEOUT_STEP`: **10s**. -- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource`, it will be used in preference to polling notification endpoint. - +- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource` and `SharedWorker`, a `SharedWorker` will be used in preference to polling notification endpoint. Set to **-1** to disable the `EventSource`. ## Markdown (`markdown`) -- `ENABLE_HARD_LINE_BREAK`: **true**: Render soft line breaks as hard line breaks, which +- `ENABLE_HARD_LINE_BREAK_IN_COMMENTS`: **true**: Render soft line breaks as hard line breaks in comments, which + means a single newline character between paragraphs will cause a line break and adding + trailing whitespace to paragraphs is not necessary to force a line break. +- `ENABLE_HARD_LINE_BREAK_IN_DOCUMENTS`: **false**: Render soft line breaks as hard line breaks in documents, which means a single newline character between paragraphs will cause a line break and adding trailing whitespace to paragraphs is not necessary to force a line break. - `CUSTOM_URL_SCHEMES`: Use a comma separated list (ftp,git,svn) to indicate additional @@ -239,7 +244,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `require`: Enable TLS without any verifications. - `verify-ca`: Enable TLS with verification of the database server certificate against its root certificate. - `verify-full`: Enable TLS and verify the database server name matches the given certificate in either the `Common Name` or `Subject Alternative Name` fields. -- `CHARSET`: **utf8**: For MySQL only, either "utf8" or "utf8mb4", default is "utf8". NOTICE: for "utf8mb4" you must use MySQL InnoDB > 5.6. Gitea is unable to check this. +- `CHARSET`: **utf8mb4**: For MySQL only, either "utf8" or "utf8mb4". NOTICE: for "utf8mb4" you must use MySQL InnoDB > 5.6. Gitea is unable to check this. - `PATH`: **data/gitea.db**: For SQLite3 only, the database file path. - `LOG_SQL`: **true**: Log the executed SQL. - `DB_RETRIES`: **10**: How many ORM init / DB connect attempts allowed. @@ -394,11 +399,17 @@ set name for unique queues. Individual queues will default to - `DISABLE_HELO`: **\**: Disable HELO operation. - `HELO_HOSTNAME`: **\**: Custom hostname for HELO operation. - `HOST`: **\**: SMTP mail host address and port (example: smtp.gitea.io:587). + - Using opportunistic TLS via STARTTLS on port 587 is recommended per RFC 6409. +- `IS_TLS_ENABLED` : **false** : Forcibly use TLS to connect even if not on a default SMTPS port. + - Note, if the port ends with `465` SMTPS/SMTP over TLS will be used despite this setting. + - Otherwise if `IS_TLS_ENABLED=false` and the server supports `STARTTLS` this will be used. Thus if `STARTTLS` is preferred you should set `IS_TLS_ENABLED=false`. - `FROM`: **\**: Mail from address, RFC 5322. This can be just an email address, or the "Name" \ format. - `USER`: **\**: Username of mailing user (usually the sender's e-mail address). - `PASSWD`: **\**: Password of mailing user. Use \`your password\` for quoting if you use special characters in the password. -- `SKIP_VERIFY`: **\**: Do not verify the self-signed certificates. + - Please note: authentication is only supported when the SMTP server communication is encrypted with TLS (this can be via `STARTTLS`) or `HOST=localhost`. See [Email Setup]({{< relref "doc/usage/email-setup.en-us.md" >}}) for more information. +- `SKIP_VERIFY`: **false**: Whether or not to skip verification of certificates; `true` to disable verification. + - **Warning:** This option is unsafe. Consider adding the certificate to the system trust store instead. - **Note:** Gitea only supports SMTP with STARTTLS. - `SUBJECT_PREFIX`: **\**: Prefix to be placed before e-mail subject lines. - `MAILER_TYPE`: **smtp**: \[smtp, sendmail, dummy\] @@ -412,7 +423,6 @@ set name for unique queues. Individual queues will default to - `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be command or full path). - `SENDMAIL_TIMEOUT`: **5m**: default timeout for sending email through sendmail -- ``IS_TLS_ENABLED`` : **false** : Decide if SMTP connections should use TLS. ## Cache (`cache`) @@ -460,7 +470,7 @@ set name for unique queues. Individual queues will default to - `ENABLED`: **true**: Enable this to allow uploading attachments. - `PATH`: **data/attachments**: Path to store attachments. -- `ALLOWED_TYPES`: **see app.ini.sample**: Allowed MIME types, e.g. `image/jpeg|image/png`. +- `ALLOWED_TYPES`: **see app.example.ini**: Allowed MIME types, e.g. `image/jpeg|image/png`. Use `*/*` for all types. - `MAX_SIZE`: **4**: Maximum size (MB). - `MAX_FILES`: **5**: Maximum number of attachments that can be uploaded at once. @@ -602,33 +612,8 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false` ## i18n (`i18n`) -- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR**: List of locales shown in language selector -- `NAMES`: **English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,日本語,español,português do Brasil,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어**: Visible names corresponding to the locales - -### i18n - Datepicker Language (`i18n.datelang`) -Maps locales to the languages used by the datepicker plugin - -- `en-US`: **en** -- `zh-CN`: **zh** -- `zh-HK`: **zh-HK** -- `zh-TW`: **zh-TW** -- `de-DE`: **de** -- `fr-FR`: **fr** -- `nl-NL`: **nl** -- `lv-LV`: **lv** -- `ru-RU`: **ru** -- `ja-JP`: **ja** -- `es-ES`: **es** -- `pt-BR`: **pt-BR** -- `pl-PL`: **pl** -- `bg-BG`: **bg** -- `it-IT`: **it** -- `fi-FI`: **fi** -- `tr-TR`: **tr** -- `cs-CZ`: **cs-CZ** -- `sr-SP`: **sr** -- `sv-SE`: **sv** -- `ko-KR`: **ko** +- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR**: List of locales shown in language selector +- `NAMES`: **English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,français,Nederlands,latviešu,русский,日本語,español,português do Brasil,Português de Portugal,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어**: Visible names corresponding to the locales ## U2F (`U2F`) - `APP_ID`: **`ROOT_URL`**: Declares the facet of the application. Requires HTTPS. diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index 082944c8a..48cf0b462 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -15,7 +15,7 @@ menu: # 配置说明 -这是针对Gitea配置文件的说明,你可以了解Gitea的强大配置。需要说明的是,你的所有改变请修改 `custom/conf/app.ini` 文件而不是源文件。所有默认值可以通过 [app.ini.sample](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.ini.sample) 查看到。如果你发现 `%(X)s` 这样的内容,请查看 [ini](https://github.com/go-ini/ini/#recursive-values) 这里的说明。标注了 :exclamation: 的配置项表明除非你真的理解这个配置项的意义,否则最好使用默认值。 +这是针对Gitea配置文件的说明,你可以了解Gitea的强大配置。需要说明的是,你的所有改变请修改 `custom/conf/app.ini` 文件而不是源文件。所有默认值可以通过 [app.example.ini](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini) 查看到。如果你发现 `%(X)s` 这样的内容,请查看 [ini](https://github.com/go-ini/ini/#recursive-values) 这里的说明。标注了 :exclamation: 的配置项表明除非你真的理解这个配置项的意义,否则最好使用默认值。 ## Overall (`DEFAULT`) @@ -81,7 +81,7 @@ menu: - `USER`: 数据库用户名。 - `PASSWD`: 数据库用户密码。 - `SSL_MODE`: MySQL 或 PostgreSQL数据库是否启用SSL模式。 -- `CHARSET`: **utf8**: 仅当数据库为 MySQL 时有效, 可以为 "utf8" 或 "utf8mb4"。注意:如果使用 "utf8mb4",你的 MySQL InnoDB 版本必须在 5.6 以上。 +- `CHARSET`: **utf8mb4**: 仅当数据库为 MySQL 时有效, 可以为 "utf8" 或 "utf8mb4"。注意:如果使用 "utf8mb4",你的 MySQL InnoDB 版本必须在 5.6 以上。 - `PATH`: Tidb 或者 SQLite3 数据文件存放路径。 - `LOG_SQL`: **true**: 显示生成的SQL,默认为真。 - `MAX_IDLE_CONNS` **0**: 最大空闲数据库连接 diff --git a/docs/content/doc/advanced/customizing-gitea.en-us.md b/docs/content/doc/advanced/customizing-gitea.en-us.md index b52a713e4..6bc7be4ad 100644 --- a/docs/content/doc/advanced/customizing-gitea.en-us.md +++ b/docs/content/doc/advanced/customizing-gitea.en-us.md @@ -35,7 +35,7 @@ Again `gitea help` will allow you review this variable and you can override it u `--config` option on the `gitea` binary. - [Quick Cheat Sheet](https://docs.gitea.io/en-us/config-cheat-sheet/) -- [Complete List](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.ini.sample) +- [Complete List](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini) If the `CustomPath` folder can't be found despite checking `gitea help`, check the `GITEA_CUSTOM` environment variable; this can be used to override the default path to something else. @@ -108,45 +108,6 @@ Apart from `extra_links.tmpl` and `extra_tabs.tmpl`, there are other useful temp - `body_outer_post.tmpl`, before the bottom `