1 module webapi.feedly;
2 
3 /***
4 	Feedly API Client for the D Programming Language - written 2014 Laeeth Isharc
5 
6 	Pre-alpha stage.  Please report issues on GitHub.
7 
8 		not yet implemented: Microsoft, Facebook
9 
10 	struct FeedlyClient - methods
11 
12 		this(string clientID,string clientSecret)
13 		void setSandbox(bool sandbox)
14 		void setClientID(string clientID)
15 		void setClientToken(string clientToken)
16 		void setClientSecret(string clientSecret)
17 		auto epochTime(DateTime dt)
18 		string getCodeURI(string callbackURI)
19 	    	string authenticateUser(string responseType, string redirectURI, string state)
20 		string getAccessToken(string redirectURI,string code,string state)
21 		string refreshAccessToken(string refreshToken)
22 		string revokeAccessToken(string revokeToken)
23 		string getCategories()
24 		string updateCategoryLabel(string category, string newlabel)
25 		string deleteCategory(string category)
26 		string getFeedMetadata(string feedID)
27 		string getFeedMetadata(string[] feedIDs)
28 		string linkDropbox(string redirectURI, string state)
29 		string unlinkDropbox()
30 		string linkEvernote(string redirectURI, string state)
31 		string unlinkEvernote()
32 		string getEvernoteBookList()
33 		string saveArticleEvernote(string notebookName, string[] tags, string entryID, string notebookType, string notebookGUID,
34 		string getEntry(string entryID)
35 		string getEntries(string[] entryIDs)
36 		string createEntry(string title, string content, bool contentLeftToRight, string summary, bool summaryLeftToRight, 
37 				string[]  enclosure,string[2][] alternate,DateTime crawled, DateTime published, DateTime updated)
38 		string saveArticleDropbox(string entryID)
39 		string getMixes(string streamID, int count, bool unreadOnly, int hours, DateTime newerThan, bool backFill, string locale)
40 		string getOPML()
41 		string postOPML(string opml)
42 		string getPreferences()
43 		string updatePreferences(string[string] preferences)
44 		string getProfile()
45 		string updateProfile(string email, string givenName, string familyName, string picture, bool gender, string locale, string twitter, string facebook)
46 		string searchStreamContent(string streamID, string query)
47 		string getUserSubscriptions()
48 		string subscribeFeed(string ID, string title, string[2][] categories)
49 		string updateSubscription(string ID, string title, string[2][] categories)
50 		string unsubscribeFeed(string ID)
51 	    	string getShortenedURL(string entryID)
52 	    	string getFeedIDs(string streamID, int count, string ranked, bool unreadOnly, DateTime newerThan, int continuation)
53 		string getFeedContent(string streamID, int count, string ranked, bool unreadOnly, DateTime newerThan, int continuation)
54 		string getFeedUnreadCounts(bool autorefresh, DateTime newerThan, string streamID)
55 		string getFeedUnreadCounts(bool autorefresh, string streamID)
56 		string markArticlesAsRead(string[] entryIDs)
57 		string markArticlesAsSaved(string[] entryIDs)
58 		string markArticlesAsUnsaved(string[] entryIDs)
59 		string getLatestRead(DateTime newerThan)
60 		string getLatestTaggedEntries(DateTime newerThan)
61 		string markArticlesAsUnread(string[] entryIDs)
62 		string markFeedAsRead(string feedID, string lastReadEntryID)
63 		string undoMarkFeedsAsRead(string[] feedIDs)
64 		string markCategoriesAsRead(string[] categoryIDs, string lastReadEntryID)
65 		string markCategoriesAsRead(string[] categoryIDs, DateTime asOf)
66 		string undoMarkCategoriesAsRead(string[] categoryIDs)
67 		string saveForLater(string[] entryIDs)
68 		string searchFeeds(string query, int count, string locale)
69 		string getTags()
70 		string addTag(string[] tags, string[] entryIDs)
71 		string changeTagLabel(string tag, string oldLabel, string newLabel)
72 		string unTagEntries(string[] tags, string[] entryIDs)
73 		string deleteTags(string[] tags)
74 		string getTopics()
75 		string addTopic(string topicID, string topicInterest)
76 		string updateTopic(string topicID, string topicInterest)
77 		string deleteTopic(string topicID)
78 		string twitterSuggest1()
79 		string twitterSuggest2(string[] twitterHandles)
80 		string twitterUnlink()
81 		string twitterLink(string redirectURI, string state)
82 	
83 */
84 
85 import std.stdio;
86 import std.conv;
87 import std.exception;
88 import std.string;
89 import std.file;
90 import std.exception;
91 import std.datetime;
92 import vibe.d;
93 import vibe.core.log;
94 import vibe.http.client;
95 import vibe.stream.operations;
96 import vibe.utils.dictionarylist;
97 
98 struct FeedlyClient
99 {
100  
101         	enum baseURLCloud ="cloud.feedly.com";
102         	enum baseURLSandbox="sandbox.feedly.com";
103     	string baseURL=baseURLCloud;
104 
105  	string urlAuth="/v3/auth/auth";
106  	string urlCategories="/v3/categories";
107  	string urlDropbox="/v3/dropbox";
108  	string urlEvernote="/v3/evernote";
109  	string urlEntries="/v3/entries";
110  	string urlFeeds="/v3/feeds";
111  	string urlToken="/v3/auth/token";
112 	string urlMarkers="/v3/markers";
113 	string urlMixes="/v3/mixes";
114 	string urlOPML="/v3/opml";
115 	string urlPreferences="/v3/preferences";
116 	string urlProfile="/v3/profile";
117 	string urlSaveForLater="/v3/tags/user%2F";
118 	string urlSearchStream="/v3/search";
119 	string urlSearchFeeds="/v3/search/feeds";
120 	string urlStreams="/v3/streams";
121 	string urlShorten = "/v3/shorten/entries";
122 	string urlSubscriptions = "/v3/subscriptions";
123 	string urlTags="/v3/tags";
124 	string urlTopics="/v3/topics";
125 
126 	string urlTwitterAuth="/v3/twitter/auth";
127 	string urlTwitterSuggest1="/v3/twitter/suggestions";
128 	string urlTwitterSuggest2="/v3/twitter/feeds/.mget";
129 
130 	string clientID;
131 	string clientSecret;
132 	string clientToken;
133 	bool sandbox=false;
134 
135 	this(string clientID,string clientSecret)
136 	{
137 		this.clientID=clientID;
138 		this.clientSecret=clientSecret;
139 	}
140 
141 	void setSandbox(bool sandbox)
142 	{
143 		this.sandbox=sandbox;
144 		if (sandbox)
145 			baseURL=baseURLSandbox;
146 		else
147 			baseURL=baseURLCloud;
148 	}
149 
150 	void setClientID(string clientID)
151 	{
152 		this.clientID=clientID;
153 	}
154 	void setClientToken(string clientToken)
155 	{
156 		this.clientToken=clientToken;
157 	}
158 	void setClientSecret(string clientSecret)
159 	{
160 		this.clientSecret=clientSecret;
161 	}
162 
163 	
164 	auto epochTime(DateTime dt)
165 	{
166 		return SysTime(dt).toUnixTime();
167 	}
168 
169 	string getCodeURI(string callbackURI)
170 	{
171 		return(format("%s?client_id=%s&redirect_uri=%s&scope=%s&response_type=%s",
172 			"https://" ~ urlAuth,this.clientID,callbackURI,"https://"~urlSubscriptions,"code"));
173 	}
174 	
175     	string authenticateUser(string responseType, string redirectURI, string state)
176 	{
177 		string url="https://"~baseURL~urlAuth;
178 		auto jsonparam=Json.emptyObject;
179 		if (responseType.length==0)
180 			jsonparam.responseType="code";
181 		else
182 			jsonparam.responseType=responseType;
183 		jsonparam.clientID=this.clientID;
184 		jsonparam.redirectURI=redirectURI;
185 		jsonparam.state=state;
186 		jsonparam["scope"]=urlSubscriptions;
187 
188 		string ret;
189 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
190 		requestHTTP(url,
191 			(scope req)
192 			{
193 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
194 				req.method = HTTPMethod.GET;
195 				req.bodyWriter.write(jsonbody);
196 			},
197 			(scope res)
198 			{
199 				ret~= to!string(res.bodyReader.readAllUTF8());
200 			}
201 		);
202 		return ret;
203 	}
204     
205 	string getAccessToken(string redirectURI,string code,string state)
206 	{
207 		string url="https://"~baseURL~urlToken;
208 		auto jsonparam=Json.emptyObject;
209 		jsonparam.client_id=this.clientID;
210 		jsonparam.client_secret=this.clientSecret;
211 		jsonparam.grant_type="authorization_code";
212 		jsonparam.redirect_uri=redirectURI;
213 		jsonparam.code=code;
214 		if (state.length>0)
215 			jsonparam.state=state;
216 
217 		string ret;
218 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
219 		requestHTTP(url,
220 			(scope req)
221 			{
222 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
223 				req.method = HTTPMethod.POST;
224 				req.bodyWriter.write(jsonbody);
225 			},
226 			(scope res)
227 			{
228 				ret~= to!string(res.bodyReader.readAllUTF8());
229 			}
230 		);
231 		return ret;
232 	}
233     
234         	// obtain a new access token by sending a refresh token to the feedly Authorization server
235         	// return contents of a feed
236 	string refreshAccessToken(string refreshToken)
237 	{
238 		string url="https://"~baseURL~urlToken;
239 		auto jsonparam=Json.emptyObject;
240 		jsonparam.refresh_token=refreshToken;
241 		jsonparam.client_id=this.clientID;
242 		jsonparam.client_secret=this.clientSecret;
243 		jsonparam.grant_type="refresh_token";
244 
245 		
246 		string ret;
247 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
248 		requestHTTP(url,
249 			(scope req)
250 			{
251 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
252 				
253 				req.method = HTTPMethod.POST;
254 				req.bodyWriter.write(jsonbody);
255 			},
256 			(scope res)
257 			{
258 				ret~= to!string(res.bodyReader.readAllUTF8());
259 			}
260 		);
261 		return ret;
262 	}
263 
264 	string revokeAccessToken(string revokeToken)
265 	{
266 		string url="https://"~baseURL~urlToken;
267 		auto jsonparam=Json.emptyObject;
268 		jsonparam.refresh_token=revokeToken;
269 		jsonparam.client_id=this.clientID;
270 		jsonparam.client_secret=this.clientSecret;
271 		jsonparam.grant_type="revoke_token";
272 
273 		
274 		string ret;
275 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
276 		requestHTTP(url,
277 			(scope req)
278 			{
279 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
280  				req.method = HTTPMethod.POST;
281 				req.bodyWriter.write(jsonbody);
282 			},
283 			(scope res)
284 			{
285 				ret~= to!string(res.bodyReader.readAllUTF8());
286 			}
287 		);
288 		return ret;
289 	}
290 
291 	string getCategories()
292 	{
293 		string url="https://"~baseURL~urlCategories;
294 		
295 		string ret;
296 		auto jsonbody="";
297 		requestHTTP(url,
298 			(scope req)
299 			{
300 				req.contentType="application/json; charset=UTF8";
301 				req.headers["Authorization"]="OAuth "~this.clientToken;
302 				req.method = HTTPMethod.GET;
303 				req.bodyWriter.write(jsonbody);
304 			},
305 			(scope res)
306 			{
307 				ret~= to!string(res.bodyReader.readAllUTF8());
308 			}
309 		);
310 		return ret;
311 	}
312 
313 	string updateCategoryLabel(string category, string newlabel)
314 	{
315 		string url="https://"~baseURL~urlCategories~"/"~category;
316 		auto jsonparam=Json.emptyObject;
317 
318 		
319 		jsonparam.label=newlabel;
320 		string ret;
321 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
322 		requestHTTP(url,
323 			(scope req)
324 			{
325 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
326 				
327 				req.method = HTTPMethod.POST;
328 				req.bodyWriter.write(jsonbody);
329 			},
330 			(scope res)
331 			{
332 				ret~= to!string(res.bodyReader.readAllUTF8());
333 			}
334 		);
335 		return ret;
336 	}
337 
338 	string deleteCategory(string category)
339 	{
340 		string url="https://"~baseURL~urlCategories~"/"~category;
341 		auto jsonparam=Json.emptyObject;
342 
343 		
344 		string ret;
345 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
346 		requestHTTP(url,
347 			(scope req)
348 			{
349 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
350 				
351 				req.method = HTTPMethod.DELETE;
352 				req.bodyWriter.write(jsonbody);
353 			},
354 			(scope res)
355 			{
356 				ret~= to!string(res.bodyReader.readAllUTF8());
357 			}
358 		);
359 		return ret;
360 	}
361 	
362 	string getFeedMetadata(string feedID)
363 	{
364 		string url="https://"~baseURL~urlFeeds~"/"~feedID;
365 		auto jsonparam=Json.emptyObject;
366 
367 		
368 		string ret;
369 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
370 		requestHTTP(url,
371 			(scope req)
372 			{
373 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
374 				
375 				req.method = HTTPMethod.POST;
376 				req.bodyWriter.write(jsonbody);
377 			},
378 			(scope res)
379 			{
380 				ret~= to!string(res.bodyReader.readAllUTF8());
381 			}
382 		);
383 		return ret;
384 	}
385 
386 	string getFeedMetadata(string[] feedIDs)
387 	{
388 		string url="https://"~baseURL~urlFeeds~"/.mget";
389 		auto jsonparam=serializeToJson(feedIDs);
390 		string ret;
391 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
392 		requestHTTP(url,
393 			(scope req)
394 			{
395 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
396 				
397 				req.method = HTTPMethod.POST;
398 				req.bodyWriter.write(jsonbody);
399 			},
400 			(scope res)
401 			{
402 				ret~= to!string(res.bodyReader.readAllUTF8());
403 			}
404 		);
405 		return ret;
406 	}
407 	string linkDropbox(string redirectURI, string state)
408 	{
409 		string url="https://"~baseURL~urlDropbox ~ "/auth";
410 		auto jsonparam=Json.emptyObject;
411 
412 		
413 		jsonparam.redirectUri=redirectURI;
414 		if (state.length>0)
415 			jsonparam.state=state;
416 		string ret;
417 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
418 		requestHTTP(url,
419 			(scope req)
420 			{
421 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
422 				
423 				req.method = HTTPMethod.GET;
424 				req.bodyWriter.write(jsonbody);
425 			},
426 			(scope res)
427 			{
428 				ret~= to!string(res.bodyReader.readAllUTF8());
429 			}
430 		);
431 		return ret;
432 	}
433 
434 	string unlinkDropbox()
435 	{
436 		string url="https://"~baseURL~urlDropbox ~ "/auth";
437 		auto jsonparam=Json.emptyObject;
438 
439 		
440 		string ret;
441 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
442 		requestHTTP(url,
443 			(scope req)
444 			{
445 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
446 				
447 				req.method = HTTPMethod.DELETE;
448 				req.bodyWriter.write(jsonbody);
449 			},
450 			(scope res)
451 			{
452 				ret~= to!string(res.bodyReader.readAllUTF8());
453 			}
454 		);
455 		return ret;
456 	}
457 
458 
459 	string linkEvernote(string redirectURI, string state)
460 	{
461 		string url="https://"~baseURL~urlEvernote ~ "/auth";
462 		auto jsonparam=Json.emptyObject;
463 
464 		
465 		jsonparam.redirectUri=redirectURI;
466 		if (state.length>0)
467 			jsonparam.state=state;
468 		string ret;
469 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
470 		requestHTTP(url,
471 			(scope req)
472 			{
473 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
474 				
475 				req.method = HTTPMethod.GET;
476 				req.bodyWriter.write(jsonbody);
477 			},
478 			(scope res)
479 			{
480 				ret~= to!string(res.bodyReader.readAllUTF8());
481 			}
482 		);
483 		return ret;
484 	}
485 
486 	string unlinkEvernote()
487 	{
488 		string url="https://"~baseURL~urlEvernote ~ "/auth";
489 		auto jsonparam=Json.emptyObject;
490 
491 		
492 		string ret;
493 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
494 		requestHTTP(url,
495 			(scope req)
496 			{
497 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
498 				
499 				req.method = HTTPMethod.DELETE;
500 				req.bodyWriter.write(jsonbody);
501 			},
502 			(scope res)
503 			{
504 				ret~= to!string(res.bodyReader.readAllUTF8());
505 			}
506 		);
507 		return ret;
508 	}
509 
510 	string getEvernoteBookList()
511 	{
512 		string url="https://"~baseURL~urlEvernote ~ "/notebooks";
513 		auto jsonparam=Json.emptyObject;
514 
515 		
516 		string ret;
517 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
518 		requestHTTP(url,
519 			(scope req)
520 			{
521 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
522 				
523 				req.method = HTTPMethod.GET;
524 				req.bodyWriter.write(jsonbody);
525 			},
526 			(scope res)
527 			{
528 				ret~= to!string(res.bodyReader.readAllUTF8());
529 			}
530 		);
531 		return ret;
532 	}
533 
534 	string saveArticleEvernote(string notebookName, string[] tags, string entryID, string notebookType, string notebookGUID,
535 															string comment)
536 	{
537 		string url="https://"~baseURL~urlEvernote ~ "/note";
538 		auto jsonparam=Json.emptyObject;
539 		jsonparam.notebookName=notebookName;
540 		jsonparam.tags=serializeToJson(tags);
541 		jsonparam.entryID=entryID;
542 		jsonparam.notebookType=notebookType;
543 		jsonparam.notebookGUID=notebookGUID;
544 		jsonparam.comment=comment;
545 		
546 		
547 		string ret;
548 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
549 		requestHTTP(url,
550 			(scope req)
551 			{
552 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
553 				
554 				req.method = HTTPMethod.POST;
555 				req.bodyWriter.write(jsonbody);
556 			},
557 			(scope res)
558 			{
559 				ret~= to!string(res.bodyReader.readAllUTF8());
560 			}
561 		);
562 		return ret;
563 	}
564 	
565 
566 	string getEntry(string entryID)
567 	{
568 		string url="https://"~baseURL~urlEntries ~ "/"~entryID;
569 		auto jsonparam=Json.emptyObject;
570 
571 		
572 		string ret;
573 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
574 		requestHTTP(url,
575 			(scope req)
576 			{
577 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
578 				
579 				req.method = HTTPMethod.GET;
580 				req.bodyWriter.write(jsonbody);
581 			},
582 			(scope res)
583 			{
584 				ret~= to!string(res.bodyReader.readAllUTF8());
585 			}
586 		);
587 		return ret;
588 	}
589 	
590 	string getEntries(string[] entryIDs)
591 	{
592 		string url="https://"~baseURL~urlEntries ~ "/"~".mget";
593 		auto jsonparam=Json.emptyArray;
594 		jsonparam.appendArrayElement(serializeToJson(entryIDs));
595 		
596 		string ret;
597 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
598 		requestHTTP(url,
599 			(scope req)
600 			{
601 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
602 				
603 				req.method = HTTPMethod.POST;
604 				req.bodyWriter.write(jsonbody);
605 			},
606 			(scope res)
607 			{
608 				ret~= to!string(res.bodyReader.readAllUTF8());
609 			}
610 		);
611 		return ret;
612 	}
613 	
614 	string createEntry(string title, string content, bool contentLeftToRight, string summary, bool summaryLeftToRight, 
615 			string[]  enclosure,string[2][] alternate,DateTime crawled, DateTime published, DateTime updated)
616 	{
617 		string url="https://"~baseURL~urlEntries;
618 		auto jsonparam=Json.emptyArray;
619 		jsonparam.title=title;
620 		auto jsonContent=Json.emptyObject;
621 		jsonContent.direction=contentLeftToRight?"ltr":"rtl";
622 		jsonparam.content=jsonContent;
623 		auto jsonparamSummary=Json.emptyObject;
624 		jsonparamSummary.direction=summaryLeftToRight?"ltr":"rtl";
625 		jsonparamSummary.content=summary;
626 		jsonparam.summary=jsonparamSummary;
627 		jsonparam.enclosure=serializeToJson(enclosure);
628 		jsonparam.alternate=serializeToJson(alternate);
629 		jsonparam.crawled=serializeToJson(epochTime(crawled));
630 		jsonparam.published=serializeToJson(epochTime(published));
631 		jsonparam.updated=serializeToJson(epochTime(updated));
632 
633 		
634 		string ret;
635 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
636 		requestHTTP(url,
637 			(scope req)
638 			{
639 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
640 				
641 				req.method = HTTPMethod.POST;
642 				req.bodyWriter.write(jsonbody);
643 			},
644 			(scope res)
645 			{
646 				ret~= to!string(res.bodyReader.readAllUTF8());
647 			}
648 		);
649 		return ret;
650 	}
651 
652 
653 	
654 	string saveArticleDropbox(string entryID)
655 	{
656 		string url="https://"~baseURL~urlDropbox ~ "/save";
657 		auto jsonparam=Json.emptyObject;
658 		jsonparam.entryID=entryID;
659 
660 		
661 		string ret;
662 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
663 		requestHTTP(url,
664 			(scope req)
665 			{
666 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
667 				
668 				req.method = HTTPMethod.POST;
669 				req.bodyWriter.write(jsonbody);
670 			},
671 			(scope res)
672 			{
673 				ret~= to!string(res.bodyReader.readAllUTF8());
674 			}
675 		);
676 		return ret;
677 	}
678 	string getMixes(string streamID, int count, bool unreadOnly, int hours, DateTime newerThan, bool backFill, string locale)
679 	{
680 		string url="https://"~baseURL~urlOPML~"/"~streamID~"/contents";
681 		auto jsonparam=Json.emptyObject;
682 		
683 		if (count>=0)
684 			jsonparam.count=count;
685 		jsonparam.unreadOnly=unreadOnly;
686 		if (hours>=0)
687 			jsonparam.hours=hours;
688 		jsonparam.backFill=backFill;
689 		jsonparam.newerThan=serializeToJson(epochTime(newerThan));
690 		if (locale.length>0)
691 			jsonparam.locale=locale;
692 
693 		string ret;
694 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
695 		requestHTTP(url,
696 			(scope req)
697 			{
698 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
699 				
700 				req.method = HTTPMethod.GET;
701 				req.bodyWriter.write(jsonbody);
702 			},
703 			(scope res)
704 			{
705 				ret~= to!string(res.bodyReader.readAllUTF8());
706 			}
707 		);
708 		return ret;
709 	}
710 
711 	string getOPML()
712 	{
713 		string url="https://"~baseURL~urlOPML;
714 		string ret;
715 		auto jsonbody="";
716 		requestHTTP(url,
717 			(scope req)
718 			{
719 				req.contentType="application/json; charset=UTF8";
720 				req.headers["Authorization"]="OAuth "~this.clientToken;
721 				req.method = HTTPMethod.GET;
722 				req.bodyWriter.write(jsonbody);
723 			},
724 			(scope res)
725 			{
726 				ret~= to!string(res.bodyReader.readAllUTF8());
727 			}
728 		);
729 		return ret;
730 	}
731 
732 	string postOPML(string opml)
733 	{
734 		string url="https://"~baseURL~urlOPML;
735 		string ret;
736 		requestHTTP(url,
737 			(scope req)
738 			{
739 				req.contentType="text/xml; charset=UTF8";
740 				req.method = HTTPMethod.POST;
741 				req.bodyWriter.write(opml);
742 			},
743 			(scope res)
744 			{
745 				ret~= to!string(res.bodyReader.readAllUTF8());
746 			}
747 		);
748 		return ret;
749 	}
750 
751 	string getPreferences()
752 	{
753 		string url="https://"~baseURL~urlPreferences;
754 		auto jsonparam=Json.emptyObject;
755 		
756 		string ret;
757 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
758 		requestHTTP(url,
759 			(scope req)
760 			{
761 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
762 				
763 				req.method = HTTPMethod.GET;
764 				req.bodyWriter.write(jsonbody);
765 			},
766 			(scope res)
767 			{
768 				ret~= to!string(res.bodyReader.readAllUTF8());
769 			}
770 		);
771 		return ret;
772 	}
773 
774 	string updatePreferences(string[string] preferences)
775 	{
776 		string url="https://"~baseURL~urlPreferences;
777 		auto jsonparam=Json.emptyObject;
778 		
779 		foreach(preference;preferences.keys)
780 		{
781 			jsonparam.preferences=preferences[preference];
782 		}
783 		string ret;
784 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
785 		requestHTTP(url,
786 			(scope req)
787 			{
788 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
789 				
790 				req.method = HTTPMethod.POST;
791 				req.bodyWriter.write(jsonbody);
792 			},
793 			(scope res)
794 			{
795 				ret~= to!string(res.bodyReader.readAllUTF8());
796 			}
797 		);
798 		return ret;
799 	}
800 
801 
802 	string getProfile()
803 	{
804 		string url="https://"~baseURL~urlProfile;
805 		auto jsonparam=Json.emptyObject;
806 		
807 		string ret;
808 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
809 		requestHTTP(url,
810 			(scope req)
811 			{
812 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
813 				
814 				req.method = HTTPMethod.GET;
815 				req.bodyWriter.write(jsonbody);
816 			},
817 			(scope res)
818 			{
819 				ret~= to!string(res.bodyReader.readAllUTF8());
820 			}
821 		);
822 		return ret;
823 	}
824 
825 	string updateProfile(string email, string givenName, string familyName, string picture, bool gender, string locale, string twitter, string facebook)
826 	{
827 		string url="https://"~baseURL~urlProfile;
828 		auto jsonparam=Json.emptyObject;
829 		
830 		
831 		if (email.length>0)
832 			jsonparam.email=email;
833 		if (givenName.length>0)
834 			jsonparam.givenName=givenName;
835 		if (familyName.length>0)
836 			jsonparam.familyName=familyName;
837 		if (picture.length>0)
838 			jsonparam.picture=picture;
839 		jsonparam.gender=gender;
840 		if (locale.length>0)
841 			jsonparam["locale"]=locale;
842 		if (twitter.length>0)
843 			jsonparam["twitter"]=twitter;
844 		if (facebook.length>0)
845 			jsonparam["facebook"]=facebook;
846 
847 		string ret;
848 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
849 		requestHTTP(url,
850 			(scope req)
851 			{
852 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
853 				
854 				req.method = HTTPMethod.POST;
855 				req.bodyWriter.write(jsonbody);
856 			},
857 			(scope res)
858 			{
859 				ret~= to!string(res.bodyReader.readAllUTF8());
860 			}
861 		);
862 		return ret;
863 	}
864 
865 
866 
867         	// return contents of a feed
868 	string searchStreamContent(string streamID, string query)
869 	{
870 		string url="https://"~baseURL~urlSearchStream ~streamID ~"/contents?query="~query;
871 		auto jsonparam=Json.emptyObject;
872 		
873 		string ret;
874 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
875 		requestHTTP(url,
876 			(scope req)
877 			{
878 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
879 				
880 				req.method = HTTPMethod.GET;
881 				req.bodyWriter.write(jsonbody);
882 			},
883 			(scope res)
884 			{
885 				ret~= to!string(res.bodyReader.readAllUTF8());
886 			}
887 		);
888 		return ret;
889 	}
890 
891         	// return contents of a feed
892 	string getUserSubscriptions()
893 	{
894 		string url="https://"~baseURL~urlSubscriptions;
895 		auto jsonparam=Json.emptyObject;
896 		
897 		string ret;
898 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
899 		requestHTTP(url,
900 			(scope req)
901 			{
902 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
903 				
904 				req.method = HTTPMethod.GET;
905 				req.bodyWriter.write(jsonbody);
906 			},
907 			(scope res)
908 			{
909 				ret~= to!string(res.bodyReader.readAllUTF8());
910 			}
911 		);
912 		return ret;
913 	}
914 
915 	string subscribeFeed(string ID, string title, string[2][] categories)
916 	{
917 		string url="https://"~baseURL~urlSubscriptions;
918 		auto jsonparam=Json.emptyObject;
919 		
920 		if (title.length>0)
921 			jsonparam.title=title;
922 		jsonparam.id=ID;
923 		if (categories.length>0)
924 		{
925 			auto jsonCategories=Json.emptyArray;
926 			foreach(category;categories)
927 			{
928 				auto jsonCategory=Json.emptyObject;
929 				jsonCategory["id"]=serializeToJson(category[0]);
930 				jsonCategory["label"]=serializeToJson(category[1]);
931 				jsonCategories.appendArrayElement(jsonCategory);
932 			}
933 			jsonparam["categories"]=jsonCategories;
934 		}
935 
936 		string ret;
937 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
938 		requestHTTP(url,
939 			(scope req)
940 			{
941 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
942 				
943 				req.method = HTTPMethod.POST;
944 				req.bodyWriter.write(jsonbody);
945 			},
946 			(scope res)
947 			{
948 				ret~= to!string(res.bodyReader.readAllUTF8());
949 			}
950 		);
951 		return ret;
952 	}
953 
954 	string updateSubscription(string ID, string title, string[2][] categories)
955 	{
956 		return subscribeFeed(ID,title,categories);
957 	}
958 
959 	string unsubscribeFeed(string ID)
960 	{
961 		string url="https://"~baseURL~urlSubscriptions ~"/"~ID;
962 		auto jsonparam=Json.emptyObject;
963 		
964 
965 		string ret;
966 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
967 		requestHTTP(url,
968 			(scope req)
969 			{
970 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
971 				
972 				req.method = HTTPMethod.DELETE;
973 				req.bodyWriter.write(jsonbody);
974 			},
975 			(scope res)
976 			{
977 				ret~= to!string(res.bodyReader.readAllUTF8());
978 			}
979 		);
980 		return ret;
981 	}
982 
983     	string getShortenedURL(string entryID)
984     	{
985     		string url="https://"~baseURL~urlShorten~"/"~entryID;
986 		auto jsonparam=Json.emptyObject;
987 		
988 		string ret;
989 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
990 		requestHTTP(url,
991 			(scope req)
992 			{
993 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
994 				
995 				req.method = HTTPMethod.GET;
996 				req.bodyWriter.write(jsonbody);
997 			},
998 			(scope res)
999 			{
1000 				ret~= to!string(res.bodyReader.readAllUTF8());
1001 			}
1002 		);
1003 		return ret;
1004 	}
1005 
1006     	string getFeedIDs(string streamID, int count, string ranked, bool unreadOnly, DateTime newerThan, int continuation)
1007     	{
1008     		string url="https://"~baseURL~urlStreams~"/"~streamID~"/ids";
1009 		auto jsonparam=Json.emptyObject;
1010 		if (count>=0)
1011 			jsonparam.count=serializeToJson(count);
1012 		if (ranked.length>0)
1013 			jsonparam.ranked=serializeToJson(ranked);
1014 		jsonparam.newerThan=serializeToJson(epochTime(newerThan));
1015 		jsonparam.unreadOnly=unreadOnly;
1016 		if (continuation>0)
1017 			jsonparam.continuation=continuation;
1018 
1019 		
1020 		string ret;
1021 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1022 		requestHTTP(url,
1023 			(scope req)
1024 			{
1025 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1026 				
1027 				req.method = HTTPMethod.GET;
1028 				req.bodyWriter.write(jsonbody);
1029 			},
1030 			(scope res)
1031 			{
1032 				ret~= to!string(res.bodyReader.readAllUTF8());
1033 			}
1034 		);
1035 		return ret;
1036 	}
1037 
1038         	// return contents of a feed
1039     	
1040 	string getFeedContent(string streamID, int count, string ranked, bool unreadOnly, DateTime newerThan, int continuation)
1041 	{
1042 		string url="https://"~baseURL~urlStreams~"/content";
1043 		auto jsonparam=Json.emptyObject;
1044 		jsonparam.streamID=streamID;
1045 		if (count>=0)
1046 			jsonparam.count=count;
1047 		if (ranked.length>0)
1048 			jsonparam.ranked=ranked;
1049 		jsonparam.newerThan=serializeToJson(epochTime(newerThan));
1050 		jsonparam.unreadOnly=unreadOnly;
1051 		if (continuation>0)
1052 			jsonparam.continuation=continuation;
1053 
1054 		
1055 		string ret;
1056 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1057 		requestHTTP(url,
1058 			(scope req)
1059 			{
1060 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1061 				
1062 				req.method = HTTPMethod.GET;
1063 				req.bodyWriter.write(jsonbody);
1064 			},
1065 			(scope res)
1066 			{
1067 				ret~= to!string(res.bodyReader.readAllUTF8());
1068 			}
1069 		);
1070 		return ret;
1071 	}
1072 
1073 
1074 
1075 	string getFeedUnreadCounts(bool autorefresh, DateTime newerThan, string streamID)
1076 	{
1077 		string url="https://"~baseURL~urlMarkers;
1078 		auto jsonparam=Json.emptyObject;
1079 		jsonparam.autorefresh=autorefresh;
1080 		jsonparam.newerThan=serializeToJson(epochTime(newerThan));
1081 		if (streamID.length>0)
1082 			jsonparam.streamID=streamID;
1083 		
1084 		string ret;
1085 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1086 		requestHTTP(url,
1087 			(scope req)
1088 			{
1089 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1090 				
1091 				req.method = HTTPMethod.GET;
1092 				req.bodyWriter.write(jsonbody);
1093 			},
1094 			(scope res)
1095 			{
1096 				ret~= to!string(res.bodyReader.readAllUTF8());
1097 			}
1098 		);
1099 		return ret;
1100 	}
1101 
1102 	string getFeedUnreadCounts(bool autorefresh, string streamID)
1103 	{
1104 		string url="https://"~baseURL~urlMarkers;
1105 		auto jsonparam=Json.emptyObject;
1106 		jsonparam.autorefresh=autorefresh;
1107 		if (streamID.length>0)
1108 			jsonparam.streamID=streamID;
1109 		
1110 		string ret;
1111 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1112 		requestHTTP(url,
1113 			(scope req)
1114 			{
1115 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1116 				
1117 				req.method = HTTPMethod.GET;
1118 				req.bodyWriter.write(jsonbody);
1119 			},
1120 			(scope res)
1121 			{
1122 				ret~= to!string(res.bodyReader.readAllUTF8());
1123 			}
1124 		);
1125 		return ret;
1126 	}
1127 
1128 	// Mark one or multiple articles as read''
1129 
1130 	string markArticlesAsRead(string[] entryIDs)
1131 	{
1132 		string url="https://"~baseURL~urlMarkers;
1133 		auto jsonparam=Json.emptyObject;
1134 		jsonparam.action=serializeToJson("markAsRead");
1135 		jsonparam["type"]=serializeToJson("entries");
1136 		jsonparam.Authorization=serializeToJson("OAuth "~clientToken);
1137 		string ret;
1138 		auto jsonIDs=Json.emptyArray;
1139 		jsonparam.entryIds=serializeToJson(entryIDs);
1140 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1141 		requestHTTP(url,
1142 			(scope req)
1143 			{
1144 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1145 				
1146 				req.method = HTTPMethod.POST;
1147 				req.bodyWriter.write(jsonbody);
1148 			},
1149 			(scope res)
1150 			{
1151 				ret~= to!string(res.bodyReader.readAllUTF8());
1152 			}
1153 		);
1154 		return ret;
1155 	}
1156     
1157 	string markArticlesAsSaved(string[] entryIDs)
1158 	{
1159 		string url="https://"~baseURL~urlMarkers;
1160 		auto jsonparam=Json.emptyObject;
1161 		jsonparam.action="markAsSaved";
1162 		jsonparam["type"]="entries";
1163 		
1164 		string ret;
1165 		auto jsonIDs=Json.emptyArray;
1166 		jsonparam.entryIds=serializeToJson(entryIDs);
1167 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1168 		requestHTTP(url,
1169 			(scope req)
1170 			{
1171 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1172 				
1173 				req.method = HTTPMethod.POST;
1174 				req.bodyWriter.write(jsonbody);
1175 			},
1176 			(scope res)
1177 			{
1178 				ret~= to!string(res.bodyReader.readAllUTF8());
1179 			}
1180 		);
1181 		return ret;
1182 	}
1183 	
1184 	string markArticlesAsUnsaved(string[] entryIDs)
1185 	{
1186 		string url="https://"~baseURL~urlMarkers;
1187 		auto jsonparam=Json.emptyObject;
1188 		jsonparam.action="markAsUnsaved";
1189 		jsonparam["type"]="entries";
1190 		
1191 		string ret;
1192 		auto jsonIDs=Json.emptyArray;
1193 		jsonparam.entryIds=serializeToJson(entryIDs);
1194 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1195 		requestHTTP(url,
1196 			(scope req)
1197 			{
1198 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1199 				
1200 				req.method = HTTPMethod.POST;
1201 				req.bodyWriter.write(jsonbody);
1202 			},
1203 			(scope res)
1204 			{
1205 				ret~= to!string(res.bodyReader.readAllUTF8());
1206 			}
1207 		);
1208 		return ret;
1209 	}
1210 
1211 	string getLatestRead(DateTime newerThan)
1212 	{
1213 		string url="https://"~baseURL~urlMarkers~"/reads";
1214 		auto jsonparam=Json.emptyObject;
1215 		jsonparam.newerThan=serializeToJson(epochTime(newerThan));
1216 		
1217 		string ret;
1218 		auto jsonIDs=Json.emptyArray;
1219 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1220 		requestHTTP(url,
1221 			(scope req)
1222 			{
1223 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1224 				
1225 				req.method = HTTPMethod.GET;
1226 				req.bodyWriter.write(jsonbody);
1227 			},
1228 			(scope res)
1229 			{
1230 				ret~= to!string(res.bodyReader.readAllUTF8());
1231 			}
1232 		);
1233 		return ret;
1234 	}
1235 
1236 	string getLatestTaggedEntries(DateTime newerThan)
1237 	{
1238 		string url="https://"~baseURL~urlMarkers~"/tags";
1239 		auto jsonparam=Json.emptyObject;
1240 		jsonparam.newerThan=serializeToJson(epochTime(newerThan));
1241 		
1242 		string ret;
1243 		auto jsonIDs=Json.emptyArray;
1244 
1245 		jsonparam.entryIds=jsonIDs;
1246 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1247 		requestHTTP(url,
1248 			(scope req)
1249 			{
1250 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1251 				
1252 				req.method = HTTPMethod.GET;
1253 				req.bodyWriter.write(jsonbody);
1254 			},
1255 			(scope res)
1256 			{
1257 				ret~= to!string(res.bodyReader.readAllUTF8());
1258 			}
1259 		);
1260 		return ret;
1261 	}
1262 			
1263 
1264 	string markArticlesAsUnread(string[] entryIDs)
1265 	{
1266 		string url="https://"~baseURL~urlMarkers;
1267 		auto jsonparam=Json.emptyObject;
1268 		jsonparam.action="keepUnread";
1269 		jsonparam["type"]="entries";
1270 		
1271 		string ret;
1272 		auto jsonIDs=Json.emptyArray;
1273 		jsonparam.entryIds=serializeToJson(entryIDs);
1274 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1275 		requestHTTP(url,
1276 			(scope req)
1277 			{
1278 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1279 				
1280 				req.method = HTTPMethod.POST;
1281 				req.bodyWriter.write(jsonbody);
1282 			},
1283 			(scope res)
1284 			{
1285 				ret~= to!string(res.bodyReader.readAllUTF8());
1286 			}
1287 		);
1288 		return ret;
1289 	}
1290     
1291 	string markFeedAsRead(string feedID, string lastReadEntryID)
1292 	{
1293 		string url="https://"~baseURL~urlMarkers;
1294 		auto jsonparam=Json.emptyObject;
1295 		jsonparam.action="markAsRead";
1296 		jsonparam["type"]="feeds";
1297 		jsonparam.lastReadEntryID=lastReadEntryID;
1298 		auto jsonFeed=Json.emptyArray;
1299 		jsonFeed.appendArrayElement(serializeToJson(feedID));
1300 		jsonparam.feedIds=jsonFeed;
1301 
1302 		
1303 		string ret;
1304 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1305 		requestHTTP(url,
1306 			(scope req)
1307 			{
1308 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1309 				
1310 				req.method = HTTPMethod.POST;
1311 				req.bodyWriter.write(jsonbody);
1312 			},
1313 			(scope res)
1314 			{
1315 				ret~= to!string(res.bodyReader.readAllUTF8());
1316 			}
1317 		);
1318 		return ret;
1319 	}
1320 
1321 	string undoMarkFeedsAsRead(string[] feedIDs)
1322 	{
1323 		string url="https://"~baseURL~urlMarkers;
1324 		auto jsonparam=Json.emptyObject;
1325 		jsonparam.action="undoMarkAsRead";
1326 		jsonparam["type"]="feeds";
1327 		jsonparam.feddIds=serializeToJson(feedIDs);
1328 		
1329 		string ret;
1330 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1331 		requestHTTP(url,
1332 			(scope req)
1333 			{
1334 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1335 				
1336 				req.method = HTTPMethod.POST;
1337 				req.bodyWriter.write(jsonbody);
1338 			},
1339 			(scope res)
1340 			{
1341 				ret~= to!string(res.bodyReader.readAllUTF8());
1342 			}
1343 		);
1344 		return ret;
1345 	}
1346 
1347 	string markCategoriesAsRead(string[] categoryIDs, string lastReadEntryID)
1348 	{
1349 		string url="https://"~baseURL~urlMarkers;
1350 		auto jsonparam=Json.emptyObject;
1351 		jsonparam.action="markAsRead";
1352 		jsonparam["type"]="categories";
1353 		jsonparam.lastReadEntryID=lastReadEntryID;
1354 		jsonparam.categoryIds=serializeToJson(categoryIDs);
1355 		
1356 		string ret;
1357 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1358 		requestHTTP(url,
1359 			(scope req)
1360 			{
1361 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1362 				
1363 				req.method = HTTPMethod.POST;
1364 				req.bodyWriter.write(jsonbody);
1365 			},
1366 			(scope res)
1367 			{
1368 				ret~= to!string(res.bodyReader.readAllUTF8());
1369 			}
1370 		);
1371 		return ret;
1372 	}
1373 
1374 	string markCategoriesAsRead(string[] categoryIDs, DateTime asOf)
1375 	{
1376 		string url="https://"~baseURL~urlMarkers;
1377 		auto jsonparam=Json.emptyObject;
1378 		jsonparam.action="markAsRead";
1379 		jsonparam["type"]="categories";
1380 		jsonparam.asOf=serializeToJson(epochTime(asOf));
1381 		jsonparam.categoryIds=serializeToJson(categoryIDs);
1382 		
1383 		string ret;
1384 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1385 		requestHTTP(url,
1386 			(scope req)
1387 			{
1388 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1389 				
1390 				req.method = HTTPMethod.POST;
1391 				req.bodyWriter.write(jsonbody);
1392 			},
1393 			(scope res)
1394 			{
1395 				ret~= to!string(res.bodyReader.readAllUTF8());
1396 			}
1397 		);
1398 		return ret;
1399 	}
1400 
1401 	string undoMarkCategoriesAsRead(string[] categoryIDs)
1402 	{
1403 		string url="https://"~baseURL~urlMarkers;
1404 		auto jsonparam=Json.emptyObject;
1405 		jsonparam.action="undoMarkAsRead";
1406 		jsonparam["type"]="categories";
1407 		auto jsonCategories=Json.emptyArray;
1408 		jsonparam.categoryIds=serializeToJson(categoryIDs);
1409 		
1410 		string ret;
1411 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1412 		requestHTTP(url,
1413 			(scope req)
1414 			{
1415 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1416 				
1417 				req.method = HTTPMethod.POST;
1418 				req.bodyWriter.write(jsonbody);
1419 			},
1420 			(scope res)
1421 			{
1422 				ret~= to!string(res.bodyReader.readAllUTF8());
1423 			}
1424 		);
1425 		return ret;
1426 	}
1427                 
1428 
1429 	string saveForLater(string[] entryIDs)
1430 	{
1431 		string url="https://"~baseURL~urlSaveForLater~this.clientID~"%2Ftag%2Fglobal.saved";
1432 		auto jsonparam=Json.emptyObject;
1433 		jsonparam.action="markAsSaved";
1434 		jsonparam["type"]="entries";
1435 		
1436 		string ret;
1437 		jsonparam.entryIds=serializeToJson(entryIDs);
1438 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1439 		requestHTTP(url,
1440 			(scope req)
1441 			{
1442 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1443 				
1444 				req.method = HTTPMethod.POST;
1445 				req.bodyWriter.write(jsonbody);
1446 			},
1447 			(scope res)
1448 			{
1449 				ret~= to!string(res.bodyReader.readAllUTF8());
1450 			}
1451 		);
1452 		return ret;
1453 	}
1454 
1455 	string searchFeeds(string query, int count, string locale)
1456 	{
1457 		string url="https://"~baseURL~urlSearchFeeds;
1458 		auto jsonparam=Json.emptyObject;
1459 		jsonparam.query=serializeToJsonString(query);
1460 		if (count>=0)
1461 			jsonparam.count=count;
1462 		if (locale.length>0)
1463 			jsonparam.locale=locale;
1464 		
1465 		string ret;
1466 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1467 		requestHTTP(url,
1468 			(scope req)
1469 			{
1470 				req.contentType="application/json; charset=UTF8";
1471 				req.headers["Authorization"]="OAuth "~this.clientToken;
1472 				req.method = HTTPMethod.GET;
1473 				req.bodyWriter.write(jsonbody);
1474 			},
1475 			(scope res)
1476 			{
1477 				ret~= to!string(res.bodyReader.readAllUTF8());
1478 			}
1479 		);
1480 		return ret;
1481 	}
1482 
1483 	string getTags()
1484 	{
1485 		string url="https://"~baseURL~urlTags;
1486 		auto jsonparam=Json.emptyObject;
1487 		
1488 		string ret;
1489 
1490 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1491 		requestHTTP(url,
1492 			(scope req)
1493 			{
1494 				req.contentType="application/json; charset=UTF8";
1495 				req.headers["Authorization"]="OAuth "~this.clientToken;
1496 				req.method = HTTPMethod.GET;
1497 				req.bodyWriter.write(jsonbody);
1498 			},
1499 			(scope res)
1500 			{
1501 				ret~= to!string(res.bodyReader.readAllUTF8());
1502 			}
1503 		);
1504 		return ret;
1505 	}
1506 
1507 	string addTag(string[] tags, string[] entryIDs)
1508 	{
1509 		string url="https://"~baseURL~urlTags~join(tags,",");
1510 		auto jsonparam=Json.emptyObject;
1511 		
1512 
1513 		if (entryIDs.length<=1)
1514 			jsonparam.entryID=serializeToJson(entryIDs[0]);
1515 		else
1516 		{
1517 			jsonparam.entryIds=serializeToJson(entryIDs);
1518 		}
1519 		string ret;
1520 
1521 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1522 		requestHTTP(url,
1523 			(scope req)
1524 			{
1525 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1526 				
1527 				req.method = HTTPMethod.PUT;
1528 				req.bodyWriter.write(jsonbody);
1529 			},
1530 			(scope res)
1531 			{
1532 				ret~= to!string(res.bodyReader.readAllUTF8());
1533 			}
1534 		);
1535 		return ret;
1536 	}
1537 
1538 
1539 	string changeTagLabel(string tag, string oldLabel, string newLabel)
1540 	{
1541 		string url="https://"~baseURL~urlTags~tag;
1542 		auto jsonparam=Json.emptyObject;
1543 		
1544 		jsonparam[oldLabel]=newLabel;
1545 
1546 		string ret;
1547 
1548 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1549 		requestHTTP(url,
1550 			(scope req)
1551 			{
1552 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1553 				
1554 				req.method = HTTPMethod.POST;
1555 				req.bodyWriter.write(jsonbody);
1556 			},
1557 			(scope res)
1558 			{
1559 				ret~= to!string(res.bodyReader.readAllUTF8());
1560 			}
1561 		);
1562 		return ret;
1563 	}
1564 	
1565 
1566 	string unTagEntries(string[] tags, string[] entryIDs)
1567 	{
1568 		string url="https://"~baseURL~urlTags~join(tags,",")~"/"~join(entryIDs,",");
1569 		auto jsonparam=Json.emptyObject;
1570 		
1571 
1572 		string ret;
1573 
1574 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1575 		requestHTTP(url,
1576 			(scope req)
1577 			{
1578 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1579 				
1580 				req.method = HTTPMethod.DELETE;
1581 				req.bodyWriter.write(jsonbody);
1582 			},
1583 			(scope res)
1584 			{
1585 				ret~= to!string(res.bodyReader.readAllUTF8());
1586 			}
1587 		);
1588 		return ret;
1589 	}
1590 
1591 	string deleteTags(string[] tags)
1592 	{
1593 		string url="https://"~baseURL~urlTags~join(tags,",");
1594 		auto jsonparam=Json.emptyObject;
1595 		
1596 
1597 		string ret;
1598 
1599 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1600 		requestHTTP(url,
1601 			(scope req)
1602 			{
1603 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1604 				
1605 				req.method = HTTPMethod.DELETE;
1606 				req.bodyWriter.write(jsonbody);
1607 			},
1608 			(scope res)
1609 			{
1610 				ret~= to!string(res.bodyReader.readAllUTF8());
1611 			}
1612 		);
1613 		return ret;
1614 	}
1615 
1616 	
1617 	string getTopics()
1618 	{
1619 		string url="https://"~baseURL~urlTopics;
1620 		auto jsonparam=Json.emptyObject;
1621 		string ret;
1622 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1623 		requestHTTP(url,
1624 			(scope req)
1625 			{
1626 				req.contentType="application/json; charset=UTF8";
1627 				req.headers["Authorization"]="OAuth "~this.clientToken;
1628 				req.method = HTTPMethod.GET;
1629 				req.bodyWriter.write(jsonbody);
1630 			},
1631 			(scope res)
1632 			{
1633 				ret~= to!string(res.bodyReader.readAllUTF8());
1634 			}
1635 		);
1636 		return ret;
1637 	}
1638 
1639 	string addTopic(string topicID, string topicInterest)
1640 	{
1641 		string url="https://"~baseURL~urlTopics;
1642 		auto jsonparam=Json.emptyObject;
1643 		
1644 		jsonparam.id=topicID;
1645 		jsonparam.interest=topicInterest;
1646 		string ret;
1647 
1648 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1649 		requestHTTP(url,
1650 			(scope req)
1651 			{
1652 				req.contentType="application/json; charset=UTF8";
1653 				req.headers["Authorization"]="OAuth "~this.clientToken;
1654 				req.method = HTTPMethod.POST;
1655 				req.bodyWriter.write(jsonbody);
1656 			},
1657 			(scope res)
1658 			{
1659 				ret~= to!string(res.bodyReader.readAllUTF8());
1660 			}
1661 		);
1662 		return ret;
1663 	}
1664 	string updateTopic(string topicID, string topicInterest)
1665 	{
1666 		return addTopic(topicID,topicInterest);
1667 	}
1668 
1669 	string deleteTopic(string topicID)
1670 	{
1671 		string url="https://"~baseURL~urlTopics;
1672 		auto jsonparam=Json.emptyObject;
1673 		
1674 		jsonparam.id=topicID;
1675 		string ret;
1676 
1677 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1678 		requestHTTP(url,
1679 			(scope req)
1680 			{
1681 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1682 				
1683 				req.method = HTTPMethod.DELETE;
1684 				req.bodyWriter.write(jsonbody);
1685 			},
1686 			(scope res)
1687 			{
1688 				ret~= to!string(res.bodyReader.readAllUTF8());
1689 			}
1690 		);
1691 		return ret;
1692 	}
1693 
1694 	string twitterSuggest1()
1695 	{
1696 		string url="https://"~baseURL~urlTwitterSuggest1;
1697 		auto jsonparam=Json.emptyObject;
1698 		string ret;
1699 
1700 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1701 		requestHTTP(url,
1702 			(scope req)
1703 			{
1704 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1705 				
1706 				req.method = HTTPMethod.GET;
1707 				req.bodyWriter.write(jsonbody);
1708 				req.headers["Authorization"]="OAuth "~this.clientToken;
1709 			},
1710 			(scope res)
1711 			{
1712 				ret~= to!string(res.bodyReader.readAllUTF8());
1713 			}
1714 		);
1715 		return ret;
1716 	}
1717 
1718 	string twitterSuggest2(string[] twitterHandles)
1719 	{
1720 		string url="https://"~baseURL~urlTwitterSuggest2;
1721 		string ret;
1722 		auto jsonparam=serializeToJson(twitterHandles);
1723 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1724 		requestHTTP(url,
1725 			(scope req)
1726 			{
1727 				req.contentType="application/json; charset=UTF8";
1728 				req.headers["Authorization"]="OAuth "~this.clientToken;
1729 				req.method = HTTPMethod.POST;
1730 				req.bodyWriter.write(jsonbody);
1731 			},
1732 			(scope res)
1733 			{
1734 				ret~= to!string(res.bodyReader.readAllUTF8());
1735 			}
1736 		);
1737 		return ret;
1738 	}
1739 
1740 	string twitterUnlink()
1741 	{
1742 		string url="https://"~baseURL~urlTwitterAuth;
1743 		string ret;
1744 		auto jsonparam=Json.emptyObject;
1745 		
1746 
1747 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1748 		requestHTTP(url,
1749 			(scope req)
1750 			{
1751 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1752 				
1753 				req.method = HTTPMethod.DELETE;
1754 				req.bodyWriter.write(jsonbody);
1755 			},
1756 			(scope res)
1757 			{
1758 				ret~= to!string(res.bodyReader.readAllUTF8());
1759 			}
1760 		);
1761 		return ret;
1762 	}
1763 
1764 	string twitterLink(string redirectURI, string state)
1765 	{
1766 		string url="https://"~baseURL~urlTwitterAuth;
1767 		string ret;
1768 		auto jsonparam=Json.emptyObject;
1769 		
1770 		jsonparam.redirectUri=redirectURI;
1771 		jsonparam.state=state;
1772 
1773 		auto jsonbody=to!string(serializeToJsonString(jsonparam));
1774 		requestHTTP(url,
1775 			(scope req)
1776 			{
1777 				req.contentType="application/json; charset=UTF8"; req.headers["Authorization"]="OAuth "~this.clientToken;
1778 				
1779 				req.method = HTTPMethod.GET;
1780 				req.bodyWriter.write(jsonbody);
1781 			},
1782 			(scope res)
1783 			{
1784 				ret~= to!string(res.bodyReader.readAllUTF8());
1785 			}
1786 		);
1787 		return ret;
1788 	}
1789 }