From 4ae4e66cbf9ad3df0b13a9352769280921804867 Mon Sep 17 00:00:00 2001 From: Matt Tucker Date: Fri, 11 Apr 2003 15:50:20 +0000 Subject: [PATCH] Initial check-in. git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@1879 b35dd754-fafc-0310-a699-88a17e54d16e --- .../jivesoftware/webchat/EmoticonFilter.java | 292 ++++++++++++++++ .../org/jivesoftware/webchat/URLFilter.java | 312 ++++++++++++++++++ .../source/web/images/emoticons/angry.gif | Bin 0 -> 692 bytes .../source/web/images/emoticons/blush.gif | Bin 0 -> 688 bytes .../source/web/images/emoticons/confused.gif | Bin 0 -> 688 bytes .../source/web/images/emoticons/cool.gif | Bin 0 -> 687 bytes .../source/web/images/emoticons/cry.gif | Bin 0 -> 693 bytes .../source/web/images/emoticons/devil.gif | Bin 0 -> 1093 bytes .../source/web/images/emoticons/grin.gif | Bin 0 -> 680 bytes .../source/web/images/emoticons/happy.gif | Bin 0 -> 675 bytes .../source/web/images/emoticons/laugh.gif | Bin 0 -> 670 bytes .../source/web/images/emoticons/love.gif | Bin 0 -> 1084 bytes .../source/web/images/emoticons/mischief.gif | Bin 0 -> 693 bytes .../source/web/images/emoticons/plain.gif | Bin 0 -> 678 bytes .../source/web/images/emoticons/sad.gif | Bin 0 -> 694 bytes .../source/web/images/emoticons/shocked.gif | Bin 0 -> 688 bytes .../source/web/images/emoticons/silly.gif | Bin 0 -> 685 bytes .../source/web/images/emoticons/wink.gif | Bin 0 -> 634 bytes 18 files changed, 604 insertions(+) create mode 100644 apps/webchat/source/java/org/jivesoftware/webchat/EmoticonFilter.java create mode 100644 apps/webchat/source/java/org/jivesoftware/webchat/URLFilter.java create mode 100644 apps/webchat/source/web/images/emoticons/angry.gif create mode 100644 apps/webchat/source/web/images/emoticons/blush.gif create mode 100644 apps/webchat/source/web/images/emoticons/confused.gif create mode 100644 apps/webchat/source/web/images/emoticons/cool.gif create mode 100644 apps/webchat/source/web/images/emoticons/cry.gif create mode 100644 apps/webchat/source/web/images/emoticons/devil.gif create mode 100644 apps/webchat/source/web/images/emoticons/grin.gif create mode 100644 apps/webchat/source/web/images/emoticons/happy.gif create mode 100644 apps/webchat/source/web/images/emoticons/laugh.gif create mode 100644 apps/webchat/source/web/images/emoticons/love.gif create mode 100644 apps/webchat/source/web/images/emoticons/mischief.gif create mode 100644 apps/webchat/source/web/images/emoticons/plain.gif create mode 100644 apps/webchat/source/web/images/emoticons/sad.gif create mode 100644 apps/webchat/source/web/images/emoticons/shocked.gif create mode 100644 apps/webchat/source/web/images/emoticons/silly.gif create mode 100644 apps/webchat/source/web/images/emoticons/wink.gif diff --git a/apps/webchat/source/java/org/jivesoftware/webchat/EmoticonFilter.java b/apps/webchat/source/java/org/jivesoftware/webchat/EmoticonFilter.java new file mode 100644 index 000000000..293edf0ff --- /dev/null +++ b/apps/webchat/source/java/org/jivesoftware/webchat/EmoticonFilter.java @@ -0,0 +1,292 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 2003 Jive Software. All rights reserved. + * + * This software is the proprietary information of Jive Software. Use is subject to license terms. + */ + +package org.jivesoftware.webchat; + +/** + * A Filter that converts ASCII emoticons into image equivalents. + * This filter should only be run after any HTML stripping filters.

+ * + * The filter must be configured with information about where the image files + * are located. A table containing all the supported emoticons with their + * ASCII representations and image file names is as follows:

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
EmotionASCIIImage
Happy:) or :-)happy.gif
Sad:( or :-(sad.gif
Grin:Dgrin.gif
Love:xlove.gif
Mischief;\mischief.gif
CoolB-)cool.gif
Devil]:)devil.gif
Silly:psilly.gif
AngryX-(angry.gif
Laugh:^Olaugh.gif
Wink;) or ;-)wink.gif
Blush:8}blush.gif
Cry:_|cry.gif
Confused?:|confused.gif
Shocked:Oshocked.gif
Plain:|plain.gif
+ * + * Note: special thanks to August Harrison for implementing an earlier version of this filter. + */ +public class EmoticonFilter { + + private static String imageHappy = "happy.gif"; + private static String imageSad = "sad.gif"; + private static String imageGrin = "grin.gif"; + private static String imageLove = "love.gif"; + private static String imageMischief = "mischief.gif"; + private static String imageCool = "cool.gif"; + private static String imageDevil = "devil.gif"; + private static String imageSilly = "silly.gif"; + private static String imageAngry = "angry.gif"; + private static String imageLaugh = "laugh.gif"; + private static String imageWink = "wink.gif"; + private static String imageBlush = "blush.gif"; + private static String imageCry = "cry.gif"; + private static String imageConfused = "confused.gif"; + private static String imageShocked = "shocked.gif"; + private static String imagePlain = "plain.gif"; + private static String imageURL = "images/emoticons"; + + // Placeholders for the built image tags + private static String imgHappy; + private static String imgSad; + private static String imgGrin; + private static String imgLove; + private static String imgMischief; + private static String imgCool; + private static String imgDevil; + private static String imgSilly; + private static String imgAngry; + private static String imgLaugh; + private static String imgWink; + private static String imgBlush; + private static String imgCry; + private static String imgConfused; + private static String imgShocked; + private static String imgPlain; + + public EmoticonFilter() { + buildImageTags(); + } + + public String applyFilter(String string) { + if (string == null || string.length() < 1) { + return string; + } + + int length = string.length(); + StringBuffer filtered = new StringBuffer(string.length() + 100); + char[] chars = string.toCharArray(); + + int length1 = length - 1; + int length2 = length - 2; + + int index = -1, i = 0, oldend = 0; + String imgTag; + + // Replace each of the emoticons, expanded search for performance + while (++index < length1) { + // no tag found yet... + imgTag = null; + + switch (chars[i = index]) { + case ']': + // "]:)" + if (i < length2 && chars[++i] == ':' && chars[++i] == ')') { + imgTag = imgDevil; + } + break; + case ':': + switch (chars[++i]) { + case ')': + // ":)" + imgTag = imgHappy; + break; + case '-': + // ":-)" + if (i < length1 && chars[++i] == ')') { + imgTag = imgHappy; + } + // ":-(" + else if (chars[i] == '(') { + imgTag = imgSad; + } + break; + case '(': + // ":(" + imgTag = imgSad; + break; + case 'D': + // ":D" + imgTag = imgGrin; + break; + case 'x': + // ":x" + imgTag = imgLove; + break; + case 'p': + // ":p" + imgTag = imgSilly; + break; + case '^': + // ":^O" + if (i < length1 && chars[++i] == 'O') { + imgTag = imgLaugh; + } + break; + case '8': + // ":8}" + if (i < length1 && chars[++i] == '}') { + imgTag = imgBlush; + } + break; + case '_': + // ":_|" + if (i < length1 && chars[++i] == '|') { + imgTag = imgCry; + } + break; + case 'O': + // ":O" + imgTag = imgShocked; + break; + case '|': + // ":|" + imgTag = imgPlain; + break; + default: + break; + } + break; + case ';': + switch (chars[++i]) { + case ')': + // ";)" + imgTag = imgWink; + break; + case '-': + // ";-)" + if (i < length1 && chars[++i] == ')') { + imgTag = imgWink; + } + break; + case '\\': + // ";\\" + imgTag = imgMischief; + break; + default: + break; + } + break; + case 'B': + // "B-)" + if (i < length2 && chars[++i] == '-' && chars[++i] == ')') { + imgTag = imgCool; + } + break; + case 'X': + // "X-(" + if (i < length2 && chars[++i] == '-' && chars[++i] == '(') { + imgTag = imgAngry; + } + break; + case '?': + // "?:|" + if (i < length2 && chars[++i] == ':' && chars[++i] == '|') { + imgTag = imgConfused; + } + break; + default: + break; + } + + // if we found one, replace + if (imgTag != null) { + filtered.append(chars, oldend, index-oldend); + filtered.append(imgTag); + + oldend = i + 1; + index = i; + } + } + + if (oldend < length) { + filtered.append(chars, oldend, length-oldend); + } + + return filtered.toString(); + } + + /** + * Returns the base URL for emoticon images. This can be specified as + * an absolute or relative path. + * + * @return the base URL for smiley images. + */ + public String getImageURL() { + return imageURL; + } + + /** + * Sets the base URL for emoticon images. This can be specified as + * an absolute or relative path. + * + * @param imageURL the base URL for emoticon images. + */ + public void setImageURL(String imageURL) { + if (imageURL != null && imageURL.length() > 0) { + if (imageURL.charAt(imageURL.length()-1) == '/') { + imageURL = imageURL.substring(0, imageURL.length()-1); + } + } + this.imageURL = imageURL; + + // rebuild the image tags + buildImageTags(); + } + + /** + * Build image tags + */ + private void buildImageTags() { + imgHappy = buildURL(imageHappy); + imgSad = buildURL(imageSad); + imgGrin = buildURL(imageGrin); + imgLove = buildURL(imageLove); + imgMischief = buildURL(imageMischief); + imgCool = buildURL(imageCool); + imgDevil = buildURL(imageDevil); + imgSilly = buildURL(imageSilly); + imgAngry = buildURL(imageAngry); + imgLaugh = buildURL(imageLaugh); + imgWink = buildURL(imageWink); + imgBlush = buildURL(imageBlush); + imgCry = buildURL(imageCry); + imgConfused = buildURL(imageConfused); + imgShocked = buildURL(imageShocked); + imgPlain = buildURL(imagePlain); + } + + /** + * Returns an HTML image tag using the base image URL and image name. + */ + private String buildURL(String imageName) { + String tag = ""; + + return tag; + } +} \ No newline at end of file diff --git a/apps/webchat/source/java/org/jivesoftware/webchat/URLFilter.java b/apps/webchat/source/java/org/jivesoftware/webchat/URLFilter.java new file mode 100644 index 000000000..de2f972b5 --- /dev/null +++ b/apps/webchat/source/java/org/jivesoftware/webchat/URLFilter.java @@ -0,0 +1,312 @@ +/** + * $RCSfile$ + * $Revision$ + * $Date$ + * + * Copyright (C) 1999-2002 CoolServlets, Inc. All rights reserved. + * + * This software is the proprietary information of CoolServlets, Inc. + * Use is subject to license terms. + */ + +package org.jivesoftware.webchat; + +import java.util.*; + +/** + * A Filter that converts URL's to working HTML web links.

+ * + * The default set of patterns recognized are ftp://path-of-url, + * http://path-of-url, https://path-of-url but can be expanded upon.

+ * + * In addition, the following patterns are also recognized. + * + * [url path-of-url]descriptive text[/url] and + * [url=path-of-url]descriptive text[/url].

+ * + * The [url] allows any path to be defined as link. + */ +public class URLFilter{ + + private ArrayList schemes = new ArrayList(); + + // define a preset default set of schemes + public URLFilter() { + schemes.add("http://"); + schemes.add("https://"); + schemes.add("ftp://"); + } + + public String applyFilter(String string) { + if (string == null || string.length() == 0) { + return string; + } + + int length = string.length(); + StringBuffer filtered = new StringBuffer((int) (length * 1.5)); + ArrayList urlBlocks = new ArrayList(5); + + // search for url's such as [url=..]text[/url] or [url ..]text[/url] + int start = string.indexOf("[url"); + while (start != -1 && (start + 5 < length)) { + // check to verify we're not in another block + if (withinAnotherBlock(urlBlocks, start)) { + start = string.indexOf("[url", start + 5); + continue; + } + + int end = string.indexOf("[/url]", start + 5); + + if (end == -1 || end >= length) { + // went past end of string, skip + break; + } + + String u = string.substring(start, end + 6); + int startTagClose = u.indexOf(']'); + String url; + String description; + if (startTagClose > 5) { + url = u.substring(5, startTagClose); + description = u.substring(startTagClose + 1, u.length() - 6); + + // Check the user entered URL for a "javascript:" or "file:" link. Only + // append the user entered link if it doesn't contain 'javascript:' and 'file:' + String lcURL = url.toLowerCase(); + if (lcURL.indexOf("javascript:") == -1 && lcURL.indexOf("file:") == -1) { + URLBlock block = new URLBlock(start, end + 5, url, description); + urlBlocks.add(block); + } + } + else { + url = description = u.substring(startTagClose + 1, u.length() - 6); + // Check the user entered URL for a "javascript:" or "file:" link. Only + // append the user entered link if it doesn't contain 'javascript:' and 'file:' + String lcURL = url.toLowerCase(); + if (lcURL.indexOf("javascript:") == -1 && lcURL.indexOf("file:") == -1) { + URLBlock block = new URLBlock(start, end + 5, url); + urlBlocks.add(block); + } + } + + start = string.indexOf("[url", end + 6); + } + + // now handle all the other urls + Iterator iter = schemes.iterator(); + + while (iter.hasNext()) { + String scheme = (String) iter.next(); + start = string.indexOf(scheme, 0); + + while (start != -1) { + int end = start; + + // check context, don't handle patterns preceded by any of '"<= + if (start > 0) { + char c = string.charAt(start - 1); + + if (c == '\'' || c == '"' || c == '<' || c == '=') { + start = string.indexOf(scheme, start + scheme.length()); + continue; + } + } + + // check to verify we're not in another block + if (withinAnotherBlock(urlBlocks, start)) { + start = string.indexOf(scheme, start + scheme.length()); + continue; + } + + // find the end of the url + int cur = start + scheme.length(); + while (end == start && cur < length) { + char c = string.charAt(cur); + + switch (c) { + case ' ': + end = cur; + break; + case '\t': + end = cur; + break; + case '\'': + end = cur; + break; + case '\"': + end = cur; + break; + case '<': + end = cur; + break; + case '[': + end = cur; + break; + case '\n': + end = cur; + break; + case '\r': + end = cur; + break; + default: + // acceptable character + } + + cur++; + } + + // if this is true it means the url goes to the end of the string + if (end == start) { + end = length - 1; + } + + URLBlock block = new URLBlock(start, end-1, string.substring(start, end)); + urlBlocks.add(block); + + start = string.indexOf(scheme, end); + } + } + + // sort the blocks so that they are in start index order + sortBlocks(urlBlocks); + + // now, markup the urls and pass along the filter chain the rest + Iterator blocks = urlBlocks.iterator(); + int last = 0; + + while (blocks.hasNext()) { + URLBlock block = (URLBlock) blocks.next(); + + if (block.getStart() > 0) { + filtered.append(string.substring(last, block.getStart())); + } + + last = block.getEnd() + 1; + + filtered.append(""); + if (block.getDescription().length() > 0) { + filtered.append(block.getDescription()); + } + else { + filtered.append(block.getUrl()); + } + filtered.append(""); + } + + if (last < string.length() - 1) { + filtered.append(string.substring(last)); + } + + return filtered.toString(); + } + + /** + * Returns the current supported uri schemes as a comma seperated string. + * + * @return the current supported uri schemes as a comma seperated string. + */ + public String getSchemes() { + StringBuffer buf = new StringBuffer(50); + + for (int i = 0; i < schemes.size(); i++) { + buf.append((String) schemes.get(i)).append(","); + } + buf.deleteCharAt(buf.length() - 1); + + return buf.toString(); + } + + /** + * Sets the current supported uri schemes as a comma seperated string. + * + * @param schemes a comma seperated string of uri schemes. + */ + public void setSchemes(String schemes) { + if (schemes == null) { + return; + } + + // enpty the current list + this.schemes.clear(); + + StringTokenizer st = new StringTokenizer(schemes, ","); + + while (st.hasMoreElements()) { + this.schemes.add(st.nextElement()); + } + } + + private void sortBlocks(ArrayList blocks) { + Collections.sort(blocks, new Comparator() { + public int compare(Object object1, Object object2) { + URLBlock b1 = (URLBlock) object1; + URLBlock b2 = (URLBlock) object2; + return (b1.getStart() > b2.getStart()) ? 1 : -1; + } + }); + } + + private boolean withinAnotherBlock(List blocks, int start) { + for (int i = 0; i < blocks.size(); i++) { + URLBlock block = (URLBlock) blocks.get(i); + + if (start >= block.getStart() && start < block.getEnd()) { + return true; + } + } + + return false; + } + + class URLBlock { + int start = 0; + int end = 0; + String description = ""; + String url = ""; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + URLBlock(int start, int end, String url) { + this.start = start; + this.end = end; + this.url = url; + } + + URLBlock(int start, int end, String url, String description) { + this.start = start; + this.end = end; + this.description = description; + this.url = url; + } + + public int getStart() { + return start; + } + + public void setStart(int start) { + this.start = start; + } + + public int getEnd() { + return end; + } + + public void setEnd(int end) { + this.end = end; + } + } +} \ No newline at end of file diff --git a/apps/webchat/source/web/images/emoticons/angry.gif b/apps/webchat/source/web/images/emoticons/angry.gif new file mode 100644 index 0000000000000000000000000000000000000000..6489c9bc9ffaa5448b597b17249d090228556243 GIT binary patch literal 692 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 literal 0 HcmV?d00001 diff --git a/apps/webchat/source/web/images/emoticons/devil.gif b/apps/webchat/source/web/images/emoticons/devil.gif new file mode 100644 index 0000000000000000000000000000000000000000..31bca49fb84673af853fdd6ca0b7f124930cc901 GIT binary patch literal 1093 zcmZ?wbhEHb6krfw_&$YU*Up_*rskK9T|B=2z>Q0{uAaVXX=)x79#L0W>+0yddfA$b zM=zY%cyRyR%}18+x_J2fg+u2~Z$EbZ!p-X!Z)N(#p51fm{DHG8`}?;vEjYXPR9-;f z!G+rnF51@L(zC8)+S%jh=S`n?{rt_$u*8gzgpIXxuAaTNy=&>@p2>?U`!Aooa%}b9 zdEGOPuG~|dS-haEr>(AKUQSW9Tk4flSCT_x56s;>DJ1sn{u3uRA9i(c-aBLcfq9#c zuiJla{~2Rd9VZ=&`Lh<3c_nXYS(p`_a%9D>gL@87>6@}5t#^6T%!2H^iJcS9?mjuU zed^hL$7{-}>-@9oD(j5ZbXsd$f{a~{t=;FOZE@q`t>nn~LkqVpOYGV=Yvbg;$=A-` z*i=97!2B&qA<@xck=gO-t8ympnX~pHxosUw^0RZ#A3S?>)t((a z%ZrnCMFoi(}WD6+!FmQZl zP!E*y*pP70lf6Y@p~=fjbKG@*#R$z{Khx+L<@Y5+xs!XIiNp>nx#Pnd&L>WO5 zQ%;8l2L@wJt%45)FNKyE+uZTlaO9d0qXYjk7ESLa))sx2TT#Cp+!>gKr!yQVT)@uT zXU`>K!^x0zu)&-`YkF%;xshjQy z9BJ`kl;&58(M&0DQ5NmcN@*}`a8qe!-n&EMii10^i17sBJqsF{Sb4>H*jN~>0cN^+ AtpET3 literal 0 HcmV?d00001 diff --git a/apps/webchat/source/web/images/emoticons/grin.gif b/apps/webchat/source/web/images/emoticons/grin.gif new file mode 100644 index 0000000000000000000000000000000000000000..e5c92e2d588ee89b770d2fc9e0edbb3b8a75a13b GIT binary patch literal 680 zcmZ?wbhEHb6krfwcoxcV;`s6OIOWebOnyJtjSTkr@z9_#&7iMAqp7B>AQDqF+{A z5*et{->mlMxz3LV2EU)`UD%_0aj&kAi}LJl&By?i@AnPgpSOqz^6_?2etkuMR+rY# zM+Qx`W%DMgeZOb;=Y>vxS4&io@`M((j~_o?yL$ESOYQ$)z(9AP_)p!&**_rC&N;uJ zvM4h>qeQ_gvn*91I6tkVJh3QM!N|bCNEb*LGbsLKVPs$kWzYdR5)^$5?6(?1o0=@m zIoVA4o4Z4UM6`{yR5W!=f_gj!4VeO1h1@N8Bw3n+1U&-Gm;(dt9UW8!riY3c28h`) zhKDnTFtbYWhFWSfnFR(1?>-qWW~9eqZXCcI?jN!{#40?{mrtBii#2ff)2E^m23%|^ zLQkGOmyqT*)$|cQ8S*QHF<97DCe9|I@vsMn4ucTW0ii|gQ}}IGT}asA+{vyZv9Uto z5@QR8W0295h@wL--C}BfB?1OaM-`X^Oil+TW PdKwWQ4skAaV6X-NY#!&a literal 0 HcmV?d00001 diff --git a/apps/webchat/source/web/images/emoticons/happy.gif b/apps/webchat/source/web/images/emoticons/happy.gif new file mode 100644 index 0000000000000000000000000000000000000000..20a93e32b9fc9798bf305cad7f8dc8ec5a0678b3 GIT binary patch literal 675 zcmZ?wbhEHb6krfwcoxL)>xq6;kn)d*29d!&pKqA_ey%&AMXfqF==BN9pN|Y0tIOV< zvzRwg?a%`A-_LYga`jqr^cyque?HRxc-idz9j%X7Oj~mGe?Bz$`B?wgQ@!SF{iDlG z8`BKF-7)%p-|)sp>w9}G`kU20UNL)r-u&Gei}x4I-<-BwJy*RZKQKK`xv8eCIwz8R*ZFkSw6Uh_!$tGEyDa~{(5Wd1e09v~)>f-Si_CvKFqk_* zy}!HV%Pr$8hc!#GRNtSs`2AEbJx;~WLhz|milH89Z7$y&*3dXS)+KcAvzNQfpIE0YO- z5SKiQWFRBs?vo*WvZh+v7XGXuJZ!t!)I$O}xixh3nF4n|eQL%aEFhyI{^Z$n22n9~ z4mraQPXmQi&5bSXCTv-d(C5^xmwdxq3&Jo8H@N(VVS+ zW25!^^X6Y}8P^m9e!OD(_KZbKuD+p;;)jdoKAv9R?;GCQYE_b@`tFQHYk}VWSr&&D zn18!tba$8Kj|T=n9~v}f=zqLoc4(1#V|Ce;!uz15-B_mf;H=Kuo4OG}K0hDn|9Ywy8K7ck zssH<#?$NE9-|rblg-7&vwS4^e@x<}t*REcj(4zMDrM9xX!vFvO8R!la|Eb$J`v*kY zIp-Ht7GiF32F0H&j0_CH3_2i3f})Rs{X#=< zQ-iJH*)}^ftsAG4pVcGwnKoU4GW9EhrW^V^k75o z0C(jG28IY_5k?h>U=tZ;Z(&o0@NfoGVLx3xR!)Hcm(w?Huvqbnu_-dzhdqAsgv(q= zRMWsW3BqUF0kW`5hNj#9iK80J-Lw8cs!K2O63IZ7cfs-aKU=ma5_|ecD IsK8(i0Nbz>% literal 0 HcmV?d00001 diff --git a/apps/webchat/source/web/images/emoticons/love.gif b/apps/webchat/source/web/images/emoticons/love.gif new file mode 100644 index 0000000000000000000000000000000000000000..d1c320e3db12012e643d97224823da4e99dc531e GIT binary patch literal 1084 zcmZ?wbhEHb6krfw_|CwvX7%ciA3t8ZdbPR8;O`6bw4|t)XYG{b6~5lHdUwV4{T;J6 zmu&4Ulg8Uzt^srCE>>P?hiY>xo5rocf!KcHiz>JwI*VR9p7$s_om$w!3!j z{CwN`@*(4!`)ohmvVPH%`}vObmBYpr*;eJ5R^RSf&2Be&(VO@4vBmse;|FI=@0>8- zGS}kWEwdNR$q$a%+&^Rb;fBqfhUASiEs}i=s-e^;r zrI`?7b|=jG&ohe;*KJZ_{a)0>yuWIruc>69t#tc#4=7s}_-gYHb$Uug=^3eroaK zv1LJw){lpl@2}c^ykXOrZ}_4w??rdcym;>;n~e&5T@Pcrzh;^bea^TYQ4Q-_T{ei!}BJ2J{G0fn$iF3 z2F0H&j3A43Km;iJFmSwMVC0bb(a<6x#LuQBvLdZbhB=zY#_(gBVuM_$RtsmMx=SCc zoDxrtaEiN>enf!JgilM|*!Wo)UcB7=;+UX(ww26_hQ%GyylM;?f|HgA%+w59AXBmA z@qzjL;s$dH3!N@-I+)1>RxDBQmSquDVQ64Z;^C0ul3Q8p^1yu&3p0a&rZRIshhX;2 zZ4na{^A?EYB;2{V%dD%*P5+3}&JPFsg*YlN2}LaG;FITJl2p|&OypN&vr#bUU`{*d z;NsUXjrW#8^w{d!_iQyld6vTb!?(2qx!%|!;kpIW>+ zXZPp1`IkG^ks&_cA6m|vsQdew#h1I*jroS@aq91`*uK4FdwsXvorAVNA6tICXZ_-g z{nxwJuP@p))|MSuVbxe*@b`uJ$D1}$L2A!W+y8lP@#dmkONl{Kp}~#4wmVlDG~^rp zd}7g5Wbo^$#l9t0w+`4ISZ;M_wdMB*mUb4(vwQT4Gc_;mH;D{XdwLX`bI>`uUFamBYsKCg`5oY4-8s$7@%w_IJ1Z zd13zdrTPE={~2fu6#uE)IQs`g+BxSJR2F5XXOt*-WtOEX1m~xflqVLYDi|3U80i8D zV+O^aEQ|~cQ4BgDCxN1mf&Fdevpe3Z={1A zgCSpYj6MTnsF{wrq^TpD{PZXVA4YyXo7h-y4_96_&L}zY0A{@qkvJ`{SV4Xz115GA zMh+ee@OzV@vcRF6g;$c5iNP8G4(sr0 literal 0 HcmV?d00001 diff --git a/apps/webchat/source/web/images/emoticons/plain.gif b/apps/webchat/source/web/images/emoticons/plain.gif new file mode 100644 index 0000000000000000000000000000000000000000..a5beeea43d6524c0159b811f3decae667faa7773 GIT binary patch literal 678 zcmZ?wbhEHb6krfwc;?A4p+)D%Bg@wp?3!xJUY)b6E)4o|$NI}%>t9bSYKnv2Ubby6 zGKdWEIkMU4&vWySH*MZtvVDKe_Rc}u*B9*$t+sr3#rE$D^QJZ)Bb(_z3tec7q8f(jb zKef1Z!1ntC%k(()pN}mY3k+`TwS95M{^eP_?+-1HY%)5($220?XWj(epN}mjH0#Xm z*ZuX>qQ6P!&vT2i;*$5*Z01hT?Q7Dxu-9buT)j`XtiRp2`t!p47IrrZl=!q9v=F3jBLu>p4y6n?zWPuK0d0FvZnmH%&aPIjC__1 zrx{%NIM|su)mhl&Jx;&y@z8M>(2`rfD+*5+1bmvT1Zya5yD~39(7L*;o`j;b2o1 f)tC^qCB>1OQ9#6J0>dHI#f+RGIvOW51Q@IVtmn`@ literal 0 HcmV?d00001 diff --git a/apps/webchat/source/web/images/emoticons/sad.gif b/apps/webchat/source/web/images/emoticons/sad.gif new file mode 100644 index 0000000000000000000000000000000000000000..0320885df0790a2be3ba5eed317e02a461d32c90 GIT binary patch literal 694 zcmZ?wbhEHb6krfwc$UO);rYiCkKVU+^&NfiZq>zC?wJjnuD-6SX$S}kt7`7tapO%y zY~qG1uiLx&CLDe`@AQjv&pw=g_Q5wGr0d|5>BpaKy!v{}wb#>*J==5p?a>GCXB>aF z`qHb4>V~vgd)HrnHR;IHeRtljz5L2GqdsrmzKm5@wqAcd zqNeR$e*R@eO+)+sCyUO$h{&$=&2G$Jd$pshFE+2rHnq+swXW~*)80c*{R2ZHb1FSE z8xGukcl6eiV-Mc%y7^}NjW>RQAx(Q9r_9<@yZQRTd+%27I}w*x<&ai?^3i)|7x((z zkIITm^2@9H=PWvQ`^nr5yI1Wyaq#ZD`KMn528SJg_`d(})0Y0JRh^S9Ev)MIJnEmb zc;(&``)s^e+KFS#eeEH&i(cV(8;l8}><I~#U^noVcGV2$OiktVOJ-)XFfmgXWlm`l>!h1XL0_*w_@>v`MkdVY8>c(5P b;6Pzx6SIeY$1+<*xPbXBKZS+5UWD@$QQ4^V9Y(&)VJCYkPgSU1Xrz^NW^^wPl+Z8NE1T ze`vL3L%!j!rxx$;nEiZgxo?Tp>x*{jaq71Y*v^}vdtkX$Q<1@rl?Im&8n=`f+&O6b z_l3EEw$j&o)^9G_H5M2&6&geZseQX|bzp_n$D204pIS8L8{Ru&6A|q5;J9^Rs@9+9 z7N74}f4yt{`L^|k>o&`$8{9i;Q&wEEVur!G*(O_;7%rY{`17&F(kX_AHX0YEX|11Q za%`L7-4kZ}R-0^HYWV$u<@;;4cTWPjriV8f9p7g7{+f-lyuzOs<{v+Pyms|!e|O8@ zm*)Tf|7V~*Q2eKE8LUm06am5S*V@Ql40ps$gVbV5AEqj2RSv zvM@3*L^0@qTm_0g2KGk{QB6&fY_jHT49(q9F$QA7Oia?EhA};siXyHdoP7R17HZth zF^W#sZtQ{_3IX0$Cexz~MBKgP7$YMY`9nSRnWH4df*j>ERAXaRHTYdjRT$WWdD$7o zjZPbhGjj0pu*foT3P!RjpH^m#G&2@ZH)rDGh>Vp#{X^#+7c-l*y#q^x+Xinj7CRRK zh5$y7DeRH6L^KjwS^JrJ!+0(VH9Ph*Yi{T`GKr~^n^TLW&~Twb<76?VXrIEu*26lw q+!=dTG&(l3@$jk?C~WOG%^<|1pdql)>8P(81IHYR4HE(t7_0#s@9g~m literal 0 HcmV?d00001 diff --git a/apps/webchat/source/web/images/emoticons/silly.gif b/apps/webchat/source/web/images/emoticons/silly.gif new file mode 100644 index 0000000000000000000000000000000000000000..a162605bd4cd0a6f36c3cf2b0c669d528e1021fa GIT binary patch literal 685 zcmZ?wbhEHb6krfwcoxa<=Y@GwZP}+=)~_$veYs;@Qylc_oZZ{Ywm%+OHWwLuyKhxp z7!(=e^XrMlm%G;AA6iam(K)o*vZ=`6#$MZ(XYKABwEcYB`qly4-%l+*-?4si#{S(E z+v~gSKHju>d&#!3w(P@on*%GX{yaB-n&ft1xz*1n7H=-v?F+GQ$T$3Y&pI_kvoYUr z-x90zIQ5nigQ!5Y$UwE%7wz6(vyBQ;o9=G@{Iq>jp+RGTK}4{RorUuIYc{X1nZLen z{`Ic4x2@`%8|HOcx<4OV_BZKVK4|>=nZ>bfhWAdHK0RmESf>5_qUGNg=IOB-rP-R@ z35I3GCC9cJ)@AFio~t)+g6_*J7T+IO-iUSi_0-~1nrB~=&c}}*uU);`-`(=}rTPE= z{~7246#uE)IQs`g+BxSJR2F5XXOt*-WtOEX1m~xflqVLYDi|3U80i8DV+O^aEQ|~c zkqkN@hk>Gxf&G3%WK)wow}v)1V{><8w7HBa8=I7{S#*zuj))Nx3!j(*vkFghv<@>9 z7l$gZV~8ZX;`B&!5hnf!T?PhSCk_@h&PaI~Bd#z5{g@bi0~dZ-aYk-aCJv<_fztwk zO1yl`tQu@Astl)J#4t#3$q8w*@$o)?8RPYaos(Ni%*Ov~OxK?mf{Ps*I2D#DoHT6a zY>~8^_C_G!pr@ELvyp;?)8iwZS|&Y9Zai?hAST4lVH05Z=oE*jW{Jy;sjZG2!m^Vb kGMS#7XyaHSmg`xN*wD^wsI_CkNeu@^PEH;pE*1uB06o|0lK=n! literal 0 HcmV?d00001 diff --git a/apps/webchat/source/web/images/emoticons/wink.gif b/apps/webchat/source/web/images/emoticons/wink.gif new file mode 100644 index 0000000000000000000000000000000000000000..6d91b0fa25aa104127aba70ba3a81baa17f958b1 GIT binary patch literal 634 zcmZ?wbhEHb6krfwcoxj?`?+pZkn*o5`ad2Te7<248SK+kt~zg`T4}aQbxzQq=Q=+h z>93xv-jb`|SY6hft$%B))uBb^ExCG)8T$KYSsYqm-ddpd=CoyFnn8be%f~CGzn<#d z-DUayg8BFRhTrZOeY$FTW25!YM+R@tShVEmzdK`bbh&9$P1(<_&2E@6K7&6a?PeYw_rUmXE8_gch|A7tI@M%06B(`*O>;IydO!WwX~OEE~(z z-rv#cZ&H7CMgQS>t)p8t-`~+bwoS9Fxa9XU-J@Hy-rmxQ2=Y;uSNQ!@FFj8A{do&J z3&p0|vbht~e>^bwe$TMKtL5XzkAGh1T)TSp?@R6f|Nk=#5K#Qd!pOi7%%B6Z9~37H z?AIHDo0|AI^&~9Kn!AI8gcY@vRjmd1gL*tf#90EFHRLRGMOmAJM0^6J8A3w1yaLPx zrw0p*2ip0E?b^k_Y$_DYr^q7h$r#4Y6J`|VDlenXsTIh;=pAOu!N_P7qNJ~_r_3C( z`&pPKla-2us>ajjyIxB1T3X9-ePjy@;g&TpQ+QxdbU>zAl8wQo(=p{#vzUE_$wJ3u zHYUZ8h=vUc9$u}|%zZ49Of6gtVk|x>5+Mpsz5Gfn91#MnEu2B!OFSNYaB6SkGt^m= SqVnPhmk@7)MWP4?gEau!n$Kwf literal 0 HcmV?d00001