Empty FullText property with Tweetmode.Extended [update May 30th] - twitter

I'm programming a .Net Core (2.1 preview, C# 7.3) Streaming Console App with L2T (5.0.0 beta 2) but even with the strm.TweetMode == TweetMode.Extended the query gives "compat" tweets back, the FullText property is empty.
You can reproduce this with the L2T query below.
I searched online, I've found something similar (with 'search' instead of 'Streaming') but no answers, except to add && strm.TweetMode == TweetMode.Extended, which I did.
Any ideas?
try
{
await
(from strm in twitterCtx.Streaming
.WithCancellation(cancelTokenSrc.Token)
where
strm.Type == StreamingType.Filter
&& strm.Track == "twitter"
&& strm.Language == "nl"
&& strm.TweetMode == TweetMode.Extended
select strm)
.StartAsync(async strm =>
{
await HandleStreamResponse(strm);
if (count++ >= 20)
cancelTokenSrc.Cancel();
});
}
[Update May 30th]
Found something. It's in the subroutine "HandleStreamResponse" (code below). The Status.TweetMode and Status.ExtendedTweet.TweetMode both return "Compat" for all tweets, but the full text of a tweet is in status.ExtendedTweet.FullText
But even with this check, retweets are truncated to 140 chars max. I do not need retweets for my progam so I filter them out.
I do not know, yet, how to filter retweets from a stream directly (is it possible?), so I check the retweetstatus of the Status from the stream result. It's in the code below.
FYI: In the examples of Linq To Twitter for this subroutine Joe Mayo uses the following line of code, but that doesn't work: Console.WriteLine("{0}: {1} {2}", status.StatusID, status.User.ScreenNameResponse, status.Text ?? status.FullText);
Even with && strm.TweetMode == TweetMode.Extended in the L2T query, the status.FullText is empty.
There is more code than neccesary in the example below, but I used it for clarity.
static async Task<int> HandleStreamResponse(StreamContent strm)
{
switch (strm.EntityType)
{
case StreamEntityType.Status:
var status = strm.Entity as Status;
if (status.RetweetedStatus.StatusID == 0)
{
if (status.ExtendedTweet.FullText != null)
{
Console.WriteLine("Longer than 140 - \"#{0}\": {1} (TweetMode:{2})",
status.User.ScreenNameResponse, status.ExtendedTweet.FullText, status.TweetMode);
}
else
{
Console.WriteLine("Shorter than 140 - \"#{0}\": {1} (TweetMode:{2})",
status.User.ScreenNameResponse, status.Text, status.TweetMode);
}
}
// Console.WriteLine("{0}: {1} {2}", status.StatusID, status.User.ScreenNameResponse, status.Text ?? status.FullText);
break;
default:
Console.WriteLine("Unknown - " + strm.Content + "\n");
break;
}
return await Task.FromResult(0);
}
}

Here are my observations:
status.ExtentendedTweet.FullText should hold the tweet in normal circumstances.
However, if the tweet is retweeted, then status.RetweetedStatus.ExtendedTweet.FullText should hold the tweet.
If you can't find the FullText in either of those circumstances, use status.Text.
I'm updating the sample with the following:
case StreamEntityType.Status:
var status = strm.Entity as Status;
string text = null;
if (status.ExtendedTweet?.FullText != null)
text = status.ExtendedTweet?.FullText;
else if (status.RetweetedStatus?.ExtendedTweet?.FullText != null)
text = status.RetweetedStatus?.ExtendedTweet?.FullText;
else
text = status.Text;
Console.WriteLine("Status - #{0}: {1}", status.User.ScreenNameResponse, text);
break;
Note: Via Twitter documentation (see Standard Streams), TweetMode doesn't apply to streams. Additionally, the docs say the ExtentedTweet should always be there with FullText. As we can see, that isn't the full picture in practice. I'll mark Streaming.TweetMode as obsolete in upcoming releases.

Related

Google Sheets Script Error - Cannot read property '1' of null (line 7)

