Goodbye, Disqus! Hello, Utterances!

[This article was first published on Posts on Maëlle's R blog, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Removing Disqus from my blogdown blog had been on my mind for a while,
ever since I saw Bob Rudis’ tweet enjoining Noam Ross to not use
it
for his
brand-new website
.
The same Twitter thread introduced me to
Utterances, a “lightweight
comments widget built on GitHub issues”, which I have at last installed
to my blog in lieu of Disqus. How did I manage to not lose anything of
value? How easy was it to switch tools? Read on to learn more!

Was saying goodbye to Disqus hard?

Removing Disqus was neither emotionally nor technically hard.

Comments I (kinda) let go of

To deal with my fear of loss, I exported all the comments to an
XML
.
It means I have a backup, that in theory I could explore within R! I’ll
show some XML wrangling a bit later. The export does contain Disqus
usernames and names which means I’m now responsible for person
identifying information that Disqus collected.

Thanks a lot to commenters in the past system for taking the time to
leave me a note: it helped me keep blogging!

The Disqus XML contains information about

  • posts that are in fact comments, not blog posts, along with
    their threading information i.e. both whose blog post the comment
    was on, and if relevant, which comment the comment is an answer to;

  • threads, one thread per comment but not necessarily one comment
    per thread, and potentially more than one thread per blog post. Each
    top-level comment is a thread, but a website page with no comment
    also gets a thread, obviously empty.

In the code below, I shall
rectangle the
information about threads (id, title) and about comments (message,
author name, date, thread id, was it spam, was it deleted) using the
xml2
package
.

export <- xml2::read_xml("data/disqus-export.xml")
export

## {xml_document}
## 
##  [1] \n  masalmon\n  Ge ...
##  [2] <thread dsq:id="5169974011">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [3] <thread dsq:id="5177145143">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [4] <thread dsq:id="5192091523">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [5] <thread dsq:id="5490361085">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [6] <thread dsq:id="5490455492">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [7] <thread dsq:id="5496622766">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [8] <thread dsq:id="5496655533">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [9] <thread dsq:id="5499530252">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [10] <thread dsq:id="5499566886">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [11] <thread dsq:id="5503605733">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [12] <thread dsq:id="5503629818">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [13] <thread dsq:id="5519522381">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [14] <thread dsq:id="5521172753">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [15] <thread dsq:id="5523856167">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [16] <thread dsq:id="5523862926">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [17] <thread dsq:id="5544585525">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [18] <thread dsq:id="5544919490">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [19] <thread dsq:id="5544919711">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [20] <thread dsq:id="5544920033">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## ...
</pre>
<p>Explaining how to parse XML is beyond the scope of this blog post, but<br />
let me just mention I used a search engine to answer questions such as<br />
“XPath extract nodes by name”, “xml2 namespace”. I reckon my code could<br />
be more elegant if I knew more XPath.</p>
<p>Let me start with threads.</p>
<pre># extract nodes corresponding to comments
threads_nodes <- xml2::xml_find_all(export, "d1:thread")
threads_nodes

## {xml_nodeset (283)}
##  [1] <thread dsq:id="5169974011">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [2] <thread dsq:id="5177145143">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [3] <thread dsq:id="5192091523">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [4] <thread dsq:id="5490361085">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [5] <thread dsq:id="5490455492">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [6] <thread dsq:id="5496622766">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [7] <thread dsq:id="5496655533">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [8] <thread dsq:id="5499530252">\n  <id/>\n  <forum>masalmon</forum>\n  ...
##  [9] <thread dsq:id="5499566886">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [10] <thread dsq:id="5503605733">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [11] <thread dsq:id="5503629818">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [12] <thread dsq:id="5519522381">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [13] <thread dsq:id="5521172753">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [14] <thread dsq:id="5523856167">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [15] <thread dsq:id="5523862926">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [16] <thread dsq:id="5544585525">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [17] <thread dsq:id="5544919490">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [18] <thread dsq:id="5544919711">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [19] <thread dsq:id="5544920033">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## [20] <thread dsq:id="5544931944">\n  <id/>\n  <forum>masalmon</forum>\n  ...
## ...

# extract interesting information from each node,
# information that is potentially nested
threads <- tibble::tibble(
  thread_id = xml2::xml_attr( threads_nodes, 
                              "id"),
  title = xml2::xml_text(
    xml2::xml_find_all(threads_nodes, "d1:title")
    ))
</pre>
<p>Now on to comments…</p>
<pre># extract nodes corresponding to comments
comments_nodes <- xml2::xml_find_all(export, "d1:post") 
comments_nodes

## {xml_nodeset (206)}
##  [1] <post dsq:id="2916181700">\n  <id/>\n  <message><![CDATA[<p>La poss ...
##  [2] <post dsq:id="3118121105">\n  <id/>\n  <message><![CDATA[<p>Great b ...
##  [3] <post dsq:id="3118236082">\n  <id/>\n  <message><![CDATA[<p>Nice Ma ...
##  [4] <post dsq:id="3118757895">\n  <id/>\n  <message><![CDATA[<p>Thanks  ...
##  [5] <post dsq:id="3118758593">\n  <id/>\n  <message><![CDATA[<p>Thanks  ...
##  [6] <post dsq:id="3118783826">\n  <id/>\n  <message><![CDATA[<p>I love  ...
##  [7] <post dsq:id="3118785805">\n  <id/>\n  <message><![CDATA[<p>Thanks! ...
##  [8] <post dsq:id="3121124991">\n  <id/>\n  <message><![CDATA[<p>Chouett ...
##  [9] <post dsq:id="3121137475">\n  <id/>\n  <message><![CDATA[<p>Oops qu ...
## [10] <post dsq:id="3121945521">\n  <id/>\n  <message><![CDATA[<p>I poste ...
## [11] <post dsq:id="3122653372">\n  <id/>\n  <message><![CDATA[<p>Another ...
## [12] <post dsq:id="3122759373">\n  <id/>\n  <message><![CDATA[<p>Thank y ...
## [13] <post dsq:id="3123851616">\n  <id/>\n  <message><![CDATA[<p>Great s ...
## [14] <post dsq:id="3126340152">\n  <id/>\n  <message><![CDATA[<p>Once ag ...
## [15] <post dsq:id="3126343942">\n  <id/>\n  <message><![CDATA[<p>Thank y ...
## [16] <post dsq:id="3140125477">\n  <id/>\n  <message><![CDATA[<p>The ide ...
## [17] <post dsq:id="3140136118">\n  <id/>\n  <message><![CDATA[<p>Thank y ...
## [18] <post dsq:id="3140161542">\n  <id/>\n  <message><![CDATA[<p>Not rel ...
## [19] <post dsq:id="3140329480">\n  <id/>\n  <message><![CDATA[<p>Yes def ...
## [20] <post dsq:id="3150961786">\n  <id/>\n  <message><![CDATA[<p>That's  ...
## ...

# extract interesting information from each node,
# information that is potentially nested
comments <- tibble::tibble(
  thread_id = xml2::xml_attr(
    xml2::xml_find_all(comments_nodes, "d1:thread"), 
    "id"),
  message = xml2::xml_text(
    xml2::xml_find_all(comments_nodes, "d1:message")
    ),
  date =  xml2::xml_text(
    xml2::xml_find_all(comments_nodes, "d1:createdAt")
    ),
  deleted = xml2::xml_text(
    xml2::xml_find_all(comments_nodes, "d1:isDeleted")
    ),
  spam = xml2::xml_text(
    xml2::xml_find_all(comments_nodes, "d1:isSpam")
    ),
  author = xml2::xml_text(
    xml2::xml_find_all(
    xml2::xml_find_all(comments_nodes, "d1:author"), 
    "d1:name")))
  
comments <- dplyr::mutate(comments,
                          date = anytime::anydate(date),
                          deleted = deleted == "true",
                          spam = spam == "true")
</pre>
<p>I was then able to join the two tables.</p>
<pre>comments <- dplyr::left_join(comments, threads,
                             by = "thread_id")
readr::write_csv(comments, "comments.csv")

comments[2:12, c("message", "title")]

## # A tibble: 11 x 2
##    message                                        title                    
##    <chr>                                          <chr>                    
##  1 "<p>Great blog post, thank you! I really appr… French villages and a so…
##  2 <p>Nice Maëlle!</p><p>Good, interesting quest… French villages and a so…
##  3 <p>Thanks Nick!</p>                            French villages and a so…
##  4 <p>Thanks Lisa! Toponomy is quite fascinating… French villages and a so…
##  5 "<p>I love this! I wonder, would it be possib… French villages and a so…
##  6 <p>Thanks! I got a similar question on Twitte… French villages and a so…
##  7 "<p>Chouette! Mais la mer c'est \"sea\", \"se… French villages and a so…
##  8 <p>Oops quelle faute de frappe idiote, je la … French villages and a so…
##  9 "<p>I posted an update! <a href=\"http://www.… rel="nofollow" target="_blank">Another good one, Maëlle! It's a great exa… More water, a bit more a…
## 11 <p>Thank you! Lol on ninja grep skills, I wis… More water, a bit more a…
</pre>
<p>I got a pretty nice rectangle in the end, that could be used for some<br />
text analysis, but in my case, I mostly view it as memorabilia. I hope<br />
any comment warranting action had been tackled. I wrote 93<br />
(<code>sum(comments$author == "Maëlle Salmon")</code>) out of the 206 comments<br />
(Disqus classified a few comments as spam, 15 to be exact, of which a<br />
few were informative comments. ), because I tend to answer comments, if<br />
only with a simple thank you! Now that I have GitHub issues as comments,<br />
I could also answer with emojis.</p>
<p>It was fun because I didn’t even remember about some notes I had gotten.<br />
I hope you don’t feel slighted, dear reader, now that I keep these old<br />
comments to myself! Be happy you’re no longer tracked.</p>
<h2 id="getting-rid-of-disqus">Getting rid of Disqus</h2>
<p>I removed Disqus from my website, and my website from Disqus!</p>
<p>To remove Disqus from a Hugo website, one can, depending on the<br />
website’s theme:</p>
<ul>
<li>
<p>use <a href="https://gohugo.io/about/hugo-and-gdpr/" rel="nofollow" target="_blank">Hugo’s Disqus GDPR<br />
setting</a> if the website<br />
theme uses Hugo’s built-in Disqus template (i.e. if there’s a<br />
mention of a <a href="https://gohugo.io/templates/internal/#use-the-disqus-template" rel="nofollow" target="_blank">internal Disqus<br />
partial</a>,<br />
not of a Disqus partial stored somewhere in the theme files);</p>
</li>
<li>
<p>or remove one’s Disqus username from the config file, or remove the<br />
Disqus partial mention in the post template. To do that, the best<br />
process is not to edit the e.g. post/single.html file in the theme<br />
folder, but instead to save it and edit it under<br />
layouts/post/single.html. <a href="https://bookdown.org/yihui/blogdown/custom-layouts.html" rel="nofollow" target="_blank">Refer to the blogdown book for more<br />
information</a>.</p>
</li>
</ul>
<p>After that, there should be no mention of Disqus scripts in your website<br />
source.</p>
<p>Then, to delete my website from my Disqus account, following <a href="https://help.disqus.com/en/articles/1717289-how-do-i-remove-my-site" rel="nofollow" target="_blank">Disqus<br />
guidance</a>,<br />
I logged into my account and, <em>after exporting my website’s comments</em>,<br />
confirmed I wanted to do that and voilà!</p>
<h1 id="adding-utterances">Adding Utterances</h1>
<p>To add Utterances, a “lightweight comments widget built on GitHub<br />
issues”, I also followed <a href="https://utteranc.es/#configuration" rel="nofollow" target="_blank">official<br />
guidance</a>:</p>
<ul>
<li>
<p>I installed the app to my website GitHub repo.</p>
</li>
<li>
<p>In my custom single.html layout for posts (again, <a href="https://bookdown.org/yihui/blogdown/custom-layouts.html" rel="nofollow" target="_blank">refer to the<br />
blogdown book for clear information on the<br />
topic</a>), I<br />
added the script tag corresponding to Utterances. The docs linked<br />
above help you configure the appearance of the widget.</p>
</li>
</ul>
<p>Here’s the Utterances script tag for my blog. The label needs to <a href="https://help.github.com/en/articles/creating-a-label" rel="nofollow" target="_blank">have been created for your website repo</a>tterances can only use existing issue labels.</p>
<pre><script src="https://utteranc.es/client.js"
        repo="maelle/simplymaelle"
        issue-term="title"
        label="comments :speech_balloon:"
        theme="github-light"
        crossorigin="anonymous"
        async>
</script>
</pre>
<p>I then wrote a comment under <a href="https://masalmon.eu/2019/01/25/uptodate/" rel="nofollow" target="_blank">one of my<br />
posts</a> to make sure things<br />
worked. I also took a few seconds to <a href="https://utteranc.es/#sites-using-utterances" rel="nofollow" target="_blank">add my site to the list of sites<br />
using Utterances</a>. Overall,<br />
I found the process easy, as I had the first time I installed Utterances<br />
<a href="https://blog.r-hub.io/" rel="nofollow" target="_blank">on a blogdown website</a>.</p>
<p>I am aware that a downside of Utterances is that it is tied to GitHub.<br />
However, I am not afraid of switching to yet another tool in the future,<br />
and hope not too many potential commenters will be turned off by the<br />
necessity to use a GitHub account to comment.</p>
<h1 id="conclusion">Conclusion</h1>
<p>In this post I explained how I removed Disqus from my blog and vice<br />
versa, and how I installed Utterances instead. What I did not do was<br />
analyzing the Disqus data. I moreover did not try to <em>transfer</em> old<br />
comments to the new system, partly because that’d mean removing<br />
commenters’ ownership on what they had written.</p>
<p>In <a href="https://twitter.com/hrbrmstr/status/1135915244532822018" rel="nofollow" target="_blank">his tweet that motivated me to say goodbye to<br />
Disqus</a>, Bob<br />
wrote <em>“Yet another service where you and your site visitors are the<br />
product. Plus it acts like malicious javascript.”</em>. I therefore feel a<br />
bit better about this website! Now, I didn’t have a ton of comments, and<br />
I don’t have a real need for moderating comments, so maybe you’ll make a<br />
different decision for your website. I’d be glad to hear about it… in<br />
the comments section below! Also feel free to tell me if you explore<br />
your own Disqus data in a more thorough way than I!</p>

<script type="text/javascript">
    var vglnk = {key: '949efb41171ac6ec1bf7f206d57e90b8'};
    (function(d, t) {
        var s = d.createElement(t);
            s.type = 'text/javascript';
            s.async = true;
			// s.defer = true;
//          s.src = '//cdn.viglink.com/api/vglnk.js'; 
			s.src = 'https://www.r-bloggers.com/wp-content/uploads/2020/08/vglnk.js';
        var r = d.getElementsByTagName(t)[0];
            r.parentNode.insertBefore(s, r);
    }(document, 'script'));
</script>
		
<div id='jp-relatedposts' class='jp-relatedposts' >
	<h3 class="jp-relatedposts-headline"><em>Related</em></h3>
</div><aside class="mashsb-container mashsb-main mashsb-stretched"><div class="mashsb-box"><div class="mashsb-buttons"><a class="mashicon-facebook mash-small mash-center mashsb-noshadow" href="https://www.facebook.com/sharer.php?u=https%3A%2F%2Fwww.r-bloggers.com%2F2019%2F10%2Fgoodbye-disqus-hello-utterances%2F" target="_blank" rel="nofollow"><span class="icon"></span><span class="text">Share</span></a><a class="mashicon-twitter mash-small mash-center mashsb-noshadow" href="https://twitter.com/intent/tweet?text=Goodbye%2C%20Disqus%21%20Hello%2C%20Utterances%21&url=https://www.r-bloggers.com/2019/10/goodbye-disqus-hello-utterances/&via=Rbloggers" target="_blank" rel="nofollow"><span class="icon"></span><span class="text">Tweet</span></a><div class="onoffswitch2 mash-small mashsb-noshadow" style="display:none;"></div></div>
            </div>
                <div style="clear:both;"></div></aside>
            <!-- Share buttons by mashshare.net - Version: 3.7.7-->
<p class="syndicated-attribution"><div style="border: 1px solid; background: none repeat scroll 0 0 #EDEDED; margin: 1px; font-size: 13px;">
<div style="text-align: center;">To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://masalmon.eu/2019/10/02/disqus/"> Posts on Maëlle's R blog</a></strong>.</div>
<hr />
<a href="https://www.r-bloggers.com/" rel="nofollow">R-bloggers.com</a> offers <strong><a href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" rel="nofollow">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" href="https://www.r-project.org/" rel="nofollow">R</a> news and tutorials about <a title="R tutorials" href="https://www.r-bloggers.com/how-to-learn-r-2/" rel="nofollow">learning R</a> and many other topics. <a title="Data science jobs" href="https://www.r-users.com/" rel="nofollow">Click here if you're looking to post or find an R/data-science job</a>.

<hr>Want to share your content on R-bloggers?<a href="https://www.r-bloggers.com/add-your-blog/" rel="nofollow"> click here</a> if you have a blog, or <a href="http://r-posts.com/" rel="nofollow"> here</a> if you don't.
</div></p>			</div>
	</article><nav class="post-navigation clearfix" role="navigation">
<div class="post-nav left">
<a href="https://www.r-bloggers.com/2019/10/how-to-use-math-symbols-with-ggdag-2/" rel="prev">← Previous post</a></div>
<div class="post-nav right">
<a href="https://www.r-bloggers.com/2019/10/kannada-mnist-prediction-classification-using-h2o-automl-in-r/" rel="next">Next post →</a></div>
</nav>
	</div>
	<aside class="mh-sidebar sb-right">
	<div id="custom_html-2" class="widget_text sb-widget widget_custom_html"><div class="textwidget custom-html-widget">
<div class="top-search" style="padding-left: 0px;">
	<form id="searchform" action="http://www.google.com/cse" target="_blank">
		<div>
			<input type="hidden" name="cx" value="005359090438081006639:paz69t-s8ua" />
			<input type="hidden" name="ie" value="UTF-8" />
			<input type="text" value="" name="q" id="q" autocomplete="on" style="font-size:16px;" placeholder="Search R-bloggers.." />
			<input type="submit" id="searchsubmit2" name="sa" value="Go" style="font-size:16px;" />
		</div>
	</form>

</div>
<!-- thanks: https://stackoverflow.com/questions/14981575/google-cse-with-a-custom-form 
https://stackoverflow.com/questions/10363674/change-size-of-text-in-text-input-tag
--></div></div><div id="text-6" class="sb-widget widget_text">			<div class="textwidget"><div style="min-height:26px;border:1px solid #ccc;padding:3px;text-align:left; background: none repeat scroll 0 0 #FDEADA;">

<form  style="width:202px; float:left;" action="https://feedburner.google.com/fb/a/mailverify" method="post" target="popupwindow" onsubmit="window.open('https://feedburner.google.com/fb/a/mailverify?uri=RBloggers', 'popupwindow', 'scrollbars=yes,width=550,height=520');return true">

<input type="text" style="width:110px"  onclick="if (this.value == 'Your e-mail here') this.value = '';" value='Your e-mail here' name="email"/>
<input type="hidden" value="RBloggers" name="uri"/><input type="hidden" name="loc" value="en_US"/><input type="submit" value="Subscribe" />

<!-- https://feeds.feedburner.com/~fc/RBloggers?bg=99CCFF&fg=444444&anim=0 -->

</form>

<div>
<a href="https://feeds.feedburner.com/RBloggers"><img src="https://i2.wp.com/www.r-bloggers.com/wp-content/uploads/2020/07/RBloggers_feedburner_count_2020_07_01-e1593671704447.gif?w=578&ssl=1" style="height:17px;min-width:80px;class:skip-lazy;" alt data-recalc-dims="1" data-lazy-src="https://i2.wp.com/www.r-bloggers.com/wp-content/uploads/2020/07/RBloggers_feedburner_count_2020_07_01-e1593671704447.gif?w=578&is-pending-load=1#038;ssl=1" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class=" jetpack-lazy-image"><noscript><img src="https://i2.wp.com/www.r-bloggers.com/wp-content/uploads/2020/07/RBloggers_feedburner_count_2020_07_01-e1593671704447.gif?w=578&ssl=1" style="height:17px;min-width:80px;class:skip-lazy;" alt="" data-recalc-dims="1" /></noscript></a>
</div>

</div>

<br/>

<div>
<script>
function init() {
var vidDefer = document.getElementsByTagName('iframe');
for (var i=0; i<vidDefer.length; i++) {
if(vidDefer[i].getAttribute('data-src')) {
vidDefer[i].setAttribute('src',vidDefer[i].getAttribute('data-src'));
} } }
window.onload = init;
</script>

<iframe allowtransparency="true" frameborder="0" scrolling="no"
src="" data-src="//platform.twitter.com/widgets/follow_button.html?screen_name=rbloggers&data-show-count"
  style="width:100%; height:30px;"></iframe>


<div id="fb-root"></div>
<script async defer crossorigin="anonymous" src="https://connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v7.0&appId=124112670941750&autoLogAppEvents=1" nonce="RysU23SE"></script>

<div style="min-height: 154px;" class="fb-page" data-href="https://www.facebook.com/rbloggers/" data-tabs="" data-width="300" data-height="154" data-small-header="true" data-adapt-container-width="true" data-hide-cover="false" data-show-facepile="true"><blockquote cite="https://www.facebook.com/rbloggers/" class="fb-xfbml-parse-ignore"><a href="https://www.facebook.com/rbloggers/">R bloggers Facebook page</a></blockquote></div>



<!--
<iframe src="" data-src="//www.facebook.com/plugins/likebox.php?href=http%3A%2F%2Fwww.facebook.com%2Fpages%2FR-bloggers%2F191414254890&width=300&height=155&show_faces=true&colorscheme=light&stream=false&border_color&header=false&appId=400430016676958" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:100%; height:140px;" allowTransparency="true"></iframe>
-->


<!--
<br/>
<strong>If you are an R blogger yourself</strong> you are invited to <a href="https://www.r-bloggers.com/add-your-blog/">add your own R content feed to this site</a> (<strong>Non-English</strong> R bloggers should add themselves- <a href="https://www.r-bloggers.com/lang/add-your-blog">here</a>) -->

</div></div>
		</div><div id="wppp-3" class="sb-widget widget_wppp"><h4 class="widget-title">Most viewed posts (weekly)</h4>
<ul class='wppp_list'>
	<li><a href='https://www.r-bloggers.com/2016/11/5-ways-to-subset-a-data-frame-in-r/' title='5 Ways to Subset a Data Frame in R'>5 Ways to Subset a Data Frame in R</a></li>
	<li><a href='https://www.r-bloggers.com/2015/12/how-to-write-the-first-for-loop-in-r/' title='How to write the first for loop in R'>How to write the first for loop in R</a></li>
	<li><a href='https://www.r-bloggers.com/2013/08/date-formats-in-r/' title='Date Formats in R'>Date Formats in R</a></li>
	<li><a href='https://www.r-bloggers.com/2010/02/r-sorting-a-data-frame-by-the-contents-of-a-column/' title='R – Sorting a data frame by the contents of a column'>R – Sorting a data frame by the contents of a column</a></li>
	<li><a href='https://www.r-bloggers.com/2020/01/how-to-remove-outliers-in-r/' title='How to Remove Outliers in R'>How to Remove Outliers in R</a></li>
	<li><a href='https://www.r-bloggers.com/2020/09/the-fastest-way-to-read-and-writes-file-in-r/' title='The fastest way to Read and Writes file in R'>The fastest way to Read and Writes file in R</a></li>
	<li><a href='https://www.r-bloggers.com/2020/09/generalized-linear-models-and-plots-with-edger-advanced-differential-expression-analysis/' title='Generalized Linear Models and Plots with edgeR – Advanced Differential Expression Analysis'>Generalized Linear Models and Plots with edgeR – Advanced Differential Expression Analysis</a></li>
</ul>
</div><div id="text-18" class="sb-widget widget_text"><h4 class="widget-title">Sponsors</h4>			<div class="textwidget"><div style="min-height: 2055px;">

<script data-cfasync="false" type="text/javascript">
// https://support.cloudflare.com/hc/en-us/articles/200169436-How-can-I-have-Rocket-Loader-ignore-my-script-s-in-Automatic-Mode-
// this must be placed higher. Otherwise it doesn't work.
// data-cfasync="false" is for making sure cloudflares' rocketcache doesn't interfeare with this
// in this case it only works because it was used at the original script in the text widget


function createCookie(name,value,days) {
    var expires = "";
    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days*24*60*60*1000));
        expires = "; expires=" + date.toUTCString();
    }
    document.cookie = name + "=" + value + expires + "; path=/";
}

