diff --git a/css/style.css b/css/style.css
new file mode 100644
index 0000000..a548f8c
--- /dev/null
+++ b/css/style.css
@@ -0,0 +1,1929 @@
+/* style options, foreground */
+.cof-separator {
+ color: #68b5d4;
+}
+.cof-chat {
+ color: #f7f7f7;
+}
+.cof-chat_time {
+ color: #f7f7f7;
+}
+.cof-chat_time_delimiters {
+ color: #cc843b;
+}
+.cof-chat_prefix_error {
+ color: #ffe377;
+}
+.cof-chat_prefix_network {
+ color: #fbb1f9;
+}
+.cof-chat_prefix_action {
+ color: #f7f7f7;
+}
+.cof-chat_prefix_join {
+ color: #cdee69;
+}
+.cof-chat_prefix_quit {
+ color: #c75646;
+}
+.cof-chat_prefix_more {
+ color: #fbb1f9;
+}
+.cof-chat_prefix_suffix {
+ color: #cdee69;
+}
+.cof-chat_buffer {
+ color: #f7f7f7;
+}
+.cof-chat_server {
+ color: #cc843b;
+}
+.cof-chat_channel {
+ color: #f7f7f7;
+}
+.cof-chat_nick {
+ color: #77dfd8;
+}
+.cof-chat_nick_self {
+ color: #f7f7f7;
+}
+.cof-chat_nick_other {
+ color: #77dfd8;
+}
+.cof-invalid {
+ /* should never happen */
+ color: #f7f7f7;
+ background-color: transparent;
+}
+.cof-chat_host {
+ color: #77dfd8;
+}
+.cof-chat_delimiters {
+ color: #cdee69;
+}
+.cof-chat_highlight {
+ color: #ffe377;
+ background-color: #c8a0d1;
+}
+.cof-chat_read_marker {
+ color: #fbb1f9;
+}
+.cof-chat_text_found {
+ color: #ffe377;
+}
+.cof-chat_value {
+ color: #77dfd8;
+}
+.cof-chat_prefix_buffer {
+ color: #cc843b;
+}
+.cof-chat_tags {
+ color: #c75646;
+}
+.cof-chat_inactive_window {
+ color: #5d5d5d;
+}
+.cof-chat_inactive_buffer {
+ color: #5d5d5d;
+}
+.cof-chat_prefix_buffer_inactive_buffer {
+ color: #5d5d5d;
+}
+.cof-chat_nick_offline {
+ color: #5d5d5d;
+}
+.cof-chat_nick_offline_highlight {
+ color: #f7f7f7;
+ background-color: #5d5d5d;
+}
+.cof-chat_nick_prefix {
+ color: #cdee69;
+}
+.cof-chat_nick_suffix {
+ color: #cdee69;
+}
+.cof-emphasis {
+ color: #ffe377;
+ background-color: #c8a0d1;
+}
+.cof-chat_day_change {
+ color: #77dfd8;
+}
+
+/* style options, background */
+.cob-separator {
+}
+.cob-chat {
+}
+.cob-chat_time {
+}
+.cob-chat_time_delimiters {
+}
+.cob-chat_prefix_error {
+}
+.cob-chat_prefix_network {
+}
+.cob-chat_prefix_action {
+}
+.cob-chat_prefix_join {
+}
+.cob-chat_prefix_quit {
+}
+.cob-chat_prefix_more {
+}
+.cob-chat_prefix_suffix {
+}
+.cob-chat_buffer {
+}
+.cob-chat_server {
+}
+.cob-chat_channel {
+}
+.cob-chat_nick {
+}
+.cob-chat_nick_self {
+}
+.cob-chat_nick_other {
+}
+.cob-invalid {
+}
+.cob-chat_host {
+}
+.cob-chat_delimiters {
+}
+.cob-chat_highlight {
+ background-color: #c8a0d1;
+}
+.cob-chat_read_marker {
+}
+.cob-chat_text_found {
+}
+.cob-chat_value {
+}
+.cob-chat_prefix_buffer {
+}
+.cob-chat_tags {
+}
+.cob-chat_inactive_window {
+}
+.cob-chat_inactive_buffer {
+}
+.cob-chat_prefix_buffer_inactive_buffer {
+}
+.cob-chat_nick_offline {
+}
+.cob-chat_nick_offline_highlight {
+ background-color: #5d5d5d;
+}
+.cob-chat_nick_prefix {
+}
+.cob-chat_nick_suffix {
+}
+.cob-emphasis {
+ background-color: #c8a0d1;
+}
+.cob-chat_day_change {
+}
+
+/* style options, attributes */
+.coa-separator {
+}
+.coa-chat {
+}
+.coa-chat_time {
+}
+.coa-chat_time_delimiters {
+}
+.coa-chat_prefix_error {
+}
+.coa-chat_prefix_network {
+}
+.coa-chat_prefix_action {
+}
+.coa-chat_prefix_join {
+}
+.coa-chat_prefix_quit {
+}
+.coa-chat_prefix_more {
+}
+.coa-chat_prefix_suffix {
+}
+.coa-chat_buffer {
+}
+.coa-chat_server {
+}
+.coa-chat_channel {
+}
+.coa-chat_nick {
+}
+.coa-chat_nick_self {
+}
+.coa-chat_nick_other {
+}
+.coa-invalid {
+}
+.coa-chat_host {
+}
+.coa-chat_delimiters {
+}
+.coa-chat_highlight {
+}
+.coa-chat_read_marker {
+}
+.coa-chat_text_found {
+}
+.coa-chat_value {
+}
+.coa-chat_prefix_buffer {
+}
+.coa-chat_tags {
+}
+.coa-chat_inactive_window {
+}
+.coa-chat_inactive_buffer {
+}
+.coa-chat_prefix_buffer_inactive_buffer {
+}
+.coa-chat_nick_offline {
+}
+.coa-chat_nick_offline_highlight {
+}
+.coa-chat_nick_prefix {
+}
+.coa-chat_nick_suffix {
+}
+.coa-emphasis {
+}
+.coa-chat_day_change {
+}
+
+/* WeeChat colors, foreground */
+.cwf-default {
+ color: #f7f7f7;
+}
+.cwf-black {
+ color: #000000;
+}
+.cwf-darkgray {
+ color: #5d5d5d;
+}
+.cwf-darkred {
+ color: #c75646;
+}
+.cwf-lightred {
+ color: #e09690;
+}
+.cwf-darkgreen {
+ color: #8eb33b;
+}
+.cwf-lightgreen {
+ color: #cdee69;
+}
+.cwf-brown {
+ color: #b27232;
+}
+.cwf-yellow {
+ color: #ffe377;
+}
+.cwf-darkblue {
+ color: #72b3cc;
+}
+.cwf-lightblue {
+ color: #9cd9f0;
+}
+.cwf-darkmagenta {
+ color: #c8a0d1;
+}
+.cwf-lightmagenta {
+ color: #fbb1f9;
+}
+.cwf-darkcyan {
+ color: #218693;
+}
+.cwf-lightcyan {
+ color: #77dfd8;
+}
+.cwf-gray {
+ color: #b0b0b0;
+}
+.cwf-white {
+ color: #f7f7f7;
+}
+
+/* WeeChat colors, background */
+.cwb-default {
+ background-color: transparent;
+}
+.cwb-black {
+ background-color: #000000;
+}
+.cwb-darkgray {
+ background-color: #5d5d5d;
+}
+.cwb-darkred {
+ background-color: #c75646;
+}
+.cwb-lightred {
+ background-color: #e09690;
+}
+.cwb-darkgreen {
+ background-color: #8eb33b;
+}
+.cwb-lightgreen {
+ background-color: #cdee69;
+}
+.cwb-brown {
+ background-color: #b27232;
+}
+.cwb-yellow {
+ background-color: #ffe377;
+}
+.cwb-darkblue {
+ background-color: #72b3cc;
+}
+.cwb-lightblue {
+ background-color: #9cd9f0;
+}
+.cwb-darkmagenta {
+ background-color: #c8a0d1;
+}
+.cwb-lightmagenta {
+ background-color: #fbb1f9;
+}
+.cwb-darkcyan {
+ background-color: #218693;
+}
+.cwb-lightcyan {
+ background-color: #77dfd8;
+}
+.cwb-gray {
+ background-color: #b0b0b0;
+}
+.cwb-white {
+ background-color: #f7f7f7;
+}
+
+/* extended colors, foreground */
+.cef-0 {
+ color: #000000; /* 000 Black */
+}
+.cef-1 {
+ color: #cd0000; /* 001 DarkRed */
+}
+.cef-2 {
+ color: #00cd00; /* 002 DarkGreen */
+}
+.cef-3 {
+ color: #cdcd00; /* 003 DarkYellow */
+}
+.cef-4 {
+ color: #0000ee; /* 004 DarkBlue */
+}
+.cef-5 {
+ color: #cd00cd; /* 005 DarkMagenta */
+}
+.cef-6 {
+ color: #00cdcd; /* 006 DarkCyan */
+}
+.cef-7 {
+ color: #e5e5e5; /* 007 LightGrey */
+}
+.cef-8 {
+ color: #7f7f7f; /* 008 DarkGrey */
+}
+.cef-9 {
+ color: #ff0000; /* 009 LightRed */
+}
+.cef-10 {
+ color: #00ff00; /* 010 LightGreen */
+}
+.cef-11 {
+ color: #ffff00; /* 011 LightYellow */
+}
+.cef-12 {
+ color: #5c5cff; /* 012 LightBlue */
+}
+.cef-13 {
+ color: #ff00ff; /* 013 LightMagenta */
+}
+.cef-14 {
+ color: #00ffff; /* 014 LightCyan */
+}
+.cef-15 {
+ color: #ffffff; /* 015 White */
+}
+.cef-16 {
+ color: #000000; /* 016 Grey0 */
+}
+.cef-17 {
+ color: #00005f; /* 017 NavyBlue */
+}
+.cef-18 {
+ color: #000087; /* 018 DarkBlue */
+}
+.cef-19 {
+ color: #0000af; /* 019 Blue3 */
+}
+.cef-20 {
+ color: #0000d7; /* 020 Blue3 */
+}
+.cef-21 {
+ color: #0000ff; /* 021 Blue1 */
+}
+.cef-22 {
+ color: #005f00; /* 022 DarkGreen */
+}
+.cef-23 {
+ color: #005f5f; /* 023 DeepSkyBlue4 */
+}
+.cef-24 {
+ color: #005f87; /* 024 DeepSkyBlue4 */
+}
+.cef-25 {
+ color: #005faf; /* 025 DeepSkyBlue4 */
+}
+.cef-26 {
+ color: #005fd7; /* 026 DodgerBlue3 */
+}
+.cef-27 {
+ color: #005fff; /* 027 DodgerBlue2 */
+}
+.cef-28 {
+ color: #008700; /* 028 Green4 */
+}
+.cef-29 {
+ color: #00875f; /* 029 SpringGreen4 */
+}
+.cef-30 {
+ color: #008787; /* 030 Turquoise4 */
+}
+.cef-31 {
+ color: #0087af; /* 031 DeepSkyBlue3 */
+}
+.cef-32 {
+ color: #0087d7; /* 032 DeepSkyBlue3 */
+}
+.cef-33 {
+ color: #0087ff; /* 033 DodgerBlue1 */
+}
+.cef-34 {
+ color: #00af00; /* 034 Green3 */
+}
+.cef-35 {
+ color: #00af5f; /* 035 SpringGreen3 */
+}
+.cef-36 {
+ color: #00af87; /* 036 DarkCyan */
+}
+.cef-37 {
+ color: #00afaf; /* 037 LightSeaGreen */
+}
+.cef-38 {
+ color: #00afd7; /* 038 DeepSkyBlue2 */
+}
+.cef-39 {
+ color: #00afff; /* 039 DeepSkyBlue1 */
+}
+.cef-40 {
+ color: #00d700; /* 040 Green3 */
+}
+.cef-41 {
+ color: #00d75f; /* 041 SpringGreen3 */
+}
+.cef-42 {
+ color: #00d787; /* 042 SpringGreen2 */
+}
+.cef-43 {
+ color: #00d7af; /* 043 Cyan3 */
+}
+.cef-44 {
+ color: #00d7d7; /* 044 DarkTurquoise */
+}
+.cef-45 {
+ color: #00d7ff; /* 045 Turquoise2 */
+}
+.cef-46 {
+ color: #00ff00; /* 046 Green1 */
+}
+.cef-47 {
+ color: #00ff5f; /* 047 SpringGreen2 */
+}
+.cef-48 {
+ color: #00ff87; /* 048 SpringGreen1 */
+}
+.cef-49 {
+ color: #00ffaf; /* 049 MediumSpringGreen */
+}
+.cef-50 {
+ color: #00ffd7; /* 050 Cyan2 */
+}
+.cef-51 {
+ color: #00ffff; /* 051 Cyan1 */
+}
+.cef-52 {
+ color: #5f0000; /* 052 DarkRed */
+}
+.cef-53 {
+ color: #5f005f; /* 053 DeepPink4 */
+}
+.cef-54 {
+ color: #5f0087; /* 054 Purple4 */
+}
+.cef-55 {
+ color: #5f00af; /* 055 Purple4 */
+}
+.cef-56 {
+ color: #5f00d7; /* 056 Purple3 */
+}
+.cef-57 {
+ color: #5f00ff; /* 057 BlueViolet */
+}
+.cef-58 {
+ color: #5f5f00; /* 058 Orange4 */
+}
+.cef-59 {
+ color: #5f5f5f; /* 059 Grey37 */
+}
+.cef-60 {
+ color: #5f5f87; /* 060 MediumPurple4 */
+}
+.cef-61 {
+ color: #5f5faf; /* 061 SlateBlue3 */
+}
+.cef-62 {
+ color: #5f5fd7; /* 062 SlateBlue3 */
+}
+.cef-63 {
+ color: #5f5fff; /* 063 RoyalBlue1 */
+}
+.cef-64 {
+ color: #5f8700; /* 064 Chartreuse4 */
+}
+.cef-65 {
+ color: #5f875f; /* 065 DarkSeaGreen4 */
+}
+.cef-66 {
+ color: #5f8787; /* 066 PaleTurquoise4 */
+}
+.cef-67 {
+ color: #5f87af; /* 067 SteelBlue */
+}
+.cef-68 {
+ color: #5f87d7; /* 068 SteelBlue3 */
+}
+.cef-69 {
+ color: #5f87ff; /* 069 CornflowerBlue */
+}
+.cef-70 {
+ color: #5faf00; /* 070 Chartreuse3 */
+}
+.cef-71 {
+ color: #5faf5f; /* 071 DarkSeaGreen4 */
+}
+.cef-72 {
+ color: #5faf87; /* 072 CadetBlue */
+}
+.cef-73 {
+ color: #5fafaf; /* 073 CadetBlue */
+}
+.cef-74 {
+ color: #5fafd7; /* 074 SkyBlue3 */
+}
+.cef-75 {
+ color: #5fafff; /* 075 SteelBlue1 */
+}
+.cef-76 {
+ color: #5fd700; /* 076 Chartreuse3 */
+}
+.cef-77 {
+ color: #5fd75f; /* 077 PaleGreen3 */
+}
+.cef-78 {
+ color: #5fd787; /* 078 SeaGreen3 */
+}
+.cef-79 {
+ color: #5fd7af; /* 079 Aquamarine3 */
+}
+.cef-80 {
+ color: #5fd7d7; /* 080 MediumTurquoise */
+}
+.cef-81 {
+ color: #5fd7ff; /* 081 SteelBlue1 */
+}
+.cef-82 {
+ color: #5fff00; /* 082 Chartreuse2 */
+}
+.cef-83 {
+ color: #5fff5f; /* 083 SeaGreen2 */
+}
+.cef-84 {
+ color: #5fff87; /* 084 SeaGreen1 */
+}
+.cef-85 {
+ color: #5fffaf; /* 085 SeaGreen1 */
+}
+.cef-86 {
+ color: #5fffd7; /* 086 Aquamarine1 */
+}
+.cef-87 {
+ color: #5fffff; /* 087 DarkSlateGray2 */
+}
+.cef-88 {
+ color: #870000; /* 088 DarkRed */
+}
+.cef-89 {
+ color: #87005f; /* 089 DeepPink4 */
+}
+.cef-90 {
+ color: #870087; /* 090 DarkMagenta */
+}
+.cef-91 {
+ color: #8700af; /* 091 DarkMagenta */
+}
+.cef-92 {
+ color: #8700d7; /* 092 DarkViolet */
+}
+.cef-93 {
+ color: #8700ff; /* 093 Purple */
+}
+.cef-94 {
+ color: #875f00; /* 094 Orange4 */
+}
+.cef-95 {
+ color: #875f5f; /* 095 LightPink4 */
+}
+.cef-96 {
+ color: #875f87; /* 096 Plum4 */
+}
+.cef-97 {
+ color: #875faf; /* 097 MediumPurple3 */
+}
+.cef-98 {
+ color: #875fd7; /* 098 MediumPurple3 */
+}
+.cef-99 {
+ color: #875fff; /* 099 SlateBlue1 */
+}
+.cef-100 {
+ color: #878700; /* 100 Yellow4 */
+}
+.cef-101 {
+ color: #87875f; /* 101 Wheat4 */
+}
+.cef-102 {
+ color: #878787; /* 102 Grey53 */
+}
+.cef-103 {
+ color: #8787af; /* 103 LightSlateGrey */
+}
+.cef-104 {
+ color: #8787d7; /* 104 MediumPurple */
+}
+.cef-105 {
+ color: #8787ff; /* 105 LightSlateBlue */
+}
+.cef-106 {
+ color: #87af00; /* 106 Yellow4 */
+}
+.cef-107 {
+ color: #87af5f; /* 107 DarkOliveGreen3 */
+}
+.cef-108 {
+ color: #87af87; /* 108 DarkSeaGreen */
+}
+.cef-109 {
+ color: #87afaf; /* 109 LightSkyBlue3 */
+}
+.cef-110 {
+ color: #87afd7; /* 110 LightSkyBlue3 */
+}
+.cef-111 {
+ color: #87afff; /* 111 SkyBlue2 */
+}
+.cef-112 {
+ color: #87d700; /* 112 Chartreuse2 */
+}
+.cef-113 {
+ color: #87d75f; /* 113 DarkOliveGreen3 */
+}
+.cef-114 {
+ color: #87d787; /* 114 PaleGreen3 */
+}
+.cef-115 {
+ color: #87d7af; /* 115 DarkSeaGreen3 */
+}
+.cef-116 {
+ color: #87d7d7; /* 116 DarkSlateGray3 */
+}
+.cef-117 {
+ color: #87d7ff; /* 117 SkyBlue1 */
+}
+.cef-118 {
+ color: #87ff00; /* 118 Chartreuse1 */
+}
+.cef-119 {
+ color: #87ff5f; /* 119 LightGreen */
+}
+.cef-120 {
+ color: #87ff87; /* 120 LightGreen */
+}
+.cef-121 {
+ color: #87ffaf; /* 121 PaleGreen1 */
+}
+.cef-122 {
+ color: #87ffd7; /* 122 Aquamarine1 */
+}
+.cef-123 {
+ color: #87ffff; /* 123 DarkSlateGray1 */
+}
+.cef-124 {
+ color: #af0000; /* 124 Red3 */
+}
+.cef-125 {
+ color: #af005f; /* 125 DeepPink4 */
+}
+.cef-126 {
+ color: #af0087; /* 126 MediumVioletRed */
+}
+.cef-127 {
+ color: #af00af; /* 127 Magenta3 */
+}
+.cef-128 {
+ color: #af00d7; /* 128 DarkViolet */
+}
+.cef-129 {
+ color: #af00ff; /* 129 Purple */
+}
+.cef-130 {
+ color: #af5f00; /* 130 DarkOrange3 */
+}
+.cef-131 {
+ color: #af5f5f; /* 131 IndianRed */
+}
+.cef-132 {
+ color: #af5f87; /* 132 HotPink3 */
+}
+.cef-133 {
+ color: #af5faf; /* 133 MediumOrchid3 */
+}
+.cef-134 {
+ color: #af5fd7; /* 134 MediumOrchid */
+}
+.cef-135 {
+ color: #af5fff; /* 135 MediumPurple2 */
+}
+.cef-136 {
+ color: #af8700; /* 136 DarkGoldenrod */
+}
+.cef-137 {
+ color: #af875f; /* 137 LightSalmon3 */
+}
+.cef-138 {
+ color: #af8787; /* 138 RosyBrown */
+}
+.cef-139 {
+ color: #af87af; /* 139 Grey63 */
+}
+.cef-140 {
+ color: #af87d7; /* 140 MediumPurple2 */
+}
+.cef-141 {
+ color: #af87ff; /* 141 MediumPurple1 */
+}
+.cef-142 {
+ color: #afaf00; /* 142 Gold3 */
+}
+.cef-143 {
+ color: #afaf5f; /* 143 DarkKhaki */
+}
+.cef-144 {
+ color: #afaf87; /* 144 NavajoWhite3 */
+}
+.cef-145 {
+ color: #afafaf; /* 145 Grey69 */
+}
+.cef-146 {
+ color: #afafd7; /* 146 LightSteelBlue3 */
+}
+.cef-147 {
+ color: #afafff; /* 147 LightSteelBlue */
+}
+.cef-148 {
+ color: #afd700; /* 148 Yellow3 */
+}
+.cef-149 {
+ color: #afd75f; /* 149 DarkOliveGreen3 */
+}
+.cef-150 {
+ color: #afd787; /* 150 DarkSeaGreen3 */
+}
+.cef-151 {
+ color: #afd7af; /* 151 DarkSeaGreen2 */
+}
+.cef-152 {
+ color: #afd7d7; /* 152 LightCyan3 */
+}
+.cef-153 {
+ color: #afd7ff; /* 153 LightSkyBlue1 */
+}
+.cef-154 {
+ color: #afff00; /* 154 GreenYellow */
+}
+.cef-155 {
+ color: #afff5f; /* 155 DarkOliveGreen2 */
+}
+.cef-156 {
+ color: #afff87; /* 156 PaleGreen1 */
+}
+.cef-157 {
+ color: #afffaf; /* 157 DarkSeaGreen2 */
+}
+.cef-158 {
+ color: #afffd7; /* 158 DarkSeaGreen1 */
+}
+.cef-159 {
+ color: #afffff; /* 159 PaleTurquoise1 */
+}
+.cef-160 {
+ color: #d70000; /* 160 Red3 */
+}
+.cef-161 {
+ color: #d7005f; /* 161 DeepPink3 */
+}
+.cef-162 {
+ color: #d70087; /* 162 DeepPink3 */
+}
+.cef-163 {
+ color: #d700af; /* 163 Magenta3 */
+}
+.cef-164 {
+ color: #d700d7; /* 164 Magenta3 */
+}
+.cef-165 {
+ color: #d700ff; /* 165 Magenta2 */
+}
+.cef-166 {
+ color: #d75f00; /* 166 DarkOrange3 */
+}
+.cef-167 {
+ color: #d75f5f; /* 167 IndianRed */
+}
+.cef-168 {
+ color: #d75f87; /* 168 HotPink3 */
+}
+.cef-169 {
+ color: #d75faf; /* 169 HotPink2 */
+}
+.cef-170 {
+ color: #d75fd7; /* 170 Orchid */
+}
+.cef-171 {
+ color: #d75fff; /* 171 MediumOrchid1 */
+}
+.cef-172 {
+ color: #d78700; /* 172 Orange3 */
+}
+.cef-173 {
+ color: #d7875f; /* 173 LightSalmon3 */
+}
+.cef-174 {
+ color: #d78787; /* 174 LightPink3 */
+}
+.cef-175 {
+ color: #d787af; /* 175 Pink3 */
+}
+.cef-176 {
+ color: #d787d7; /* 176 Plum3 */
+}
+.cef-177 {
+ color: #d787ff; /* 177 Violet */
+}
+.cef-178 {
+ color: #d7af00; /* 178 Gold3 */
+}
+.cef-179 {
+ color: #d7af5f; /* 179 LightGoldenrod3 */
+}
+.cef-180 {
+ color: #d7af87; /* 180 Tan */
+}
+.cef-181 {
+ color: #d7afaf; /* 181 MistyRose3 */
+}
+.cef-182 {
+ color: #d7afd7; /* 182 Thistle3 */
+}
+.cef-183 {
+ color: #d7afff; /* 183 Plum2 */
+}
+.cef-184 {
+ color: #d7d700; /* 184 Yellow3 */
+}
+.cef-185 {
+ color: #d7d75f; /* 185 Khaki3 */
+}
+.cef-186 {
+ color: #d7d787; /* 186 LightGoldenrod2 */
+}
+.cef-187 {
+ color: #d7d7af; /* 187 LightYellow3 */
+}
+.cef-188 {
+ color: #d7d7d7; /* 188 Grey84 */
+}
+.cef-189 {
+ color: #d7d7ff; /* 189 LightSteelBlue1 */
+}
+.cef-190 {
+ color: #d7ff00; /* 190 Yellow2 */
+}
+.cef-191 {
+ color: #d7ff5f; /* 191 DarkOliveGreen1 */
+}
+.cef-192 {
+ color: #d7ff87; /* 192 DarkOliveGreen1 */
+}
+.cef-193 {
+ color: #d7ffaf; /* 193 DarkSeaGreen1 */
+}
+.cef-194 {
+ color: #d7ffd7; /* 194 Honeydew2 */
+}
+.cef-195 {
+ color: #d7ffff; /* 195 LightCyan1 */
+}
+.cef-196 {
+ color: #ff0000; /* 196 Red1 */
+}
+.cef-197 {
+ color: #ff005f; /* 197 DeepPink2 */
+}
+.cef-198 {
+ color: #ff0087; /* 198 DeepPink1 */
+}
+.cef-199 {
+ color: #ff00af; /* 199 DeepPink1 */
+}
+.cef-200 {
+ color: #ff00d7; /* 200 Magenta2 */
+}
+.cef-201 {
+ color: #ff00ff; /* 201 Magenta1 */
+}
+.cef-202 {
+ color: #ff5f00; /* 202 OrangeRed1 */
+}
+.cef-203 {
+ color: #ff5f5f; /* 203 IndianRed1 */
+}
+.cef-204 {
+ color: #ff5f87; /* 204 IndianRed1 */
+}
+.cef-205 {
+ color: #ff5faf; /* 205 HotPink */
+}
+.cef-206 {
+ color: #ff5fd7; /* 206 HotPink */
+}
+.cef-207 {
+ color: #ff5fff; /* 207 MediumOrchid1 */
+}
+.cef-208 {
+ color: #ff8700; /* 208 DarkOrange */
+}
+.cef-209 {
+ color: #ff875f; /* 209 Salmon1 */
+}
+.cef-210 {
+ color: #ff8787; /* 210 LightCoral */
+}
+.cef-211 {
+ color: #ff87af; /* 211 PaleVioletRed1 */
+}
+.cef-212 {
+ color: #ff87d7; /* 212 Orchid2 */
+}
+.cef-213 {
+ color: #ff87ff; /* 213 Orchid1 */
+}
+.cef-214 {
+ color: #ffaf00; /* 214 Orange1 */
+}
+.cef-215 {
+ color: #ffaf5f; /* 215 SandyBrown */
+}
+.cef-216 {
+ color: #ffaf87; /* 216 LightSalmon1 */
+}
+.cef-217 {
+ color: #ffafaf; /* 217 LightPink1 */
+}
+.cef-218 {
+ color: #ffafd7; /* 218 Pink1 */
+}
+.cef-219 {
+ color: #ffafff; /* 219 Plum1 */
+}
+.cef-220 {
+ color: #ffd700; /* 220 Gold1 */
+}
+.cef-221 {
+ color: #ffd75f; /* 221 LightGoldenrod2 */
+}
+.cef-222 {
+ color: #ffd787; /* 222 LightGoldenrod2 */
+}
+.cef-223 {
+ color: #ffd7af; /* 223 NavajoWhite1 */
+}
+.cef-224 {
+ color: #ffd7d7; /* 224 MistyRose1 */
+}
+.cef-225 {
+ color: #ffd7ff; /* 225 Thistle1 */
+}
+.cef-226 {
+ color: #ffff00; /* 226 Yellow1 */
+}
+.cef-227 {
+ color: #ffff5f; /* 227 LightGoldenrod1 */
+}
+.cef-228 {
+ color: #ffff87; /* 228 Khaki1 */
+}
+.cef-229 {
+ color: #ffffaf; /* 229 Wheat1 */
+}
+.cef-230 {
+ color: #ffffd7; /* 230 Cornsilk1 */
+}
+.cef-231 {
+ color: #ffffff; /* 231 Grey100 */
+}
+.cef-232 {
+ color: #080808; /* 232 Grey3 */
+}
+.cef-233 {
+ color: #121212; /* 233 Grey7 */
+}
+.cef-234 {
+ color: #1c1c1c; /* 234 Grey11 */
+}
+.cef-235 {
+ color: #262626; /* 235 Grey15 */
+}
+.cef-236 {
+ color: #303030; /* 236 Grey19 */
+}
+.cef-237 {
+ color: #3a3a3a; /* 237 Grey23 */
+}
+.cef-238 {
+ color: #444444; /* 238 Grey27 */
+}
+.cef-239 {
+ color: #4e4e4e; /* 239 Grey30 */
+}
+.cef-240 {
+ color: #585858; /* 240 Grey35 */
+}
+.cef-241 {
+ color: #626262; /* 241 Grey39 */
+}
+.cef-242 {
+ color: #6c6c6c; /* 242 Grey42 */
+}
+.cef-243 {
+ color: #767676; /* 243 Grey46 */
+}
+.cef-244 {
+ color: #808080; /* 244 Grey50 */
+}
+.cef-245 {
+ color: #8a8a8a; /* 245 Grey54 */
+}
+.cef-246 {
+ color: #949494; /* 246 Grey58 */
+}
+.cef-247 {
+ color: #9e9e9e; /* 247 Grey62 */
+}
+.cef-248 {
+ color: #a8a8a8; /* 248 Grey66 */
+}
+.cef-249 {
+ color: #b2b2b2; /* 249 Grey70 */
+}
+.cef-250 {
+ color: #bcbcbc; /* 250 Grey74 */
+}
+.cef-251 {
+ color: #c6c6c6; /* 251 Grey78 */
+}
+.cef-252 {
+ color: #d0d0d0; /* 252 Grey82 */
+}
+.cef-253 {
+ color: #dadada; /* 253 Grey85 */
+}
+.cef-254 {
+ color: #e4e4e4; /* 254 Grey89 */
+}
+.cef-255 {
+ color: #eeeeee; /* 255 Grey93 */
+}
+
+/* extended colors, background */
+.ceb-0 {
+ background-color: #000000; /* 000 Black */
+}
+.ceb-1 {
+ background-color: #cd0000; /* 001 DarkRed */
+}
+.ceb-2 {
+ background-color: #00cd00; /* 002 DarkGreen */
+}
+.ceb-3 {
+ background-color: #cdcd00; /* 003 DarkYellow */
+}
+.ceb-4 {
+ background-color: #0000ee; /* 004 DarkBlue */
+}
+.ceb-5 {
+ background-color: #cd00cd; /* 005 DarkMagenta */
+}
+.ceb-6 {
+ background-color: #00cdcd; /* 006 DarkCyan */
+}
+.ceb-7 {
+ background-color: #e5e5e5; /* 007 LightGrey */
+}
+.ceb-8 {
+ background-color: #7f7f7f; /* 008 DarkGrey */
+}
+.ceb-9 {
+ background-color: #ff0000; /* 009 LightRed */
+}
+.ceb-10 {
+ background-color: #00ff00; /* 010 LightGreen */
+}
+.ceb-11 {
+ background-color: #ffff00; /* 011 LightYellow */
+}
+.ceb-12 {
+ background-color: #5c5cff; /* 012 LightBlue */
+}
+.ceb-13 {
+ background-color: #ff00ff; /* 013 LightMagenta */
+}
+.ceb-14 {
+ background-color: #00ffff; /* 014 LightCyan */
+}
+.ceb-15 {
+ background-color: #ffffff; /* 015 White */
+}
+.ceb-16 {
+ background-color: #000000; /* 016 Grey0 */
+}
+.ceb-17 {
+ background-color: #00005f; /* 017 NavyBlue */
+}
+.ceb-18 {
+ background-color: #000087; /* 018 DarkBlue */
+}
+.ceb-19 {
+ background-color: #0000af; /* 019 Blue3 */
+}
+.ceb-20 {
+ background-color: #0000d7; /* 020 Blue3 */
+}
+.ceb-21 {
+ background-color: #0000ff; /* 021 Blue1 */
+}
+.ceb-22 {
+ background-color: #005f00; /* 022 DarkGreen */
+}
+.ceb-23 {
+ background-color: #005f5f; /* 023 DeepSkyBlue4 */
+}
+.ceb-24 {
+ background-color: #005f87; /* 024 DeepSkyBlue4 */
+}
+.ceb-25 {
+ background-color: #005faf; /* 025 DeepSkyBlue4 */
+}
+.ceb-26 {
+ background-color: #005fd7; /* 026 DodgerBlue3 */
+}
+.ceb-27 {
+ background-color: #005fff; /* 027 DodgerBlue2 */
+}
+.ceb-28 {
+ background-color: #008700; /* 028 Green4 */
+}
+.ceb-29 {
+ background-color: #00875f; /* 029 SpringGreen4 */
+}
+.ceb-30 {
+ background-color: #008787; /* 030 Turquoise4 */
+}
+.ceb-31 {
+ background-color: #0087af; /* 031 DeepSkyBlue3 */
+}
+.ceb-32 {
+ background-color: #0087d7; /* 032 DeepSkyBlue3 */
+}
+.ceb-33 {
+ background-color: #0087ff; /* 033 DodgerBlue1 */
+}
+.ceb-34 {
+ background-color: #00af00; /* 034 Green3 */
+}
+.ceb-35 {
+ background-color: #00af5f; /* 035 SpringGreen3 */
+}
+.ceb-36 {
+ background-color: #00af87; /* 036 DarkCyan */
+}
+.ceb-37 {
+ background-color: #00afaf; /* 037 LightSeaGreen */
+}
+.ceb-38 {
+ background-color: #00afd7; /* 038 DeepSkyBlue2 */
+}
+.ceb-39 {
+ background-color: #00afff; /* 039 DeepSkyBlue1 */
+}
+.ceb-40 {
+ background-color: #00d700; /* 040 Green3 */
+}
+.ceb-41 {
+ background-color: #00d75f; /* 041 SpringGreen3 */
+}
+.ceb-42 {
+ background-color: #00d787; /* 042 SpringGreen2 */
+}
+.ceb-43 {
+ background-color: #00d7af; /* 043 Cyan3 */
+}
+.ceb-44 {
+ background-color: #00d7d7; /* 044 DarkTurquoise */
+}
+.ceb-45 {
+ background-color: #00d7ff; /* 045 Turquoise2 */
+}
+.ceb-46 {
+ background-color: #00ff00; /* 046 Green1 */
+}
+.ceb-47 {
+ background-color: #00ff5f; /* 047 SpringGreen2 */
+}
+.ceb-48 {
+ background-color: #00ff87; /* 048 SpringGreen1 */
+}
+.ceb-49 {
+ background-color: #00ffaf; /* 049 MediumSpringGreen */
+}
+.ceb-50 {
+ background-color: #00ffd7; /* 050 Cyan2 */
+}
+.ceb-51 {
+ background-color: #00ffff; /* 051 Cyan1 */
+}
+.ceb-52 {
+ background-color: #5f0000; /* 052 DarkRed */
+}
+.ceb-53 {
+ background-color: #5f005f; /* 053 DeepPink4 */
+}
+.ceb-54 {
+ background-color: #5f0087; /* 054 Purple4 */
+}
+.ceb-55 {
+ background-color: #5f00af; /* 055 Purple4 */
+}
+.ceb-56 {
+ background-color: #5f00d7; /* 056 Purple3 */
+}
+.ceb-57 {
+ background-color: #5f00ff; /* 057 BlueViolet */
+}
+.ceb-58 {
+ background-color: #5f5f00; /* 058 Orange4 */
+}
+.ceb-59 {
+ background-color: #5f5f5f; /* 059 Grey37 */
+}
+.ceb-60 {
+ background-color: #5f5f87; /* 060 MediumPurple4 */
+}
+.ceb-61 {
+ background-color: #5f5faf; /* 061 SlateBlue3 */
+}
+.ceb-62 {
+ background-color: #5f5fd7; /* 062 SlateBlue3 */
+}
+.ceb-63 {
+ background-color: #5f5fff; /* 063 RoyalBlue1 */
+}
+.ceb-64 {
+ background-color: #5f8700; /* 064 Chartreuse4 */
+}
+.ceb-65 {
+ background-color: #5f875f; /* 065 DarkSeaGreen4 */
+}
+.ceb-66 {
+ background-color: #5f8787; /* 066 PaleTurquoise4 */
+}
+.ceb-67 {
+ background-color: #5f87af; /* 067 SteelBlue */
+}
+.ceb-68 {
+ background-color: #5f87d7; /* 068 SteelBlue3 */
+}
+.ceb-69 {
+ background-color: #5f87ff; /* 069 CornflowerBlue */
+}
+.ceb-70 {
+ background-color: #5faf00; /* 070 Chartreuse3 */
+}
+.ceb-71 {
+ background-color: #5faf5f; /* 071 DarkSeaGreen4 */
+}
+.ceb-72 {
+ background-color: #5faf87; /* 072 CadetBlue */
+}
+.ceb-73 {
+ background-color: #5fafaf; /* 073 CadetBlue */
+}
+.ceb-74 {
+ background-color: #5fafd7; /* 074 SkyBlue3 */
+}
+.ceb-75 {
+ background-color: #5fafff; /* 075 SteelBlue1 */
+}
+.ceb-76 {
+ background-color: #5fd700; /* 076 Chartreuse3 */
+}
+.ceb-77 {
+ background-color: #5fd75f; /* 077 PaleGreen3 */
+}
+.ceb-78 {
+ background-color: #5fd787; /* 078 SeaGreen3 */
+}
+.ceb-79 {
+ background-color: #5fd7af; /* 079 Aquamarine3 */
+}
+.ceb-80 {
+ background-color: #5fd7d7; /* 080 MediumTurquoise */
+}
+.ceb-81 {
+ background-color: #5fd7ff; /* 081 SteelBlue1 */
+}
+.ceb-82 {
+ background-color: #5fff00; /* 082 Chartreuse2 */
+}
+.ceb-83 {
+ background-color: #5fff5f; /* 083 SeaGreen2 */
+}
+.ceb-84 {
+ background-color: #5fff87; /* 084 SeaGreen1 */
+}
+.ceb-85 {
+ background-color: #5fffaf; /* 085 SeaGreen1 */
+}
+.ceb-86 {
+ background-color: #5fffd7; /* 086 Aquamarine1 */
+}
+.ceb-87 {
+ background-color: #5fffff; /* 087 DarkSlateGray2 */
+}
+.ceb-88 {
+ background-color: #870000; /* 088 DarkRed */
+}
+.ceb-89 {
+ background-color: #87005f; /* 089 DeepPink4 */
+}
+.ceb-90 {
+ background-color: #870087; /* 090 DarkMagenta */
+}
+.ceb-91 {
+ background-color: #8700af; /* 091 DarkMagenta */
+}
+.ceb-92 {
+ background-color: #8700d7; /* 092 DarkViolet */
+}
+.ceb-93 {
+ background-color: #8700ff; /* 093 Purple */
+}
+.ceb-94 {
+ background-color: #875f00; /* 094 Orange4 */
+}
+.ceb-95 {
+ background-color: #875f5f; /* 095 LightPink4 */
+}
+.ceb-96 {
+ background-color: #875f87; /* 096 Plum4 */
+}
+.ceb-97 {
+ background-color: #875faf; /* 097 MediumPurple3 */
+}
+.ceb-98 {
+ background-color: #875fd7; /* 098 MediumPurple3 */
+}
+.ceb-99 {
+ background-color: #875fff; /* 099 SlateBlue1 */
+}
+.ceb-100 {
+ background-color: #878700; /* 100 Yellow4 */
+}
+.ceb-101 {
+ background-color: #87875f; /* 101 Wheat4 */
+}
+.ceb-102 {
+ background-color: #878787; /* 102 Grey53 */
+}
+.ceb-103 {
+ background-color: #8787af; /* 103 LightSlateGrey */
+}
+.ceb-104 {
+ background-color: #8787d7; /* 104 MediumPurple */
+}
+.ceb-105 {
+ background-color: #8787ff; /* 105 LightSlateBlue */
+}
+.ceb-106 {
+ background-color: #87af00; /* 106 Yellow4 */
+}
+.ceb-107 {
+ background-color: #87af5f; /* 107 DarkOliveGreen3 */
+}
+.ceb-108 {
+ background-color: #87af87; /* 108 DarkSeaGreen */
+}
+.ceb-109 {
+ background-color: #87afaf; /* 109 LightSkyBlue3 */
+}
+.ceb-110 {
+ background-color: #87afd7; /* 110 LightSkyBlue3 */
+}
+.ceb-111 {
+ background-color: #87afff; /* 111 SkyBlue2 */
+}
+.ceb-112 {
+ background-color: #87d700; /* 112 Chartreuse2 */
+}
+.ceb-113 {
+ background-color: #87d75f; /* 113 DarkOliveGreen3 */
+}
+.ceb-114 {
+ background-color: #87d787; /* 114 PaleGreen3 */
+}
+.ceb-115 {
+ background-color: #87d7af; /* 115 DarkSeaGreen3 */
+}
+.ceb-116 {
+ background-color: #87d7d7; /* 116 DarkSlateGray3 */
+}
+.ceb-117 {
+ background-color: #87d7ff; /* 117 SkyBlue1 */
+}
+.ceb-118 {
+ background-color: #87ff00; /* 118 Chartreuse1 */
+}
+.ceb-119 {
+ background-color: #87ff5f; /* 119 LightGreen */
+}
+.ceb-120 {
+ background-color: #87ff87; /* 120 LightGreen */
+}
+.ceb-121 {
+ background-color: #87ffaf; /* 121 PaleGreen1 */
+}
+.ceb-122 {
+ background-color: #87ffd7; /* 122 Aquamarine1 */
+}
+.ceb-123 {
+ background-color: #87ffff; /* 123 DarkSlateGray1 */
+}
+.ceb-124 {
+ background-color: #af0000; /* 124 Red3 */
+}
+.ceb-125 {
+ background-color: #af005f; /* 125 DeepPink4 */
+}
+.ceb-126 {
+ background-color: #af0087; /* 126 MediumVioletRed */
+}
+.ceb-127 {
+ background-color: #af00af; /* 127 Magenta3 */
+}
+.ceb-128 {
+ background-color: #af00d7; /* 128 DarkViolet */
+}
+.ceb-129 {
+ background-color: #af00ff; /* 129 Purple */
+}
+.ceb-130 {
+ background-color: #af5f00; /* 130 DarkOrange3 */
+}
+.ceb-131 {
+ background-color: #af5f5f; /* 131 IndianRed */
+}
+.ceb-132 {
+ background-color: #af5f87; /* 132 HotPink3 */
+}
+.ceb-133 {
+ background-color: #af5faf; /* 133 MediumOrchid3 */
+}
+.ceb-134 {
+ background-color: #af5fd7; /* 134 MediumOrchid */
+}
+.ceb-135 {
+ background-color: #af5fff; /* 135 MediumPurple2 */
+}
+.ceb-136 {
+ background-color: #af8700; /* 136 DarkGoldenrod */
+}
+.ceb-137 {
+ background-color: #af875f; /* 137 LightSalmon3 */
+}
+.ceb-138 {
+ background-color: #af8787; /* 138 RosyBrown */
+}
+.ceb-139 {
+ background-color: #af87af; /* 139 Grey63 */
+}
+.ceb-140 {
+ background-color: #af87d7; /* 140 MediumPurple2 */
+}
+.ceb-141 {
+ background-color: #af87ff; /* 141 MediumPurple1 */
+}
+.ceb-142 {
+ background-color: #afaf00; /* 142 Gold3 */
+}
+.ceb-143 {
+ background-color: #afaf5f; /* 143 DarkKhaki */
+}
+.ceb-144 {
+ background-color: #afaf87; /* 144 NavajoWhite3 */
+}
+.ceb-145 {
+ background-color: #afafaf; /* 145 Grey69 */
+}
+.ceb-146 {
+ background-color: #afafd7; /* 146 LightSteelBlue3 */
+}
+.ceb-147 {
+ background-color: #afafff; /* 147 LightSteelBlue */
+}
+.ceb-148 {
+ background-color: #afd700; /* 148 Yellow3 */
+}
+.ceb-149 {
+ background-color: #afd75f; /* 149 DarkOliveGreen3 */
+}
+.ceb-150 {
+ background-color: #afd787; /* 150 DarkSeaGreen3 */
+}
+.ceb-151 {
+ background-color: #afd7af; /* 151 DarkSeaGreen2 */
+}
+.ceb-152 {
+ background-color: #afd7d7; /* 152 LightCyan3 */
+}
+.ceb-153 {
+ background-color: #afd7ff; /* 153 LightSkyBlue1 */
+}
+.ceb-154 {
+ background-color: #afff00; /* 154 GreenYellow */
+}
+.ceb-155 {
+ background-color: #afff5f; /* 155 DarkOliveGreen2 */
+}
+.ceb-156 {
+ background-color: #afff87; /* 156 PaleGreen1 */
+}
+.ceb-157 {
+ background-color: #afffaf; /* 157 DarkSeaGreen2 */
+}
+.ceb-158 {
+ background-color: #afffd7; /* 158 DarkSeaGreen1 */
+}
+.ceb-159 {
+ background-color: #afffff; /* 159 PaleTurquoise1 */
+}
+.ceb-160 {
+ background-color: #d70000; /* 160 Red3 */
+}
+.ceb-161 {
+ background-color: #d7005f; /* 161 DeepPink3 */
+}
+.ceb-162 {
+ background-color: #d70087; /* 162 DeepPink3 */
+}
+.ceb-163 {
+ background-color: #d700af; /* 163 Magenta3 */
+}
+.ceb-164 {
+ background-color: #d700d7; /* 164 Magenta3 */
+}
+.ceb-165 {
+ background-color: #d700ff; /* 165 Magenta2 */
+}
+.ceb-166 {
+ background-color: #d75f00; /* 166 DarkOrange3 */
+}
+.ceb-167 {
+ background-color: #d75f5f; /* 167 IndianRed */
+}
+.ceb-168 {
+ background-color: #d75f87; /* 168 HotPink3 */
+}
+.ceb-169 {
+ background-color: #d75faf; /* 169 HotPink2 */
+}
+.ceb-170 {
+ background-color: #d75fd7; /* 170 Orchid */
+}
+.ceb-171 {
+ background-color: #d75fff; /* 171 MediumOrchid1 */
+}
+.ceb-172 {
+ background-color: #d78700; /* 172 Orange3 */
+}
+.ceb-173 {
+ background-color: #d7875f; /* 173 LightSalmon3 */
+}
+.ceb-174 {
+ background-color: #d78787; /* 174 LightPink3 */
+}
+.ceb-175 {
+ background-color: #d787af; /* 175 Pink3 */
+}
+.ceb-176 {
+ background-color: #d787d7; /* 176 Plum3 */
+}
+.ceb-177 {
+ background-color: #d787ff; /* 177 Violet */
+}
+.ceb-178 {
+ background-color: #d7af00; /* 178 Gold3 */
+}
+.ceb-179 {
+ background-color: #d7af5f; /* 179 LightGoldenrod3 */
+}
+.ceb-180 {
+ background-color: #d7af87; /* 180 Tan */
+}
+.ceb-181 {
+ background-color: #d7afaf; /* 181 MistyRose3 */
+}
+.ceb-182 {
+ background-color: #d7afd7; /* 182 Thistle3 */
+}
+.ceb-183 {
+ background-color: #d7afff; /* 183 Plum2 */
+}
+.ceb-184 {
+ background-color: #d7d700; /* 184 Yellow3 */
+}
+.ceb-185 {
+ background-color: #d7d75f; /* 185 Khaki3 */
+}
+.ceb-186 {
+ background-color: #d7d787; /* 186 LightGoldenrod2 */
+}
+.ceb-187 {
+ background-color: #d7d7af; /* 187 LightYellow3 */
+}
+.ceb-188 {
+ background-color: #d7d7d7; /* 188 Grey84 */
+}
+.ceb-189 {
+ background-color: #d7d7ff; /* 189 LightSteelBlue1 */
+}
+.ceb-190 {
+ background-color: #d7ff00; /* 190 Yellow2 */
+}
+.ceb-191 {
+ background-color: #d7ff5f; /* 191 DarkOliveGreen1 */
+}
+.ceb-192 {
+ background-color: #d7ff87; /* 192 DarkOliveGreen1 */
+}
+.ceb-193 {
+ background-color: #d7ffaf; /* 193 DarkSeaGreen1 */
+}
+.ceb-194 {
+ background-color: #d7ffd7; /* 194 Honeydew2 */
+}
+.ceb-195 {
+ background-color: #d7ffff; /* 195 LightCyan1 */
+}
+.ceb-196 {
+ background-color: #ff0000; /* 196 Red1 */
+}
+.ceb-197 {
+ background-color: #ff005f; /* 197 DeepPink2 */
+}
+.ceb-198 {
+ background-color: #ff0087; /* 198 DeepPink1 */
+}
+.ceb-199 {
+ background-color: #ff00af; /* 199 DeepPink1 */
+}
+.ceb-200 {
+ background-color: #ff00d7; /* 200 Magenta2 */
+}
+.ceb-201 {
+ background-color: #ff00ff; /* 201 Magenta1 */
+}
+.ceb-202 {
+ background-color: #ff5f00; /* 202 OrangeRed1 */
+}
+.ceb-203 {
+ background-color: #ff5f5f; /* 203 IndianRed1 */
+}
+.ceb-204 {
+ background-color: #ff5f87; /* 204 IndianRed1 */
+}
+.ceb-205 {
+ background-color: #ff5faf; /* 205 HotPink */
+}
+.ceb-206 {
+ background-color: #ff5fd7; /* 206 HotPink */
+}
+.ceb-207 {
+ background-color: #ff5fff; /* 207 MediumOrchid1 */
+}
+.ceb-208 {
+ background-color: #ff8700; /* 208 DarkOrange */
+}
+.ceb-209 {
+ background-color: #ff875f; /* 209 Salmon1 */
+}
+.ceb-210 {
+ background-color: #ff8787; /* 210 LightCoral */
+}
+.ceb-211 {
+ background-color: #ff87af; /* 211 PaleVioletRed1 */
+}
+.ceb-212 {
+ background-color: #ff87d7; /* 212 Orchid2 */
+}
+.ceb-213 {
+ background-color: #ff87ff; /* 213 Orchid1 */
+}
+.ceb-214 {
+ background-color: #ffaf00; /* 214 Orange1 */
+}
+.ceb-215 {
+ background-color: #ffaf5f; /* 215 SandyBrown */
+}
+.ceb-216 {
+ background-color: #ffaf87; /* 216 LightSalmon1 */
+}
+.ceb-217 {
+ background-color: #ffafaf; /* 217 LightPink1 */
+}
+.ceb-218 {
+ background-color: #ffafd7; /* 218 Pink1 */
+}
+.ceb-219 {
+ background-color: #ffafff; /* 219 Plum1 */
+}
+.ceb-220 {
+ background-color: #ffd700; /* 220 Gold1 */
+}
+.ceb-221 {
+ background-color: #ffd75f; /* 221 LightGoldenrod2 */
+}
+.ceb-222 {
+ background-color: #ffd787; /* 222 LightGoldenrod2 */
+}
+.ceb-223 {
+ background-color: #ffd7af; /* 223 NavajoWhite1 */
+}
+.ceb-224 {
+ background-color: #ffd7d7; /* 224 MistyRose1 */
+}
+.ceb-225 {
+ background-color: #ffd7ff; /* 225 Thistle1 */
+}
+.ceb-226 {
+ background-color: #ffff00; /* 226 Yellow1 */
+}
+.ceb-227 {
+ background-color: #ffff5f; /* 227 LightGoldenrod1 */
+}
+.ceb-228 {
+ background-color: #ffff87; /* 228 Khaki1 */
+}
+.ceb-229 {
+ background-color: #ffffaf; /* 229 Wheat1 */
+}
+.ceb-230 {
+ background-color: #ffffd7; /* 230 Cornsilk1 */
+}
+.ceb-231 {
+ background-color: #ffffff; /* 231 Grey100 */
+}
+.ceb-232 {
+ background-color: #080808; /* 232 Grey3 */
+}
+.ceb-233 {
+ background-color: #121212; /* 233 Grey7 */
+}
+.ceb-234 {
+ background-color: #1c1c1c; /* 234 Grey11 */
+}
+.ceb-235 {
+ background-color: #262626; /* 235 Grey15 */
+}
+.ceb-236 {
+ background-color: #303030; /* 236 Grey19 */
+}
+.ceb-237 {
+ background-color: #3a3a3a; /* 237 Grey23 */
+}
+.ceb-238 {
+ background-color: #444444; /* 238 Grey27 */
+}
+.ceb-239 {
+ background-color: #4e4e4e; /* 239 Grey30 */
+}
+.ceb-240 {
+ background-color: #585858; /* 240 Grey35 */
+}
+.ceb-241 {
+ background-color: #626262; /* 241 Grey39 */
+}
+.ceb-242 {
+ background-color: #6c6c6c; /* 242 Grey42 */
+}
+.ceb-243 {
+ background-color: #767676; /* 243 Grey46 */
+}
+.ceb-244 {
+ background-color: #808080; /* 244 Grey50 */
+}
+.ceb-245 {
+ background-color: #8a8a8a; /* 245 Grey54 */
+}
+.ceb-246 {
+ background-color: #949494; /* 246 Grey58 */
+}
+.ceb-247 {
+ background-color: #9e9e9e; /* 247 Grey62 */
+}
+.ceb-248 {
+ background-color: #a8a8a8; /* 248 Grey66 */
+}
+.ceb-249 {
+ background-color: #b2b2b2; /* 249 Grey70 */
+}
+.ceb-250 {
+ background-color: #bcbcbc; /* 250 Grey74 */
+}
+.ceb-251 {
+ background-color: #c6c6c6; /* 251 Grey78 */
+}
+.ceb-252 {
+ background-color: #d0d0d0; /* 252 Grey82 */
+}
+.ceb-253 {
+ background-color: #dadada; /* 253 Grey85 */
+}
+.ceb-254 {
+ background-color: #e4e4e4; /* 254 Grey89 */
+}
+.ceb-255 {
+ background-color: #eeeeee; /* 255 Grey93 */
+}
+
+/* attributes overrides */
+.a-bold {
+ font-weight: bold;
+}
+.a-no-bold {
+ font-weight: normal;
+}
+.a-italic {
+ font-style: italic;
+}
+.a-no-italic {
+ font-style: normal;
+}
+.a-underline {
+ text-decoration: underline;
+}
+.a-no-underline {
+ text-decoration: none;
+}
+.a-reset {
+ font-weight: normal;
+ font-style: normal;
+ text-decoration: none;
+}
diff --git a/index.html b/index.html
index b28d6fb..b1d4e64 100644
--- a/index.html
+++ b/index.html
@@ -7,6 +7,7 @@
+
@@ -221,9 +222,9 @@ $ openssl req -nodes -newkey rsa:2048 -keyout relay.pem -x509 -days 365 -out rel
{{ bufferline.date | date:'HH:mm' }}
- {{ part.text }} |
+ {{ part.text }} |
-
+
diff --git a/js/models.js b/js/models.js
index ce8bbea..9d53c61 100644
--- a/js/models.js
+++ b/js/models.js
@@ -4,7 +4,7 @@
*/
var models = angular.module('weechatModels', []);
-models.service('models', ['$rootScope', 'colors', function($rootScope, colors) {
+models.service('models', ['$rootScope', function($rootScope) {
/*
* Buffer class
*/
@@ -59,36 +59,64 @@ models.service('models', ['$rootScope', 'colors', function($rootScope, colors) {
* BufferLine class
*/
this.BufferLine = function(message) {
-
- /*
- * Parse the text elements from the buffer line added
- *
- * @param message weechat message
- */
- function parseLineAddedTextElements(message) {
- var text = colors.parse(message);
- text_elements =_.map(text, function(text_element) {
- if (text_element && ('fg' in text_element)) {
- text_element['fg'] = colors.prepareCss(text_element['fg']);
- }
- // TODO: parse background as well
-
- return text_element;
- });
- return text_elements;
- }
-
-
var buffer = message['buffer'];
var date = message['date'];
+ function addClasses(textElements) {
+ var typeToClassPrefixFg = {
+ 'option': 'cof-',
+ 'weechat': 'cwf-',
+ 'ext': 'cef-'
+ };
+ var typeToClassPrefixBg = {
+ 'option': 'cob-',
+ 'weechat': 'cwb-',
+ 'ext': 'ceb-'
+ };
+ textElements.forEach(function(textEl) {
+ textEl.classes = [];
- var prefix = parseLineAddedTextElements(message['prefix']);
+ // foreground color
+ var prefix = typeToClassPrefixFg[textEl.fgColor.type];
+ textEl.classes.push(prefix + textEl.fgColor.name);
+
+ // background color
+ prefix = typeToClassPrefixBg[textEl.bgColor.type];
+ textEl.classes.push(prefix + textEl.bgColor.name);
+
+ // attributes
+ if (textEl.attrs.name !== null) {
+ textEl.classes.push('coa-' + textEl.attrs.name);
+ }
+ var allReset = true;
+ for (var attr in textEl.attrs.override) {
+ if (textEl.attrs.override[attr]) {
+ allReset = false;
+ break;
+ }
+ }
+ if (allReset) {
+ textEl.classes.push('a-reset');
+ } else for (var attr in textEl.attrs.override) {
+ val = textEl.attrs.override[attr];
+ if (val) {
+ textEl.classes.push('a-' + attr);
+ } else {
+ textEl.classes.push('a-no-' + attr);
+ }
+ }
+ });
+ }
+
+
+ var prefix = weeChat.Protocol.rawText2Rich(message['prefix']);
+ addClasses(prefix);
var tags_array = message['tags_array'];
var displayed = message['displayed'];
var highlight = message['highlight'];
- var content = parseLineAddedTextElements(message['message']);
+ var content = weeChat.Protocol.rawText2Rich(message['message']);
+ addClasses(content);
var rtext = "";
if(content[0] != undefined) {
@@ -104,6 +132,7 @@ models.service('models', ['$rootScope', 'colors', function($rootScope, colors) {
highlight: highlight,
displayed: displayed,
text: rtext,
+
}
}
diff --git a/js/websockets.js b/js/websockets.js
index f44cf38..5a515bd 100644
--- a/js/websockets.js
+++ b/js/websockets.js
@@ -14,16 +14,7 @@ weechat.filter('toArray', function () {
}
});
-weechat.factory('colors', [function($scope) {
-
- return {
- prepareCss: weeChat.color.prepareCss,
- parse: weeChat.color.parse
- };
-
-}]);
-
-weechat.factory('handlers', ['$rootScope', 'colors', 'models', 'plugins', function($rootScope, colors, models, plugins) {
+weechat.factory('handlers', ['$rootScope', 'models', 'plugins', function($rootScope, models, plugins) {
var handleBufferClosing = function(message) {
var bufferMessage = message['objects'][0]['content'][0];
@@ -147,7 +138,7 @@ weechat.factory('handlers', ['$rootScope', 'colors', 'models', 'plugins', functi
}]);
-weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers', 'colors', 'models', function($q, $rootScope, $log, storage, handlers, colors, models) {
+weechat.factory('connection', ['$q', '$rootScope', '$log', '$store', 'handlers', 'models', function($q, $rootScope, $log, storage, handlers, models) {
protocol = new weeChat.Protocol();
var websocket = null;
@@ -570,4 +561,4 @@ weechat.controller('WeechatCtrl', ['$rootScope', '$scope', '$store', '$timeout',
}
}]
- );
+);
diff --git a/js/weechat.js b/js/weechat.js
index 31b5d5f..698113a 100644
--- a/js/weechat.js
+++ b/js/weechat.js
@@ -1,829 +1,1171 @@
(function(exports) {// http://weechat.org/files/doc/devel/weechat_dev.en.html#color_codes_in_strings
-(function() {
- // http://weechat.org/files/doc/devel/weechat_dev.en.html#color_codes_in_strings
- var part, fg, bg, attrs;
-
- // XTerm 8-bit pallete
- var colors = [
- '#666666', '#AA0000', '#00AA00', '#AA5500', '#0000AA',
- '#AA00AA', '#00AAAA', '#AAAAAA', '#555555', '#FF5555',
- '#55FF55', '#FFFF55', '#5555FF', '#FF55FF', '#55FFFF',
- '#FFFFFF', '#666666', '#00005F', '#000087', '#0000AF',
- '#0000D7', '#0000FF', '#005F00', '#005F5F', '#005F87',
- '#005FAF', '#005FD7', '#005FFF', '#008700', '#00875F',
- '#008787', '#0087AF', '#0087D7', '#00AF00', '#00AF5F',
- '#00AF87', '#00AFAF', '#00AFD7', '#00AFFF', '#00D700',
- '#00D75F', '#00D787', '#00D7AF', '#00D7D7', '#00D7FF',
- '#00FF00', '#00FF5F', '#00FF87', '#00FFAF', '#00FFD7',
- '#00FFFF', '#5F0000', '#5F005F', '#5F0087', '#5F00AF',
- '#5F00D7', '#5F00FF', '#5F5F00', '#5F5F5F', '#5F5F87',
- '#5F5FAF', '#5F5FD7', '#5F5FFF', '#5F8700', '#5F875F',
- '#5F8787', '#5F87AF', '#5F87D7', '#5F87FF', '#5FAF00',
- '#5FAF5F', '#5FAF87', '#5FAFAF', '#5FAFD7', '#5FAFFF',
- '#5FD700', '#5FD75F', '#5FD787', '#5FD7AF', '#5FD7D7',
- '#5FD7FF', '#5FFF00', '#5FFF5F', '#5FFF87', '#5FFFAF',
- '#5FFFD7', '#5FFFFF', '#870000', '#87005F', '#870087',
- '#8700AF', '#8700D7', '#8700FF', '#875F00', '#875F5F',
- '#875F87', '#875FAF', '#875FD7', '#875FFF', '#878700',
- '#87875F', '#878787', '#8787AF', '#8787D7', '#8787FF',
- '#87AF00', '#87AF5F', '#87AF87', '#87AFAF', '#87AFD7',
- '#87AFFF', '#87D700', '#87D75F', '#87D787', '#87D7AF',
- '#87D7D7', '#87D7FF', '#87FF00', '#87FF5F', '#87FF87',
- '#87FFAF', '#87FFD7', '#87FFFF', '#AF0000', '#AF005F',
- '#AF0087', '#AF00AF', '#AF00D7', '#AF00FF', '#AF5F00',
- '#AF5F5F', '#AF5F87', '#AF5FAF', '#AF5FD7', '#AF5FFF',
- '#AF8700', '#AF875F', '#AF8787', '#AF87AF', '#AF87D7',
- '#AF87FF', '#AFAF00', '#AFAF5F', '#AFAF87', '#AFAFAF',
- '#AFAFD7', '#AFAFFF', '#AFD700', '#AFD75F', '#AFD787',
- '#AFD7AF', '#AFD7D7', '#AFD7FF', '#AFFF00', '#AFFF5F',
- '#AFFF87', '#AFFFAF', '#AFFFD7', '#AFFFFF', '#D70000',
- '#D7005F', '#D70087', '#D700AF', '#D700D7', '#D700FF',
- '#D75F00', '#D75F5F', '#D75F87', '#D75FAF', '#D75FD7',
- '#D75FFF', '#D78700', '#D7875F', '#D78787', '#D787AF',
- '#D787D7', '#D787FF', '#D7AF00', '#D7AF5F', '#D7AF87',
- '#D7AFAF', '#D7AFD7', '#D7AFFF', '#D7D700', '#D7D75F',
- '#D7D787', '#D7D7AF', '#D7D7D7', '#D7D7FF', '#D7FF00',
- '#D7FF5F', '#D7FF87', '#D7FFAF', '#D7FFD7', '#D7FFFF',
- '#FF0000', '#FF005F', '#FF0087', '#FF00AF', '#FF00D7',
- '#FF00FF', '#FF5F00', '#FF5F5F', '#FF5F87', '#FF5FAF',
- '#FF5FD7', '#FF5FFF', '#FF8700', '#FF875F', '#FF8787',
- '#FF87AF', '#FF87D7', '#FF87FF', '#FFAF00', '#FFAF5F',
- '#FFAF87', '#FFAFAF', '#FFAFD7', '#FFAFFF', '#FFD700',
- '#FFD75F', '#FFD787', '#FFD7AF', '#FFD7D7', '#FFD7FF',
- '#FFFF00', '#FFFF5F', '#FFFF87', '#FFFFAF', '#FFFFD7',
- '#FFFFFF', '#080808', '#121212', '#1C1C1C', '#262626',
- '#303030', '#3A3A3A', '#444444', '#4E4E4E', '#585858',
- '#626262', '#6C6C6C', '#767676', '#808080', '#8A8A8A',
- '#949494', '#9E9E9E', '#A8A8A8', '#B2B2B2', '#BCBCBC',
- '#C6C6C6', '#D0D0D0', '#DADADA', '#E4E4E4', '#EEEEEE'
- ];
-
- // Push the basic color list on top of the extended color list
- // and then when weechat requests a basic color (0-15) we rewrite
- // it to be a number in the extended color table
- colors.push.apply(colors, ['', 'black', 'darkgray', 'darkred', 'red', 'darkgreen', 'lightgreen', 'brown',
- 'yellow', 'darkblue', 'lightblue', 'darkmagenta', 'magenta', 'darkcyan', 'lightcyan', 'gray', 'white'
- ]);
-
- function setAttrs() {
- while (part.match(/^[\*\/\_\|]/)) {
- attrs.push(part.charAt(0));
- part = part.slice(1);
- }
- }
-
- function getColor() {
- var c;
- if (part.match(/^@/)) {
- c = part.slice(1, 6);
- part = part.slice(6);
- } else {
- c = part.slice(0, 2);
- // Rewrite the basic color value to the part in the extended
- // palette where we store the basic colors
- c = parseInt(c, 10) + 255;
- part = part.slice(2);
- }
- return c;
- }
-
- function prepareCss(color) {
- /*
- * Translates a weechat color to CSS
- */
- return 'color: ' + color;
- }
-
- var prefixes = {
- '\x19': function() {
- if (part.match(/^F/)) {
- part = part.slice(1);
- setAttrs();
- fg = getColor();
- } else if (part.match(/^B/)) {
- part = part.slice(1);
- setAttrs();
- bg = getColor();
- } else {
- setAttrs();
- fg = getColor();
- if (part.match(/^,/)) {
- part = part.slice(1);
- bg = getColor();
- }
- }
- },
- '\x1A': function() {
- // Don't know what to do
- },
- '\x1B': function() {
- attrs = [];
- },
- '\x1C': function() {
- fg = '';
- bg = '';
- }
- };
-
- function parse(text) {
- if (!text) {
- return text;
- }
- var f, parts = text.split(/(\x19|\x1A|\x1B|\x1C)/);
- if (parts.length === 1) return [{
- text: parts[0]
- }];
- attrs = [];
-
- return parts.map(function(p) {
- var res, tmp = prefixes[p.charAt(0)];
- if (f) {
- part = p;
- f();
- res = {
- text: part,
- fg: colors[parseInt(fg, 10)],
- bg: colors[parseInt(bg, 10)],
- attrs: attrs
- };
- if (!res.fg) res.fg = fg;
- if (!res.bg) res.bg = bg;
- }
- f = tmp;
- return res;
- }).filter(function(p) {
- return p;
- });
- }
-
- exports.color = {
- prepareCss: prepareCss,
- parse: parse
- };
-})();
-;/**
+/**
* WeeChat protocol handling.
*
* This object parses messages and formats commands for the WeeChat
* protocol. It's independent from the communication layer and thus
* may be used with any network mechanism.
*/
-
(function() {
- var WeeChatProtocol = function() {
- // specific parsing for each message type
- this._types = {
- 'chr': this._getChar,
- 'int': this._getInt,
- 'str': this._getString,
- 'inf': this._getInfo,
- 'hda': this._getHdata,
- 'ptr': this._getPointer,
- 'lon': this._getStrNumber,
- 'tim': this._getTime,
- 'buf': this._getString,
- 'arr': this._getArray,
- 'htb': this._getHashTable,
- 'inl': function() {
- this._warnUnimplemented('infolist');
- }
- };
-
- // string value for some message types
- this._typesStr = {
- 'chr': this._strDirect,
- 'str': this._strDirect,
- 'int': this._strToString,
- 'tim': this._strToString,
- 'ptr': this._strDirect
- };
- };
-
- /**
- * Unsigned integer array to string.
- *
- * @param uia Unsigned integer array
- * @return Decoded string
- */
- WeeChatProtocol._uia2s = function(uia) {
- var str = [];
-
- for (var c = 0; c < uia.length; c++) {
- str.push(String.fromCharCode(uia[c]));
- }
-
- return decodeURIComponent(escape(str.join('')));
- };
-
- /**
- * Merges default parameters with overriding parameters.
- *
- * @param defaults Default parameters
- * @param override Overriding parameters
- * @return Merged parameters
- */
- WeeChatProtocol._mergeParams = function(defaults, override) {
- for (var v in override) {
- defaults[v] = override[v];
- }
-
- return defaults;
- };
-
- /**
- * Formats a command.
- *
- * @param id Command ID (null for no ID)
- * @param name Command name
- * @param parts Command parts
- * @return Formatted command string
- */
- WeeChatProtocol._formatCmd = function(id, name, parts) {
- var cmdIdName;
- var cmd;
-
- cmdIdName = (id !== null) ? '(' + id + ') ' : '';
- cmdIdName += name;
- parts.unshift(cmdIdName);
- cmd = parts.join(' ');
- cmd += '\n';
-
- return cmd;
- };
-
- /**
- * Formats an init command.
- *
- * @param params Parameters:
- * password: password (optional)
- * compression: compression ('off' or 'zlib') (optional)
- * @return Formatted init command string
- */
- WeeChatProtocol.formatInit = function(params) {
- var defaultParams = {
- password: null,
- compression: 'off'
- };
- var keys = [];
- var parts = [];
-
- params = WeeChatProtocol._mergeParams(defaultParams, params);
- keys.push('compression=' + params.compression);
- if (params.password !== null) {
- keys.push('password=' + params.password);
- }
- parts.push(keys.join(','));
-
- return WeeChatProtocol._formatCmd(null, 'init', parts);
- };
-
- /**
- * Formats an hdata command.
- *
- * @param params Parameters:
- * id: command ID (optional)
- * path: hdata path (mandatory)
- * keys: array of keys (optional)
- * @return Formatted hdata command string
- */
- WeeChatProtocol.formatHdata = function(params) {
- var defaultParams = {
- id: null,
- keys: null
- };
- var parts = [];
-
- params = WeeChatProtocol._mergeParams(defaultParams, params);
- parts.push(params.path);
- if (params.keys !== null) {
- parts.push(params.keys.join(','));
- }
-
- return WeeChatProtocol._formatCmd(params.id, 'hdata', parts);
- };
-
- /**
- * Formats an info command.
- *
- * @param params Parameters:
- * id: command ID (optional)
- * name: info name (mandatory)
- * @return Formatted info command string
- */
- WeeChatProtocol.formatInfo = function(params) {
- var defaultParams = {
- id: null
- };
- var parts = [];
-
- params = WeeChatProtocol._mergeParams(defaultParams, params);
- parts.push(params.name);
-
- return WeeChatProtocol._formatCmd(params.id, 'info', parts);
- };
-
- /**
- * Formats a nicklist command.
- *
- * @param params Parameters:
- * id: command ID (optional)
- * buffer: buffer name (optional)
- * @return Formatted nicklist command string
- */
- WeeChatProtocol.formatNicklist = function(params) {
- var defaultParams = {
- id: null,
- buffer: null
- };
- var parts = [];
-
- params = WeeChatProtocol._mergeParams(defaultParams, params);
- if (params.buffer !== null) {
- parts.push(params.buffer);
- }
-
- return WeeChatProtocol._formatCmd(params.id, 'nicklist', parts);
- };
-
- /**
- * Formats an input command.
- *
- * @param params Parameters:
- * id: command ID (optional)
- * buffer: target buffer (mandatory)
- * data: input data (mandatory)
- * @return Formatted input command string
- */
- WeeChatProtocol.formatInput = function(params) {
- var defaultParams = {
- id: null
- };
- var parts = [];
-
- params = WeeChatProtocol._mergeParams(defaultParams, params);
- parts.push(params.buffer);
- parts.push(params.data);
-
- return WeeChatProtocol._formatCmd(params.id, 'input', parts);
- };
-
- /**
- * Formats a sync or a desync command.
- *
- * @param params Parameters (see _formatSync and _formatDesync)
- * @return Formatted sync/desync command string
- */
- WeeChatProtocol._formatSyncDesync = function(cmdName, params) {
- var defaultParams = {
- id: null,
- buffers: null,
- options: null
- };
- var parts = [];
-
- params = WeeChatProtocol._mergeParams(defaultParams, params);
- if (params.buffers !== null) {
- parts.push(params.buffers.join(','));
- if (params.options !== null) {
- parts.push(params.options.join(','));
- }
- }
-
- return WeeChatProtocol._formatCmd(params.id, cmdName, parts);
- };
-
- /**
- * Formats a sync command.
- *
- * @param params Parameters:
- * id: command ID (optional)
- * buffers: array of buffers to sync (optional)
- * options: array of options (optional)
- * @return Formatted sync command string
- */
- WeeChatProtocol.formatSync = function(params) {
- return WeeChatProtocol._formatSyncDesync('sync', params);
- };
-
- /**
- * Formats a desync command.
- *
- * @param params Parameters:
- * id: command ID (optional)
- * buffers: array of buffers to desync (optional)
- * options: array of options (optional)
- * @return Formatted desync command string
- */
- WeeChatProtocol.formatDesync = function(params) {
- return WeeChatProtocol._formatSyncDesync('desync', params);
- };
-
- /**
- * Formats a test command.
- *
- * @param params Parameters:
- * id: command ID (optional)
- * @return Formatted test command string
- */
- WeeChatProtocol.formatTest = function(params) {
- var defaultParams = {
- id: null
- };
- var parts = [];
-
- params = WeeChatProtocol._mergeParams(defaultParams, params);
-
- return WeeChatProtocol._formatCmd(params.id, 'test', parts);
- };
-
- /**
- * Formats a quit command.
- *
- * @return Formatted quit command string
- */
- WeeChatProtocol.formatQuit = function() {
- return WeeChatProtocol._formatCmd(null, 'quit', []);
- };
-
- /**
- * Formats a ping command.
- *
- * @param params Parameters:
- * id: command ID (optional)
- * args: array of custom arguments (optional)
- * @return Formatted ping command string
- */
- WeeChatProtocol.formatPing = function(params) {
- var defaultParams = {
- id: null,
- args: null
- };
- var parts = [];
-
- params = WeeChatProtocol._mergeParams(defaultParams, params);
- if (params.args !== null) {
- parts.push(params.args.join(' '));
- }
-
- return WeeChatProtocol._formatCmd(params.id, 'ping', parts);
- };
-
- WeeChatProtocol.prototype = {
- /**
- * Warns that message parsing is not implemented for a
- * specific type.
- *
- * @param type Message type to display
- */
- _warnUnimplemented: function(type) {
- console.log('Warning: ' + type + ' message parsing is not implemented');
- },
-
- /**
- * Reads a 3-character message type token value from current
- * set data.
- *
- * @return Type
- */
- _getType: function() {
- var t = this._getSlice(3);
-
- if (!t) {
- return null;
- }
-
- return WeeChatProtocol._uia2s(new Uint8Array(t));
- },
-
- /**
- * Runs the appropriate read routine for the specified message type.
- *
- * @param type Message type
- * @return Data value
- */
- _runType: function(type) {
- var cb = this._types[type];
- var boundCb = cb.bind(this);
-
- return boundCb();
- },
-
- /**
- * Reads a "number as a string" token value from current set data.
- *
- * @return Number as a string
- */
- _getStrNumber: function() {
- var len = this._getByte();
- var str = this._getSlice(len);
-
- return WeeChatProtocol._uia2s(new Uint8Array(str));
- },
-
- /**
- * Returns the passed object.
- *
- * @param obj Object
- * @return Passed object
- */
- _strDirect: function(obj) {
- return obj;
- },
-
- /**
- * Calls toString() on the passed object and returns the value.
- *
- * @param obj Object to call toString() on
- * @return String value of object
- */
- _strToString: function(obj) {
- return obj.toString();
- },
-
- /**
- * Gets the string value of an object representing the message
- * value for a specified type.
- *
- * @param obj Object for which to get the string value
- * @param type Message type
- * @return String value of object
- */
- _objToString: function(obj, type) {
- var cb = this._typesStr[type];
- var boundCb = cb.bind(this);
-
- return boundCb(obj);
- },
-
- /**
- * Reads an info token value from current set data.
- *
- * @return Info object
- */
- _getInfo: function() {
- var info = {};
- info.key = this._getString();
- info.value = this._getString();
-
- return info;
- },
-
- /**
- * Reads an hdata token value from current set data.
- *
- * @return Hdata object
- */
- _getHdata: function() {
- var self = this;
- var paths;
- var count;
- var objs = [];
- var hpath = this._getString();
-
- keys = this._getString().split(',');
- paths = hpath.split('/');
- count = this._getInt();
-
- keys = keys.map(function(key) {
- return key.split(':');
- });
-
- function runType() {
- var tmp = {};
-
- tmp.pointers = paths.map(function(path) {
- return self._getPointer();
- });
- keys.forEach(function(key) {
- tmp[key[0]] = self._runType(key[1]);
- });
- objs.push(tmp);
- }
-
- for (var i = 0; i < count; i++) {
- runType();
- }
-
- return objs;
- },
-
- /**
- * Reads a pointer token value from current set data.
- *
- * @return Pointer value
- */
- _getPointer: function() {
- return this._getStrNumber();
- },
-
- /**
- * Reads a time token value from current set data.
- *
- * @return Time value (Date)
- */
- _getTime: function() {
- var str = this._getStrNumber();
-
- return new Date(parseInt(str, 10) * 1000);
- },
-
- /**
- * Reads an integer token value from current set data.
- *
- * @return Integer value
- */
- _getInt: function() {
- var parsedData = new Uint8Array(this._getSlice(4));
-
- return ((parsedData[0] & 0xff) << 24) |
- ((parsedData[1] & 0xff) << 16) |
- ((parsedData[2] & 0xff) << 8) |
- (parsedData[3] & 0xff);
- },
-
- /**
- * Reads a byte from current set data.
- *
- * @return Byte value (integer)
- */
- _getByte: function() {
- var parsedData = new Uint8Array(this._getSlice(1));
-
- return parsedData[0];
- },
-
- /**
- * Reads a character token value from current set data.
- *
- * @return Character (string)
- */
- _getChar: function() {
- return this._getByte();
- },
-
- /**
- * Reads a string token value from current set data.
- *
- * @return String value
- */
- _getString: function() {
- var l = this._getInt();
-
- if (l > 0) {
- var s = this._getSlice(l);
- var parsedData = new Uint8Array(s);
-
- return WeeChatProtocol._uia2s(parsedData);
- }
-
- return "";
- },
-
- /**
- * Reads a message header from current set data.
- *
- * @return Header object
- */
- _getHeader: function() {
- var len = this._getInt();
- var comp = this._getByte();
-
- return {
- length: len,
- compression: comp,
- };
- },
-
- /**
- * Reads a message header ID from current set data.
- *
- * @return Message ID (string)
- */
- _getId: function() {
- return this._getString();
- },
-
- /**
- * Reads an arbitrary object token from current set data.
- *
- * @return Object value
- */
- _getObject: function() {
- var self = this;
- var type = this._getType();
-
- if (type) {
- return {
- type: type,
- content: self._runType(type),
+ var WeeChatProtocol = function() {
+ // specific parsing for each object type
+ this._types = {
+ 'chr': this._getChar,
+ 'int': this._getInt,
+ 'str': this._getString,
+ 'inf': this._getInfo,
+ 'hda': this._getHdata,
+ 'ptr': this._getPointer,
+ 'lon': this._getStrNumber,
+ 'tim': this._getTime,
+ 'buf': this._getString,
+ 'arr': this._getArray,
+ 'htb': this._getHashTable,
+ 'inl': function() {
+ this._warnUnimplemented('infolist');
+ }
};
- }
- },
+
+ // string value for some object types
+ this._typesStr = {
+ 'chr': this._strDirect,
+ 'str': this._strDirect,
+ 'int': this._strToString,
+ 'tim': this._strToString,
+ 'ptr': this._strDirect
+ };
+ };
/**
- * Reads an hash table token from current set data.
- *
- * @return Hash table
+ * WeeChat colors names.
*/
- _getHashTable: function() {
- var self = this;
- var typeKeys, typeValues, count;
- var dict = {};
-
- typeKeys = this._getType();
- typeValues = this._getType();
- count = this._getInt();
-
- for (var i = 0; i < count; ++i) {
- var key = self._runType(typeKeys);
- var keyStr = self._objToString(key, typeKeys);
- var value = self._runType(typeValues);
- dict[keyStr] = value;
- }
-
- return dict;
- },
+ WeeChatProtocol._weeChatColorsNames = [
+ 'default',
+ 'black',
+ 'darkgray',
+ 'darkred',
+ 'lightred',
+ 'darkgreen',
+ 'lightgreen',
+ 'brown',
+ 'yellow',
+ 'darkblue',
+ 'lightblue',
+ 'darkmagenta',
+ 'lightmagenta',
+ 'darkcyan',
+ 'lightcyan',
+ 'gray',
+ 'white'
+ ];
/**
- * Reads an array token from current set data.
- *
- * @return Array
+ * Style options names.
*/
- _getArray: function() {
- var self = this;
- var type;
- var count;
- var values;
-
- type = this._getType();
- count = this._getInt();
- values = [];
-
- for (var i = 0; i < count; i++) {
- values.push(self._runType(type));
- }
-
- return values;
- },
+ WeeChatProtocol._colorsOptionsNames = [
+ 'separator',
+ 'chat',
+ 'chat_time',
+ 'chat_time_delimiters',
+ 'chat_prefix_error',
+ 'chat_prefix_network',
+ 'chat_prefix_action',
+ 'chat_prefix_join',
+ 'chat_prefix_quit',
+ 'chat_prefix_more',
+ 'chat_prefix_suffix',
+ 'chat_buffer',
+ 'chat_server',
+ 'chat_channel',
+ 'chat_nick',
+ 'chat_nick_self',
+ 'chat_nick_other',
+ 'invalid',
+ 'invalid',
+ 'invalid',
+ 'invalid',
+ 'invalid',
+ 'invalid',
+ 'invalid',
+ 'invalid',
+ 'invalid',
+ 'invalid',
+ 'chat_host',
+ 'chat_delimiters',
+ 'chat_highlight',
+ 'chat_read_marker',
+ 'chat_text_found',
+ 'chat_value',
+ 'chat_prefix_buffer',
+ 'chat_tags',
+ 'chat_inactive_window',
+ 'chat_inactive_buffer',
+ 'chat_prefix_buffer_inactive_buffer',
+ 'chat_nick_offline',
+ 'chat_nick_offline_highlight',
+ 'chat_nick_prefix',
+ 'chat_nick_suffix',
+ 'emphasis',
+ 'chat_day_change'
+ ];
/**
- * Reads a specified number of bytes from current set data.
+ * Gets the default color.
*
- * @param length Number of bytes to read
- * @return Sliced array
+ * @return Default color
*/
- _getSlice: function(length) {
- if (this.dataAt + length > this._data.byteLength) {
- return null;
- }
-
- var slice = this._data.slice(this._dataAt, this._dataAt + length);
-
- this._dataAt += length;
-
- return slice;
- },
-
- /**
- * Sets the current data.
- *
- * @param data Current data
- */
- _setData: function(data) {
- this._data = data;
- },
-
- /**
- * Parses a WeeChat message.
- *
- * @param data Message data (ArrayBuffer)
- * @return Message value
- */
- parse: function(data) {
- var self = this;
-
- this._setData(data);
- this._dataAt = 0;
-
- var header = this._getHeader();
- var id = this._getId();
- var objects = [];
- var object = this._getObject();
-
- while (object) {
- objects.push(object);
- object = self._getObject();
- }
-
- return {
- header: header,
- id: id,
- objects: objects,
- };
+ WeeChatProtocol._getDefaultColor = function() {
+ return {
+ type: 'weechat',
+ name: 'default'
+ };
}
- };
- exports.Protocol = WeeChatProtocol;
+ /**
+ * Gets the default attributes.
+ *
+ * @return Default attributes
+ */
+ WeeChatProtocol._getDefaultAttributes = function() {
+ return {
+ name: null,
+ override: {
+ 'bold': false,
+ 'reverse': false,
+ 'italic': false,
+ 'underline': false
+ }
+ };
+ }
+
+ /**
+ * Gets the default style (default colors and attributes).
+ *
+ * @return Default style
+ */
+ WeeChatProtocol._getDefaultStyle = function() {
+ return {
+ fgColor: WeeChatProtocol._getDefaultColor(),
+ bgColor: WeeChatProtocol._getDefaultColor(),
+ attrs: WeeChatProtocol._getDefaultAttributes()
+ };
+ }
+
+ /**
+ * Clones a color object.
+ *
+ * @param color Color object to clone
+ * @return Cloned color object
+ */
+ WeeChatProtocol._cloneColor = function(color) {
+ var clone = {};
+
+ for (var key in color) {
+ clone[key] = color[key];
+ }
+
+ return clone;
+ }
+
+ /**
+ * Clones an attributes object.
+ *
+ * @param attrs Attributes object to clone
+ * @return Cloned attributes object
+ */
+ WeeChatProtocol._cloneAttrs = function(attrs) {
+ var clone = {};
+
+ clone.name = attrs.name;
+ clone.override = {};
+ for (var attr in attrs.override) {
+ clone.override[attr] = attrs.override[attr];
+ }
+
+ return clone;
+ }
+
+ /**
+ * Gets the name of an attribute from its character.
+ *
+ * @param ch Character of attribute
+ * @return Name of attribute
+ */
+ WeeChatProtocol._attrNameFromChar = function(ch) {
+ var chars = {
+ '*': 'bold',
+ '!': 'reverse',
+ '/': 'italic',
+ '_': 'underline'
+ };
+
+ if (ch in chars) {
+ return chars[ch];
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Gets an attributes object from a string of attribute characters.
+ *
+ * @param str String of attribute characters
+ * @return Attributes object (null if unchanged)
+ */
+ WeeChatProtocol._attrsFromStr = function(str) {
+ var attrs = WeeChatProtocol._getDefaultAttributes();
+
+ for (var i = 0; i < str.length; ++i) {
+ var ch = str.charAt(i);
+ if (ch == '|') {
+ // means keep attributes, so unchanged
+ return null;
+ }
+ var attrName = WeeChatProtocol._attrNameFromChar(ch);
+ if (attrName === null) {
+ // ignore invalid attribute
+ continue;
+ }
+ attrs.override[attrName] = true;
+ }
+
+ return attrs;
+ }
+
+ /**
+ * Gets a single color from a string representing its index (WeeChat and
+ * extended colors only, NOT colors options).
+ *
+ * @param str Color string (e.g., "05" or "00134")
+ * @return Color object
+ */
+ WeeChatProtocol._getColorObj = function(str) {
+ if (str.length == 2) {
+ var code = parseInt(str);
+ if (code > 16) {
+ // should never happen
+ return WeeChatProtocol._getDefaultColor();
+ } else {
+ return {
+ type: 'weechat',
+ name: WeeChatProtocol._weeChatColorsNames[code]
+ };
+ }
+ } else {
+ var codeStr = str.substring(1);
+ return {
+ type: 'ext',
+ name: parseInt(codeStr).toString()
+ };
+ }
+ }
+
+ /**
+ * Gets colors and attributes of text element.
+ *
+ * See .
+ *
+ * @param txt Text element
+ * @return Colors, attributes and plain text of this text element:
+ * fgColor: Foreground color (null if unchanged)
+ * bgColor: Background color (null if unchanged)
+ * attrs: Attributes (null if unchanged)
+ * text: Plain text element
+ */
+ WeeChatProtocol._getStyle = function(txt) {
+ var matchers = [
+ {
+ // color option
+ // STD
+ regex: /^(\d{2})/,
+ fn: function(m) {
+ var ret = {};
+ var optionCode = parseInt(m[1]);
+
+ if (optionCode > 43) {
+ // should never happen
+ return {
+ fgColor: null,
+ bgColor: null,
+ attrs: null
+ };
+ }
+ var optionName = WeeChatProtocol._colorsOptionsNames[optionCode];
+ ret.fgColor = {
+ type: 'option',
+ name: optionName
+ };
+ ret.bgColor = WeeChatProtocol._cloneColor(ret.fgColor);
+ ret.attrs = {
+ name: optionName,
+ override: {}
+ };
+
+ return ret;
+ }
+ },
+ {
+ // ncurses pair
+ // EXT
+ regex: /^@(\d{5})/,
+ fn: function(m) {
+ // unimplemented case
+ return {
+ fgColor: null,
+ bgColor: null,
+ attrs: null
+ };
+ }
+ },
+ {
+ // foreground color with F
+ // "F" + (A)STD
+ // "F" + (A)EXT
+ regex: /^F(?:([*!\/_|]*)(\d{2})|@([*!\/_|]*)(\d{5}))/,
+ fn: function(m) {
+ var ret = {
+ bgColor: null
+ };
+
+ if (m[2]) {
+ ret.attrs = WeeChatProtocol._attrsFromStr(m[1]);
+ ret.fgColor = WeeChatProtocol._getColorObj(m[2]);
+ } else {
+ ret.attrs = WeeChatProtocol._attrsFromStr(m[3]);
+ ret.fgColor = WeeChatProtocol._getColorObj(m[4]);
+ }
+
+ return ret;
+ }
+ },
+ {
+ // background color (no attributes)
+ // "B" + STD
+ // "B" + EXT
+ regex: /^B(\d{2}|@\d{5})/,
+ fn: function(m) {
+ return {
+ fgColor: null,
+ bgColor: WeeChatProtocol._getColorObj(m[1]),
+ attrs: null
+ };
+ }
+ },
+ {
+ // foreground, background (+ attributes)
+ // "*" + (A)STD + "," + (A)STD
+ // "*" + (A)STD + "," + (A)EXT
+ // "*" + (A)EXT + "," + (A)STD
+ // "*" + (A)EXT + "," + (A)EXT
+ regex: /^\*(?:([*!\/_|]*)(\d{2})|@([*!\/_|]*)(\d{5})),(\d{2}|@\d{5})/,
+ fn: function(m) {
+ var ret = {};
+
+ if (m[2]) {
+ ret.attrs = WeeChatProtocol._attrsFromStr(m[1]);
+ ret.fgColor = WeeChatProtocol._getColorObj(m[2]);
+ } else {
+ ret.attrs = WeeChatProtocol._attrsFromStr(m[3]);
+ ret.fgColor = WeeChatProtocol._getColorObj(m[4]);
+ }
+ ret.bgColor = WeeChatProtocol._getColorObj(m[5]);
+
+ return ret;
+ }
+ },
+ {
+ // foreground color with * (+ attributes) (fall back, must be checked before previous case)
+ // "*" + (A)STD
+ // "*" + (A)EXT
+ regex: /^\*([*!\/_|]*)(\d{2}|@\d{5})/,
+ fn: function(m) {
+ return {
+ fgColor: WeeChatProtocol._getColorObj(m[2]),
+ bgColor: null,
+ attrs: WeeChatProtocol._attrsFromStr(m[1])
+ };
+ }
+ },
+ {
+ // emphasis
+ // "E"
+ regex: /^E/,
+ fn: function(m) {
+ var ret = {};
+
+ ret.fgColor = {
+ type: 'option',
+ name: 'emphasis'
+ };
+ ret.bgColor = WeeChatProtocol._cloneColor(ret.fgColor);
+ ret.attrs = {
+ name: 'emphasis',
+ override: {}
+ };
+
+ return ret;
+ }
+ }
+ ];
+
+ // parse
+ var ret = {
+ fgColor: null,
+ bgColor: null,
+ attrs: null,
+ text: txt
+ };
+ matchers.some(function(matcher) {
+ var m = txt.match(matcher.regex);
+ if (m) {
+ ret = matcher.fn(m);
+ ret.text = txt.substring(m[0].length);
+ return true;
+ }
+
+ return false;
+ });
+
+ return ret;
+ }
+
+ /**
+ * Transforms a raw text into an array of text elements with integrated
+ * colors and attributes.
+ *
+ * @param rawText Raw text to transform
+ * @return Array of text elements
+ */
+ WeeChatProtocol.rawText2Rich = function(rawText) {
+ /* This is subtle, but JavaScript adds the token to the output list
+ * when it's surrounded by capturing parentheses.
+ */
+ var parts = rawText.split(/(\x19|\x1a|\x1b|\x1c)/);
+
+ // no colors/attributes
+ if (parts.length == 1) {
+ return [
+ {
+ attrs: WeeChatProtocol._getDefaultAttributes(),
+ fgColor: WeeChatProtocol._getDefaultColor(),
+ bgColor: WeeChatProtocol._getDefaultColor(),
+ text: parts[0]
+ }
+ ];
+ }
+
+ // find the style of every part
+ var curFgColor = WeeChatProtocol._getDefaultColor();
+ var curBgColor = WeeChatProtocol._getDefaultColor();
+ var curAttrs = WeeChatProtocol._getDefaultAttributes();
+ var curSpecialToken = null;
+
+ return parts.map(function(p) {
+ if (p.length == 0) {
+ return null;
+ }
+ var firstCharCode = p.charCodeAt(0);
+ var firstChar = p.charAt(0);
+
+ if (firstCharCode >= 0x19 && firstCharCode <= 0x1c) {
+ // special token
+ if (firstCharCode == 0x1c) {
+ // always reset colors
+ curFgColor = WeeChatProtocol._getDefaultColor();
+ curBgColor = WeeChatProtocol._getDefaultColor();
+ if (curSpecialToken != 0x19) {
+ // also reset attributes
+ curAttrs = WeeChatProtocol._getDefaultAttributes();
+ }
+ }
+ curSpecialToken = firstCharCode;
+ return null;
+ }
+
+ var text = p;
+ if (curSpecialToken == 0x19) {
+ // get new style
+ var style = WeeChatProtocol._getStyle(p);
+
+ // set foreground color if changed
+ if (style.fgColor !== null) {
+ curFgColor = style.fgColor;
+ }
+
+ // set background color if changed
+ if (style.bgColor !== null) {
+ curBgColor = style.bgColor;
+ }
+
+ // set attibutes if changed
+ if (style.attrs !== null) {
+ curAttrs = style.attrs;
+ }
+
+ // set plain text
+ text = style.text;
+ } else if (curSpecialToken == 0x1a || curSpecialToken == 0x1b) {
+ // set/reset attribute
+ var orideVal = (curSpecialToken == 0x1a);
+
+ // set attribute override if we don't have to keep all of them
+ if (firstChar != '|') {
+ var orideName = WeeChatProtocol._attrNameFromChar(firstChar);
+ if (orideName) {
+ // known attribute
+ curAttrs.override[orideName] = orideVal;
+ text = p.substring(1);
+ }
+ }
+ }
+
+ // reset current special token
+ curSpecialToken = null;
+
+ // if text is empty, don't bother returning it
+ if (text.length == 0) {
+ return null;
+ }
+
+ // parsed text element
+ return {
+ fgColor: WeeChatProtocol._cloneColor(curFgColor),
+ bgColor: WeeChatProtocol._cloneColor(curBgColor),
+ attrs: WeeChatProtocol._cloneAttrs(curAttrs),
+ text: text
+ };
+ }).filter(function(p) {
+ return p !== null;
+ });
+ };
+
+ /**
+ * Unsigned integer array to string.
+ *
+ * @param uia Unsigned integer array
+ * @return Decoded string
+ */
+ WeeChatProtocol._uia2s = function(uia) {
+ var str = [];
+
+ for (var c = 0; c < uia.length; c++) {
+ str.push(String.fromCharCode(uia[c]));
+ }
+
+ return decodeURIComponent(escape(str.join('')));
+ };
+
+ /**
+ * Merges default parameters with overriding parameters.
+ *
+ * @param defaults Default parameters
+ * @param override Overriding parameters
+ * @return Merged parameters
+ */
+ WeeChatProtocol._mergeParams = function(defaults, override) {
+ for (var v in override) {
+ defaults[v] = override[v];
+ }
+
+ return defaults;
+ };
+
+ /**
+ * Formats a command.
+ *
+ * @param id Command ID (null for no ID)
+ * @param name Command name
+ * @param parts Command parts
+ * @return Formatted command string
+ */
+ WeeChatProtocol._formatCmd = function(id, name, parts) {
+ var cmdIdName;
+ var cmd;
+
+ cmdIdName = (id !== null) ? '(' + id + ') ' : '';
+ cmdIdName += name;
+ parts.unshift(cmdIdName);
+ cmd = parts.join(' ');
+ cmd += '\n';
+
+ return cmd;
+ };
+
+ /**
+ * Formats an init command.
+ *
+ * @param params Parameters:
+ * password: password (optional)
+ * compression: compression ('off' or 'zlib') (optional)
+ * @return Formatted init command string
+ */
+ WeeChatProtocol.formatInit = function(params) {
+ var defaultParams = {
+ password: null,
+ compression: 'off'
+ };
+ var keys = [];
+ var parts = [];
+
+ params = WeeChatProtocol._mergeParams(defaultParams, params);
+ keys.push('compression=' + params.compression);
+ if (params.password !== null) {
+ keys.push('password=' + params.password);
+ }
+ parts.push(keys.join(','));
+
+ return WeeChatProtocol._formatCmd(null, 'init', parts);
+ };
+
+ /**
+ * Formats an hdata command.
+ *
+ * @param params Parameters:
+ * id: command ID (optional)
+ * path: hdata path (mandatory)
+ * keys: array of keys (optional)
+ * @return Formatted hdata command string
+ */
+ WeeChatProtocol.formatHdata = function(params) {
+ var defaultParams = {
+ id: null,
+ keys: null
+ };
+ var parts = [];
+
+ params = WeeChatProtocol._mergeParams(defaultParams, params);
+ parts.push(params.path);
+ if (params.keys !== null) {
+ parts.push(params.keys.join(','));
+ }
+
+ return WeeChatProtocol._formatCmd(params.id, 'hdata', parts);
+ };
+
+ /**
+ * Formats an info command.
+ *
+ * @param params Parameters:
+ * id: command ID (optional)
+ * name: info name (mandatory)
+ * @return Formatted info command string
+ */
+ WeeChatProtocol.formatInfo = function(params) {
+ var defaultParams = {
+ id: null
+ };
+ var parts = [];
+
+ params = WeeChatProtocol._mergeParams(defaultParams, params);
+ parts.push(params.name);
+
+ return WeeChatProtocol._formatCmd(params.id, 'info', parts);
+ };
+
+ /**
+ * Formats a nicklist command.
+ *
+ * @param params Parameters:
+ * id: command ID (optional)
+ * buffer: buffer name (optional)
+ * @return Formatted nicklist command string
+ */
+ WeeChatProtocol.formatNicklist = function(params) {
+ var defaultParams = {
+ id: null,
+ buffer: null
+ };
+ var parts = [];
+
+ params = WeeChatProtocol._mergeParams(defaultParams, params);
+ if (params.buffer !== null) {
+ parts.push(params.buffer);
+ }
+
+ return WeeChatProtocol._formatCmd(params.id, 'nicklist', parts);
+ };
+
+ /**
+ * Formats an input command.
+ *
+ * @param params Parameters:
+ * id: command ID (optional)
+ * buffer: target buffer (mandatory)
+ * data: input data (mandatory)
+ * @return Formatted input command string
+ */
+ WeeChatProtocol.formatInput = function(params) {
+ var defaultParams = {
+ id: null
+ };
+ var parts = [];
+
+ params = WeeChatProtocol._mergeParams(defaultParams, params);
+ parts.push(params.buffer);
+ parts.push(params.data);
+
+ return WeeChatProtocol._formatCmd(params.id, 'input', parts);
+ };
+
+ /**
+ * Formats a sync or a desync command.
+ *
+ * @param params Parameters (see _formatSync and _formatDesync)
+ * @return Formatted sync/desync command string
+ */
+ WeeChatProtocol._formatSyncDesync = function(cmdName, params) {
+ var defaultParams = {
+ id: null,
+ buffers: null,
+ options: null
+ };
+ var parts = [];
+
+ params = WeeChatProtocol._mergeParams(defaultParams, params);
+ if (params.buffers !== null) {
+ parts.push(params.buffers.join(','));
+ if (params.options !== null) {
+ parts.push(params.options.join(','));
+ }
+ }
+
+ return WeeChatProtocol._formatCmd(params.id, cmdName, parts);
+ };
+
+ /**
+ * Formats a sync command.
+ *
+ * @param params Parameters:
+ * id: command ID (optional)
+ * buffers: array of buffers to sync (optional)
+ * options: array of options (optional)
+ * @return Formatted sync command string
+ */
+ WeeChatProtocol.formatSync = function(params) {
+ return WeeChatProtocol._formatSyncDesync('sync', params);
+ };
+
+ /**
+ * Formats a desync command.
+ *
+ * @param params Parameters:
+ * id: command ID (optional)
+ * buffers: array of buffers to desync (optional)
+ * options: array of options (optional)
+ * @return Formatted desync command string
+ */
+ WeeChatProtocol.formatDesync = function(params) {
+ return WeeChatProtocol._formatSyncDesync('desync', params);
+ };
+
+ /**
+ * Formats a test command.
+ *
+ * @param params Parameters:
+ * id: command ID (optional)
+ * @return Formatted test command string
+ */
+ WeeChatProtocol.formatTest = function(params) {
+ var defaultParams = {
+ id: null
+ };
+ var parts = [];
+
+ params = WeeChatProtocol._mergeParams(defaultParams, params);
+
+ return WeeChatProtocol._formatCmd(params.id, 'test', parts);
+ };
+
+ /**
+ * Formats a quit command.
+ *
+ * @return Formatted quit command string
+ */
+ WeeChatProtocol.formatQuit = function() {
+ return WeeChatProtocol._formatCmd(null, 'quit', []);
+ };
+
+ /**
+ * Formats a ping command.
+ *
+ * @param params Parameters:
+ * id: command ID (optional)
+ * args: array of custom arguments (optional)
+ * @return Formatted ping command string
+ */
+ WeeChatProtocol.formatPing = function(params) {
+ var defaultParams = {
+ id: null,
+ args: null
+ };
+ var parts = [];
+
+ params = WeeChatProtocol._mergeParams(defaultParams, params);
+ if (params.args !== null) {
+ parts.push(params.args.join(' '));
+ }
+
+ return WeeChatProtocol._formatCmd(params.id, 'ping', parts);
+ };
+
+ WeeChatProtocol.prototype = {
+ /**
+ * Warns that message parsing is not implemented for a
+ * specific type.
+ *
+ * @param type Message type to display
+ */
+ _warnUnimplemented: function(type) {
+ console.log('Warning: ' + type + ' message parsing is not implemented');
+ },
+
+ /**
+ * Reads a 3-character message type token value from current
+ * set data.
+ *
+ * @return Type
+ */
+ _getType: function() {
+ var t = this._getSlice(3);
+
+ if (!t) {
+ return null;
+ }
+
+ return WeeChatProtocol._uia2s(new Uint8Array(t));
+ },
+
+ /**
+ * Runs the appropriate read routine for the specified message type.
+ *
+ * @param type Message type
+ * @return Data value
+ */
+ _runType: function(type) {
+ var cb = this._types[type];
+ var boundCb = cb.bind(this);
+
+ return boundCb();
+ },
+
+ /**
+ * Reads a "number as a string" token value from current set data.
+ *
+ * @return Number as a string
+ */
+ _getStrNumber: function() {
+ var len = this._getByte();
+ var str = this._getSlice(len);
+
+ return WeeChatProtocol._uia2s(new Uint8Array(str));
+ },
+
+ /**
+ * Returns the passed object.
+ *
+ * @param obj Object
+ * @return Passed object
+ */
+ _strDirect: function(obj) {
+ return obj;
+ },
+
+ /**
+ * Calls toString() on the passed object and returns the value.
+ *
+ * @param obj Object to call toString() on
+ * @return String value of object
+ */
+ _strToString: function(obj) {
+ return obj.toString();
+ },
+
+ /**
+ * Gets the string value of an object representing the message
+ * value for a specified type.
+ *
+ * @param obj Object for which to get the string value
+ * @param type Message type
+ * @return String value of object
+ */
+ _objToString: function(obj, type) {
+ var cb = this._typesStr[type];
+ var boundCb = cb.bind(this);
+
+ return boundCb(obj);
+ },
+
+ /**
+ * Reads an info token value from current set data.
+ *
+ * @return Info object
+ */
+ _getInfo: function() {
+ var info = {};
+ info.key = this._getString();
+ info.value = this._getString();
+
+ return info;
+ },
+
+ /**
+ * Reads an hdata token value from current set data.
+ *
+ * @return Hdata object
+ */
+ _getHdata: function() {
+ var self = this;
+ var paths;
+ var count;
+ var objs = [];
+ var hpath = this._getString();
+
+ keys = this._getString().split(',');
+ paths = hpath.split('/');
+ count = this._getInt();
+
+ keys = keys.map(function(key) {
+ return key.split(':');
+ });
+
+ function runType() {
+ var tmp = {};
+
+ tmp.pointers = paths.map(function(path) {
+ return self._getPointer();
+ });
+ keys.forEach(function(key) {
+ tmp[key[0]] = self._runType(key[1]);
+ });
+ objs.push(tmp);
+ }
+
+ for (var i = 0; i < count; i++) {
+ runType();
+ }
+
+ return objs;
+ },
+
+ /**
+ * Reads a pointer token value from current set data.
+ *
+ * @return Pointer value
+ */
+ _getPointer: function() {
+ return this._getStrNumber();
+ },
+
+ /**
+ * Reads a time token value from current set data.
+ *
+ * @return Time value (Date)
+ */
+ _getTime: function() {
+ var str = this._getStrNumber();
+
+ return new Date(parseInt(str, 10) * 1000);
+ },
+
+ /**
+ * Reads an integer token value from current set data.
+ *
+ * @return Integer value
+ */
+ _getInt: function() {
+ var parsedData = new Uint8Array(this._getSlice(4));
+
+ return ((parsedData[0] & 0xff) << 24) |
+ ((parsedData[1] & 0xff) << 16) |
+ ((parsedData[2] & 0xff) << 8) |
+ (parsedData[3] & 0xff);
+ },
+
+ /**
+ * Reads a byte from current set data.
+ *
+ * @return Byte value (integer)
+ */
+ _getByte: function() {
+ var parsedData = new Uint8Array(this._getSlice(1));
+
+ return parsedData[0];
+ },
+
+ /**
+ * Reads a character token value from current set data.
+ *
+ * @return Character (string)
+ */
+ _getChar: function() {
+ return this._getByte();
+ },
+
+ /**
+ * Reads a string token value from current set data.
+ *
+ * @return String value
+ */
+ _getString: function() {
+ var l = this._getInt();
+
+ if (l > 0) {
+ var s = this._getSlice(l);
+ var parsedData = new Uint8Array(s);
+
+ return WeeChatProtocol._uia2s(parsedData);
+ }
+
+ return "";
+ },
+
+ /**
+ * Reads a message header from current set data.
+ *
+ * @return Header object
+ */
+ _getHeader: function() {
+ var len = this._getInt();
+ var comp = this._getByte();
+
+ return {
+ length: len,
+ compression: comp,
+ };
+ },
+
+ /**
+ * Reads a message header ID from current set data.
+ *
+ * @return Message ID (string)
+ */
+ _getId: function() {
+ return this._getString();
+ },
+
+ /**
+ * Reads an arbitrary object token from current set data.
+ *
+ * @return Object value
+ */
+ _getObject: function() {
+ var self = this;
+ var type = this._getType();
+
+ if (type) {
+ return {
+ type: type,
+ content: self._runType(type),
+ };
+ }
+ },
+
+ /**
+ * Reads an hash table token from current set data.
+ *
+ * @return Hash table
+ */
+ _getHashTable: function() {
+ var self = this;
+ var typeKeys, typeValues, count;
+ var dict = {};
+
+ typeKeys = this._getType();
+ typeValues = this._getType();
+ count = this._getInt();
+
+ for (var i = 0; i < count; ++i) {
+ var key = self._runType(typeKeys);
+ var keyStr = self._objToString(key, typeKeys);
+ var value = self._runType(typeValues);
+ dict[keyStr] = value;
+ }
+
+ return dict;
+ },
+
+ /**
+ * Reads an array token from current set data.
+ *
+ * @return Array
+ */
+ _getArray: function() {
+ var self = this;
+ var type;
+ var count;
+ var values;
+
+ type = this._getType();
+ count = this._getInt();
+ values = [];
+
+ for (var i = 0; i < count; i++) {
+ values.push(self._runType(type));
+ }
+
+ return values;
+ },
+
+ /**
+ * Reads a specified number of bytes from current set data.
+ *
+ * @param length Number of bytes to read
+ * @return Sliced array
+ */
+ _getSlice: function(length) {
+ if (this.dataAt + length > this._data.byteLength) {
+ return null;
+ }
+
+ var slice = this._data.slice(this._dataAt, this._dataAt + length);
+
+ this._dataAt += length;
+
+ return slice;
+ },
+
+ /**
+ * Sets the current data.
+ *
+ * @param data Current data
+ */
+ _setData: function(data) {
+ this._data = data;
+ },
+
+ /**
+ * Parses a WeeChat message.
+ *
+ * @param data Message data (ArrayBuffer)
+ * @return Message value
+ */
+ parse: function(data, optionsValues) {
+ var self = this;
+
+ this._setData(data);
+ this._dataAt = 0;
+
+ var header = this._getHeader();
+ var id = this._getId();
+ var objects = [];
+ var object = this._getObject();
+
+ while (object) {
+ objects.push(object);
+ object = self._getObject();
+ }
+ var msg = {
+ header: header,
+ id: id,
+ objects: objects,
+ };
+
+ return msg;
+ }
+ };
+
+ exports.Protocol = WeeChatProtocol;
})();
-})(typeof exports === "undefined" ? this.weeChat = {} : exports)
\ No newline at end of file
+})(typeof exports === "undefined" ? this.weeChat = {} : exports)
|