From 41856e6aaa397b8c74e8382d05b9fa79f8492f08 Mon Sep 17 00:00:00 2001 From: Maksim Totmin Date: Wed, 26 Aug 2026 10:35:20 +0700 Subject: [PATCH] refactor: restructure to standard Go project layout (cmd/ + internal/) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move entry point to cmd/streamdeck-lets-go/ - Split package main into internal packages: - internal/deck: hardware control (Deck, events, brightness) - internal/render: key rendering, icons, fonts, PageManager - internal/web: HTTP API + embedded SPA - internal/daemon: event loop, autoswitch, screensaver, actions - Add ConfigDir() to internal/config - Export cross-package API (Deck, PageManager, WebServer, etc.) - Move dist/arch/ → packaging/ with updated PKGBUILD/.SRCINFO - Add Makefile (build, test, vet, fmt, install) - Update README with new build commands and project structure - Delete unused media.go stub --- Makefile | 33 + README.md | 22 +- emoji.go | 209 -- fontawesome_icons.go | 1979 ----------------- internal/config/config.go | 53 +- action.go => internal/daemon/action.go | 102 +- .../daemon/autoswitch.go | 6 +- .../daemon/autoswitch_test.go | 2 +- daemon.go => internal/daemon/daemon.go | 67 +- gesture.go => internal/daemon/gesture.go | 13 +- .../daemon/screensaver.go | 18 +- deck.go => internal/deck/deck.go | 46 +- .../Font_Awesome_7_BrandsRegular400.otf | Bin .../assets}/Font_Awesome_7_FreeRegular400.otf | Bin .../assets}/Font_Awesome_7_FreeSolid900.otf | Bin .../render/assets}/mplus-1m-medium.ttf | Bin .../render/assets}/mplus-1m-regular.ttf | Bin cbdt.go => internal/render/cbdt.go | 8 +- internal/render/emoji.go | 209 ++ .../render/fontawesome.go | 3 +- .../render/fontawesome_data.go | 4 +- internal/render/fontawesome_icons.go | 1979 +++++++++++++++++ icons.go => internal/render/icons.go | 2 +- page.go => internal/render/page.go | 139 +- render.go => internal/render/render.go | 4 +- {static => internal/web/static}/alpine.min.js | 0 {static => internal/web/static}/app.js | 0 .../web/static}/fontawesome/css/all.min.css | 0 .../fontawesome/webfonts/fa-brands-400.ttf | Bin .../fontawesome/webfonts/fa-brands-400.woff2 | Bin .../fontawesome/webfonts/fa-regular-400.ttf | Bin .../fontawesome/webfonts/fa-regular-400.woff2 | Bin .../fontawesome/webfonts/fa-solid-900.ttf | Bin .../fontawesome/webfonts/fa-solid-900.woff2 | Bin .../webfonts/fa-v4compatibility.ttf | Bin .../webfonts/fa-v4compatibility.woff2 | Bin {static => internal/web/static}/index.html | 0 {static => internal/web/static}/styles.css | 0 web.go => internal/web/web.go | 46 +- main.go | 135 -- media.go | 11 - {dist/arch => packaging}/.SRCINFO | 4 +- {dist/arch => packaging}/90-streamdeck.rules | 0 {dist/arch => packaging}/PKGBUILD | 10 +- .../streamdeck-lets-go.service | 0 45 files changed, 2506 insertions(+), 2598 deletions(-) create mode 100644 Makefile delete mode 100644 emoji.go delete mode 100644 fontawesome_icons.go rename action.go => internal/daemon/action.go (71%) rename autoswitch.go => internal/daemon/autoswitch.go (99%) rename autoswitch_test.go => internal/daemon/autoswitch_test.go (99%) rename daemon.go => internal/daemon/daemon.go (87%) rename gesture.go => internal/daemon/gesture.go (92%) rename screensaver.go => internal/daemon/screensaver.go (81%) rename deck.go => internal/deck/deck.go (88%) rename {assets => internal/render/assets}/Font_Awesome_7_BrandsRegular400.otf (100%) rename {assets => internal/render/assets}/Font_Awesome_7_FreeRegular400.otf (100%) rename {assets => internal/render/assets}/Font_Awesome_7_FreeSolid900.otf (100%) rename {assets => internal/render/assets}/mplus-1m-medium.ttf (100%) rename {assets => internal/render/assets}/mplus-1m-regular.ttf (100%) rename cbdt.go => internal/render/cbdt.go (98%) create mode 100644 internal/render/emoji.go rename fontawesome.go => internal/render/fontawesome.go (99%) rename fontawesome_data.go => internal/render/fontawesome_data.go (97%) create mode 100644 internal/render/fontawesome_icons.go rename icons.go => internal/render/icons.go (99%) rename page.go => internal/render/page.go (88%) rename render.go => internal/render/render.go (98%) rename {static => internal/web/static}/alpine.min.js (100%) rename {static => internal/web/static}/app.js (100%) rename {static => internal/web/static}/fontawesome/css/all.min.css (100%) rename {static => internal/web/static}/fontawesome/webfonts/fa-brands-400.ttf (100%) rename {static => internal/web/static}/fontawesome/webfonts/fa-brands-400.woff2 (100%) rename {static => internal/web/static}/fontawesome/webfonts/fa-regular-400.ttf (100%) rename {static => internal/web/static}/fontawesome/webfonts/fa-regular-400.woff2 (100%) rename {static => internal/web/static}/fontawesome/webfonts/fa-solid-900.ttf (100%) rename {static => internal/web/static}/fontawesome/webfonts/fa-solid-900.woff2 (100%) rename {static => internal/web/static}/fontawesome/webfonts/fa-v4compatibility.ttf (100%) rename {static => internal/web/static}/fontawesome/webfonts/fa-v4compatibility.woff2 (100%) rename {static => internal/web/static}/index.html (100%) rename {static => internal/web/static}/styles.css (100%) rename web.go => internal/web/web.go (94%) delete mode 100644 main.go delete mode 100644 media.go rename {dist/arch => packaging}/.SRCINFO (88%) rename {dist/arch => packaging}/90-streamdeck.rules (100%) rename {dist/arch => packaging}/PKGBUILD (80%) rename {dist/arch => packaging}/streamdeck-lets-go.service (100%) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3510c17 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +BINARY := streamdeck-lets-go +MODULE := streamdeck-lets-go +CMDDIR := cmd/streamdeck-lets-go +PKGARCH := packaging + +.PHONY: all build test vet fmt clean install + +all: build + +build: + CGO_ENABLED=1 go build -ldflags "-s -w" -o $(BINARY) ./$(CMDDIR) + +test: + go test ./... + +vet: + go vet ./... + +fmt: + gofmt -l . + +clean: + rm -f $(BINARY) + +install: build + install -Dm755 $(BINARY) /usr/local/bin/$(BINARY) + install -Dm644 $(PKGARCH)/streamdeck-lets-go.service /usr/lib/systemd/user/streamdeck-lets-go.service + install -Dm644 $(PKGARCH)/90-streamdeck.rules /usr/lib/udev/rules.d/90-streamdeck.rules + +uninstall: + rm -f /usr/local/bin/$(BINARY) + rm -f /usr/lib/systemd/user/streamdeck-lets-go.service + rm -f /usr/lib/udev/rules.d/90-streamdeck.rules diff --git a/README.md b/README.md index 922ca04..d73e595 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,9 @@ ### Install from source ```bash -go build -o streamdeck-lets-go . +make build +# or +go build -o streamdeck-lets-go ./cmd/streamdeck-lets-go ``` ### Run @@ -47,7 +49,19 @@ Open `http://localhost:9090` in your browser. --- -## Configuration +## Project structure + +``` +cmd/streamdeck-lets-go entry point (CLI: daemon, switch, discover) +internal/ + config JSON config model, load/save/validate + deck Stream Deck hardware: open, render, brightness, events + render Key rendering, icon/fonts, PageManager, display outputs + web HTTP API + embedded Alpine.js SPA + daemon Event loop, autoswitch, screensaver, actions, gestures +packaging/ AUR PKGBUILD, systemd unit, udev rule +Makefile build, test, vet, fmt, install +``` The config file is stored at `~/.config/streamdeck-lets-go/config.json`. You can edit it manually or through the web UI. @@ -371,9 +385,9 @@ After a configurable idle period the deck dims or shows a custom image. ## Building from source ```bash -git clone git@git.totmin.ru:en2zmax/streamdeck-lets-go.git +git clone git@github.com:totmin/streamdeck-lets-go.git cd streamdeck-lets-go -go build -o streamdeck-lets-go . +make build ``` Dependencies: diff --git a/emoji.go b/emoji.go deleted file mode 100644 index 93d83c6..0000000 --- a/emoji.go +++ /dev/null @@ -1,209 +0,0 @@ -package main - -import "sync" - -var emojiShortcodes = map[string]rune{ - // media - "play_pause": 0x25B6, - "stop": 0x23F9, - "record": 0x23FA, - "eject": 0x23CF, - "track_previous": 0x23EE, - "track_next": 0x23ED, - "fast_forward": 0x23E9, - "rewind": 0x23EA, - "shuffle": 0x1F500, - "repeat": 0x1F501, - "repeat_one": 0x1F502, - - // volume - "speaker": 0x1F50A, - "mute": 0x1F507, - "sound": 0x1F509, - - // navigation - "arrow_up": 0x2B06, - "arrow_down": 0x2B07, - "arrow_left": 0x2B05, - "arrow_right": 0x27A1, - "arrows_clockwise": 0x1F503, - "arrows_counterclockwise": 0x1F504, - - // status - "check": 0x2705, - "heavy_check_mark": 0x2714, - "x": 0x274C, - "heavy_multiplication_x": 0x2716, - "warning": 0x26A0, - "information_source": 0x2139, - "question": 0x2753, - "exclamation": 0x2757, - "white_check_mark": 0x2705, - "heavy_plus_sign": 0x2795, - "heavy_minus_sign": 0x2796, - "heavy_division_sign": 0x2797, - - // actions - "gear": 0x2699, - "hammer": 0x1F528, - "wrench": 0x1F527, - "key": 0x1F511, - "lock": 0x1F512, - "unlocked": 0x1F513, - "magnifying_glass": 0x1F50D, - "home": 0x1F3E0, - "bookmark": 0x1F516, - "bell": 0x1F514, - "clock": 0x1F550, - "alarm_clock": 0x23F0, - "hourglass": 0x231B, - "calendar": 0x1F4C5, - "envelope": 0x2709, - "camera": 0x1F4F7, - "video_camera": 0x1F4F9, - "microphone": 0x1F3A4, - "telephone": 0x260E, - "phone": 0x1F4DE, - "computer": 0x1F4BB, - "laptop": 0x1F4BB, - "folder": 0x1F4C1, - "open_file_folder": 0x1F4C2, - "clipboard": 0x1F4CB, - "memo": 0x1F4DD, - "pencil": 0x270F, - "scissors": 0x2702, - "link": 0x1F517, - "paperclip": 0x1F4CE, - "pushpin": 0x1F4CC, - "trash": 0x1F5D1, - "star": 0x2B50, - "trophy": 0x1F3C6, - "medal": 0x1F3C5, - "target": 0x1F3AF, - "dart": 0x1F3AF, - - // objects - "lightbulb": 0x1F4A1, - "bulb": 0x1F4A1, - "battery": 0x1F50B, - "electric_plug": 0x1F50C, - "rocket": 0x1F680, - "airplane": 0x2708, - "car": 0x1F697, - "bicycle": 0x1F6B2, - "headphones": 0x1F3A7, - "gamepad": 0x1F3AE, - "joystick": 0x1F579, - "musical_note": 0x1F3B5, - "notes": 0x1F3B6, - "printer": 0x1F5A8, - "keyboard": 0x2328, - - // weather - "sun": 0x2600, - "sunny": 0x2600, - "moon": 0x1F319, - "cloud": 0x2601, - "rainbow": 0x1F308, - "fire": 0x1F525, - "flame": 0x1F525, - "zap": 0x26A1, - "lightning": 0x26A1, - "snowflake": 0x2744, - "umbrella": 0x2602, - - // hearts - "heart": 0x2764, - "yellow_heart": 0x1F49B, - "green_heart": 0x1F49A, - "blue_heart": 0x1F499, - "purple_heart": 0x1F49C, - "black_heart": 0x1F5A4, - "broken_heart": 0x1F494, - "two_hearts": 0x1F495, - "sparkling_heart": 0x1F496, - "heartpulse": 0x1F497, - "heart_beat": 0x1F493, - "revolving_hearts": 0x1F49E, - "cupid": 0x1F498, - "gift_heart": 0x1F49D, - - // faces - "smile": 0x1F600, - "smiley": 0x1F603, - "grinning": 0x1F604, - "blush": 0x1F60A, - "wink": 0x1F609, - "heart_eyes": 0x1F60D, - "kissing_heart": 0x1F618, - "kissing": 0x1F617, - "smirk": 0x1F60F, - "stuck_out_tongue": 0x1F61B, - "stuck_out_tongue_winking_eye": 0x1F61C, - "sunglasses": 0x1F60E, - "innocent": 0x1F607, - "neutral_face": 0x1F610, - "expressionless": 0x1F611, - "thinking": 0x1F914, - "confused": 0x1F615, - "worried": 0x1F61F, - "frown": 0x1F641, - "persevere": 0x1F623, - "tired": 0x1F62B, - "weary": 0x1F629, - "cry": 0x1F622, - "sob": 0x1F62D, - "sweat_smile": 0x1F605, - "joy": 0x1F602, - "relaxed": 0x263A, - "angry": 0x1F620, - "rage": 0x1F621, - "skull": 0x1F480, - "ghost": 0x1F47B, - "robot": 0x1F916, - "sleeping": 0x1F634, - "sleep": 0x1F634, - "zzz": 0x1F4A4, - "dizzy": 0x1F4AB, - "boom": 0x1F4A5, - "collision": 0x1F4A5, - "sweat_drops": 0x1F4A6, - "dash": 0x1F4A8, - "alien": 0x1F47D, - "poop": 0x1F4A9, - - // hands & gestures - "thumbsup": 0x1F44D, - "thumbsdown": 0x1F44E, - "ok_hand": 0x1F44C, - "wave": 0x1F44B, - "clap": 0x1F44F, - "open_hands": 0x1F450, - "raised_hands": 0x1F64C, - "pray": 0x1F64F, - "muscle": 0x1F4AA, - "point_up": 0x261D, - "point_down": 0x1F447, - "point_left": 0x1F448, - "point_right": 0x1F449, - "fist": 0x270A, - "raised_hand": 0x270B, - "v": 0x270C, - "victory": 0x270C, - "crossed_fingers": 0x1F91E, - "writing_hand": 0x270D, - "call_me": 0x1F919, - "hand": 0x270B, -} - -var ( - emojiColorFontOnce sync.Once - emojiColorFontData []byte -) - -func loadColorEmojiFont() []byte { - emojiColorFontOnce.Do(func() { - emojiColorFontData = fcRead("emoji") - }) - return emojiColorFontData -} diff --git a/fontawesome_icons.go b/fontawesome_icons.go deleted file mode 100644 index 98d5ea5..0000000 --- a/fontawesome_icons.go +++ /dev/null @@ -1,1979 +0,0 @@ -package main - -var fa7Icons = map[string]string{ - "0": "0", // U+0030 - "1": "1", // U+0031 - "2": "2", // U+0032 - "3": "3", // U+0033 - "4": "4", // U+0034 - "5": "5", // U+0035 - "6": "6", // U+0036 - "7": "7", // U+0037 - "8": "8", // U+0038 - "9": "9", // U+0039 - "A": "A", // U+0041 - "AddressBook": "\xef\x8a\xb9", // U+f2b9 - "AddressCard": "\xef\x8a\xbb", // U+f2bb - "AlarmClock": "\xef\x8d\x8e", // U+f34e - "AlignCenter": "\xef\x80\xb7", // U+f037 - "AlignJustify": "\xef\x80\xb9", // U+f039 - "AlignLeft": "\xef\x80\xb6", // U+f036 - "AlignRight": "\xef\x80\xb8", // U+f038 - "Anchor": "\xef\x84\xbd", // U+f13d - "AnchorCircleCheck": "\xee\x92\xaa", // U+e4aa - "AnchorCircleExclamation": "\xee\x92\xab", // U+e4ab - "AnchorCircleXmark": "\xee\x92\xac", // U+e4ac - "AnchorLock": "\xee\x92\xad", // U+e4ad - "AngleDown": "\xef\x84\x87", // U+f107 - "AngleLeft": "\xef\x84\x84", // U+f104 - "AngleRight": "\xef\x84\x85", // U+f105 - "AngleUp": "\xef\x84\x86", // U+f106 - "AnglesDown": "\xef\x84\x83", // U+f103 - "AnglesLeft": "\xef\x84\x80", // U+f100 - "AnglesRight": "\xef\x84\x81", // U+f101 - "AnglesUp": "\xef\x84\x82", // U+f102 - "Ankh": "\xef\x99\x84", // U+f644 - "AppleWhole": "\xef\x97\x91", // U+f5d1 - "Aquarius": "\xee\xa1\x85", // U+e845 - "Archway": "\xef\x95\x97", // U+f557 - "Aries": "\xee\xa1\x86", // U+e846 - "ArrowDown": "\xef\x81\xa3", // U+f063 - "ArrowDown19": "\xef\x85\xa2", // U+f162 - "ArrowDown91": "\xef\xa2\x86", // U+f886 - "ArrowDownAZ": "\xef\x85\x9d", // U+f15d - "ArrowDownLong": "\xef\x85\xb5", // U+f175 - "ArrowDownShortWide": "\xef\xa2\x84", // U+f884 - "ArrowDownUpAcrossLine": "\xee\x92\xaf", // U+e4af - "ArrowDownUpLock": "\xee\x92\xb0", // U+e4b0 - "ArrowDownWideShort": "\xef\x85\xa0", // U+f160 - "ArrowDownZA": "\xef\xa2\x81", // U+f881 - "ArrowLeft": "\xef\x81\xa0", // U+f060 - "ArrowLeftLong": "\xef\x85\xb7", // U+f177 - "ArrowPointer": "\xef\x89\x85", // U+f245 - "ArrowRight": "\xef\x81\xa1", // U+f061 - "ArrowRightArrowLeft": "\xef\x83\xac", // U+f0ec - "ArrowRightFromBracket": "\xef\x82\x8b", // U+f08b - "ArrowRightLong": "\xef\x85\xb8", // U+f178 - "ArrowRightToBracket": "\xef\x82\x90", // U+f090 - "ArrowRightToCity": "\xee\x92\xb3", // U+e4b3 - "ArrowRotateLeft": "\xef\x83\xa2", // U+f0e2 - "ArrowRotateRight": "\xef\x80\x9e", // U+f01e - "ArrowTrendDown": "\xee\x82\x97", // U+e097 - "ArrowTrendUp": "\xee\x82\x98", // U+e098 - "ArrowTurnDown": "\xef\x85\x89", // U+f149 - "ArrowTurnUp": "\xef\x85\x88", // U+f148 - "ArrowUp": "\xef\x81\xa2", // U+f062 - "ArrowUp19": "\xef\x85\xa3", // U+f163 - "ArrowUp91": "\xef\xa2\x87", // U+f887 - "ArrowUpAZ": "\xef\x85\x9e", // U+f15e - "ArrowUpFromBracket": "\xee\x82\x9a", // U+e09a - "ArrowUpFromGroundWater": "\xee\x92\xb5", // U+e4b5 - "ArrowUpFromWaterPump": "\xee\x92\xb6", // U+e4b6 - "ArrowUpLong": "\xef\x85\xb6", // U+f176 - "ArrowUpRightDots": "\xee\x92\xb7", // U+e4b7 - "ArrowUpRightFromSquare": "\xef\x82\x8e", // U+f08e - "ArrowUpShortWide": "\xef\xa2\x85", // U+f885 - "ArrowUpWideShort": "\xef\x85\xa1", // U+f161 - "ArrowUpZA": "\xef\xa2\x82", // U+f882 - "ArrowsDownToLine": "\xee\x92\xb8", // U+e4b8 - "ArrowsDownToPeople": "\xee\x92\xb9", // U+e4b9 - "ArrowsLeftRight": "\xef\x81\xbe", // U+f07e - "ArrowsLeftRightToLine": "\xee\x92\xba", // U+e4ba - "ArrowsRotate": "\xef\x80\xa1", // U+f021 - "ArrowsSpin": "\xee\x92\xbb", // U+e4bb - "ArrowsSplitUpAndLeft": "\xee\x92\xbc", // U+e4bc - "ArrowsToCircle": "\xee\x92\xbd", // U+e4bd - "ArrowsToDot": "\xee\x92\xbe", // U+e4be - "ArrowsToEye": "\xee\x92\xbf", // U+e4bf - "ArrowsTurnRight": "\xee\x93\x80", // U+e4c0 - "ArrowsTurnToDots": "\xee\x93\x81", // U+e4c1 - "ArrowsUpDown": "\xef\x81\xbd", // U+f07d - "ArrowsUpDownLeftRight": "\xef\x81\x87", // U+f047 - "ArrowsUpToLine": "\xee\x93\x82", // U+e4c2 - "Asterisk": "*", // U+002a - "At": "@", // U+0040 - "Atom": "\xef\x97\x92", // U+f5d2 - "AudioDescription": "\xef\x8a\x9e", // U+f29e - "AustralSign": "\xee\x82\xa9", // U+e0a9 - "Award": "\xef\x95\x99", // U+f559 - "B": "B", // U+0042 - "Baby": "\xef\x9d\xbc", // U+f77c - "BabyCarriage": "\xef\x9d\xbd", // U+f77d - "Backward": "\xef\x81\x8a", // U+f04a - "BackwardFast": "\xef\x81\x89", // U+f049 - "BackwardStep": "\xef\x81\x88", // U+f048 - "Bacon": "\xef\x9f\xa5", // U+f7e5 - "Bacteria": "\xee\x81\x99", // U+e059 - "Bacterium": "\xee\x81\x9a", // U+e05a - "BagShopping": "\xef\x8a\x90", // U+f290 - "Bahai": "\xef\x99\xa6", // U+f666 - "BahtSign": "\xee\x82\xac", // U+e0ac - "Ban": "\xef\x81\x9e", // U+f05e - "BanSmoking": "\xef\x95\x8d", // U+f54d - "Bandage": "\xef\x91\xa2", // U+f462 - "BangladeshiTakaSign": "\xee\x8b\xa6", // U+e2e6 - "Barcode": "\xef\x80\xaa", // U+f02a - "Bars": "\xef\x83\x89", // U+f0c9 - "BarsProgress": "\xef\xa0\xa8", // U+f828 - "BarsStaggered": "\xef\x95\x90", // U+f550 - "Baseball": "\xef\x90\xb3", // U+f433 - "BaseballBatBall": "\xef\x90\xb2", // U+f432 - "BasketShopping": "\xef\x8a\x91", // U+f291 - "Basketball": "\xef\x90\xb4", // U+f434 - "Bath": "\xef\x8b\x8d", // U+f2cd - "BatteryEmpty": "\xef\x89\x84", // U+f244 - "BatteryFull": "\xef\x89\x80", // U+f240 - "BatteryHalf": "\xef\x89\x82", // U+f242 - "BatteryQuarter": "\xef\x89\x83", // U+f243 - "BatteryThreeQuarters": "\xef\x89\x81", // U+f241 - "Bed": "\xef\x88\xb6", // U+f236 - "BedPulse": "\xef\x92\x87", // U+f487 - "BeerMugEmpty": "\xef\x83\xbc", // U+f0fc - "Bell": "\xef\x83\xb3", // U+f0f3 - "BellConcierge": "\xef\x95\xa2", // U+f562 - "BellSlash": "\xef\x87\xb6", // U+f1f6 - "BezierCurve": "\xef\x95\x9b", // U+f55b - "Bicycle": "\xef\x88\x86", // U+f206 - "Binoculars": "\xef\x87\xa5", // U+f1e5 - "Biohazard": "\xef\x9e\x80", // U+f780 - "BitcoinSign": "\xee\x82\xb4", // U+e0b4 - "Blender": "\xef\x94\x97", // U+f517 - "BlenderPhone": "\xef\x9a\xb6", // U+f6b6 - "Blog": "\xef\x9e\x81", // U+f781 - "Bold": "\xef\x80\xb2", // U+f032 - "Bolt": "\xef\x83\xa7", // U+f0e7 - "BoltLightning": "\xee\x82\xb7", // U+e0b7 - "Bomb": "\xef\x87\xa2", // U+f1e2 - "Bone": "\xef\x97\x97", // U+f5d7 - "Bong": "\xef\x95\x9c", // U+f55c - "Book": "\xef\x80\xad", // U+f02d - "BookAtlas": "\xef\x95\x98", // U+f558 - "BookBible": "\xef\x99\x87", // U+f647 - "BookBookmark": "\xee\x82\xbb", // U+e0bb - "BookJournalWhills": "\xef\x99\xaa", // U+f66a - "BookMedical": "\xef\x9f\xa6", // U+f7e6 - "BookOpen": "\xef\x94\x98", // U+f518 - "BookOpenReader": "\xef\x97\x9a", // U+f5da - "BookQuran": "\xef\x9a\x87", // U+f687 - "BookSkull": "\xef\x9a\xb7", // U+f6b7 - "BookTanakh": "\xef\xa0\xa7", // U+f827 - "Bookmark": "\xef\x80\xae", // U+f02e - "BorderAll": "\xef\xa1\x8c", // U+f84c - "BorderNone": "\xef\xa1\x90", // U+f850 - "BorderTopLeft": "\xef\xa1\x93", // U+f853 - "BoreHole": "\xee\x93\x83", // U+e4c3 - "BottleDroplet": "\xee\x93\x84", // U+e4c4 - "BottleWater": "\xee\x93\x85", // U+e4c5 - "BowlFood": "\xee\x93\x86", // U+e4c6 - "BowlRice": "\xee\x8b\xab", // U+e2eb - "BowlingBall": "\xef\x90\xb6", // U+f436 - "Box": "\xef\x91\xa6", // U+f466 - "BoxArchive": "\xef\x86\x87", // U+f187 - "BoxOpen": "\xef\x92\x9e", // U+f49e - "BoxTissue": "\xee\x81\x9b", // U+e05b - "BoxesPacking": "\xee\x93\x87", // U+e4c7 - "BoxesStacked": "\xef\x91\xa8", // U+f468 - "Braille": "\xef\x8a\xa1", // U+f2a1 - "Brain": "\xef\x97\x9c", // U+f5dc - "BrazilianRealSign": "\xee\x91\xac", // U+e46c - "BreadSlice": "\xef\x9f\xac", // U+f7ec - "Bridge": "\xee\x93\x88", // U+e4c8 - "BridgeCircleCheck": "\xee\x93\x89", // U+e4c9 - "BridgeCircleExclamation": "\xee\x93\x8a", // U+e4ca - "BridgeCircleXmark": "\xee\x93\x8b", // U+e4cb - "BridgeLock": "\xee\x93\x8c", // U+e4cc - "BridgeWater": "\xee\x93\x8e", // U+e4ce - "Briefcase": "\xef\x82\xb1", // U+f0b1 - "BriefcaseMedical": "\xef\x91\xa9", // U+f469 - "Broom": "\xef\x94\x9a", // U+f51a - "BroomBall": "\xef\x91\x98", // U+f458 - "Brush": "\xef\x95\x9d", // U+f55d - "Bucket": "\xee\x93\x8f", // U+e4cf - "Bug": "\xef\x86\x88", // U+f188 - "BugSlash": "\xee\x92\x90", // U+e490 - "Bugs": "\xee\x93\x90", // U+e4d0 - "Building": "\xef\x86\xad", // U+f1ad - "BuildingCircleArrowRight": "\xee\x93\x91", // U+e4d1 - "BuildingCircleCheck": "\xee\x93\x92", // U+e4d2 - "BuildingCircleExclamation": "\xee\x93\x93", // U+e4d3 - "BuildingCircleXmark": "\xee\x93\x94", // U+e4d4 - "BuildingColumns": "\xef\x86\x9c", // U+f19c - "BuildingFlag": "\xee\x93\x95", // U+e4d5 - "BuildingLock": "\xee\x93\x96", // U+e4d6 - "BuildingNgo": "\xee\x93\x97", // U+e4d7 - "BuildingShield": "\xee\x93\x98", // U+e4d8 - "BuildingUn": "\xee\x93\x99", // U+e4d9 - "BuildingUser": "\xee\x93\x9a", // U+e4da - "BuildingWheat": "\xee\x93\x9b", // U+e4db - "Bullhorn": "\xef\x82\xa1", // U+f0a1 - "Bullseye": "\xef\x85\x80", // U+f140 - "Burger": "\xef\xa0\x85", // U+f805 - "Burst": "\xee\x93\x9c", // U+e4dc - "Bus": "\xef\x88\x87", // U+f207 - "BusSide": "\xee\xa0\x9d", // U+e81d - "BusSimple": "\xef\x95\x9e", // U+f55e - "BusinessTime": "\xef\x99\x8a", // U+f64a - "C": "C", // U+0043 - "CableCar": "\xef\x9f\x9a", // U+f7da - "CakeCandles": "\xef\x87\xbd", // U+f1fd - "Calculator": "\xef\x87\xac", // U+f1ec - "Calendar": "\xef\x84\xb3", // U+f133 - "CalendarCheck": "\xef\x89\xb4", // U+f274 - "CalendarDay": "\xef\x9e\x83", // U+f783 - "CalendarDays": "\xef\x81\xb3", // U+f073 - "CalendarMinus": "\xef\x89\xb2", // U+f272 - "CalendarPlus": "\xef\x89\xb1", // U+f271 - "CalendarWeek": "\xef\x9e\x84", // U+f784 - "CalendarXmark": "\xef\x89\xb3", // U+f273 - "Camera": "\xef\x80\xb0", // U+f030 - "CameraRetro": "\xef\x82\x83", // U+f083 - "CameraRotate": "\xee\x83\x98", // U+e0d8 - "Campground": "\xef\x9a\xbb", // U+f6bb - "Cancer": "\xee\xa1\x87", // U+e847 - "CandyCane": "\xef\x9e\x86", // U+f786 - "Cannabis": "\xef\x95\x9f", // U+f55f - "Capricorn": "\xee\xa1\x88", // U+e848 - "Capsules": "\xef\x91\xab", // U+f46b - "Car": "\xef\x86\xb9", // U+f1b9 - "CarBattery": "\xef\x97\x9f", // U+f5df - "CarBurst": "\xef\x97\xa1", // U+f5e1 - "CarOn": "\xee\x93\x9d", // U+e4dd - "CarRear": "\xef\x97\x9e", // U+f5de - "CarSide": "\xef\x97\xa4", // U+f5e4 - "CarTunnel": "\xee\x93\x9e", // U+e4de - "Caravan": "\xef\xa3\xbf", // U+f8ff - "CaretDown": "\xef\x83\x97", // U+f0d7 - "CaretLeft": "\xef\x83\x99", // U+f0d9 - "CaretRight": "\xef\x83\x9a", // U+f0da - "CaretUp": "\xef\x83\x98", // U+f0d8 - "Carrot": "\xef\x9e\x87", // U+f787 - "CartArrowDown": "\xef\x88\x98", // U+f218 - "CartFlatbed": "\xef\x91\xb4", // U+f474 - "CartFlatbedSuitcase": "\xef\x96\x9d", // U+f59d - "CartPlus": "\xef\x88\x97", // U+f217 - "CartShopping": "\xef\x81\xba", // U+f07a - "CashRegister": "\xef\x9e\x88", // U+f788 - "Cat": "\xef\x9a\xbe", // U+f6be - "CediSign": "\xee\x83\x9f", // U+e0df - "CentSign": "\xee\x8f\xb5", // U+e3f5 - "Certificate": "\xef\x82\xa3", // U+f0a3 - "Chair": "\xef\x9b\x80", // U+f6c0 - "Chalkboard": "\xef\x94\x9b", // U+f51b - "ChalkboardUser": "\xef\x94\x9c", // U+f51c - "ChampagneGlasses": "\xef\x9e\x9f", // U+f79f - "ChargingStation": "\xef\x97\xa7", // U+f5e7 - "ChartArea": "\xef\x87\xbe", // U+f1fe - "ChartBar": "\xef\x82\x80", // U+f080 - "ChartColumn": "\xee\x83\xa3", // U+e0e3 - "ChartDiagram": "\xee\x9a\x95", // U+e695 - "ChartGantt": "\xee\x83\xa4", // U+e0e4 - "ChartLine": "\xef\x88\x81", // U+f201 - "ChartPie": "\xef\x88\x80", // U+f200 - "ChartSimple": "\xee\x91\xb3", // U+e473 - "Check": "\xef\x80\x8c", // U+f00c - "CheckDouble": "\xef\x95\xa0", // U+f560 - "CheckToSlot": "\xef\x9d\xb2", // U+f772 - "Cheese": "\xef\x9f\xaf", // U+f7ef - "Chess": "\xef\x90\xb9", // U+f439 - "ChessBishop": "\xef\x90\xba", // U+f43a - "ChessBoard": "\xef\x90\xbc", // U+f43c - "ChessKing": "\xef\x90\xbf", // U+f43f - "ChessKnight": "\xef\x91\x81", // U+f441 - "ChessPawn": "\xef\x91\x83", // U+f443 - "ChessQueen": "\xef\x91\x85", // U+f445 - "ChessRook": "\xef\x91\x87", // U+f447 - "ChevronDown": "\xef\x81\xb8", // U+f078 - "ChevronLeft": "\xef\x81\x93", // U+f053 - "ChevronRight": "\xef\x81\x94", // U+f054 - "ChevronUp": "\xef\x81\xb7", // U+f077 - "Child": "\xef\x86\xae", // U+f1ae - "ChildCombatant": "\xee\x93\xa0", // U+e4e0 - "ChildDress": "\xee\x96\x9c", // U+e59c - "ChildReaching": "\xee\x96\x9d", // U+e59d - "Children": "\xee\x93\xa1", // U+e4e1 - "Church": "\xef\x94\x9d", // U+f51d - "Circle": "\xef\x84\x91", // U+f111 - "CircleArrowDown": "\xef\x82\xab", // U+f0ab - "CircleArrowLeft": "\xef\x82\xa8", // U+f0a8 - "CircleArrowRight": "\xef\x82\xa9", // U+f0a9 - "CircleArrowUp": "\xef\x82\xaa", // U+f0aa - "CircleCheck": "\xef\x81\x98", // U+f058 - "CircleChevronDown": "\xef\x84\xba", // U+f13a - "CircleChevronLeft": "\xef\x84\xb7", // U+f137 - "CircleChevronRight": "\xef\x84\xb8", // U+f138 - "CircleChevronUp": "\xef\x84\xb9", // U+f139 - "CircleDollarToSlot": "\xef\x92\xb9", // U+f4b9 - "CircleDot": "\xef\x86\x92", // U+f192 - "CircleDown": "\xef\x8d\x98", // U+f358 - "CircleExclamation": "\xef\x81\xaa", // U+f06a - "CircleH": "\xef\x91\xbe", // U+f47e - "CircleHalfStroke": "\xef\x81\x82", // U+f042 - "CircleInfo": "\xef\x81\x9a", // U+f05a - "CircleLeft": "\xef\x8d\x99", // U+f359 - "CircleMinus": "\xef\x81\x96", // U+f056 - "CircleNodes": "\xee\x93\xa2", // U+e4e2 - "CircleNotch": "\xef\x87\x8e", // U+f1ce - "CirclePause": "\xef\x8a\x8b", // U+f28b - "CirclePlay": "\xef\x85\x84", // U+f144 - "CirclePlus": "\xef\x81\x95", // U+f055 - "CircleQuestion": "\xef\x81\x99", // U+f059 - "CircleRadiation": "\xef\x9e\xba", // U+f7ba - "CircleRight": "\xef\x8d\x9a", // U+f35a - "CircleStop": "\xef\x8a\x8d", // U+f28d - "CircleUp": "\xef\x8d\x9b", // U+f35b - "CircleUser": "\xef\x8a\xbd", // U+f2bd - "CircleXmark": "\xef\x81\x97", // U+f057 - "City": "\xef\x99\x8f", // U+f64f - "Clapperboard": "\xee\x84\xb1", // U+e131 - "Clipboard": "\xef\x8c\xa8", // U+f328 - "ClipboardCheck": "\xef\x91\xac", // U+f46c - "ClipboardList": "\xef\x91\xad", // U+f46d - "ClipboardQuestion": "\xee\x93\xa3", // U+e4e3 - "ClipboardUser": "\xef\x9f\xb3", // U+f7f3 - "Clock": "\xef\x80\x97", // U+f017 - "ClockRotateLeft": "\xef\x87\x9a", // U+f1da - "Clone": "\xef\x89\x8d", // U+f24d - "ClosedCaptioning": "\xef\x88\x8a", // U+f20a - "ClosedCaptioningSlash": "\xee\x84\xb5", // U+e135 - "Cloud": "\xef\x83\x82", // U+f0c2 - "CloudArrowDown": "\xef\x83\xad", // U+f0ed - "CloudArrowUp": "\xef\x83\xae", // U+f0ee - "CloudBolt": "\xef\x9d\xac", // U+f76c - "CloudMeatball": "\xef\x9c\xbb", // U+f73b - "CloudMoon": "\xef\x9b\x83", // U+f6c3 - "CloudMoonRain": "\xef\x9c\xbc", // U+f73c - "CloudRain": "\xef\x9c\xbd", // U+f73d - "CloudShowersHeavy": "\xef\x9d\x80", // U+f740 - "CloudShowersWater": "\xee\x93\xa4", // U+e4e4 - "CloudSun": "\xef\x9b\x84", // U+f6c4 - "CloudSunRain": "\xef\x9d\x83", // U+f743 - "Clover": "\xee\x84\xb9", // U+e139 - "Code": "\xef\x84\xa1", // U+f121 - "CodeBranch": "\xef\x84\xa6", // U+f126 - "CodeCommit": "\xef\x8e\x86", // U+f386 - "CodeCompare": "\xee\x84\xba", // U+e13a - "CodeFork": "\xee\x84\xbb", // U+e13b - "CodeMerge": "\xef\x8e\x87", // U+f387 - "CodePullRequest": "\xee\x84\xbc", // U+e13c - "Coins": "\xef\x94\x9e", // U+f51e - "ColonSign": "\xee\x85\x80", // U+e140 - "Comment": "\xef\x81\xb5", // U+f075 - "CommentDollar": "\xef\x99\x91", // U+f651 - "CommentDots": "\xef\x92\xad", // U+f4ad - "CommentMedical": "\xef\x9f\xb5", // U+f7f5 - "CommentNodes": "\xee\x9a\x96", // U+e696 - "CommentSlash": "\xef\x92\xb3", // U+f4b3 - "CommentSms": "\xef\x9f\x8d", // U+f7cd - "Comments": "\xef\x82\x86", // U+f086 - "CommentsDollar": "\xef\x99\x93", // U+f653 - "CompactDisc": "\xef\x94\x9f", // U+f51f - "Compass": "\xef\x85\x8e", // U+f14e - "CompassDrafting": "\xef\x95\xa8", // U+f568 - "Compress": "\xef\x81\xa6", // U+f066 - "Computer": "\xee\x93\xa5", // U+e4e5 - "ComputerMouse": "\xef\xa3\x8c", // U+f8cc - "Cookie": "\xef\x95\xa3", // U+f563 - "CookieBite": "\xef\x95\xa4", // U+f564 - "Copy": "\xef\x83\x85", // U+f0c5 - "Copyright": "\xef\x87\xb9", // U+f1f9 - "Couch": "\xef\x92\xb8", // U+f4b8 - "Cow": "\xef\x9b\x88", // U+f6c8 - "CreditCard": "\xef\x82\x9d", // U+f09d - "Crop": "\xef\x84\xa5", // U+f125 - "CropSimple": "\xef\x95\xa5", // U+f565 - "Cross": "\xef\x99\x94", // U+f654 - "Crosshairs": "\xef\x81\x9b", // U+f05b - "Crow": "\xef\x94\xa0", // U+f520 - "Crown": "\xef\x94\xa1", // U+f521 - "Crutch": "\xef\x9f\xb7", // U+f7f7 - "CruzeiroSign": "\xee\x85\x92", // U+e152 - "Cube": "\xef\x86\xb2", // U+f1b2 - "Cubes": "\xef\x86\xb3", // U+f1b3 - "CubesStacked": "\xee\x93\xa6", // U+e4e6 - "D": "D", // U+0044 - "Database": "\xef\x87\x80", // U+f1c0 - "DeleteLeft": "\xef\x95\x9a", // U+f55a - "Democrat": "\xef\x9d\x87", // U+f747 - "Desktop": "\xef\x8e\x90", // U+f390 - "Dharmachakra": "\xef\x99\x95", // U+f655 - "DiagramNext": "\xee\x91\xb6", // U+e476 - "DiagramPredecessor": "\xee\x91\xb7", // U+e477 - "DiagramProject": "\xef\x95\x82", // U+f542 - "DiagramSuccessor": "\xee\x91\xba", // U+e47a - "Diamond": "\xef\x88\x99", // U+f219 - "DiamondTurnRight": "\xef\x97\xab", // U+f5eb - "Dice": "\xef\x94\xa2", // U+f522 - "DiceD20": "\xef\x9b\x8f", // U+f6cf - "DiceD6": "\xef\x9b\x91", // U+f6d1 - "DiceFive": "\xef\x94\xa3", // U+f523 - "DiceFour": "\xef\x94\xa4", // U+f524 - "DiceOne": "\xef\x94\xa5", // U+f525 - "DiceSix": "\xef\x94\xa6", // U+f526 - "DiceThree": "\xef\x94\xa7", // U+f527 - "DiceTwo": "\xef\x94\xa8", // U+f528 - "Disease": "\xef\x9f\xba", // U+f7fa - "Display": "\xee\x85\xa3", // U+e163 - "Divide": "\xef\x94\xa9", // U+f529 - "Dna": "\xef\x91\xb1", // U+f471 - "Dog": "\xef\x9b\x93", // U+f6d3 - "DollarSign": "$", // U+0024 - "Dolly": "\xef\x91\xb2", // U+f472 - "DongSign": "\xee\x85\xa9", // U+e169 - "DoorClosed": "\xef\x94\xaa", // U+f52a - "DoorOpen": "\xef\x94\xab", // U+f52b - "Dove": "\xef\x92\xba", // U+f4ba - "DownLeftAndUpRightToCenter": "\xef\x90\xa2", // U+f422 - "DownLong": "\xef\x8c\x89", // U+f309 - "Download": "\xef\x80\x99", // U+f019 - "Dragon": "\xef\x9b\x95", // U+f6d5 - "DrawPolygon": "\xef\x97\xae", // U+f5ee - "Droplet": "\xef\x81\x83", // U+f043 - "DropletSlash": "\xef\x97\x87", // U+f5c7 - "Drum": "\xef\x95\xa9", // U+f569 - "DrumSteelpan": "\xef\x95\xaa", // U+f56a - "DrumstickBite": "\xef\x9b\x97", // U+f6d7 - "Dumbbell": "\xef\x91\x8b", // U+f44b - "Dumpster": "\xef\x9e\x93", // U+f793 - "DumpsterFire": "\xef\x9e\x94", // U+f794 - "Dungeon": "\xef\x9b\x99", // U+f6d9 - "E": "E", // U+0045 - "EarDeaf": "\xef\x8a\xa4", // U+f2a4 - "EarListen": "\xef\x8a\xa2", // U+f2a2 - "EarthAfrica": "\xef\x95\xbc", // U+f57c - "EarthAmericas": "\xef\x95\xbd", // U+f57d - "EarthAsia": "\xef\x95\xbe", // U+f57e - "EarthEurope": "\xef\x9e\xa2", // U+f7a2 - "EarthOceania": "\xee\x91\xbb", // U+e47b - "Egg": "\xef\x9f\xbb", // U+f7fb - "Eject": "\xef\x81\x92", // U+f052 - "Elevator": "\xee\x85\xad", // U+e16d - "Ellipsis": "\xef\x85\x81", // U+f141 - "EllipsisVertical": "\xef\x85\x82", // U+f142 - "Envelope": "\xef\x83\xa0", // U+f0e0 - "EnvelopeCircleCheck": "\xee\x93\xa8", // U+e4e8 - "EnvelopeOpen": "\xef\x8a\xb6", // U+f2b6 - "EnvelopeOpenText": "\xef\x99\x98", // U+f658 - "EnvelopesBulk": "\xef\x99\xb4", // U+f674 - "Equals": "=", // U+003d - "Eraser": "\xef\x84\xad", // U+f12d - "Ethernet": "\xef\x9e\x96", // U+f796 - "EuroSign": "\xef\x85\x93", // U+f153 - "Exclamation": "!", // U+0021 - "Expand": "\xef\x81\xa5", // U+f065 - "Explosion": "\xee\x93\xa9", // U+e4e9 - "Eye": "\xef\x81\xae", // U+f06e - "EyeDropper": "\xef\x87\xbb", // U+f1fb - "EyeLowVision": "\xef\x8a\xa8", // U+f2a8 - "EyeSlash": "\xef\x81\xb0", // U+f070 - "F": "F", // U+0046 - "FaceAngry": "\xef\x95\x96", // U+f556 - "FaceDizzy": "\xef\x95\xa7", // U+f567 - "FaceFlushed": "\xef\x95\xb9", // U+f579 - "FaceFrown": "\xef\x84\x99", // U+f119 - "FaceFrownOpen": "\xef\x95\xba", // U+f57a - "FaceGrimace": "\xef\x95\xbf", // U+f57f - "FaceGrin": "\xef\x96\x80", // U+f580 - "FaceGrinBeam": "\xef\x96\x82", // U+f582 - "FaceGrinBeamSweat": "\xef\x96\x83", // U+f583 - "FaceGrinHearts": "\xef\x96\x84", // U+f584 - "FaceGrinSquint": "\xef\x96\x85", // U+f585 - "FaceGrinSquintTears": "\xef\x96\x86", // U+f586 - "FaceGrinStars": "\xef\x96\x87", // U+f587 - "FaceGrinTears": "\xef\x96\x88", // U+f588 - "FaceGrinTongue": "\xef\x96\x89", // U+f589 - "FaceGrinTongueSquint": "\xef\x96\x8a", // U+f58a - "FaceGrinTongueWink": "\xef\x96\x8b", // U+f58b - "FaceGrinWide": "\xef\x96\x81", // U+f581 - "FaceGrinWink": "\xef\x96\x8c", // U+f58c - "FaceKiss": "\xef\x96\x96", // U+f596 - "FaceKissBeam": "\xef\x96\x97", // U+f597 - "FaceKissWinkHeart": "\xef\x96\x98", // U+f598 - "FaceLaugh": "\xef\x96\x99", // U+f599 - "FaceLaughBeam": "\xef\x96\x9a", // U+f59a - "FaceLaughSquint": "\xef\x96\x9b", // U+f59b - "FaceLaughWink": "\xef\x96\x9c", // U+f59c - "FaceMeh": "\xef\x84\x9a", // U+f11a - "FaceMehBlank": "\xef\x96\xa4", // U+f5a4 - "FaceRollingEyes": "\xef\x96\xa5", // U+f5a5 - "FaceSadCry": "\xef\x96\xb3", // U+f5b3 - "FaceSadTear": "\xef\x96\xb4", // U+f5b4 - "FaceSmile": "\xef\x84\x98", // U+f118 - "FaceSmileBeam": "\xef\x96\xb8", // U+f5b8 - "FaceSmileWink": "\xef\x93\x9a", // U+f4da - "FaceSurprise": "\xef\x97\x82", // U+f5c2 - "FaceTired": "\xef\x97\x88", // U+f5c8 - "Fan": "\xef\xa1\xa3", // U+f863 - "Faucet": "\xee\x80\x85", // U+e005 - "FaucetDrip": "\xee\x80\x86", // U+e006 - "Fax": "\xef\x86\xac", // U+f1ac - "Feather": "\xef\x94\xad", // U+f52d - "FeatherPointed": "\xef\x95\xab", // U+f56b - "Ferry": "\xee\x93\xaa", // U+e4ea - "File": "\xef\x85\x9b", // U+f15b - "FileArrowDown": "\xef\x95\xad", // U+f56d - "FileArrowUp": "\xef\x95\xb4", // U+f574 - "FileAudio": "\xef\x87\x87", // U+f1c7 - "FileCircleCheck": "\xee\x96\xa0", // U+e5a0 - "FileCircleExclamation": "\xee\x93\xab", // U+e4eb - "FileCircleMinus": "\xee\x93\xad", // U+e4ed - "FileCirclePlus": "\xee\x92\x94", // U+e494 - "FileCircleQuestion": "\xee\x93\xaf", // U+e4ef - "FileCircleXmark": "\xee\x96\xa1", // U+e5a1 - "FileCode": "\xef\x87\x89", // U+f1c9 - "FileContract": "\xef\x95\xac", // U+f56c - "FileCsv": "\xef\x9b\x9d", // U+f6dd - "FileExcel": "\xef\x87\x83", // U+f1c3 - "FileExport": "\xef\x95\xae", // U+f56e - "FileFragment": "\xee\x9a\x97", // U+e697 - "FileHalfDashed": "\xee\x9a\x98", // U+e698 - "FileImage": "\xef\x87\x85", // U+f1c5 - "FileImport": "\xef\x95\xaf", // U+f56f - "FileInvoice": "\xef\x95\xb0", // U+f570 - "FileInvoiceDollar": "\xef\x95\xb1", // U+f571 - "FileLines": "\xef\x85\x9c", // U+f15c - "FileMedical": "\xef\x91\xb7", // U+f477 - "FilePdf": "\xef\x87\x81", // U+f1c1 - "FilePen": "\xef\x8c\x9c", // U+f31c - "FilePowerpoint": "\xef\x87\x84", // U+f1c4 - "FilePrescription": "\xef\x95\xb2", // U+f572 - "FileShield": "\xee\x93\xb0", // U+e4f0 - "FileSignature": "\xef\x95\xb3", // U+f573 - "FileVideo": "\xef\x87\x88", // U+f1c8 - "FileWaveform": "\xef\x91\xb8", // U+f478 - "FileWord": "\xef\x87\x82", // U+f1c2 - "FileZipper": "\xef\x87\x86", // U+f1c6 - "Fill": "\xef\x95\xb5", // U+f575 - "FillDrip": "\xef\x95\xb6", // U+f576 - "Film": "\xef\x80\x88", // U+f008 - "Filter": "\xef\x82\xb0", // U+f0b0 - "FilterCircleDollar": "\xef\x99\xa2", // U+f662 - "FilterCircleXmark": "\xee\x85\xbb", // U+e17b - "Fingerprint": "\xef\x95\xb7", // U+f577 - "Fire": "\xef\x81\xad", // U+f06d - "FireBurner": "\xee\x93\xb1", // U+e4f1 - "FireExtinguisher": "\xef\x84\xb4", // U+f134 - "FireFlameCurved": "\xef\x9f\xa4", // U+f7e4 - "FireFlameSimple": "\xef\x91\xaa", // U+f46a - "Fish": "\xef\x95\xb8", // U+f578 - "FishFins": "\xee\x93\xb2", // U+e4f2 - "Flag": "\xef\x80\xa4", // U+f024 - "FlagCheckered": "\xef\x84\x9e", // U+f11e - "FlagUsa": "\xef\x9d\x8d", // U+f74d - "Flask": "\xef\x83\x83", // U+f0c3 - "FlaskVial": "\xee\x93\xb3", // U+e4f3 - "FloppyDisk": "\xef\x83\x87", // U+f0c7 - "FlorinSign": "\xee\x86\x84", // U+e184 - "Folder": "\xef\x81\xbb", // U+f07b - "FolderClosed": "\xee\x86\x85", // U+e185 - "FolderMinus": "\xef\x99\x9d", // U+f65d - "FolderOpen": "\xef\x81\xbc", // U+f07c - "FolderPlus": "\xef\x99\x9e", // U+f65e - "FolderTree": "\xef\xa0\x82", // U+f802 - "Font": "\xef\x80\xb1", // U+f031 - "FontAwesome": "\xef\x8a\xb4", // U+f2b4 - "Football": "\xef\x91\x8e", // U+f44e - "Forward": "\xef\x81\x8e", // U+f04e - "ForwardFast": "\xef\x81\x90", // U+f050 - "ForwardStep": "\xef\x81\x91", // U+f051 - "FrancSign": "\xee\x86\x8f", // U+e18f - "Frog": "\xef\x94\xae", // U+f52e - "Futbol": "\xef\x87\xa3", // U+f1e3 - "G": "G", // U+0047 - "Gamepad": "\xef\x84\x9b", // U+f11b - "GasPump": "\xef\x94\xaf", // U+f52f - "Gauge": "\xef\x98\xa4", // U+f624 - "GaugeHigh": "\xef\x98\xa5", // U+f625 - "GaugeSimple": "\xef\x98\xa9", // U+f629 - "GaugeSimpleHigh": "\xef\x98\xaa", // U+f62a - "Gavel": "\xef\x83\xa3", // U+f0e3 - "Gear": "\xef\x80\x93", // U+f013 - "Gears": "\xef\x82\x85", // U+f085 - "Gem": "\xef\x8e\xa5", // U+f3a5 - "Gemini": "\xee\xa1\x89", // U+e849 - "Genderless": "\xef\x88\xad", // U+f22d - "Ghost": "\xef\x9b\xa2", // U+f6e2 - "Gift": "\xef\x81\xab", // U+f06b - "Gifts": "\xef\x9e\x9c", // U+f79c - "GlassWater": "\xee\x93\xb4", // U+e4f4 - "GlassWaterDroplet": "\xee\x93\xb5", // U+e4f5 - "Glasses": "\xef\x94\xb0", // U+f530 - "Globe": "\xef\x82\xac", // U+f0ac - "GolfBallTee": "\xef\x91\x90", // U+f450 - "Gopuram": "\xef\x99\xa4", // U+f664 - "GraduationCap": "\xef\x86\x9d", // U+f19d - "GreaterThan": ">", // U+003e - "GreaterThanEqual": "\xef\x94\xb2", // U+f532 - "Grip": "\xef\x96\x8d", // U+f58d - "GripLines": "\xef\x9e\xa4", // U+f7a4 - "GripLinesVertical": "\xef\x9e\xa5", // U+f7a5 - "GripVertical": "\xef\x96\x8e", // U+f58e - "GroupArrowsRotate": "\xee\x93\xb6", // U+e4f6 - "GuaraniSign": "\xee\x86\x9a", // U+e19a - "Guitar": "\xef\x9e\xa6", // U+f7a6 - "Gun": "\xee\x86\x9b", // U+e19b - "H": "H", // U+0048 - "Hammer": "\xef\x9b\xa3", // U+f6e3 - "Hamsa": "\xef\x99\xa5", // U+f665 - "Hand": "\xef\x89\x96", // U+f256 - "HandBackFist": "\xef\x89\x95", // U+f255 - "HandDots": "\xef\x91\xa1", // U+f461 - "HandFist": "\xef\x9b\x9e", // U+f6de - "HandHolding": "\xef\x92\xbd", // U+f4bd - "HandHoldingDollar": "\xef\x93\x80", // U+f4c0 - "HandHoldingDroplet": "\xef\x93\x81", // U+f4c1 - "HandHoldingHand": "\xee\x93\xb7", // U+e4f7 - "HandHoldingHeart": "\xef\x92\xbe", // U+f4be - "HandHoldingMedical": "\xee\x81\x9c", // U+e05c - "HandLizard": "\xef\x89\x98", // U+f258 - "HandMiddleFinger": "\xef\xa0\x86", // U+f806 - "HandPeace": "\xef\x89\x9b", // U+f25b - "HandPointDown": "\xef\x82\xa7", // U+f0a7 - "HandPointLeft": "\xef\x82\xa5", // U+f0a5 - "HandPointRight": "\xef\x82\xa4", // U+f0a4 - "HandPointUp": "\xef\x82\xa6", // U+f0a6 - "HandPointer": "\xef\x89\x9a", // U+f25a - "HandScissors": "\xef\x89\x97", // U+f257 - "HandSparkles": "\xee\x81\x9d", // U+e05d - "HandSpock": "\xef\x89\x99", // U+f259 - "Handcuffs": "\xee\x93\xb8", // U+e4f8 - "Hands": "\xef\x8a\xa7", // U+f2a7 - "HandsAslInterpreting": "\xef\x8a\xa3", // U+f2a3 - "HandsBound": "\xee\x93\xb9", // U+e4f9 - "HandsBubbles": "\xee\x81\x9e", // U+e05e - "HandsClapping": "\xee\x86\xa8", // U+e1a8 - "HandsHolding": "\xef\x93\x82", // U+f4c2 - "HandsHoldingChild": "\xee\x93\xba", // U+e4fa - "HandsHoldingCircle": "\xee\x93\xbb", // U+e4fb - "HandsPraying": "\xef\x9a\x84", // U+f684 - "Handshake": "\xef\x8a\xb5", // U+f2b5 - "HandshakeAngle": "\xef\x93\x84", // U+f4c4 - "HandshakeSlash": "\xee\x81\xa0", // U+e060 - "Hanukiah": "\xef\x9b\xa6", // U+f6e6 - "HardDrive": "\xef\x82\xa0", // U+f0a0 - "Hashtag": "#", // U+0023 - "HatCowboy": "\xef\xa3\x80", // U+f8c0 - "HatCowboySide": "\xef\xa3\x81", // U+f8c1 - "HatWizard": "\xef\x9b\xa8", // U+f6e8 - "HeadSideCough": "\xee\x81\xa1", // U+e061 - "HeadSideCoughSlash": "\xee\x81\xa2", // U+e062 - "HeadSideMask": "\xee\x81\xa3", // U+e063 - "HeadSideVirus": "\xee\x81\xa4", // U+e064 - "Heading": "\xef\x87\x9c", // U+f1dc - "Headphones": "\xef\x80\xa5", // U+f025 - "Headset": "\xef\x96\x90", // U+f590 - "Heart": "\xef\x80\x84", // U+f004 - "HeartCircleBolt": "\xee\x93\xbc", // U+e4fc - "HeartCircleCheck": "\xee\x93\xbd", // U+e4fd - "HeartCircleExclamation": "\xee\x93\xbe", // U+e4fe - "HeartCircleMinus": "\xee\x93\xbf", // U+e4ff - "HeartCirclePlus": "\xee\x94\x80", // U+e500 - "HeartCircleXmark": "\xee\x94\x81", // U+e501 - "HeartCrack": "\xef\x9e\xa9", // U+f7a9 - "HeartPulse": "\xef\x88\x9e", // U+f21e - "Helicopter": "\xef\x94\xb3", // U+f533 - "HelicopterSymbol": "\xee\x94\x82", // U+e502 - "HelmetSafety": "\xef\xa0\x87", // U+f807 - "HelmetUn": "\xee\x94\x83", // U+e503 - "Hexagon": "\xef\x8c\x92", // U+f312 - "HexagonNodes": "\xee\x9a\x99", // U+e699 - "HexagonNodesBolt": "\xee\x9a\x9a", // U+e69a - "Highlighter": "\xef\x96\x91", // U+f591 - "HillAvalanche": "\xee\x94\x87", // U+e507 - "HillRockslide": "\xee\x94\x88", // U+e508 - "Hippo": "\xef\x9b\xad", // U+f6ed - "HockeyPuck": "\xef\x91\x93", // U+f453 - "HollyBerry": "\xef\x9e\xaa", // U+f7aa - "Horse": "\xef\x9b\xb0", // U+f6f0 - "HorseHead": "\xef\x9e\xab", // U+f7ab - "Hospital": "\xef\x83\xb8", // U+f0f8 - "HospitalUser": "\xef\xa0\x8d", // U+f80d - "HotTubPerson": "\xef\x96\x93", // U+f593 - "Hotdog": "\xef\xa0\x8f", // U+f80f - "Hotel": "\xef\x96\x94", // U+f594 - "Hourglass": "\xef\x89\x94", // U+f254 - "HourglassEnd": "\xef\x89\x93", // U+f253 - "HourglassHalf": "\xef\x89\x92", // U+f252 - "HourglassStart": "\xef\x89\x91", // U+f251 - "House": "\xef\x80\x95", // U+f015 - "HouseChimney": "\xee\x8e\xaf", // U+e3af - "HouseChimneyCrack": "\xef\x9b\xb1", // U+f6f1 - "HouseChimneyMedical": "\xef\x9f\xb2", // U+f7f2 - "HouseChimneyUser": "\xee\x81\xa5", // U+e065 - "HouseChimneyWindow": "\xee\x80\x8d", // U+e00d - "HouseCircleCheck": "\xee\x94\x89", // U+e509 - "HouseCircleExclamation": "\xee\x94\x8a", // U+e50a - "HouseCircleXmark": "\xee\x94\x8b", // U+e50b - "HouseCrack": "\xee\x8e\xb1", // U+e3b1 - "HouseFire": "\xee\x94\x8c", // U+e50c - "HouseFlag": "\xee\x94\x8d", // U+e50d - "HouseFloodWater": "\xee\x94\x8e", // U+e50e - "HouseFloodWaterCircleArrowRight": "\xee\x94\x8f", // U+e50f - "HouseLaptop": "\xee\x81\xa6", // U+e066 - "HouseLock": "\xee\x94\x90", // U+e510 - "HouseMedical": "\xee\x8e\xb2", // U+e3b2 - "HouseMedicalCircleCheck": "\xee\x94\x91", // U+e511 - "HouseMedicalCircleExclamation": "\xee\x94\x92", // U+e512 - "HouseMedicalCircleXmark": "\xee\x94\x93", // U+e513 - "HouseMedicalFlag": "\xee\x94\x94", // U+e514 - "HouseSignal": "\xee\x80\x92", // U+e012 - "HouseTsunami": "\xee\x94\x95", // U+e515 - "HouseUser": "\xee\x86\xb0", // U+e1b0 - "HryvniaSign": "\xef\x9b\xb2", // U+f6f2 - "Hurricane": "\xef\x9d\x91", // U+f751 - "I": "I", // U+0049 - "ICursor": "\xef\x89\x86", // U+f246 - "IceCream": "\xef\xa0\x90", // U+f810 - "Icicles": "\xef\x9e\xad", // U+f7ad - "Icons": "\xef\xa1\xad", // U+f86d - "IdBadge": "\xef\x8b\x81", // U+f2c1 - "IdCard": "\xef\x8b\x82", // U+f2c2 - "IdCardClip": "\xef\x91\xbf", // U+f47f - "Igloo": "\xef\x9e\xae", // U+f7ae - "Image": "\xef\x80\xbe", // U+f03e - "ImagePortrait": "\xef\x8f\xa0", // U+f3e0 - "Images": "\xef\x8c\x82", // U+f302 - "Inbox": "\xef\x80\x9c", // U+f01c - "Indent": "\xef\x80\xbc", // U+f03c - "IndianRupeeSign": "\xee\x86\xbc", // U+e1bc - "Industry": "\xef\x89\xb5", // U+f275 - "Infinity": "\xef\x94\xb4", // U+f534 - "Info": "\xef\x84\xa9", // U+f129 - "Italic": "\xef\x80\xb3", // U+f033 - "J": "J", // U+004a - "Jar": "\xee\x94\x96", // U+e516 - "JarWheat": "\xee\x94\x97", // U+e517 - "Jedi": "\xef\x99\xa9", // U+f669 - "JetFighter": "\xef\x83\xbb", // U+f0fb - "JetFighterUp": "\xee\x94\x98", // U+e518 - "Joint": "\xef\x96\x95", // U+f595 - "JugDetergent": "\xee\x94\x99", // U+e519 - "K": "K", // U+004b - "Kaaba": "\xef\x99\xab", // U+f66b - "Key": "\xef\x82\x84", // U+f084 - "Keyboard": "\xef\x84\x9c", // U+f11c - "Khanda": "\xef\x99\xad", // U+f66d - "KipSign": "\xee\x87\x84", // U+e1c4 - "KitMedical": "\xef\x91\xb9", // U+f479 - "KitchenSet": "\xee\x94\x9a", // U+e51a - "KiwiBird": "\xef\x94\xb5", // U+f535 - "L": "L", // U+004c - "LandMineOn": "\xee\x94\x9b", // U+e51b - "Landmark": "\xef\x99\xaf", // U+f66f - "LandmarkDome": "\xef\x9d\x92", // U+f752 - "LandmarkFlag": "\xee\x94\x9c", // U+e51c - "Language": "\xef\x86\xab", // U+f1ab - "Laptop": "\xef\x84\x89", // U+f109 - "LaptopCode": "\xef\x97\xbc", // U+f5fc - "LaptopFile": "\xee\x94\x9d", // U+e51d - "LaptopMedical": "\xef\xa0\x92", // U+f812 - "LariSign": "\xee\x87\x88", // U+e1c8 - "LayerGroup": "\xef\x97\xbd", // U+f5fd - "Leaf": "\xef\x81\xac", // U+f06c - "LeftLong": "\xef\x8c\x8a", // U+f30a - "LeftRight": "\xef\x8c\xb7", // U+f337 - "Lemon": "\xef\x82\x94", // U+f094 - "Leo": "\xee\xa1\x8a", // U+e84a - "LessThan": "<", // U+003c - "LessThanEqual": "\xef\x94\xb7", // U+f537 - "Libra": "\xee\xa1\x8b", // U+e84b - "LifeRing": "\xef\x87\x8d", // U+f1cd - "Lightbulb": "\xef\x83\xab", // U+f0eb - "LinesLeaning": "\xee\x94\x9e", // U+e51e - "Link": "\xef\x83\x81", // U+f0c1 - "LinkSlash": "\xef\x84\xa7", // U+f127 - "LiraSign": "\xef\x86\x95", // U+f195 - "List": "\xef\x80\xba", // U+f03a - "ListCheck": "\xef\x82\xae", // U+f0ae - "ListOl": "\xef\x83\x8b", // U+f0cb - "ListUl": "\xef\x83\x8a", // U+f0ca - "LitecoinSign": "\xee\x87\x93", // U+e1d3 - "LocationArrow": "\xef\x84\xa4", // U+f124 - "LocationCrosshairs": "\xef\x98\x81", // U+f601 - "LocationDot": "\xef\x8f\x85", // U+f3c5 - "LocationPin": "\xef\x81\x81", // U+f041 - "LocationPinLock": "\xee\x94\x9f", // U+e51f - "Lock": "\xef\x80\xa3", // U+f023 - "LockOpen": "\xef\x8f\x81", // U+f3c1 - "Locust": "\xee\x94\xa0", // U+e520 - "Lungs": "\xef\x98\x84", // U+f604 - "LungsVirus": "\xee\x81\xa7", // U+e067 - "M": "M", // U+004d - "Magnet": "\xef\x81\xb6", // U+f076 - "MagnifyingGlass": "\xef\x80\x82", // U+f002 - "MagnifyingGlassArrowRight": "\xee\x94\xa1", // U+e521 - "MagnifyingGlassChart": "\xee\x94\xa2", // U+e522 - "MagnifyingGlassDollar": "\xef\x9a\x88", // U+f688 - "MagnifyingGlassLocation": "\xef\x9a\x89", // U+f689 - "MagnifyingGlassMinus": "\xef\x80\x90", // U+f010 - "MagnifyingGlassPlus": "\xef\x80\x8e", // U+f00e - "ManatSign": "\xee\x87\x95", // U+e1d5 - "Map": "\xef\x89\xb9", // U+f279 - "MapLocation": "\xef\x96\x9f", // U+f59f - "MapLocationDot": "\xef\x96\xa0", // U+f5a0 - "MapPin": "\xef\x89\xb6", // U+f276 - "Marker": "\xef\x96\xa1", // U+f5a1 - "Mars": "\xef\x88\xa2", // U+f222 - "MarsAndVenus": "\xef\x88\xa4", // U+f224 - "MarsAndVenusBurst": "\xee\x94\xa3", // U+e523 - "MarsDouble": "\xef\x88\xa7", // U+f227 - "MarsStroke": "\xef\x88\xa9", // U+f229 - "MarsStrokeRight": "\xef\x88\xab", // U+f22b - "MarsStrokeUp": "\xef\x88\xaa", // U+f22a - "MartiniGlass": "\xef\x95\xbb", // U+f57b - "MartiniGlassCitrus": "\xef\x95\xa1", // U+f561 - "MartiniGlassEmpty": "\xef\x80\x80", // U+f000 - "Mask": "\xef\x9b\xba", // U+f6fa - "MaskFace": "\xee\x87\x97", // U+e1d7 - "MaskVentilator": "\xee\x94\xa4", // U+e524 - "MasksTheater": "\xef\x98\xb0", // U+f630 - "MattressPillow": "\xee\x94\xa5", // U+e525 - "Maximize": "\xef\x8c\x9e", // U+f31e - "Medal": "\xef\x96\xa2", // U+f5a2 - "Memory": "\xef\x94\xb8", // U+f538 - "Menorah": "\xef\x99\xb6", // U+f676 - "Mercury": "\xef\x88\xa3", // U+f223 - "Message": "\xef\x89\xba", // U+f27a - "Meteor": "\xef\x9d\x93", // U+f753 - "Microchip": "\xef\x8b\x9b", // U+f2db - "Microphone": "\xef\x84\xb0", // U+f130 - "MicrophoneLines": "\xef\x8f\x89", // U+f3c9 - "MicrophoneLinesSlash": "\xef\x94\xb9", // U+f539 - "MicrophoneSlash": "\xef\x84\xb1", // U+f131 - "Microscope": "\xef\x98\x90", // U+f610 - "MillSign": "\xee\x87\xad", // U+e1ed - "Minimize": "\xef\x9e\x8c", // U+f78c - "Minus": "\xef\x81\xa8", // U+f068 - "Mitten": "\xef\x9e\xb5", // U+f7b5 - "Mobile": "\xef\x8f\x8e", // U+f3ce - "MobileButton": "\xef\x84\x8b", // U+f10b - "MobileRetro": "\xee\x94\xa7", // U+e527 - "MobileScreen": "\xef\x8f\x8f", // U+f3cf - "MobileScreenButton": "\xef\x8f\x8d", // U+f3cd - "MobileVibrate": "\xee\xa0\x96", // U+e816 - "MoneyBill": "\xef\x83\x96", // U+f0d6 - "MoneyBill1": "\xef\x8f\x91", // U+f3d1 - "MoneyBill1Wave": "\xef\x94\xbb", // U+f53b - "MoneyBillTransfer": "\xee\x94\xa8", // U+e528 - "MoneyBillTrendUp": "\xee\x94\xa9", // U+e529 - "MoneyBillWave": "\xef\x94\xba", // U+f53a - "MoneyBillWheat": "\xee\x94\xaa", // U+e52a - "MoneyBills": "\xee\x87\xb3", // U+e1f3 - "MoneyCheck": "\xef\x94\xbc", // U+f53c - "MoneyCheckDollar": "\xef\x94\xbd", // U+f53d - "Monument": "\xef\x96\xa6", // U+f5a6 - "Moon": "\xef\x86\x86", // U+f186 - "MortarPestle": "\xef\x96\xa7", // U+f5a7 - "Mosque": "\xef\x99\xb8", // U+f678 - "Mosquito": "\xee\x94\xab", // U+e52b - "MosquitoNet": "\xee\x94\xac", // U+e52c - "Motorcycle": "\xef\x88\x9c", // U+f21c - "Mound": "\xee\x94\xad", // U+e52d - "Mountain": "\xef\x9b\xbc", // U+f6fc - "MountainCity": "\xee\x94\xae", // U+e52e - "MountainSun": "\xee\x94\xaf", // U+e52f - "MugHot": "\xef\x9e\xb6", // U+f7b6 - "MugSaucer": "\xef\x83\xb4", // U+f0f4 - "Music": "\xef\x80\x81", // U+f001 - "N": "N", // U+004e - "NairaSign": "\xee\x87\xb6", // U+e1f6 - "NetworkWired": "\xef\x9b\xbf", // U+f6ff - "Neuter": "\xef\x88\xac", // U+f22c - "Newspaper": "\xef\x87\xaa", // U+f1ea - "NonBinary": "\xee\xa0\x87", // U+e807 - "NotEqual": "\xef\x94\xbe", // U+f53e - "Notdef": "\xee\x87\xbe", // U+e1fe - "NoteSticky": "\xef\x89\x89", // U+f249 - "NotesMedical": "\xef\x92\x81", // U+f481 - "O": "O", // U+004f - "ObjectGroup": "\xef\x89\x87", // U+f247 - "ObjectUngroup": "\xef\x89\x88", // U+f248 - "Octagon": "\xef\x8c\x86", // U+f306 - "OilCan": "\xef\x98\x93", // U+f613 - "OilWell": "\xee\x94\xb2", // U+e532 - "Om": "\xef\x99\xb9", // U+f679 - "Otter": "\xef\x9c\x80", // U+f700 - "Outdent": "\xef\x80\xbb", // U+f03b - "P": "P", // U+0050 - "Pager": "\xef\xa0\x95", // U+f815 - "PaintRoller": "\xef\x96\xaa", // U+f5aa - "Paintbrush": "\xef\x87\xbc", // U+f1fc - "Palette": "\xef\x94\xbf", // U+f53f - "Pallet": "\xef\x92\x82", // U+f482 - "Panorama": "\xee\x88\x89", // U+e209 - "PaperPlane": "\xef\x87\x98", // U+f1d8 - "Paperclip": "\xef\x83\x86", // U+f0c6 - "ParachuteBox": "\xef\x93\x8d", // U+f4cd - "Paragraph": "\xef\x87\x9d", // U+f1dd - "Passport": "\xef\x96\xab", // U+f5ab - "Paste": "\xef\x83\xaa", // U+f0ea - "Pause": "\xef\x81\x8c", // U+f04c - "Paw": "\xef\x86\xb0", // U+f1b0 - "Peace": "\xef\x99\xbc", // U+f67c - "Pen": "\xef\x8c\x84", // U+f304 - "PenClip": "\xef\x8c\x85", // U+f305 - "PenFancy": "\xef\x96\xac", // U+f5ac - "PenNib": "\xef\x96\xad", // U+f5ad - "PenRuler": "\xef\x96\xae", // U+f5ae - "PenToSquare": "\xef\x81\x84", // U+f044 - "Pencil": "\xef\x8c\x83", // U+f303 - "Pentagon": "\xee\x9e\x90", // U+e790 - "PeopleArrows": "\xee\x81\xa8", // U+e068 - "PeopleCarryBox": "\xef\x93\x8e", // U+f4ce - "PeopleGroup": "\xee\x94\xb3", // U+e533 - "PeopleLine": "\xee\x94\xb4", // U+e534 - "PeoplePulling": "\xee\x94\xb5", // U+e535 - "PeopleRobbery": "\xee\x94\xb6", // U+e536 - "PeopleRoof": "\xee\x94\xb7", // U+e537 - "PepperHot": "\xef\xa0\x96", // U+f816 - "Percent": "%", // U+0025 - "Person": "\xef\x86\x83", // U+f183 - "PersonArrowDownToLine": "\xee\x94\xb8", // U+e538 - "PersonArrowUpFromLine": "\xee\x94\xb9", // U+e539 - "PersonBiking": "\xef\xa1\x8a", // U+f84a - "PersonBooth": "\xef\x9d\x96", // U+f756 - "PersonBreastfeeding": "\xee\x94\xba", // U+e53a - "PersonBurst": "\xee\x94\xbb", // U+e53b - "PersonCane": "\xee\x94\xbc", // U+e53c - "PersonChalkboard": "\xee\x94\xbd", // U+e53d - "PersonCircleCheck": "\xee\x94\xbe", // U+e53e - "PersonCircleExclamation": "\xee\x94\xbf", // U+e53f - "PersonCircleMinus": "\xee\x95\x80", // U+e540 - "PersonCirclePlus": "\xee\x95\x81", // U+e541 - "PersonCircleQuestion": "\xee\x95\x82", // U+e542 - "PersonCircleXmark": "\xee\x95\x83", // U+e543 - "PersonDigging": "\xef\xa1\x9e", // U+f85e - "PersonDotsFromLine": "\xef\x91\xb0", // U+f470 - "PersonDress": "\xef\x86\x82", // U+f182 - "PersonDressBurst": "\xee\x95\x84", // U+e544 - "PersonDrowning": "\xee\x95\x85", // U+e545 - "PersonFalling": "\xee\x95\x86", // U+e546 - "PersonFallingBurst": "\xee\x95\x87", // U+e547 - "PersonHalfDress": "\xee\x95\x88", // U+e548 - "PersonHarassing": "\xee\x95\x89", // U+e549 - "PersonHiking": "\xef\x9b\xac", // U+f6ec - "PersonMilitaryPointing": "\xee\x95\x8a", // U+e54a - "PersonMilitaryRifle": "\xee\x95\x8b", // U+e54b - "PersonMilitaryToPerson": "\xee\x95\x8c", // U+e54c - "PersonPraying": "\xef\x9a\x83", // U+f683 - "PersonPregnant": "\xee\x8c\x9e", // U+e31e - "PersonRays": "\xee\x95\x8d", // U+e54d - "PersonRifle": "\xee\x95\x8e", // U+e54e - "PersonRunning": "\xef\x9c\x8c", // U+f70c - "PersonShelter": "\xee\x95\x8f", // U+e54f - "PersonSkating": "\xef\x9f\x85", // U+f7c5 - "PersonSkiing": "\xef\x9f\x89", // U+f7c9 - "PersonSkiingNordic": "\xef\x9f\x8a", // U+f7ca - "PersonSnowboarding": "\xef\x9f\x8e", // U+f7ce - "PersonSwimming": "\xef\x97\x84", // U+f5c4 - "PersonThroughWindow": "\xee\x96\xa9", // U+e5a9 - "PersonWalking": "\xef\x95\x94", // U+f554 - "PersonWalkingArrowLoopLeft": "\xee\x95\x91", // U+e551 - "PersonWalkingArrowRight": "\xee\x95\x92", // U+e552 - "PersonWalkingDashedLineArrowRight": "\xee\x95\x93", // U+e553 - "PersonWalkingLuggage": "\xee\x95\x94", // U+e554 - "PersonWalkingWithCane": "\xef\x8a\x9d", // U+f29d - "PesetaSign": "\xee\x88\xa1", // U+e221 - "PesoSign": "\xee\x88\xa2", // U+e222 - "Phone": "\xef\x82\x95", // U+f095 - "PhoneFlip": "\xef\xa1\xb9", // U+f879 - "PhoneSlash": "\xef\x8f\x9d", // U+f3dd - "PhoneVolume": "\xef\x8a\xa0", // U+f2a0 - "PhotoFilm": "\xef\xa1\xbc", // U+f87c - "PictureInPicture": "\xee\xa0\x8b", // U+e80b - "PiggyBank": "\xef\x93\x93", // U+f4d3 - "Pills": "\xef\x92\x84", // U+f484 - "Pisces": "\xee\xa1\x8c", // U+e84c - "PizzaSlice": "\xef\xa0\x98", // U+f818 - "PlaceOfWorship": "\xef\x99\xbf", // U+f67f - "Plane": "\xef\x81\xb2", // U+f072 - "PlaneArrival": "\xef\x96\xaf", // U+f5af - "PlaneCircleCheck": "\xee\x95\x95", // U+e555 - "PlaneCircleExclamation": "\xee\x95\x96", // U+e556 - "PlaneCircleXmark": "\xee\x95\x97", // U+e557 - "PlaneDeparture": "\xef\x96\xb0", // U+f5b0 - "PlaneLock": "\xee\x95\x98", // U+e558 - "PlaneSlash": "\xee\x81\xa9", // U+e069 - "PlaneUp": "\xee\x88\xad", // U+e22d - "PlantWilt": "\xee\x96\xaa", // U+e5aa - "PlateWheat": "\xee\x95\x9a", // U+e55a - "Play": "\xef\x81\x8b", // U+f04b - "Plug": "\xef\x87\xa6", // U+f1e6 - "PlugCircleBolt": "\xee\x95\x9b", // U+e55b - "PlugCircleCheck": "\xee\x95\x9c", // U+e55c - "PlugCircleExclamation": "\xee\x95\x9d", // U+e55d - "PlugCircleMinus": "\xee\x95\x9e", // U+e55e - "PlugCirclePlus": "\xee\x95\x9f", // U+e55f - "PlugCircleXmark": "\xee\x95\xa0", // U+e560 - "Plus": "+", // U+002b - "PlusMinus": "\xee\x90\xbc", // U+e43c - "Podcast": "\xef\x8b\x8e", // U+f2ce - "Poo": "\xef\x8b\xbe", // U+f2fe - "PooStorm": "\xef\x9d\x9a", // U+f75a - "Poop": "\xef\x98\x99", // U+f619 - "PowerOff": "\xef\x80\x91", // U+f011 - "Prescription": "\xef\x96\xb1", // U+f5b1 - "PrescriptionBottle": "\xef\x92\x85", // U+f485 - "PrescriptionBottleMedical": "\xef\x92\x86", // U+f486 - "Print": "\xef\x80\xaf", // U+f02f - "PumpMedical": "\xee\x81\xaa", // U+e06a - "PumpSoap": "\xee\x81\xab", // U+e06b - "PuzzlePiece": "\xef\x84\xae", // U+f12e - "Q": "Q", // U+0051 - "Qrcode": "\xef\x80\xa9", // U+f029 - "Question": "?", // U+003f - "QuoteLeft": "\xef\x84\x8d", // U+f10d - "QuoteRight": "\xef\x84\x8e", // U+f10e - "R": "R", // U+0052 - "Radiation": "\xef\x9e\xb9", // U+f7b9 - "Radio": "\xef\xa3\x97", // U+f8d7 - "Rainbow": "\xef\x9d\x9b", // U+f75b - "RankingStar": "\xee\x95\xa1", // U+e561 - "Receipt": "\xef\x95\x83", // U+f543 - "RecordVinyl": "\xef\xa3\x99", // U+f8d9 - "RectangleAd": "\xef\x99\x81", // U+f641 - "RectangleList": "\xef\x80\xa2", // U+f022 - "RectangleXmark": "\xef\x90\x90", // U+f410 - "Recycle": "\xef\x86\xb8", // U+f1b8 - "Registered": "\xef\x89\x9d", // U+f25d - "Repeat": "\xef\x8d\xa3", // U+f363 - "Reply": "\xef\x8f\xa5", // U+f3e5 - "ReplyAll": "\xef\x84\xa2", // U+f122 - "Republican": "\xef\x9d\x9e", // U+f75e - "Restroom": "\xef\x9e\xbd", // U+f7bd - "Retweet": "\xef\x81\xb9", // U+f079 - "Ribbon": "\xef\x93\x96", // U+f4d6 - "RightFromBracket": "\xef\x8b\xb5", // U+f2f5 - "RightLeft": "\xef\x8d\xa2", // U+f362 - "RightLong": "\xef\x8c\x8b", // U+f30b - "RightToBracket": "\xef\x8b\xb6", // U+f2f6 - "Ring": "\xef\x9c\x8b", // U+f70b - "Road": "\xef\x80\x98", // U+f018 - "RoadBarrier": "\xee\x95\xa2", // U+e562 - "RoadBridge": "\xee\x95\xa3", // U+e563 - "RoadCircleCheck": "\xee\x95\xa4", // U+e564 - "RoadCircleExclamation": "\xee\x95\xa5", // U+e565 - "RoadCircleXmark": "\xee\x95\xa6", // U+e566 - "RoadLock": "\xee\x95\xa7", // U+e567 - "RoadSpikes": "\xee\x95\xa8", // U+e568 - "Robot": "\xef\x95\x84", // U+f544 - "Rocket": "\xef\x84\xb5", // U+f135 - "Rotate": "\xef\x8b\xb1", // U+f2f1 - "RotateLeft": "\xef\x8b\xaa", // U+f2ea - "RotateRight": "\xef\x8b\xb9", // U+f2f9 - "Route": "\xef\x93\x97", // U+f4d7 - "Rss": "\xef\x82\x9e", // U+f09e - "RubleSign": "\xef\x85\x98", // U+f158 - "Rug": "\xee\x95\xa9", // U+e569 - "Ruler": "\xef\x95\x85", // U+f545 - "RulerCombined": "\xef\x95\x86", // U+f546 - "RulerHorizontal": "\xef\x95\x87", // U+f547 - "RulerVertical": "\xef\x95\x88", // U+f548 - "RupeeSign": "\xef\x85\x96", // U+f156 - "RupiahSign": "\xee\x88\xbd", // U+e23d - "S": "S", // U+0053 - "SackDollar": "\xef\xa0\x9d", // U+f81d - "SackXmark": "\xee\x95\xaa", // U+e56a - "Sagittarius": "\xee\xa1\x8d", // U+e84d - "Sailboat": "\xee\x91\x85", // U+e445 - "Satellite": "\xef\x9e\xbf", // U+f7bf - "SatelliteDish": "\xef\x9f\x80", // U+f7c0 - "ScaleBalanced": "\xef\x89\x8e", // U+f24e - "ScaleUnbalanced": "\xef\x94\x95", // U+f515 - "ScaleUnbalancedFlip": "\xef\x94\x96", // U+f516 - "School": "\xef\x95\x89", // U+f549 - "SchoolCircleCheck": "\xee\x95\xab", // U+e56b - "SchoolCircleExclamation": "\xee\x95\xac", // U+e56c - "SchoolCircleXmark": "\xee\x95\xad", // U+e56d - "SchoolFlag": "\xee\x95\xae", // U+e56e - "SchoolLock": "\xee\x95\xaf", // U+e56f - "Scissors": "\xef\x83\x84", // U+f0c4 - "Scorpio": "\xee\xa1\x8e", // U+e84e - "Screwdriver": "\xef\x95\x8a", // U+f54a - "ScrewdriverWrench": "\xef\x9f\x99", // U+f7d9 - "Scroll": "\xef\x9c\x8e", // U+f70e - "ScrollTorah": "\xef\x9a\xa0", // U+f6a0 - "SdCard": "\xef\x9f\x82", // U+f7c2 - "Section": "\xee\x91\x87", // U+e447 - "Seedling": "\xef\x93\x98", // U+f4d8 - "Septagon": "\xee\xa0\xa0", // U+e820 - "Server": "\xef\x88\xb3", // U+f233 - "Shapes": "\xef\x98\x9f", // U+f61f - "Share": "\xef\x81\xa4", // U+f064 - "ShareFromSquare": "\xef\x85\x8d", // U+f14d - "ShareNodes": "\xef\x87\xa0", // U+f1e0 - "SheetPlastic": "\xee\x95\xb1", // U+e571 - "ShekelSign": "\xef\x88\x8b", // U+f20b - "Shield": "\xef\x84\xb2", // U+f132 - "ShieldCat": "\xee\x95\xb2", // U+e572 - "ShieldDog": "\xee\x95\xb3", // U+e573 - "ShieldHalved": "\xef\x8f\xad", // U+f3ed - "ShieldHeart": "\xee\x95\xb4", // U+e574 - "ShieldVirus": "\xee\x81\xac", // U+e06c - "Ship": "\xef\x88\x9a", // U+f21a - "Shirt": "\xef\x95\x93", // U+f553 - "ShoePrints": "\xef\x95\x8b", // U+f54b - "Shop": "\xef\x95\x8f", // U+f54f - "ShopLock": "\xee\x92\xa5", // U+e4a5 - "ShopSlash": "\xee\x81\xb0", // U+e070 - "Shower": "\xef\x8b\x8c", // U+f2cc - "Shrimp": "\xee\x91\x88", // U+e448 - "Shuffle": "\xef\x81\xb4", // U+f074 - "ShuttleSpace": "\xef\x86\x97", // U+f197 - "SignHanging": "\xef\x93\x99", // U+f4d9 - "Signal": "\xef\x80\x92", // U+f012 - "Signature": "\xef\x96\xb7", // U+f5b7 - "SignsPost": "\xef\x89\xb7", // U+f277 - "SimCard": "\xef\x9f\x84", // U+f7c4 - "SingleQuoteLeft": "\xee\xa0\x9b", // U+e81b - "SingleQuoteRight": "\xee\xa0\x9c", // U+e81c - "Sink": "\xee\x81\xad", // U+e06d - "Sitemap": "\xef\x83\xa8", // U+f0e8 - "Skull": "\xef\x95\x8c", // U+f54c - "SkullCrossbones": "\xef\x9c\x94", // U+f714 - "Slash": "\xef\x9c\x95", // U+f715 - "Sleigh": "\xef\x9f\x8c", // U+f7cc - "Sliders": "\xef\x87\x9e", // U+f1de - "Smog": "\xef\x9d\x9f", // U+f75f - "Smoking": "\xef\x92\x8d", // U+f48d - "Snowflake": "\xef\x8b\x9c", // U+f2dc - "Snowman": "\xef\x9f\x90", // U+f7d0 - "Snowplow": "\xef\x9f\x92", // U+f7d2 - "Soap": "\xee\x81\xae", // U+e06e - "Socks": "\xef\x9a\x96", // U+f696 - "SolarPanel": "\xef\x96\xba", // U+f5ba - "Sort": "\xef\x83\x9c", // U+f0dc - "SortDown": "\xef\x83\x9d", // U+f0dd - "SortUp": "\xef\x83\x9e", // U+f0de - "Spa": "\xef\x96\xbb", // U+f5bb - "SpaghettiMonsterFlying": "\xef\x99\xbb", // U+f67b - "SpellCheck": "\xef\xa2\x91", // U+f891 - "Spider": "\xef\x9c\x97", // U+f717 - "Spinner": "\xef\x84\x90", // U+f110 - "Spiral": "\xee\xa0\x8a", // U+e80a - "Splotch": "\xef\x96\xbc", // U+f5bc - "Spoon": "\xef\x8b\xa5", // U+f2e5 - "SprayCan": "\xef\x96\xbd", // U+f5bd - "SprayCanSparkles": "\xef\x97\x90", // U+f5d0 - "Square": "\xef\x83\x88", // U+f0c8 - "SquareArrowUpRight": "\xef\x85\x8c", // U+f14c - "SquareBinary": "\xee\x9a\x9b", // U+e69b - "SquareCaretDown": "\xef\x85\x90", // U+f150 - "SquareCaretLeft": "\xef\x86\x91", // U+f191 - "SquareCaretRight": "\xef\x85\x92", // U+f152 - "SquareCaretUp": "\xef\x85\x91", // U+f151 - "SquareCheck": "\xef\x85\x8a", // U+f14a - "SquareEnvelope": "\xef\x86\x99", // U+f199 - "SquareFull": "\xef\x91\x9c", // U+f45c - "SquareH": "\xef\x83\xbd", // U+f0fd - "SquareMinus": "\xef\x85\x86", // U+f146 - "SquareNfi": "\xee\x95\xb6", // U+e576 - "SquareParking": "\xef\x95\x80", // U+f540 - "SquarePen": "\xef\x85\x8b", // U+f14b - "SquarePersonConfined": "\xee\x95\xb7", // U+e577 - "SquarePhone": "\xef\x82\x98", // U+f098 - "SquarePhoneFlip": "\xef\xa1\xbb", // U+f87b - "SquarePlus": "\xef\x83\xbe", // U+f0fe - "SquarePollHorizontal": "\xef\x9a\x82", // U+f682 - "SquarePollVertical": "\xef\x9a\x81", // U+f681 - "SquareRootVariable": "\xef\x9a\x98", // U+f698 - "SquareRss": "\xef\x85\x83", // U+f143 - "SquareShareNodes": "\xef\x87\xa1", // U+f1e1 - "SquareUpRight": "\xef\x8d\xa0", // U+f360 - "SquareVirus": "\xee\x95\xb8", // U+e578 - "SquareXmark": "\xef\x8b\x93", // U+f2d3 - "StaffSnake": "\xee\x95\xb9", // U+e579 - "Stairs": "\xee\x8a\x89", // U+e289 - "Stamp": "\xef\x96\xbf", // U+f5bf - "Stapler": "\xee\x96\xaf", // U+e5af - "Star": "\xef\x80\x85", // U+f005 - "StarAndCrescent": "\xef\x9a\x99", // U+f699 - "StarHalf": "\xef\x82\x89", // U+f089 - "StarHalfStroke": "\xef\x97\x80", // U+f5c0 - "StarOfDavid": "\xef\x9a\x9a", // U+f69a - "StarOfLife": "\xef\x98\xa1", // U+f621 - "SterlingSign": "\xef\x85\x94", // U+f154 - "Stethoscope": "\xef\x83\xb1", // U+f0f1 - "Stop": "\xef\x81\x8d", // U+f04d - "Stopwatch": "\xef\x8b\xb2", // U+f2f2 - "Stopwatch20": "\xee\x81\xaf", // U+e06f - "Store": "\xef\x95\x8e", // U+f54e - "StoreSlash": "\xee\x81\xb1", // U+e071 - "StreetView": "\xef\x88\x9d", // U+f21d - "Strikethrough": "\xef\x83\x8c", // U+f0cc - "Stroopwafel": "\xef\x95\x91", // U+f551 - "Subscript": "\xef\x84\xac", // U+f12c - "Suitcase": "\xef\x83\xb2", // U+f0f2 - "SuitcaseMedical": "\xef\x83\xba", // U+f0fa - "SuitcaseRolling": "\xef\x97\x81", // U+f5c1 - "Sun": "\xef\x86\x85", // U+f185 - "SunPlantWilt": "\xee\x95\xba", // U+e57a - "Superscript": "\xef\x84\xab", // U+f12b - "Swatchbook": "\xef\x97\x83", // U+f5c3 - "Synagogue": "\xef\x9a\x9b", // U+f69b - "Syringe": "\xef\x92\x8e", // U+f48e - "T": "T", // U+0054 - "Table": "\xef\x83\x8e", // U+f0ce - "TableCells": "\xef\x80\x8a", // U+f00a - "TableCellsColumnLock": "\xee\x99\xb8", // U+e678 - "TableCellsLarge": "\xef\x80\x89", // U+f009 - "TableCellsRowLock": "\xee\x99\xba", // U+e67a - "TableCellsRowUnlock": "\xee\x9a\x91", // U+e691 - "TableColumns": "\xef\x83\x9b", // U+f0db - "TableList": "\xef\x80\x8b", // U+f00b - "TableTennisPaddleBall": "\xef\x91\x9d", // U+f45d - "Tablet": "\xef\x8f\xbb", // U+f3fb - "TabletButton": "\xef\x84\x8a", // U+f10a - "TabletScreenButton": "\xef\x8f\xba", // U+f3fa - "Tablets": "\xef\x92\x90", // U+f490 - "TachographDigital": "\xef\x95\xa6", // U+f566 - "Tag": "\xef\x80\xab", // U+f02b - "Tags": "\xef\x80\xac", // U+f02c - "Tape": "\xef\x93\x9b", // U+f4db - "Tarp": "\xee\x95\xbb", // U+e57b - "TarpDroplet": "\xee\x95\xbc", // U+e57c - "Taurus": "\xee\xa1\x8f", // U+e84f - "Taxi": "\xef\x86\xba", // U+f1ba - "Teeth": "\xef\x98\xae", // U+f62e - "TeethOpen": "\xef\x98\xaf", // U+f62f - "TemperatureArrowDown": "\xee\x80\xbf", // U+e03f - "TemperatureArrowUp": "\xee\x81\x80", // U+e040 - "TemperatureEmpty": "\xef\x8b\x8b", // U+f2cb - "TemperatureFull": "\xef\x8b\x87", // U+f2c7 - "TemperatureHalf": "\xef\x8b\x89", // U+f2c9 - "TemperatureHigh": "\xef\x9d\xa9", // U+f769 - "TemperatureLow": "\xef\x9d\xab", // U+f76b - "TemperatureQuarter": "\xef\x8b\x8a", // U+f2ca - "TemperatureThreeQuarters": "\xef\x8b\x88", // U+f2c8 - "TengeSign": "\xef\x9f\x97", // U+f7d7 - "Tent": "\xee\x95\xbd", // U+e57d - "TentArrowDownToLine": "\xee\x95\xbe", // U+e57e - "TentArrowLeftRight": "\xee\x95\xbf", // U+e57f - "TentArrowTurnLeft": "\xee\x96\x80", // U+e580 - "TentArrowsDown": "\xee\x96\x81", // U+e581 - "Tents": "\xee\x96\x82", // U+e582 - "Terminal": "\xef\x84\xa0", // U+f120 - "TextHeight": "\xef\x80\xb4", // U+f034 - "TextSlash": "\xef\xa1\xbd", // U+f87d - "TextWidth": "\xef\x80\xb5", // U+f035 - "Thermometer": "\xef\x92\x91", // U+f491 - "ThumbsDown": "\xef\x85\xa5", // U+f165 - "ThumbsUp": "\xef\x85\xa4", // U+f164 - "Thumbtack": "\xef\x82\x8d", // U+f08d - "ThumbtackSlash": "\xee\x9a\x8f", // U+e68f - "Ticket": "\xef\x85\x85", // U+f145 - "TicketSimple": "\xef\x8f\xbf", // U+f3ff - "Timeline": "\xee\x8a\x9c", // U+e29c - "ToggleOff": "\xef\x88\x84", // U+f204 - "ToggleOn": "\xef\x88\x85", // U+f205 - "Toilet": "\xef\x9f\x98", // U+f7d8 - "ToiletPaper": "\xef\x9c\x9e", // U+f71e - "ToiletPaperSlash": "\xee\x81\xb2", // U+e072 - "ToiletPortable": "\xee\x96\x83", // U+e583 - "ToiletsPortable": "\xee\x96\x84", // U+e584 - "Toolbox": "\xef\x95\x92", // U+f552 - "Tooth": "\xef\x97\x89", // U+f5c9 - "ToriiGate": "\xef\x9a\xa1", // U+f6a1 - "Tornado": "\xef\x9d\xaf", // U+f76f - "TowerBroadcast": "\xef\x94\x99", // U+f519 - "TowerCell": "\xee\x96\x85", // U+e585 - "TowerObservation": "\xee\x96\x86", // U+e586 - "Tractor": "\xef\x9c\xa2", // U+f722 - "Trademark": "\xef\x89\x9c", // U+f25c - "TrafficLight": "\xef\x98\xb7", // U+f637 - "Trailer": "\xee\x81\x81", // U+e041 - "Train": "\xef\x88\xb8", // U+f238 - "TrainSubway": "\xef\x88\xb9", // U+f239 - "TrainTram": "\xee\x96\xb4", // U+e5b4 - "Transgender": "\xef\x88\xa5", // U+f225 - "Trash": "\xef\x87\xb8", // U+f1f8 - "TrashArrowUp": "\xef\xa0\xa9", // U+f829 - "TrashCan": "\xef\x8b\xad", // U+f2ed - "TrashCanArrowUp": "\xef\xa0\xaa", // U+f82a - "Tree": "\xef\x86\xbb", // U+f1bb - "TreeCity": "\xee\x96\x87", // U+e587 - "TriangleExclamation": "\xef\x81\xb1", // U+f071 - "Trophy": "\xef\x82\x91", // U+f091 - "Trowel": "\xee\x96\x89", // U+e589 - "TrowelBricks": "\xee\x96\x8a", // U+e58a - "Truck": "\xef\x83\x91", // U+f0d1 - "TruckArrowRight": "\xee\x96\x8b", // U+e58b - "TruckDroplet": "\xee\x96\x8c", // U+e58c - "TruckFast": "\xef\x92\x8b", // U+f48b - "TruckField": "\xee\x96\x8d", // U+e58d - "TruckFieldUn": "\xee\x96\x8e", // U+e58e - "TruckFront": "\xee\x8a\xb7", // U+e2b7 - "TruckMedical": "\xef\x83\xb9", // U+f0f9 - "TruckMonster": "\xef\x98\xbb", // U+f63b - "TruckMoving": "\xef\x93\x9f", // U+f4df - "TruckPickup": "\xef\x98\xbc", // U+f63c - "TruckPlane": "\xee\x96\x8f", // U+e58f - "TruckRampBox": "\xef\x93\x9e", // U+f4de - "Tty": "\xef\x87\xa4", // U+f1e4 - "TurkishLiraSign": "\xee\x8a\xbb", // U+e2bb - "TurnDown": "\xef\x8e\xbe", // U+f3be - "TurnUp": "\xef\x8e\xbf", // U+f3bf - "Tv": "\xef\x89\xac", // U+f26c - "U": "U", // U+0055 - "Umbrella": "\xef\x83\xa9", // U+f0e9 - "UmbrellaBeach": "\xef\x97\x8a", // U+f5ca - "Underline": "\xef\x83\x8d", // U+f0cd - "UniversalAccess": "\xef\x8a\x9a", // U+f29a - "Unlock": "\xef\x82\x9c", // U+f09c - "UnlockKeyhole": "\xef\x84\xbe", // U+f13e - "UpDown": "\xef\x8c\xb8", // U+f338 - "UpDownLeftRight": "\xef\x82\xb2", // U+f0b2 - "UpLong": "\xef\x8c\x8c", // U+f30c - "UpRightAndDownLeftFromCenter": "\xef\x90\xa4", // U+f424 - "UpRightFromSquare": "\xef\x8d\x9d", // U+f35d - "Upload": "\xef\x82\x93", // U+f093 - "User": "\xef\x80\x87", // U+f007 - "UserAstronaut": "\xef\x93\xbb", // U+f4fb - "UserCheck": "\xef\x93\xbc", // U+f4fc - "UserClock": "\xef\x93\xbd", // U+f4fd - "UserDoctor": "\xef\x83\xb0", // U+f0f0 - "UserGear": "\xef\x93\xbe", // U+f4fe - "UserGraduate": "\xef\x94\x81", // U+f501 - "UserGroup": "\xef\x94\x80", // U+f500 - "UserInjured": "\xef\x9c\xa8", // U+f728 - "UserLock": "\xef\x94\x82", // U+f502 - "UserMinus": "\xef\x94\x83", // U+f503 - "UserNinja": "\xef\x94\x84", // U+f504 - "UserNurse": "\xef\xa0\xaf", // U+f82f - "UserPen": "\xef\x93\xbf", // U+f4ff - "UserPlus": "\xef\x88\xb4", // U+f234 - "UserSecret": "\xef\x88\x9b", // U+f21b - "UserShield": "\xef\x94\x85", // U+f505 - "UserSlash": "\xef\x94\x86", // U+f506 - "UserTag": "\xef\x94\x87", // U+f507 - "UserTie": "\xef\x94\x88", // U+f508 - "UserXmark": "\xef\x88\xb5", // U+f235 - "Users": "\xef\x83\x80", // U+f0c0 - "UsersBetweenLines": "\xee\x96\x91", // U+e591 - "UsersGear": "\xef\x94\x89", // U+f509 - "UsersLine": "\xee\x96\x92", // U+e592 - "UsersRays": "\xee\x96\x93", // U+e593 - "UsersRectangle": "\xee\x96\x94", // U+e594 - "UsersSlash": "\xee\x81\xb3", // U+e073 - "UsersViewfinder": "\xee\x96\x95", // U+e595 - "Utensils": "\xef\x8b\xa7", // U+f2e7 - "V": "V", // U+0056 - "VanShuttle": "\xef\x96\xb6", // U+f5b6 - "Vault": "\xee\x8b\x85", // U+e2c5 - "Venus": "\xef\x88\xa1", // U+f221 - "VenusDouble": "\xef\x88\xa6", // U+f226 - "VenusMars": "\xef\x88\xa8", // U+f228 - "Vest": "\xee\x82\x85", // U+e085 - "VestPatches": "\xee\x82\x86", // U+e086 - "Vial": "\xef\x92\x92", // U+f492 - "VialCircleCheck": "\xee\x96\x96", // U+e596 - "VialVirus": "\xee\x96\x97", // U+e597 - "Vials": "\xef\x92\x93", // U+f493 - "Video": "\xef\x80\xbd", // U+f03d - "VideoSlash": "\xef\x93\xa2", // U+f4e2 - "Vihara": "\xef\x9a\xa7", // U+f6a7 - "Virgo": "\xee\xa1\x90", // U+e850 - "Virus": "\xee\x81\xb4", // U+e074 - "VirusCovid": "\xee\x92\xa8", // U+e4a8 - "VirusCovidSlash": "\xee\x92\xa9", // U+e4a9 - "VirusSlash": "\xee\x81\xb5", // U+e075 - "Viruses": "\xee\x81\xb6", // U+e076 - "Voicemail": "\xef\xa2\x97", // U+f897 - "Volcano": "\xef\x9d\xb0", // U+f770 - "Volleyball": "\xef\x91\x9f", // U+f45f - "Volume": "\xef\x9a\xa8", // U+f6a8 - "VolumeHigh": "\xef\x80\xa8", // U+f028 - "VolumeLow": "\xef\x80\xa7", // U+f027 - "VolumeOff": "\xef\x80\xa6", // U+f026 - "VolumeXmark": "\xef\x9a\xa9", // U+f6a9 - "VrCardboard": "\xef\x9c\xa9", // U+f729 - "W": "W", // U+0057 - "WalkieTalkie": "\xef\xa3\xaf", // U+f8ef - "Wallet": "\xef\x95\x95", // U+f555 - "WandMagic": "\xef\x83\x90", // U+f0d0 - "WandMagicSparkles": "\xee\x8b\x8a", // U+e2ca - "WandSparkles": "\xef\x9c\xab", // U+f72b - "Warehouse": "\xef\x92\x94", // U+f494 - "Water": "\xef\x9d\xb3", // U+f773 - "WaterLadder": "\xef\x97\x85", // U+f5c5 - "WaveSquare": "\xef\xa0\xbe", // U+f83e - "WebAwesome": "\xee\x9a\x82", // U+e682 - "WeightHanging": "\xef\x97\x8d", // U+f5cd - "WeightScale": "\xef\x92\x96", // U+f496 - "WheatAwn": "\xee\x8b\x8d", // U+e2cd - "WheatAwnCircleExclamation": "\xee\x96\x98", // U+e598 - "Wheelchair": "\xef\x86\x93", // U+f193 - "WheelchairMove": "\xee\x8b\x8e", // U+e2ce - "WhiskeyGlass": "\xef\x9e\xa0", // U+f7a0 - "Wifi": "\xef\x87\xab", // U+f1eb - "Wind": "\xef\x9c\xae", // U+f72e - "WindowMaximize": "\xef\x8b\x90", // U+f2d0 - "WindowMinimize": "\xef\x8b\x91", // U+f2d1 - "WindowRestore": "\xef\x8b\x92", // U+f2d2 - "WineBottle": "\xef\x9c\xaf", // U+f72f - "WineGlass": "\xef\x93\xa3", // U+f4e3 - "WineGlassEmpty": "\xef\x97\x8e", // U+f5ce - "WonSign": "\xef\x85\x99", // U+f159 - "Worm": "\xee\x96\x99", // U+e599 - "Wrench": "\xef\x82\xad", // U+f0ad - "X": "X", // U+0058 - "XRay": "\xef\x92\x97", // U+f497 - "Xmark": "\xef\x80\x8d", // U+f00d - "XmarksLines": "\xee\x96\x9a", // U+e59a - "Y": "Y", // U+0059 - "YenSign": "\xef\x85\x97", // U+f157 - "YinYang": "\xef\x9a\xad", // U+f6ad - "Z": "Z", // U+005a - } - -var fa7BrandsIcons = map[string]string{ - "42Group": "\xee\x82\x80", // U+e080 - "500px": "\xef\x89\xae", // U+f26e - "AccessibleIcon": "\xef\x8d\xa8", // U+f368 - "Accusoft": "\xef\x8d\xa9", // U+f369 - "Adn": "\xef\x85\xb0", // U+f170 - "Adversal": "\xef\x8d\xaa", // U+f36a - "Affiliatetheme": "\xef\x8d\xab", // U+f36b - "Airbnb": "\xef\xa0\xb4", // U+f834 - "Algolia": "\xef\x8d\xac", // U+f36c - "Alipay": "\xef\x99\x82", // U+f642 - "Amazon": "\xef\x89\xb0", // U+f270 - "AmazonPay": "\xef\x90\xac", // U+f42c - "Amilia": "\xef\x8d\xad", // U+f36d - "Android": "\xef\x85\xbb", // U+f17b - "Angellist": "\xef\x88\x89", // U+f209 - "Angrycreative": "\xef\x8d\xae", // U+f36e - "Angular": "\xef\x90\xa0", // U+f420 - "AppStore": "\xef\x8d\xaf", // U+f36f - "AppStoreIos": "\xef\x8d\xb0", // U+f370 - "Apper": "\xef\x8d\xb1", // U+f371 - "Apple": "\xef\x85\xb9", // U+f179 - "ApplePay": "\xef\x90\x95", // U+f415 - "ArchLinux": "\xee\xa1\xa7", // U+e867 - "Artstation": "\xef\x9d\xba", // U+f77a - "Asymmetrik": "\xef\x8d\xb2", // U+f372 - "Atlassian": "\xef\x9d\xbb", // U+f77b - "Audible": "\xef\x8d\xb3", // U+f373 - "Autoprefixer": "\xef\x90\x9c", // U+f41c - "Avianex": "\xef\x8d\xb4", // U+f374 - "Aviato": "\xef\x90\xa1", // U+f421 - "Aws": "\xef\x8d\xb5", // U+f375 - "Bandcamp": "\xef\x8b\x95", // U+f2d5 - "BattleNet": "\xef\xa0\xb5", // U+f835 - "Behance": "\xef\x86\xb4", // U+f1b4 - "Bilibili": "\xee\x8f\x99", // U+e3d9 - "Bimobject": "\xef\x8d\xb8", // U+f378 - "Bitbucket": "\xef\x85\xb1", // U+f171 - "Bitcoin": "\xef\x8d\xb9", // U+f379 - "Bity": "\xef\x8d\xba", // U+f37a - "BlackTie": "\xef\x89\xbe", // U+f27e - "Blackberry": "\xef\x8d\xbb", // U+f37b - "Blogger": "\xef\x8d\xbc", // U+f37c - "BloggerB": "\xef\x8d\xbd", // U+f37d - "Bluesky": "\xee\x99\xb1", // U+e671 - "Bluetooth": "\xef\x8a\x93", // U+f293 - "BluetoothB": "\xef\x8a\x94", // U+f294 - "BoardGameGeek": "\xee\xa1\x95", // U+e855 - "Bootstrap": "\xef\xa0\xb6", // U+f836 - "Bots": "\xee\x8d\x80", // U+e340 - "Brave": "\xee\x98\xbc", // U+e63c - "BraveReverse": "\xee\x98\xbd", // U+e63d - "Btc": "\xef\x85\x9a", // U+f15a - "Buffer": "\xef\xa0\xb7", // U+f837 - "Buromobelexperte": "\xef\x8d\xbf", // U+f37f - "BuyNLarge": "\xef\xa2\xa6", // U+f8a6 - "Buysellads": "\xef\x88\x8d", // U+f20d - "CanadianMapleLeaf": "\xef\x9e\x85", // U+f785 - "CashApp": "\xee\x9f\x94", // U+e7d4 - "CcAmazonPay": "\xef\x90\xad", // U+f42d - "CcAmex": "\xef\x87\xb3", // U+f1f3 - "CcApplePay": "\xef\x90\x96", // U+f416 - "CcDinersClub": "\xef\x89\x8c", // U+f24c - "CcDiscover": "\xef\x87\xb2", // U+f1f2 - "CcJcb": "\xef\x89\x8b", // U+f24b - "CcMastercard": "\xef\x87\xb1", // U+f1f1 - "CcPaypal": "\xef\x87\xb4", // U+f1f4 - "CcStripe": "\xef\x87\xb5", // U+f1f5 - "CcVisa": "\xef\x87\xb0", // U+f1f0 - "Centercode": "\xef\x8e\x80", // U+f380 - "Centos": "\xef\x9e\x89", // U+f789 - "Chrome": "\xef\x89\xa8", // U+f268 - "Chromecast": "\xef\xa0\xb8", // U+f838 - "CircleZulip": "\xee\xa1\x91", // U+e851 - "Claude": "\xee\xa1\xa1", // U+e861 - "Cloudflare": "\xee\x81\xbd", // U+e07d - "Cloudscale": "\xef\x8e\x83", // U+f383 - "Cloudsmith": "\xef\x8e\x84", // U+f384 - "Cloudversify": "\xef\x8e\x85", // U+f385 - "Cmplid": "\xee\x8d\xa0", // U+e360 - "Codepen": "\xef\x87\x8b", // U+f1cb - "Codiepie": "\xef\x8a\x84", // U+f284 - "Confluence": "\xef\x9e\x8d", // U+f78d - "Connectdevelop": "\xef\x88\x8e", // U+f20e - "Contao": "\xef\x89\xad", // U+f26d - "CottonBureau": "\xef\xa2\x9e", // U+f89e - "Cpanel": "\xef\x8e\x88", // U+f388 - "CreativeCommons": "\xef\x89\x9e", // U+f25e - "CreativeCommonsBy": "\xef\x93\xa7", // U+f4e7 - "CreativeCommonsNc": "\xef\x93\xa8", // U+f4e8 - "CreativeCommonsNcEu": "\xef\x93\xa9", // U+f4e9 - "CreativeCommonsNcJp": "\xef\x93\xaa", // U+f4ea - "CreativeCommonsNd": "\xef\x93\xab", // U+f4eb - "CreativeCommonsPd": "\xef\x93\xac", // U+f4ec - "CreativeCommonsPdAlt": "\xef\x93\xad", // U+f4ed - "CreativeCommonsRemix": "\xef\x93\xae", // U+f4ee - "CreativeCommonsSa": "\xef\x93\xaf", // U+f4ef - "CreativeCommonsSampling": "\xef\x93\xb0", // U+f4f0 - "CreativeCommonsSamplingPlus": "\xef\x93\xb1", // U+f4f1 - "CreativeCommonsShare": "\xef\x93\xb2", // U+f4f2 - "CreativeCommonsZero": "\xef\x93\xb3", // U+f4f3 - "CriticalRole": "\xef\x9b\x89", // U+f6c9 - "Css": "\xee\x9a\xa2", // U+e6a2 - "Css3": "\xef\x84\xbc", // U+f13c - "Css3Alt": "\xef\x8e\x8b", // U+f38b - "Cuttlefish": "\xef\x8e\x8c", // U+f38c - "DAndD": "\xef\x8e\x8d", // U+f38d - "DAndDBeyond": "\xef\x9b\x8a", // U+f6ca - "Dailymotion": "\xee\x81\x92", // U+e052 - "DartLang": "\xee\x9a\x93", // U+e693 - "Dashcube": "\xef\x88\x90", // U+f210 - "Debian": "\xee\x98\x8b", // U+e60b - "Deezer": "\xee\x81\xb7", // U+e077 - "Delicious": "\xef\x86\xa5", // U+f1a5 - "Deploydog": "\xef\x8e\x8e", // U+f38e - "Deskpro": "\xef\x8e\x8f", // U+f38f - "Dev": "\xef\x9b\x8c", // U+f6cc - "Deviantart": "\xef\x86\xbd", // U+f1bd - "Dhl": "\xef\x9e\x90", // U+f790 - "Diaspora": "\xef\x9e\x91", // U+f791 - "Digg": "\xef\x86\xa6", // U+f1a6 - "DigitalOcean": "\xef\x8e\x91", // U+f391 - "Discord": "\xef\x8e\x92", // U+f392 - "Discourse": "\xef\x8e\x93", // U+f393 - "Disqus": "\xee\x9f\x95", // U+e7d5 - "Dochub": "\xef\x8e\x94", // U+f394 - "Docker": "\xef\x8e\x95", // U+f395 - "Draft2digital": "\xef\x8e\x96", // U+f396 - "Dribbble": "\xef\x85\xbd", // U+f17d - "Dropbox": "\xef\x85\xab", // U+f16b - "Drupal": "\xef\x86\xa9", // U+f1a9 - "Duolingo": "\xee\xa0\x92", // U+e812 - "Dyalog": "\xef\x8e\x99", // U+f399 - "Earlybirds": "\xef\x8e\x9a", // U+f39a - "Ebay": "\xef\x93\xb4", // U+f4f4 - "Edge": "\xef\x8a\x82", // U+f282 - "EdgeLegacy": "\xee\x81\xb8", // U+e078 - "Elementor": "\xef\x90\xb0", // U+f430 - "Eleventy": "\xee\x9f\x96", // U+e7d6 - "Ello": "\xef\x97\xb1", // U+f5f1 - "Ember": "\xef\x90\xa3", // U+f423 - "Empire": "\xef\x87\x91", // U+f1d1 - "Envira": "\xef\x8a\x99", // U+f299 - "Erlang": "\xef\x8e\x9d", // U+f39d - "Ethereum": "\xef\x90\xae", // U+f42e - "Etsy": "\xef\x8b\x97", // U+f2d7 - "Evernote": "\xef\xa0\xb9", // U+f839 - "Expeditedssl": "\xef\x88\xbe", // U+f23e - "Facebook": "\xef\x82\x9a", // U+f09a - "FacebookF": "\xef\x8e\x9e", // U+f39e - "FacebookMessenger": "\xef\x8e\x9f", // U+f39f - "FantasyFlightGames": "\xef\x9b\x9c", // U+f6dc - "Fedex": "\xef\x9e\x97", // U+f797 - "Fediverse": "\xee\xa1\xa5", // U+e865 - "Fedora": "\xef\x9e\x98", // U+f798 - "Figma": "\xef\x9e\x99", // U+f799 - "FilesPinwheel": "\xee\x9a\x9f", // U+e69f - "Firefox": "\xef\x89\xa9", // U+f269 - "FirefoxBrowser": "\xee\x80\x87", // U+e007 - "FirstOrder": "\xef\x8a\xb0", // U+f2b0 - "FirstOrderAlt": "\xef\x94\x8a", // U+f50a - "Firstdraft": "\xef\x8e\xa1", // U+f3a1 - "Flickr": "\xef\x85\xae", // U+f16e - "Flipboard": "\xef\x91\x8d", // U+f44d - "Flutter": "\xee\x9a\x94", // U+e694 - "Fly": "\xef\x90\x97", // U+f417 - "FontAwesome": "\xef\x8a\xb4", // U+f2b4 - "Fonticons": "\xef\x8a\x80", // U+f280 - "FonticonsFi": "\xef\x8e\xa2", // U+f3a2 - "Forgejo": "\xee\xa1\xa0", // U+e860 - "FortAwesome": "\xef\x8a\x86", // U+f286 - "FortAwesomeAlt": "\xef\x8e\xa3", // U+f3a3 - "Forumbee": "\xef\x88\x91", // U+f211 - "Foursquare": "\xef\x86\x80", // U+f180 - "FreeCodeCamp": "\xef\x8b\x85", // U+f2c5 - "Freebsd": "\xef\x8e\xa4", // U+f3a4 - "Fulcrum": "\xef\x94\x8b", // U+f50b - "GalacticRepublic": "\xef\x94\x8c", // U+f50c - "GalacticSenate": "\xef\x94\x8d", // U+f50d - "GetPocket": "\xef\x89\xa5", // U+f265 - "Gg": "\xef\x89\xa0", // U+f260 - "GgCircle": "\xef\x89\xa1", // U+f261 - "Git": "\xef\x87\x93", // U+f1d3 - "GitAlt": "\xef\xa1\x81", // U+f841 - "Gitee": "\xee\xa1\xa3", // U+e863 - "Github": "\xef\x82\x9b", // U+f09b - "GithubAlt": "\xef\x84\x93", // U+f113 - "Gitkraken": "\xef\x8e\xa6", // U+f3a6 - "Gitlab": "\xef\x8a\x96", // U+f296 - "Gitter": "\xef\x90\xa6", // U+f426 - "Glide": "\xef\x8a\xa5", // U+f2a5 - "GlideG": "\xef\x8a\xa6", // U+f2a6 - "Globaleaks": "\xee\xa1\x9d", // U+e85d - "Gofore": "\xef\x8e\xa7", // U+f3a7 - "Golang": "\xee\x90\x8f", // U+e40f - "Goodreads": "\xef\x8e\xa8", // U+f3a8 - "GoodreadsG": "\xef\x8e\xa9", // U+f3a9 - "Google": "\xef\x86\xa0", // U+f1a0 - "GoogleDrive": "\xef\x8e\xaa", // U+f3aa - "GooglePay": "\xee\x81\xb9", // U+e079 - "GooglePlay": "\xef\x8e\xab", // U+f3ab - "GooglePlus": "\xef\x8a\xb3", // U+f2b3 - "GooglePlusG": "\xef\x83\x95", // U+f0d5 - "GoogleScholar": "\xee\x98\xbb", // U+e63b - "GoogleWallet": "\xef\x87\xae", // U+f1ee - "Gratipay": "\xef\x86\x84", // U+f184 - "Grav": "\xef\x8b\x96", // U+f2d6 - "Gripfire": "\xef\x8e\xac", // U+f3ac - "Grunt": "\xef\x8e\xad", // U+f3ad - "Guilded": "\xee\x81\xbe", // U+e07e - "Gulp": "\xef\x8e\xae", // U+f3ae - "HackerNews": "\xef\x87\x94", // U+f1d4 - "Hackerrank": "\xef\x97\xb7", // U+f5f7 - "Hashnode": "\xee\x92\x99", // U+e499 - "Hips": "\xef\x91\x92", // U+f452 - "HireAHelper": "\xef\x8e\xb0", // U+f3b0 - "Hive": "\xee\x81\xbf", // U+e07f - "Hooli": "\xef\x90\xa7", // U+f427 - "Hornbill": "\xef\x96\x92", // U+f592 - "Hotjar": "\xef\x8e\xb1", // U+f3b1 - "Houzz": "\xef\x89\xbc", // U+f27c - "Html5": "\xef\x84\xbb", // U+f13b - "Hubspot": "\xef\x8e\xb2", // U+f3b2 - "HuggingFace": "\xee\xa1\xa9", // U+e869 - "Ideal": "\xee\x80\x93", // U+e013 - "Imdb": "\xef\x8b\x98", // U+f2d8 - "Instagram": "\xef\x85\xad", // U+f16d - "Instalod": "\xee\x82\x81", // U+e081 - "Intercom": "\xef\x9e\xaf", // U+f7af - "InternetExplorer": "\xef\x89\xab", // U+f26b - "Invision": "\xef\x9e\xb0", // U+f7b0 - "Ioxhost": "\xef\x88\x88", // U+f208 - "ItchIo": "\xef\xa0\xba", // U+f83a - "Itunes": "\xef\x8e\xb4", // U+f3b4 - "ItunesNote": "\xef\x8e\xb5", // U+f3b5 - "Java": "\xef\x93\xa4", // U+f4e4 - "JediOrder": "\xef\x94\x8e", // U+f50e - "Jenkins": "\xef\x8e\xb6", // U+f3b6 - "Jira": "\xef\x9e\xb1", // U+f7b1 - "Joget": "\xef\x8e\xb7", // U+f3b7 - "Joomla": "\xef\x86\xaa", // U+f1aa - "Js": "\xef\x8e\xb8", // U+f3b8 - "Jsfiddle": "\xef\x87\x8c", // U+f1cc - "Julia": "\xee\xa1\x92", // U+e852 - "Jxl": "\xee\x99\xbb", // U+e67b - "Kaggle": "\xef\x97\xba", // U+f5fa - "KakaoTalk": "\xee\x9f\x97", // U+e7d7 - "Keybase": "\xef\x93\xb5", // U+f4f5 - "Keycdn": "\xef\x8e\xba", // U+f3ba - "Kickstarter": "\xef\x8e\xbb", // U+f3bb - "KickstarterK": "\xef\x8e\xbc", // U+f3bc - "KoFi": "\xee\xa1\x96", // U+e856 - "Korvue": "\xef\x90\xaf", // U+f42f - "Kubernetes": "\xee\xa1\x97", // U+e857 - "Laravel": "\xef\x8e\xbd", // U+f3bd - "Lastfm": "\xef\x88\x82", // U+f202 - "Leanpub": "\xef\x88\x92", // U+f212 - "Leetcode": "\xee\xa1\xaa", // U+e86a - "Less": "\xef\x90\x9d", // U+f41d - "Letterboxd": "\xee\x98\xad", // U+e62d - "Line": "\xef\x8f\x80", // U+f3c0 - "Linkedin": "\xef\x82\x8c", // U+f08c - "LinkedinIn": "\xef\x83\xa1", // U+f0e1 - "Linktree": "\xee\x9f\x98", // U+e7d8 - "Linode": "\xef\x8a\xb8", // U+f2b8 - "Linux": "\xef\x85\xbc", // U+f17c - "Lumon": "\xee\x9f\xa2", // U+e7e2 - "LumonDrop": "\xee\x9f\xa3", // U+e7e3 - "Lyft": "\xef\x8f\x83", // U+f3c3 - "Magento": "\xef\x8f\x84", // U+f3c4 - "Mailchimp": "\xef\x96\x9e", // U+f59e - "Mandalorian": "\xef\x94\x8f", // U+f50f - "Markdown": "\xef\x98\x8f", // U+f60f - "Mastodon": "\xef\x93\xb6", // U+f4f6 - "Maxcdn": "\xef\x84\xb6", // U+f136 - "Mdb": "\xef\xa3\x8a", // U+f8ca - "Medapps": "\xef\x8f\x86", // U+f3c6 - "Medium": "\xef\x88\xba", // U+f23a - "Medrt": "\xef\x8f\x88", // U+f3c8 - "Meetup": "\xef\x8b\xa0", // U+f2e0 - "Megaport": "\xef\x96\xa3", // U+f5a3 - "Mendeley": "\xef\x9e\xb3", // U+f7b3 - "Meta": "\xee\x92\x9b", // U+e49b - "Microblog": "\xee\x80\x9a", // U+e01a - "Microsoft": "\xef\x8f\x8a", // U+f3ca - "Mintbit": "\xee\x98\xaf", // U+e62f - "Mix": "\xef\x8f\x8b", // U+f3cb - "Mixcloud": "\xef\x8a\x89", // U+f289 - "Mixer": "\xee\x81\x96", // U+e056 - "Mizuni": "\xef\x8f\x8c", // U+f3cc - "Modx": "\xef\x8a\x85", // U+f285 - "Monero": "\xef\x8f\x90", // U+f3d0 - "Napster": "\xef\x8f\x92", // U+f3d2 - "Neos": "\xef\x98\x92", // U+f612 - "NfcDirectional": "\xee\x94\xb0", // U+e530 - "NfcSymbol": "\xee\x94\xb1", // U+e531 - "Nimblr": "\xef\x96\xa8", // U+f5a8 - "Node": "\xef\x90\x99", // U+f419 - "NodeJs": "\xef\x8f\x93", // U+f3d3 - "Notion": "\xee\x9f\x99", // U+e7d9 - "Npm": "\xef\x8f\x94", // U+f3d4 - "Ns8": "\xef\x8f\x95", // U+f3d5 - "Nutritionix": "\xef\x8f\x96", // U+f3d6 - "Obsidian": "\xee\xa1\xb9", // U+e879 - "OctopusDeploy": "\xee\x82\x82", // U+e082 - "Odnoklassniki": "\xef\x89\xa3", // U+f263 - "Odysee": "\xee\x97\x86", // U+e5c6 - "OldRepublic": "\xef\x94\x90", // U+f510 - "Openai": "\xee\x9f\x8f", // U+e7cf - "Opencart": "\xef\x88\xbd", // U+f23d - "Openid": "\xef\x86\x9b", // U+f19b - "Openstreetmap": "\xee\xa1\xab", // U+e86b - "Opensuse": "\xee\x98\xab", // U+e62b - "Opera": "\xef\x89\xaa", // U+f26a - "OptinMonster": "\xef\x88\xbc", // U+f23c - "Orcid": "\xef\xa3\x92", // U+f8d2 - "Osi": "\xef\x90\x9a", // U+f41a - "Padlet": "\xee\x92\xa0", // U+e4a0 - "Page4": "\xef\x8f\x97", // U+f3d7 - "Pagelines": "\xef\x86\x8c", // U+f18c - "Palfed": "\xef\x8f\x98", // U+f3d8 - "Pandora": "\xee\x9f\x9a", // U+e7da - "Patreon": "\xef\x8f\x99", // U+f3d9 - "Paypal": "\xef\x87\xad", // U+f1ed - "Perbyte": "\xee\x82\x83", // U+e083 - "Periscope": "\xef\x8f\x9a", // U+f3da - "Phabricator": "\xef\x8f\x9b", // U+f3db - "PhoenixFramework": "\xef\x8f\x9c", // U+f3dc - "PhoenixSquadron": "\xef\x94\x91", // U+f511 - "Php": "\xef\x91\x97", // U+f457 - "PiedPiper": "\xef\x8a\xae", // U+f2ae - "PiedPiperAlt": "\xef\x86\xa8", // U+f1a8 - "PiedPiperHat": "\xef\x93\xa5", // U+f4e5 - "PiedPiperPp": "\xef\x86\xa7", // U+f1a7 - "Pinterest": "\xef\x83\x92", // U+f0d2 - "PinterestP": "\xef\x88\xb1", // U+f231 - "Pix": "\xee\x90\xba", // U+e43a - "Pixelfed": "\xee\x9f\x9b", // U+e7db - "Pixiv": "\xee\x99\x80", // U+e640 - "Playstation": "\xef\x8f\x9f", // U+f3df - "Postgresql": "\xee\xa1\x98", // U+e858 - "ProductHunt": "\xef\x8a\x88", // U+f288 - "Pushed": "\xef\x8f\xa1", // U+f3e1 - "Python": "\xef\x8f\xa2", // U+f3e2 - "Qq": "\xef\x87\x96", // U+f1d6 - "Quinscape": "\xef\x91\x99", // U+f459 - "Quora": "\xef\x8b\x84", // U+f2c4 - "RProject": "\xef\x93\xb7", // U+f4f7 - "RaspberryPi": "\xef\x9e\xbb", // U+f7bb - "Ravelry": "\xef\x8b\x99", // U+f2d9 - "React": "\xef\x90\x9b", // U+f41b - "Reacteurope": "\xef\x9d\x9d", // U+f75d - "Readme": "\xef\x93\x95", // U+f4d5 - "Rebel": "\xef\x87\x90", // U+f1d0 - "RedRiver": "\xef\x8f\xa3", // U+f3e3 - "Reddit": "\xef\x86\xa1", // U+f1a1 - "RedditAlien": "\xef\x8a\x81", // U+f281 - "Redhat": "\xef\x9e\xbc", // U+f7bc - "Renren": "\xef\x86\x8b", // U+f18b - "Replyd": "\xef\x8f\xa6", // U+f3e6 - "Researchgate": "\xef\x93\xb8", // U+f4f8 - "Resolving": "\xef\x8f\xa7", // U+f3e7 - "Rev": "\xef\x96\xb2", // U+f5b2 - "Rocketchat": "\xef\x8f\xa8", // U+f3e8 - "Rockrms": "\xef\x8f\xa9", // U+f3e9 - "Rust": "\xee\x81\xba", // U+e07a - "Safari": "\xef\x89\xa7", // U+f267 - "Salesforce": "\xef\xa0\xbb", // U+f83b - "Sass": "\xef\x90\x9e", // U+f41e - "Scaleway": "\xee\xa1\x99", // U+e859 - "Schlix": "\xef\x8f\xaa", // U+f3ea - "Screenpal": "\xee\x95\xb0", // U+e570 - "Scribd": "\xef\x8a\x8a", // U+f28a - "Searchengin": "\xef\x8f\xab", // U+f3eb - "Sellcast": "\xef\x8b\x9a", // U+f2da - "Sellsy": "\xef\x88\x93", // U+f213 - "Servicestack": "\xef\x8f\xac", // U+f3ec - "Shirtsinbulk": "\xef\x88\x94", // U+f214 - "Shoelace": "\xee\x98\x8c", // U+e60c - "Shopify": "\xee\x81\x97", // U+e057 - "Shopware": "\xef\x96\xb5", // U+f5b5 - "SignalMessenger": "\xee\x99\xa3", // U+e663 - "Simplybuilt": "\xef\x88\x95", // U+f215 - "Sistrix": "\xef\x8f\xae", // U+f3ee - "Sith": "\xef\x94\x92", // U+f512 - "Sitrox": "\xee\x91\x8a", // U+e44a - "Sketch": "\xef\x9f\x86", // U+f7c6 - "Skyatlas": "\xef\x88\x96", // U+f216 - "Skype": "\xef\x85\xbe", // U+f17e - "Slack": "\xef\x86\x98", // U+f198 - "Slideshare": "\xef\x87\xa7", // U+f1e7 - "Snapchat": "\xef\x8a\xab", // U+f2ab - "Solana": "\xee\xa1\x9e", // U+e85e - "Soundcloud": "\xef\x86\xbe", // U+f1be - "Sourcetree": "\xef\x9f\x93", // U+f7d3 - "SpaceAwesome": "\xee\x96\xac", // U+e5ac - "Speakap": "\xef\x8f\xb3", // U+f3f3 - "SpeakerDeck": "\xef\xa0\xbc", // U+f83c - "Spotify": "\xef\x86\xbc", // U+f1bc - "SquareBehance": "\xef\x86\xb5", // U+f1b5 - "SquareBluesky": "\xee\x9a\xa3", // U+e6a3 - "SquareDeskpro": "\xee\xa1\x84", // U+e844 - "SquareDribbble": "\xef\x8e\x97", // U+f397 - "SquareFacebook": "\xef\x82\x82", // U+f082 - "SquareFigma": "\xee\x9f\xa4", // U+e7e4 - "SquareFontAwesome": "\xee\x96\xad", // U+e5ad - "SquareFontAwesomeStroke": "\xef\x8d\x9c", // U+f35c - "SquareGit": "\xef\x87\x92", // U+f1d2 - "SquareGithub": "\xef\x82\x92", // U+f092 - "SquareGitlab": "\xee\x96\xae", // U+e5ae - "SquareGooglePlus": "\xef\x83\x94", // U+f0d4 - "SquareHackerNews": "\xef\x8e\xaf", // U+f3af - "SquareInstagram": "\xee\x81\x95", // U+e055 - "SquareJs": "\xef\x8e\xb9", // U+f3b9 - "SquareLastfm": "\xef\x88\x83", // U+f203 - "SquareLetterboxd": "\xee\x98\xae", // U+e62e - "SquareLinkedin": "\xee\x9f\x90", // U+e7d0 - "SquareOdnoklassniki": "\xef\x89\xa4", // U+f264 - "SquarePiedPiper": "\xee\x80\x9e", // U+e01e - "SquarePinterest": "\xef\x83\x93", // U+f0d3 - "SquareReddit": "\xef\x86\xa2", // U+f1a2 - "SquareSnapchat": "\xef\x8a\xad", // U+f2ad - "SquareSteam": "\xef\x86\xb7", // U+f1b7 - "SquareThreads": "\xee\x98\x99", // U+e619 - "SquareTumblr": "\xef\x85\xb4", // U+f174 - "SquareTwitter": "\xef\x82\x81", // U+f081 - "SquareUpwork": "\xee\x99\xbc", // U+e67c - "SquareViadeo": "\xef\x8a\xaa", // U+f2aa - "SquareVimeo": "\xef\x86\x94", // U+f194 - "SquareWebAwesome": "\xee\x9a\x83", // U+e683 - "SquareWebAwesomeStroke": "\xee\x9a\x84", // U+e684 - "SquareWhatsapp": "\xef\x90\x8c", // U+f40c - "SquareXTwitter": "\xee\x98\x9a", // U+e61a - "SquareXing": "\xef\x85\xa9", // U+f169 - "SquareYoutube": "\xef\x90\xb1", // U+f431 - "Squarespace": "\xef\x96\xbe", // U+f5be - "StackExchange": "\xef\x86\x8d", // U+f18d - "StackOverflow": "\xef\x85\xac", // U+f16c - "Stackpath": "\xef\xa1\x82", // U+f842 - "Staylinked": "\xef\x8f\xb5", // U+f3f5 - "Steam": "\xef\x86\xb6", // U+f1b6 - "SteamSymbol": "\xef\x8f\xb6", // U+f3f6 - "StickerMule": "\xef\x8f\xb7", // U+f3f7 - "Strava": "\xef\x90\xa8", // U+f428 - "Stripe": "\xef\x90\xa9", // U+f429 - "StripeS": "\xef\x90\xaa", // U+f42a - "Stubber": "\xee\x97\x87", // U+e5c7 - "Studiovinari": "\xef\x8f\xb8", // U+f3f8 - "Stumbleupon": "\xef\x86\xa4", // U+f1a4 - "StumbleuponCircle": "\xef\x86\xa3", // U+f1a3 - "Superpowers": "\xef\x8b\x9d", // U+f2dd - "Supple": "\xef\x8f\xb9", // U+f3f9 - "Supportnow": "\xee\xa0\xb3", // U+e833 - "Suse": "\xef\x9f\x96", // U+f7d6 - "Svelte": "\xee\xa1\xa8", // U+e868 - "Swift": "\xef\xa3\xa1", // U+f8e1 - "Symfony": "\xef\xa0\xbd", // U+f83d - "Symfonycasts": "\xee\xa2\xab", // U+e8ab - "TailwindCss": "\xee\xa1\xa6", // U+e866 - "Teamspeak": "\xef\x93\xb9", // U+f4f9 - "Telegram": "\xef\x8b\x86", // U+f2c6 - "TencentWeibo": "\xef\x87\x95", // U+f1d5 - "Tex": "\xee\x9f\xbf", // U+e7ff - "TheRedYeti": "\xef\x9a\x9d", // U+f69d - "Themeco": "\xef\x97\x86", // U+f5c6 - "Themeisle": "\xef\x8a\xb2", // U+f2b2 - "ThinkPeaks": "\xef\x9c\xb1", // U+f731 - "Threads": "\xee\x98\x98", // U+e618 - "Threema": "\xee\xa1\x9f", // U+e85f - "Tidal": "\xee\x9f\x9c", // U+e7dc - "Tiktok": "\xee\x81\xbb", // U+e07b - "TorBrowser": "\xee\xa0\xb8", // U+e838 - "TradeFederation": "\xef\x94\x93", // U+f513 - "Trello": "\xef\x86\x81", // U+f181 - "Tumblr": "\xef\x85\xb3", // U+f173 - "Twitch": "\xef\x87\xa8", // U+f1e8 - "Twitter": "\xef\x82\x99", // U+f099 - "Typescript": "\xee\xa1\x80", // U+e840 - "Typo3": "\xef\x90\xab", // U+f42b - "Uber": "\xef\x90\x82", // U+f402 - "Ubuntu": "\xef\x9f\x9f", // U+f7df - "Uikit": "\xef\x90\x83", // U+f403 - "Ultralytics": "\xee\xa1\xad", // U+e86d - "UltralyticsHub": "\xee\xa1\xae", // U+e86e - "UltralyticsYolo": "\xee\xa1\xaf", // U+e86f - "Umbraco": "\xef\xa3\xa8", // U+f8e8 - "Uncharted": "\xee\x82\x84", // U+e084 - "Uniregistry": "\xef\x90\x84", // U+f404 - "Unison": "\xee\xa1\x94", // U+e854 - "Unity": "\xee\x81\x89", // U+e049 - "UnrealEngine": "\xee\xa1\x9c", // U+e85c - "Unsplash": "\xee\x81\xbc", // U+e07c - "Untappd": "\xef\x90\x85", // U+f405 - "Ups": "\xef\x9f\xa0", // U+f7e0 - "Upwork": "\xee\x99\x81", // U+e641 - "Usb": "\xef\x8a\x87", // U+f287 - "Usps": "\xef\x9f\xa1", // U+f7e1 - "Ussunnah": "\xef\x90\x87", // U+f407 - "Vaadin": "\xef\x90\x88", // U+f408 - "Venmo": "\xee\xa1\x9a", // U+e85a - "VenmoV": "\xee\xa1\x9b", // U+e85b - "Viacoin": "\xef\x88\xb7", // U+f237 - "Viadeo": "\xef\x8a\xa9", // U+f2a9 - "Viber": "\xef\x90\x89", // U+f409 - "Vim": "\xee\xa2\x8a", // U+e88a - "Vimeo": "\xef\x90\x8a", // U+f40a - "VimeoV": "\xef\x89\xbd", // U+f27d - "Vine": "\xef\x87\x8a", // U+f1ca - "Vk": "\xef\x86\x89", // U+f189 - "Vnv": "\xef\x90\x8b", // U+f40b - "Vsco": "\xee\x9f\x9d", // U+e7dd - "Vuejs": "\xef\x90\x9f", // U+f41f - "W3c": "\xee\x9f\x9e", // U+e7de - "WatchmanMonitoring": "\xee\x82\x87", // U+e087 - "Waze": "\xef\xa0\xbf", // U+f83f - "WebAwesome": "\xee\x9a\x82", // U+e682 - "Webflow": "\xee\x99\x9c", // U+e65c - "Weebly": "\xef\x97\x8c", // U+f5cc - "Weibo": "\xef\x86\x8a", // U+f18a - "Weixin": "\xef\x87\x97", // U+f1d7 - "Whatsapp": "\xef\x88\xb2", // U+f232 - "Whmcs": "\xef\x90\x8d", // U+f40d - "WikipediaW": "\xef\x89\xa6", // U+f266 - "Windows": "\xef\x85\xba", // U+f17a - "Wirsindhandwerk": "\xee\x8b\x90", // U+e2d0 - "Wix": "\xef\x97\x8f", // U+f5cf - "WizardsOfTheCoast": "\xef\x9c\xb0", // U+f730 - "Wodu": "\xee\x82\x88", // U+e088 - "WolfPackBattalion": "\xef\x94\x94", // U+f514 - "Wordpress": "\xef\x86\x9a", // U+f19a - "WordpressSimple": "\xef\x90\x91", // U+f411 - "Wpbeginner": "\xef\x8a\x97", // U+f297 - "Wpexplorer": "\xef\x8b\x9e", // U+f2de - "Wpforms": "\xef\x8a\x98", // U+f298 - "Wpressr": "\xef\x8f\xa4", // U+f3e4 - "XTwitter": "\xee\x98\x9b", // U+e61b - "Xbox": "\xef\x90\x92", // U+f412 - "Xing": "\xef\x85\xa8", // U+f168 - "Xmpp": "\xee\xa1\xa4", // U+e864 - "YCombinator": "\xef\x88\xbb", // U+f23b - "Yahoo": "\xef\x86\x9e", // U+f19e - "Yammer": "\xef\xa1\x80", // U+f840 - "Yandex": "\xef\x90\x93", // U+f413 - "YandexInternational": "\xef\x90\x94", // U+f414 - "Yarn": "\xef\x9f\xa3", // U+f7e3 - "Yelp": "\xef\x87\xa9", // U+f1e9 - "Yoast": "\xef\x8a\xb1", // U+f2b1 - "Youtube": "\xef\x85\xa7", // U+f167 - "Zhihu": "\xef\x98\xbf", // U+f63f - "Zoom": "\xee\xa1\xbb", // U+e87b - "Zulip": "\xee\xa1\x93", // U+e853 - } diff --git a/internal/config/config.go b/internal/config/config.go index 14b0d12..786b547 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -11,16 +11,16 @@ import ( ) type Config struct { - Version int `json:"version"` - LogLevel string `json:"log_level"` - DefaultPage string `json:"default_page"` - Font string `json:"font,omitempty"` - ShowLabelBackground bool `json:"show_label_background"` - Devices []DeviceConfig `json:"devices"` - Pages []PageConfig `json:"pages"` - AutoSwitch []SwitchRule `json:"auto_switch"` - Screensaver ScreensaverCfg `json:"screensaver"` - Timing TimingConfig `json:"timing,omitempty"` + Version int `json:"version"` + LogLevel string `json:"log_level"` + DefaultPage string `json:"default_page"` + Font string `json:"font,omitempty"` + ShowLabelBackground bool `json:"show_label_background"` + Devices []DeviceConfig `json:"devices"` + Pages []PageConfig `json:"pages"` + AutoSwitch []SwitchRule `json:"auto_switch"` + Screensaver ScreensaverCfg `json:"screensaver"` + Timing TimingConfig `json:"timing,omitempty"` } type TimingConfig struct { @@ -57,15 +57,15 @@ type DynamicKeyGen struct { } type KeyConfig struct { - Index int `json:"index"` - Icon string `json:"icon,omitempty"` - Background string `json:"background,omitempty"` - Label string `json:"label,omitempty"` - Font string `json:"font,omitempty"` - FontSize *float64 `json:"font_size,omitempty"` - IconScale *float64 `json:"icon_scale,omitempty"` - Actions []KeyAction `json:"actions,omitempty"` - Display *DisplayCfg `json:"display,omitempty"` + Index int `json:"index"` + Icon string `json:"icon,omitempty"` + Background string `json:"background,omitempty"` + Label string `json:"label,omitempty"` + Font string `json:"font,omitempty"` + FontSize *float64 `json:"font_size,omitempty"` + IconScale *float64 `json:"icon_scale,omitempty"` + Actions []KeyAction `json:"actions,omitempty"` + Display *DisplayCfg `json:"display,omitempty"` } type KeyAction struct { @@ -151,6 +151,21 @@ func ConfigPath(path string) string { return filepath.Join(home, ".config", "streamdeck-lets-go", "config.json") } +var cachedConfigDir string + +func ConfigDir() string { + if cachedConfigDir != "" { + return cachedConfigDir + } + home, err := os.UserHomeDir() + if err != nil { + cachedConfigDir = "." + return cachedConfigDir + } + cachedConfigDir = filepath.Join(home, ".config", "streamdeck-lets-go") + return cachedConfigDir +} + func LoadConfig(path string) (*Config, error) { path = ConfigPath(path) data, err := os.ReadFile(path) diff --git a/action.go b/internal/daemon/action.go similarity index 71% rename from action.go rename to internal/daemon/action.go index 350ff3a..86f7bf4 100644 --- a/action.go +++ b/internal/daemon/action.go @@ -1,21 +1,18 @@ -package main +package daemon import ( - "bytes" - "context" - "encoding/json" "fmt" "log/slog" "os" "os/exec" - "path/filepath" "strings" - "time" "streamdeck-lets-go/internal/config" + "streamdeck-lets-go/internal/deck" + "streamdeck-lets-go/internal/render" ) -func ExecuteAction(a *config.Action, deck *Deck, pm *PageManager) error { +func ExecuteAction(a *config.Action, deck *deck.Deck, pm *render.PageManager) error { if a == nil { return nil } @@ -76,78 +73,7 @@ func execScript(a *config.Action) error { return nil } -func execDisplayCapture(d *config.DisplayCfg, timeout time.Duration) (string, error) { - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - - var cmd *exec.Cmd - if d.Command != "" { - cmd = exec.CommandContext(ctx, "sh", "-c", d.Command) - } else { - cmd = exec.CommandContext(ctx, d.Script) - } - var stdout, stderr bytes.Buffer - cmd.Stdout = &stdout - cmd.Stderr = &stderr - - err := cmd.Run() - output := stdout.String() - if stderr.Len() > 0 { - if output != "" { - output += "\n" - } - output += stderr.String() - } - return output, err -} - -func execDynamicKeys(dg *config.DynamicKeyGen, timeout time.Duration, keyCount int) ([]config.KeyConfig, error) { - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - - var cmd *exec.Cmd - if dg.Command != "" { - cmd = exec.CommandContext(ctx, "sh", "-c", dg.Command) - } else { - script := dg.Script - if !filepath.IsAbs(script) { - script = filepath.Join(configDir(), script) - } - cmd = exec.CommandContext(ctx, script) - } - - // Set environment variables for the script - cmd.Env = append(os.Environ(), - fmt.Sprintf("STREAMDECK_KEY_COUNT=%d", keyCount), - fmt.Sprintf("STREAMDECK_CONFIG_DIR=%s", configDir()), - ) - - var stdout, stderr bytes.Buffer - cmd.Stdout = &stdout - cmd.Stderr = &stderr - - err := cmd.Run() - - // Log stderr separately (don't merge into stdout for JSON parsing) - if stderr.Len() > 0 { - slog.Debug("dynamic_keys script stderr", "output", stderr.String()) - } - - if err != nil { - return nil, fmt.Errorf("execute dynamic_keys: %w", err) - } - - // Parse JSON from stdout - var keys []config.KeyConfig - output := stdout.String() - if err := json.Unmarshal([]byte(output), &keys); err != nil { - return nil, fmt.Errorf("parse dynamic_keys JSON: %w", err) - } - - return keys, nil -} - -func execBuiltin(a *config.Action, deck *Deck, pm *PageManager) error { +func execBuiltin(a *config.Action, deck *deck.Deck, pm *render.PageManager) error { parts := strings.SplitN(a.Builtin, ":", 2) if len(parts) < 1 { return fmt.Errorf("invalid builtin: %s", a.Builtin) @@ -225,10 +151,10 @@ func brightnessAction(action string) error { return exec.Command("sh", "-c", cmd).Run() } -func pageBuiltinAction(action string, pm *PageManager) error { +func pageBuiltinAction(action string, pm *render.PageManager) error { switch action { case "next": - pageNames := pm.PageNames() + pageNames := pm.GetPageNames() current := pm.ActivePageName() for i, name := range pageNames { if name == current { @@ -240,7 +166,7 @@ func pageBuiltinAction(action string, pm *PageManager) error { return pm.ActivatePage(pageNames[0]) } case "prev": - pageNames := pm.PageNames() + pageNames := pm.GetPageNames() current := pm.ActivePageName() for i, name := range pageNames { if name == current { @@ -257,7 +183,7 @@ func pageBuiltinAction(action string, pm *PageManager) error { return nil } -func deckBuiltinAction(action string, deck *Deck) error { +func deckBuiltinAction(action string, deck *deck.Deck) error { switch action { case "brightness-up": current := deck.Brightness() @@ -360,13 +286,3 @@ func execYDOTool(keys string) error { cmd.Stderr = os.Stderr return cmd.Run() } - -func (pm *PageManager) PageNames() []string { - pm.mu.RLock() - defer pm.mu.RUnlock() - names := make([]string, 0, len(pm.pages)) - for name := range pm.pages { - names = append(names, name) - } - return names -} diff --git a/autoswitch.go b/internal/daemon/autoswitch.go similarity index 99% rename from autoswitch.go rename to internal/daemon/autoswitch.go index d380040..7319e2c 100644 --- a/autoswitch.go +++ b/internal/daemon/autoswitch.go @@ -1,4 +1,4 @@ -package main +package daemon import ( "context" @@ -265,6 +265,7 @@ func (d *niriDetector) getWindow(ctx context.Context) Window { } type gnomeDetector struct{ basePoll } + func (d *gnomeDetector) Start(ctx context.Context) (<-chan Window, error) { d.pollFn = d.getWindow ctx, d.cancel = context.WithCancel(ctx) @@ -307,6 +308,7 @@ func parseGnomeEval(out string) string { } type kdeDetector struct{ basePoll } + func (d *kdeDetector) Start(ctx context.Context) (<-chan Window, error) { d.pollFn = d.getWindow ctx, d.cancel = context.WithCancel(ctx) @@ -323,6 +325,7 @@ func (d *kdeDetector) getWindow(ctx context.Context) Window { } type x11Detector struct{ basePoll } + func (d *x11Detector) Start(ctx context.Context) (<-chan Window, error) { d.pollFn = d.getWindow ctx, d.cancel = context.WithCancel(ctx) @@ -339,6 +342,7 @@ func (d *x11Detector) getWindow(ctx context.Context) Window { } type portalDetector struct{ basePoll } + func (d *portalDetector) Start(ctx context.Context) (<-chan Window, error) { d.pollFn = d.getWindow ctx, d.cancel = context.WithCancel(ctx) diff --git a/autoswitch_test.go b/internal/daemon/autoswitch_test.go similarity index 99% rename from autoswitch_test.go rename to internal/daemon/autoswitch_test.go index a4e60b3..4616986 100644 --- a/autoswitch_test.go +++ b/internal/daemon/autoswitch_test.go @@ -1,4 +1,4 @@ -package main +package daemon import ( "encoding/json" diff --git a/daemon.go b/internal/daemon/daemon.go similarity index 87% rename from daemon.go rename to internal/daemon/daemon.go index 53cf631..b97c70c 100644 --- a/daemon.go +++ b/internal/daemon/daemon.go @@ -1,4 +1,4 @@ -package main +package daemon import ( "context" @@ -8,6 +8,9 @@ import ( "time" "streamdeck-lets-go/internal/config" + "streamdeck-lets-go/internal/deck" + "streamdeck-lets-go/internal/render" + "streamdeck-lets-go/internal/web" ) type RunOptions struct { @@ -19,7 +22,7 @@ type RunOptions struct { } func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error { - web := NewWebServer(cfg, opts.ConfigPath) + web := web.NewWebServer(cfg, opts.ConfigPath) if !opts.NoDeck || opts.HTTPEnabled { checkKeyboardTool() @@ -38,11 +41,11 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error { return nil } - var decks []*Deck + var decks []*deck.Deck var err error for { - decks, err = OpenAllDecks() + decks, err = deck.OpenAllDecks() if err == nil { break } @@ -54,11 +57,11 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error { } } - pageMgrs := make([]*PageManager, len(decks)) + pageMgrs := make([]*render.PageManager, len(decks)) for i, d := range decks { - pageMgrs[i] = NewPageManager(d) - pageMgrs[i].defaultFont = cfg.Font - pageMgrs[i].showLabelBackground = cfg.ShowLabelBackground + pageMgrs[i] = render.NewPageManager(d) + pageMgrs[i].DefaultFont = cfg.Font + pageMgrs[i].ShowLabelBackground = cfg.ShowLabelBackground pageMgrs[i].LoadPages(cfg.Pages) } primaryPM := pageMgrs[0] @@ -92,7 +95,7 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error { if err := pm.ActivatePage(startPage); err != nil { slog.Warn("activate start page", "error", err) } - pm.startPeriodicKeys() + pm.StartPeriodicKeys() } var windowCh <-chan Window @@ -127,8 +130,8 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error { asm.NotifyManualPage(a.Page) } for _, pm := range pageMgrs { - pm.stopPeriodicKeys() - pm.startPeriodicKeys() + pm.StopPeriodicKeys() + pm.StartPeriodicKeys() } web.BroadcastPageChange(newPage) } else { @@ -156,7 +159,7 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error { slog.Warn("deck event channel closed, attempting reconnect...") // Stop all periodic scripts to avoid wasting cycles on a closed device. - primaryPM.stopPeriodicKeys() + primaryPM.StopPeriodicKeys() asm.Pause() primaryDeck.Close() @@ -181,7 +184,7 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error { wasSsActive := ssCtrl.IsActive() ssCtrl.NotifyInput() - if evt.Kind == EventKeyPressed { + if evt.Kind == deck.EventKeyPressed { if wasSsActive { ssCtrl.Deactivate(primaryDeck) @@ -207,7 +210,7 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error { if page == nil { continue } - for _, k := range primaryPM.activeKeys() { + for _, k := range primaryPM.ActiveKeys() { if k.Index == evt.Index { if len(k.Actions) > 0 { ge.HandleEvent(evt, k.Actions) @@ -229,8 +232,8 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error { if err := pm.ActivatePage(page); err != nil { slog.Warn("auto-switch: activate page", "error", err) } - pm.stopPeriodicKeys() - pm.startPeriodicKeys() + pm.StopPeriodicKeys() + pm.StartPeriodicKeys() } web.BroadcastPageChange(page) } @@ -256,14 +259,14 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error { for _, d := range decks { d.SetBrightness(deviceBrightness(cfg, d.Serial())) } - var activePages []string - for _, pm := range pageMgrs { - activePages = append(activePages, pm.ActivePageName()) - pm.stopPeriodicKeys() - pm.defaultFont = cfg.Font - pm.showLabelBackground = cfg.ShowLabelBackground - pm.LoadPages(cfg.Pages) - } + var activePages []string + for _, pm := range pageMgrs { + activePages = append(activePages, pm.ActivePageName()) + pm.StopPeriodicKeys() + pm.DefaultFont = cfg.Font + pm.ShowLabelBackground = cfg.ShowLabelBackground + pm.LoadPages(cfg.Pages) + } ge.ReloadTiming(cfg.Timing.LongPressMs, cfg.Timing.DoubleTapMs) asm.Reload(cfg.AutoSwitch) if len(cfg.AutoSwitch) > 0 && detector == nil { @@ -283,7 +286,7 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error { if err := pm.ActivatePage(page); err != nil { slog.Warn("reload: activate page", "error", err) } - pm.startPeriodicKeys() + pm.StartPeriodicKeys() } } if lastConfigMod.IsZero() { @@ -295,7 +298,7 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error { slog.Warn("deck connection lost, reconnecting...", "error", err) // Stop all periodic scripts to avoid wasting cycles on a closed device. - primaryPM.stopPeriodicKeys() + primaryPM.StopPeriodicKeys() asm.Pause() primaryDeck.Close() @@ -364,16 +367,16 @@ func deviceBrightness(cfg *config.Config, serial string) int { return 75 } -func reconnectDeck(ctx context.Context, cfg *config.Config, pm **PageManager, startPage string) *Deck { +func reconnectDeck(ctx context.Context, cfg *config.Config, pm **render.PageManager, startPage string) *deck.Deck { for { - newDeck, err := OpenDeck("") + newDeck, err := deck.OpenDeck("") if err == nil { - *pm = NewPageManager(newDeck) - (*pm).defaultFont = cfg.Font - (*pm).showLabelBackground = cfg.ShowLabelBackground + *pm = render.NewPageManager(newDeck) + (*pm).DefaultFont = cfg.Font + (*pm).ShowLabelBackground = cfg.ShowLabelBackground (*pm).LoadPages(cfg.Pages) (*pm).ActivatePage(startPage) - (*pm).startPeriodicKeys() + (*pm).StartPeriodicKeys() return newDeck } select { diff --git a/gesture.go b/internal/daemon/gesture.go similarity index 92% rename from gesture.go rename to internal/daemon/gesture.go index 7f45839..433c7cc 100644 --- a/gesture.go +++ b/internal/daemon/gesture.go @@ -1,10 +1,11 @@ -package main +package daemon import ( "sync" "time" "streamdeck-lets-go/internal/config" + "streamdeck-lets-go/internal/deck" ) type ActionCallback func(idx int, a *config.Action) @@ -95,7 +96,7 @@ func findAction(actions []config.KeyAction, trigger string) *config.Action { return nil } -func (ge *GestureEngine) HandleEvent(evt Event, actions []config.KeyAction) { +func (ge *GestureEngine) HandleEvent(evt deck.Event, actions []config.KeyAction) { state := ge.getState(evt.Index) if len(actions) == 0 { @@ -103,14 +104,14 @@ func (ge *GestureEngine) HandleEvent(evt Event, actions []config.KeyAction) { } switch evt.Kind { - case EventKeyPressed: + case deck.EventKeyPressed: ge.handleKeyPress(state, evt, actions) - case EventKeyReleased: + case deck.EventKeyReleased: ge.handleKeyRelease(state, evt, actions) } } -func (ge *GestureEngine) handleKeyPress(state *gestureKeyState, evt Event, actions []config.KeyAction) { +func (ge *GestureEngine) handleKeyPress(state *gestureKeyState, evt deck.Event, actions []config.KeyAction) { state.mu.Lock() state.cancelTimers() state.holdActive = false @@ -130,7 +131,7 @@ func (ge *GestureEngine) handleKeyPress(state *gestureKeyState, evt Event, actio state.mu.Unlock() } -func (ge *GestureEngine) handleKeyRelease(state *gestureKeyState, evt Event, actions []config.KeyAction) { +func (ge *GestureEngine) handleKeyRelease(state *gestureKeyState, evt deck.Event, actions []config.KeyAction) { state.mu.Lock() state.cancelTimers() diff --git a/screensaver.go b/internal/daemon/screensaver.go similarity index 81% rename from screensaver.go rename to internal/daemon/screensaver.go index ff4a359..35a558f 100644 --- a/screensaver.go +++ b/internal/daemon/screensaver.go @@ -1,17 +1,19 @@ -package main +package daemon import ( "log/slog" "time" "streamdeck-lets-go/internal/config" + "streamdeck-lets-go/internal/deck" + "streamdeck-lets-go/internal/render" ) type Screensaver struct { - enabled bool - idleAfter time.Duration - lastInput time.Time - active bool + enabled bool + idleAfter time.Duration + lastInput time.Time + active bool savedBrightness int } @@ -50,7 +52,7 @@ func (ss *Screensaver) Check() bool { return false } -func (ss *Screensaver) Activate(deck *Deck, cfg *config.ScreensaverCfg) { +func (ss *Screensaver) Activate(deck *deck.Deck, cfg *config.ScreensaverCfg) { ss.savedBrightness = deck.Brightness() brightness := cfg.Brightness @@ -62,7 +64,7 @@ func (ss *Screensaver) Activate(deck *Deck, cfg *config.ScreensaverCfg) { } if cfg.Image != "" { - img, err := loadImage(cfg.Image, 0, 0) + img, err := render.LoadImage(cfg.Image, 0, 0) if err != nil { slog.Warn("screensaver: load image", "path", cfg.Image, "error", err) return @@ -75,7 +77,7 @@ func (ss *Screensaver) Activate(deck *Deck, cfg *config.ScreensaverCfg) { slog.Info("screensaver activated") } -func (ss *Screensaver) Deactivate(deck *Deck) { +func (ss *Screensaver) Deactivate(deck *deck.Deck) { brightness := ss.savedBrightness if brightness <= 0 { brightness = 75 diff --git a/deck.go b/internal/deck/deck.go similarity index 88% rename from deck.go rename to internal/deck/deck.go index 9caf997..34a1067 100644 --- a/deck.go +++ b/internal/deck/deck.go @@ -1,4 +1,4 @@ -package main +package deck import ( "fmt" @@ -22,28 +22,28 @@ type DeviceInfo struct { } type DeckConfig struct { - PID uint16 - Name string - KeysX int - KeysY int - KeySize int - ImageFmt string - Rotate bool - Convert bool - HasDials bool - HasTouch bool + PID uint16 + Name string + KeysX int + KeysY int + KeySize int + ImageFmt string + Rotate bool + Convert bool + HasDials bool + HasTouch bool } -var knownDecks = []DeckConfig{ - {PID: 0x60, Name: "Mini", KeysX: 3, KeysY: 2, KeySize: 80, ImageFmt: "bmp", Convert: true}, - {PID: 0x6d, Name: "Original", KeysX: 5, KeysY: 3, KeySize: 72, ImageFmt: "jpg", Rotate: true}, - {PID: 0x63, Name: "OriginalV2",KeysX: 5, KeysY: 3, KeySize: 72, ImageFmt: "bmp"}, - {PID: 0x80, Name: "MK2", KeysX: 5, KeysY: 3, KeySize: 72, ImageFmt: "jpg", Rotate: true}, - {PID: 0x6c, Name: "XL", KeysX: 8, KeysY: 4, KeySize: 96, ImageFmt: "jpg"}, +var KnownDecks = []DeckConfig{ + {PID: 0x60, Name: "Mini", KeysX: 3, KeysY: 2, KeySize: 80, ImageFmt: "bmp", Convert: true}, + {PID: 0x6d, Name: "Original", KeysX: 5, KeysY: 3, KeySize: 72, ImageFmt: "jpg", Rotate: true}, + {PID: 0x63, Name: "OriginalV2", KeysX: 5, KeysY: 3, KeySize: 72, ImageFmt: "bmp"}, + {PID: 0x80, Name: "MK2", KeysX: 5, KeysY: 3, KeySize: 72, ImageFmt: "jpg", Rotate: true}, + {PID: 0x6c, Name: "XL", KeysX: 8, KeysY: 4, KeySize: 96, ImageFmt: "jpg"}, } func findConfig(pid uint16) (DeckConfig, bool) { - for _, d := range knownDecks { + for _, d := range KnownDecks { if d.PID == pid { return d, true } @@ -161,12 +161,12 @@ func (d *Deck) Close() { d.sd.Close() } -func (d *Deck) Serial() string { return d.serial } +func (d *Deck) Serial() string { return d.serial } func (d *Deck) Events() <-chan Event { return d.events } -func (d *Deck) NumKeys() int { return d.cfg.KeysX * d.cfg.KeysY } -func (d *Deck) KeySize() int { return d.cfg.KeySize } -func (d *Deck) Config() DeckConfig { return d.cfg } -func (d *Deck) Model() string { return d.cfg.Name } +func (d *Deck) NumKeys() int { return d.cfg.KeysX * d.cfg.KeysY } +func (d *Deck) KeySize() int { return d.cfg.KeySize } +func (d *Deck) Config() DeckConfig { return d.cfg } +func (d *Deck) Model() string { return d.cfg.Name } type DeckInfo struct { Serial string `json:"serial"` diff --git a/assets/Font_Awesome_7_BrandsRegular400.otf b/internal/render/assets/Font_Awesome_7_BrandsRegular400.otf similarity index 100% rename from assets/Font_Awesome_7_BrandsRegular400.otf rename to internal/render/assets/Font_Awesome_7_BrandsRegular400.otf diff --git a/assets/Font_Awesome_7_FreeRegular400.otf b/internal/render/assets/Font_Awesome_7_FreeRegular400.otf similarity index 100% rename from assets/Font_Awesome_7_FreeRegular400.otf rename to internal/render/assets/Font_Awesome_7_FreeRegular400.otf diff --git a/assets/Font_Awesome_7_FreeSolid900.otf b/internal/render/assets/Font_Awesome_7_FreeSolid900.otf similarity index 100% rename from assets/Font_Awesome_7_FreeSolid900.otf rename to internal/render/assets/Font_Awesome_7_FreeSolid900.otf diff --git a/assets/mplus-1m-medium.ttf b/internal/render/assets/mplus-1m-medium.ttf similarity index 100% rename from assets/mplus-1m-medium.ttf rename to internal/render/assets/mplus-1m-medium.ttf diff --git a/assets/mplus-1m-regular.ttf b/internal/render/assets/mplus-1m-regular.ttf similarity index 100% rename from assets/mplus-1m-regular.ttf rename to internal/render/assets/mplus-1m-regular.ttf diff --git a/cbdt.go b/internal/render/cbdt.go similarity index 98% rename from cbdt.go rename to internal/render/cbdt.go index 6e3d004..45a209c 100644 --- a/cbdt.go +++ b/internal/render/cbdt.go @@ -1,4 +1,4 @@ -package main +package render import ( "bytes" @@ -16,9 +16,9 @@ import ( ) type cbdtIndex struct { - once sync.Once - imgs []image.Image - scale int + once sync.Once + imgs []image.Image + scale int } var emojiCBDT cbdtIndex diff --git a/internal/render/emoji.go b/internal/render/emoji.go new file mode 100644 index 0000000..1ad8450 --- /dev/null +++ b/internal/render/emoji.go @@ -0,0 +1,209 @@ +package render + +import "sync" + +var emojiShortcodes = map[string]rune{ + // media + "play_pause": 0x25B6, + "stop": 0x23F9, + "record": 0x23FA, + "eject": 0x23CF, + "track_previous": 0x23EE, + "track_next": 0x23ED, + "fast_forward": 0x23E9, + "rewind": 0x23EA, + "shuffle": 0x1F500, + "repeat": 0x1F501, + "repeat_one": 0x1F502, + + // volume + "speaker": 0x1F50A, + "mute": 0x1F507, + "sound": 0x1F509, + + // navigation + "arrow_up": 0x2B06, + "arrow_down": 0x2B07, + "arrow_left": 0x2B05, + "arrow_right": 0x27A1, + "arrows_clockwise": 0x1F503, + "arrows_counterclockwise": 0x1F504, + + // status + "check": 0x2705, + "heavy_check_mark": 0x2714, + "x": 0x274C, + "heavy_multiplication_x": 0x2716, + "warning": 0x26A0, + "information_source": 0x2139, + "question": 0x2753, + "exclamation": 0x2757, + "white_check_mark": 0x2705, + "heavy_plus_sign": 0x2795, + "heavy_minus_sign": 0x2796, + "heavy_division_sign": 0x2797, + + // actions + "gear": 0x2699, + "hammer": 0x1F528, + "wrench": 0x1F527, + "key": 0x1F511, + "lock": 0x1F512, + "unlocked": 0x1F513, + "magnifying_glass": 0x1F50D, + "home": 0x1F3E0, + "bookmark": 0x1F516, + "bell": 0x1F514, + "clock": 0x1F550, + "alarm_clock": 0x23F0, + "hourglass": 0x231B, + "calendar": 0x1F4C5, + "envelope": 0x2709, + "camera": 0x1F4F7, + "video_camera": 0x1F4F9, + "microphone": 0x1F3A4, + "telephone": 0x260E, + "phone": 0x1F4DE, + "computer": 0x1F4BB, + "laptop": 0x1F4BB, + "folder": 0x1F4C1, + "open_file_folder": 0x1F4C2, + "clipboard": 0x1F4CB, + "memo": 0x1F4DD, + "pencil": 0x270F, + "scissors": 0x2702, + "link": 0x1F517, + "paperclip": 0x1F4CE, + "pushpin": 0x1F4CC, + "trash": 0x1F5D1, + "star": 0x2B50, + "trophy": 0x1F3C6, + "medal": 0x1F3C5, + "target": 0x1F3AF, + "dart": 0x1F3AF, + + // objects + "lightbulb": 0x1F4A1, + "bulb": 0x1F4A1, + "battery": 0x1F50B, + "electric_plug": 0x1F50C, + "rocket": 0x1F680, + "airplane": 0x2708, + "car": 0x1F697, + "bicycle": 0x1F6B2, + "headphones": 0x1F3A7, + "gamepad": 0x1F3AE, + "joystick": 0x1F579, + "musical_note": 0x1F3B5, + "notes": 0x1F3B6, + "printer": 0x1F5A8, + "keyboard": 0x2328, + + // weather + "sun": 0x2600, + "sunny": 0x2600, + "moon": 0x1F319, + "cloud": 0x2601, + "rainbow": 0x1F308, + "fire": 0x1F525, + "flame": 0x1F525, + "zap": 0x26A1, + "lightning": 0x26A1, + "snowflake": 0x2744, + "umbrella": 0x2602, + + // hearts + "heart": 0x2764, + "yellow_heart": 0x1F49B, + "green_heart": 0x1F49A, + "blue_heart": 0x1F499, + "purple_heart": 0x1F49C, + "black_heart": 0x1F5A4, + "broken_heart": 0x1F494, + "two_hearts": 0x1F495, + "sparkling_heart": 0x1F496, + "heartpulse": 0x1F497, + "heart_beat": 0x1F493, + "revolving_hearts": 0x1F49E, + "cupid": 0x1F498, + "gift_heart": 0x1F49D, + + // faces + "smile": 0x1F600, + "smiley": 0x1F603, + "grinning": 0x1F604, + "blush": 0x1F60A, + "wink": 0x1F609, + "heart_eyes": 0x1F60D, + "kissing_heart": 0x1F618, + "kissing": 0x1F617, + "smirk": 0x1F60F, + "stuck_out_tongue": 0x1F61B, + "stuck_out_tongue_winking_eye": 0x1F61C, + "sunglasses": 0x1F60E, + "innocent": 0x1F607, + "neutral_face": 0x1F610, + "expressionless": 0x1F611, + "thinking": 0x1F914, + "confused": 0x1F615, + "worried": 0x1F61F, + "frown": 0x1F641, + "persevere": 0x1F623, + "tired": 0x1F62B, + "weary": 0x1F629, + "cry": 0x1F622, + "sob": 0x1F62D, + "sweat_smile": 0x1F605, + "joy": 0x1F602, + "relaxed": 0x263A, + "angry": 0x1F620, + "rage": 0x1F621, + "skull": 0x1F480, + "ghost": 0x1F47B, + "robot": 0x1F916, + "sleeping": 0x1F634, + "sleep": 0x1F634, + "zzz": 0x1F4A4, + "dizzy": 0x1F4AB, + "boom": 0x1F4A5, + "collision": 0x1F4A5, + "sweat_drops": 0x1F4A6, + "dash": 0x1F4A8, + "alien": 0x1F47D, + "poop": 0x1F4A9, + + // hands & gestures + "thumbsup": 0x1F44D, + "thumbsdown": 0x1F44E, + "ok_hand": 0x1F44C, + "wave": 0x1F44B, + "clap": 0x1F44F, + "open_hands": 0x1F450, + "raised_hands": 0x1F64C, + "pray": 0x1F64F, + "muscle": 0x1F4AA, + "point_up": 0x261D, + "point_down": 0x1F447, + "point_left": 0x1F448, + "point_right": 0x1F449, + "fist": 0x270A, + "raised_hand": 0x270B, + "v": 0x270C, + "victory": 0x270C, + "crossed_fingers": 0x1F91E, + "writing_hand": 0x270D, + "call_me": 0x1F919, + "hand": 0x270B, +} + +var ( + emojiColorFontOnce sync.Once + emojiColorFontData []byte +) + +func loadColorEmojiFont() []byte { + emojiColorFontOnce.Do(func() { + emojiColorFontData = fcRead("emoji") + }) + return emojiColorFontData +} diff --git a/fontawesome.go b/internal/render/fontawesome.go similarity index 99% rename from fontawesome.go rename to internal/render/fontawesome.go index d8b4fbd..43e8a6f 100644 --- a/fontawesome.go +++ b/internal/render/fontawesome.go @@ -1,4 +1,4 @@ -package main +package render import ( "fmt" @@ -138,4 +138,3 @@ func renderFAGlyph(style faStyle, name string, size int, scale float64) (image.I func isFAIconRef(path string) bool { return strings.HasPrefix(path, "fa:") || strings.HasPrefix(path, "far:") || strings.HasPrefix(path, "fab:") } - diff --git a/fontawesome_data.go b/internal/render/fontawesome_data.go similarity index 97% rename from fontawesome_data.go rename to internal/render/fontawesome_data.go index 1c81776..0d10ebe 100644 --- a/fontawesome_data.go +++ b/internal/render/fontawesome_data.go @@ -1,4 +1,4 @@ -package main +package render import ( "embed" @@ -14,7 +14,7 @@ var faFonts embed.FS type faStyle int const ( - faSolid faStyle = iota + faSolid faStyle = iota faRegular faBrands ) diff --git a/internal/render/fontawesome_icons.go b/internal/render/fontawesome_icons.go new file mode 100644 index 0000000..bd24655 --- /dev/null +++ b/internal/render/fontawesome_icons.go @@ -0,0 +1,1979 @@ +package render + +var fa7Icons = map[string]string{ + "0": "0", // U+0030 + "1": "1", // U+0031 + "2": "2", // U+0032 + "3": "3", // U+0033 + "4": "4", // U+0034 + "5": "5", // U+0035 + "6": "6", // U+0036 + "7": "7", // U+0037 + "8": "8", // U+0038 + "9": "9", // U+0039 + "A": "A", // U+0041 + "AddressBook": "\xef\x8a\xb9", // U+f2b9 + "AddressCard": "\xef\x8a\xbb", // U+f2bb + "AlarmClock": "\xef\x8d\x8e", // U+f34e + "AlignCenter": "\xef\x80\xb7", // U+f037 + "AlignJustify": "\xef\x80\xb9", // U+f039 + "AlignLeft": "\xef\x80\xb6", // U+f036 + "AlignRight": "\xef\x80\xb8", // U+f038 + "Anchor": "\xef\x84\xbd", // U+f13d + "AnchorCircleCheck": "\xee\x92\xaa", // U+e4aa + "AnchorCircleExclamation": "\xee\x92\xab", // U+e4ab + "AnchorCircleXmark": "\xee\x92\xac", // U+e4ac + "AnchorLock": "\xee\x92\xad", // U+e4ad + "AngleDown": "\xef\x84\x87", // U+f107 + "AngleLeft": "\xef\x84\x84", // U+f104 + "AngleRight": "\xef\x84\x85", // U+f105 + "AngleUp": "\xef\x84\x86", // U+f106 + "AnglesDown": "\xef\x84\x83", // U+f103 + "AnglesLeft": "\xef\x84\x80", // U+f100 + "AnglesRight": "\xef\x84\x81", // U+f101 + "AnglesUp": "\xef\x84\x82", // U+f102 + "Ankh": "\xef\x99\x84", // U+f644 + "AppleWhole": "\xef\x97\x91", // U+f5d1 + "Aquarius": "\xee\xa1\x85", // U+e845 + "Archway": "\xef\x95\x97", // U+f557 + "Aries": "\xee\xa1\x86", // U+e846 + "ArrowDown": "\xef\x81\xa3", // U+f063 + "ArrowDown19": "\xef\x85\xa2", // U+f162 + "ArrowDown91": "\xef\xa2\x86", // U+f886 + "ArrowDownAZ": "\xef\x85\x9d", // U+f15d + "ArrowDownLong": "\xef\x85\xb5", // U+f175 + "ArrowDownShortWide": "\xef\xa2\x84", // U+f884 + "ArrowDownUpAcrossLine": "\xee\x92\xaf", // U+e4af + "ArrowDownUpLock": "\xee\x92\xb0", // U+e4b0 + "ArrowDownWideShort": "\xef\x85\xa0", // U+f160 + "ArrowDownZA": "\xef\xa2\x81", // U+f881 + "ArrowLeft": "\xef\x81\xa0", // U+f060 + "ArrowLeftLong": "\xef\x85\xb7", // U+f177 + "ArrowPointer": "\xef\x89\x85", // U+f245 + "ArrowRight": "\xef\x81\xa1", // U+f061 + "ArrowRightArrowLeft": "\xef\x83\xac", // U+f0ec + "ArrowRightFromBracket": "\xef\x82\x8b", // U+f08b + "ArrowRightLong": "\xef\x85\xb8", // U+f178 + "ArrowRightToBracket": "\xef\x82\x90", // U+f090 + "ArrowRightToCity": "\xee\x92\xb3", // U+e4b3 + "ArrowRotateLeft": "\xef\x83\xa2", // U+f0e2 + "ArrowRotateRight": "\xef\x80\x9e", // U+f01e + "ArrowTrendDown": "\xee\x82\x97", // U+e097 + "ArrowTrendUp": "\xee\x82\x98", // U+e098 + "ArrowTurnDown": "\xef\x85\x89", // U+f149 + "ArrowTurnUp": "\xef\x85\x88", // U+f148 + "ArrowUp": "\xef\x81\xa2", // U+f062 + "ArrowUp19": "\xef\x85\xa3", // U+f163 + "ArrowUp91": "\xef\xa2\x87", // U+f887 + "ArrowUpAZ": "\xef\x85\x9e", // U+f15e + "ArrowUpFromBracket": "\xee\x82\x9a", // U+e09a + "ArrowUpFromGroundWater": "\xee\x92\xb5", // U+e4b5 + "ArrowUpFromWaterPump": "\xee\x92\xb6", // U+e4b6 + "ArrowUpLong": "\xef\x85\xb6", // U+f176 + "ArrowUpRightDots": "\xee\x92\xb7", // U+e4b7 + "ArrowUpRightFromSquare": "\xef\x82\x8e", // U+f08e + "ArrowUpShortWide": "\xef\xa2\x85", // U+f885 + "ArrowUpWideShort": "\xef\x85\xa1", // U+f161 + "ArrowUpZA": "\xef\xa2\x82", // U+f882 + "ArrowsDownToLine": "\xee\x92\xb8", // U+e4b8 + "ArrowsDownToPeople": "\xee\x92\xb9", // U+e4b9 + "ArrowsLeftRight": "\xef\x81\xbe", // U+f07e + "ArrowsLeftRightToLine": "\xee\x92\xba", // U+e4ba + "ArrowsRotate": "\xef\x80\xa1", // U+f021 + "ArrowsSpin": "\xee\x92\xbb", // U+e4bb + "ArrowsSplitUpAndLeft": "\xee\x92\xbc", // U+e4bc + "ArrowsToCircle": "\xee\x92\xbd", // U+e4bd + "ArrowsToDot": "\xee\x92\xbe", // U+e4be + "ArrowsToEye": "\xee\x92\xbf", // U+e4bf + "ArrowsTurnRight": "\xee\x93\x80", // U+e4c0 + "ArrowsTurnToDots": "\xee\x93\x81", // U+e4c1 + "ArrowsUpDown": "\xef\x81\xbd", // U+f07d + "ArrowsUpDownLeftRight": "\xef\x81\x87", // U+f047 + "ArrowsUpToLine": "\xee\x93\x82", // U+e4c2 + "Asterisk": "*", // U+002a + "At": "@", // U+0040 + "Atom": "\xef\x97\x92", // U+f5d2 + "AudioDescription": "\xef\x8a\x9e", // U+f29e + "AustralSign": "\xee\x82\xa9", // U+e0a9 + "Award": "\xef\x95\x99", // U+f559 + "B": "B", // U+0042 + "Baby": "\xef\x9d\xbc", // U+f77c + "BabyCarriage": "\xef\x9d\xbd", // U+f77d + "Backward": "\xef\x81\x8a", // U+f04a + "BackwardFast": "\xef\x81\x89", // U+f049 + "BackwardStep": "\xef\x81\x88", // U+f048 + "Bacon": "\xef\x9f\xa5", // U+f7e5 + "Bacteria": "\xee\x81\x99", // U+e059 + "Bacterium": "\xee\x81\x9a", // U+e05a + "BagShopping": "\xef\x8a\x90", // U+f290 + "Bahai": "\xef\x99\xa6", // U+f666 + "BahtSign": "\xee\x82\xac", // U+e0ac + "Ban": "\xef\x81\x9e", // U+f05e + "BanSmoking": "\xef\x95\x8d", // U+f54d + "Bandage": "\xef\x91\xa2", // U+f462 + "BangladeshiTakaSign": "\xee\x8b\xa6", // U+e2e6 + "Barcode": "\xef\x80\xaa", // U+f02a + "Bars": "\xef\x83\x89", // U+f0c9 + "BarsProgress": "\xef\xa0\xa8", // U+f828 + "BarsStaggered": "\xef\x95\x90", // U+f550 + "Baseball": "\xef\x90\xb3", // U+f433 + "BaseballBatBall": "\xef\x90\xb2", // U+f432 + "BasketShopping": "\xef\x8a\x91", // U+f291 + "Basketball": "\xef\x90\xb4", // U+f434 + "Bath": "\xef\x8b\x8d", // U+f2cd + "BatteryEmpty": "\xef\x89\x84", // U+f244 + "BatteryFull": "\xef\x89\x80", // U+f240 + "BatteryHalf": "\xef\x89\x82", // U+f242 + "BatteryQuarter": "\xef\x89\x83", // U+f243 + "BatteryThreeQuarters": "\xef\x89\x81", // U+f241 + "Bed": "\xef\x88\xb6", // U+f236 + "BedPulse": "\xef\x92\x87", // U+f487 + "BeerMugEmpty": "\xef\x83\xbc", // U+f0fc + "Bell": "\xef\x83\xb3", // U+f0f3 + "BellConcierge": "\xef\x95\xa2", // U+f562 + "BellSlash": "\xef\x87\xb6", // U+f1f6 + "BezierCurve": "\xef\x95\x9b", // U+f55b + "Bicycle": "\xef\x88\x86", // U+f206 + "Binoculars": "\xef\x87\xa5", // U+f1e5 + "Biohazard": "\xef\x9e\x80", // U+f780 + "BitcoinSign": "\xee\x82\xb4", // U+e0b4 + "Blender": "\xef\x94\x97", // U+f517 + "BlenderPhone": "\xef\x9a\xb6", // U+f6b6 + "Blog": "\xef\x9e\x81", // U+f781 + "Bold": "\xef\x80\xb2", // U+f032 + "Bolt": "\xef\x83\xa7", // U+f0e7 + "BoltLightning": "\xee\x82\xb7", // U+e0b7 + "Bomb": "\xef\x87\xa2", // U+f1e2 + "Bone": "\xef\x97\x97", // U+f5d7 + "Bong": "\xef\x95\x9c", // U+f55c + "Book": "\xef\x80\xad", // U+f02d + "BookAtlas": "\xef\x95\x98", // U+f558 + "BookBible": "\xef\x99\x87", // U+f647 + "BookBookmark": "\xee\x82\xbb", // U+e0bb + "BookJournalWhills": "\xef\x99\xaa", // U+f66a + "BookMedical": "\xef\x9f\xa6", // U+f7e6 + "BookOpen": "\xef\x94\x98", // U+f518 + "BookOpenReader": "\xef\x97\x9a", // U+f5da + "BookQuran": "\xef\x9a\x87", // U+f687 + "BookSkull": "\xef\x9a\xb7", // U+f6b7 + "BookTanakh": "\xef\xa0\xa7", // U+f827 + "Bookmark": "\xef\x80\xae", // U+f02e + "BorderAll": "\xef\xa1\x8c", // U+f84c + "BorderNone": "\xef\xa1\x90", // U+f850 + "BorderTopLeft": "\xef\xa1\x93", // U+f853 + "BoreHole": "\xee\x93\x83", // U+e4c3 + "BottleDroplet": "\xee\x93\x84", // U+e4c4 + "BottleWater": "\xee\x93\x85", // U+e4c5 + "BowlFood": "\xee\x93\x86", // U+e4c6 + "BowlRice": "\xee\x8b\xab", // U+e2eb + "BowlingBall": "\xef\x90\xb6", // U+f436 + "Box": "\xef\x91\xa6", // U+f466 + "BoxArchive": "\xef\x86\x87", // U+f187 + "BoxOpen": "\xef\x92\x9e", // U+f49e + "BoxTissue": "\xee\x81\x9b", // U+e05b + "BoxesPacking": "\xee\x93\x87", // U+e4c7 + "BoxesStacked": "\xef\x91\xa8", // U+f468 + "Braille": "\xef\x8a\xa1", // U+f2a1 + "Brain": "\xef\x97\x9c", // U+f5dc + "BrazilianRealSign": "\xee\x91\xac", // U+e46c + "BreadSlice": "\xef\x9f\xac", // U+f7ec + "Bridge": "\xee\x93\x88", // U+e4c8 + "BridgeCircleCheck": "\xee\x93\x89", // U+e4c9 + "BridgeCircleExclamation": "\xee\x93\x8a", // U+e4ca + "BridgeCircleXmark": "\xee\x93\x8b", // U+e4cb + "BridgeLock": "\xee\x93\x8c", // U+e4cc + "BridgeWater": "\xee\x93\x8e", // U+e4ce + "Briefcase": "\xef\x82\xb1", // U+f0b1 + "BriefcaseMedical": "\xef\x91\xa9", // U+f469 + "Broom": "\xef\x94\x9a", // U+f51a + "BroomBall": "\xef\x91\x98", // U+f458 + "Brush": "\xef\x95\x9d", // U+f55d + "Bucket": "\xee\x93\x8f", // U+e4cf + "Bug": "\xef\x86\x88", // U+f188 + "BugSlash": "\xee\x92\x90", // U+e490 + "Bugs": "\xee\x93\x90", // U+e4d0 + "Building": "\xef\x86\xad", // U+f1ad + "BuildingCircleArrowRight": "\xee\x93\x91", // U+e4d1 + "BuildingCircleCheck": "\xee\x93\x92", // U+e4d2 + "BuildingCircleExclamation": "\xee\x93\x93", // U+e4d3 + "BuildingCircleXmark": "\xee\x93\x94", // U+e4d4 + "BuildingColumns": "\xef\x86\x9c", // U+f19c + "BuildingFlag": "\xee\x93\x95", // U+e4d5 + "BuildingLock": "\xee\x93\x96", // U+e4d6 + "BuildingNgo": "\xee\x93\x97", // U+e4d7 + "BuildingShield": "\xee\x93\x98", // U+e4d8 + "BuildingUn": "\xee\x93\x99", // U+e4d9 + "BuildingUser": "\xee\x93\x9a", // U+e4da + "BuildingWheat": "\xee\x93\x9b", // U+e4db + "Bullhorn": "\xef\x82\xa1", // U+f0a1 + "Bullseye": "\xef\x85\x80", // U+f140 + "Burger": "\xef\xa0\x85", // U+f805 + "Burst": "\xee\x93\x9c", // U+e4dc + "Bus": "\xef\x88\x87", // U+f207 + "BusSide": "\xee\xa0\x9d", // U+e81d + "BusSimple": "\xef\x95\x9e", // U+f55e + "BusinessTime": "\xef\x99\x8a", // U+f64a + "C": "C", // U+0043 + "CableCar": "\xef\x9f\x9a", // U+f7da + "CakeCandles": "\xef\x87\xbd", // U+f1fd + "Calculator": "\xef\x87\xac", // U+f1ec + "Calendar": "\xef\x84\xb3", // U+f133 + "CalendarCheck": "\xef\x89\xb4", // U+f274 + "CalendarDay": "\xef\x9e\x83", // U+f783 + "CalendarDays": "\xef\x81\xb3", // U+f073 + "CalendarMinus": "\xef\x89\xb2", // U+f272 + "CalendarPlus": "\xef\x89\xb1", // U+f271 + "CalendarWeek": "\xef\x9e\x84", // U+f784 + "CalendarXmark": "\xef\x89\xb3", // U+f273 + "Camera": "\xef\x80\xb0", // U+f030 + "CameraRetro": "\xef\x82\x83", // U+f083 + "CameraRotate": "\xee\x83\x98", // U+e0d8 + "Campground": "\xef\x9a\xbb", // U+f6bb + "Cancer": "\xee\xa1\x87", // U+e847 + "CandyCane": "\xef\x9e\x86", // U+f786 + "Cannabis": "\xef\x95\x9f", // U+f55f + "Capricorn": "\xee\xa1\x88", // U+e848 + "Capsules": "\xef\x91\xab", // U+f46b + "Car": "\xef\x86\xb9", // U+f1b9 + "CarBattery": "\xef\x97\x9f", // U+f5df + "CarBurst": "\xef\x97\xa1", // U+f5e1 + "CarOn": "\xee\x93\x9d", // U+e4dd + "CarRear": "\xef\x97\x9e", // U+f5de + "CarSide": "\xef\x97\xa4", // U+f5e4 + "CarTunnel": "\xee\x93\x9e", // U+e4de + "Caravan": "\xef\xa3\xbf", // U+f8ff + "CaretDown": "\xef\x83\x97", // U+f0d7 + "CaretLeft": "\xef\x83\x99", // U+f0d9 + "CaretRight": "\xef\x83\x9a", // U+f0da + "CaretUp": "\xef\x83\x98", // U+f0d8 + "Carrot": "\xef\x9e\x87", // U+f787 + "CartArrowDown": "\xef\x88\x98", // U+f218 + "CartFlatbed": "\xef\x91\xb4", // U+f474 + "CartFlatbedSuitcase": "\xef\x96\x9d", // U+f59d + "CartPlus": "\xef\x88\x97", // U+f217 + "CartShopping": "\xef\x81\xba", // U+f07a + "CashRegister": "\xef\x9e\x88", // U+f788 + "Cat": "\xef\x9a\xbe", // U+f6be + "CediSign": "\xee\x83\x9f", // U+e0df + "CentSign": "\xee\x8f\xb5", // U+e3f5 + "Certificate": "\xef\x82\xa3", // U+f0a3 + "Chair": "\xef\x9b\x80", // U+f6c0 + "Chalkboard": "\xef\x94\x9b", // U+f51b + "ChalkboardUser": "\xef\x94\x9c", // U+f51c + "ChampagneGlasses": "\xef\x9e\x9f", // U+f79f + "ChargingStation": "\xef\x97\xa7", // U+f5e7 + "ChartArea": "\xef\x87\xbe", // U+f1fe + "ChartBar": "\xef\x82\x80", // U+f080 + "ChartColumn": "\xee\x83\xa3", // U+e0e3 + "ChartDiagram": "\xee\x9a\x95", // U+e695 + "ChartGantt": "\xee\x83\xa4", // U+e0e4 + "ChartLine": "\xef\x88\x81", // U+f201 + "ChartPie": "\xef\x88\x80", // U+f200 + "ChartSimple": "\xee\x91\xb3", // U+e473 + "Check": "\xef\x80\x8c", // U+f00c + "CheckDouble": "\xef\x95\xa0", // U+f560 + "CheckToSlot": "\xef\x9d\xb2", // U+f772 + "Cheese": "\xef\x9f\xaf", // U+f7ef + "Chess": "\xef\x90\xb9", // U+f439 + "ChessBishop": "\xef\x90\xba", // U+f43a + "ChessBoard": "\xef\x90\xbc", // U+f43c + "ChessKing": "\xef\x90\xbf", // U+f43f + "ChessKnight": "\xef\x91\x81", // U+f441 + "ChessPawn": "\xef\x91\x83", // U+f443 + "ChessQueen": "\xef\x91\x85", // U+f445 + "ChessRook": "\xef\x91\x87", // U+f447 + "ChevronDown": "\xef\x81\xb8", // U+f078 + "ChevronLeft": "\xef\x81\x93", // U+f053 + "ChevronRight": "\xef\x81\x94", // U+f054 + "ChevronUp": "\xef\x81\xb7", // U+f077 + "Child": "\xef\x86\xae", // U+f1ae + "ChildCombatant": "\xee\x93\xa0", // U+e4e0 + "ChildDress": "\xee\x96\x9c", // U+e59c + "ChildReaching": "\xee\x96\x9d", // U+e59d + "Children": "\xee\x93\xa1", // U+e4e1 + "Church": "\xef\x94\x9d", // U+f51d + "Circle": "\xef\x84\x91", // U+f111 + "CircleArrowDown": "\xef\x82\xab", // U+f0ab + "CircleArrowLeft": "\xef\x82\xa8", // U+f0a8 + "CircleArrowRight": "\xef\x82\xa9", // U+f0a9 + "CircleArrowUp": "\xef\x82\xaa", // U+f0aa + "CircleCheck": "\xef\x81\x98", // U+f058 + "CircleChevronDown": "\xef\x84\xba", // U+f13a + "CircleChevronLeft": "\xef\x84\xb7", // U+f137 + "CircleChevronRight": "\xef\x84\xb8", // U+f138 + "CircleChevronUp": "\xef\x84\xb9", // U+f139 + "CircleDollarToSlot": "\xef\x92\xb9", // U+f4b9 + "CircleDot": "\xef\x86\x92", // U+f192 + "CircleDown": "\xef\x8d\x98", // U+f358 + "CircleExclamation": "\xef\x81\xaa", // U+f06a + "CircleH": "\xef\x91\xbe", // U+f47e + "CircleHalfStroke": "\xef\x81\x82", // U+f042 + "CircleInfo": "\xef\x81\x9a", // U+f05a + "CircleLeft": "\xef\x8d\x99", // U+f359 + "CircleMinus": "\xef\x81\x96", // U+f056 + "CircleNodes": "\xee\x93\xa2", // U+e4e2 + "CircleNotch": "\xef\x87\x8e", // U+f1ce + "CirclePause": "\xef\x8a\x8b", // U+f28b + "CirclePlay": "\xef\x85\x84", // U+f144 + "CirclePlus": "\xef\x81\x95", // U+f055 + "CircleQuestion": "\xef\x81\x99", // U+f059 + "CircleRadiation": "\xef\x9e\xba", // U+f7ba + "CircleRight": "\xef\x8d\x9a", // U+f35a + "CircleStop": "\xef\x8a\x8d", // U+f28d + "CircleUp": "\xef\x8d\x9b", // U+f35b + "CircleUser": "\xef\x8a\xbd", // U+f2bd + "CircleXmark": "\xef\x81\x97", // U+f057 + "City": "\xef\x99\x8f", // U+f64f + "Clapperboard": "\xee\x84\xb1", // U+e131 + "Clipboard": "\xef\x8c\xa8", // U+f328 + "ClipboardCheck": "\xef\x91\xac", // U+f46c + "ClipboardList": "\xef\x91\xad", // U+f46d + "ClipboardQuestion": "\xee\x93\xa3", // U+e4e3 + "ClipboardUser": "\xef\x9f\xb3", // U+f7f3 + "Clock": "\xef\x80\x97", // U+f017 + "ClockRotateLeft": "\xef\x87\x9a", // U+f1da + "Clone": "\xef\x89\x8d", // U+f24d + "ClosedCaptioning": "\xef\x88\x8a", // U+f20a + "ClosedCaptioningSlash": "\xee\x84\xb5", // U+e135 + "Cloud": "\xef\x83\x82", // U+f0c2 + "CloudArrowDown": "\xef\x83\xad", // U+f0ed + "CloudArrowUp": "\xef\x83\xae", // U+f0ee + "CloudBolt": "\xef\x9d\xac", // U+f76c + "CloudMeatball": "\xef\x9c\xbb", // U+f73b + "CloudMoon": "\xef\x9b\x83", // U+f6c3 + "CloudMoonRain": "\xef\x9c\xbc", // U+f73c + "CloudRain": "\xef\x9c\xbd", // U+f73d + "CloudShowersHeavy": "\xef\x9d\x80", // U+f740 + "CloudShowersWater": "\xee\x93\xa4", // U+e4e4 + "CloudSun": "\xef\x9b\x84", // U+f6c4 + "CloudSunRain": "\xef\x9d\x83", // U+f743 + "Clover": "\xee\x84\xb9", // U+e139 + "Code": "\xef\x84\xa1", // U+f121 + "CodeBranch": "\xef\x84\xa6", // U+f126 + "CodeCommit": "\xef\x8e\x86", // U+f386 + "CodeCompare": "\xee\x84\xba", // U+e13a + "CodeFork": "\xee\x84\xbb", // U+e13b + "CodeMerge": "\xef\x8e\x87", // U+f387 + "CodePullRequest": "\xee\x84\xbc", // U+e13c + "Coins": "\xef\x94\x9e", // U+f51e + "ColonSign": "\xee\x85\x80", // U+e140 + "Comment": "\xef\x81\xb5", // U+f075 + "CommentDollar": "\xef\x99\x91", // U+f651 + "CommentDots": "\xef\x92\xad", // U+f4ad + "CommentMedical": "\xef\x9f\xb5", // U+f7f5 + "CommentNodes": "\xee\x9a\x96", // U+e696 + "CommentSlash": "\xef\x92\xb3", // U+f4b3 + "CommentSms": "\xef\x9f\x8d", // U+f7cd + "Comments": "\xef\x82\x86", // U+f086 + "CommentsDollar": "\xef\x99\x93", // U+f653 + "CompactDisc": "\xef\x94\x9f", // U+f51f + "Compass": "\xef\x85\x8e", // U+f14e + "CompassDrafting": "\xef\x95\xa8", // U+f568 + "Compress": "\xef\x81\xa6", // U+f066 + "Computer": "\xee\x93\xa5", // U+e4e5 + "ComputerMouse": "\xef\xa3\x8c", // U+f8cc + "Cookie": "\xef\x95\xa3", // U+f563 + "CookieBite": "\xef\x95\xa4", // U+f564 + "Copy": "\xef\x83\x85", // U+f0c5 + "Copyright": "\xef\x87\xb9", // U+f1f9 + "Couch": "\xef\x92\xb8", // U+f4b8 + "Cow": "\xef\x9b\x88", // U+f6c8 + "CreditCard": "\xef\x82\x9d", // U+f09d + "Crop": "\xef\x84\xa5", // U+f125 + "CropSimple": "\xef\x95\xa5", // U+f565 + "Cross": "\xef\x99\x94", // U+f654 + "Crosshairs": "\xef\x81\x9b", // U+f05b + "Crow": "\xef\x94\xa0", // U+f520 + "Crown": "\xef\x94\xa1", // U+f521 + "Crutch": "\xef\x9f\xb7", // U+f7f7 + "CruzeiroSign": "\xee\x85\x92", // U+e152 + "Cube": "\xef\x86\xb2", // U+f1b2 + "Cubes": "\xef\x86\xb3", // U+f1b3 + "CubesStacked": "\xee\x93\xa6", // U+e4e6 + "D": "D", // U+0044 + "Database": "\xef\x87\x80", // U+f1c0 + "DeleteLeft": "\xef\x95\x9a", // U+f55a + "Democrat": "\xef\x9d\x87", // U+f747 + "Desktop": "\xef\x8e\x90", // U+f390 + "Dharmachakra": "\xef\x99\x95", // U+f655 + "DiagramNext": "\xee\x91\xb6", // U+e476 + "DiagramPredecessor": "\xee\x91\xb7", // U+e477 + "DiagramProject": "\xef\x95\x82", // U+f542 + "DiagramSuccessor": "\xee\x91\xba", // U+e47a + "Diamond": "\xef\x88\x99", // U+f219 + "DiamondTurnRight": "\xef\x97\xab", // U+f5eb + "Dice": "\xef\x94\xa2", // U+f522 + "DiceD20": "\xef\x9b\x8f", // U+f6cf + "DiceD6": "\xef\x9b\x91", // U+f6d1 + "DiceFive": "\xef\x94\xa3", // U+f523 + "DiceFour": "\xef\x94\xa4", // U+f524 + "DiceOne": "\xef\x94\xa5", // U+f525 + "DiceSix": "\xef\x94\xa6", // U+f526 + "DiceThree": "\xef\x94\xa7", // U+f527 + "DiceTwo": "\xef\x94\xa8", // U+f528 + "Disease": "\xef\x9f\xba", // U+f7fa + "Display": "\xee\x85\xa3", // U+e163 + "Divide": "\xef\x94\xa9", // U+f529 + "Dna": "\xef\x91\xb1", // U+f471 + "Dog": "\xef\x9b\x93", // U+f6d3 + "DollarSign": "$", // U+0024 + "Dolly": "\xef\x91\xb2", // U+f472 + "DongSign": "\xee\x85\xa9", // U+e169 + "DoorClosed": "\xef\x94\xaa", // U+f52a + "DoorOpen": "\xef\x94\xab", // U+f52b + "Dove": "\xef\x92\xba", // U+f4ba + "DownLeftAndUpRightToCenter": "\xef\x90\xa2", // U+f422 + "DownLong": "\xef\x8c\x89", // U+f309 + "Download": "\xef\x80\x99", // U+f019 + "Dragon": "\xef\x9b\x95", // U+f6d5 + "DrawPolygon": "\xef\x97\xae", // U+f5ee + "Droplet": "\xef\x81\x83", // U+f043 + "DropletSlash": "\xef\x97\x87", // U+f5c7 + "Drum": "\xef\x95\xa9", // U+f569 + "DrumSteelpan": "\xef\x95\xaa", // U+f56a + "DrumstickBite": "\xef\x9b\x97", // U+f6d7 + "Dumbbell": "\xef\x91\x8b", // U+f44b + "Dumpster": "\xef\x9e\x93", // U+f793 + "DumpsterFire": "\xef\x9e\x94", // U+f794 + "Dungeon": "\xef\x9b\x99", // U+f6d9 + "E": "E", // U+0045 + "EarDeaf": "\xef\x8a\xa4", // U+f2a4 + "EarListen": "\xef\x8a\xa2", // U+f2a2 + "EarthAfrica": "\xef\x95\xbc", // U+f57c + "EarthAmericas": "\xef\x95\xbd", // U+f57d + "EarthAsia": "\xef\x95\xbe", // U+f57e + "EarthEurope": "\xef\x9e\xa2", // U+f7a2 + "EarthOceania": "\xee\x91\xbb", // U+e47b + "Egg": "\xef\x9f\xbb", // U+f7fb + "Eject": "\xef\x81\x92", // U+f052 + "Elevator": "\xee\x85\xad", // U+e16d + "Ellipsis": "\xef\x85\x81", // U+f141 + "EllipsisVertical": "\xef\x85\x82", // U+f142 + "Envelope": "\xef\x83\xa0", // U+f0e0 + "EnvelopeCircleCheck": "\xee\x93\xa8", // U+e4e8 + "EnvelopeOpen": "\xef\x8a\xb6", // U+f2b6 + "EnvelopeOpenText": "\xef\x99\x98", // U+f658 + "EnvelopesBulk": "\xef\x99\xb4", // U+f674 + "Equals": "=", // U+003d + "Eraser": "\xef\x84\xad", // U+f12d + "Ethernet": "\xef\x9e\x96", // U+f796 + "EuroSign": "\xef\x85\x93", // U+f153 + "Exclamation": "!", // U+0021 + "Expand": "\xef\x81\xa5", // U+f065 + "Explosion": "\xee\x93\xa9", // U+e4e9 + "Eye": "\xef\x81\xae", // U+f06e + "EyeDropper": "\xef\x87\xbb", // U+f1fb + "EyeLowVision": "\xef\x8a\xa8", // U+f2a8 + "EyeSlash": "\xef\x81\xb0", // U+f070 + "F": "F", // U+0046 + "FaceAngry": "\xef\x95\x96", // U+f556 + "FaceDizzy": "\xef\x95\xa7", // U+f567 + "FaceFlushed": "\xef\x95\xb9", // U+f579 + "FaceFrown": "\xef\x84\x99", // U+f119 + "FaceFrownOpen": "\xef\x95\xba", // U+f57a + "FaceGrimace": "\xef\x95\xbf", // U+f57f + "FaceGrin": "\xef\x96\x80", // U+f580 + "FaceGrinBeam": "\xef\x96\x82", // U+f582 + "FaceGrinBeamSweat": "\xef\x96\x83", // U+f583 + "FaceGrinHearts": "\xef\x96\x84", // U+f584 + "FaceGrinSquint": "\xef\x96\x85", // U+f585 + "FaceGrinSquintTears": "\xef\x96\x86", // U+f586 + "FaceGrinStars": "\xef\x96\x87", // U+f587 + "FaceGrinTears": "\xef\x96\x88", // U+f588 + "FaceGrinTongue": "\xef\x96\x89", // U+f589 + "FaceGrinTongueSquint": "\xef\x96\x8a", // U+f58a + "FaceGrinTongueWink": "\xef\x96\x8b", // U+f58b + "FaceGrinWide": "\xef\x96\x81", // U+f581 + "FaceGrinWink": "\xef\x96\x8c", // U+f58c + "FaceKiss": "\xef\x96\x96", // U+f596 + "FaceKissBeam": "\xef\x96\x97", // U+f597 + "FaceKissWinkHeart": "\xef\x96\x98", // U+f598 + "FaceLaugh": "\xef\x96\x99", // U+f599 + "FaceLaughBeam": "\xef\x96\x9a", // U+f59a + "FaceLaughSquint": "\xef\x96\x9b", // U+f59b + "FaceLaughWink": "\xef\x96\x9c", // U+f59c + "FaceMeh": "\xef\x84\x9a", // U+f11a + "FaceMehBlank": "\xef\x96\xa4", // U+f5a4 + "FaceRollingEyes": "\xef\x96\xa5", // U+f5a5 + "FaceSadCry": "\xef\x96\xb3", // U+f5b3 + "FaceSadTear": "\xef\x96\xb4", // U+f5b4 + "FaceSmile": "\xef\x84\x98", // U+f118 + "FaceSmileBeam": "\xef\x96\xb8", // U+f5b8 + "FaceSmileWink": "\xef\x93\x9a", // U+f4da + "FaceSurprise": "\xef\x97\x82", // U+f5c2 + "FaceTired": "\xef\x97\x88", // U+f5c8 + "Fan": "\xef\xa1\xa3", // U+f863 + "Faucet": "\xee\x80\x85", // U+e005 + "FaucetDrip": "\xee\x80\x86", // U+e006 + "Fax": "\xef\x86\xac", // U+f1ac + "Feather": "\xef\x94\xad", // U+f52d + "FeatherPointed": "\xef\x95\xab", // U+f56b + "Ferry": "\xee\x93\xaa", // U+e4ea + "File": "\xef\x85\x9b", // U+f15b + "FileArrowDown": "\xef\x95\xad", // U+f56d + "FileArrowUp": "\xef\x95\xb4", // U+f574 + "FileAudio": "\xef\x87\x87", // U+f1c7 + "FileCircleCheck": "\xee\x96\xa0", // U+e5a0 + "FileCircleExclamation": "\xee\x93\xab", // U+e4eb + "FileCircleMinus": "\xee\x93\xad", // U+e4ed + "FileCirclePlus": "\xee\x92\x94", // U+e494 + "FileCircleQuestion": "\xee\x93\xaf", // U+e4ef + "FileCircleXmark": "\xee\x96\xa1", // U+e5a1 + "FileCode": "\xef\x87\x89", // U+f1c9 + "FileContract": "\xef\x95\xac", // U+f56c + "FileCsv": "\xef\x9b\x9d", // U+f6dd + "FileExcel": "\xef\x87\x83", // U+f1c3 + "FileExport": "\xef\x95\xae", // U+f56e + "FileFragment": "\xee\x9a\x97", // U+e697 + "FileHalfDashed": "\xee\x9a\x98", // U+e698 + "FileImage": "\xef\x87\x85", // U+f1c5 + "FileImport": "\xef\x95\xaf", // U+f56f + "FileInvoice": "\xef\x95\xb0", // U+f570 + "FileInvoiceDollar": "\xef\x95\xb1", // U+f571 + "FileLines": "\xef\x85\x9c", // U+f15c + "FileMedical": "\xef\x91\xb7", // U+f477 + "FilePdf": "\xef\x87\x81", // U+f1c1 + "FilePen": "\xef\x8c\x9c", // U+f31c + "FilePowerpoint": "\xef\x87\x84", // U+f1c4 + "FilePrescription": "\xef\x95\xb2", // U+f572 + "FileShield": "\xee\x93\xb0", // U+e4f0 + "FileSignature": "\xef\x95\xb3", // U+f573 + "FileVideo": "\xef\x87\x88", // U+f1c8 + "FileWaveform": "\xef\x91\xb8", // U+f478 + "FileWord": "\xef\x87\x82", // U+f1c2 + "FileZipper": "\xef\x87\x86", // U+f1c6 + "Fill": "\xef\x95\xb5", // U+f575 + "FillDrip": "\xef\x95\xb6", // U+f576 + "Film": "\xef\x80\x88", // U+f008 + "Filter": "\xef\x82\xb0", // U+f0b0 + "FilterCircleDollar": "\xef\x99\xa2", // U+f662 + "FilterCircleXmark": "\xee\x85\xbb", // U+e17b + "Fingerprint": "\xef\x95\xb7", // U+f577 + "Fire": "\xef\x81\xad", // U+f06d + "FireBurner": "\xee\x93\xb1", // U+e4f1 + "FireExtinguisher": "\xef\x84\xb4", // U+f134 + "FireFlameCurved": "\xef\x9f\xa4", // U+f7e4 + "FireFlameSimple": "\xef\x91\xaa", // U+f46a + "Fish": "\xef\x95\xb8", // U+f578 + "FishFins": "\xee\x93\xb2", // U+e4f2 + "Flag": "\xef\x80\xa4", // U+f024 + "FlagCheckered": "\xef\x84\x9e", // U+f11e + "FlagUsa": "\xef\x9d\x8d", // U+f74d + "Flask": "\xef\x83\x83", // U+f0c3 + "FlaskVial": "\xee\x93\xb3", // U+e4f3 + "FloppyDisk": "\xef\x83\x87", // U+f0c7 + "FlorinSign": "\xee\x86\x84", // U+e184 + "Folder": "\xef\x81\xbb", // U+f07b + "FolderClosed": "\xee\x86\x85", // U+e185 + "FolderMinus": "\xef\x99\x9d", // U+f65d + "FolderOpen": "\xef\x81\xbc", // U+f07c + "FolderPlus": "\xef\x99\x9e", // U+f65e + "FolderTree": "\xef\xa0\x82", // U+f802 + "Font": "\xef\x80\xb1", // U+f031 + "FontAwesome": "\xef\x8a\xb4", // U+f2b4 + "Football": "\xef\x91\x8e", // U+f44e + "Forward": "\xef\x81\x8e", // U+f04e + "ForwardFast": "\xef\x81\x90", // U+f050 + "ForwardStep": "\xef\x81\x91", // U+f051 + "FrancSign": "\xee\x86\x8f", // U+e18f + "Frog": "\xef\x94\xae", // U+f52e + "Futbol": "\xef\x87\xa3", // U+f1e3 + "G": "G", // U+0047 + "Gamepad": "\xef\x84\x9b", // U+f11b + "GasPump": "\xef\x94\xaf", // U+f52f + "Gauge": "\xef\x98\xa4", // U+f624 + "GaugeHigh": "\xef\x98\xa5", // U+f625 + "GaugeSimple": "\xef\x98\xa9", // U+f629 + "GaugeSimpleHigh": "\xef\x98\xaa", // U+f62a + "Gavel": "\xef\x83\xa3", // U+f0e3 + "Gear": "\xef\x80\x93", // U+f013 + "Gears": "\xef\x82\x85", // U+f085 + "Gem": "\xef\x8e\xa5", // U+f3a5 + "Gemini": "\xee\xa1\x89", // U+e849 + "Genderless": "\xef\x88\xad", // U+f22d + "Ghost": "\xef\x9b\xa2", // U+f6e2 + "Gift": "\xef\x81\xab", // U+f06b + "Gifts": "\xef\x9e\x9c", // U+f79c + "GlassWater": "\xee\x93\xb4", // U+e4f4 + "GlassWaterDroplet": "\xee\x93\xb5", // U+e4f5 + "Glasses": "\xef\x94\xb0", // U+f530 + "Globe": "\xef\x82\xac", // U+f0ac + "GolfBallTee": "\xef\x91\x90", // U+f450 + "Gopuram": "\xef\x99\xa4", // U+f664 + "GraduationCap": "\xef\x86\x9d", // U+f19d + "GreaterThan": ">", // U+003e + "GreaterThanEqual": "\xef\x94\xb2", // U+f532 + "Grip": "\xef\x96\x8d", // U+f58d + "GripLines": "\xef\x9e\xa4", // U+f7a4 + "GripLinesVertical": "\xef\x9e\xa5", // U+f7a5 + "GripVertical": "\xef\x96\x8e", // U+f58e + "GroupArrowsRotate": "\xee\x93\xb6", // U+e4f6 + "GuaraniSign": "\xee\x86\x9a", // U+e19a + "Guitar": "\xef\x9e\xa6", // U+f7a6 + "Gun": "\xee\x86\x9b", // U+e19b + "H": "H", // U+0048 + "Hammer": "\xef\x9b\xa3", // U+f6e3 + "Hamsa": "\xef\x99\xa5", // U+f665 + "Hand": "\xef\x89\x96", // U+f256 + "HandBackFist": "\xef\x89\x95", // U+f255 + "HandDots": "\xef\x91\xa1", // U+f461 + "HandFist": "\xef\x9b\x9e", // U+f6de + "HandHolding": "\xef\x92\xbd", // U+f4bd + "HandHoldingDollar": "\xef\x93\x80", // U+f4c0 + "HandHoldingDroplet": "\xef\x93\x81", // U+f4c1 + "HandHoldingHand": "\xee\x93\xb7", // U+e4f7 + "HandHoldingHeart": "\xef\x92\xbe", // U+f4be + "HandHoldingMedical": "\xee\x81\x9c", // U+e05c + "HandLizard": "\xef\x89\x98", // U+f258 + "HandMiddleFinger": "\xef\xa0\x86", // U+f806 + "HandPeace": "\xef\x89\x9b", // U+f25b + "HandPointDown": "\xef\x82\xa7", // U+f0a7 + "HandPointLeft": "\xef\x82\xa5", // U+f0a5 + "HandPointRight": "\xef\x82\xa4", // U+f0a4 + "HandPointUp": "\xef\x82\xa6", // U+f0a6 + "HandPointer": "\xef\x89\x9a", // U+f25a + "HandScissors": "\xef\x89\x97", // U+f257 + "HandSparkles": "\xee\x81\x9d", // U+e05d + "HandSpock": "\xef\x89\x99", // U+f259 + "Handcuffs": "\xee\x93\xb8", // U+e4f8 + "Hands": "\xef\x8a\xa7", // U+f2a7 + "HandsAslInterpreting": "\xef\x8a\xa3", // U+f2a3 + "HandsBound": "\xee\x93\xb9", // U+e4f9 + "HandsBubbles": "\xee\x81\x9e", // U+e05e + "HandsClapping": "\xee\x86\xa8", // U+e1a8 + "HandsHolding": "\xef\x93\x82", // U+f4c2 + "HandsHoldingChild": "\xee\x93\xba", // U+e4fa + "HandsHoldingCircle": "\xee\x93\xbb", // U+e4fb + "HandsPraying": "\xef\x9a\x84", // U+f684 + "Handshake": "\xef\x8a\xb5", // U+f2b5 + "HandshakeAngle": "\xef\x93\x84", // U+f4c4 + "HandshakeSlash": "\xee\x81\xa0", // U+e060 + "Hanukiah": "\xef\x9b\xa6", // U+f6e6 + "HardDrive": "\xef\x82\xa0", // U+f0a0 + "Hashtag": "#", // U+0023 + "HatCowboy": "\xef\xa3\x80", // U+f8c0 + "HatCowboySide": "\xef\xa3\x81", // U+f8c1 + "HatWizard": "\xef\x9b\xa8", // U+f6e8 + "HeadSideCough": "\xee\x81\xa1", // U+e061 + "HeadSideCoughSlash": "\xee\x81\xa2", // U+e062 + "HeadSideMask": "\xee\x81\xa3", // U+e063 + "HeadSideVirus": "\xee\x81\xa4", // U+e064 + "Heading": "\xef\x87\x9c", // U+f1dc + "Headphones": "\xef\x80\xa5", // U+f025 + "Headset": "\xef\x96\x90", // U+f590 + "Heart": "\xef\x80\x84", // U+f004 + "HeartCircleBolt": "\xee\x93\xbc", // U+e4fc + "HeartCircleCheck": "\xee\x93\xbd", // U+e4fd + "HeartCircleExclamation": "\xee\x93\xbe", // U+e4fe + "HeartCircleMinus": "\xee\x93\xbf", // U+e4ff + "HeartCirclePlus": "\xee\x94\x80", // U+e500 + "HeartCircleXmark": "\xee\x94\x81", // U+e501 + "HeartCrack": "\xef\x9e\xa9", // U+f7a9 + "HeartPulse": "\xef\x88\x9e", // U+f21e + "Helicopter": "\xef\x94\xb3", // U+f533 + "HelicopterSymbol": "\xee\x94\x82", // U+e502 + "HelmetSafety": "\xef\xa0\x87", // U+f807 + "HelmetUn": "\xee\x94\x83", // U+e503 + "Hexagon": "\xef\x8c\x92", // U+f312 + "HexagonNodes": "\xee\x9a\x99", // U+e699 + "HexagonNodesBolt": "\xee\x9a\x9a", // U+e69a + "Highlighter": "\xef\x96\x91", // U+f591 + "HillAvalanche": "\xee\x94\x87", // U+e507 + "HillRockslide": "\xee\x94\x88", // U+e508 + "Hippo": "\xef\x9b\xad", // U+f6ed + "HockeyPuck": "\xef\x91\x93", // U+f453 + "HollyBerry": "\xef\x9e\xaa", // U+f7aa + "Horse": "\xef\x9b\xb0", // U+f6f0 + "HorseHead": "\xef\x9e\xab", // U+f7ab + "Hospital": "\xef\x83\xb8", // U+f0f8 + "HospitalUser": "\xef\xa0\x8d", // U+f80d + "HotTubPerson": "\xef\x96\x93", // U+f593 + "Hotdog": "\xef\xa0\x8f", // U+f80f + "Hotel": "\xef\x96\x94", // U+f594 + "Hourglass": "\xef\x89\x94", // U+f254 + "HourglassEnd": "\xef\x89\x93", // U+f253 + "HourglassHalf": "\xef\x89\x92", // U+f252 + "HourglassStart": "\xef\x89\x91", // U+f251 + "House": "\xef\x80\x95", // U+f015 + "HouseChimney": "\xee\x8e\xaf", // U+e3af + "HouseChimneyCrack": "\xef\x9b\xb1", // U+f6f1 + "HouseChimneyMedical": "\xef\x9f\xb2", // U+f7f2 + "HouseChimneyUser": "\xee\x81\xa5", // U+e065 + "HouseChimneyWindow": "\xee\x80\x8d", // U+e00d + "HouseCircleCheck": "\xee\x94\x89", // U+e509 + "HouseCircleExclamation": "\xee\x94\x8a", // U+e50a + "HouseCircleXmark": "\xee\x94\x8b", // U+e50b + "HouseCrack": "\xee\x8e\xb1", // U+e3b1 + "HouseFire": "\xee\x94\x8c", // U+e50c + "HouseFlag": "\xee\x94\x8d", // U+e50d + "HouseFloodWater": "\xee\x94\x8e", // U+e50e + "HouseFloodWaterCircleArrowRight": "\xee\x94\x8f", // U+e50f + "HouseLaptop": "\xee\x81\xa6", // U+e066 + "HouseLock": "\xee\x94\x90", // U+e510 + "HouseMedical": "\xee\x8e\xb2", // U+e3b2 + "HouseMedicalCircleCheck": "\xee\x94\x91", // U+e511 + "HouseMedicalCircleExclamation": "\xee\x94\x92", // U+e512 + "HouseMedicalCircleXmark": "\xee\x94\x93", // U+e513 + "HouseMedicalFlag": "\xee\x94\x94", // U+e514 + "HouseSignal": "\xee\x80\x92", // U+e012 + "HouseTsunami": "\xee\x94\x95", // U+e515 + "HouseUser": "\xee\x86\xb0", // U+e1b0 + "HryvniaSign": "\xef\x9b\xb2", // U+f6f2 + "Hurricane": "\xef\x9d\x91", // U+f751 + "I": "I", // U+0049 + "ICursor": "\xef\x89\x86", // U+f246 + "IceCream": "\xef\xa0\x90", // U+f810 + "Icicles": "\xef\x9e\xad", // U+f7ad + "Icons": "\xef\xa1\xad", // U+f86d + "IdBadge": "\xef\x8b\x81", // U+f2c1 + "IdCard": "\xef\x8b\x82", // U+f2c2 + "IdCardClip": "\xef\x91\xbf", // U+f47f + "Igloo": "\xef\x9e\xae", // U+f7ae + "Image": "\xef\x80\xbe", // U+f03e + "ImagePortrait": "\xef\x8f\xa0", // U+f3e0 + "Images": "\xef\x8c\x82", // U+f302 + "Inbox": "\xef\x80\x9c", // U+f01c + "Indent": "\xef\x80\xbc", // U+f03c + "IndianRupeeSign": "\xee\x86\xbc", // U+e1bc + "Industry": "\xef\x89\xb5", // U+f275 + "Infinity": "\xef\x94\xb4", // U+f534 + "Info": "\xef\x84\xa9", // U+f129 + "Italic": "\xef\x80\xb3", // U+f033 + "J": "J", // U+004a + "Jar": "\xee\x94\x96", // U+e516 + "JarWheat": "\xee\x94\x97", // U+e517 + "Jedi": "\xef\x99\xa9", // U+f669 + "JetFighter": "\xef\x83\xbb", // U+f0fb + "JetFighterUp": "\xee\x94\x98", // U+e518 + "Joint": "\xef\x96\x95", // U+f595 + "JugDetergent": "\xee\x94\x99", // U+e519 + "K": "K", // U+004b + "Kaaba": "\xef\x99\xab", // U+f66b + "Key": "\xef\x82\x84", // U+f084 + "Keyboard": "\xef\x84\x9c", // U+f11c + "Khanda": "\xef\x99\xad", // U+f66d + "KipSign": "\xee\x87\x84", // U+e1c4 + "KitMedical": "\xef\x91\xb9", // U+f479 + "KitchenSet": "\xee\x94\x9a", // U+e51a + "KiwiBird": "\xef\x94\xb5", // U+f535 + "L": "L", // U+004c + "LandMineOn": "\xee\x94\x9b", // U+e51b + "Landmark": "\xef\x99\xaf", // U+f66f + "LandmarkDome": "\xef\x9d\x92", // U+f752 + "LandmarkFlag": "\xee\x94\x9c", // U+e51c + "Language": "\xef\x86\xab", // U+f1ab + "Laptop": "\xef\x84\x89", // U+f109 + "LaptopCode": "\xef\x97\xbc", // U+f5fc + "LaptopFile": "\xee\x94\x9d", // U+e51d + "LaptopMedical": "\xef\xa0\x92", // U+f812 + "LariSign": "\xee\x87\x88", // U+e1c8 + "LayerGroup": "\xef\x97\xbd", // U+f5fd + "Leaf": "\xef\x81\xac", // U+f06c + "LeftLong": "\xef\x8c\x8a", // U+f30a + "LeftRight": "\xef\x8c\xb7", // U+f337 + "Lemon": "\xef\x82\x94", // U+f094 + "Leo": "\xee\xa1\x8a", // U+e84a + "LessThan": "<", // U+003c + "LessThanEqual": "\xef\x94\xb7", // U+f537 + "Libra": "\xee\xa1\x8b", // U+e84b + "LifeRing": "\xef\x87\x8d", // U+f1cd + "Lightbulb": "\xef\x83\xab", // U+f0eb + "LinesLeaning": "\xee\x94\x9e", // U+e51e + "Link": "\xef\x83\x81", // U+f0c1 + "LinkSlash": "\xef\x84\xa7", // U+f127 + "LiraSign": "\xef\x86\x95", // U+f195 + "List": "\xef\x80\xba", // U+f03a + "ListCheck": "\xef\x82\xae", // U+f0ae + "ListOl": "\xef\x83\x8b", // U+f0cb + "ListUl": "\xef\x83\x8a", // U+f0ca + "LitecoinSign": "\xee\x87\x93", // U+e1d3 + "LocationArrow": "\xef\x84\xa4", // U+f124 + "LocationCrosshairs": "\xef\x98\x81", // U+f601 + "LocationDot": "\xef\x8f\x85", // U+f3c5 + "LocationPin": "\xef\x81\x81", // U+f041 + "LocationPinLock": "\xee\x94\x9f", // U+e51f + "Lock": "\xef\x80\xa3", // U+f023 + "LockOpen": "\xef\x8f\x81", // U+f3c1 + "Locust": "\xee\x94\xa0", // U+e520 + "Lungs": "\xef\x98\x84", // U+f604 + "LungsVirus": "\xee\x81\xa7", // U+e067 + "M": "M", // U+004d + "Magnet": "\xef\x81\xb6", // U+f076 + "MagnifyingGlass": "\xef\x80\x82", // U+f002 + "MagnifyingGlassArrowRight": "\xee\x94\xa1", // U+e521 + "MagnifyingGlassChart": "\xee\x94\xa2", // U+e522 + "MagnifyingGlassDollar": "\xef\x9a\x88", // U+f688 + "MagnifyingGlassLocation": "\xef\x9a\x89", // U+f689 + "MagnifyingGlassMinus": "\xef\x80\x90", // U+f010 + "MagnifyingGlassPlus": "\xef\x80\x8e", // U+f00e + "ManatSign": "\xee\x87\x95", // U+e1d5 + "Map": "\xef\x89\xb9", // U+f279 + "MapLocation": "\xef\x96\x9f", // U+f59f + "MapLocationDot": "\xef\x96\xa0", // U+f5a0 + "MapPin": "\xef\x89\xb6", // U+f276 + "Marker": "\xef\x96\xa1", // U+f5a1 + "Mars": "\xef\x88\xa2", // U+f222 + "MarsAndVenus": "\xef\x88\xa4", // U+f224 + "MarsAndVenusBurst": "\xee\x94\xa3", // U+e523 + "MarsDouble": "\xef\x88\xa7", // U+f227 + "MarsStroke": "\xef\x88\xa9", // U+f229 + "MarsStrokeRight": "\xef\x88\xab", // U+f22b + "MarsStrokeUp": "\xef\x88\xaa", // U+f22a + "MartiniGlass": "\xef\x95\xbb", // U+f57b + "MartiniGlassCitrus": "\xef\x95\xa1", // U+f561 + "MartiniGlassEmpty": "\xef\x80\x80", // U+f000 + "Mask": "\xef\x9b\xba", // U+f6fa + "MaskFace": "\xee\x87\x97", // U+e1d7 + "MaskVentilator": "\xee\x94\xa4", // U+e524 + "MasksTheater": "\xef\x98\xb0", // U+f630 + "MattressPillow": "\xee\x94\xa5", // U+e525 + "Maximize": "\xef\x8c\x9e", // U+f31e + "Medal": "\xef\x96\xa2", // U+f5a2 + "Memory": "\xef\x94\xb8", // U+f538 + "Menorah": "\xef\x99\xb6", // U+f676 + "Mercury": "\xef\x88\xa3", // U+f223 + "Message": "\xef\x89\xba", // U+f27a + "Meteor": "\xef\x9d\x93", // U+f753 + "Microchip": "\xef\x8b\x9b", // U+f2db + "Microphone": "\xef\x84\xb0", // U+f130 + "MicrophoneLines": "\xef\x8f\x89", // U+f3c9 + "MicrophoneLinesSlash": "\xef\x94\xb9", // U+f539 + "MicrophoneSlash": "\xef\x84\xb1", // U+f131 + "Microscope": "\xef\x98\x90", // U+f610 + "MillSign": "\xee\x87\xad", // U+e1ed + "Minimize": "\xef\x9e\x8c", // U+f78c + "Minus": "\xef\x81\xa8", // U+f068 + "Mitten": "\xef\x9e\xb5", // U+f7b5 + "Mobile": "\xef\x8f\x8e", // U+f3ce + "MobileButton": "\xef\x84\x8b", // U+f10b + "MobileRetro": "\xee\x94\xa7", // U+e527 + "MobileScreen": "\xef\x8f\x8f", // U+f3cf + "MobileScreenButton": "\xef\x8f\x8d", // U+f3cd + "MobileVibrate": "\xee\xa0\x96", // U+e816 + "MoneyBill": "\xef\x83\x96", // U+f0d6 + "MoneyBill1": "\xef\x8f\x91", // U+f3d1 + "MoneyBill1Wave": "\xef\x94\xbb", // U+f53b + "MoneyBillTransfer": "\xee\x94\xa8", // U+e528 + "MoneyBillTrendUp": "\xee\x94\xa9", // U+e529 + "MoneyBillWave": "\xef\x94\xba", // U+f53a + "MoneyBillWheat": "\xee\x94\xaa", // U+e52a + "MoneyBills": "\xee\x87\xb3", // U+e1f3 + "MoneyCheck": "\xef\x94\xbc", // U+f53c + "MoneyCheckDollar": "\xef\x94\xbd", // U+f53d + "Monument": "\xef\x96\xa6", // U+f5a6 + "Moon": "\xef\x86\x86", // U+f186 + "MortarPestle": "\xef\x96\xa7", // U+f5a7 + "Mosque": "\xef\x99\xb8", // U+f678 + "Mosquito": "\xee\x94\xab", // U+e52b + "MosquitoNet": "\xee\x94\xac", // U+e52c + "Motorcycle": "\xef\x88\x9c", // U+f21c + "Mound": "\xee\x94\xad", // U+e52d + "Mountain": "\xef\x9b\xbc", // U+f6fc + "MountainCity": "\xee\x94\xae", // U+e52e + "MountainSun": "\xee\x94\xaf", // U+e52f + "MugHot": "\xef\x9e\xb6", // U+f7b6 + "MugSaucer": "\xef\x83\xb4", // U+f0f4 + "Music": "\xef\x80\x81", // U+f001 + "N": "N", // U+004e + "NairaSign": "\xee\x87\xb6", // U+e1f6 + "NetworkWired": "\xef\x9b\xbf", // U+f6ff + "Neuter": "\xef\x88\xac", // U+f22c + "Newspaper": "\xef\x87\xaa", // U+f1ea + "NonBinary": "\xee\xa0\x87", // U+e807 + "NotEqual": "\xef\x94\xbe", // U+f53e + "Notdef": "\xee\x87\xbe", // U+e1fe + "NoteSticky": "\xef\x89\x89", // U+f249 + "NotesMedical": "\xef\x92\x81", // U+f481 + "O": "O", // U+004f + "ObjectGroup": "\xef\x89\x87", // U+f247 + "ObjectUngroup": "\xef\x89\x88", // U+f248 + "Octagon": "\xef\x8c\x86", // U+f306 + "OilCan": "\xef\x98\x93", // U+f613 + "OilWell": "\xee\x94\xb2", // U+e532 + "Om": "\xef\x99\xb9", // U+f679 + "Otter": "\xef\x9c\x80", // U+f700 + "Outdent": "\xef\x80\xbb", // U+f03b + "P": "P", // U+0050 + "Pager": "\xef\xa0\x95", // U+f815 + "PaintRoller": "\xef\x96\xaa", // U+f5aa + "Paintbrush": "\xef\x87\xbc", // U+f1fc + "Palette": "\xef\x94\xbf", // U+f53f + "Pallet": "\xef\x92\x82", // U+f482 + "Panorama": "\xee\x88\x89", // U+e209 + "PaperPlane": "\xef\x87\x98", // U+f1d8 + "Paperclip": "\xef\x83\x86", // U+f0c6 + "ParachuteBox": "\xef\x93\x8d", // U+f4cd + "Paragraph": "\xef\x87\x9d", // U+f1dd + "Passport": "\xef\x96\xab", // U+f5ab + "Paste": "\xef\x83\xaa", // U+f0ea + "Pause": "\xef\x81\x8c", // U+f04c + "Paw": "\xef\x86\xb0", // U+f1b0 + "Peace": "\xef\x99\xbc", // U+f67c + "Pen": "\xef\x8c\x84", // U+f304 + "PenClip": "\xef\x8c\x85", // U+f305 + "PenFancy": "\xef\x96\xac", // U+f5ac + "PenNib": "\xef\x96\xad", // U+f5ad + "PenRuler": "\xef\x96\xae", // U+f5ae + "PenToSquare": "\xef\x81\x84", // U+f044 + "Pencil": "\xef\x8c\x83", // U+f303 + "Pentagon": "\xee\x9e\x90", // U+e790 + "PeopleArrows": "\xee\x81\xa8", // U+e068 + "PeopleCarryBox": "\xef\x93\x8e", // U+f4ce + "PeopleGroup": "\xee\x94\xb3", // U+e533 + "PeopleLine": "\xee\x94\xb4", // U+e534 + "PeoplePulling": "\xee\x94\xb5", // U+e535 + "PeopleRobbery": "\xee\x94\xb6", // U+e536 + "PeopleRoof": "\xee\x94\xb7", // U+e537 + "PepperHot": "\xef\xa0\x96", // U+f816 + "Percent": "%", // U+0025 + "Person": "\xef\x86\x83", // U+f183 + "PersonArrowDownToLine": "\xee\x94\xb8", // U+e538 + "PersonArrowUpFromLine": "\xee\x94\xb9", // U+e539 + "PersonBiking": "\xef\xa1\x8a", // U+f84a + "PersonBooth": "\xef\x9d\x96", // U+f756 + "PersonBreastfeeding": "\xee\x94\xba", // U+e53a + "PersonBurst": "\xee\x94\xbb", // U+e53b + "PersonCane": "\xee\x94\xbc", // U+e53c + "PersonChalkboard": "\xee\x94\xbd", // U+e53d + "PersonCircleCheck": "\xee\x94\xbe", // U+e53e + "PersonCircleExclamation": "\xee\x94\xbf", // U+e53f + "PersonCircleMinus": "\xee\x95\x80", // U+e540 + "PersonCirclePlus": "\xee\x95\x81", // U+e541 + "PersonCircleQuestion": "\xee\x95\x82", // U+e542 + "PersonCircleXmark": "\xee\x95\x83", // U+e543 + "PersonDigging": "\xef\xa1\x9e", // U+f85e + "PersonDotsFromLine": "\xef\x91\xb0", // U+f470 + "PersonDress": "\xef\x86\x82", // U+f182 + "PersonDressBurst": "\xee\x95\x84", // U+e544 + "PersonDrowning": "\xee\x95\x85", // U+e545 + "PersonFalling": "\xee\x95\x86", // U+e546 + "PersonFallingBurst": "\xee\x95\x87", // U+e547 + "PersonHalfDress": "\xee\x95\x88", // U+e548 + "PersonHarassing": "\xee\x95\x89", // U+e549 + "PersonHiking": "\xef\x9b\xac", // U+f6ec + "PersonMilitaryPointing": "\xee\x95\x8a", // U+e54a + "PersonMilitaryRifle": "\xee\x95\x8b", // U+e54b + "PersonMilitaryToPerson": "\xee\x95\x8c", // U+e54c + "PersonPraying": "\xef\x9a\x83", // U+f683 + "PersonPregnant": "\xee\x8c\x9e", // U+e31e + "PersonRays": "\xee\x95\x8d", // U+e54d + "PersonRifle": "\xee\x95\x8e", // U+e54e + "PersonRunning": "\xef\x9c\x8c", // U+f70c + "PersonShelter": "\xee\x95\x8f", // U+e54f + "PersonSkating": "\xef\x9f\x85", // U+f7c5 + "PersonSkiing": "\xef\x9f\x89", // U+f7c9 + "PersonSkiingNordic": "\xef\x9f\x8a", // U+f7ca + "PersonSnowboarding": "\xef\x9f\x8e", // U+f7ce + "PersonSwimming": "\xef\x97\x84", // U+f5c4 + "PersonThroughWindow": "\xee\x96\xa9", // U+e5a9 + "PersonWalking": "\xef\x95\x94", // U+f554 + "PersonWalkingArrowLoopLeft": "\xee\x95\x91", // U+e551 + "PersonWalkingArrowRight": "\xee\x95\x92", // U+e552 + "PersonWalkingDashedLineArrowRight": "\xee\x95\x93", // U+e553 + "PersonWalkingLuggage": "\xee\x95\x94", // U+e554 + "PersonWalkingWithCane": "\xef\x8a\x9d", // U+f29d + "PesetaSign": "\xee\x88\xa1", // U+e221 + "PesoSign": "\xee\x88\xa2", // U+e222 + "Phone": "\xef\x82\x95", // U+f095 + "PhoneFlip": "\xef\xa1\xb9", // U+f879 + "PhoneSlash": "\xef\x8f\x9d", // U+f3dd + "PhoneVolume": "\xef\x8a\xa0", // U+f2a0 + "PhotoFilm": "\xef\xa1\xbc", // U+f87c + "PictureInPicture": "\xee\xa0\x8b", // U+e80b + "PiggyBank": "\xef\x93\x93", // U+f4d3 + "Pills": "\xef\x92\x84", // U+f484 + "Pisces": "\xee\xa1\x8c", // U+e84c + "PizzaSlice": "\xef\xa0\x98", // U+f818 + "PlaceOfWorship": "\xef\x99\xbf", // U+f67f + "Plane": "\xef\x81\xb2", // U+f072 + "PlaneArrival": "\xef\x96\xaf", // U+f5af + "PlaneCircleCheck": "\xee\x95\x95", // U+e555 + "PlaneCircleExclamation": "\xee\x95\x96", // U+e556 + "PlaneCircleXmark": "\xee\x95\x97", // U+e557 + "PlaneDeparture": "\xef\x96\xb0", // U+f5b0 + "PlaneLock": "\xee\x95\x98", // U+e558 + "PlaneSlash": "\xee\x81\xa9", // U+e069 + "PlaneUp": "\xee\x88\xad", // U+e22d + "PlantWilt": "\xee\x96\xaa", // U+e5aa + "PlateWheat": "\xee\x95\x9a", // U+e55a + "Play": "\xef\x81\x8b", // U+f04b + "Plug": "\xef\x87\xa6", // U+f1e6 + "PlugCircleBolt": "\xee\x95\x9b", // U+e55b + "PlugCircleCheck": "\xee\x95\x9c", // U+e55c + "PlugCircleExclamation": "\xee\x95\x9d", // U+e55d + "PlugCircleMinus": "\xee\x95\x9e", // U+e55e + "PlugCirclePlus": "\xee\x95\x9f", // U+e55f + "PlugCircleXmark": "\xee\x95\xa0", // U+e560 + "Plus": "+", // U+002b + "PlusMinus": "\xee\x90\xbc", // U+e43c + "Podcast": "\xef\x8b\x8e", // U+f2ce + "Poo": "\xef\x8b\xbe", // U+f2fe + "PooStorm": "\xef\x9d\x9a", // U+f75a + "Poop": "\xef\x98\x99", // U+f619 + "PowerOff": "\xef\x80\x91", // U+f011 + "Prescription": "\xef\x96\xb1", // U+f5b1 + "PrescriptionBottle": "\xef\x92\x85", // U+f485 + "PrescriptionBottleMedical": "\xef\x92\x86", // U+f486 + "Print": "\xef\x80\xaf", // U+f02f + "PumpMedical": "\xee\x81\xaa", // U+e06a + "PumpSoap": "\xee\x81\xab", // U+e06b + "PuzzlePiece": "\xef\x84\xae", // U+f12e + "Q": "Q", // U+0051 + "Qrcode": "\xef\x80\xa9", // U+f029 + "Question": "?", // U+003f + "QuoteLeft": "\xef\x84\x8d", // U+f10d + "QuoteRight": "\xef\x84\x8e", // U+f10e + "R": "R", // U+0052 + "Radiation": "\xef\x9e\xb9", // U+f7b9 + "Radio": "\xef\xa3\x97", // U+f8d7 + "Rainbow": "\xef\x9d\x9b", // U+f75b + "RankingStar": "\xee\x95\xa1", // U+e561 + "Receipt": "\xef\x95\x83", // U+f543 + "RecordVinyl": "\xef\xa3\x99", // U+f8d9 + "RectangleAd": "\xef\x99\x81", // U+f641 + "RectangleList": "\xef\x80\xa2", // U+f022 + "RectangleXmark": "\xef\x90\x90", // U+f410 + "Recycle": "\xef\x86\xb8", // U+f1b8 + "Registered": "\xef\x89\x9d", // U+f25d + "Repeat": "\xef\x8d\xa3", // U+f363 + "Reply": "\xef\x8f\xa5", // U+f3e5 + "ReplyAll": "\xef\x84\xa2", // U+f122 + "Republican": "\xef\x9d\x9e", // U+f75e + "Restroom": "\xef\x9e\xbd", // U+f7bd + "Retweet": "\xef\x81\xb9", // U+f079 + "Ribbon": "\xef\x93\x96", // U+f4d6 + "RightFromBracket": "\xef\x8b\xb5", // U+f2f5 + "RightLeft": "\xef\x8d\xa2", // U+f362 + "RightLong": "\xef\x8c\x8b", // U+f30b + "RightToBracket": "\xef\x8b\xb6", // U+f2f6 + "Ring": "\xef\x9c\x8b", // U+f70b + "Road": "\xef\x80\x98", // U+f018 + "RoadBarrier": "\xee\x95\xa2", // U+e562 + "RoadBridge": "\xee\x95\xa3", // U+e563 + "RoadCircleCheck": "\xee\x95\xa4", // U+e564 + "RoadCircleExclamation": "\xee\x95\xa5", // U+e565 + "RoadCircleXmark": "\xee\x95\xa6", // U+e566 + "RoadLock": "\xee\x95\xa7", // U+e567 + "RoadSpikes": "\xee\x95\xa8", // U+e568 + "Robot": "\xef\x95\x84", // U+f544 + "Rocket": "\xef\x84\xb5", // U+f135 + "Rotate": "\xef\x8b\xb1", // U+f2f1 + "RotateLeft": "\xef\x8b\xaa", // U+f2ea + "RotateRight": "\xef\x8b\xb9", // U+f2f9 + "Route": "\xef\x93\x97", // U+f4d7 + "Rss": "\xef\x82\x9e", // U+f09e + "RubleSign": "\xef\x85\x98", // U+f158 + "Rug": "\xee\x95\xa9", // U+e569 + "Ruler": "\xef\x95\x85", // U+f545 + "RulerCombined": "\xef\x95\x86", // U+f546 + "RulerHorizontal": "\xef\x95\x87", // U+f547 + "RulerVertical": "\xef\x95\x88", // U+f548 + "RupeeSign": "\xef\x85\x96", // U+f156 + "RupiahSign": "\xee\x88\xbd", // U+e23d + "S": "S", // U+0053 + "SackDollar": "\xef\xa0\x9d", // U+f81d + "SackXmark": "\xee\x95\xaa", // U+e56a + "Sagittarius": "\xee\xa1\x8d", // U+e84d + "Sailboat": "\xee\x91\x85", // U+e445 + "Satellite": "\xef\x9e\xbf", // U+f7bf + "SatelliteDish": "\xef\x9f\x80", // U+f7c0 + "ScaleBalanced": "\xef\x89\x8e", // U+f24e + "ScaleUnbalanced": "\xef\x94\x95", // U+f515 + "ScaleUnbalancedFlip": "\xef\x94\x96", // U+f516 + "School": "\xef\x95\x89", // U+f549 + "SchoolCircleCheck": "\xee\x95\xab", // U+e56b + "SchoolCircleExclamation": "\xee\x95\xac", // U+e56c + "SchoolCircleXmark": "\xee\x95\xad", // U+e56d + "SchoolFlag": "\xee\x95\xae", // U+e56e + "SchoolLock": "\xee\x95\xaf", // U+e56f + "Scissors": "\xef\x83\x84", // U+f0c4 + "Scorpio": "\xee\xa1\x8e", // U+e84e + "Screwdriver": "\xef\x95\x8a", // U+f54a + "ScrewdriverWrench": "\xef\x9f\x99", // U+f7d9 + "Scroll": "\xef\x9c\x8e", // U+f70e + "ScrollTorah": "\xef\x9a\xa0", // U+f6a0 + "SdCard": "\xef\x9f\x82", // U+f7c2 + "Section": "\xee\x91\x87", // U+e447 + "Seedling": "\xef\x93\x98", // U+f4d8 + "Septagon": "\xee\xa0\xa0", // U+e820 + "Server": "\xef\x88\xb3", // U+f233 + "Shapes": "\xef\x98\x9f", // U+f61f + "Share": "\xef\x81\xa4", // U+f064 + "ShareFromSquare": "\xef\x85\x8d", // U+f14d + "ShareNodes": "\xef\x87\xa0", // U+f1e0 + "SheetPlastic": "\xee\x95\xb1", // U+e571 + "ShekelSign": "\xef\x88\x8b", // U+f20b + "Shield": "\xef\x84\xb2", // U+f132 + "ShieldCat": "\xee\x95\xb2", // U+e572 + "ShieldDog": "\xee\x95\xb3", // U+e573 + "ShieldHalved": "\xef\x8f\xad", // U+f3ed + "ShieldHeart": "\xee\x95\xb4", // U+e574 + "ShieldVirus": "\xee\x81\xac", // U+e06c + "Ship": "\xef\x88\x9a", // U+f21a + "Shirt": "\xef\x95\x93", // U+f553 + "ShoePrints": "\xef\x95\x8b", // U+f54b + "Shop": "\xef\x95\x8f", // U+f54f + "ShopLock": "\xee\x92\xa5", // U+e4a5 + "ShopSlash": "\xee\x81\xb0", // U+e070 + "Shower": "\xef\x8b\x8c", // U+f2cc + "Shrimp": "\xee\x91\x88", // U+e448 + "Shuffle": "\xef\x81\xb4", // U+f074 + "ShuttleSpace": "\xef\x86\x97", // U+f197 + "SignHanging": "\xef\x93\x99", // U+f4d9 + "Signal": "\xef\x80\x92", // U+f012 + "Signature": "\xef\x96\xb7", // U+f5b7 + "SignsPost": "\xef\x89\xb7", // U+f277 + "SimCard": "\xef\x9f\x84", // U+f7c4 + "SingleQuoteLeft": "\xee\xa0\x9b", // U+e81b + "SingleQuoteRight": "\xee\xa0\x9c", // U+e81c + "Sink": "\xee\x81\xad", // U+e06d + "Sitemap": "\xef\x83\xa8", // U+f0e8 + "Skull": "\xef\x95\x8c", // U+f54c + "SkullCrossbones": "\xef\x9c\x94", // U+f714 + "Slash": "\xef\x9c\x95", // U+f715 + "Sleigh": "\xef\x9f\x8c", // U+f7cc + "Sliders": "\xef\x87\x9e", // U+f1de + "Smog": "\xef\x9d\x9f", // U+f75f + "Smoking": "\xef\x92\x8d", // U+f48d + "Snowflake": "\xef\x8b\x9c", // U+f2dc + "Snowman": "\xef\x9f\x90", // U+f7d0 + "Snowplow": "\xef\x9f\x92", // U+f7d2 + "Soap": "\xee\x81\xae", // U+e06e + "Socks": "\xef\x9a\x96", // U+f696 + "SolarPanel": "\xef\x96\xba", // U+f5ba + "Sort": "\xef\x83\x9c", // U+f0dc + "SortDown": "\xef\x83\x9d", // U+f0dd + "SortUp": "\xef\x83\x9e", // U+f0de + "Spa": "\xef\x96\xbb", // U+f5bb + "SpaghettiMonsterFlying": "\xef\x99\xbb", // U+f67b + "SpellCheck": "\xef\xa2\x91", // U+f891 + "Spider": "\xef\x9c\x97", // U+f717 + "Spinner": "\xef\x84\x90", // U+f110 + "Spiral": "\xee\xa0\x8a", // U+e80a + "Splotch": "\xef\x96\xbc", // U+f5bc + "Spoon": "\xef\x8b\xa5", // U+f2e5 + "SprayCan": "\xef\x96\xbd", // U+f5bd + "SprayCanSparkles": "\xef\x97\x90", // U+f5d0 + "Square": "\xef\x83\x88", // U+f0c8 + "SquareArrowUpRight": "\xef\x85\x8c", // U+f14c + "SquareBinary": "\xee\x9a\x9b", // U+e69b + "SquareCaretDown": "\xef\x85\x90", // U+f150 + "SquareCaretLeft": "\xef\x86\x91", // U+f191 + "SquareCaretRight": "\xef\x85\x92", // U+f152 + "SquareCaretUp": "\xef\x85\x91", // U+f151 + "SquareCheck": "\xef\x85\x8a", // U+f14a + "SquareEnvelope": "\xef\x86\x99", // U+f199 + "SquareFull": "\xef\x91\x9c", // U+f45c + "SquareH": "\xef\x83\xbd", // U+f0fd + "SquareMinus": "\xef\x85\x86", // U+f146 + "SquareNfi": "\xee\x95\xb6", // U+e576 + "SquareParking": "\xef\x95\x80", // U+f540 + "SquarePen": "\xef\x85\x8b", // U+f14b + "SquarePersonConfined": "\xee\x95\xb7", // U+e577 + "SquarePhone": "\xef\x82\x98", // U+f098 + "SquarePhoneFlip": "\xef\xa1\xbb", // U+f87b + "SquarePlus": "\xef\x83\xbe", // U+f0fe + "SquarePollHorizontal": "\xef\x9a\x82", // U+f682 + "SquarePollVertical": "\xef\x9a\x81", // U+f681 + "SquareRootVariable": "\xef\x9a\x98", // U+f698 + "SquareRss": "\xef\x85\x83", // U+f143 + "SquareShareNodes": "\xef\x87\xa1", // U+f1e1 + "SquareUpRight": "\xef\x8d\xa0", // U+f360 + "SquareVirus": "\xee\x95\xb8", // U+e578 + "SquareXmark": "\xef\x8b\x93", // U+f2d3 + "StaffSnake": "\xee\x95\xb9", // U+e579 + "Stairs": "\xee\x8a\x89", // U+e289 + "Stamp": "\xef\x96\xbf", // U+f5bf + "Stapler": "\xee\x96\xaf", // U+e5af + "Star": "\xef\x80\x85", // U+f005 + "StarAndCrescent": "\xef\x9a\x99", // U+f699 + "StarHalf": "\xef\x82\x89", // U+f089 + "StarHalfStroke": "\xef\x97\x80", // U+f5c0 + "StarOfDavid": "\xef\x9a\x9a", // U+f69a + "StarOfLife": "\xef\x98\xa1", // U+f621 + "SterlingSign": "\xef\x85\x94", // U+f154 + "Stethoscope": "\xef\x83\xb1", // U+f0f1 + "Stop": "\xef\x81\x8d", // U+f04d + "Stopwatch": "\xef\x8b\xb2", // U+f2f2 + "Stopwatch20": "\xee\x81\xaf", // U+e06f + "Store": "\xef\x95\x8e", // U+f54e + "StoreSlash": "\xee\x81\xb1", // U+e071 + "StreetView": "\xef\x88\x9d", // U+f21d + "Strikethrough": "\xef\x83\x8c", // U+f0cc + "Stroopwafel": "\xef\x95\x91", // U+f551 + "Subscript": "\xef\x84\xac", // U+f12c + "Suitcase": "\xef\x83\xb2", // U+f0f2 + "SuitcaseMedical": "\xef\x83\xba", // U+f0fa + "SuitcaseRolling": "\xef\x97\x81", // U+f5c1 + "Sun": "\xef\x86\x85", // U+f185 + "SunPlantWilt": "\xee\x95\xba", // U+e57a + "Superscript": "\xef\x84\xab", // U+f12b + "Swatchbook": "\xef\x97\x83", // U+f5c3 + "Synagogue": "\xef\x9a\x9b", // U+f69b + "Syringe": "\xef\x92\x8e", // U+f48e + "T": "T", // U+0054 + "Table": "\xef\x83\x8e", // U+f0ce + "TableCells": "\xef\x80\x8a", // U+f00a + "TableCellsColumnLock": "\xee\x99\xb8", // U+e678 + "TableCellsLarge": "\xef\x80\x89", // U+f009 + "TableCellsRowLock": "\xee\x99\xba", // U+e67a + "TableCellsRowUnlock": "\xee\x9a\x91", // U+e691 + "TableColumns": "\xef\x83\x9b", // U+f0db + "TableList": "\xef\x80\x8b", // U+f00b + "TableTennisPaddleBall": "\xef\x91\x9d", // U+f45d + "Tablet": "\xef\x8f\xbb", // U+f3fb + "TabletButton": "\xef\x84\x8a", // U+f10a + "TabletScreenButton": "\xef\x8f\xba", // U+f3fa + "Tablets": "\xef\x92\x90", // U+f490 + "TachographDigital": "\xef\x95\xa6", // U+f566 + "Tag": "\xef\x80\xab", // U+f02b + "Tags": "\xef\x80\xac", // U+f02c + "Tape": "\xef\x93\x9b", // U+f4db + "Tarp": "\xee\x95\xbb", // U+e57b + "TarpDroplet": "\xee\x95\xbc", // U+e57c + "Taurus": "\xee\xa1\x8f", // U+e84f + "Taxi": "\xef\x86\xba", // U+f1ba + "Teeth": "\xef\x98\xae", // U+f62e + "TeethOpen": "\xef\x98\xaf", // U+f62f + "TemperatureArrowDown": "\xee\x80\xbf", // U+e03f + "TemperatureArrowUp": "\xee\x81\x80", // U+e040 + "TemperatureEmpty": "\xef\x8b\x8b", // U+f2cb + "TemperatureFull": "\xef\x8b\x87", // U+f2c7 + "TemperatureHalf": "\xef\x8b\x89", // U+f2c9 + "TemperatureHigh": "\xef\x9d\xa9", // U+f769 + "TemperatureLow": "\xef\x9d\xab", // U+f76b + "TemperatureQuarter": "\xef\x8b\x8a", // U+f2ca + "TemperatureThreeQuarters": "\xef\x8b\x88", // U+f2c8 + "TengeSign": "\xef\x9f\x97", // U+f7d7 + "Tent": "\xee\x95\xbd", // U+e57d + "TentArrowDownToLine": "\xee\x95\xbe", // U+e57e + "TentArrowLeftRight": "\xee\x95\xbf", // U+e57f + "TentArrowTurnLeft": "\xee\x96\x80", // U+e580 + "TentArrowsDown": "\xee\x96\x81", // U+e581 + "Tents": "\xee\x96\x82", // U+e582 + "Terminal": "\xef\x84\xa0", // U+f120 + "TextHeight": "\xef\x80\xb4", // U+f034 + "TextSlash": "\xef\xa1\xbd", // U+f87d + "TextWidth": "\xef\x80\xb5", // U+f035 + "Thermometer": "\xef\x92\x91", // U+f491 + "ThumbsDown": "\xef\x85\xa5", // U+f165 + "ThumbsUp": "\xef\x85\xa4", // U+f164 + "Thumbtack": "\xef\x82\x8d", // U+f08d + "ThumbtackSlash": "\xee\x9a\x8f", // U+e68f + "Ticket": "\xef\x85\x85", // U+f145 + "TicketSimple": "\xef\x8f\xbf", // U+f3ff + "Timeline": "\xee\x8a\x9c", // U+e29c + "ToggleOff": "\xef\x88\x84", // U+f204 + "ToggleOn": "\xef\x88\x85", // U+f205 + "Toilet": "\xef\x9f\x98", // U+f7d8 + "ToiletPaper": "\xef\x9c\x9e", // U+f71e + "ToiletPaperSlash": "\xee\x81\xb2", // U+e072 + "ToiletPortable": "\xee\x96\x83", // U+e583 + "ToiletsPortable": "\xee\x96\x84", // U+e584 + "Toolbox": "\xef\x95\x92", // U+f552 + "Tooth": "\xef\x97\x89", // U+f5c9 + "ToriiGate": "\xef\x9a\xa1", // U+f6a1 + "Tornado": "\xef\x9d\xaf", // U+f76f + "TowerBroadcast": "\xef\x94\x99", // U+f519 + "TowerCell": "\xee\x96\x85", // U+e585 + "TowerObservation": "\xee\x96\x86", // U+e586 + "Tractor": "\xef\x9c\xa2", // U+f722 + "Trademark": "\xef\x89\x9c", // U+f25c + "TrafficLight": "\xef\x98\xb7", // U+f637 + "Trailer": "\xee\x81\x81", // U+e041 + "Train": "\xef\x88\xb8", // U+f238 + "TrainSubway": "\xef\x88\xb9", // U+f239 + "TrainTram": "\xee\x96\xb4", // U+e5b4 + "Transgender": "\xef\x88\xa5", // U+f225 + "Trash": "\xef\x87\xb8", // U+f1f8 + "TrashArrowUp": "\xef\xa0\xa9", // U+f829 + "TrashCan": "\xef\x8b\xad", // U+f2ed + "TrashCanArrowUp": "\xef\xa0\xaa", // U+f82a + "Tree": "\xef\x86\xbb", // U+f1bb + "TreeCity": "\xee\x96\x87", // U+e587 + "TriangleExclamation": "\xef\x81\xb1", // U+f071 + "Trophy": "\xef\x82\x91", // U+f091 + "Trowel": "\xee\x96\x89", // U+e589 + "TrowelBricks": "\xee\x96\x8a", // U+e58a + "Truck": "\xef\x83\x91", // U+f0d1 + "TruckArrowRight": "\xee\x96\x8b", // U+e58b + "TruckDroplet": "\xee\x96\x8c", // U+e58c + "TruckFast": "\xef\x92\x8b", // U+f48b + "TruckField": "\xee\x96\x8d", // U+e58d + "TruckFieldUn": "\xee\x96\x8e", // U+e58e + "TruckFront": "\xee\x8a\xb7", // U+e2b7 + "TruckMedical": "\xef\x83\xb9", // U+f0f9 + "TruckMonster": "\xef\x98\xbb", // U+f63b + "TruckMoving": "\xef\x93\x9f", // U+f4df + "TruckPickup": "\xef\x98\xbc", // U+f63c + "TruckPlane": "\xee\x96\x8f", // U+e58f + "TruckRampBox": "\xef\x93\x9e", // U+f4de + "Tty": "\xef\x87\xa4", // U+f1e4 + "TurkishLiraSign": "\xee\x8a\xbb", // U+e2bb + "TurnDown": "\xef\x8e\xbe", // U+f3be + "TurnUp": "\xef\x8e\xbf", // U+f3bf + "Tv": "\xef\x89\xac", // U+f26c + "U": "U", // U+0055 + "Umbrella": "\xef\x83\xa9", // U+f0e9 + "UmbrellaBeach": "\xef\x97\x8a", // U+f5ca + "Underline": "\xef\x83\x8d", // U+f0cd + "UniversalAccess": "\xef\x8a\x9a", // U+f29a + "Unlock": "\xef\x82\x9c", // U+f09c + "UnlockKeyhole": "\xef\x84\xbe", // U+f13e + "UpDown": "\xef\x8c\xb8", // U+f338 + "UpDownLeftRight": "\xef\x82\xb2", // U+f0b2 + "UpLong": "\xef\x8c\x8c", // U+f30c + "UpRightAndDownLeftFromCenter": "\xef\x90\xa4", // U+f424 + "UpRightFromSquare": "\xef\x8d\x9d", // U+f35d + "Upload": "\xef\x82\x93", // U+f093 + "User": "\xef\x80\x87", // U+f007 + "UserAstronaut": "\xef\x93\xbb", // U+f4fb + "UserCheck": "\xef\x93\xbc", // U+f4fc + "UserClock": "\xef\x93\xbd", // U+f4fd + "UserDoctor": "\xef\x83\xb0", // U+f0f0 + "UserGear": "\xef\x93\xbe", // U+f4fe + "UserGraduate": "\xef\x94\x81", // U+f501 + "UserGroup": "\xef\x94\x80", // U+f500 + "UserInjured": "\xef\x9c\xa8", // U+f728 + "UserLock": "\xef\x94\x82", // U+f502 + "UserMinus": "\xef\x94\x83", // U+f503 + "UserNinja": "\xef\x94\x84", // U+f504 + "UserNurse": "\xef\xa0\xaf", // U+f82f + "UserPen": "\xef\x93\xbf", // U+f4ff + "UserPlus": "\xef\x88\xb4", // U+f234 + "UserSecret": "\xef\x88\x9b", // U+f21b + "UserShield": "\xef\x94\x85", // U+f505 + "UserSlash": "\xef\x94\x86", // U+f506 + "UserTag": "\xef\x94\x87", // U+f507 + "UserTie": "\xef\x94\x88", // U+f508 + "UserXmark": "\xef\x88\xb5", // U+f235 + "Users": "\xef\x83\x80", // U+f0c0 + "UsersBetweenLines": "\xee\x96\x91", // U+e591 + "UsersGear": "\xef\x94\x89", // U+f509 + "UsersLine": "\xee\x96\x92", // U+e592 + "UsersRays": "\xee\x96\x93", // U+e593 + "UsersRectangle": "\xee\x96\x94", // U+e594 + "UsersSlash": "\xee\x81\xb3", // U+e073 + "UsersViewfinder": "\xee\x96\x95", // U+e595 + "Utensils": "\xef\x8b\xa7", // U+f2e7 + "V": "V", // U+0056 + "VanShuttle": "\xef\x96\xb6", // U+f5b6 + "Vault": "\xee\x8b\x85", // U+e2c5 + "Venus": "\xef\x88\xa1", // U+f221 + "VenusDouble": "\xef\x88\xa6", // U+f226 + "VenusMars": "\xef\x88\xa8", // U+f228 + "Vest": "\xee\x82\x85", // U+e085 + "VestPatches": "\xee\x82\x86", // U+e086 + "Vial": "\xef\x92\x92", // U+f492 + "VialCircleCheck": "\xee\x96\x96", // U+e596 + "VialVirus": "\xee\x96\x97", // U+e597 + "Vials": "\xef\x92\x93", // U+f493 + "Video": "\xef\x80\xbd", // U+f03d + "VideoSlash": "\xef\x93\xa2", // U+f4e2 + "Vihara": "\xef\x9a\xa7", // U+f6a7 + "Virgo": "\xee\xa1\x90", // U+e850 + "Virus": "\xee\x81\xb4", // U+e074 + "VirusCovid": "\xee\x92\xa8", // U+e4a8 + "VirusCovidSlash": "\xee\x92\xa9", // U+e4a9 + "VirusSlash": "\xee\x81\xb5", // U+e075 + "Viruses": "\xee\x81\xb6", // U+e076 + "Voicemail": "\xef\xa2\x97", // U+f897 + "Volcano": "\xef\x9d\xb0", // U+f770 + "Volleyball": "\xef\x91\x9f", // U+f45f + "Volume": "\xef\x9a\xa8", // U+f6a8 + "VolumeHigh": "\xef\x80\xa8", // U+f028 + "VolumeLow": "\xef\x80\xa7", // U+f027 + "VolumeOff": "\xef\x80\xa6", // U+f026 + "VolumeXmark": "\xef\x9a\xa9", // U+f6a9 + "VrCardboard": "\xef\x9c\xa9", // U+f729 + "W": "W", // U+0057 + "WalkieTalkie": "\xef\xa3\xaf", // U+f8ef + "Wallet": "\xef\x95\x95", // U+f555 + "WandMagic": "\xef\x83\x90", // U+f0d0 + "WandMagicSparkles": "\xee\x8b\x8a", // U+e2ca + "WandSparkles": "\xef\x9c\xab", // U+f72b + "Warehouse": "\xef\x92\x94", // U+f494 + "Water": "\xef\x9d\xb3", // U+f773 + "WaterLadder": "\xef\x97\x85", // U+f5c5 + "WaveSquare": "\xef\xa0\xbe", // U+f83e + "WebAwesome": "\xee\x9a\x82", // U+e682 + "WeightHanging": "\xef\x97\x8d", // U+f5cd + "WeightScale": "\xef\x92\x96", // U+f496 + "WheatAwn": "\xee\x8b\x8d", // U+e2cd + "WheatAwnCircleExclamation": "\xee\x96\x98", // U+e598 + "Wheelchair": "\xef\x86\x93", // U+f193 + "WheelchairMove": "\xee\x8b\x8e", // U+e2ce + "WhiskeyGlass": "\xef\x9e\xa0", // U+f7a0 + "Wifi": "\xef\x87\xab", // U+f1eb + "Wind": "\xef\x9c\xae", // U+f72e + "WindowMaximize": "\xef\x8b\x90", // U+f2d0 + "WindowMinimize": "\xef\x8b\x91", // U+f2d1 + "WindowRestore": "\xef\x8b\x92", // U+f2d2 + "WineBottle": "\xef\x9c\xaf", // U+f72f + "WineGlass": "\xef\x93\xa3", // U+f4e3 + "WineGlassEmpty": "\xef\x97\x8e", // U+f5ce + "WonSign": "\xef\x85\x99", // U+f159 + "Worm": "\xee\x96\x99", // U+e599 + "Wrench": "\xef\x82\xad", // U+f0ad + "X": "X", // U+0058 + "XRay": "\xef\x92\x97", // U+f497 + "Xmark": "\xef\x80\x8d", // U+f00d + "XmarksLines": "\xee\x96\x9a", // U+e59a + "Y": "Y", // U+0059 + "YenSign": "\xef\x85\x97", // U+f157 + "YinYang": "\xef\x9a\xad", // U+f6ad + "Z": "Z", // U+005a +} + +var fa7BrandsIcons = map[string]string{ + "42Group": "\xee\x82\x80", // U+e080 + "500px": "\xef\x89\xae", // U+f26e + "AccessibleIcon": "\xef\x8d\xa8", // U+f368 + "Accusoft": "\xef\x8d\xa9", // U+f369 + "Adn": "\xef\x85\xb0", // U+f170 + "Adversal": "\xef\x8d\xaa", // U+f36a + "Affiliatetheme": "\xef\x8d\xab", // U+f36b + "Airbnb": "\xef\xa0\xb4", // U+f834 + "Algolia": "\xef\x8d\xac", // U+f36c + "Alipay": "\xef\x99\x82", // U+f642 + "Amazon": "\xef\x89\xb0", // U+f270 + "AmazonPay": "\xef\x90\xac", // U+f42c + "Amilia": "\xef\x8d\xad", // U+f36d + "Android": "\xef\x85\xbb", // U+f17b + "Angellist": "\xef\x88\x89", // U+f209 + "Angrycreative": "\xef\x8d\xae", // U+f36e + "Angular": "\xef\x90\xa0", // U+f420 + "AppStore": "\xef\x8d\xaf", // U+f36f + "AppStoreIos": "\xef\x8d\xb0", // U+f370 + "Apper": "\xef\x8d\xb1", // U+f371 + "Apple": "\xef\x85\xb9", // U+f179 + "ApplePay": "\xef\x90\x95", // U+f415 + "ArchLinux": "\xee\xa1\xa7", // U+e867 + "Artstation": "\xef\x9d\xba", // U+f77a + "Asymmetrik": "\xef\x8d\xb2", // U+f372 + "Atlassian": "\xef\x9d\xbb", // U+f77b + "Audible": "\xef\x8d\xb3", // U+f373 + "Autoprefixer": "\xef\x90\x9c", // U+f41c + "Avianex": "\xef\x8d\xb4", // U+f374 + "Aviato": "\xef\x90\xa1", // U+f421 + "Aws": "\xef\x8d\xb5", // U+f375 + "Bandcamp": "\xef\x8b\x95", // U+f2d5 + "BattleNet": "\xef\xa0\xb5", // U+f835 + "Behance": "\xef\x86\xb4", // U+f1b4 + "Bilibili": "\xee\x8f\x99", // U+e3d9 + "Bimobject": "\xef\x8d\xb8", // U+f378 + "Bitbucket": "\xef\x85\xb1", // U+f171 + "Bitcoin": "\xef\x8d\xb9", // U+f379 + "Bity": "\xef\x8d\xba", // U+f37a + "BlackTie": "\xef\x89\xbe", // U+f27e + "Blackberry": "\xef\x8d\xbb", // U+f37b + "Blogger": "\xef\x8d\xbc", // U+f37c + "BloggerB": "\xef\x8d\xbd", // U+f37d + "Bluesky": "\xee\x99\xb1", // U+e671 + "Bluetooth": "\xef\x8a\x93", // U+f293 + "BluetoothB": "\xef\x8a\x94", // U+f294 + "BoardGameGeek": "\xee\xa1\x95", // U+e855 + "Bootstrap": "\xef\xa0\xb6", // U+f836 + "Bots": "\xee\x8d\x80", // U+e340 + "Brave": "\xee\x98\xbc", // U+e63c + "BraveReverse": "\xee\x98\xbd", // U+e63d + "Btc": "\xef\x85\x9a", // U+f15a + "Buffer": "\xef\xa0\xb7", // U+f837 + "Buromobelexperte": "\xef\x8d\xbf", // U+f37f + "BuyNLarge": "\xef\xa2\xa6", // U+f8a6 + "Buysellads": "\xef\x88\x8d", // U+f20d + "CanadianMapleLeaf": "\xef\x9e\x85", // U+f785 + "CashApp": "\xee\x9f\x94", // U+e7d4 + "CcAmazonPay": "\xef\x90\xad", // U+f42d + "CcAmex": "\xef\x87\xb3", // U+f1f3 + "CcApplePay": "\xef\x90\x96", // U+f416 + "CcDinersClub": "\xef\x89\x8c", // U+f24c + "CcDiscover": "\xef\x87\xb2", // U+f1f2 + "CcJcb": "\xef\x89\x8b", // U+f24b + "CcMastercard": "\xef\x87\xb1", // U+f1f1 + "CcPaypal": "\xef\x87\xb4", // U+f1f4 + "CcStripe": "\xef\x87\xb5", // U+f1f5 + "CcVisa": "\xef\x87\xb0", // U+f1f0 + "Centercode": "\xef\x8e\x80", // U+f380 + "Centos": "\xef\x9e\x89", // U+f789 + "Chrome": "\xef\x89\xa8", // U+f268 + "Chromecast": "\xef\xa0\xb8", // U+f838 + "CircleZulip": "\xee\xa1\x91", // U+e851 + "Claude": "\xee\xa1\xa1", // U+e861 + "Cloudflare": "\xee\x81\xbd", // U+e07d + "Cloudscale": "\xef\x8e\x83", // U+f383 + "Cloudsmith": "\xef\x8e\x84", // U+f384 + "Cloudversify": "\xef\x8e\x85", // U+f385 + "Cmplid": "\xee\x8d\xa0", // U+e360 + "Codepen": "\xef\x87\x8b", // U+f1cb + "Codiepie": "\xef\x8a\x84", // U+f284 + "Confluence": "\xef\x9e\x8d", // U+f78d + "Connectdevelop": "\xef\x88\x8e", // U+f20e + "Contao": "\xef\x89\xad", // U+f26d + "CottonBureau": "\xef\xa2\x9e", // U+f89e + "Cpanel": "\xef\x8e\x88", // U+f388 + "CreativeCommons": "\xef\x89\x9e", // U+f25e + "CreativeCommonsBy": "\xef\x93\xa7", // U+f4e7 + "CreativeCommonsNc": "\xef\x93\xa8", // U+f4e8 + "CreativeCommonsNcEu": "\xef\x93\xa9", // U+f4e9 + "CreativeCommonsNcJp": "\xef\x93\xaa", // U+f4ea + "CreativeCommonsNd": "\xef\x93\xab", // U+f4eb + "CreativeCommonsPd": "\xef\x93\xac", // U+f4ec + "CreativeCommonsPdAlt": "\xef\x93\xad", // U+f4ed + "CreativeCommonsRemix": "\xef\x93\xae", // U+f4ee + "CreativeCommonsSa": "\xef\x93\xaf", // U+f4ef + "CreativeCommonsSampling": "\xef\x93\xb0", // U+f4f0 + "CreativeCommonsSamplingPlus": "\xef\x93\xb1", // U+f4f1 + "CreativeCommonsShare": "\xef\x93\xb2", // U+f4f2 + "CreativeCommonsZero": "\xef\x93\xb3", // U+f4f3 + "CriticalRole": "\xef\x9b\x89", // U+f6c9 + "Css": "\xee\x9a\xa2", // U+e6a2 + "Css3": "\xef\x84\xbc", // U+f13c + "Css3Alt": "\xef\x8e\x8b", // U+f38b + "Cuttlefish": "\xef\x8e\x8c", // U+f38c + "DAndD": "\xef\x8e\x8d", // U+f38d + "DAndDBeyond": "\xef\x9b\x8a", // U+f6ca + "Dailymotion": "\xee\x81\x92", // U+e052 + "DartLang": "\xee\x9a\x93", // U+e693 + "Dashcube": "\xef\x88\x90", // U+f210 + "Debian": "\xee\x98\x8b", // U+e60b + "Deezer": "\xee\x81\xb7", // U+e077 + "Delicious": "\xef\x86\xa5", // U+f1a5 + "Deploydog": "\xef\x8e\x8e", // U+f38e + "Deskpro": "\xef\x8e\x8f", // U+f38f + "Dev": "\xef\x9b\x8c", // U+f6cc + "Deviantart": "\xef\x86\xbd", // U+f1bd + "Dhl": "\xef\x9e\x90", // U+f790 + "Diaspora": "\xef\x9e\x91", // U+f791 + "Digg": "\xef\x86\xa6", // U+f1a6 + "DigitalOcean": "\xef\x8e\x91", // U+f391 + "Discord": "\xef\x8e\x92", // U+f392 + "Discourse": "\xef\x8e\x93", // U+f393 + "Disqus": "\xee\x9f\x95", // U+e7d5 + "Dochub": "\xef\x8e\x94", // U+f394 + "Docker": "\xef\x8e\x95", // U+f395 + "Draft2digital": "\xef\x8e\x96", // U+f396 + "Dribbble": "\xef\x85\xbd", // U+f17d + "Dropbox": "\xef\x85\xab", // U+f16b + "Drupal": "\xef\x86\xa9", // U+f1a9 + "Duolingo": "\xee\xa0\x92", // U+e812 + "Dyalog": "\xef\x8e\x99", // U+f399 + "Earlybirds": "\xef\x8e\x9a", // U+f39a + "Ebay": "\xef\x93\xb4", // U+f4f4 + "Edge": "\xef\x8a\x82", // U+f282 + "EdgeLegacy": "\xee\x81\xb8", // U+e078 + "Elementor": "\xef\x90\xb0", // U+f430 + "Eleventy": "\xee\x9f\x96", // U+e7d6 + "Ello": "\xef\x97\xb1", // U+f5f1 + "Ember": "\xef\x90\xa3", // U+f423 + "Empire": "\xef\x87\x91", // U+f1d1 + "Envira": "\xef\x8a\x99", // U+f299 + "Erlang": "\xef\x8e\x9d", // U+f39d + "Ethereum": "\xef\x90\xae", // U+f42e + "Etsy": "\xef\x8b\x97", // U+f2d7 + "Evernote": "\xef\xa0\xb9", // U+f839 + "Expeditedssl": "\xef\x88\xbe", // U+f23e + "Facebook": "\xef\x82\x9a", // U+f09a + "FacebookF": "\xef\x8e\x9e", // U+f39e + "FacebookMessenger": "\xef\x8e\x9f", // U+f39f + "FantasyFlightGames": "\xef\x9b\x9c", // U+f6dc + "Fedex": "\xef\x9e\x97", // U+f797 + "Fediverse": "\xee\xa1\xa5", // U+e865 + "Fedora": "\xef\x9e\x98", // U+f798 + "Figma": "\xef\x9e\x99", // U+f799 + "FilesPinwheel": "\xee\x9a\x9f", // U+e69f + "Firefox": "\xef\x89\xa9", // U+f269 + "FirefoxBrowser": "\xee\x80\x87", // U+e007 + "FirstOrder": "\xef\x8a\xb0", // U+f2b0 + "FirstOrderAlt": "\xef\x94\x8a", // U+f50a + "Firstdraft": "\xef\x8e\xa1", // U+f3a1 + "Flickr": "\xef\x85\xae", // U+f16e + "Flipboard": "\xef\x91\x8d", // U+f44d + "Flutter": "\xee\x9a\x94", // U+e694 + "Fly": "\xef\x90\x97", // U+f417 + "FontAwesome": "\xef\x8a\xb4", // U+f2b4 + "Fonticons": "\xef\x8a\x80", // U+f280 + "FonticonsFi": "\xef\x8e\xa2", // U+f3a2 + "Forgejo": "\xee\xa1\xa0", // U+e860 + "FortAwesome": "\xef\x8a\x86", // U+f286 + "FortAwesomeAlt": "\xef\x8e\xa3", // U+f3a3 + "Forumbee": "\xef\x88\x91", // U+f211 + "Foursquare": "\xef\x86\x80", // U+f180 + "FreeCodeCamp": "\xef\x8b\x85", // U+f2c5 + "Freebsd": "\xef\x8e\xa4", // U+f3a4 + "Fulcrum": "\xef\x94\x8b", // U+f50b + "GalacticRepublic": "\xef\x94\x8c", // U+f50c + "GalacticSenate": "\xef\x94\x8d", // U+f50d + "GetPocket": "\xef\x89\xa5", // U+f265 + "Gg": "\xef\x89\xa0", // U+f260 + "GgCircle": "\xef\x89\xa1", // U+f261 + "Git": "\xef\x87\x93", // U+f1d3 + "GitAlt": "\xef\xa1\x81", // U+f841 + "Gitee": "\xee\xa1\xa3", // U+e863 + "Github": "\xef\x82\x9b", // U+f09b + "GithubAlt": "\xef\x84\x93", // U+f113 + "Gitkraken": "\xef\x8e\xa6", // U+f3a6 + "Gitlab": "\xef\x8a\x96", // U+f296 + "Gitter": "\xef\x90\xa6", // U+f426 + "Glide": "\xef\x8a\xa5", // U+f2a5 + "GlideG": "\xef\x8a\xa6", // U+f2a6 + "Globaleaks": "\xee\xa1\x9d", // U+e85d + "Gofore": "\xef\x8e\xa7", // U+f3a7 + "Golang": "\xee\x90\x8f", // U+e40f + "Goodreads": "\xef\x8e\xa8", // U+f3a8 + "GoodreadsG": "\xef\x8e\xa9", // U+f3a9 + "Google": "\xef\x86\xa0", // U+f1a0 + "GoogleDrive": "\xef\x8e\xaa", // U+f3aa + "GooglePay": "\xee\x81\xb9", // U+e079 + "GooglePlay": "\xef\x8e\xab", // U+f3ab + "GooglePlus": "\xef\x8a\xb3", // U+f2b3 + "GooglePlusG": "\xef\x83\x95", // U+f0d5 + "GoogleScholar": "\xee\x98\xbb", // U+e63b + "GoogleWallet": "\xef\x87\xae", // U+f1ee + "Gratipay": "\xef\x86\x84", // U+f184 + "Grav": "\xef\x8b\x96", // U+f2d6 + "Gripfire": "\xef\x8e\xac", // U+f3ac + "Grunt": "\xef\x8e\xad", // U+f3ad + "Guilded": "\xee\x81\xbe", // U+e07e + "Gulp": "\xef\x8e\xae", // U+f3ae + "HackerNews": "\xef\x87\x94", // U+f1d4 + "Hackerrank": "\xef\x97\xb7", // U+f5f7 + "Hashnode": "\xee\x92\x99", // U+e499 + "Hips": "\xef\x91\x92", // U+f452 + "HireAHelper": "\xef\x8e\xb0", // U+f3b0 + "Hive": "\xee\x81\xbf", // U+e07f + "Hooli": "\xef\x90\xa7", // U+f427 + "Hornbill": "\xef\x96\x92", // U+f592 + "Hotjar": "\xef\x8e\xb1", // U+f3b1 + "Houzz": "\xef\x89\xbc", // U+f27c + "Html5": "\xef\x84\xbb", // U+f13b + "Hubspot": "\xef\x8e\xb2", // U+f3b2 + "HuggingFace": "\xee\xa1\xa9", // U+e869 + "Ideal": "\xee\x80\x93", // U+e013 + "Imdb": "\xef\x8b\x98", // U+f2d8 + "Instagram": "\xef\x85\xad", // U+f16d + "Instalod": "\xee\x82\x81", // U+e081 + "Intercom": "\xef\x9e\xaf", // U+f7af + "InternetExplorer": "\xef\x89\xab", // U+f26b + "Invision": "\xef\x9e\xb0", // U+f7b0 + "Ioxhost": "\xef\x88\x88", // U+f208 + "ItchIo": "\xef\xa0\xba", // U+f83a + "Itunes": "\xef\x8e\xb4", // U+f3b4 + "ItunesNote": "\xef\x8e\xb5", // U+f3b5 + "Java": "\xef\x93\xa4", // U+f4e4 + "JediOrder": "\xef\x94\x8e", // U+f50e + "Jenkins": "\xef\x8e\xb6", // U+f3b6 + "Jira": "\xef\x9e\xb1", // U+f7b1 + "Joget": "\xef\x8e\xb7", // U+f3b7 + "Joomla": "\xef\x86\xaa", // U+f1aa + "Js": "\xef\x8e\xb8", // U+f3b8 + "Jsfiddle": "\xef\x87\x8c", // U+f1cc + "Julia": "\xee\xa1\x92", // U+e852 + "Jxl": "\xee\x99\xbb", // U+e67b + "Kaggle": "\xef\x97\xba", // U+f5fa + "KakaoTalk": "\xee\x9f\x97", // U+e7d7 + "Keybase": "\xef\x93\xb5", // U+f4f5 + "Keycdn": "\xef\x8e\xba", // U+f3ba + "Kickstarter": "\xef\x8e\xbb", // U+f3bb + "KickstarterK": "\xef\x8e\xbc", // U+f3bc + "KoFi": "\xee\xa1\x96", // U+e856 + "Korvue": "\xef\x90\xaf", // U+f42f + "Kubernetes": "\xee\xa1\x97", // U+e857 + "Laravel": "\xef\x8e\xbd", // U+f3bd + "Lastfm": "\xef\x88\x82", // U+f202 + "Leanpub": "\xef\x88\x92", // U+f212 + "Leetcode": "\xee\xa1\xaa", // U+e86a + "Less": "\xef\x90\x9d", // U+f41d + "Letterboxd": "\xee\x98\xad", // U+e62d + "Line": "\xef\x8f\x80", // U+f3c0 + "Linkedin": "\xef\x82\x8c", // U+f08c + "LinkedinIn": "\xef\x83\xa1", // U+f0e1 + "Linktree": "\xee\x9f\x98", // U+e7d8 + "Linode": "\xef\x8a\xb8", // U+f2b8 + "Linux": "\xef\x85\xbc", // U+f17c + "Lumon": "\xee\x9f\xa2", // U+e7e2 + "LumonDrop": "\xee\x9f\xa3", // U+e7e3 + "Lyft": "\xef\x8f\x83", // U+f3c3 + "Magento": "\xef\x8f\x84", // U+f3c4 + "Mailchimp": "\xef\x96\x9e", // U+f59e + "Mandalorian": "\xef\x94\x8f", // U+f50f + "Markdown": "\xef\x98\x8f", // U+f60f + "Mastodon": "\xef\x93\xb6", // U+f4f6 + "Maxcdn": "\xef\x84\xb6", // U+f136 + "Mdb": "\xef\xa3\x8a", // U+f8ca + "Medapps": "\xef\x8f\x86", // U+f3c6 + "Medium": "\xef\x88\xba", // U+f23a + "Medrt": "\xef\x8f\x88", // U+f3c8 + "Meetup": "\xef\x8b\xa0", // U+f2e0 + "Megaport": "\xef\x96\xa3", // U+f5a3 + "Mendeley": "\xef\x9e\xb3", // U+f7b3 + "Meta": "\xee\x92\x9b", // U+e49b + "Microblog": "\xee\x80\x9a", // U+e01a + "Microsoft": "\xef\x8f\x8a", // U+f3ca + "Mintbit": "\xee\x98\xaf", // U+e62f + "Mix": "\xef\x8f\x8b", // U+f3cb + "Mixcloud": "\xef\x8a\x89", // U+f289 + "Mixer": "\xee\x81\x96", // U+e056 + "Mizuni": "\xef\x8f\x8c", // U+f3cc + "Modx": "\xef\x8a\x85", // U+f285 + "Monero": "\xef\x8f\x90", // U+f3d0 + "Napster": "\xef\x8f\x92", // U+f3d2 + "Neos": "\xef\x98\x92", // U+f612 + "NfcDirectional": "\xee\x94\xb0", // U+e530 + "NfcSymbol": "\xee\x94\xb1", // U+e531 + "Nimblr": "\xef\x96\xa8", // U+f5a8 + "Node": "\xef\x90\x99", // U+f419 + "NodeJs": "\xef\x8f\x93", // U+f3d3 + "Notion": "\xee\x9f\x99", // U+e7d9 + "Npm": "\xef\x8f\x94", // U+f3d4 + "Ns8": "\xef\x8f\x95", // U+f3d5 + "Nutritionix": "\xef\x8f\x96", // U+f3d6 + "Obsidian": "\xee\xa1\xb9", // U+e879 + "OctopusDeploy": "\xee\x82\x82", // U+e082 + "Odnoklassniki": "\xef\x89\xa3", // U+f263 + "Odysee": "\xee\x97\x86", // U+e5c6 + "OldRepublic": "\xef\x94\x90", // U+f510 + "Openai": "\xee\x9f\x8f", // U+e7cf + "Opencart": "\xef\x88\xbd", // U+f23d + "Openid": "\xef\x86\x9b", // U+f19b + "Openstreetmap": "\xee\xa1\xab", // U+e86b + "Opensuse": "\xee\x98\xab", // U+e62b + "Opera": "\xef\x89\xaa", // U+f26a + "OptinMonster": "\xef\x88\xbc", // U+f23c + "Orcid": "\xef\xa3\x92", // U+f8d2 + "Osi": "\xef\x90\x9a", // U+f41a + "Padlet": "\xee\x92\xa0", // U+e4a0 + "Page4": "\xef\x8f\x97", // U+f3d7 + "Pagelines": "\xef\x86\x8c", // U+f18c + "Palfed": "\xef\x8f\x98", // U+f3d8 + "Pandora": "\xee\x9f\x9a", // U+e7da + "Patreon": "\xef\x8f\x99", // U+f3d9 + "Paypal": "\xef\x87\xad", // U+f1ed + "Perbyte": "\xee\x82\x83", // U+e083 + "Periscope": "\xef\x8f\x9a", // U+f3da + "Phabricator": "\xef\x8f\x9b", // U+f3db + "PhoenixFramework": "\xef\x8f\x9c", // U+f3dc + "PhoenixSquadron": "\xef\x94\x91", // U+f511 + "Php": "\xef\x91\x97", // U+f457 + "PiedPiper": "\xef\x8a\xae", // U+f2ae + "PiedPiperAlt": "\xef\x86\xa8", // U+f1a8 + "PiedPiperHat": "\xef\x93\xa5", // U+f4e5 + "PiedPiperPp": "\xef\x86\xa7", // U+f1a7 + "Pinterest": "\xef\x83\x92", // U+f0d2 + "PinterestP": "\xef\x88\xb1", // U+f231 + "Pix": "\xee\x90\xba", // U+e43a + "Pixelfed": "\xee\x9f\x9b", // U+e7db + "Pixiv": "\xee\x99\x80", // U+e640 + "Playstation": "\xef\x8f\x9f", // U+f3df + "Postgresql": "\xee\xa1\x98", // U+e858 + "ProductHunt": "\xef\x8a\x88", // U+f288 + "Pushed": "\xef\x8f\xa1", // U+f3e1 + "Python": "\xef\x8f\xa2", // U+f3e2 + "Qq": "\xef\x87\x96", // U+f1d6 + "Quinscape": "\xef\x91\x99", // U+f459 + "Quora": "\xef\x8b\x84", // U+f2c4 + "RProject": "\xef\x93\xb7", // U+f4f7 + "RaspberryPi": "\xef\x9e\xbb", // U+f7bb + "Ravelry": "\xef\x8b\x99", // U+f2d9 + "React": "\xef\x90\x9b", // U+f41b + "Reacteurope": "\xef\x9d\x9d", // U+f75d + "Readme": "\xef\x93\x95", // U+f4d5 + "Rebel": "\xef\x87\x90", // U+f1d0 + "RedRiver": "\xef\x8f\xa3", // U+f3e3 + "Reddit": "\xef\x86\xa1", // U+f1a1 + "RedditAlien": "\xef\x8a\x81", // U+f281 + "Redhat": "\xef\x9e\xbc", // U+f7bc + "Renren": "\xef\x86\x8b", // U+f18b + "Replyd": "\xef\x8f\xa6", // U+f3e6 + "Researchgate": "\xef\x93\xb8", // U+f4f8 + "Resolving": "\xef\x8f\xa7", // U+f3e7 + "Rev": "\xef\x96\xb2", // U+f5b2 + "Rocketchat": "\xef\x8f\xa8", // U+f3e8 + "Rockrms": "\xef\x8f\xa9", // U+f3e9 + "Rust": "\xee\x81\xba", // U+e07a + "Safari": "\xef\x89\xa7", // U+f267 + "Salesforce": "\xef\xa0\xbb", // U+f83b + "Sass": "\xef\x90\x9e", // U+f41e + "Scaleway": "\xee\xa1\x99", // U+e859 + "Schlix": "\xef\x8f\xaa", // U+f3ea + "Screenpal": "\xee\x95\xb0", // U+e570 + "Scribd": "\xef\x8a\x8a", // U+f28a + "Searchengin": "\xef\x8f\xab", // U+f3eb + "Sellcast": "\xef\x8b\x9a", // U+f2da + "Sellsy": "\xef\x88\x93", // U+f213 + "Servicestack": "\xef\x8f\xac", // U+f3ec + "Shirtsinbulk": "\xef\x88\x94", // U+f214 + "Shoelace": "\xee\x98\x8c", // U+e60c + "Shopify": "\xee\x81\x97", // U+e057 + "Shopware": "\xef\x96\xb5", // U+f5b5 + "SignalMessenger": "\xee\x99\xa3", // U+e663 + "Simplybuilt": "\xef\x88\x95", // U+f215 + "Sistrix": "\xef\x8f\xae", // U+f3ee + "Sith": "\xef\x94\x92", // U+f512 + "Sitrox": "\xee\x91\x8a", // U+e44a + "Sketch": "\xef\x9f\x86", // U+f7c6 + "Skyatlas": "\xef\x88\x96", // U+f216 + "Skype": "\xef\x85\xbe", // U+f17e + "Slack": "\xef\x86\x98", // U+f198 + "Slideshare": "\xef\x87\xa7", // U+f1e7 + "Snapchat": "\xef\x8a\xab", // U+f2ab + "Solana": "\xee\xa1\x9e", // U+e85e + "Soundcloud": "\xef\x86\xbe", // U+f1be + "Sourcetree": "\xef\x9f\x93", // U+f7d3 + "SpaceAwesome": "\xee\x96\xac", // U+e5ac + "Speakap": "\xef\x8f\xb3", // U+f3f3 + "SpeakerDeck": "\xef\xa0\xbc", // U+f83c + "Spotify": "\xef\x86\xbc", // U+f1bc + "SquareBehance": "\xef\x86\xb5", // U+f1b5 + "SquareBluesky": "\xee\x9a\xa3", // U+e6a3 + "SquareDeskpro": "\xee\xa1\x84", // U+e844 + "SquareDribbble": "\xef\x8e\x97", // U+f397 + "SquareFacebook": "\xef\x82\x82", // U+f082 + "SquareFigma": "\xee\x9f\xa4", // U+e7e4 + "SquareFontAwesome": "\xee\x96\xad", // U+e5ad + "SquareFontAwesomeStroke": "\xef\x8d\x9c", // U+f35c + "SquareGit": "\xef\x87\x92", // U+f1d2 + "SquareGithub": "\xef\x82\x92", // U+f092 + "SquareGitlab": "\xee\x96\xae", // U+e5ae + "SquareGooglePlus": "\xef\x83\x94", // U+f0d4 + "SquareHackerNews": "\xef\x8e\xaf", // U+f3af + "SquareInstagram": "\xee\x81\x95", // U+e055 + "SquareJs": "\xef\x8e\xb9", // U+f3b9 + "SquareLastfm": "\xef\x88\x83", // U+f203 + "SquareLetterboxd": "\xee\x98\xae", // U+e62e + "SquareLinkedin": "\xee\x9f\x90", // U+e7d0 + "SquareOdnoklassniki": "\xef\x89\xa4", // U+f264 + "SquarePiedPiper": "\xee\x80\x9e", // U+e01e + "SquarePinterest": "\xef\x83\x93", // U+f0d3 + "SquareReddit": "\xef\x86\xa2", // U+f1a2 + "SquareSnapchat": "\xef\x8a\xad", // U+f2ad + "SquareSteam": "\xef\x86\xb7", // U+f1b7 + "SquareThreads": "\xee\x98\x99", // U+e619 + "SquareTumblr": "\xef\x85\xb4", // U+f174 + "SquareTwitter": "\xef\x82\x81", // U+f081 + "SquareUpwork": "\xee\x99\xbc", // U+e67c + "SquareViadeo": "\xef\x8a\xaa", // U+f2aa + "SquareVimeo": "\xef\x86\x94", // U+f194 + "SquareWebAwesome": "\xee\x9a\x83", // U+e683 + "SquareWebAwesomeStroke": "\xee\x9a\x84", // U+e684 + "SquareWhatsapp": "\xef\x90\x8c", // U+f40c + "SquareXTwitter": "\xee\x98\x9a", // U+e61a + "SquareXing": "\xef\x85\xa9", // U+f169 + "SquareYoutube": "\xef\x90\xb1", // U+f431 + "Squarespace": "\xef\x96\xbe", // U+f5be + "StackExchange": "\xef\x86\x8d", // U+f18d + "StackOverflow": "\xef\x85\xac", // U+f16c + "Stackpath": "\xef\xa1\x82", // U+f842 + "Staylinked": "\xef\x8f\xb5", // U+f3f5 + "Steam": "\xef\x86\xb6", // U+f1b6 + "SteamSymbol": "\xef\x8f\xb6", // U+f3f6 + "StickerMule": "\xef\x8f\xb7", // U+f3f7 + "Strava": "\xef\x90\xa8", // U+f428 + "Stripe": "\xef\x90\xa9", // U+f429 + "StripeS": "\xef\x90\xaa", // U+f42a + "Stubber": "\xee\x97\x87", // U+e5c7 + "Studiovinari": "\xef\x8f\xb8", // U+f3f8 + "Stumbleupon": "\xef\x86\xa4", // U+f1a4 + "StumbleuponCircle": "\xef\x86\xa3", // U+f1a3 + "Superpowers": "\xef\x8b\x9d", // U+f2dd + "Supple": "\xef\x8f\xb9", // U+f3f9 + "Supportnow": "\xee\xa0\xb3", // U+e833 + "Suse": "\xef\x9f\x96", // U+f7d6 + "Svelte": "\xee\xa1\xa8", // U+e868 + "Swift": "\xef\xa3\xa1", // U+f8e1 + "Symfony": "\xef\xa0\xbd", // U+f83d + "Symfonycasts": "\xee\xa2\xab", // U+e8ab + "TailwindCss": "\xee\xa1\xa6", // U+e866 + "Teamspeak": "\xef\x93\xb9", // U+f4f9 + "Telegram": "\xef\x8b\x86", // U+f2c6 + "TencentWeibo": "\xef\x87\x95", // U+f1d5 + "Tex": "\xee\x9f\xbf", // U+e7ff + "TheRedYeti": "\xef\x9a\x9d", // U+f69d + "Themeco": "\xef\x97\x86", // U+f5c6 + "Themeisle": "\xef\x8a\xb2", // U+f2b2 + "ThinkPeaks": "\xef\x9c\xb1", // U+f731 + "Threads": "\xee\x98\x98", // U+e618 + "Threema": "\xee\xa1\x9f", // U+e85f + "Tidal": "\xee\x9f\x9c", // U+e7dc + "Tiktok": "\xee\x81\xbb", // U+e07b + "TorBrowser": "\xee\xa0\xb8", // U+e838 + "TradeFederation": "\xef\x94\x93", // U+f513 + "Trello": "\xef\x86\x81", // U+f181 + "Tumblr": "\xef\x85\xb3", // U+f173 + "Twitch": "\xef\x87\xa8", // U+f1e8 + "Twitter": "\xef\x82\x99", // U+f099 + "Typescript": "\xee\xa1\x80", // U+e840 + "Typo3": "\xef\x90\xab", // U+f42b + "Uber": "\xef\x90\x82", // U+f402 + "Ubuntu": "\xef\x9f\x9f", // U+f7df + "Uikit": "\xef\x90\x83", // U+f403 + "Ultralytics": "\xee\xa1\xad", // U+e86d + "UltralyticsHub": "\xee\xa1\xae", // U+e86e + "UltralyticsYolo": "\xee\xa1\xaf", // U+e86f + "Umbraco": "\xef\xa3\xa8", // U+f8e8 + "Uncharted": "\xee\x82\x84", // U+e084 + "Uniregistry": "\xef\x90\x84", // U+f404 + "Unison": "\xee\xa1\x94", // U+e854 + "Unity": "\xee\x81\x89", // U+e049 + "UnrealEngine": "\xee\xa1\x9c", // U+e85c + "Unsplash": "\xee\x81\xbc", // U+e07c + "Untappd": "\xef\x90\x85", // U+f405 + "Ups": "\xef\x9f\xa0", // U+f7e0 + "Upwork": "\xee\x99\x81", // U+e641 + "Usb": "\xef\x8a\x87", // U+f287 + "Usps": "\xef\x9f\xa1", // U+f7e1 + "Ussunnah": "\xef\x90\x87", // U+f407 + "Vaadin": "\xef\x90\x88", // U+f408 + "Venmo": "\xee\xa1\x9a", // U+e85a + "VenmoV": "\xee\xa1\x9b", // U+e85b + "Viacoin": "\xef\x88\xb7", // U+f237 + "Viadeo": "\xef\x8a\xa9", // U+f2a9 + "Viber": "\xef\x90\x89", // U+f409 + "Vim": "\xee\xa2\x8a", // U+e88a + "Vimeo": "\xef\x90\x8a", // U+f40a + "VimeoV": "\xef\x89\xbd", // U+f27d + "Vine": "\xef\x87\x8a", // U+f1ca + "Vk": "\xef\x86\x89", // U+f189 + "Vnv": "\xef\x90\x8b", // U+f40b + "Vsco": "\xee\x9f\x9d", // U+e7dd + "Vuejs": "\xef\x90\x9f", // U+f41f + "W3c": "\xee\x9f\x9e", // U+e7de + "WatchmanMonitoring": "\xee\x82\x87", // U+e087 + "Waze": "\xef\xa0\xbf", // U+f83f + "WebAwesome": "\xee\x9a\x82", // U+e682 + "Webflow": "\xee\x99\x9c", // U+e65c + "Weebly": "\xef\x97\x8c", // U+f5cc + "Weibo": "\xef\x86\x8a", // U+f18a + "Weixin": "\xef\x87\x97", // U+f1d7 + "Whatsapp": "\xef\x88\xb2", // U+f232 + "Whmcs": "\xef\x90\x8d", // U+f40d + "WikipediaW": "\xef\x89\xa6", // U+f266 + "Windows": "\xef\x85\xba", // U+f17a + "Wirsindhandwerk": "\xee\x8b\x90", // U+e2d0 + "Wix": "\xef\x97\x8f", // U+f5cf + "WizardsOfTheCoast": "\xef\x9c\xb0", // U+f730 + "Wodu": "\xee\x82\x88", // U+e088 + "WolfPackBattalion": "\xef\x94\x94", // U+f514 + "Wordpress": "\xef\x86\x9a", // U+f19a + "WordpressSimple": "\xef\x90\x91", // U+f411 + "Wpbeginner": "\xef\x8a\x97", // U+f297 + "Wpexplorer": "\xef\x8b\x9e", // U+f2de + "Wpforms": "\xef\x8a\x98", // U+f298 + "Wpressr": "\xef\x8f\xa4", // U+f3e4 + "XTwitter": "\xee\x98\x9b", // U+e61b + "Xbox": "\xef\x90\x92", // U+f412 + "Xing": "\xef\x85\xa8", // U+f168 + "Xmpp": "\xee\xa1\xa4", // U+e864 + "YCombinator": "\xef\x88\xbb", // U+f23b + "Yahoo": "\xef\x86\x9e", // U+f19e + "Yammer": "\xef\xa1\x80", // U+f840 + "Yandex": "\xef\x90\x93", // U+f413 + "YandexInternational": "\xef\x90\x94", // U+f414 + "Yarn": "\xef\x9f\xa3", // U+f7e3 + "Yelp": "\xef\x87\xa9", // U+f1e9 + "Yoast": "\xef\x8a\xb1", // U+f2b1 + "Youtube": "\xef\x85\xa7", // U+f167 + "Zhihu": "\xef\x98\xbf", // U+f63f + "Zoom": "\xee\xa1\xbb", // U+e87b + "Zulip": "\xee\xa1\x93", // U+e853 +} diff --git a/icons.go b/internal/render/icons.go similarity index 99% rename from icons.go rename to internal/render/icons.go index a7c869d..19eccd8 100644 --- a/icons.go +++ b/internal/render/icons.go @@ -1,4 +1,4 @@ -package main +package render import ( "bytes" diff --git a/page.go b/internal/render/page.go similarity index 88% rename from page.go rename to internal/render/page.go index 5774825..bfe24fb 100644 --- a/page.go +++ b/internal/render/page.go @@ -1,6 +1,7 @@ -package main +package render import ( + "bytes" "context" "encoding/json" "fmt" @@ -28,6 +29,7 @@ import ( "golang.org/x/image/math/fixed" "streamdeck-lets-go/internal/config" + "streamdeck-lets-go/internal/deck" ) type keyState struct { @@ -44,30 +46,30 @@ type PageManager struct { mu sync.RWMutex pages map[string]*config.PageConfig active string - deck *Deck + deck *deck.Deck keyStates map[int]*keyState displayOutputs map[int]*DisplayOutput displayMu sync.RWMutex - defaultFont string - showLabelBackground bool + DefaultFont string + ShowLabelBackground bool dynamicCancel context.CancelFunc dynamicKeys []config.KeyConfig dynamicKeysMu sync.RWMutex dynamicResults map[string][]config.KeyConfig } -func NewPageManager(deck *Deck) *PageManager { +func NewPageManager(deck *deck.Deck) *PageManager { return &PageManager{ pages: make(map[string]*config.PageConfig), deck: deck, keyStates: make(map[int]*keyState), displayOutputs: make(map[int]*DisplayOutput), - defaultFont: "medium", + DefaultFont: "medium", dynamicResults: make(map[string][]config.KeyConfig), } } -func (pm *PageManager) activeKeys() []config.KeyConfig { +func (pm *PageManager) ActiveKeys() []config.KeyConfig { pm.mu.RLock() page := pm.pages[pm.active] pm.mu.RUnlock() @@ -165,7 +167,7 @@ func (pm *PageManager) ActivatePage(name string) error { } if page.Background != "" { - if img, err := loadImage(page.Background, 0, 0); err == nil { + if img, err := LoadImage(page.Background, 0, 0); err == nil { if err := pm.deck.FillPanel(img); err != nil { slog.Warn("fill panel failed", "error", err) } @@ -227,8 +229,18 @@ func (pm *PageManager) GetPage(name string) *config.PageConfig { return pm.pages[name] } +func (pm *PageManager) GetPageNames() []string { + pm.mu.RLock() + defer pm.mu.RUnlock() + names := make([]string, 0, len(pm.pages)) + for name := range pm.pages { + names = append(names, name) + } + return names +} + func (pm *PageManager) RenderKey(keyIndex int) { - for _, k := range pm.activeKeys() { + for _, k := range pm.ActiveKeys() { if k.Index == keyIndex { pm.renderKey(keyIndex, &k) return @@ -237,7 +249,7 @@ func (pm *PageManager) RenderKey(keyIndex int) { } func (pm *PageManager) ReRenderDisplayKey(keyIndex int, output string) { - for _, k := range pm.activeKeys() { + for _, k := range pm.ActiveKeys() { if k.Index == keyIndex && k.Display != nil { pm.renderKeyOutput(keyIndex, k.Display, output, nil) return @@ -248,7 +260,7 @@ func (pm *PageManager) ReRenderDisplayKey(keyIndex int, output string) { func (pm *PageManager) renderKey(idx int, k *config.KeyConfig) { fontName := k.Font if fontName == "" { - fontName = pm.defaultFont + fontName = pm.DefaultFont } fontSize := 18.0 if k.FontSize != nil { @@ -261,7 +273,7 @@ func (pm *PageManager) renderKey(idx int, k *config.KeyConfig) { } if k.Icon != "" { - img, err := loadImage(k.Icon, pm.deck.KeySize(), faScale) + img, err := LoadImage(k.Icon, pm.deck.KeySize(), faScale) if err != nil { slog.Warn("load icon", "path", k.Icon, "error", err) pm.deck.FillColor(idx, 64, 64, 64) @@ -285,11 +297,11 @@ func (pm *PageManager) renderKey(idx int, k *config.KeyConfig) { } onImgFontName := fontName if k.Font == "" { - onImgFontName = pm.defaultFont + onImgFontName = pm.DefaultFont } if k.Label != "" { - if err := pm.deck.WriteTextOnImage(idx, img, k.Label, onImgFontName, onImgFontSize, pm.showLabelBackground); err != nil { + if err := pm.deck.WriteTextOnImage(idx, img, k.Label, onImgFontName, onImgFontSize, pm.ShowLabelBackground); err != nil { slog.Warn("write text on image", "error", err) pm.deck.FillImage(idx, img) } @@ -305,7 +317,7 @@ func (pm *PageManager) renderKey(idx int, k *config.KeyConfig) { ks := pm.deck.KeySize() img := image.NewRGBA(image.Rect(0, 0, ks, ks)) draw.Draw(img, img.Bounds(), &image.Uniform{bg}, image.Point{}, draw.Src) - if err := pm.deck.WriteTextOnImage(idx, img, k.Label, fontName, fontSize, pm.showLabelBackground); err != nil { + if err := pm.deck.WriteTextOnImage(idx, img, k.Label, fontName, fontSize, pm.ShowLabelBackground); err != nil { slog.Warn("write text on image", "error", err) pm.deck.FillImage(idx, img) } @@ -326,7 +338,7 @@ func (pm *PageManager) renderKey(idx int, k *config.KeyConfig) { } } -func (pm *PageManager) stopPeriodicKeys() { +func (pm *PageManager) StopPeriodicKeys() { pm.stopDynamicKeys() pm.mu.Lock() @@ -337,7 +349,7 @@ func (pm *PageManager) stopPeriodicKeys() { pm.keyStates = make(map[int]*keyState) } -func (pm *PageManager) startPeriodicKeys() { +func (pm *PageManager) StartPeriodicKeys() { pm.mu.Lock() page := pm.pages[pm.active] if page == nil { @@ -474,12 +486,12 @@ func (pm *PageManager) rerenderActivePage() { pm.mu.RUnlock() if bg != "" { - if img, err := loadImage(bg, 0, 0); err == nil { + if img, err := LoadImage(bg, 0, 0); err == nil { pm.deck.FillPanel(img) } } - keys := pm.activeKeys() + keys := pm.ActiveKeys() keyByIndex := make(map[int]config.KeyConfig, len(keys)) for _, k := range keys { keyByIndex[k.Index] = k @@ -588,7 +600,7 @@ func parseDisplayOutput(output string) (*DisplayOutput, color.Color, color.Color func (pm *PageManager) renderKeyOutput(idx int, d *config.DisplayCfg, output string, execErr error) { var kc *config.KeyConfig - for _, k := range pm.activeKeys() { + for _, k := range pm.ActiveKeys() { if k.Index == idx { kCopy := k kc = &kCopy @@ -638,7 +650,7 @@ func (pm *PageManager) renderKeyOutput(idx int, d *config.DisplayCfg, output str } if kc.Icon != "" { - img, err := loadImage(kc.Icon, pm.deck.KeySize(), faScale) + img, err := LoadImage(kc.Icon, pm.deck.KeySize(), faScale) if err != nil { slog.Warn("load icon for display", "path", kc.Icon, "error", err) var bg color.Color = color.Black @@ -664,7 +676,7 @@ func (pm *PageManager) renderKeyOutput(idx int, d *config.DisplayCfg, output str } } - composite := renderUnicodeTextOnImage(img, text, fontSize, pm.deck.KeySize(), fg, pm.showLabelBackground) + composite := renderUnicodeTextOnImage(img, text, fontSize, pm.deck.KeySize(), fg, pm.ShowLabelBackground) if err := pm.deck.FillImage(idx, composite); err != nil { slog.Warn("fill image", "error", err) } @@ -686,7 +698,7 @@ func (pm *PageManager) renderKeyOutput(idx int, d *config.DisplayCfg, output str } func (pm *PageManager) RefreshDisplayKey(idx int) { - for _, k := range pm.activeKeys() { + for _, k := range pm.ActiveKeys() { if k.Index == idx && k.Display != nil { timeout := 30 * time.Second if k.Display.Timeout != "" { @@ -856,7 +868,7 @@ func renderUnicodeText(text string, fontSize float64, keySize int, bg, fg color. return rgba } -func renderUnicodeTextOnImage(baseImg image.Image, text string, fontSize float64, keySize int, fg color.Color, showLabelBackground bool) *image.RGBA { +func renderUnicodeTextOnImage(baseImg image.Image, text string, fontSize float64, keySize int, fg color.Color, ShowLabelBackground bool) *image.RGBA { g := gift.New(gift.Resize(keySize, keySize, gift.LanczosResampling)) rgba := image.NewRGBA(image.Rect(0, 0, keySize, keySize)) g.Draw(rgba, baseImg) @@ -865,7 +877,7 @@ func renderUnicodeTextOnImage(baseImg image.Image, text string, fontSize float64 if keySize < 72 { barHeight = 16 } - if showLabelBackground { + if ShowLabelBackground { barRect := image.Rect(0, keySize-barHeight, keySize, keySize) draw.Draw(rgba, barRect, &image.Uniform{color.RGBA{0, 0, 0, 180}}, image.Point{}, draw.Over) } @@ -1003,7 +1015,7 @@ func cacheKey(path string, targetSize int, faScale float64) string { return fmt.Sprintf("%s|%d|%.6f", path, targetSize, faScale) } -func loadImage(path string, targetSize int, faScale float64) (image.Image, error) { +func LoadImage(path string, targetSize int, faScale float64) (image.Image, error) { key := cacheKey(path, targetSize, faScale) if cached, ok := imageCache.Load(key); ok { return cached.(image.Image), nil @@ -1040,7 +1052,7 @@ func loadImage(path string, targetSize int, faScale float64) (image.Image, error } resolved = p } else if !strings.HasPrefix(path, "/") { - resolved = filepath.Join(configDir(), path) + resolved = filepath.Join(config.ConfigDir(), path) } if strings.HasSuffix(resolved, ".svg") { @@ -1095,17 +1107,70 @@ func loadImage(path string, targetSize int, faScale float64) (image.Image, error return img, nil } -var cachedConfigDir string +func execDisplayCapture(d *config.DisplayCfg, timeout time.Duration) (string, error) { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() -func configDir() string { - if cachedConfigDir != "" { - return cachedConfigDir + var cmd *exec.Cmd + if d.Command != "" { + cmd = exec.CommandContext(ctx, "sh", "-c", d.Command) + } else { + cmd = exec.CommandContext(ctx, d.Script) } - home, err := os.UserHomeDir() - if err != nil { - cachedConfigDir = "." - return cachedConfigDir + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + err := cmd.Run() + output := stdout.String() + if stderr.Len() > 0 { + if output != "" { + output += "\n" + } + output += stderr.String() } - cachedConfigDir = filepath.Join(home, ".config", "streamdeck-lets-go") - return cachedConfigDir + return output, err +} + +func execDynamicKeys(dg *config.DynamicKeyGen, timeout time.Duration, keyCount int) ([]config.KeyConfig, error) { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + var cmd *exec.Cmd + if dg.Command != "" { + cmd = exec.CommandContext(ctx, "sh", "-c", dg.Command) + } else { + script := dg.Script + if !filepath.IsAbs(script) { + script = filepath.Join(config.ConfigDir(), script) + } + cmd = exec.CommandContext(ctx, script) + } + + cmd.Env = append(os.Environ(), + fmt.Sprintf("STREAMDECK_KEY_COUNT=%d", keyCount), + fmt.Sprintf("STREAMDECK_CONFIG_DIR=%s", config.ConfigDir()), + ) + + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + err := cmd.Run() + + if stderr.Len() > 0 { + slog.Debug("dynamic_keys script stderr", "output", stderr.String()) + } + + if err != nil { + return nil, fmt.Errorf("execute dynamic_keys: %w", err) + } + + var keys []config.KeyConfig + output := stdout.String() + if err := json.Unmarshal([]byte(output), &keys); err != nil { + return nil, fmt.Errorf("parse dynamic_keys JSON: %w", err) + } + + return keys, nil } diff --git a/render.go b/internal/render/render.go similarity index 98% rename from render.go rename to internal/render/render.go index 54224b6..25cdfe4 100644 --- a/render.go +++ b/internal/render/render.go @@ -1,4 +1,4 @@ -package main +package render import ( "image" @@ -32,7 +32,7 @@ func RenderKeyToImage(k *config.KeyConfig, keySize int, showLabelBackground bool } if k.Icon != "" { - img, err := loadImage(k.Icon, keySize, faScale) + img, err := LoadImage(k.Icon, keySize, faScale) if err != nil { img = blankImage(keySize, color.RGBA{64, 64, 64, 255}) } diff --git a/static/alpine.min.js b/internal/web/static/alpine.min.js similarity index 100% rename from static/alpine.min.js rename to internal/web/static/alpine.min.js diff --git a/static/app.js b/internal/web/static/app.js similarity index 100% rename from static/app.js rename to internal/web/static/app.js diff --git a/static/fontawesome/css/all.min.css b/internal/web/static/fontawesome/css/all.min.css similarity index 100% rename from static/fontawesome/css/all.min.css rename to internal/web/static/fontawesome/css/all.min.css diff --git a/static/fontawesome/webfonts/fa-brands-400.ttf b/internal/web/static/fontawesome/webfonts/fa-brands-400.ttf similarity index 100% rename from static/fontawesome/webfonts/fa-brands-400.ttf rename to internal/web/static/fontawesome/webfonts/fa-brands-400.ttf diff --git a/static/fontawesome/webfonts/fa-brands-400.woff2 b/internal/web/static/fontawesome/webfonts/fa-brands-400.woff2 similarity index 100% rename from static/fontawesome/webfonts/fa-brands-400.woff2 rename to internal/web/static/fontawesome/webfonts/fa-brands-400.woff2 diff --git a/static/fontawesome/webfonts/fa-regular-400.ttf b/internal/web/static/fontawesome/webfonts/fa-regular-400.ttf similarity index 100% rename from static/fontawesome/webfonts/fa-regular-400.ttf rename to internal/web/static/fontawesome/webfonts/fa-regular-400.ttf diff --git a/static/fontawesome/webfonts/fa-regular-400.woff2 b/internal/web/static/fontawesome/webfonts/fa-regular-400.woff2 similarity index 100% rename from static/fontawesome/webfonts/fa-regular-400.woff2 rename to internal/web/static/fontawesome/webfonts/fa-regular-400.woff2 diff --git a/static/fontawesome/webfonts/fa-solid-900.ttf b/internal/web/static/fontawesome/webfonts/fa-solid-900.ttf similarity index 100% rename from static/fontawesome/webfonts/fa-solid-900.ttf rename to internal/web/static/fontawesome/webfonts/fa-solid-900.ttf diff --git a/static/fontawesome/webfonts/fa-solid-900.woff2 b/internal/web/static/fontawesome/webfonts/fa-solid-900.woff2 similarity index 100% rename from static/fontawesome/webfonts/fa-solid-900.woff2 rename to internal/web/static/fontawesome/webfonts/fa-solid-900.woff2 diff --git a/static/fontawesome/webfonts/fa-v4compatibility.ttf b/internal/web/static/fontawesome/webfonts/fa-v4compatibility.ttf similarity index 100% rename from static/fontawesome/webfonts/fa-v4compatibility.ttf rename to internal/web/static/fontawesome/webfonts/fa-v4compatibility.ttf diff --git a/static/fontawesome/webfonts/fa-v4compatibility.woff2 b/internal/web/static/fontawesome/webfonts/fa-v4compatibility.woff2 similarity index 100% rename from static/fontawesome/webfonts/fa-v4compatibility.woff2 rename to internal/web/static/fontawesome/webfonts/fa-v4compatibility.woff2 diff --git a/static/index.html b/internal/web/static/index.html similarity index 100% rename from static/index.html rename to internal/web/static/index.html diff --git a/static/styles.css b/internal/web/static/styles.css similarity index 100% rename from static/styles.css rename to internal/web/static/styles.css diff --git a/web.go b/internal/web/web.go similarity index 94% rename from web.go rename to internal/web/web.go index 31fe979..a60bd64 100644 --- a/web.go +++ b/internal/web/web.go @@ -1,4 +1,4 @@ -package main +package web import ( "context" @@ -18,6 +18,8 @@ import ( "time" "streamdeck-lets-go/internal/config" + "streamdeck-lets-go/internal/deck" + "streamdeck-lets-go/internal/render" ) //go:embed static/* @@ -36,9 +38,9 @@ func init() { type WebServer struct { cfg *config.Config configPath string - pm *PageManager - extraPMs []*PageManager - decks []*Deck + pm *render.PageManager + extraPMs []*render.PageManager + decks []*deck.Deck mu sync.RWMutex sseClients map[chan string]struct{} @@ -59,19 +61,19 @@ func (s *WebServer) UpdateConfig(cfg *config.Config) { s.cfg = cfg } -func (s *WebServer) SetPageManager(pm *PageManager) { +func (s *WebServer) SetPageManager(pm *render.PageManager) { s.mu.Lock() defer s.mu.Unlock() s.pm = pm } -func (s *WebServer) SetDecks(decks []*Deck) { +func (s *WebServer) SetDecks(decks []*deck.Deck) { s.mu.Lock() defer s.mu.Unlock() s.decks = decks } -func (s *WebServer) SetExtraPageManagers(pms []*PageManager) { +func (s *WebServer) SetExtraPageManagers(pms []*render.PageManager) { s.mu.Lock() defer s.mu.Unlock() s.extraPMs = pms @@ -216,7 +218,7 @@ func (s *WebServer) handleActivatePage(w http.ResponseWriter, r *http.Request) { } s.mu.RLock() - allPMs := append([]*PageManager{s.pm}, s.extraPMs...) + allPMs := append([]*render.PageManager{s.pm}, s.extraPMs...) s.mu.RUnlock() for _, pm := range allPMs { @@ -226,8 +228,8 @@ func (s *WebServer) handleActivatePage(w http.ResponseWriter, r *http.Request) { if err := pm.ActivatePage(req.Page); err != nil { slog.Warn("activate page", "page", req.Page, "error", err) } else { - pm.stopPeriodicKeys() - pm.startPeriodicKeys() + pm.StopPeriodicKeys() + pm.StartPeriodicKeys() } } @@ -421,7 +423,7 @@ func (s *WebServer) handleRender(w http.ResponseWriter, r *http.Request) { kc.Background = bg } - img := RenderKeyToImage(kc, keySize, s.cfg.ShowLabelBackground) + img := render.RenderKeyToImage(kc, keySize, s.cfg.ShowLabelBackground) w.Header().Set("Content-Type", "image/png") w.Header().Set("Cache-Control", "no-cache") @@ -487,7 +489,7 @@ func collectIcons(cfg *config.Config, used map[string]bool) { } func gcImages(cfg *config.Config) { - imgDir := filepath.Join(configDir(), "images") + imgDir := filepath.Join(config.ConfigDir(), "images") entries, err := os.ReadDir(imgDir) if err != nil { return @@ -496,7 +498,7 @@ func gcImages(cfg *config.Config) { used := make(map[string]bool) collectIcons(cfg, used) - backupDir := filepath.Join(configDir(), "backups") + backupDir := filepath.Join(config.ConfigDir(), "backups") backupEntries, _ := os.ReadDir(backupDir) for _, be := range backupEntries { if be.IsDir() { @@ -598,15 +600,15 @@ func (s *WebServer) handleGetBackup(w http.ResponseWriter, r *http.Request) { func (s *WebServer) handleGetModels(w http.ResponseWriter, r *http.Request) { type modelInfo struct { - PID uint16 `json:"pid"` - Name string `json:"name"` - KeysX int `json:"keys_x"` - KeysY int `json:"keys_y"` - KeySize int `json:"key_size"` + PID uint16 `json:"pid"` + Name string `json:"name"` + KeysX int `json:"keys_x"` + KeysY int `json:"keys_y"` + KeySize int `json:"key_size"` } - models := make([]modelInfo, 0, len(knownDecks)) - for _, d := range knownDecks { + models := make([]modelInfo, 0, len(deck.KnownDecks)) + for _, d := range deck.KnownDecks { models = append(models, modelInfo{ PID: d.PID, Name: d.Name, @@ -624,7 +626,7 @@ func (s *WebServer) handleGetDecks(w http.ResponseWriter, r *http.Request) { s.mu.RLock() defer s.mu.RUnlock() - infos := make([]DeckInfo, 0, len(s.decks)) + infos := make([]deck.DeckInfo, 0, len(s.decks)) for _, d := range s.decks { infos = append(infos, d.DeckInfo()) } @@ -661,7 +663,7 @@ func (s *WebServer) handleUpload(w http.ResponseWriter, r *http.Request) { } defer file.Close() - uploadDir := filepath.Join(configDir(), "images") + uploadDir := filepath.Join(config.ConfigDir(), "images") if err := os.MkdirAll(uploadDir, 0755); err != nil { http.Error(w, fmt.Sprintf("create upload dir: %v", err), http.StatusInternalServerError) return diff --git a/main.go b/main.go deleted file mode 100644 index bfd75eb..0000000 --- a/main.go +++ /dev/null @@ -1,135 +0,0 @@ -package main - -import ( - "bytes" - "context" - "encoding/json" - "flag" - "fmt" - "log/slog" - "net/http" - "os" - "os/signal" - "strings" - "syscall" - - _ "image/gif" - _ "image/jpeg" - _ "image/png" - - "streamdeck-lets-go/internal/config" -) - -func main() { - slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo}))) - - fs := flag.NewFlagSet("streamdeck-lets-go", flag.ExitOnError) - configPath := fs.String("config", "", "path to config.json (default: ~/.config/streamdeck-lets-go/config.json)") - httpAddr := fs.String("addr", ":9090", "web UI listen address") - startPage := fs.String("page", "", "page to activate on startup (default: config's default_page)") - noDeck := fs.Bool("no-deck", false, "run without Stream Deck hardware (config editing only)") - verbose := fs.Bool("v", false, "verbose output") - - if len(os.Args) < 2 || os.Args[1] == "--help" || os.Args[1] == "-help" || os.Args[1] == "-h" { - fmt.Fprintf(os.Stderr, "Usage: streamdeck-lets-go [flags] [command]\n\n") - fmt.Fprintf(os.Stderr, "Commands:\n") - fmt.Fprintf(os.Stderr, " daemon run the Stream Deck daemon with web UI (default)\n") - fmt.Fprintf(os.Stderr, " switch switch running daemon to a page (e.g. 'switch games')\n") - fmt.Fprintf(os.Stderr, " discover list connected Stream Decks\n") - fmt.Fprintf(os.Stderr, "\nFlags:\n") - fs.PrintDefaults() - os.Exit(0) - } - - cmd := os.Args[1] - args := os.Args[2:] - - switch cmd { - case "daemon": - fs.Parse(args) - case "switch": - fs.Parse(args) - if fs.NArg() == 0 { - fmt.Fprintf(os.Stderr, "Usage: streamdeck-lets-go switch \n") - os.Exit(1) - } - if err := switchToPage(*httpAddr, fs.Arg(0)); err != nil { - fmt.Fprintf(os.Stderr, "error: %v\n", err) - os.Exit(1) - } - fmt.Printf("switched to page %q\n", fs.Arg(0)) - return - case "discover": - discover() - return - default: - if cmd == "serve" { - fmt.Fprintf(os.Stderr, "streamdeck-lets-go: 'serve' removed; use 'daemon --no-deck' instead\n") - os.Exit(1) - } - fs.Parse(os.Args[1:]) - } - - if *verbose { - slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug}))) - } - - cfg, err := config.LoadConfig(*configPath) - if err != nil { - slog.Error("config", "error", err) - os.Exit(1) - } - - ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) - defer cancel() - - httpEnabled := true - if err := Run(ctx, cfg, RunOptions{ - ConfigPath: *configPath, - HTTPAddr: *httpAddr, - HTTPEnabled: httpEnabled, - NoDeck: *noDeck, - StartPage: *startPage, - }); err != nil { - slog.Error("run", "error", err) - os.Exit(1) - } -} - -func discover() { - devices, err := EnumerateDevices() - if err != nil { - slog.Error("discover", "error", err) - os.Exit(1) - } - if len(devices) == 0 { - fmt.Println("No Stream Deck devices found.") - return - } - fmt.Printf("Found %d Stream Deck(s):\n", len(devices)) - for _, d := range devices { - fmt.Printf(" Serial: %s Model: %s PID: 0x%04x\n", d.Serial, d.Model, d.PID) - } -} - -// switchToPage tells the running daemon (at httpAddr) to activate the given page -// by POSTing to its /api/activate-page endpoint. -func switchToPage(httpAddr, page string) error { - host := httpAddr - if strings.HasPrefix(host, ":") { - host = "127.0.0.1" + host - } - url := "http://" + host + "/api/activate-page" - - body, _ := json.Marshal(map[string]string{"page": page}) - resp, err := http.Post(url, "application/json", bytes.NewReader(body)) - if err != nil { - return fmt.Errorf("daemon not running? %v", err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("switch failed (HTTP %d)", resp.StatusCode) - } - return nil -} diff --git a/media.go b/media.go deleted file mode 100644 index e7cb558..0000000 --- a/media.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "log/slog" -) - -func init() { - slog.Info("media module loaded") -} - -// mediaAction is handled inline in action.go via playerctl/wpctl diff --git a/dist/arch/.SRCINFO b/packaging/.SRCINFO similarity index 88% rename from dist/arch/.SRCINFO rename to packaging/.SRCINFO index db8a8f7..c4cd582 100644 --- a/dist/arch/.SRCINFO +++ b/packaging/.SRCINFO @@ -14,8 +14,8 @@ pkgbase = streamdeck-lets-go-git provides = streamdeck-lets-go conflicts = streamdeck-lets-go source = streamdeck-lets-go-git::git+https://github.com/totmin/streamdeck-lets-go.git - source = streamdeck-lets-go.service - source = 90-streamdeck.rules + source = packaging/streamdeck-lets-go.service + source = packaging/90-streamdeck.rules b2sums = SKIP b2sums = SKIP b2sums = SKIP diff --git a/dist/arch/90-streamdeck.rules b/packaging/90-streamdeck.rules similarity index 100% rename from dist/arch/90-streamdeck.rules rename to packaging/90-streamdeck.rules diff --git a/dist/arch/PKGBUILD b/packaging/PKGBUILD similarity index 80% rename from dist/arch/PKGBUILD rename to packaging/PKGBUILD index f495755..746e899 100644 --- a/dist/arch/PKGBUILD +++ b/packaging/PKGBUILD @@ -16,8 +16,8 @@ provides=('streamdeck-lets-go') conflicts=('streamdeck-lets-go') source=("${pkgname}::git+${_giturl}" - "streamdeck-lets-go.service" - "90-streamdeck.rules") + "packaging/streamdeck-lets-go.service" + "packaging/90-streamdeck.rules") b2sums=('SKIP' 'SKIP' 'SKIP') @@ -32,7 +32,7 @@ build() { export CGO_ENABLED=1 go build \ -ldflags "-s -w" \ - -o streamdeck-lets-go . + -o streamdeck-lets-go ./cmd/streamdeck-lets-go } package() { @@ -40,9 +40,9 @@ package() { install -Dm755 streamdeck-lets-go "${pkgdir}/usr/bin/streamdeck-lets-go" - install -Dm644 "${srcdir}/streamdeck-lets-go.service" \ + install -Dm644 "${srcdir}/packaging/streamdeck-lets-go.service" \ "${pkgdir}/usr/lib/systemd/user/streamdeck-lets-go.service" - install -Dm644 "${srcdir}/90-streamdeck.rules" \ + install -Dm644 "${srcdir}/packaging/90-streamdeck.rules" \ "${pkgdir}/usr/lib/udev/rules.d/90-streamdeck.rules" } diff --git a/dist/arch/streamdeck-lets-go.service b/packaging/streamdeck-lets-go.service similarity index 100% rename from dist/arch/streamdeck-lets-go.service rename to packaging/streamdeck-lets-go.service