function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
}

function eraseCookie(name) {
    createCookie(name,"",-1);
}

// no longer use async because of google
// async 
async function readTextFile(file)
{
	// Helps people browse between pages without the need to keep downloading the same 
	// ads txt page everytime. This way, it allows them to use their browser's cache.
	var random_number = readCookie("ad_random_number_cookie");
	if(random_number == null) {
		var random_number = Math.floor(Math.random()*100*(new Date().getTime()/10000000000));
		createCookie("ad_random_number_cookie",random_number,1)
	}
	
    file += '?t='+random_number;
    var rawFile = new XMLHttpRequest();
    rawFile.onreadystatechange = function ()
    {
        if(rawFile.readyState === 4)
        {
            if(rawFile.status === 200 || rawFile.status == 0)
            {
                // var allText = rawFile.responseText;
                // document.write(allText);
                document.write(rawFile.responseText);
            }
        }
    }
    rawFile.open("GET", file, false);
    rawFile.send(null);
}

// readTextFile('https://raw.githubusercontent.com/Raynos/file-store/master/temp.txt');

readTextFile("https://www.r-bloggers.com/wp-content/uploads/text-widget_anti-cache.txt");


</script>

</div></div>
		</div>
		<div id="recent-posts-3" class="sb-widget widget_recent_entries">
		<h4 class="widget-title">Recent Posts</h4>
		<ul>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/building-a-simple-pipeline-in-r/">Building a Simple Pipeline in R</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/building-apps-with-shinipsum-and-golem/">Building apps with {shinipsum} and {golem}</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/slicing-the-onion-3-ways-toy-problems-in-r-python-and-julia/">Slicing the onion 3 ways- Toy problems in R, python, and Julia</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/path-chain-concise-structure-for-chainable-paths/">path.chain: Concise Structure for Chainable Paths</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/generalized-linear-models-and-plots-with-edger-advanced-differential-expression-analysis/">Generalized Linear Models and Plots with edgeR – Advanced Differential Expression Analysis</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/national-weekly-death-rates/">National Weekly Death Rates</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/kmeans-clustering-of-penguins-2/">Kmeans Clustering of Penguins</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/running-an-r-script-on-a-schedule-overview/">Running an R Script on a Schedule: Overview</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/free-workshop-on-deep-learning-with-keras-and-tensorflow/">Free workshop on Deep Learning with Keras and TensorFlow</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/le-monde-puzzle-1155/">Le Monde puzzle [#1155]</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/the-fastest-way-to-read-and-writes-file-in-r/">The fastest way to Read and Writes file in R</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/why-r-2020-conference-starts-2020-09-26/">Why R? 2020 Conference Starts 2020-09-26</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/free-text-in-surveys-important-issues-in-the-2017-new-zealand-election-study-by-ellis2013nz/">Free text in surveys – important issues in the 2017 New Zealand Election Study by @ellis2013nz</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/lessons-learned-from-500-data-science-interviews/">Lessons learned from 500+ Data Science interviews</a>
									</li>
											<li>
					<a href="https://www.r-bloggers.com/2020/09/writing-conundrums/">Writing conundrums</a>
									</li>
					</ul>

		</div><div id="rss-7" class="sb-widget widget_rss"><h4 class="widget-title"><a class="rsswidget" href="https://feeds.feedburner.com/Rjobs"><img class="rss-widget-icon" style="border:0" width="14" height="14" src="https://www.r-bloggers.com/wp-includes/images/rss.png" alt="RSS" /></a> <a class="rsswidget" href="https://www.r-users.com/">Jobs for R-users</a></h4><ul><li><a class='rsswidget' href='http://feedproxy.google.com/~r/RJobs/~3/XUqQfUzxziw/'>Junior Data Scientist / Quantitative economist</a></li><li><a class='rsswidget' href='http://feedproxy.google.com/~r/RJobs/~3/C2KYkXtMCHw/'>Senior Quantitative Analyst</a></li><li><a class='rsswidget' href='http://feedproxy.google.com/~r/RJobs/~3/z5mEr8qKkUI/'>R programmer</a></li><li><a class='rsswidget' href='http://feedproxy.google.com/~r/RJobs/~3/wi3Gfi8GNqA/'>Data Scientist – CGIAR Excellence in Agronomy (Ref No: DDG-R4D/DS/1/CG/EA/06/20)</a></li><li><a class='rsswidget' href='http://feedproxy.google.com/~r/RJobs/~3/aSK4JGQQOfg/'>Data Analytics Auditor, Future of Audit Lead @ London or Newcastle</a></li></ul></div><div id="rss-9" class="sb-widget widget_rss"><h4 class="widget-title"><a class="rsswidget" href="https://feeds.feedburner.com/Python-bloggers"><img class="rss-widget-icon" style="border:0" width="14" height="14" src="https://www.r-bloggers.com/wp-includes/images/rss.png" alt="RSS" /></a> <a class="rsswidget" href="https://python-bloggers.com/">python-bloggers.com (python/data-science news)</a></h4><ul><li><a class='rsswidget' href='http://feedproxy.google.com/~r/Python-bloggers/~3/aeOWm291YBM/'>Writing conundrums</a></li><li><a class='rsswidget' href='http://feedproxy.google.com/~r/Python-bloggers/~3/Eu8ZoDGo_ro/'>Introducing Unguided Projects: The World’s First Interactive Code-Along Exercises</a></li><li><a class='rsswidget' href='http://feedproxy.google.com/~r/Python-bloggers/~3/nEBrVWBG7Ao/'>Document Letter Frequency in Python</a></li><li><a class='rsswidget' href='http://feedproxy.google.com/~r/Python-bloggers/~3/oQGmvR_1iGg/'>Equipping Petroleum Engineers in Calgary With Critical Data Skills</a></li><li><a class='rsswidget' href='http://feedproxy.google.com/~r/Python-bloggers/~3/UcltGO0ZtYA/'>Connecting Python to SQL Server using trusted and login credentials</a></li><li><a class='rsswidget' href='http://feedproxy.google.com/~r/Python-bloggers/~3/zRTGnHNTQR8/'>Intro to GSC API with Python (Video)</a></li><li><a class='rsswidget' href='http://feedproxy.google.com/~r/Python-bloggers/~3/Ih7X5g4SNhM/'>Technical documentation</a></li></ul></div><div id="text-16" class="sb-widget widget_text">			<div class="textwidget"><strong><a href="https://www.r-bloggers.com/blogs-list/">Full list of contributing R-bloggers</a></strong></div>
		</div><div id="archives-3" class="sb-widget widget_archive"><h4 class="widget-title">Archives</h4>		<label class="screen-reader-text" for="archives-dropdown-3">Archives</label>
		<select id="archives-dropdown-3" name="archive-dropdown">
			
			<option value="">Select Month</option>
				<option value='https://www.r-bloggers.com/2020/09/'> September 2020  (162)</option>
	<option value='https://www.r-bloggers.com/2020/08/'> August 2020  (180)</option>
	<option value='https://www.r-bloggers.com/2020/07/'> July 2020  (229)</option>
	<option value='https://www.r-bloggers.com/2020/06/'> June 2020  (204)</option>
	<option value='https://www.r-bloggers.com/2020/05/'> May 2020  (285)</option>
	<option value='https://www.r-bloggers.com/2020/04/'> April 2020  (292)</option>
	<option value='https://www.r-bloggers.com/2020/03/'> March 2020  (246)</option>
	<option value='https://www.r-bloggers.com/2020/02/'> February 2020  (219)</option>
	<option value='https://www.r-bloggers.com/2020/01/'> January 2020  (213)</option>
	<option value='https://www.r-bloggers.com/2019/12/'> December 2019  (215)</option>
	<option value='https://www.r-bloggers.com/2019/11/'> November 2019  (193)</option>
	<option value='https://www.r-bloggers.com/2019/10/'> October 2019  (216)</option>
	<option value='https://www.r-bloggers.com/2019/09/'> September 2019  (211)</option>
	<option value='https://www.r-bloggers.com/2019/08/'> August 2019  (256)</option>
	<option value='https://www.r-bloggers.com/2019/07/'> July 2019  (228)</option>
	<option value='https://www.r-bloggers.com/2019/06/'> June 2019  (218)</option>
	<option value='https://www.r-bloggers.com/2019/05/'> May 2019  (250)</option>
	<option value='https://www.r-bloggers.com/2019/04/'> April 2019  (275)</option>
	<option value='https://www.r-bloggers.com/2019/03/'> March 2019  (295)</option>
	<option value='https://www.r-bloggers.com/2019/02/'> February 2019  (255)</option>
	<option value='https://www.r-bloggers.com/2019/01/'> January 2019  (281)</option>
	<option value='https://www.r-bloggers.com/2018/12/'> December 2018  (252)</option>
	<option value='https://www.r-bloggers.com/2018/11/'> November 2018  (285)</option>
	<option value='https://www.r-bloggers.com/2018/10/'> October 2018  (308)</option>
	<option value='https://www.r-bloggers.com/2018/09/'> September 2018  (291)</option>
	<option value='https://www.r-bloggers.com/2018/08/'> August 2018  (270)</option>
	<option value='https://www.r-bloggers.com/2018/07/'> July 2018  (333)</option>
	<option value='https://www.r-bloggers.com/2018/06/'> June 2018  (298)</option>
	<option value='https://www.r-bloggers.com/2018/05/'> May 2018  (321)</option>
	<option value='https://www.r-bloggers.com/2018/04/'> April 2018  (301)</option>
	<option value='https://www.r-bloggers.com/2018/03/'> March 2018  (291)</option>
	<option value='https://www.r-bloggers.com/2018/02/'> February 2018  (241)</option>
	<option value='https://www.r-bloggers.com/2018/01/'> January 2018  (330)</option>
	<option value='https://www.r-bloggers.com/2017/12/'> December 2017  (261)</option>
	<option value='https://www.r-bloggers.com/2017/11/'> November 2017  (270)</option>
	<option value='https://www.r-bloggers.com/2017/10/'> October 2017  (290)</option>
	<option value='https://www.r-bloggers.com/2017/09/'> September 2017  (294)</option>
	<option value='https://www.r-bloggers.com/2017/08/'> August 2017  (340)</option>
	<option value='https://www.r-bloggers.com/2017/07/'> July 2017  (283)</option>
	<option value='https://www.r-bloggers.com/2017/06/'> June 2017  (317)</option>
	<option value='https://www.r-bloggers.com/2017/05/'> May 2017  (349)</option>
	<option value='https://www.r-bloggers.com/2017/04/'> April 2017  (324)</option>
	<option value='https://www.r-bloggers.com/2017/03/'> March 2017  (365)</option>
	<option value='https://www.r-bloggers.com/2017/02/'> February 2017  (317)</option>
	<option value='https://www.r-bloggers.com/2017/01/'> January 2017  (367)</option>
	<option value='https://www.r-bloggers.com/2016/12/'> December 2016  (347)</option>
	<option value='https://www.r-bloggers.com/2016/11/'> November 2016  (294)</option>
	<option value='https://www.r-bloggers.com/2016/10/'> October 2016  (306)</option>
	<option value='https://www.r-bloggers.com/2016/09/'> September 2016  (254)</option>
	<option value='https://www.r-bloggers.com/2016/08/'> August 2016  (287)</option>
	<option value='https://www.r-bloggers.com/2016/07/'> July 2016  (326)</option>
	<option value='https://www.r-bloggers.com/2016/06/'> June 2016  (263)</option>
	<option value='https://www.r-bloggers.com/2016/05/'> May 2016  (292)</option>
	<option value='https://www.r-bloggers.com/2016/04/'> April 2016  (260)</option>
	<option value='https://www.r-bloggers.com/2016/03/'> March 2016  (302)</option>
	<option value='https://www.r-bloggers.com/2016/02/'> February 2016  (268)</option>
	<option value='https://www.r-bloggers.com/2016/01/'> January 2016  (337)</option>
	<option value='https://www.r-bloggers.com/2015/12/'> December 2015  (304)</option>
	<option value='https://www.r-bloggers.com/2015/11/'> November 2015  (234)</option>
	<option value='https://www.r-bloggers.com/2015/10/'> October 2015  (259)</option>
	<option value='https://www.r-bloggers.com/2015/09/'> September 2015  (238)</option>
	<option value='https://www.r-bloggers.com/2015/08/'> August 2015  (264)</option>
	<option value='https://www.r-bloggers.com/2015/07/'> July 2015  (243)</option>
	<option value='https://www.r-bloggers.com/2015/06/'> June 2015  (213)</option>
	<option value='https://www.r-bloggers.com/2015/05/'> May 2015  (235)</option>
	<option value='https://www.r-bloggers.com/2015/04/'> April 2015  (211)</option>
	<option value='https://www.r-bloggers.com/2015/03/'> March 2015  (259)</option>
	<option value='https://www.r-bloggers.com/2015/02/'> February 2015  (212)</option>
	<option value='https://www.r-bloggers.com/2015/01/'> January 2015  (245)</option>
	<option value='https://www.r-bloggers.com/2014/12/'> December 2014  (236)</option>
	<option value='https://www.r-bloggers.com/2014/11/'> November 2014  (221)</option>
	<option value='https://www.r-bloggers.com/2014/10/'> October 2014  (218)</option>
	<option value='https://www.r-bloggers.com/2014/09/'> September 2014  (259)</option>
	<option value='https://www.r-bloggers.com/2014/08/'> August 2014  (217)</option>
	<option value='https://www.r-bloggers.com/2014/07/'> July 2014  (235)</option>
	<option value='https://www.r-bloggers.com/2014/06/'> June 2014  (241)</option>
	<option value='https://www.r-bloggers.com/2014/05/'> May 2014  (243)</option>
	<option value='https://www.r-bloggers.com/2014/04/'> April 2014  (260)</option>
	<option value='https://www.r-bloggers.com/2014/03/'> March 2014  (289)</option>
	<option value='https://www.r-bloggers.com/2014/02/'> February 2014  (269)</option>
	<option value='https://www.r-bloggers.com/2014/01/'> January 2014  (263)</option>
	<option value='https://www.r-bloggers.com/2013/12/'> December 2013  (264)</option>
	<option value='https://www.r-bloggers.com/2013/11/'> November 2013  (241)</option>
	<option value='https://www.r-bloggers.com/2013/10/'> October 2013  (234)</option>
	<option value='https://www.r-bloggers.com/2013/09/'> September 2013  (215)</option>
	<option value='https://www.r-bloggers.com/2013/08/'> August 2013  (223)</option>
	<option value='https://www.r-bloggers.com/2013/07/'> July 2013  (254)</option>
	<option value='https://www.r-bloggers.com/2013/06/'> June 2013  (272)</option>
	<option value='https://www.r-bloggers.com/2013/05/'> May 2013  (260)</option>
	<option value='https://www.r-bloggers.com/2013/04/'> April 2013  (279)</option>
	<option value='https://www.r-bloggers.com/2013/03/'> March 2013  (277)</option>
	<option value='https://www.r-bloggers.com/2013/02/'> February 2013  (294)</option>
	<option value='https://www.r-bloggers.com/2013/01/'> January 2013  (343)</option>
	<option value='https://www.r-bloggers.com/2012/12/'> December 2012  (308)</option>
	<option value='https://www.r-bloggers.com/2012/11/'> November 2012  (277)</option>
	<option value='https://www.r-bloggers.com/2012/10/'> October 2012  (308)</option>
	<option value='https://www.r-bloggers.com/2012/09/'> September 2012  (270)</option>
	<option value='https://www.r-bloggers.com/2012/08/'> August 2012  (263)</option>
	<option value='https://www.r-bloggers.com/2012/07/'> July 2012  (247)</option>
	<option value='https://www.r-bloggers.com/2012/06/'> June 2012  (298)</option>
	<option value='https://www.r-bloggers.com/2012/05/'> May 2012  (287)</option>
	<option value='https://www.r-bloggers.com/2012/04/'> April 2012  (295)</option>
	<option value='https://www.r-bloggers.com/2012/03/'> March 2012  (304)</option>
	<option value='https://www.r-bloggers.com/2012/02/'> February 2012  (264)</option>
	<option value='https://www.r-bloggers.com/2012/01/'> January 2012  (280)</option>
	<option value='https://www.r-bloggers.com/2011/12/'> December 2011  (251)</option>
	<option value='https://www.r-bloggers.com/2011/11/'> November 2011  (261)</option>
	<option value='https://www.r-bloggers.com/2011/10/'> October 2011  (281)</option>
	<option value='https://www.r-bloggers.com/2011/09/'> September 2011  (187)</option>
	<option value='https://www.r-bloggers.com/2011/08/'> August 2011  (258)</option>
	<option value='https://www.r-bloggers.com/2011/07/'> July 2011  (219)</option>
	<option value='https://www.r-bloggers.com/2011/06/'> June 2011  (225)</option>
	<option value='https://www.r-bloggers.com/2011/05/'> May 2011  (239)</option>
	<option value='https://www.r-bloggers.com/2011/04/'> April 2011  (268)</option>
	<option value='https://www.r-bloggers.com/2011/03/'> March 2011  (249)</option>
	<option value='https://www.r-bloggers.com/2011/02/'> February 2011  (205)</option>
	<option value='https://www.r-bloggers.com/2011/01/'> January 2011  (209)</option>
	<option value='https://www.r-bloggers.com/2010/12/'> December 2010  (188)</option>
	<option value='https://www.r-bloggers.com/2010/11/'> November 2010  (172)</option>
	<option value='https://www.r-bloggers.com/2010/10/'> October 2010  (219)</option>
	<option value='https://www.r-bloggers.com/2010/09/'> September 2010  (185)</option>
	<option value='https://www.r-bloggers.com/2010/08/'> August 2010  (203)</option>
	<option value='https://www.r-bloggers.com/2010/07/'> July 2010  (175)</option>
	<option value='https://www.r-bloggers.com/2010/06/'> June 2010  (167)</option>
	<option value='https://www.r-bloggers.com/2010/05/'> May 2010  (164)</option>
	<option value='https://www.r-bloggers.com/2010/04/'> April 2010  (152)</option>
	<option value='https://www.r-bloggers.com/2010/03/'> March 2010  (165)</option>
	<option value='https://www.r-bloggers.com/2010/02/'> February 2010  (135)</option>
	<option value='https://www.r-bloggers.com/2010/01/'> January 2010  (121)</option>
	<option value='https://www.r-bloggers.com/2009/12/'> December 2009  (126)</option>
	<option value='https://www.r-bloggers.com/2009/11/'> November 2009  (66)</option>
	<option value='https://www.r-bloggers.com/2009/10/'> October 2009  (87)</option>
	<option value='https://www.r-bloggers.com/2009/09/'> September 2009  (65)</option>
	<option value='https://www.r-bloggers.com/2009/08/'> August 2009  (56)</option>
	<option value='https://www.r-bloggers.com/2009/07/'> July 2009  (64)</option>
	<option value='https://www.r-bloggers.com/2009/06/'> June 2009  (54)</option>
	<option value='https://www.r-bloggers.com/2009/05/'> May 2009  (35)</option>
	<option value='https://www.r-bloggers.com/2009/04/'> April 2009  (38)</option>
	<option value='https://www.r-bloggers.com/2009/03/'> March 2009  (40)</option>
	<option value='https://www.r-bloggers.com/2009/02/'> February 2009  (33)</option>
	<option value='https://www.r-bloggers.com/2009/01/'> January 2009  (42)</option>
	<option value='https://www.r-bloggers.com/2008/12/'> December 2008  (16)</option>
	<option value='https://www.r-bloggers.com/2008/11/'> November 2008  (14)</option>
	<option value='https://www.r-bloggers.com/2008/10/'> October 2008  (10)</option>
	<option value='https://www.r-bloggers.com/2008/09/'> September 2008  (8)</option>
	<option value='https://www.r-bloggers.com/2008/08/'> August 2008  (11)</option>
	<option value='https://www.r-bloggers.com/2008/07/'> July 2008  (7)</option>
	<option value='https://www.r-bloggers.com/2008/06/'> June 2008  (8)</option>
	<option value='https://www.r-bloggers.com/2008/05/'> May 2008  (8)</option>
	<option value='https://www.r-bloggers.com/2008/04/'> April 2008  (4)</option>
	<option value='https://www.r-bloggers.com/2008/03/'> March 2008  (5)</option>
	<option value='https://www.r-bloggers.com/2008/02/'> February 2008  (6)</option>
	<option value='https://www.r-bloggers.com/2008/01/'> January 2008  (10)</option>
	<option value='https://www.r-bloggers.com/2007/12/'> December 2007  (3)</option>
	<option value='https://www.r-bloggers.com/2007/11/'> November 2007  (5)</option>
	<option value='https://www.r-bloggers.com/2007/10/'> October 2007  (9)</option>
	<option value='https://www.r-bloggers.com/2007/09/'> September 2007  (7)</option>
	<option value='https://www.r-bloggers.com/2007/08/'> August 2007  (21)</option>
	<option value='https://www.r-bloggers.com/2007/07/'> July 2007  (9)</option>
	<option value='https://www.r-bloggers.com/2007/06/'> June 2007  (3)</option>
	<option value='https://www.r-bloggers.com/2007/05/'> May 2007  (3)</option>
	<option value='https://www.r-bloggers.com/2007/04/'> April 2007  (1)</option>
	<option value='https://www.r-bloggers.com/2007/03/'> March 2007  (5)</option>
	<option value='https://www.r-bloggers.com/2007/02/'> February 2007  (4)</option>
	<option value='https://www.r-bloggers.com/2006/11/'> November 2006  (1)</option>
	<option value='https://www.r-bloggers.com/2006/10/'> October 2006  (2)</option>
	<option value='https://www.r-bloggers.com/2006/08/'> August 2006  (3)</option>
	<option value='https://www.r-bloggers.com/2006/07/'> July 2006  (1)</option>
	<option value='https://www.r-bloggers.com/2006/06/'> June 2006  (1)</option>
	<option value='https://www.r-bloggers.com/2006/05/'> May 2006  (3)</option>
	<option value='https://www.r-bloggers.com/2006/04/'> April 2006  (1)</option>
	<option value='https://www.r-bloggers.com/2006/03/'> March 2006  (1)</option>
	<option value='https://www.r-bloggers.com/2006/02/'> February 2006  (5)</option>
	<option value='https://www.r-bloggers.com/2006/01/'> January 2006  (1)</option>
	<option value='https://www.r-bloggers.com/2005/10/'> October 2005  (1)</option>
	<option value='https://www.r-bloggers.com/2005/09/'> September 2005  (3)</option>
	<option value='https://www.r-bloggers.com/2005/05/'> May 2005  (1)</option>

		</select>

<script type="text/javascript">
/* <![CDATA[ */
(function() {
	var dropdown = document.getElementById( "archives-dropdown-3" );
	function onSelectChange() {
		if ( dropdown.options[ dropdown.selectedIndex ].value !== '' ) {
			document.location.href = this.options[ this.selectedIndex ].value;
		}
	}
	dropdown.onchange = onSelectChange;
})();
/* ]]> */
</script>
			</div><div id="linkcat-3349" class="sb-widget widget_links"><h4 class="widget-title">Other sites</h4>
	<ul class='xoxo blogroll'>
<li><a href="http://www.proc-x.com/" title="SAS news gathered from bloggers">SAS blogs</a></li>
<li><a href="https://www.r-users.com/">Jobs for R-users</a></li>

	</ul>
</div>
</aside></div>
</div>
<div class="copyright-wrap">
	<p class="copyright">Copyright © 2020 | <a href="https://www.mhthemes.com/" rel="nofollow">MH Corporate basic by MH Themes</a></p>
</div>
</div>

<!--
TPC! Memory Usage (http://webjawns.com)
Memory Usage: 73717448
Memory Peak Usage: 73833352
WP Memory Limit: 820M
PHP Memory Limit: 800M
Checkpoints: 9
-->


<!-- Schema & Structured Data For WP v1.9.49.1 - -->
<script type="application/ld+json" class="saswp-schema-markup-output">
[{"@context":"https:\/\/schema.org","@graph":[{"@type":"Organization","@id":"https:\/\/www.r-bloggers.com#Organization","name":"R-bloggers","url":"http:\/\/www.r-bloggers.com","sameAs":[],"logo":{"@type":"ImageObject","url":"http:\/\/www.r-bloggers.com\/wp-content\/uploads\/2020\/07\/R_blogger_logo_02.png","width":"1061","height":"304"},"contactPoint":{"@type":"ContactPoint","contactType":"technical support","telephone":"","url":"https:\/\/www.r-bloggers.com\/contact-us\/"}},{"@type":"WebSite","@id":"https:\/\/www.r-bloggers.com#website","headline":"R-bloggers","name":"R-bloggers","description":"R news and tutorials contributed by hundreds of R bloggers","url":"https:\/\/www.r-bloggers.com","potentialAction":{"@type":"SearchAction","target":"https:\/\/www.r-bloggers.com\/?s={search_term_string}","query-input":"required name=search_term_string"},"publisher":{"@id":"https:\/\/www.r-bloggers.com#Organization"}},{"@context":"https:\/\/schema.org","@type":"WebPage","@id":"https:\/\/www.r-bloggers.com\/2019\/10\/goodbye-disqus-hello-utterances\/#webpage","name":"Goodbye, Disqus! Hello, Utterances! | R-bloggers","url":"https:\/\/www.r-bloggers.com\/2019\/10\/goodbye-disqus-hello-utterances\/","lastReviewed":"2019-10-01T18:00:00-06:00","reviewedBy":{"@type":"Organization","logo":{"@type":"ImageObject","url":"http:\/\/www.r-bloggers.com\/wp-content\/uploads\/2020\/07\/R_blogger_logo_02.png","width":"1061","height":"304"},"name":"R-bloggers"},"inLanguage":"en-US","description":"Removing Disqus from my blogdown blog had been on my mind for a while,\never since I saw Bob Rudis\u2019 tweet enjoining Noam Ross to not use\nit for his\nbrand-new website.\nThe same Twitter thread introduced me to\nUtterances, a \u201clightweight\ncomments widget built on GitHub issues\u201d, which I have at last installed\nto my blog in lieu of Disqus. How did I manage to not lose anything of\nvalue? How easy was it to switch tools? Read on to learn more!\n\n\n\nWas saying goodbye to Disqus hard?\n\nRemoving Disqus was neither emotionally nor technically hard.\n\nComments I (kinda) let go of\n\nTo deal with my fear of loss, I exported all the comments to an\nXML.\nIt means I have a backup, that in theory I could explore within R! I\u2019ll\nshow some XML wrangling a bit later. The export does contain Disqus\nusernames and names which means I\u2019m now responsible for person\nidentifying information that Disqus collected.\n\nThanks a lot to commenters in the past system for taking the time to\nleave me a note: it helped me keep blogging!\n\nThe Disqus XML contains information about\n\n\nposts that are in fact comments, not blog posts, along with\ntheir threading information i.e.\u00a0both whose blog post the comment\nwas on, and if relevant, which comment the comment is an answer to;\n\nthreads, one thread per comment but not necessarily one comment\nper thread, and potentially more than one thread per blog post. Each\ntop-level comment is a thread, but a website page with no comment\nalso gets a thread, obviously empty.\n\nIn the code below, I shall\nrectangle the\ninformation about threads (id, title) and about comments (message,\nauthor name, date, thread id, was it spam, was it deleted) using the\nxml2\npackage.\n\nexport <- xml2::read_xml(\"data\/disqus-export.xml\")\nexport\n\n\n## {xml_document}\n## <disqus schemaLocation=\"http:\/\/disqus.com\/api\/schemas\/1.0\/disqus.xsd http:\/\/disqus.com\/api\/schemas\/1.0\/disqus-internals.xsd\" xmlns=\"http:\/\/disqus.com\" xmlns:dsq=\"http:\/\/disqus.com\/disqus-internals\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\">\n##   <category dsq:id=\"5516420\">\\n  <forum>masalmon<\/forum>\\n  <title>Ge ...\n##   <thread dsq:id=\"5169974011\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5177145143\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5192091523\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5490361085\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5490455492\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5496622766\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5496655533\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5499530252\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5499566886\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5503605733\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5503629818\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5519522381\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5521172753\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5523856167\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5523862926\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544585525\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544919490\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544919711\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544920033\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n## ...\n\n\nExplaining how to parse XML is beyond the scope of this blog post, but\nlet me just mention I used a search engine to answer questions such as\n\u201cXPath extract nodes by name\u201d, \u201cxml2 namespace\u201d. I reckon my code could\nbe more elegant if I knew more XPath.\n\nLet me start with threads.\n\n# extract nodes corresponding to comments\nthreads_nodes <- xml2::xml_find_all(export, \"d1:thread\")\nthreads_nodes\n\n\n## {xml_nodeset (283)}\n##   <thread dsq:id=\"5169974011\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5177145143\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5192091523\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5490361085\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5490455492\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5496622766\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5496655533\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5499530252\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5499566886\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5503605733\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5503629818\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5519522381\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5521172753\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5523856167\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5523862926\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544585525\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544919490\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544919711\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544920033\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544931944\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n## ...\n\n\n# extract interesting information from each node,\n# information that is potentially nested\nthreads <- tibble::tibble(\n  thread_id = xml2::xml_attr( threads_nodes, \n                              \"id\"),\n  title = xml2::xml_text(\n    xml2::xml_find_all(threads_nodes, \"d1:title\")\n    ))\n\n\nNow on to comments\u2026\n\n# extract nodes corresponding to comments\ncomments_nodes <- xml2::xml_find_all(export, \"d1:post\") \ncomments_nodes\n\n\n## {xml_nodeset (206)}\n##   <post dsq:id=\"2916181700\">\\n  <id\/>\\n  <message><![CDATA[<p>La poss ...\n##   <post dsq:id=\"3118121105\">\\n  <id\/>\\n  <message><![CDATA[<p>Great b ...\n##   <post dsq:id=\"3118236082\">\\n  <id\/>\\n  <message><![CDATA[<p>Nice Ma ...\n##   <post dsq:id=\"3118757895\">\\n  <id\/>\\n  <message><![CDATA[<p>Thanks  ...\n##   <post dsq:id=\"3118758593\">\\n  <id\/>\\n  <message><![CDATA[<p>Thanks  ...\n##   <post dsq:id=\"3118783826\">\\n  <id\/>\\n  <message><![CDATA[<p>I love  ...\n##   <post dsq:id=\"3118785805\">\\n  <id\/>\\n  <message><![CDATA[<p>Thanks! ...\n##   <post dsq:id=\"3121124991\">\\n  <id\/>\\n  <message><![CDATA[<p>Chouett ...\n##   <post dsq:id=\"3121137475\">\\n  <id\/>\\n  <message><![CDATA[<p>Oops qu ...\n##  <post dsq:id=\"3121945521\">\\n  <id\/>\\n  <message><![CDATA[<p>I poste ...\n##  <post dsq:id=\"3122653372\">\\n  <id\/>\\n  <message><![CDATA[<p>Another ...\n##  <post dsq:id=\"3122759373\">\\n  <id\/>\\n  <message><![CDATA[<p>Thank y ...\n##  <post dsq:id=\"3123851616\">\\n  <id\/>\\n  <message><![CDATA[<p>Great s ...\n##  <post dsq:id=\"3126340152\">\\n  <id\/>\\n  <message><![CDATA[<p>Once ag ...\n##  <post dsq:id=\"3126343942\">\\n  <id\/>\\n  <message><![CDATA[<p>Thank y ...\n##  <post dsq:id=\"3140125477\">\\n  <id\/>\\n  <message><![CDATA[<p>The ide ...\n##  <post dsq:id=\"3140136118\">\\n  <id\/>\\n  <message><![CDATA[<p>Thank y ...\n##  <post dsq:id=\"3140161542\">\\n  <id\/>\\n  <message><![CDATA[<p>Not rel ...\n##  <post dsq:id=\"3140329480\">\\n  <id\/>\\n  <message><![CDATA[<p>Yes def ...\n##  <post dsq:id=\"3150961786\">\\n  <id\/>\\n  <message><![CDATA[<p>That's  ...\n## ...\n\n\n# extract interesting information from each node,\n# information that is potentially nested\ncomments <- tibble::tibble(\n  thread_id = xml2::xml_attr(\n    xml2::xml_find_all(comments_nodes, \"d1:thread\"), \n    \"id\"),\n  message = xml2::xml_text(\n    xml2::xml_find_all(comments_nodes, \"d1:message\")\n    ),\n  date =  xml2::xml_text(\n    xml2::xml_find_all(comments_nodes, \"d1:createdAt\")\n    ),\n  deleted = xml2::xml_text(\n    xml2::xml_find_all(comments_nodes, \"d1:isDeleted\")\n    ),\n  spam = xml2::xml_text(\n    xml2::xml_find_all(comments_nodes, \"d1:isSpam\")\n    ),\n  author = xml2::xml_text(\n    xml2::xml_find_all(\n    xml2::xml_find_all(comments_nodes, \"d1:author\"), \n    \"d1:name\")))\n  \ncomments <- dplyr::mutate(comments,\n                          date = anytime::anydate(date),\n                          deleted = deleted == \"true\",\n                          spam = spam == \"true\")\n\n\nI was then able to join the two tables.\n\ncomments <- dplyr::left_join(comments, threads,\n                             by = \"thread_id\")\nreadr::write_csv(comments, \"comments.csv\")\n\ncomments\n\n\n## # A tibble: 11 x 2\n##    message                                        title                    \n##    <chr>                                          <chr>                    \n##  1 \"<p>Great blog post, thank you! I really appr\u2026 French villages and a so\u2026\n##  2 <p>Nice Ma\u00eblle!<\/p><p>Good, interesting quest\u2026 French villages and a so\u2026\n##  3 <p>Thanks Nick!<\/p>                            French villages and a so\u2026\n##  4 <p>Thanks Lisa! Toponomy is quite fascinating\u2026 French villages and a so\u2026\n##  5 \"<p>I love this! I wonder, would it be possib\u2026 French villages and a so\u2026\n##  6 <p>Thanks! I got a similar question on Twitte\u2026 French villages and a so\u2026\n##  7 \"<p>Chouette! Mais la mer c'est \\\"sea\\\", \\\"se\u2026 French villages and a so\u2026\n##  8 <p>Oops quelle faute de frappe idiote, je la \u2026 French villages and a so\u2026\n##  9 \"<p>I posted an update! <a href=\\\"http:\/\/www.\u2026 French villages and a so\u2026\n## 10 <p>Another good one, Ma\u00eblle! It's a great exa\u2026 More water, a bit more a\u2026\n## 11 <p>Thank you! Lol on ninja grep skills, I wis\u2026 More water, a bit more a\u2026\n\n\nI got a pretty nice rectangle in the end, that could be used for some\ntext analysis, but in my case, I mostly view it as memorabilia. I hope\nany comment warranting action had been tackled. I wrote 93\n(sum(comments$author == \"Ma\u00eblle Salmon\")) out of the 206 comments\n(Disqus classified a few comments as spam, 15 to be exact, of which a\nfew were informative comments. ), because I tend to answer comments, if\nonly with a simple thank you! Now that I have GitHub issues as comments,\nI could also answer with emojis.\n\nIt was fun because I didn\u2019t even remember about some notes I had gotten.\nI hope you don\u2019t feel slighted, dear reader, now that I keep these old\ncomments to myself! Be happy you\u2019re no longer tracked.\n\nGetting rid of Disqus\n\nI removed Disqus from my website, and my website from Disqus!\n\nTo remove Disqus from a Hugo website, one can, depending on the\nwebsite\u2019s theme:\n\n\nuse Hugo\u2019s Disqus GDPR\nsetting if the website\ntheme uses Hugo\u2019s built-in Disqus template (i.e.\u00a0if there\u2019s a\nmention of a internal Disqus\npartial,\nnot of a Disqus partial stored somewhere in the theme files);\n\nor remove one\u2019s Disqus username from the config file, or remove the\nDisqus partial mention in the post template. To do that, the best\nprocess is not to edit the e.g.\u00a0post\/single.html file in the theme\nfolder, but instead to save it and edit it under\nlayouts\/post\/single.html. Refer to the blogdown book for more\ninformation.\n\nAfter that, there should be no mention of Disqus scripts in your website\nsource.\n\nThen, to delete my website from my Disqus account, following Disqus\nguidance,\nI logged into my account and, after exporting my website\u2019s comments,\nconfirmed I wanted to do that and voil\u00e0!\n\nAdding Utterances\n\nTo add Utterances, a \u201clightweight comments widget built on GitHub\nissues\u201d, I also followed official\nguidance:\n\n\nI installed the app to my website GitHub repo.\n\nIn my custom single.html layout for posts (again, refer to the\nblogdown book for clear information on the\ntopic), I\nadded the script tag corresponding to Utterances. The docs linked\nabove help you configure the appearance of the widget.\n\nHere\u2019s the Utterances script tag for my blog. The label needs to have been created for your website repotterances can only use existing issue labels.\n\n<script src=\"https:\/\/utteranc.es\/client.js\"\n        repo=\"maelle\/simplymaelle\"\n        issue-term=\"title\"\n        label=\"comments :speech_balloon:\"\n        theme=\"github-light\"\n        crossorigin=\"anonymous\"\n        async>\n<\/script>\n\n\nI then wrote a comment under one of my\nposts to make sure things\nworked. I also took a few seconds to add my site to the list of sites\nusing Utterances. Overall,\nI found the process easy, as I had the first time I installed Utterances\non a blogdown website.\n\nI am aware that a downside of Utterances is that it is tied to GitHub.\nHowever, I am not afraid of switching to yet another tool in the future,\nand hope not too many potential commenters will be turned off by the\nnecessity to use a GitHub account to comment.\n\nConclusion\n\nIn this post I explained how I removed Disqus from my blog and vice\nversa, and how I installed Utterances instead. What I did not do was\nanalyzing the Disqus data. I moreover did not try to transfer old\ncomments to the new system, partly because that\u2019d mean removing\ncommenters\u2019 ownership on what they had written.\n\nIn his tweet that motivated me to say goodbye to\nDisqus, Bob\nwrote \u201cYet another service where you and your site visitors are the\nproduct. Plus it acts like malicious javascript.\u201d. I therefore feel a\nbit better about this website! Now, I didn\u2019t have a ton of comments, and\nI don\u2019t have a real need for moderating comments, so maybe you\u2019ll make a\ndifferent decision for your website. I\u2019d be glad to hear about it\u2026 in\nthe comments section below! Also feel free to tell me if you explore\nyour own Disqus data in a more thorough way than I!","primaryImageOfPage":{"@id":"https:\/\/www.r-bloggers.com\/2019\/10\/goodbye-disqus-hello-utterances\/#primaryimage"},"mainContentOfPage":[[{"@context":"https:\/\/schema.org","@type":"SiteNavigationElement","@id":"https:\/\/www.r-bloggers.com\/#top nav","name":"Home","url":"https:\/\/www.r-bloggers.com"},{"@context":"https:\/\/schema.org","@type":"SiteNavigationElement","@id":"https:\/\/www.r-bloggers.com\/#top nav","name":"About","url":"http:\/\/www.r-bloggers.com\/about\/"},{"@context":"https:\/\/schema.org","@type":"SiteNavigationElement","@id":"https:\/\/www.r-bloggers.com\/#top nav","name":"RSS","url":"https:\/\/feeds.feedburner.com\/RBloggers"},{"@context":"https:\/\/schema.org","@type":"SiteNavigationElement","@id":"https:\/\/www.r-bloggers.com\/#top nav","name":"add your blog!","url":"http:\/\/www.r-bloggers.com\/add-your-blog\/"},{"@context":"https:\/\/schema.org","@type":"SiteNavigationElement","@id":"https:\/\/www.r-bloggers.com\/#top nav","name":"Learn R","url":"https:\/\/www.r-bloggers.com\/how-to-learn-r-2\/"},{"@context":"https:\/\/schema.org","@type":"SiteNavigationElement","@id":"https:\/\/www.r-bloggers.com\/#top nav","name":"R jobs","url":"https:\/\/www.r-users.com\/"},{"@context":"https:\/\/schema.org","@type":"SiteNavigationElement","@id":"https:\/\/www.r-bloggers.com\/#top nav","name":"Submit a new job (it's free)","url":"https:\/\/www.r-users.com\/submit-job\/"},{"@context":"https:\/\/schema.org","@type":"SiteNavigationElement","@id":"https:\/\/www.r-bloggers.com\/#top nav","name":"Browse latest jobs (also free)","url":"https:\/\/www.r-users.com\/"},{"@context":"https:\/\/schema.org","@type":"SiteNavigationElement","@id":"https:\/\/www.r-bloggers.com\/#top nav","name":"Contact us","url":"http:\/\/www.r-bloggers.com\/contact-us\/"}]],"isPartOf":{"@id":"https:\/\/www.r-bloggers.com#website"},"breadcrumb":{"@id":"https:\/\/www.r-bloggers.com\/2019\/10\/goodbye-disqus-hello-utterances\/#breadcrumb"}},{"@type":"BreadcrumbList","@id":"https:\/\/www.r-bloggers.com\/2019\/10\/goodbye-disqus-hello-utterances\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":"https:\/\/www.r-bloggers.com","name":"R-bloggers"}},{"@type":"ListItem","position":2,"item":{"@id":"https:\/\/www.r-bloggers.com\/category\/r-bloggers\/","name":"R bloggers"}},{"@type":"ListItem","position":3,"item":{"@id":"https:\/\/www.r-bloggers.com\/2019\/10\/goodbye-disqus-hello-utterances\/","name":"Goodbye, Disqus! Hello, Utterances! | R-bloggers"}}]},{"@type":"Article","@id":"https:\/\/www.r-bloggers.com\/2019\/10\/goodbye-disqus-hello-utterances\/#article","url":"https:\/\/www.r-bloggers.com\/2019\/10\/goodbye-disqus-hello-utterances\/","inLanguage":"en-US","mainEntityOfPage":"https:\/\/www.r-bloggers.com\/2019\/10\/goodbye-disqus-hello-utterances\/#webpage","headline":"Goodbye, Disqus! Hello, Utterances! | R-bloggers","description":"Removing Disqus from my blogdown blog had been on my mind for a while,\never since I saw Bob Rudis\u2019 tweet enjoining Noam Ross to not use\nit for his\nbrand-new website.\nThe same Twitter thread introduced me to\nUtterances, a \u201clightweight\ncomments widget built on GitHub issues\u201d, which I have at last installed\nto my blog in lieu of Disqus. How did I manage to not lose anything of\nvalue? How easy was it to switch tools? Read on to learn more!\n\n\n\nWas saying goodbye to Disqus hard?\n\nRemoving Disqus was neither emotionally nor technically hard.\n\nComments I (kinda) let go of\n\nTo deal with my fear of loss, I exported all the comments to an\nXML.\nIt means I have a backup, that in theory I could explore within R! I\u2019ll\nshow some XML wrangling a bit later. The export does contain Disqus\nusernames and names which means I\u2019m now responsible for person\nidentifying information that Disqus collected.\n\nThanks a lot to commenters in the past system for taking the time to\nleave me a note: it helped me keep blogging!\n\nThe Disqus XML contains information about\n\n\nposts that are in fact comments, not blog posts, along with\ntheir threading information i.e.\u00a0both whose blog post the comment\nwas on, and if relevant, which comment the comment is an answer to;\n\nthreads, one thread per comment but not necessarily one comment\nper thread, and potentially more than one thread per blog post. Each\ntop-level comment is a thread, but a website page with no comment\nalso gets a thread, obviously empty.\n\nIn the code below, I shall\nrectangle the\ninformation about threads (id, title) and about comments (message,\nauthor name, date, thread id, was it spam, was it deleted) using the\nxml2\npackage.\n\nexport <- xml2::read_xml(\"data\/disqus-export.xml\")\nexport\n\n\n## {xml_document}\n## <disqus schemaLocation=\"http:\/\/disqus.com\/api\/schemas\/1.0\/disqus.xsd http:\/\/disqus.com\/api\/schemas\/1.0\/disqus-internals.xsd\" xmlns=\"http:\/\/disqus.com\" xmlns:dsq=\"http:\/\/disqus.com\/disqus-internals\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\">\n##   <category dsq:id=\"5516420\">\\n  <forum>masalmon<\/forum>\\n  <title>Ge ...\n##   <thread dsq:id=\"5169974011\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5177145143\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5192091523\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5490361085\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5490455492\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5496622766\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5496655533\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5499530252\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5499566886\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5503605733\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5503629818\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5519522381\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5521172753\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5523856167\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5523862926\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544585525\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544919490\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544919711\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544920033\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n## ...\n\n\nExplaining how to parse XML is beyond the scope of this blog post, but\nlet me just mention I used a search engine to answer questions such as\n\u201cXPath extract nodes by name\u201d, \u201cxml2 namespace\u201d. I reckon my code could\nbe more elegant if I knew more XPath.\n\nLet me start with threads.\n\n# extract nodes corresponding to comments\nthreads_nodes <- xml2::xml_find_all(export, \"d1:thread\")\nthreads_nodes\n\n\n## {xml_nodeset (283)}\n##   <thread dsq:id=\"5169974011\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5177145143\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5192091523\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5490361085\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5490455492\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5496622766\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5496655533\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5499530252\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##   <thread dsq:id=\"5499566886\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5503605733\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5503629818\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5519522381\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5521172753\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5523856167\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5523862926\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544585525\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544919490\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544919711\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544920033\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n##  <thread dsq:id=\"5544931944\">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ...\n## ...\n\n\n# extract interesting information from each node,\n# information that is potentially nested\nthreads <- tibble::tibble(\n  thread_id = xml2::xml_attr( threads_nodes, \n                              \"id\"),\n  title = xml2::xml_text(\n    xml2::xml_find_all(threads_nodes, \"d1:title\")\n    ))\n\n\nNow on to comments\u2026\n\n# extract nodes corresponding to comments\ncomments_nodes <- xml2::xml_find_all(export, \"d1:post\") \ncomments_nodes\n\n\n## {xml_nodeset (206)}\n##   <post dsq:id=\"2916181700\">\\n  <id\/>\\n  <message><![CDATA[<p>La poss ...\n##   <post dsq:id=\"3118121105\">\\n  <id\/>\\n  <message><![CDATA[<p>Great b ...\n##   <post dsq:id=\"3118236082\">\\n  <id\/>\\n  <message><![CDATA[<p>Nice Ma ...\n##   <post dsq:id=\"3118757895\">\\n  <id\/>\\n  <message><![CDATA[<p>Thanks  ...\n##   <post dsq:id=\"3118758593\">\\n  <id\/>\\n  <message><![CDATA[<p>Thanks  ...\n##   <post dsq:id=\"3118783826\">\\n  <id\/>\\n  <message><![CDATA[<p>I love  ...\n##   <post dsq:id=\"3118785805\">\\n  <id\/>\\n  <message><![CDATA[<p>Thanks! ...\n##   <post dsq:id=\"3121124991\">\\n  <id\/>\\n  <message><![CDATA[<p>Chouett ...\n##   <post dsq:id=\"3121137475\">\\n  <id\/>\\n  <message><![CDATA[<p>Oops qu ...\n##  <post dsq:id=\"3121945521\">\\n  <id\/>\\n  <message><![CDATA[<p>I poste ...\n##  <post dsq:id=\"3122653372\">\\n  <id\/>\\n  <message><![CDATA[<p>Another ...\n##  <post dsq:id=\"3122759373\">\\n  <id\/>\\n  <message><![CDATA[<p>Thank y ...\n##  <post dsq:id=\"3123851616\">\\n  <id\/>\\n  <message><![CDATA[<p>Great s ...\n##  <post dsq:id=\"3126340152\">\\n  <id\/>\\n  <message><![CDATA[<p>Once ag ...\n##  <post dsq:id=\"3126343942\">\\n  <id\/>\\n  <message><![CDATA[<p>Thank y ...\n##  <post dsq:id=\"3140125477\">\\n  <id\/>\\n  <message><![CDATA[<p>The ide ...\n##  <post dsq:id=\"3140136118\">\\n  <id\/>\\n  <message><![CDATA[<p>Thank y ...\n##  <post dsq:id=\"3140161542\">\\n  <id\/>\\n  <message><![CDATA[<p>Not rel ...\n##  <post dsq:id=\"3140329480\">\\n  <id\/>\\n  <message><![CDATA[<p>Yes def ...\n##  <post dsq:id=\"3150961786\">\\n  <id\/>\\n  <message><![CDATA[<p>That's  ...\n## ...\n\n\n# extract interesting information from each node,\n# information that is potentially nested\ncomments <- tibble::tibble(\n  thread_id = xml2::xml_attr(\n    xml2::xml_find_all(comments_nodes, \"d1:thread\"), \n    \"id\"),\n  message = xml2::xml_text(\n    xml2::xml_find_all(comments_nodes, \"d1:message\")\n    ),\n  date =  xml2::xml_text(\n    xml2::xml_find_all(comments_nodes, \"d1:createdAt\")\n    ),\n  deleted = xml2::xml_text(\n    xml2::xml_find_all(comments_nodes, \"d1:isDeleted\")\n    ),\n  spam = xml2::xml_text(\n    xml2::xml_find_all(comments_nodes, \"d1:isSpam\")\n    ),\n  author = xml2::xml_text(\n    xml2::xml_find_all(\n    xml2::xml_find_all(comments_nodes, \"d1:author\"), \n    \"d1:name\")))\n  \ncomments <- dplyr::mutate(comments,\n                          date = anytime::anydate(date),\n                          deleted = deleted == \"true\",\n                          spam = spam == \"true\")\n\n\nI was then able to join the two tables.\n\ncomments <- dplyr::left_join(comments, threads,\n                             by = \"thread_id\")\nreadr::write_csv(comments, \"comments.csv\")\n\ncomments\n\n\n## # A tibble: 11 x 2\n##    message                                        title                    \n##    <chr>                                          <chr>                    \n##  1 \"<p>Great blog post, thank you! I really appr\u2026 French villages and a so\u2026\n##  2 <p>Nice Ma\u00eblle!<\/p><p>Good, interesting quest\u2026 French villages and a so\u2026\n##  3 <p>Thanks Nick!<\/p>                            French villages and a so\u2026\n##  4 <p>Thanks Lisa! Toponomy is quite fascinating\u2026 French villages and a so\u2026\n##  5 \"<p>I love this! I wonder, would it be possib\u2026 French villages and a so\u2026\n##  6 <p>Thanks! I got a similar question on Twitte\u2026 French villages and a so\u2026\n##  7 \"<p>Chouette! Mais la mer c'est \\\"sea\\\", \\\"se\u2026 French villages and a so\u2026\n##  8 <p>Oops quelle faute de frappe idiote, je la \u2026 French villages and a so\u2026\n##  9 \"<p>I posted an update! <a href=\\\"http:\/\/www.\u2026 French villages and a so\u2026\n## 10 <p>Another good one, Ma\u00eblle! It's a great exa\u2026 More water, a bit more a\u2026\n## 11 <p>Thank you! Lol on ninja grep skills, I wis\u2026 More water, a bit more a\u2026\n\n\nI got a pretty nice rectangle in the end, that could be used for some\ntext analysis, but in my case, I mostly view it as memorabilia. I hope\nany comment warranting action had been tackled. I wrote 93\n(sum(comments$author == \"Ma\u00eblle Salmon\")) out of the 206 comments\n(Disqus classified a few comments as spam, 15 to be exact, of which a\nfew were informative comments. ), because I tend to answer comments, if\nonly with a simple thank you! Now that I have GitHub issues as comments,\nI could also answer with emojis.\n\nIt was fun because I didn\u2019t even remember about some notes I had gotten.\nI hope you don\u2019t feel slighted, dear reader, now that I keep these old\ncomments to myself! Be happy you\u2019re no longer tracked.\n\nGetting rid of Disqus\n\nI removed Disqus from my website, and my website from Disqus!\n\nTo remove Disqus from a Hugo website, one can, depending on the\nwebsite\u2019s theme:\n\n\nuse Hugo\u2019s Disqus GDPR\nsetting if the website\ntheme uses Hugo\u2019s built-in Disqus template (i.e.\u00a0if there\u2019s a\nmention of a internal Disqus\npartial,\nnot of a Disqus partial stored somewhere in the theme files);\n\nor remove one\u2019s Disqus username from the config file, or remove the\nDisqus partial mention in the post template. To do that, the best\nprocess is not to edit the e.g.\u00a0post\/single.html file in the theme\nfolder, but instead to save it and edit it under\nlayouts\/post\/single.html. Refer to the blogdown book for more\ninformation.\n\nAfter that, there should be no mention of Disqus scripts in your website\nsource.\n\nThen, to delete my website from my Disqus account, following Disqus\nguidance,\nI logged into my account and, after exporting my website\u2019s comments,\nconfirmed I wanted to do that and voil\u00e0!\n\nAdding Utterances\n\nTo add Utterances, a \u201clightweight comments widget built on GitHub\nissues\u201d, I also followed official\nguidance:\n\n\nI installed the app to my website GitHub repo.\n\nIn my custom single.html layout for posts (again, refer to the\nblogdown book for clear information on the\ntopic), I\nadded the script tag corresponding to Utterances. The docs linked\nabove help you configure the appearance of the widget.\n\nHere\u2019s the Utterances script tag for my blog. The label needs to have been created for your website repotterances can only use existing issue labels.\n\n<script src=\"https:\/\/utteranc.es\/client.js\"\n        repo=\"maelle\/simplymaelle\"\n        issue-term=\"title\"\n        label=\"comments :speech_balloon:\"\n        theme=\"github-light\"\n        crossorigin=\"anonymous\"\n        async>\n<\/script>\n\n\nI then wrote a comment under one of my\nposts to make sure things\nworked. I also took a few seconds to add my site to the list of sites\nusing Utterances. Overall,\nI found the process easy, as I had the first time I installed Utterances\non a blogdown website.\n\nI am aware that a downside of Utterances is that it is tied to GitHub.\nHowever, I am not afraid of switching to yet another tool in the future,\nand hope not too many potential commenters will be turned off by the\nnecessity to use a GitHub account to comment.\n\nConclusion\n\nIn this post I explained how I removed Disqus from my blog and vice\nversa, and how I installed Utterances instead. What I did not do was\nanalyzing the Disqus data. I moreover did not try to transfer old\ncomments to the new system, partly because that\u2019d mean removing\ncommenters\u2019 ownership on what they had written.\n\nIn his tweet that motivated me to say goodbye to\nDisqus, Bob\nwrote \u201cYet another service where you and your site visitors are the\nproduct. Plus it acts like malicious javascript.\u201d. I therefore feel a\nbit better about this website! Now, I didn\u2019t have a ton of comments, and\nI don\u2019t have a real need for moderating comments, so maybe you\u2019ll make a\ndifferent decision for your website. I\u2019d be glad to hear about it\u2026 in\nthe comments section below! Also feel free to tell me if you explore\nyour own Disqus data in a more thorough way than I!","articleBody":"Removing Disqus from my blogdown blog had been on my mind for a while, ever since I saw Bob Rudis\u2019 tweet enjoining Noam Ross to not use it for his brand-new website. The same Twitter thread introduced me to Utterances, a \u201clightweight comments widget built on GitHub issues\u201d, which I have at last installed to my blog in lieu of Disqus. How did I manage to not lose anything of value? How easy was it to switch tools? Read on to learn more!    Was saying goodbye to Disqus hard?  Removing Disqus was neither emotionally nor technically hard.  Comments I (kinda) let go of  To deal with my fear of loss, I exported all the comments to an XML. It means I have a backup, that in theory I could explore within R! I\u2019ll show some XML wrangling a bit later. The export does contain Disqus usernames and names which means I\u2019m now responsible for person identifying information that Disqus collected.  Thanks a lot to commenters in the past system for taking the time to leave me a note: it helped me keep blogging!  The Disqus XML contains information about   posts that are in fact comments, not blog posts, along with their threading information i.e.\u00a0both whose blog post the comment was on, and if relevant, which comment the comment is an answer to;  threads, one thread per comment but not necessarily one comment per thread, and potentially more than one thread per blog post. Each top-level comment is a thread, but a website page with no comment also gets a thread, obviously empty.   In the code below, I shall rectangle the information about threads (id, title) and about comments (message, author name, date, thread id, was it spam, was it deleted) using the xml2 package.  export <- xml2::read_xml("data\/disqus-export.xml") export   ## {xml_document} ## <disqus schemaLocation"http:\/\/disqus.com\/api\/schemas\/1.0\/disqus.xsd http:\/\/disqus.com\/api\/schemas\/1.0\/disqus-internals.xsd" xmlns"http:\/\/disqus.com" xmlns:dsq"http:\/\/disqus.com\/disqus-internals" xmlns:xsi"http:\/\/www.w3.org\/2001\/XMLSchema-instance"> ##   <category dsq:id"5516420">\\n  <forum>masalmon<\/forum>\\n  <title>Ge ... ##   <thread dsq:id"5169974011">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5177145143">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5192091523">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5490361085">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5490455492">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5496622766">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5496655533">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5499530252">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5499566886">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5503605733">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5503629818">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5519522381">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5521172753">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5523856167">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5523862926">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5544585525">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5544919490">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5544919711">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5544920033">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ## ...   Explaining how to parse XML is beyond the scope of this blog post, but let me just mention I used a search engine to answer questions such as \u201cXPath extract nodes by name\u201d, \u201cxml2 namespace\u201d. I reckon my code could be more elegant if I knew more XPath.  Let me start with threads.  # extract nodes corresponding to comments threads_nodes <- xml2::xml_find_all(export, "d1:thread") threads_nodes   ## {xml_nodeset (283)} ##   <thread dsq:id"5169974011">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5177145143">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5192091523">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5490361085">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5490455492">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5496622766">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5496655533">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5499530252">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##   <thread dsq:id"5499566886">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5503605733">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5503629818">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5519522381">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5521172753">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5523856167">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5523862926">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5544585525">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5544919490">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5544919711">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5544920033">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ##  <thread dsq:id"5544931944">\\n  <id\/>\\n  <forum>masalmon<\/forum>\\n  ... ## ...   # extract interesting information from each node, # information that is potentially nested threads <- tibble::tibble(   thread_id  xml2::xml_attr( threads_nodes,                                "id"),   title  xml2::xml_text(     xml2::xml_find_all(threads_nodes, "d1:title")     ))   Now on to comments\u2026  # extract nodes corresponding to comments comments_nodes <- xml2::xml_find_all(export, "d1:post")  comments_nodes   ## {xml_nodeset (206)} ##   <post dsq:id"2916181700">\\n  <id\/>\\n  <message><![CDATA[<p>La poss ... ##   <post dsq:id"3118121105">\\n  <id\/>\\n  <message><![CDATA[<p>Great b ... ##   <post dsq:id"3118236082">\\n  <id\/>\\n  <message><![CDATA[<p>Nice Ma ... ##   <post dsq:id"3118757895">\\n  <id\/>\\n  <message><![CDATA[<p>Thanks  ... ##   <post dsq:id"3118758593">\\n  <id\/>\\n  <message><![CDATA[<p>Thanks  ... ##   <post dsq:id"3118783826">\\n  <id\/>\\n  <message><![CDATA[<p>I love  ... ##   <post dsq:id"3118785805">\\n  <id\/>\\n  <message><![CDATA[<p>Thanks! ... ##   <post dsq:id"3121124991">\\n  <id\/>\\n  <message><![CDATA[<p>Chouett ... ##   <post dsq:id"3121137475">\\n  <id\/>\\n  <message><![CDATA[<p>Oops qu ... ##  <post dsq:id"3121945521">\\n  <id\/>\\n  <message><![CDATA[<p>I poste ... ##  <post dsq:id"3122653372">\\n  <id\/>\\n  <message><![CDATA[<p>Another ... ##  <post dsq:id"3122759373">\\n  <id\/>\\n  <message><![CDATA[<p>Thank y ... ##  <post dsq:id"3123851616">\\n  <id\/>\\n  <message><![CDATA[<p>Great s ... ##  <post dsq:id"3126340152">\\n  <id\/>\\n  <message><![CDATA[<p>Once ag ... ##  <post dsq:id"3126343942">\\n  <id\/>\\n  <message><![CDATA[<p>Thank y ... ##  <post dsq:id"3140125477">\\n  <id\/>\\n  <message><![CDATA[<p>The ide ... ##  <post dsq:id"3140136118">\\n  <id\/>\\n  <message><![CDATA[<p>Thank y ... ##  <post dsq:id"3140161542">\\n  <id\/>\\n  <message><![CDATA[<p>Not rel ... ##  <post dsq:id"3140329480">\\n  <id\/>\\n  <message><![CDATA[<p>Yes def ... ##  <post dsq:id"3150961786">\\n  <id\/>\\n  <message><![CDATA[<p>That's  ... ## ...   # extract interesting information from each node, # information that is potentially nested comments <- tibble::tibble(   thread_id  xml2::xml_attr(     xml2::xml_find_all(comments_nodes, "d1:thread"),      "id"),   message  xml2::xml_text(     xml2::xml_find_all(comments_nodes, "d1:message")     ),   date   xml2::xml_text(     xml2::xml_find_all(comments_nodes, "d1:createdAt")     ),   deleted  xml2::xml_text(     xml2::xml_find_all(comments_nodes, "d1:isDeleted")     ),   spam  xml2::xml_text(     xml2::xml_find_all(comments_nodes, "d1:isSpam")     ),   author  xml2::xml_text(     xml2::xml_find_all(     xml2::xml_find_all(comments_nodes, "d1:author"),      "d1:name")))    comments <- dplyr::mutate(comments,                           date  anytime::anydate(date),                           deleted  deleted  "true",                           spam  spam  "true")   I was then able to join the two tables.  comments <- dplyr::left_join(comments, threads,                              by  "thread_id") readr::write_csv(comments, "comments.csv")  comments   ## # A tibble: 11 x 2 ##    message                                        title                     ##    <chr>                                          <chr>                     ##  1 "<p>Great blog post, thank you! I really appr\u2026 French villages and a so\u2026 ##  2 <p>Nice Ma\u00eblle!<\/p><p>Good, interesting quest\u2026 French villages and a so\u2026 ##  3 <p>Thanks Nick!<\/p>                            French villages and a so\u2026 ##  4 <p>Thanks Lisa! Toponomy is quite fascinating\u2026 French villages and a so\u2026 ##  5 "<p>I love this! I wonder, would it be possib\u2026 French villages and a so\u2026 ##  6 <p>Thanks! I got a similar question on Twitte\u2026 French villages and a so\u2026 ##  7 "<p>Chouette! Mais la mer c'est \\"sea\\", \\"se\u2026 French villages and a so\u2026 ##  8 <p>Oops quelle faute de frappe idiote, je la \u2026 French villages and a so\u2026 ##  9 "<p>I posted an update! <a href\\"http:\/\/www.\u2026 French villages and a so\u2026 ## 10 <p>Another good one, Ma\u00eblle! It's a great exa\u2026 More water, a bit more a\u2026 ## 11 <p>Thank you! Lol on ninja grep skills, I wis\u2026 More water, a bit more a\u2026   I got a pretty nice rectangle in the end, that could be used for some text analysis, but in my case, I mostly view it as memorabilia. I hope any comment warranting action had been tackled. I wrote 93 (sum(comments$author  "Ma\u00eblle Salmon")) out of the 206 comments (Disqus classified a few comments as spam, 15 to be exact, of which a few were informative comments. ), because I tend to answer comments, if only with a simple thank you! Now that I have GitHub issues as comments, I could also answer with emojis.  It was fun because I didn\u2019t even remember about some notes I had gotten. I hope you don\u2019t feel slighted, dear reader, now that I keep these old comments to myself! Be happy you\u2019re no longer tracked.  Getting rid of Disqus  I removed Disqus from my website, and my website from Disqus!  To remove Disqus from a Hugo website, one can, depending on the website\u2019s theme:   use Hugo\u2019s Disqus GDPR setting if the website theme uses Hugo\u2019s built-in Disqus template (i.e.\u00a0if there\u2019s a mention of a internal Disqus partial, not of a Disqus partial stored somewhere in the theme files);  or remove one\u2019s Disqus username from the config file, or remove the Disqus partial mention in the post template. To do that, the best process is not to edit the e.g.\u00a0post\/single.html file in the theme folder, but instead to save it and edit it under layouts\/post\/single.html. Refer to the blogdown book for more information.   After that, there should be no mention of Disqus scripts in your website source.  Then, to delete my website from my Disqus account, following Disqus guidance, I logged into my account and, after exporting my website\u2019s comments, confirmed I wanted to do that and voil\u00e0!  Adding Utterances  To add Utterances, a \u201clightweight comments widget built on GitHub issues\u201d, I also followed official guidance:   I installed the app to my website GitHub repo.  In my custom single.html layout for posts (again, refer to the blogdown book for clear information on the topic), I added the script tag corresponding to Utterances. The docs linked above help you configure the appearance of the widget.   Here\u2019s the Utterances script tag for my blog. The label needs to have been created for your website repotterances can only use existing issue labels.  <script src"https:\/\/utteranc.es\/client.js"         repo"maelle\/simplymaelle"         issue-term"title"         label"comments :speech_balloon:"         theme"github-light"         crossorigin"anonymous"         async> <\/script>   I then wrote a comment under one of my posts to make sure things worked. I also took a few seconds to add my site to the list of sites using Utterances. Overall, I found the process easy, as I had the first time I installed Utterances on a blogdown website.  I am aware that a downside of Utterances is that it is tied to GitHub. However, I am not afraid of switching to yet another tool in the future, and hope not too many potential commenters will be turned off by the necessity to use a GitHub account to comment.  Conclusion  In this post I explained how I removed Disqus from my blog and vice versa, and how I installed Utterances instead. What I did not do was analyzing the Disqus data. I moreover did not try to transfer old comments to the new system, partly because that\u2019d mean removing commenters\u2019 ownership on what they had written.  In his tweet that motivated me to say goodbye to Disqus, Bob wrote \u201cYet another service where you and your site visitors are the product. Plus it acts like malicious javascript.\u201d. I therefore feel a bit better about this website! Now, I didn\u2019t have a ton of comments, and I don\u2019t have a real need for moderating comments, so maybe you\u2019ll make a different decision for your website. I\u2019d be glad to hear about it\u2026 in the comments section below! Also feel free to tell me if you explore your own Disqus data in a more thorough way than I!","keywords":"","datePublished":"2019-10-01T18:00:00-06:00","dateModified":"2019-10-01T18:00:00-06:00","author":{"@type":"Person","name":"Posts on Ma\u00eblle's R blog","description":"","url":"https:\/\/www.r-bloggers.com\/author\/posts-on-maelles-r-blog\/","sameAs":["https:\/\/masalmon.eu\/post\/"],"image":{"@type":"ImageObject","url":"https:\/\/secure.gravatar.com\/avatar\/5979402a47eaf6b8a7f595e6f2bf2f4a?s=96&d=mm&r=g","height":96,"width":96}},"publisher":{"@id":"https:\/\/www.r-bloggers.com#Organization"},"image":{"@type":"ImageObject","@id":"https:\/\/www.r-bloggers.com\/2019\/10\/goodbye-disqus-hello-utterances\/#primaryimage","url":"http:\/\/www.r-bloggers.com\/wp-content\/uploads\/2020\/07\/R_logo.svg_.png","width":"1280","height":"992"},"isPartOf":{"@id":"https:\/\/www.r-bloggers.com\/2019\/10\/goodbye-disqus-hello-utterances\/#webpage"}}]}]
</script>

    <script>
        var snp_f = [];
        var snp_hostname = new RegExp(location.host);
        var snp_http = new RegExp("^(http|https)://", "i");
        var snp_cookie_prefix = '';
        var snp_separate_cookies = false;
        var snp_ajax_url = 'https://www.r-bloggers.com/wp-admin/admin-ajax.php';
		var snp_ajax_nonce = '10af8f6321';
        var snp_ignore_cookies = false;
        var snp_enable_analytics_events = false;
        var snp_enable_mobile = false;
        var snp_use_in_all = false;
        var snp_excluded_urls = [];
        snp_excluded_urls.push('');    </script>
    <div class="snp-root">
        <input type="hidden" id="snp_popup" value="" />
        <input type="hidden" id="snp_popup_id" value="" />
        <input type="hidden" id="snp_popup_theme" value="" />
        <input type="hidden" id="snp_exithref" value="" />
        <input type="hidden" id="snp_exittarget" value="" />
        	<div id="snppopup-welcome" class="snp-pop-109583 snppopup"><input type="hidden" class="snp_open" value="scroll" /><input type="hidden" class="snp_show_on_exit" value="2" /><input type="hidden" class="snp_exit_js_alert_text" value="" /><input type="hidden" class="snp_exit_scroll_down" value="" /><input type="hidden" class="snp_exit_scroll_up" value="" /><input type="hidden" class="snp_open_scroll" value="50" /><input type="hidden" class="snp_optin_redirect_url" value="" /><input type="hidden" class="snp_show_cb_button" value="yes" /><input type="hidden" class="snp_popup_id" value="109583" /><input type="hidden" class="snp_popup_theme" value="theme6" /><input type="hidden" class="snp_overlay" value="disabled" /><input type="hidden" class="snp_cookie_conversion" value="30" /><input type="hidden" class="snp_cookie_close" value="180" /><div class="snp-fb snp-theme6">
    <div class="snp-subscribe-inner">
	<h1 class="snp-header"><i>Never miss an update! </i>
<br/>
<strong>Subscribe to R-bloggers</strong> to receive <br/>e-mails with the latest R posts.<br/>

<small>(You will not see this message again.)</small></h1>	<div class="snp-form">
	    <form action="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers" method="post" class="snp-subscribeform snp_subscribeform">
				<fieldset>
		    <div class="snp-field">
			<input type="text" name="email" id="snp_email" placeholder="Your E-mail..." class="snp-field snp-field-email" />		
		    </div>
		    <button type="submit" class="snp-submit">Submit</button>
		</fieldset>
	    </form>
	</div>
	<a href="#" class="snp_nothanks snp-close">Click here to close (This popup will not appear again)</a>    </div>
    </div>
<style>.snp-pop-109583 .snp-theme6 { max-width: 700px;}
.snp-pop-109583 .snp-theme6 h1 {font-size: 17px;}
.snp-pop-109583 .snp-theme6 { color: #a0a4a9;}
.snp-pop-109583 .snp-theme6 .snp-field ::-webkit-input-placeholder { color: #a0a4a9;}
.snp-pop-109583 .snp-theme6 .snp-field :-moz-placeholder { color: #a0a4a9;}
.snp-pop-109583 .snp-theme6 .snp-field :-ms-input-placeholder { color: #a0a4a9;}
.snp-pop-109583  .snp-theme6 .snp-field input { border: 1px solid #a0a4a9;}
.snp-pop-109583 .snp-theme6 .snp-field { color: #000000;}
.snp-pop-109583 .snp-theme6 { background: #f2f2f2;}
</style><script>
jQuery(document).ready(function() {
});
</script>
</div>        <script type="text/javascript">
            var CaptchaCallback = function() {
                jQuery('.g-recaptcha').each(function(index, el) {
                    grecaptcha.render(el, {
                        'sitekey' : ''
                    });
                });
            };
        </script>
    </div>
    <script type="text/javascript">/* <![CDATA[ */!function(e,n){var r={"selectors":{"block":"pre","inline":"code"},"options":{"indent":4,"ampersandCleanup":true,"linehover":true,"rawcodeDbclick":false,"textOverflow":"scroll","linenumbers":false,"theme":"enlighter","language":"r","retainCssClasses":false,"collapse":false,"toolbarOuter":"","toolbarTop":"{BTN_RAW}{BTN_COPY}{BTN_WINDOW}{BTN_WEBSITE}","toolbarBottom":""},"resources":["https:\/\/www.r-bloggers.com\/wp-content\/plugins\/enlighter\/cache\/enlighterjs.min.css?vVCnEZeurtkU0vr","https:\/\/www.r-bloggers.com\/wp-content\/plugins\/enlighter\/\/resources\/enlighterjs\/enlighterjs.min.js"]},o=document.getElementsByTagName("head")[0],t=n&&(n.error||n.log)||function(){};e.EnlighterJSINIT=function(){!function(e,n){var r=0,l=null;function c(o){l=o,++r==e.length&&(!0,n(l))}e.forEach(function(e){switch(e.match(/\.([a-z]+)(?:[#?].*)?$/)[1]){case"js":var n=document.createElement("script");n.onload=function(){c(null)},n.onerror=c,n.src=e,n.async=!0,o.appendChild(n);break;case"css":var r=document.createElement("link");r.onload=function(){c(null)},r.onerror=c,r.rel="stylesheet",r.type="text/css",r.href=e,r.media="all",o.appendChild(r);break;default:t("Error: invalid file extension",e)}})}(r.resources,function(e){e?t("Error: failed to dynamically load EnlighterJS resources!",e):"undefined"!=typeof EnlighterJS?EnlighterJS.init(r.selectors.block,r.selectors.inline,r.options):t("Error: EnlighterJS resources not loaded yet!")})},(document.querySelector(r.selectors.block)||document.querySelector(r.selectors.inline))&&e.EnlighterJSINIT()}(window,console); /* ]]> */</script><script type='text/javascript' src='https://www.r-bloggers.com/wp-content/plugins/arscode-ninja-popups/js/jquery.ck.min.js?ver=5.5.1' id='jquery-np-cookie-js'></script>
<script type='text/javascript' src='https://www.r-bloggers.com/wp-content/plugins/arscode-ninja-popups/js/dialog_trigger.js?ver=5.5.1' id='js-dialog_trigger-js'></script>
<script type='text/javascript' src='https://www.r-bloggers.com/wp-content/plugins/arscode-ninja-popups/js/ninjapopups.min.js?ver=5.5.1' id='js-ninjapopups-js'></script>
<script type='text/javascript' src='https://www.r-bloggers.com/wp-content/plugins/arscode-ninja-popups/fancybox2/jquery.fancybox.min.js?ver=5.5.1' id='fancybox2-js'></script>
<script type='text/javascript' src='https://c0.wp.com/p/jetpack/7.3.2/_inc/build/photon/photon.min.js' id='jetpack-photon-js'></script>
<script type='text/javascript' id='flying-pages-js-before'>
window.FPConfig= {
	delay: 0,
	ignoreKeywords: ["\/wp-admin","\/wp-login.php","\/cart","add-to-cart","logout","#","?",".png",".jpeg",".jpg",".gif",".svg"],
	maxRPS: 3,
    hoverDelay: 50
};
</script>
<script type='text/javascript' src='https://www.r-bloggers.com/wp-content/plugins/flying-pages/flying-pages.min.js?ver=2.4.2' id='flying-pages-js' defer></script>
<script type='text/javascript' src='https://s0.wp.com/wp-content/js/devicepx-jetpack.js?ver=202040' id='devicepx-js'></script>
<script type='text/javascript' src='https://c0.wp.com/p/jetpack/7.3.2/_inc/build/lazy-images/js/lazy-images.min.js' id='jetpack-lazy-images-js'></script>
<script type='text/javascript' src='https://c0.wp.com/c/5.5.1/wp-includes/js/wp-embed.min.js' id='wp-embed-js'></script>
<script type='text/javascript' src='https://stats.wp.com/e-202040.js' async='async' defer='defer'></script>
<script type='text/javascript'>
	_stq = window._stq || [];
	_stq.push([ 'view', {v:'ext',j:'1:7.3.2',blog:'11524731',post:'187573',tz:'-6',srv:'www.r-bloggers.com'} ]);
	_stq.push([ 'clickTrackerInit', '11524731', '187573' ]);
</script>
	<script type="text/javascript">
        jQuery(document).ready(function ($) {
            //$( document ).ajaxStart(function() {
            //});

			
            for (var i = 0; i < document.forms.length; ++i) {
                var form = document.forms[i];
				if ($(form).attr("method") != "get") { $(form).append('<input type="hidden" name="PnM-zH_AKJNfBeFs" value="v*TMZOlu5zynohG6" />'); }
if ($(form).attr("method") != "get") { $(form).append('<input type="hidden" name="-cRxUiIS" value="6UaC7c1T" />'); }
if ($(form).attr("method") != "get") { $(form).append('<input type="hidden" name="VXUxhtONi" value="Nc8akts2n" />'); }
if ($(form).attr("method") != "get") { $(form).append('<input type="hidden" name="GyoDAYLMZ" value="yE2gzT5Zm" />'); }
            }

			
            $(document).on('submit', 'form', function () {
				if ($(this).attr("method") != "get") { $(this).append('<input type="hidden" name="PnM-zH_AKJNfBeFs" value="v*TMZOlu5zynohG6" />'); }
if ($(this).attr("method") != "get") { $(this).append('<input type="hidden" name="-cRxUiIS" value="6UaC7c1T" />'); }
if ($(this).attr("method") != "get") { $(this).append('<input type="hidden" name="VXUxhtONi" value="Nc8akts2n" />'); }
if ($(this).attr("method") != "get") { $(this).append('<input type="hidden" name="GyoDAYLMZ" value="yE2gzT5Zm" />'); }
                return true;
            });

			
            jQuery.ajaxSetup({
                beforeSend: function (e, data) {

                    //console.log(Object.getOwnPropertyNames(data).sort());
                    //console.log(data.type);

                    if (data.type !== 'POST') return;

                    if (typeof data.data === 'object' && data.data !== null) {
						data.data.append("PnM-zH_AKJNfBeFs", "v*TMZOlu5zynohG6");
data.data.append("-cRxUiIS", "6UaC7c1T");
data.data.append("VXUxhtONi", "Nc8akts2n");
data.data.append("GyoDAYLMZ", "yE2gzT5Zm");
                    }
                    else {
                        data.data =  data.data + '&PnM-zH_AKJNfBeFs=v*TMZOlu5zynohG6&-cRxUiIS=6UaC7c1T&VXUxhtONi=Nc8akts2n&GyoDAYLMZ=yE2gzT5Zm';
                    }
                }
            });

        });
	</script>
	</body>
</html>
<!-- Dynamic page generated in 0.871 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2020-09-28 06:48:21 -->

<!-- Compression = gzip -->