I want my bot to send messages in such bubbles, but I do not know the code.
Those "bubbles" are embeds, types of messages that can be sent only by bots. To send them, you'll need to use the RichEmbed class: you can create an instance of the class and then edit it with the methods you find in the docs. Here's an example with the image you sent:
let embed = new Discord.RichEmbed()
.setColor([66, 134, 244])
.setTitle("Zhontroly' si zprávy")
.setDescription(":mailbox_with_mail: | Odeslal jsem ti do zpráv napovedu s příkazy!");
channel.send({embed});
Here's a more in-depth example, from "An Idiot's Guide"
const embed = new Discord.RichEmbed()
.setTitle("This is your title, it can hold 256 characters")
.setAuthor("Author Name", "https://i.imgur.com/lm8s41J.png")
/*
* Alternatively, use "#00AE86", [0, 174, 134] or an integer number.
*/
.setColor(0x00AE86)
.setDescription("This is the main body of text, it can hold 2048 characters.")
.setFooter("This is the footer text, it can hold 2048 characters", "http://i.imgur.com/w1vhFSR.png")
.setImage("http://i.imgur.com/yVpymuV.png")
.setThumbnail("http://i.imgur.com/p2qNFag.png")
/*
* Takes a Date object, defaults to current date.
*/
.setTimestamp()
.setURL("https://discord.js.org/#/docs/main/indev/class/RichEmbed")
.addField("This is a field title, it can hold 256 characters",
"This is a field value, it can hold 1024 characters.")
/*
* Inline fields may not display as inline if the thumbnail and/or image is too big.
*/
.addField("Inline Field", "They can also be inline.", true)
/*
* Blank field, useful to create some space.
*/
.addBlankField(true)
.addField("Inline Field 3", "You can have a maximum of 25 fields.", true);
message.channel.send({embed});
Related
Hello im using Nodejs with farhadi node-smpp library to send Message through smpp v3.4 protocals and gsm library to split the message, In my case i have a long Message(More than 255 characters), when i split the message i want it to be delivered as single long message, but unfortunately it is delivered in parts. Here are my sample codes for sending the message
var info = gsm(text);
var concat_ref = Math.floor(Math.random() * 255);
var part_id = 0;
info.parts.forEach(function(part){
part_id++;
var udh = new Buffer.allocUnsafe(6);
udh.write(String.fromCharCode(0x5), 0); //Length of UDF
udh.write(String.fromCharCode(0x0), 1); //Indicator for concatenated message
udh.write(String.fromCharCode(0x3), 2); // Subheader Length ( 3 bytes)
udh.write(String.fromCharCode(concat_ref), 3); //Same reference for all concatenated messages
udh.write(String.fromCharCode(info.sms_count), 4); //Number of total messages in the concatenation
udh.write(String.fromCharCode(part_id), 5); //Sequence number ( used by the mobile to concatenate the split messages)
session.submit_sm({
source_addr: from,
destination_addr: to,
message_payload: { udh: part.udh, message: part }
}, function(pdu) {
console.log('sms pdu status', lookupPDUStatusKey(pdu.command_status));
if (pdu.command_status == 0) {
// Message successfully sent
console.log(pdu.message_id);
}
});
})
You can use the message_payload parameter (field name) as stated in the official SMPP's specification to send messages longer than 254 octets.
message_payload definition:
Contains the extended short message user data. Up to 64K octets can be
transmitted.
The official document says:
Applications which need to send messages longer than 254 octets should
use the message_payload parameter. In this case the sm_length field
should be set to zero.
The short message data should be inserted in either the short_message
or message_payload fields. Both fields must not be used
simultaneously.
I made a test with node-smpp, and it works. No need to concatenate.
It's not very clear what you mean by "i want it to be delivered as single long message".
But SMPP wise, what you are doing seems correct. Long messages are delivered in parts and they are concatenated by the terminal(phone) based on the three parameters : part_ref, part_number and total_parts. However, from my experience, the concatenation is not really standard across all devices. For instance, some devices don't wait long enough for all the parts to arrive and show incomplete messages or nothing at all.
You have 2 choices when sending concatenated sms via SMPP : One is what you used (UDH), but there are also TLV parameters dedicated for the 3 parameters. You could ask your SMPP provider about extra details on how they support the sending of concatenated messages.
I currently have nouislider working fine. However I would like to add a postfix "%" symbol to my input fields, to show the user that the value is a percentage value, and the problem I'm having is that the value being passed with the form includes the % symbol. Does anyone know a workaround so that only the value is passed with the form?
An alternative method that I tried, to the format:wNumb method suggested in the nouislider documentation is as follows:
slider.noUiSlider.on('update', function( values, handle ) {
moistureValues[handle].value = values[handle] + '%';
});
However this is still appending the percentage symbol to the url. Is there any other way that would solve this problem? Thanks
The value of the input is the value that is submitted, this is how the basic feature in HTML works. You have some options:
Place the % sign in a <span> after the input.
use addEventListener('submit', ...) on the form, capture the submit, then change the input value and re-submit it (using .submit()).
Displaying the entire value in a span, and using a separate (hidden) input for the submit value.
(disclosure: I'm the lead developer for this libary).
You are changing the value while you only need to change the style of the element:
connectBar.style[side] = offset + '%';
Full example:
var connectSlider = document.getElementById('connect');
noUiSlider.create(connectSlider, {
start: [20, 80],
connect: false,
range: {
'min': 0,
'max': 100
}
});
var connectBar = document.createElement('div'),
connectBase = connectSlider.getElementsByClassName('noUi-base')[0],
connectHandles = connectSlider.getElementsByClassName('noUi-origin');
// Give the bar a class for styling and add it to the slider.
connectBar.className += 'connect';
connectBase.appendChild(connectBar);
connectSlider.noUiSlider.on('update', function( values, handle ) {
// Pick left for the first handle, right for the second.
var side = handle ? 'right' : 'left',
// Get the handle position and trim the '%' sign.
offset = (connectHandles[handle].style.left).slice(0, - 1);
// Right offset is 100% - left offset
if ( handle === 1 ) {
offset = 100 - offset;
}
connectBar.style[side] = offset + '%';
});
See the example here: https://refreshless.com/nouislider/examples/#section-custom-connect
I'm a bit new to ExactTarget in general so I apologize if this has already been answered (if it has, I can't find it anywhere).
I am attempting to create an email which will conditionally display n of 50 bulleted lists containing links to product information. However, whenever I attempt to send this email, I receive the following error message:
Other errors found in the email.
Category: AMP Script
Functions and Custom Objects:('
Field Name %%F50%% was not found in the send source.
Category: AMP Script
The second paragraph of the error message is repeated 50 times total (one for each field).
I cannot seem to figure-out why this issue is occurring:
I have a Data Extension with data for each field mapped in it.
I have imported valid data from a CSV to the data extension.
I have a list of valid subscribers to whom I am attempting to distribute.
I have an email template with custom areas inside each of which check if the subscriber has a "true" value for each field and shows/hides the content snippets on that basis.
I have 50x content snippets (one for each field).
There has to be something I'm missing here. Any ideas?
Thanks!
If the 50 fields are not in your sending data extension, you'll need to retrieve them with a script something like this. Note the values are displayed with%%=v(#DEColumn1)=%%:
%%[
var #rows, #row, #rowCount, #numRowsToReturn, #lookupValue, #i
set #lookupValue = "whee"
set #numRowsToReturn = 0 /* 0 means all */
set #rows = LookupOrderedRows("DataExtensionName",#numRowsToReturn,"DEColumn1 desc, DEColumn2 asc","LookupColumn", #lookupValue)
set #rowCount = rowcount(#rows)
if #rowCount > 0 then
for #i = 1 to #rowCount do
var #DEColumn1, #DEColumn2
set #row = row(#rows,#i) /*get row based on loop counter */
set #DEColumn1 = field(#row,"DEColumn1")
set #DEColumn2 = field(#row,"DEColumn2")
]%%
Row %%=v(#i)=%%, DEColumn1 is %%=v(#DEColumn1)=%%, DEColumn2 is %%=v(#DEColumn2)=%%
%%[ next #i ]%%
%%[ else ]%%
No rows found
%%[ endif ]%%
Also, there are a lot more people answering SFMC questions over at salesforce.stackexchange.com -- mostly tagged with marketing-cloud, ampscript.
As a part of a project, me and a few others are currently working on a URL classifier. What we are trying to implement is actually quite simple : we simply look at the URL and find relevant keywords occuring within it and classify the page accordingly.
Eg : If the url is : http://cnnworld/sports/abcd, we would classify it under the category "sports"
To accomplish this, we have a database with mappings of the format : Keyword -> Category
Now what we are currently doing is, for each URL, we keep reading all the data items within the database, and using String.find() method to see if the keyword occurs within the URL. Once this is found, we stop.
But this approach has a few problems, the main ones being :
(i) Our database is very big and such repeated querying runs extremely slowly
(ii) A page may belong to more than one category and our approach does not handle such cases. Of-course, one simple way to ensure this would be to continue querying the database even once a category match is found, but this would only make things even slower.
I was thinking of alternatives and was wondering if the reverse could be done - Parse the url, find words occuring within it and then query the database for those words only.
A naive algorithm for this would run in O( n^2 ) - query the database for all substrings that occur within the url.
I was wondering if there was any better approach to accomplish this. Any ideas ?? Thank you in advance :)
In our commercial classifier we have a database of 4m keywords :) and we also search the body of the HTML, there are number of ways to solve this:
Use Aho-Corasick, we have used a modified algorithm specially to work with web content, for example treat: tab, space, \r, \n as space, as only one, so two spaces would be considered as one space, and also ignore lower/upper case.
Another option is to put all your keywords inside a tree (std::map for example) so the search becomes very fast, the downside is that this takes memory, and a lot, but if it's on a server, you wouldn't feel it.
I think your suggestion of breaking apart the URL to find useful bits and then querying for just those items sounds like a decent way to go.
I tossed together some Java that might help illustrate code-wise what I think this would entail. The most valuable portions are probably the regexes, but I hope the general algorithm of it helps some as well:
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.List;
public class CategoryParser
{
/** The db field that keywords should be checked against */
private static final String DB_KEYWORD_FIELD_NAME = "keyword";
/** The db field that categories should be pulled from */
private static final String DB_CATEGORY_FIELD_NAME = "category";
/** The name of the table to query */
private static final String DB_TABLE_NAME = "KeywordCategoryMap";
/**
* This method takes a URL and from that text alone determines what categories that URL belongs in.
* #param url - String URL to categorize
* #return categories - A List<String&rt; of categories the URL seemingly belongs in
*/
public static List<String> getCategoriesFromUrl(String url) {
// Clean the URL to remove useless bits and encoding artifacts
String normalizedUrl = normalizeURL(url);
// Break the url apart and get the good stuff
String[] keywords = tokenizeURL(normalizedUrl);
// Construct the query we can query the database with
String query = constructKeywordCategoryQuery(keywords);
System.out.println("Generated Query: " + query);
// At this point, you'd need to fire this query off to your database,
// and the results you'd get back should each be a valid category
// for your URL. This code is not provided because it's very implementation specific,
// and you already know how to deal with databases.
// Returning null to make this compile, even though you'd obviously want to return the
// actual List of Strings
return null;
}
/**
* Removes the protocol, if it exists, from the front and
* removes any random encoding characters
* Extend this to do other url cleaning/pre-processing
* #param url - The String URL to normalize
* #return normalizedUrl - The String URL that has no junk or surprises
*/
private static String normalizeURL(String url)
{
// Decode URL to remove any %20 type stuff
String normalizedUrl = url;
try {
// I've used a URLDecoder that's part of Java here,
// but this functionality exists in most modern languages
// and is universally called url decoding
normalizedUrl = URLDecoder.decode(url, "UTF-8");
}
catch(UnsupportedEncodingException uee)
{
System.err.println("Unable to Decode URL. Decoding skipped.");
uee.printStackTrace();
}
// Remove the protocol, http:// ftp:// or similar from the front
if (normalizedUrl.contains("://"))
{
normalizedUrl = normalizedUrl.split(":\\/\\/")[1];
}
// Room here to do more pre-processing
return normalizedUrl;
}
/**
* Takes apart the url into the pieces that make at least some sense
* This doesn't guarantee that each token is a potentially valid keyword, however
* because that would require actually iterating over them again, which might be
* seen as a waste.
* #param url - Url to be tokenized
* #return tokens - A String array of all the tokens
*/
private static String[] tokenizeURL(String url)
{
// I assume that we're going to use the whole URL to find tokens in
// If you want to just look in the GET parameters, or you want to ignore the domain
// or you want to use the domain as a token itself, that would have to be
// processed above the next line, and only the remaining parts split
String[] tokens = url.split("\\b|_");
// One could alternatively use a more complex regex to remove more invalid matches
// but this is subject to your (?:in)?ability to actually write the regex you want
// These next two get rid of tokens that are too short, also.
// Destroys anything that's not alphanumeric and things that are
// alphanumeric but only 1 character long
//String[] tokens = url.split("(?:[\\W_]+\\w)*[\\W_]+");
// Destroys anything that's not alphanumeric and things that are
// alphanumeric but only 1 or 2 characters long
//String[] tokens = url.split("(?:[\\W_]+\\w{1,2})*[\\W_]+");
return tokens;
}
private static String constructKeywordCategoryQuery(String[] keywords)
{
// This will hold our WHERE body, keyword OR keyword2 OR keyword3
StringBuilder whereItems = new StringBuilder();
// Potential query, if we find anything valid
String query = null;
// Iterate over every found token
for (String keyword : keywords)
{
// Reject invalid keywords
if (isKeywordValid(keyword))
{
// If we need an OR
if (whereItems.length() > 0)
{
whereItems.append(" OR ");
}
// Simply append this item to the query
// Yields something like "keyword='thisKeyword'"
whereItems.append(DB_KEYWORD_FIELD_NAME);
whereItems.append("='");
whereItems.append(keyword);
whereItems.append("'");
}
}
// If a valid keyword actually made it into the query
if (whereItems.length() > 0)
{
query = "SELECT DISTINCT(" + DB_CATEGORY_FIELD_NAME + ") FROM " + DB_TABLE_NAME
+ " WHERE " + whereItems.toString() + ";";
}
return query;
}
private static boolean isKeywordValid(String keyword)
{
// Keywords better be at least 2 characters long
return keyword.length() > 1
// And they better be only composed of letters and numbers
&& keyword.matches("\\w+")
// And they better not be *just* numbers
// && !keyword.matches("\\d+") // If you want this
;
}
// How this would be used
public static void main(String[] args)
{
List<String> soQuestionUrlClassifications = getCategoriesFromUrl("http://stackoverflow.com/questions/10046178/pattern-matching-for-url-classification");
List<String> googleQueryURLClassifications = getCategoriesFromUrl("https://www.google.com/search?sugexp=chrome,mod=18&sourceid=chrome&ie=UTF-8&q=spring+is+a+new+service+instance+created#hl=en&sugexp=ciatsh&gs_nf=1&gs_mss=spring%20is%20a%20new%20bean%20instance%20created&tok=lnAt2g0iy8CWkY65Te75sg&pq=spring%20is%20a%20new%20bean%20instance%20created&cp=6&gs_id=1l&xhr=t&q=urlencode&pf=p&safe=off&sclient=psy-ab&oq=url+en&gs_l=&pbx=1&bav=on.2,or.r_gc.r_pw.r_cp.r_qf.,cf.osb&fp=2176d1af1be1f17d&biw=1680&bih=965");
}
}
The Generated Query for the SO link would look like:
SELECT DISTINCT(category) FROM KeywordCategoryMap WHERE keyword='stackoverflow' OR keyword='com' OR keyword='questions' OR keyword='10046178' OR keyword='pattern' OR keyword='matching' OR keyword='for' OR keyword='url' OR keyword='classification'
Plenty of room for optimization, but I imagine it to be much faster than checking the string for every possible keyword.
Aho-corasick algorithm is best for searching intermediate string with one traversal. You can form a tree (aho-corasick tree) of your keyword. At the last node contains a number mapped with a particular keyword.
Now, You just need to traverse the URL string on the tree. When you got some number (work as flag in our scenario), it means that we got some mapped category. Go on with that number on hash map and find respective category for further use.
I think this will help you.
Go to this link: good animation of aho-corasick by ivan
If you have (many) fewer categories than keywords, you could create a regex for each category, where it would match any of the keywords for that category. Then you'd run your URL against each category's regex. This would also address the issue of matching multiple categories.
I have a Groovy/Grails web app that reads e-mails from Gmail. It gets messages and attachments well, but I would like to limit the size of an attachment that I receive. Currently I have this code to read attachments:
byte[] file = new byte[maxSizeInBytes]
BufferedInputStream bis = new BufferedInputStream(part.getInputStream())
try {
file = bis.getBytes()
} catch (Exception e) {
...
}
The problem here is that Groovy simply expands the byte array to fit whatever comes in, so if my maxSizeInBytes is set to five megabytes (5*1024*1024), and I receive an attachment that is 10 megabytes the byte array simply expands to fit the entire file. How do I limit the size here? Even better, Is there a way to get how many bytes is the attachment before actually trying to download it?
Does part.inputStream.available() give you a resonable approximation?
Edit
Or, part.size probably gives you the encoded size of the attachment. I saw over here that multiplying this value by 0.65 should give you a rough approximation of the final attachment size