I'm using the following script to pull data from bulk json files:
function importRegex(url, regexInput) {
var output = '';
var fetchedUrl = UrlFetchApp.fetch(url, {muteHttpExceptions: true});
if (fetchedUrl) {
var html = fetchedUrl.getContentText();
if (html.length && regexInput.length) {
output = html.match(new RegExp(regexInput, 'i'))[1];
}
}
// Grace period to not overload
Utilities.sleep(1000);
return output;
}
Then this formula with the desired URL in E3:
=IMPORTREGEX(E3,"(.*')")
It worked completely fine to begin with, now I'm suddenly getting the error, seemingly without making any changes, any tips?
This error is because of lacking a null check.
You are now using the return value of html.match() whether it is null or not.
So you should check if the return value is null and if it has enough length.
Like this:
if (html.length && regexInput.length) {
let match = html.match(new RegExp(regexInput, 'i'));
if ( match != null && match.length > 1 ){
output = match[1];
}
}

Select no longer highlighting text on iPad (word)

In my add-in we navigate the document by calling select on either a paragraph or a search result from inside a paragraph. In the newest version of Word for iOS : 2.0.2 (170415) the document is scrolling to the correct part of the document but the text is no longer highlighting. This was working in the previous released version of word.
Oddly the text does highlight as expected if i open the search bar, and then navigate around my document.
public SelectTextInstance(text: string, paragraphIndex: number, textInstance: number) {
Word.run(function (context) {
// Create a proxy object for the paragraphs collection.
var paragraphs = context.document.body.paragraphs;
context.load(paragraphs, 'text,font');
return context.sync().then(function () {
if (paragraphIndex == -1) {//currently would occur for items that are inside of tables.
return;
}
var paragraph = paragraphs.items[paragraphIndex];
return context.sync().then(function () {
var ranges = null;
//256 is the maximum length for a search item. Longer than this and we just have to select the paragraph.
if (text != undefined && text != null && text.length <= 256) {
ranges = paragraph.search(text, { matchCase: true, ignoreSpace: true});
context.load(ranges, 'text');
}
return context.sync().then(function () {
if (ranges == null || ranges.items.length == 0) {
paragraph.select();
}
else {
//select the paragraph rather than overflow - something bad happened somewhere, so we'll fall back to highlighting the paragraph.
if (ranges.items.length <= textInstance) {
paragraph.select();
} else {
ranges.items[textInstance].select();
}
}
return context.sync().then(function () {
});
});
});
});
})
.catch(function (error) {
console.log('Error: ' + JSON.stringify(error));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
}
Thanks so much for reporting this. Effectively this is a regression. The range is selected but not colored. We will push the fix for the next update.

Display result matching optgroup using select2

I'm using select2 with Bootstrap 3.
Now I would like to know whether it is possible to display all optgroup items if the search matches the optgroup name while still being able to search for items as well. If this is possible, how can I do it?
The above answers don't seem to work out of the box with Select2 4.0 so if you're hunting for that, check this out: https://github.com/select2/select2/issues/3034
(Use the function like this: $("#example").select2({matcher: modelMatcher});)
function modelMatcher (params, data) {
data.parentText = data.parentText || "";
// Always return the object if there is nothing to compare
if ($.trim(params.term) === '') {
return data;
}
// Do a recursive check for options with children
if (data.children && data.children.length > 0) {
// Clone the data object if there are children
// This is required as we modify the object to remove any non-matches
var match = $.extend(true, {}, data);
// Check each child of the option
for (var c = data.children.length - 1; c >= 0; c--) {
var child = data.children[c];
child.parentText += data.parentText + " " + data.text;
var matches = modelMatcher(params, child);
// If there wasn't a match, remove the object in the array
if (matches == null) {
match.children.splice(c, 1);
}
}
// If any children matched, return the new object
if (match.children.length > 0) {
return match;
}
// If there were no matching children, check just the plain object
return modelMatcher(params, match);
}
// If the typed-in term matches the text of this term, or the text from any
// parent term, then it's a match.
var original = (data.parentText + ' ' + data.text).toUpperCase();
var term = params.term.toUpperCase();
// Check if the text contains the term
if (original.indexOf(term) > -1) {
return data;
}
// If it doesn't contain the term, don't return anything
return null;
}
Actually found the solution by modifying the matcher opt
$("#myselect").select2({
matcher: function(term, text, opt){
return text.toUpperCase().indexOf(term.toUpperCase())>=0 || opt.parent("optgroup").attr("label").toUpperCase().indexOf(term.toUpperCase())>=0
}
});
Under the premise that the label attribute has been set in each optgroup.
Found a solution from select2/issues/3034
Tested with select2 v.4
$("select").select2({
matcher(params, data) {
const originalMatcher = $.fn.select2.defaults.defaults.matcher;
const result = originalMatcher(params, data);
if (
result &&
data.children &&
result.children &&
data.children.length
) {
if (
data.children.length !== result.children.length &&
data.text.toLowerCase().includes(params.term.toLowerCase())
) {
result.children = data.children;
}
return result;
}
return null;
},
});
A few minor changes to people suggested code, less repetitive and copes when there are no parent optgroups:
$('select').select2({
matcher: function(term, text, opt){
var matcher = opt.parent('select').select2.defaults.matcher;
return matcher(term, text) || (opt.parent('optgroup').length && matcher(term, opt.parent('optgroup').attr("label")));
}
});

Why is this iteration of an Outlook Folder only processing a maximum of half the number of items in the folder?

Outlook rules are putting all Facebook originating mail into a Facebook folder, an external process is running as detailed here to separate the contents of that folder in a way that was not feasible through Outlook rules process, originally I had this process running in VBA in outlook but it was a pig choking outlook resources. So I decided to throw it out externally and as I want to improve my c# skill set, this would be a conversion at the same time. Anyway the mail processing is working as it should items are going to correct sub-folders but for some reason the temporary constraint to exit after i number of iterations is not doing as it should. If there are 800 mails in the Facebook folder ( I am a member of many groups) it only runs through 400 iterations, if there are 30 it only processes 15 etc.
I cant for the life of me see why - can anyone put me right?
Thanks
private void PassFBMail()
{
//do something
// result = MsgBox("Are you sure you wish to run the 'Allocate to FB Recipient' process", vbOKCancel, "Hold up")
//If result = Cancel Then Exit Sub
var result = MessageBox.Show("Are you sure you wish to run the Are you sure you wish to run the 'Allocate to SubFolders' process","Sure?",MessageBoxButtons.OKCancel,MessageBoxIcon.Question,MessageBoxDefaultButton.Button2);
if (result == DialogResult.Cancel)
{
return;
}
try
{
OutLook._Application outlookObj = new OutLook.Application();
OutLook.MAPIFolder inbox = (OutLook.MAPIFolder)
outlookObj.Session.GetDefaultFolder(OutLook.OlDefaultFolders.olFolderInbox);
OutLook.MAPIFolder fdr = inbox.Folders["facebook"];
OutLook.MAPIFolder fdrForDeletion = inbox.Folders["_ForDeletion"];
// foreach (OutLook.MAPIFolder fdr in inbox.Folders)
// {
// if (fdr.Name == "facebook")
// {
// break;
// }
// }
//openFacebookFolder Loop through mail
//LOOPING THROUGH MAIL ITEMS IN THAT FOLDER.
Redemption.SafeMailItem sMailItem = new Redemption.SafeMailItem();
int i = 0;
foreach ( Microsoft.Office.Interop.Outlook._MailItem mailItem in fdr.Items.Restrict("[MessageClass] = 'IPM.Note'"))
{
//temp only process 500 mails
i++;
if (i == 501)
{
break;
}
// eml.Item = em
// If eml.To <> "" And eml.ReceivedByName <> "" Then
// strNewFolder = DeriveMailFolder(eml.To, eml.ReceivedByName)
// End If
sMailItem.Item = mailItem;
string strTgtFdr = null;
if (sMailItem.To != null && sMailItem.ReceivedByName != null)
{
strTgtFdr = GetTargetFolder(sMailItem.To, sMailItem.ReceivedByName );
}
// If fdr.Name <> strNewFolder Then
// If dDebug Then DebugPrint "c", "fdr.Name <> strNewFolder"
// eml.Move myInbox.Folders(strNewFolder)
// If dDebug Then DebugPrint "w", "myInbox.Folders(strNewFolder) = " & myInbox.Folders(strNewFolder)
// Else
// eml.Move myInbox.Folders("_ForDeletion")
// End If
if (fdr.Name != strTgtFdr)
{
OutLook.MAPIFolder destFolder = inbox.Folders[strTgtFdr];
mailItem.Move(destFolder);
}
else
{
mailItem.Move(fdrForDeletion);
}
}
//allocate to subfolders
//Process othersGroups
//Likes Max 3 per day per user, max 20% of group posts
//Comments one per day per user, max 10% of group posts
//Shares one per day per user, max 10% of group posts
}
catch(System.Exception crap)
{
OutCrap(crap);
MessageBox.Show("MailCamp experienced an issues while processing the run request and aborted - please review the error log","Errors during the process",MessageBoxButtons.OK,MessageBoxIcon.Error,MessageBoxDefaultButton.Button1);
}
}
Do not use a foreach loop it you are modifying the number of items in the collection.
Loop from MAPIFolder.Items.Count down to 1.

OData Service not returning complete response

I am reading Sharepoint list data (>20000 entries) using Odata RESTful service as detailed here -http://blogs.msdn.com/b/ericwhite/archive/2010/12/09/getting-started-using-the-odata-rest-api-to-query-a-sharepoint-list.aspx
I am able to read data but I get only the first 1000 records. I also checked that List View Throttling is set to 5000 on sharepoint server. Kindly advise.
Update:
#Turker: Your answer is spot on!! Thank you very much. I was able to get the first 2000 records in first iteration. However, I am getting the same records in each iteration of while loop. My code is as follows-
...initial code...
int skipCount =0;
while (((QueryOperationResponse)query).GetContinuation() != null)
{
//query for the next partial set of customers
query = dc.Execute<CATrackingItem>(
((QueryOperationResponse)query).GetContinuation().NextLinkUri
);
//Add the next set of customers to the full list
caList.AddRange(query.ToList());
var results = from d in caList.Skip(skipCount)
select new
{
Actionable = Actionable,
}; Created = d.Created,
foreach (var res in results)
{
structListColumns.Actionable = res.Actionable;
structListColumns.Created= res.Created;
}
skipCount = caList.Count;
}//Close of while loop
Do you see a <link rel="next"> element at the end of the feed?
For example, if you look at
http://services.odata.org/Northwind/Northwind.svc/Customers/
you will see
<link rel="next" href="http://services.odata.org/Northwind/Northwind.svc/Customers/?$skiptoken='ERNSH'" />
at the end of the feed which means the service is implementing server side paging and you need to send the
http://services.odata.org/Northwind/Northwind.svc/Customers/?$skiptoken='ERNSH'
query to get the next set of results.
I don't see anything particularly wrong with your code. You can try to dump the URLs beign requested (either from the code, or using something like fiddler) to see if the client really sends the same queries (and thus getting same responses).
In any case, here is a sample code which does work (using the sample service):
DataServiceContext ctx = new DataServiceContext(new Uri("http://services.odata.org/Northwind/Northwind.svc"));
QueryOperationResponse<Customer> response = (QueryOperationResponse<Customer>)ctx.CreateQuery<Customer>("Customers").Execute();
do
{
foreach (Customer c in response)
{
Console.WriteLine(c.CustomerID);
}
DataServiceQueryContinuation<Customer> continuation = response.GetContinuation();
if (continuation != null)
{
response = ctx.Execute(continuation);
}
else
{
response = null;
}
} while (response != null);
I had the same problem, and wanted it to be a generic solution.
So I've extended DataServiceContext with a GetAlltems methode.
public static List<T> GetAlltems<T>(this DataServiceContext context)
{
return context.GetAlltems<T>(null);
}
public static List<T> GetAlltems<T>(this DataServiceContext context, IQueryable<T> queryable)
{
List<T> allItems = new List<T>();
DataServiceQueryContinuation<T> token = null;
EntitySetAttribute attr = (EntitySetAttribute)typeof(T).GetCustomAttributes(typeof(EntitySetAttribute), false).First();
// Execute the query for all customers and get the response object.
DataServiceQuery<T> query = null;
if (queryable == null)
{
query = context.CreateQuery<T>(attr.EntitySet);
}
else
{
query = (DataServiceQuery<T>) queryable;
}
QueryOperationResponse<T> response = query.Execute() as QueryOperationResponse<T>;
// With a paged response from the service, use a do...while loop
// to enumerate the results before getting the next link.
do
{
// If nextLink is not null, then there is a new page to load.
if (token != null)
{
// Load the new page from the next link URI.
response = context.Execute<T>(token);
}
allItems.AddRange(response);
}
// Get the next link, and continue while there is a next link.
while ((token = response.GetContinuation()) != null);
return allItems;
}

Resources