├── .Rprofile
├── .github
├── .gitignore
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ └── new-blog.yaml
└── workflows
│ ├── check-images.yaml
│ ├── hello.yaml
│ ├── knit_readme.yaml
│ ├── slack-feed.yaml
│ ├── trigger-website.yaml
│ └── validate_jsons.yaml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── LICENSE.md
├── README.Rmd
├── README.md
├── awesome-rladies-blogs.Rproj
├── blogs
├── amanda.rbind.io.json
├── aosmith.rbind.io.json
├── apreshill.com.json
├── beatrizmilz.com.json
├── blog.djnavarro.net.json
├── cararthompson.com.json
├── cghlewis.com.json
├── citizen-statistician.org.json
├── cosimameyer.com.json
├── daryavanichkina.com.json
├── datapedagogy.com.json
├── drmowinckels.io.json
├── elenadudukina.com.json
├── ellakaye.co.uk.json
├── emilyriederer.com.json
├── fgazzelloni.quarto.pub.json
├── florenciadandrea.com.json
├── hypebright.nl.json
├── isabelizimm.github.io.json
├── ivelasq.rbind.io.json
├── jadeyryan.com.json
├── jhylin.github.io.json
├── juliasilge.com.json
├── karbartolome-blog.netlify.app.json
├── lgibson7.quarto.pub-once-upon-a-time-series.json
├── loreabad6.github.io.json
├── macarenaquiroga.netlify.app.json
├── masalmon.eu.json
├── nrennie.rbind.io.json
├── pipinghotdata.com.json
├── r-ladiesgaborone2021.quarto.pub.json
├── r-ladiesmelbourne.github.io.json
├── rladies-sp.org.json
├── sabrinaschalz.wordpress.com.json
├── sarahgillespie.github.io.json
├── sctyner.me.json
├── shelkariuki.netlify.app.json
├── silviacanelon.com.json
├── soyandrea.netlify.app.json
├── sporella.xyz.json
├── steffilazerte.ca.json
├── surroundedbydata.netlify.app.json
├── thetidytrekker.com.json
├── yabellini.netlify.app.json
└── youtube.com.c.ggnot2.json
├── images
├── contrib_newfile.png
└── contrib_patch.png
├── renv.lock
├── renv
├── .gitignore
└── activate.R
└── scripts
├── .entry_schema.json
├── check-images.R
└── validate_jsons.R
/.Rprofile:
--------------------------------------------------------------------------------
1 | source("renv/activate.R")
2 |
--------------------------------------------------------------------------------
/.github/.gitignore:
--------------------------------------------------------------------------------
1 | *.html
2 | renv/
3 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @rladies/website
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/new-blog.yaml:
--------------------------------------------------------------------------------
1 | name: New Blog
2 | description: Submit an R-Ladies Blog
3 | title: "[New Blog]: "
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Thanks for taking the time to submit a new R-Ladies blog and congrats if it is yours! :tada:
9 | - type: input
10 | id: title
11 | attributes:
12 | label: Blog Name
13 | description: Name of the blog
14 | placeholder: ex. Awesome R Blog
15 | validations:
16 | required: true
17 | - type: input
18 | id: url
19 | attributes:
20 | label: Blog URL
21 | description: URL to the blog
22 | placeholder: ex. https://rladies.org/blog
23 | validations:
24 | required: true
25 | - type: input
26 | id: pic
27 | attributes:
28 | label: Picture URL
29 | description: URL to a picture illustrating the blog
30 | placeholder: ex. https://rladies.org/wp-content/uploads/2016/12/R-LadiesGlobal.png
31 | validations:
32 | required: false
33 | - type: input
34 | id: author1name
35 | attributes:
36 | label: Author Name
37 | description: Name of an author
38 | placeholder: ex. Firstname Lastname
39 | validations:
40 | required: true
41 | - type: input
42 | id: author1twitter
43 | attributes:
44 | label: Author Twitter Username
45 | description: Username on Twitter without the Twitter URL
46 | placeholder: ex. username
47 | validations:
48 | required: false
49 | - type: input
50 | id: author1github
51 | attributes:
52 | label: Author GitHub Username
53 | description: Username on GitHub without the GitHub URL
54 | placeholder: ex. username
55 | validations:
56 | required: false
57 | - type: input
58 | id: author1orcid
59 | attributes:
60 | label: Author ORCID ID
61 | description: ID on ORCID without the ORCID URL
62 | placeholder: ex. 1234-1234-1234
63 | validations:
64 | required: false
65 | - type: markdown
66 | attributes:
67 | value: |
68 | If the blog has several authors please update the issue after opening it, adding info for other authors.
69 | - type: checkboxes
70 | id: terms
71 | attributes:
72 | label: Code of Conduct
73 | description: By submitting this issue, you agree to follow our [Code of Conduct](http://rladies.org/code-of-conduct/)
74 | options:
75 | - label: I agree to follow R-Ladies' Code of Conduct
76 | required: true
77 |
--------------------------------------------------------------------------------
/.github/workflows/check-images.yaml:
--------------------------------------------------------------------------------
1 | name: Check repo image urls
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches: [main]
7 | schedule:
8 | - cron: "0 0 * * SAT"
9 |
10 | concurrency:
11 | group: ${{ github.workflow }}-${{ github.ref }}
12 | cancel-in-progress: true
13 |
14 | jobs:
15 | knit:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - name: Checkout repo
19 | uses: actions/checkout@v4
20 | with:
21 | fetch-depth: 1
22 |
23 | - name: Install cURL Headers
24 | run: |
25 | sudo apt-get update
26 | sudo apt-get install libcurl4-openssl-dev
27 |
28 | - name: Setup R
29 | uses: r-lib/actions/setup-r@v2
30 | with:
31 | r-version: 'renv'
32 |
33 | - name: Setup renv
34 | uses: r-lib/actions/setup-renv@v2
35 |
36 | - name: Check repo image urls
37 | run: |
38 | Rscript --verbose scripts/check-images.R
39 |
40 |
--------------------------------------------------------------------------------
/.github/workflows/hello.yaml:
--------------------------------------------------------------------------------
1 | name: "Auto message for PR's and Issues"
2 | on: [pull_request, issues]
3 |
4 | jobs:
5 | send-message:
6 | runs-on: ubuntu-latest
7 | if: github.event.pull_request.merged
8 | steps:
9 | - uses: actions/github-script@v6
10 | name: send-message
11 | with:
12 | github-token: ${{ secrets.GLOBAL_GHA_PAT }}
13 | script: |
14 | await github.rest.issues.createComment({
15 | issue_number: context.issue.number,
16 | owner: context.repo.owner,
17 | repo: context.repo.repo,
18 | body: `Hey, thank you for opening your Pull Request ! 🙂 We will get to this as soon as we can!`
19 | })
20 |
21 |
--------------------------------------------------------------------------------
/.github/workflows/knit_readme.yaml:
--------------------------------------------------------------------------------
1 | name: Knit readme
2 |
3 | on:
4 | push:
5 | branches: [main]
6 |
7 | concurrency:
8 | group: ${{ github.workflow }}-${{ github.ref }}
9 | cancel-in-progress: true
10 |
11 | jobs:
12 | knit:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Checkout repo
16 | uses: actions/checkout@v4
17 | with:
18 | fetch-depth: 1
19 |
20 | - name: Install cURL Headers
21 | run: |
22 | sudo apt-get update
23 | sudo apt-get install libcurl4-openssl-dev
24 |
25 | - name: Setup R
26 | uses: r-lib/actions/setup-r@v2
27 | with:
28 | r-version: '4.3.0'
29 |
30 | - name: Serup renv
31 | uses: r-lib/actions/setup-renv@v2
32 |
33 | - uses: r-lib/actions/setup-pandoc@v2
34 |
35 | - name: Render readme files
36 | run: rmarkdown::render("README.Rmd", output_format = "github_document")
37 | shell: Rscript {0}
38 |
39 | - name: Commit data
40 | env:
41 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
42 | run: |
43 | git config --local user.name "$GITHUB_ACTOR"
44 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
45 | git commit README.md -m 'Update README list' || echo "No changes to commit"
46 | git push origin || echo "Nothing to push"
47 |
48 |
--------------------------------------------------------------------------------
/.github/workflows/slack-feed.yaml:
--------------------------------------------------------------------------------
1 | name: Slack RSS Subscription
2 | on:
3 | workflow_dispatch:
4 | inputs:
5 | rss_feed_url:
6 | description: 'RSS Feed URL'
7 | required: true
8 |
9 | jobs:
10 | send_url_to_slack:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Check out code
14 | uses: actions/checkout@v3
15 |
16 | - name: Set up Node.js
17 | uses: actions/setup-node@v3
18 | with:
19 | node-version: 14
20 |
21 | - name: Subscribe to RSS feed
22 | env:
23 | SLACK_TOKEN: ${{ secrets.SLACK_TOKEN }}
24 | SLACK_CHANNEL: rladiesblogs
25 | RSS_FEED_URL: ${{ github.event.inputs.rss_feed_url }}
26 | run: |
27 | npm install @slack/web-api
28 | node -e '
29 | const { WebClient } = require("@slack/web-api");
30 |
31 | const slackToken = process.env.SLACK_TOKEN;
32 | const channel = process.env.SLACK_CHANNEL;
33 | const url = process.env.RSS_FEED_URL;
34 |
35 | (async () => {
36 | const web = new WebClient(slackToken);
37 | const response = await web.chat.postMessage({
38 | channel,
39 | text: `/feed subscribe ${url}`
40 | });
41 |
42 | console.log("Response:", response);
43 | })().catch(error => {
44 | console.error("Error:", error);
45 | process.exit(1);
46 | });
47 | '
48 |
--------------------------------------------------------------------------------
/.github/workflows/trigger-website.yaml:
--------------------------------------------------------------------------------
1 | name: Trigger Website
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | branches:
7 | - main
8 |
9 | jobs:
10 | trigger:
11 | name: Trigger
12 | runs-on: ubuntu-latest
13 | steps:
14 |
15 | - name: Trigger test build
16 | uses: actions/github-script@v7
17 | with:
18 | github-token: ${{ secrets.GLOBAL_GHA_PAT }}
19 | script: |
20 | await github.rest.actions.createWorkflowDispatch({
21 | owner: 'rladies',
22 | repo: 'rladies.github.io',
23 | workflow_id: 'build-preview.yaml',
24 | ref: 'main',
25 | inputs: {
26 | blogs: '${{ github.run_id }}',
27 | triggering_issue: '${{ github.event.pull_request.number }}',
28 | triggering_repo: '${{ github.event.repository.name }}'
29 | }
30 | })
31 |
32 | - name: Notify about build start
33 | uses: actions/github-script@v7
34 | with:
35 | github-token: ${{ secrets.GITHUB_TOKEN }}
36 | script: |
37 | const path = require('path');
38 | await github.rest.issues.createComment({
39 | owner: 'rladies',
40 | repo: 'awesome-rladies-blogs',
41 | issue_number: '${{ github.event.pull_request.number }}',
42 | body: 'Building test-site now! The build will take a few minutes, but look at its progress in the [website repo](https://github.com/rladies/rladies.github.io/actions/workflows/build-preview.yaml).'
43 | })
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.github/workflows/validate_jsons.yaml:
--------------------------------------------------------------------------------
1 | on:
2 | workflow_dispatch:
3 | pull_request:
4 | branches:
5 | - main
6 | paths:
7 | - 'blogs/**'
8 |
9 | name: Validate and clean jsons
10 |
11 | jobs:
12 | validate:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Checkout repo
16 | uses: actions/checkout@v4
17 |
18 | - name: Get changed files
19 | id: changed-files
20 | uses: tj-actions/changed-files@v12
21 | with:
22 | files: blogs/
23 |
24 | - name: Cleanup json template comments
25 | if: ${{ steps.changed-files.outputs.any_changed }}
26 | run: |
27 | for f in ${{ steps.changed-files.outputs.all_changed_files }}; do
28 | echo Cleaning $f
29 | sed -i 's.//required..g' $f
30 | done
31 |
32 | - name: Install cURL Headers
33 | run: |
34 | sudo apt-get update
35 | sudo apt-get install libcurl4-openssl-dev
36 |
37 | - name: Setup R
38 | uses: r-lib/actions/setup-r@v2
39 | with:
40 | version: 'renv'
41 |
42 | - name: Setup renv
43 | uses: r-lib/actions/setup-renv@v2
44 |
45 | - name: Validate jsons
46 | run: Rscript 'scripts/validate_jsons.R'
47 |
48 | - name: Commit data
49 | env:
50 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
51 | run: |
52 | git config --local user.name "$GITHUB_ACTOR"
53 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
54 | git commit blogs/ -m 'Commit cleaned jsons' || echo "No changes to commit"
55 | git push origin || echo "Nothing to push"
56 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | .Rhistory
3 | .RData
4 | .Ruserdata
5 | .DS_Store
6 | .httr-oauth
7 | tmp
8 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # About
2 |
3 | This repository collects R-Ladies blogs, this is inclusive of those who identify as a minority gender (including but not limited to cis/trans women, trans men, non-binary, genderqueer, & agender). We'd love to have contributions to this list! If you identify with R-Ladies and have a blog, please add yourself.
4 |
5 | # Contributing checklist
6 |
7 | - [ ] The entry is added to [blogs/](blogs/) folder
8 | - [ ] The entry filename ends with `.json`
9 | - [ ] The json contains at minimum:
10 | - [ ] title (blog title)
11 | - [ ] type ("blog")
12 | - [ ] url (blog url)
13 | - [ ] rss_feed (RSS feed for R-related posts. Ideally, you use "tags" or "categories" to identify your R-related posts. A title-based RSS feed is OK. If you need more input on how to get your RSS, have a look [here](https://zapier.com/blog/how-to-find-rss-feed-url/))
14 | - [ ] photo_url (logo or profile)
15 | - [ ] language (one of [ISO 639-1 Language Codes](https://www.w3schools.com/tags/ref_language_codes.asp))
16 | - [ ] authors (list of authors)
17 |
18 | # Contributing details
19 |
20 | All the blogs are listed in the [blogs](blogs/) folder, where each blog is in its own json-file. These files are used to render a table on the upcoming revamped R-Ladies website. Follow the below instructions to add to the list. If you have any trouble, please create an issue for us to help.
21 |
22 | Depending on how you are most comfortable working, there are several ways of adding new entries.
23 |
24 | If you are not familiar with JSON you can [open an issue](https://github.com/rladies/awesome-rladies-blogs/issues/new/choose) with your blog info, which uses a GitHub Form, and we'd create the JSON for you!
25 |
26 | Now we will focus on adding new entries directly through GitHub, but you could also work on a local copy (branch) or fork and add new entries that way too.
27 |
28 |
29 | ## Create a new file
30 |
31 | Create a new file in the [blogs/](blogs/) folder by [using this link](https://github.com/rladies/awesome-rladies-blogs/new/main/?filename=blogs/your-blog-url.com.json&value=%7B%0A%20%20%22title%22%3A%20%22Your%20title%22%2C%20%2F%2Frequired%0A%20%20%22subtitle%22%3A%20%22subtitle%20or%20tagline%22%2C%20%2F%2Foptional%0A%20%20%22type%22%3A%20%22blog%22%2C%20%2F%2Frequired%0A%20%20%22url%22%3A%20%22https%3A%2F%2Fyour_blog.com%22%2C%20%2F%2Frequired%0A%20%20%22photo_url%22%3A%20%22https%3A%2F%2Fyour_blog.com%2Fyour_photo.png%22%2C%20%2F%2Frequired%0A%20%20%22description%22%3A%20%22Short%20description%20of%20what%20you%20blog%20about%22%2C%0A%20%20%22language%22%3A%20%22en%22%2C%20%2F%2Frequired%0A%20%20%22rss_feed%22%3A%20%22%5Burl%5D%2Ffile.xml%22%2C%20%2F%2Frequired%0A%20%20%22authors%22%3A%20%5B%20%2F%2Frequired%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22name%22%3A%20%22Your%20Name%22%2C%20%2F%2Frequired%0A%20%20%20%20%20%20%22social_media%22%3A%20%5B%7B%0A%20%20%20%20%20%20%20%20%20%22twitter%22%3A%20%22username%22%2C%0A%20%20%20%20%20%20%20%20%20%22mastodon%22%3A%20%22%40username%40server.org%22%2C%0A%20%20%20%20%20%20%20%20%20%22bluesky%22%3A%20%22username.domain%22%2C%0A%20%20%20%20%20%20%20%20%20%22github%22%3A%20%22username%22%2C%0A%20%20%20%20%20%20%20%20%20%22instagram%22%3A%20%22username%22%2C%0A%20%20%20%20%20%20%20%20%20%22youtube%22%3A%20%22username%2Fend-url%22%2C%0A%20%20%20%20%20%20%20%20%20%22tiktok%22%3A%20%22username%22%2C%0A%20%20%20%20%20%20%20%20%20%22periscope%22%3A%20%22username%22%2C%0A%20%20%20%20%20%20%20%20%20%22researchgate%22%3A%20%22username%22%2C%0A%20%20%20%20%20%20%20%20%20%22website%22%3A%20%22url%22%2C%0A%20%20%20%20%20%20%20%20%20%22linkedin%22%3A%20%22username%22%2C%0A%20%20%20%20%20%20%20%20%20%22facebook%22%3A%20%22username%22%2C%0A%20%20%20%20%20%20%20%20%20%22orcid%22%3A%20%22member%20number%22%2C%0A%20%20%20%20%20%20%20%20%20%22meetup%22%3A%20%22end-url%22%0A%20%20%20%20%20%20%7D%5D%0A%20%20%20%20%7D%0A%20%20%5D%0A%7D).
32 |
33 | This link will fork the repository to your user account, and initiate a new file with some template content in it. After filling the file, please [create a PR to the main branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request).
34 |
35 | ### File name
36 |
37 | The name of the file should be the site url (without `www` or `http(s)://` . This way we can ensure each file has a unique name and that duplication does not happen.
38 |
39 | ### File content
40 |
41 | Using the link above will create a template for you to start with.
42 | Fill inn all the information that is relevant for your blog.
43 | There are several adaptations to an entry you can make that are not highlighted in every entry.
44 | Remove all mentions of `\\required`, these are just for making it clear which information you _must_ provide for the file to be valid.
45 | Any optional field you don't want to add, you may delete entirely.
46 | For instance, if you don't have a subtitle or tagline for your blog, remove the entire line of `"subtite": "subtitle or tagline"` rather than leaving it empty with `"subtite": ""`
47 |
48 | #### Photo
49 |
50 | The photo url you provide will be displayed as your blogs thumbnail.
51 | This may be a picture of you, or if you have a logo for your blog/website, it may be best to use this in stead.
52 |
53 | #### RSS Feed
54 |
55 | Please add a content-specific feed in `rss_feed`. Ideally, you have a specific RSS feed for R-related posts. Depending on your website theme, the implementation may differ. We collected a few of the most common approaches below:
56 |
57 | Quarto
58 | - Change the code in `index.qmd` as (under listing, also described [here](https://quarto.org/docs/websites/website-blog.html#rss-feed)):
59 |
60 | ```
61 | feed:
62 | categories: [R]
63 |
64 | ```
65 |
66 | - Note to new users that the category names will be the names of your category tags used in the blogs (not `posts`, which are the posts folder for Quarto blogs)
67 | - Then provide the RSS feed links as, `[url]/blog/index-r.xml` for R category posts (`[url]/blog/index.xml` will be the RSS feed link for main posts only)
68 |
69 |
70 |
71 | Distill
72 | There is currently a [workaround](https://github.com/rladies/awesome-rladies-blogs/pull/54#issuecomment-1501263818) for adding RSS feeds in distill that works as follows:
73 |
74 | - In distill, there is a categories folder generated when a post is rendered which gets deleted when the blog is rendered
75 | - Store the folder and add it later because we need a categories folder, containing each specified category with an `index.xml` for each category
76 |
77 |
78 | Hugo
79 | ###### Hugo Academic
80 |
81 | - Apparently the RSS feed is enabled by default and you can access it by using the field `category` in the YAML of your posts
82 | - Further readings for [Hugo Academic](https://cosimameyer.com/post/adding-your-hugo-academic-blog-to-r-bloggers-and-python-bloggers/)
83 |
84 | ###### Hugo Portio
85 |
86 | - Copy and paste the content of [this file](https://github.com/gohugoio/hugo/blob/master/tpl/tplimpl/embedded/templates/_default/rss.xml) (it’s Hugo’s default RSS settings)
87 | - Store it under `layouts/_default/rss.xml` (if there is no file, you need to create this one).
88 | - Exchange one line. Instead of `{{ .Summary | html }}`, we want `{{ .Content | html }}` (it’s at the very bottom of the file). This way, you RSS feed doesn’t show an excerpt but the full text.
89 | - More about [Hugo Portio](https://cosimameyer.com/post/adding-your-hugo-academic-blog-to-r-bloggers-and-python-bloggers/)
90 |
91 |
92 | If you want to check how your RSS looks like, you can use [simple pie](https://simplepie.org/demo/).
93 |
94 |
95 | #### Authors
96 |
97 | The entry may have several authors. This is for blogs where maybe there are several blogging together. If it is a blog that mainly has guest bloggers, its better to list the editors/maintainers of the blog and add "guest bloggers" as authors also.
98 |
99 | Adding several authors means duplicating the content between the curlies `{}` in the author section, and adding a comma between each one.
100 |
101 | ```json
102 | "authors": [
103 | {
104 | "name": "Athanasia Mo Mowinckel",
105 | "social_media": [{
106 | "twitter": "DrMowinckels",
107 | "github": "Athanasiamo"
108 | }]
109 | },
110 | {
111 | "name": "Mary Johnson",
112 | "social_media": [{
113 | "linkedin": "maryj",
114 | "youtube": "maryj"
115 | }]
116 | },
117 | {
118 | "name": "Guest bloggers"
119 | }
120 | ]
121 | ```
122 |
123 | #### Icons
124 |
125 | The `social_media` section supports many different key-value pairs.
126 | For rendering on the website, only the three first social media items for each author will be rendered.
127 |
128 | ```json
129 | "twitter": "username"
130 | "mastodon": "@username@instance"
131 | "bluesky": "username.domain"
132 | "github": "username"
133 | "instagram": "username"
134 | "youtube": "username/end-url"
135 | "tiktok": "username"
136 | "periscope": "username"
137 | "researchgate": "username"
138 | "website": "url"
139 | "linkedin": "username"
140 | "facebook": "username"
141 | "orcid": "member number"
142 | "meetup": "end-url"
143 | ```
144 |
145 | #### Language
146 | The language field should be populated with the [ISO 639-1 Language Codes](https://www.w3schools.com/tags/ref_language_codes.asp) of the site content.
147 | Please be thorough when entering this information.
148 |
149 | ## Commit and PR the file
150 |
151 | At the bottom of the page on GitHub, add a commit message in the box.
152 |
153 | 
154 |
155 | You will immediately be sent to the 'Pull requests' page, to create a PR to the main branch.
156 | Click the `Create pull request` button.
157 | Once this is done, a new page will open and some automated checks of your submitted entries start.
158 | In the comment section, make sure to @drmowinckels so she can take a look.
159 |
160 | If anything needs fixing you will be notified and given instructions on how to do that.
161 |
162 | Once all checks pass and the entries have been reviewed, they will be merged to the main branch.
163 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12 | HEREUNDER.
13 |
14 | Statement of Purpose
15 |
16 | The laws of most jurisdictions throughout the world automatically confer
17 | exclusive Copyright and Related Rights (defined below) upon the creator
18 | and subsequent owner(s) (each and all, an "owner") of an original work of
19 | authorship and/or a database (each, a "Work").
20 |
21 | Certain owners wish to permanently relinquish those rights to a Work for
22 | the purpose of contributing to a commons of creative, cultural and
23 | scientific works ("Commons") that the public can reliably and without fear
24 | of later claims of infringement build upon, modify, incorporate in other
25 | works, reuse and redistribute as freely as possible in any form whatsoever
26 | and for any purposes, including without limitation commercial purposes.
27 | These owners may contribute to the Commons to promote the ideal of a free
28 | culture and the further production of creative, cultural and scientific
29 | works, or to gain reputation or greater distribution for their Work in
30 | part through the use and efforts of others.
31 |
32 | For these and/or other purposes and motivations, and without any
33 | expectation of additional consideration or compensation, the person
34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35 | is an owner of Copyright and Related Rights in the Work, voluntarily
36 | elects to apply CC0 to the Work and publicly distribute the Work under its
37 | terms, with knowledge of his or her Copyright and Related Rights in the
38 | Work and the meaning and intended legal effect of CC0 on those rights.
39 |
40 | 1. Copyright and Related Rights. A Work made available under CC0 may be
41 | protected by copyright and related or neighboring rights ("Copyright and
42 | Related Rights"). Copyright and Related Rights include, but are not
43 | limited to, the following:
44 |
45 | i. the right to reproduce, adapt, distribute, perform, display,
46 | communicate, and translate a Work;
47 | ii. moral rights retained by the original author(s) and/or performer(s);
48 | iii. publicity and privacy rights pertaining to a person's image or
49 | likeness depicted in a Work;
50 | iv. rights protecting against unfair competition in regards to a Work,
51 | subject to the limitations in paragraph 4(a), below;
52 | v. rights protecting the extraction, dissemination, use and reuse of data
53 | in a Work;
54 | vi. database rights (such as those arising under Directive 96/9/EC of the
55 | European Parliament and of the Council of 11 March 1996 on the legal
56 | protection of databases, and under any national implementation
57 | thereof, including any amended or successor version of such
58 | directive); and
59 | vii. other similar, equivalent or corresponding rights throughout the
60 | world based on applicable law or treaty, and any national
61 | implementations thereof.
62 |
63 | 2. Waiver. To the greatest extent permitted by, but not in contravention
64 | of, applicable law, Affirmer hereby overtly, fully, permanently,
65 | irrevocably and unconditionally waives, abandons, and surrenders all of
66 | Affirmer's Copyright and Related Rights and associated claims and causes
67 | of action, whether now known or unknown (including existing as well as
68 | future claims and causes of action), in the Work (i) in all territories
69 | worldwide, (ii) for the maximum duration provided by applicable law or
70 | treaty (including future time extensions), (iii) in any current or future
71 | medium and for any number of copies, and (iv) for any purpose whatsoever,
72 | including without limitation commercial, advertising or promotional
73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74 | member of the public at large and to the detriment of Affirmer's heirs and
75 | successors, fully intending that such Waiver shall not be subject to
76 | revocation, rescission, cancellation, termination, or any other legal or
77 | equitable action to disrupt the quiet enjoyment of the Work by the public
78 | as contemplated by Affirmer's express Statement of Purpose.
79 |
80 | 3. Public License Fallback. Should any part of the Waiver for any reason
81 | be judged legally invalid or ineffective under applicable law, then the
82 | Waiver shall be preserved to the maximum extent permitted taking into
83 | account Affirmer's express Statement of Purpose. In addition, to the
84 | extent the Waiver is so judged Affirmer hereby grants to each affected
85 | person a royalty-free, non transferable, non sublicensable, non exclusive,
86 | irrevocable and unconditional license to exercise Affirmer's Copyright and
87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
88 | maximum duration provided by applicable law or treaty (including future
89 | time extensions), (iii) in any current or future medium and for any number
90 | of copies, and (iv) for any purpose whatsoever, including without
91 | limitation commercial, advertising or promotional purposes (the
92 | "License"). The License shall be deemed effective as of the date CC0 was
93 | applied by Affirmer to the Work. Should any part of the License for any
94 | reason be judged legally invalid or ineffective under applicable law, such
95 | partial invalidity or ineffectiveness shall not invalidate the remainder
96 | of the License, and in such case Affirmer hereby affirms that he or she
97 | will not (i) exercise any of his or her remaining Copyright and Related
98 | Rights in the Work or (ii) assert any associated claims and causes of
99 | action with respect to the Work, in either case contrary to Affirmer's
100 | express Statement of Purpose.
101 |
102 | 4. Limitations and Disclaimers.
103 |
104 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
105 | surrendered, licensed or otherwise affected by this document.
106 | b. Affirmer offers the Work as-is and makes no representations or
107 | warranties of any kind concerning the Work, express, implied,
108 | statutory or otherwise, including without limitation warranties of
109 | title, merchantability, fitness for a particular purpose, non
110 | infringement, or the absence of latent or other defects, accuracy, or
111 | the present or absence of errors, whether or not discoverable, all to
112 | the greatest extent permissible under applicable law.
113 | c. Affirmer disclaims responsibility for clearing rights of other persons
114 | that may apply to the Work or any use thereof, including without
115 | limitation any person's Copyright and Related Rights in the Work.
116 | Further, Affirmer disclaims responsibility for obtaining any necessary
117 | consents, permissions or other rights required for any use of the
118 | Work.
119 | d. Affirmer understands and acknowledges that Creative Commons is not a
120 | party to this document and has no duty or obligation with respect to
121 | this CC0 or use of the Work.
122 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | ## creative commons
2 |
3 | # CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
6 |
7 | ### Statement of Purpose
8 |
9 | The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
10 |
11 | Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
12 |
13 | For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
14 |
15 | 1. __Copyright and Related Rights.__ A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
16 |
17 | i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
18 |
19 | ii. moral rights retained by the original author(s) and/or performer(s);
20 |
21 | iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
22 |
23 | iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
24 |
25 | v. rights protecting the extraction, dissemination, use and reuse of data in a Work;
26 |
27 | vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
28 |
29 | vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
30 |
31 | 2. __Waiver.__ To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
32 |
33 | 3. __Public License Fallback.__ Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
34 |
35 | 4. __Limitations and Disclaimers.__
36 |
37 | a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
38 |
39 | b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
40 |
41 | c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
42 |
43 | d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
44 |
--------------------------------------------------------------------------------
/README.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | output: github_document
3 | ---
4 |
5 |
6 |
7 | ```{r, include = FALSE}
8 | knitr::opts_chunk$set(
9 | collapse = TRUE,
10 | comment = "#>"
11 | )
12 | ```
13 |
14 | # Awesome R-Ladies' Blogs
15 |
16 | [](https://awesome.re)
17 |
18 |
19 | Curated list of awesome blogs by R-Ladies, inspired by this [Tweet](https://twitter.com/WeAreRLadies/status/1362021673239785473).
20 | The content of this list i rendered on the [R-Ladies website](https://www.rladies.org/activities/rladies-blogs/).
21 | The list also is the source for the [R-Ladies mastodon bot](https://fosstodon.org/@rladies_bot@botsin.space), that occasionally toots links to posts from these blogs.
22 |
23 | To contribute to the list, please see the [contributing](CONTRIBUTING.md) instructions.
24 |
25 |
26 | ## List of blogs
27 |
28 | Created by accessing the json files in [blogs/](blogs/)
29 |
30 | ```{r, echo = FALSE, results='asis'}
31 | json_list <- list.files(here::here("blogs"), "json$", full.names = TRUE)
32 | dt <- lapply(json_list, jsonlite::read_json)
33 |
34 | invisible(
35 | lapply(dt, function(x){
36 | cat(sprintf(" - [%s](%s) by %s",
37 | x$title, x$url,
38 | paste(sapply(x$authors, function(x) x$name), collapse=", ")),
39 | sep = "\n")
40 | })
41 | )
42 | ```
43 |
44 |
45 | ## License
46 |
47 | [](https://creativecommons.org/publicdomain/zero/1.0/)
48 |
49 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | # Awesome R-Ladies’ Blogs
5 |
6 |
7 |
8 | [](https://awesome.re)
9 |
10 |
11 | Curated list of awesome blogs by R-Ladies, inspired by this
12 | [Tweet](https://twitter.com/WeAreRLadies/status/1362021673239785473).
13 | The content of this list i rendered on the [R-Ladies
14 | website](https://www.rladies.org/activities/rladies-blogs/). The list
15 | also is the source for the [R-Ladies mastodon
16 | bot](https://fosstodon.org/@rladies_bot@botsin.space), that occasionally
17 | toots links to posts from these blogs.
18 |
19 | To contribute to the list, please see the
20 | [contributing](CONTRIBUTING.md) instructions.
21 |
22 | ## List of blogs
23 |
24 | Created by accessing the json files in [blogs/](blogs/)
25 |
26 | - [Amanda’s Data Blog](amanda.rbind.io) by Amanda Peterson
27 | - [Very Statisticious](https://aosmith.rbind.io) by Ariel Muldoon
28 | - [Alison Hill](https://www.apreshill.com) by Alison Hill
29 | - [Beatriz Milz’s blog](https://beatrizmilz.com/) by Beatriz Milz
30 | - [Notes from a data witch](https://blog.djnavarro.net/) by Danielle
31 | Navarro
32 | - [Building Stories with Data](https://cararthompson.com/blog) by Cara
33 | Thompson
34 | - [Crystal Lewis](https://www.cghlewis.com) by Crystal Lewis
35 | - [Citizen Statistician](citizen-statistician.org) by Mine
36 | Çetinkaya-Rundel, Rob Gould, Andrew Zieffler
37 | - [Cosima Meyer](https://cosimameyer.com/) by Cosima Meyer
38 | - [Darya Vanichkina’s blog](https://www.daryavanichkina.com/posts.html)
39 | by Darya Vanichkina
40 | - [Data Pedagogy](https://www.datapedagogy.com/) by Mine Dogucu
41 | - [Dr. Mowinckel’s blog](https://drmowinckels.io) by Athanasia Monika
42 | Mowinckel
43 | - [Elena Dudukina’s blog](https://elenadudukina.com) by Elena Dudukina
44 | - [Ella Kaye](https://ellakaye.co.uk) by Ella Kaye
45 | - [Emily Riederer](https://emilyriederer.com) by Emily Riederer
46 | - [Federica Gazzelloni](https://fgazzelloni.quarto.pub) by Federica
47 | Gazzelloni
48 | - [Florencia D’Andrea](https://florenciadandrea.com) by Florencia
49 | D’Andrea
50 | - [Hypebright](https://hypebright.nl/index.php/en/home-en/blog/) by
51 | Veerle van Leemput
52 | - [Isabel Zimmerman](https://isabelizimm.github.io/) by Isabel Zimmerman
53 | - [%\>% Dreams](https://ivelasq.rbind.io/) by Isabella Velásquez
54 | - [data whiskeRs](https://jadeyryan.com/blog) by Jadey Ryan
55 | - [Data in life](https://jhylin.github.io/Data_in_life_blog/) by
56 | Jennifer HY Lin
57 | - [Julia Silge](https://juliasilge.com/) by Julia Silge
58 | - [Karina Bartolome](https://karbartolome-blog.netlify.app) by Karina
59 | Bartolome
60 | - [Once Upon a Time
61 | Series](https://lgibson7.quarto.pub/once-upon-a-time-series/) by Lydia
62 | Gibson
63 | - [Lore Abad](https://loreabad6.github.io/) by Lorena Abad
64 | - [Macarena Quiroga](https://macarenaquiroga.netlify.app) by Macarena
65 | Quiroga
66 | - [Maëlle’s R blog](https://masalmon.eu/) by Maëlle Salmon
67 | - [Nicola Rennie](https://nrennie.rbind.io) by Nicola Rennie
68 | - [Piping Hot Data](https://www.pipinghotdata.com) by Shannon Pileggi
69 | - [R-Ladies Gaborone](https://r-ladiesgaborone2021.quarto.pub) by
70 | R-Ladies Gabarone
71 | - [R-Ladies Melbourne Blog](https://r-ladiesmelbourne.github.io/) by
72 | R-Ladies Melbourde
73 | - [R-Ladies São Paulo Blog](https://rladies-sp.org/) by R-Ladies São
74 | Paulo
75 | - [Data Science
76 | Blog](https://sabrinaschalz.wordpress.com/data-science-blog/) by
77 | Sabrina Schalz
78 | - [Sarah Gillespie’s blog](https://sarahgillespie.github.io/SG/) by
79 | Sarah Gillespie
80 | - [Sam Tyner-Monroe](https://sctyner.me) by Sam Tyner-Monroe
81 | - [Shel Kariuki’s blog](https://shelkariuki.netlify.app/) by Shel
82 | Kariuki
83 | - [Meeting People Where They R](https://silviacanelon.com) by Silvia
84 | Canelón
85 | - [Soy Andrea blog](https://soyandrea.netlify.app/) by Andrea Gómez
86 | Vargas
87 | - [Ciencia de Datos en Español](https://sporella.xyz) by Steph Orellana
88 | Bello
89 | - [Steffi LaZerte](https://steffilazerte.ca/tips_and_tricks.html) by
90 | Steffi LaZerte
91 | - [Surrounded by Data](https://surroundedbydata.netlify.app/) by Veerle
92 | van Son
93 | - [Exploration Corner](https://thetidytrekker.com/blog.html) by Meghan
94 | Harris
95 | - [Yanina Bellini Saibene](https://yabellini.netlify.app/blog/) by
96 | Yanina Bellini Saibene
97 | - [Melissa Van Bussel (ggnot2)’s YouTube channel about
98 | R](https://www.youtube.com/c/ggnot2) by Melissa Van Bussel
99 |
100 | ## License
101 |
102 | [](https://creativecommons.org/publicdomain/zero/1.0/)
103 |
--------------------------------------------------------------------------------
/awesome-rladies-blogs.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: Default
4 | SaveWorkspace: Default
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
--------------------------------------------------------------------------------
/blogs/amanda.rbind.io.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Amanda's Data Blog",
3 | "type": "blog",
4 | "url": "amanda.rbind.io",
5 | "photo_url": "http://amanda.rbind.io/profile.jpg",
6 | "description": "Amanda's musings about data analysis and R programming",
7 | "language": "en",
8 | "authors": [
9 | {
10 | "name": "Amanda Peterson",
11 | "social_media": [{
12 | "twitter": "DrAmandaRP",
13 | "github": "AmandaRP"
14 | }]
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/blogs/aosmith.rbind.io.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Very Statisticious",
3 | "type": "blog",
4 | "url": "https://aosmith.rbind.io",
5 | "rss_feed": "https://aosmith.rbind.io/index.xml",
6 | "photo_url": "https://aosmith.rbind.io/img/main/ao_ppg2.jpg",
7 | "language": "en",
8 | "authors": [
9 | {
10 | "name": "Ariel Muldoon",
11 | "social_media": [{
12 | "twitter": "aosmith16",
13 | "mastodon": "@aosmith16@fosstodon.org",
14 | "github": "aosmith16",
15 | "website": "https://ariel.rbind.io",
16 | "linkedin": "arielmuldoon"
17 | }]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/blogs/apreshill.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Alison Hill",
3 | "type": "blog",
4 | "url": "https://www.apreshill.com",
5 | "rss_feed": "https://www.apreshill.com/index.xml",
6 | "photo_url": "https://www.apreshill.com/about/sidebar/avatar.jpg",
7 | "description": "Personal website, blog, and professional portfolio.",
8 | "language": "en",
9 | "authors": [
10 | {
11 | "name": "Alison Hill",
12 | "social_media": [{
13 | "twitter": "apreshill",
14 | "mastodon": "@apreshill@fosstodon.org",
15 | "github": "apreshill",
16 | "orcid": "0000-0002-8082-1890"
17 | }]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/blogs/beatrizmilz.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Beatriz Milz's blog",
3 | "type": "blog",
4 | "url": "https://beatrizmilz.com/",
5 | "photo_url": "https://beatrizmilz.com/about/sidebar/avatar.jpeg",
6 | "description": "Blog in Brazilian Portuguese, in which I share what I have been learning related to R and Data science.",
7 | "language": "pt",
8 | "authors": [
9 | {
10 | "name": "Beatriz Milz",
11 | "social_media": [{
12 | "twitter": "BeaMilz",
13 | "bluesky": "beatrizmilz.bsky.social",
14 | "github": "beatrizmilz",
15 | "orcid": "0000-0002-3064-4486",
16 | "linkedin": "beatrizmilz",
17 | "instagram": "beatrizmilz",
18 | "youtube": "UCJ3RjWuqWNfKiAthnNgcv-w",
19 | "orcid": "0000-0001-7648-6578",
20 | "website": "https://beatrizmilz.com/"
21 | }]
22 | }
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/blogs/blog.djnavarro.net.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Notes from a data witch",
3 | "type": "blog",
4 | "url": "https://blog.djnavarro.net/",
5 | "photo_url": "https://djnavarro.net/img/danielle-navarro_hexes_square.jpg",
6 | "description": "Data science and generative art",
7 | "language": "en",
8 | "authors": [
9 | {
10 | "name": "Danielle Navarro",
11 | "social_media": [{
12 | "twitter": "djnavarro",
13 | "bluesky": "djnavarro.bsky.social",
14 | "github": "djnavarro",
15 | "linkedin": "djnavarro",
16 | "instagram": "daniellenavarro77",
17 | "youtube": "daniellenavarro77",
18 | "orcid": "0000-0001-7648-6578",
19 | "website": "https://djnavarro.net"
20 | }]
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/blogs/cararthompson.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Building Stories with Data",
3 | "subtitle": "Pars pas les mains vides",
4 | "type": "blog",
5 | "url": "https://cararthompson.com/blog",
6 | "rss_feed": "https://www.cararthompson.com/posts.xml",
7 | "photo_url": "https://www.cararthompson.com/images/home/profile-pic.png",
8 | "description": "My website and portfolio, which includes talks and a blog about the things I've picked up along the way in the weird and wonderful worlds of #rstats, datascience and dataviz.",
9 | "language": "en",
10 | "authors": [
11 | {
12 | "name": "Cara Thompson",
13 | "social_media": [{
14 | "twitter": "cararthompson",
15 | "mastodon": "@cararthompson@fosstodon.org",
16 | "bluesky": "cararthompson.bsky.social",
17 | "github": "cararthompson",
18 | "website": "cararthompson.com",
19 | "linkedin": "cararthompson"
20 | }]
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/blogs/cghlewis.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Crystal Lewis",
3 | "type": "blog",
4 | "url": "https://www.cghlewis.com",
5 | "photo_url": "https://github.com/Cghlewis/crystal_site/blob/main/static/img/me2022v02.JPG?raw=true",
6 | "language": "en",
7 | "authors": [
8 | {
9 | "name": "Crystal Lewis",
10 | "social_media": [{
11 | "twitter": "Cghlewis",
12 | "bluesky": "cghlewis.bsky.social",
13 | "website": "https://www.cghlewis.com",
14 | "linkedin": "crystal-lewis-922b4193/"}]
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/blogs/citizen-statistician.org.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Citizen Statistician",
3 | "type": "blog",
4 | "url": "citizen-statistician.org",
5 | "rss_feed": "http://www.citizen-statistician.org/categories/rstats/index.xml",
6 | "photo_url": "http://www.citizen-statistician.org/img/logo.png",
7 | "description": "A blog, meant for anyone wishing to become a citizen statistician, but in particular for statistics teachers – those who help empower citizens to become citizen statisticians.",
8 | "language": "en",
9 | "authors": [
10 | {
11 | "name": "Mine Çetinkaya-Rundel",
12 | "social_media": [{
13 | "twitter": "minebocek",
14 | "mastodon": "@minecr@fosstodon.org",
15 | "bluesky": "minecr.bsky.social",
16 | "github": "mine-cetinkaya-rundel",
17 | "orcid": "0000-0001-6452-2420",
18 | "website": "http://mine-cr.com/"
19 | }]
20 | },
21 | {
22 | "name": "Rob Gould",
23 | "social_media": [{
24 | "github": "rgmobilize",
25 | "orcid": "0000-0001-5392-5945",
26 | "website": "http://www.stat.ucla.edu/~rgould/Home/About_Me.html"
27 | }]
28 | },
29 | {
30 | "name": "Andrew Zieffler",
31 | "social_media": [{
32 | "twitter": "Chili14",
33 | "github": "zief0002",
34 | "orcid": "0000-0002-1035-0341",
35 | "website": "https://www.datadreaming.org/"
36 | }]
37 | }
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/blogs/cosimameyer.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Cosima Meyer",
3 | "type": "blog",
4 | "url": "https://cosimameyer.com/",
5 | "photo_url": "https://cosimameyer.com/images/hero/avatar.jpg",
6 | "rss_feed": "https://cosimameyer.com/category/r-post/index.xml",
7 | "language": "en",
8 | "authors": [
9 | {
10 | "name": "Cosima Meyer",
11 | "social_media": [{
12 | "twitter": "cosima_meyer",
13 | "mastodon": "@cosima_meyer@mas.to",
14 | "bluesky": "cosima.bsky.social",
15 | "github": "cosimameyer",
16 | "website": "https://cosimameyer.com/",
17 | "linkedin": "cosimameyer/"
18 | }]
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/blogs/daryavanichkina.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Darya Vanichkina's blog",
3 | "type": "blog",
4 | "url": "https://www.daryavanichkina.com/posts.html",
5 | "photo_url": "https://daryavanichkina.com/images/daryaVhead1.jpg",
6 | "description": "Darya Vanichkina's blog",
7 | "language": "en",
8 | "authors": [
9 | {
10 | "name": "Darya Vanichkina",
11 | "social_media": [{
12 | "twitter": "dvanichkina",
13 | "github": "dvanic",
14 | "linkedin": "daryavanichkina",
15 | "orcid": "0000-0002-0406-164X",
16 | "website": "https://daryavanichkina.com"
17 | }]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/blogs/datapedagogy.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Data Pedagogy",
3 | "subtitle": "Thoughts longer than a tweet, shorter than a manuscript on data, pedagogy, and data pedagogy",
4 | "type": "blog",
5 | "url": "https://www.datapedagogy.com/",
6 | "photo_url": "https://www.datapedagogy.com/images/dogucu-icon.png",
7 | "description": "Teaching and learning data science",
8 | "language": "en",
9 | "authors": [
10 | {
11 | "name": "Mine Dogucu",
12 | "social_media": [{
13 | "twitter": "MineDogucu",
14 | "bluesky": "minedogucu.bsky.social",
15 | "github": "mdogucu",
16 | "linkedin": "minedogucu"
17 | }]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/blogs/drmowinckels.io.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Dr. Mowinckel's blog",
3 | "subtitle": "All things R and Neuroimaging",
4 | "type": "blog",
5 | "url": "https://drmowinckels.io",
6 | "rss_feed": "https://drmowinckels.io/tags/r/index.xml",
7 | "photo_url": "https://drmowinckels.io/about/profile.png",
8 | "description": "Personal website and blog about R and neuromaging in R",
9 | "language": "en",
10 | "authors": [
11 | {
12 | "name": "Athanasia Monika Mowinckel",
13 | "social_media": [{
14 | "mastodon": "@Drmowinckels@fosstodon.org",
15 | "bluesky": "drmowinckels.io",
16 | "github": "drmowinckels"
17 | }]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/blogs/elenadudukina.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Elena Dudukina's blog",
3 | "type": "blog",
4 | "url": "https://elenadudukina.com",
5 | "rss_feed": "https://www.elenadudukina.com/category/r/index.xml",
6 | "photo_url": "https://www.elenadudukina.com/author/elena-dudukina/avatar_hub94ed909de68ef2f7bd91a471236bb47_211159_270x270_fill_q90_lanczos_center.jpg",
7 | "description": "I blog about Rstats, pharmacoepidemiology, women's health, causal inference, and open source Nordic data",
8 | "language": "en",
9 | "authors": [
10 | {
11 | "name": "Elena Dudukina",
12 | "social_media": [{
13 | "twitter": "evpatora",
14 | "mastodon": "@evpatora@mstdn.social",
15 | "orcid": "0000-0002-4238-049X"
16 | }]
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/blogs/ellakaye.co.uk.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Ella Kaye",
3 | "type": "blog",
4 | "url": "https://ellakaye.co.uk",
5 | "rss_feed": "https://ellakaye.co.uk/posts-r.xml",
6 | "photo_url": "https://ellakaye.co.uk/images/ellakaye-profile.jpeg",
7 | "description": "Personal website, portfolio and blog",
8 | "language": "en",
9 | "authors": [
10 | {
11 | "name": "Ella Kaye",
12 | "social_media": [{
13 | "github": "EllaKaye",
14 | "mastodon": "@ellakaye@fosstodon.org",
15 | "bluesky": "ellakaye.co.uk",
16 | "linkedin": "ellakaye/",
17 | "website": "https://ellakaye.co.uk",
18 | "orcid": "0000-0002-7300-3718"
19 | }]
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/blogs/emilyriederer.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Emily Riederer",
3 | "subtitle": "",
4 | "type": "blog",
5 | "url": "https://emilyriederer.com",
6 | "photo_url": "https://avatars.githubusercontent.com/u/19798371",
7 | "description": "Thoughts on advancing the data analysis lifecycle -- from data quality and management, reproducible tooling, and statistical methods",
8 | "language": "en",
9 | "rss_feed": "https://www.emilyriederer.com/tags/rstats/index.xml",
10 | "authors": [
11 | {
12 | "name": "Emily Riederer",
13 | "social_media": [{
14 | "twitter": "emilyriederer",
15 | "mastodon": "@emilyriederer@mastodon.social",
16 | "github": "emilyriederer",
17 | "website": "emilyriederer.com",
18 | "linkedin": "linkedin.com/in/emilyriederer",
19 | "facebook": "emilyriederer",
20 | "orcid": "0000-0002-1788-7934"
21 | }]
22 | }
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/blogs/fgazzelloni.quarto.pub.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Federica Gazzelloni",
3 | "type": "blog",
4 | "url": "https://fgazzelloni.quarto.pub",
5 | "rss_feed": "https://fgazzelloni.quarto.pub/index.xml",
6 | "photo_url": "https://avatars.githubusercontent.com/u/61802414",
7 | "description": "Data analytics, visualization and modeling with R",
8 | "language": "en",
9 | "authors": [
10 | {
11 | "name": "Federica Gazzelloni",
12 | "social_media": [{
13 | "twitter": "fgazzelloni",
14 | "mastodon": "@Fgazzelloni@fosstodon.org",
15 | "github": "fgazzelloni",
16 | "youtube": "Federica Gazzelloni",
17 | "website": "https://fgazzelloni.quarto.pub",
18 | "linkedin": "federicagazzelloni",
19 | "orcid": "0000-0002-4285-611X"
20 | }]
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/blogs/florenciadandrea.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Florencia D'Andrea",
3 | "type": "website",
4 | "url": "https://florenciadandrea.com",
5 | "photo_url": "https://florencia.netlify.app/about/sidebar/avatar.jpg",
6 | "language": "en",
7 | "authors": [
8 | {
9 | "name": "Florencia D'Andrea",
10 | "social_media": [{
11 | "twitter": "cantoflor_87",
12 | "mastodon": "@florencia@techhub.social",
13 | "github": "flor14",
14 | "orcid": "0000-0002-0041-097X",
15 | "linkedin": "florenciadandrea"
16 | }]
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/blogs/hypebright.nl.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Hypebright",
3 | "subtitle": "Programming | R and Shiny",
4 | "type": "blog",
5 | "url": "https://hypebright.nl/index.php/en/home-en/blog/",
6 | "photo_url": "https://hypebright.nl/wp-content/uploads/2023/01/mvb2021-08-10-1058-scaled.jpg",
7 | "description": "R and Shiny tutorials for both beginners and advanced R developers",
8 | "language": "en",
9 | "rss_feed": "https://hypebright.nl/index.php/en/category/r-en/feed/",
10 | "authors": [
11 | {
12 | "name": "Veerle van Leemput",
13 | "social_media": [{
14 | "bluesky": "veerle.hypebright.nl",
15 | "youtube": "HypebrightBV",
16 | "website": "https://hypebright.nl",
17 | "linkedin": "veerlevanleemput",
18 | "github": "hypebright"
19 | }]
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/blogs/isabelizimm.github.io.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Isabel Zimmerman",
3 | "type": "blog",
4 | "url": "https://isabelizimm.github.io/",
5 | "rss_feed": "https://isabelizimm.github.io/blog-r.xml",
6 | "photo_url": "https://isabelizimm.github.io/profile.jpg",
7 | "language": "en",
8 | "authors": [
9 | {
10 | "name": "Isabel Zimmerman",
11 | "social_media": [{
12 | "twitter": "@isabelizimm",
13 | "bluesky": "isabelizimm.bsky.social",
14 | "mastodon": "@isabelizimm@fosstodon.org",
15 | "github": "isabelizimm",
16 | "linkedin": "isabel-zimmerman"
17 | }]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/blogs/ivelasq.rbind.io.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "%>% Dreams",
3 | "type": "blog",
4 | "url": "https://ivelasq.rbind.io/",
5 | "rss_feed": "https://ivelasq.rbind.io/index.xml",
6 | "photo_url": "https://ivelasq.rbind.io/images/avatar.jpg",
7 | "description": "Isabella Velásquez Personal Site on R and Analytics",
8 | "language": "en",
9 | "authors": [
10 | {
11 | "name": "Isabella Velásquez",
12 | "social_media": [{
13 | "bluesky": "ivelasq3.bsky.social",
14 | "mastodon": "@ivelasq3@fosstodon.org",
15 | "github": "ivelasq",
16 | "linkedin": "ivelasq",
17 | "orcid": "0000-0002-7180-4095",
18 | "instagram": "ivelasq",
19 | "website": "https://ivelasq.rbind.io/"
20 | }]
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/blogs/jadeyryan.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "data whiskeRs",
3 | "type": "blog",
4 | "url": "https://jadeyryan.com/blog",
5 | "photo_url": "https://raw.githubusercontent.com/jadeynryan/jadey_website/main/assets/img/JR-logo.png",
6 | "description": "R code, environmental data science, and cats",
7 | "language": "en",
8 | "rss_feed": "https://jadeyryan.com/blog-r.xml",
9 | "authors": [
10 | {
11 | "name": "Jadey Ryan",
12 | "social_media": [{
13 | "twitter": "jadeynryan",
14 | "mastodon": "@jadeynryan@fosstodon.org",
15 | "bluesky": "jadeynryan.bsky.social",
16 | "github": "jadeynryan",
17 | "orcid": "0009-0004-5998-4697",
18 | "youtube": "jadeynryan",
19 | "website": "https://jadeyryan.com",
20 | "linkedin": "jadeynryan"
21 | }]
22 | }
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/blogs/jhylin.github.io.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Data in life",
3 | "type": "blog",
4 | "url": "https://jhylin.github.io/Data_in_life_blog/",
5 | "description": "A blog using data science on pharmaceutical and healthcare data",
6 | "language": "en",
7 | "rss_feed": "https://jhylin.github.io/Data_in_life_blog/index-r.xml",
8 | "authors": [
9 | {
10 | "name": "Jennifer HY Lin",
11 | "social_media": [{
12 | "twitter": "@jenhylin",
13 | "mastodon": "@jhylin@fosstodon.org",
14 | "bluesky": "jhylin.bsky.social",
15 | "github": "jhylin"
16 | }]
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/blogs/juliasilge.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Julia Silge",
3 | "type": "blog",
4 | "url": "https://juliasilge.com/",
5 | "rss_feed": "https://juliasilge.com/categories/rstats/index.xml",
6 | "photo_url": "https://github.com/juliasilge.png",
7 | "description": "A data science blog by Julia Silge",
8 | "language": "en",
9 | "authors": [
10 | {
11 | "name": "Julia Silge",
12 | "social_media": [{
13 | "twitter": "juliasilge",
14 | "mastodon": "@juliasilge@fosstodon.org",
15 | "bluesky": "juliasilge.com",
16 | "github": "juliasilge",
17 | "youtube": "juliasilge",
18 | "website": "https://juliasilge.com/",
19 | "linkedin": "juliasilge",
20 | "orcid": "0000-0002-3671-836X"
21 | }]
22 | }
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/blogs/karbartolome-blog.netlify.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Karina Bartolome",
3 | "subtitle": "Personal blog",
4 | "type": "blog",
5 | "url": "https://karbartolome-blog.netlify.app",
6 | "rss_feed": "https://karbartolome-blog.netlify.app/categories/r/index.xml",
7 | "photo_url": "https://raw.githubusercontent.com/RLadies-BA/RLadies-BA/main/content/authors/kari/avatar.jpg",
8 | "description": "Data science, economics and more",
9 | "language": "es",
10 | "authors": [
11 | {
12 | "name": "Karina Bartolome",
13 | "social_media": [{
14 | "twitter": "karbartolome",
15 | "mastodon": "@karbartolome@mastodon.social",
16 | "github": "karbartolome",
17 | "instagram": "karbartolome",
18 | "website": "https://karbartolome-blog.netlify.app",
19 | "linkedin": "karinabartolome",
20 | "meetup": "276190207"
21 | }]
22 | }
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/blogs/lgibson7.quarto.pub-once-upon-a-time-series.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Once Upon a Time Series",
3 | "type": "blog",
4 | "url": "https://lgibson7.quarto.pub/once-upon-a-time-series/",
5 | "photo_url": "https://lgibson7.quarto.pub/once-upon-a-time-series/profile_pic.jpeg",
6 | "language": "en",
7 | "rss_feed": "https://lgibson7.quarto.pub/once-upon-a-time-series/index.xml",
8 | "authors": [
9 | {
10 | "name": "Lydia Gibson",
11 | "social_media": [{
12 | "twitter": "Lydz_is_Poppin",
13 | "bluesky": "lydz-gibby.bsky.social",
14 | "github": "lgibson7"
15 | }]
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/blogs/loreabad6.github.io.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Lore Abad",
3 | "type": "blog",
4 | "url": "https://loreabad6.github.io/",
5 | "rss_feed": "https://loreabad6.github.io/index.xml",
6 | "photo_url": "https://loreabad6.github.io/AbadL.jpg",
7 | "description": "My adventures with RSpatial",
8 | "language": "en",
9 | "authors": [
10 | {
11 | "name": "Lorena Abad",
12 | "social_media": [{
13 | "twitter": "@loreabad6",
14 | "mastodon": "@loreabad6@fosstodon.org",
15 | "github": "loreabad6",
16 | "researchgate": "Lorena-Abad",
17 | "linkedin": "lorena-abad",
18 | "orcid": "0000-0003-0554-734X"
19 | }]
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/blogs/macarenaquiroga.netlify.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Macarena Quiroga",
3 | "type": "blog",
4 | "url": "https://macarenaquiroga.netlify.app",
5 | "rss_feed": "https://macarenaquiroga.netlify.app/tag/rstats/index.xml",
6 | "photo_url": "https://macarenaquiroga.netlify.app/author/macarena-quiroga/avatar_hu2dcaef447beb41a9ecf37ab13d81ec8c_130063_270x270_fill_q75_lanczos_center.jpg",
7 | "description": "Linguistics, education, and data science with R",
8 | "language": "es",
9 | "authors": [
10 | {
11 | "name": "Macarena Quiroga",
12 | "social_media": [{
13 | "twitter": "_msquiroga",
14 | "mastodon": "@macarenaquiroga@datasci.social",
15 | "github": "msquiroga89",
16 | "linkedin": "macarena-quiroga"
17 | }]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/blogs/masalmon.eu.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Maëlle's R blog",
3 | "type": "blog",
4 | "url": "https://masalmon.eu/",
5 | "rss_feed": "https://masalmon.eu/post/index.xml",
6 | "photo_url": "https://masalmon.eu/img/barbie_office.jpg",
7 | "description": "R(esearch) Software Engineer & Blogger based in Nancy, France",
8 | "language": "en",
9 | "authors": [
10 | {
11 | "name": "Maëlle Salmon",
12 | "social_media": [{
13 | "twitter": "ma_salmon",
14 | "mastodon": "@maelle@mastodon.social",
15 | "bluesky": "@maellesalmon.bsky.social",
16 | "github": "maelle",
17 | "orcid": "0000-0002-2815-0399"
18 | }]
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/blogs/nrennie.rbind.io.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Nicola Rennie",
3 | "type": "blog",
4 | "url": "https://nrennie.rbind.io",
5 | "rss_feed": "https://nrennie.rbind.io/categories/r/index.xml",
6 | "photo_url": "https://nrennie.rbind.io/img/nicola_blue.jpg",
7 | "description": "Personal website, blog, and portfolio.",
8 | "language": "en",
9 | "authors": [
10 | {
11 | "name": "Nicola Rennie",
12 | "social_media": [{
13 | "twitter": "nrennie35",
14 | "mastodon": "@nrennie@fosstodon.org",
15 | "bluesky": "@nrennie.bsky.social",
16 | "github": "nrennie",
17 | "linkedin": "nicola-rennie-076511b3"
18 | }]
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/blogs/pipinghotdata.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Piping Hot Data",
3 | "type": "blog",
4 | "url": "https://www.pipinghotdata.com",
5 | "rss_feed": "https://www.pipinghotdata.com/blog.xml",
6 | "photo_url": "https://www.pipinghotdata.com/cirprofile.png",
7 | "language": "en",
8 | "authors": [
9 | {
10 | "name": "Shannon Pileggi",
11 | "social_media": [{
12 | "twitter": "PipingHotData",
13 | "mastodon": "@PipingHotData@fosstodon.org",
14 | "bluesky": "@pipinghotdata.com",
15 | "website": "https://twitter.com/PipingHotData",
16 | "linkedin": "shannon-m-pileggi/"}]
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/blogs/r-ladiesgaborone2021.quarto.pub.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "R-Ladies Gaborone",
3 | "type": "blog",
4 | "url": "https://r-ladiesgaborone2021.quarto.pub",
5 | "photo_url": "https://r-ladiesgaborone2021.quarto.pub/images/bo_5sEb-_400x400.jpg",
6 | "description": "Blog by R-Ladies Gabarone",
7 | "language": "en",
8 |
9 | "authors": [
10 | {
11 | "name": "R-Ladies Gabarone",
12 | "social_media": [{
13 | "twitter": "RLadiesGaborone",
14 | "mastodon": "@RLadiesGaborone@fosstodon.org",
15 | "youtube": "r-ladiesgaborone8407",
16 | "linkedin": "r-ladies-gaborone",
17 | "facebook": "RLadiesGaborone"
18 | }]
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/blogs/r-ladiesmelbourne.github.io.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "R-Ladies Melbourne Blog",
3 | "type": "blog",
4 | "url": "https://r-ladiesmelbourne.github.io/",
5 | "photo_url": "https://r-ladiesmelbourne.github.io/images/rladiesmelblogo.png",
6 | "description": "Blog by R-Ladies Melbourne",
7 | "language": "en",
8 | "rss_feed": "https://r-ladiesmelbourne.github.io/blog_index.html",
9 | "authors": [
10 | {
11 | "name": "R-Ladies Melbourde",
12 | "social_media": [{
13 | "twitter": "rladiesmelb",
14 | "bluesky": "@rladiesmelb.bsky.social",
15 | "github": "r-ladiesmelbourne",
16 | "linkedin": "https://www.linkedin.com/company/r-ladies-melbourne/",
17 | "meetup": "r-ladies-melbourne",
18 | "website": "https://r-ladiesmelbourne.github.io/"
19 | }]
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/blogs/rladies-sp.org.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "R-Ladies São Paulo Blog",
3 | "type": "blog",
4 | "url": "https://rladies-sp.org/",
5 | "photo_url": "https://rladies-sp.org/img/logo.jpg",
6 | "description": "Blog in Brazilian Portuguese, in which people from the R-Ladies community in São Paulo and in Brazil share about the events, R tutorials, etc.",
7 | "language": "pt",
8 | "authors": [
9 | {
10 | "name": "R-Ladies São Paulo",
11 | "social_media": [{
12 | "twitter": "rladiessaopaulo",
13 | "github": "R-Ladies-Sao-Paulo",
14 | "instagram": "rladiessaopaulo",
15 | "youtube": "RLadiesS%C3%A3oPaulo",
16 | "website": "https://rladies-sp.org/"
17 | }]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/blogs/sabrinaschalz.wordpress.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Data Science Blog",
3 | "type": "blog",
4 | "url": "https://sabrinaschalz.wordpress.com/data-science-blog/",
5 | "photo_url": "https://sabrinaschalz.files.wordpress.com/2022/07/screenshot_20220720-132450_instagram.jpg",
6 | "language": "en",
7 | "rss_feed": "https://sabrinaschalz.wordpress.com/feed/",
8 | "authors": [
9 | {
10 | "name": "Sabrina Schalz",
11 | "social_media": [{
12 | "mastodon": "@sabrinaschalz@fediscience.org",
13 | "bluesky": "sabrinaschalz.bsky.social",
14 | "github": "SabrinaSchalz",
15 | "website": "https://sabrinaschalz.wordpress.com",
16 | "orcid": "0000-0003-0237-4367"
17 | }]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/blogs/sarahgillespie.github.io.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Sarah Gillespie's blog",
3 | "subtitle": "United States student majoring in (1) statistical and data sciences and (2) quantitative economics",
4 | "type": "blog",
5 | "url": "https://sarahgillespie.github.io/SG/",
6 | "photo_url": "https://raw.githubusercontent.com/SarahGillespie/SG/main/docs/img_about_harbor_photo.jpg",
7 | "description": "Strategies to reduce machine learning bias through planning, data curation, and specific algorithm techniques.",
8 | "language": "en",
9 | "authors": [
10 | {
11 | "name": "Sarah Gillespie",
12 | "social_media": [{
13 | "twitter": "SarahG4567",
14 | "github": "SarahGillespie"
15 | }]
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/blogs/sctyner.me.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Sam Tyner-Monroe",
3 | "type": "blog",
4 | "url": "https://sctyner.me",
5 | "photo_url": "https://sctyner.me/author/sam-tyner/avatar_hufb4a28a2230dd21f7cfbe0269e6196dd_54857_270x270_fill_q90_lanczos_center.jpg",
6 | "rss_feed": "https://sctyner.me/category/r/index.xml",
7 | "language": "en",
8 | "authors": [
9 | {
10 | "name": "Sam Tyner-Monroe",
11 | "social_media": [{
12 | "twitter": "sctyner",
13 | "github": "sctyner",
14 | "website": "https://sctyner.me",
15 | "linkedin": "sctyner/",
16 | "orcid": "0000-0001-5484-2957"
17 | }]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/blogs/shelkariuki.netlify.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Shel Kariuki's blog",
3 | "type": "blog",
4 | "url": "https://shelkariuki.netlify.app/",
5 | "photo_url": "https://shelkariuki.netlify.app/author/avatar_hubc1f6cfd80a3e5aa5176d464d1c32c28_52181_270x270_fill_q90_lanczos_center.jpeg",
6 | "description": "Data Analytics Consultant based in Nairobi, Kenya",
7 | "language": "en",
8 | "authors": [
9 | {
10 | "name": "Shel Kariuki",
11 | "social_media": [{
12 | "twitter": "Shel_Kariuki",
13 | "github": "Shelmith-Kariuki"
14 | }]
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/blogs/silviacanelon.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Meeting People Where They R",
3 | "type": "blog",
4 | "url": "https://silviacanelon.com",
5 | "rss_feed": "https://silviacanelon.com/blog/index-r.xml",
6 | "language": "en",
7 | "authors": [
8 | {
9 | "name": "Silvia Canelón",
10 | "social_media": [{
11 | "twitter": "spcanelon",
12 | "mastodon": "@spcanelon@hachyderm.io",
13 | "bluesky": "silviacanelon.com",
14 | "github": "spcanelon",
15 | "linkedin": "spcanelon/"
16 | }]
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/blogs/soyandrea.netlify.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Soy Andrea blog",
3 | "type": "blog",
4 | "url": "https://soyandrea.netlify.app/",
5 | "rss_feed": "https://soyandrea.netlify.app/tag/r/index.xml",
6 | "photo_url": "https://soyandrea.netlify.app/author/andrea/avatar.jpg",
7 | "description": "Socióloga, web profesional & portafolio",
8 | "language": "es",
9 | "authors": [
10 | {
11 | "name": "Andrea Gómez Vargas",
12 | "social_media": [{
13 | "twitter": "me_andre",
14 | "mastodon": "@me_andre@mastodon.social",
15 | "github": "SoyAndrea",
16 | "linkedin": "andreasociologa"
17 | }]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/blogs/sporella.xyz.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Ciencia de Datos en Español",
3 | "type": "blog",
4 | "url": "https://sporella.xyz",
5 | "rss_feed": "https://sporella.xyz/tags/r/index.xml",
6 | "photo_url": "https://sporella.xyz/img/me.png",
7 | "description": "Blog in Spanish about Data Science and personal projects.",
8 | "language": "es",
9 | "authors": [
10 | {
11 | "name": "Steph Orellana Bello",
12 | "social_media": [{
13 | "twitter": "sporella",
14 | "mastodon": "@sporella@fosstodon.org",
15 | "bluesky": "sporella.bsky.social",
16 | "github": "sporella",
17 | "website": "https://sporella.xyz"
18 | }]
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/blogs/steffilazerte.ca.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Steffi LaZerte",
3 | "subtitle": "Tips & Tricks",
4 | "type": "blog",
5 | "url": "https://steffilazerte.ca/tips_and_tricks.html",
6 | "photo_url": "https://github.com/steffilazerte.png",
7 | "description": "Collection of statistical notes, general tips and tricks, and useful citations which serve as a reference when helping others with R, especially for statistics in the natural sciences.",
8 | "language": "en",
9 | "rss_feed": "https://steffilazerte.ca/tips_and_tricks-r.xml",
10 | "authors": [
11 | {
12 | "name": "Steffi LaZerte",
13 | "social_media": [{
14 | "github": "steffilazerte",
15 | "mastodon": "@steffilazerte@fosstodon.org",
16 | "website": "https://steffilazerte.ca",
17 | "orcid": "0000-0002-7690-8360",
18 | "researchgate": "Steffi-Lazerte",
19 | "linkedin": "steffilazerte",
20 | "twitter": "steffilazerte"
21 | }]
22 | }
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/blogs/surroundedbydata.netlify.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Surrounded by Data",
3 | "type": "blog",
4 | "url": "https://surroundedbydata.netlify.app/",
5 | "photo_url": "https://surroundedbydata.netlify.app/about_files/Veerle_klein.jpg",
6 | "description": "Stories about the data that can be found all around us, in Dutch and English",
7 | "language": "en (required)",
8 | "authors": [
9 | {
10 | "name": "Veerle van Son",
11 | "social_media": [{
12 | "twitter": "veerlevanson",
13 | "github": "veerlevanson",
14 | "instagram": "veerle.van.son",
15 | "linkedin": "veerlevanson",
16 | "meetup": "rladies-den-bosch"
17 | }]
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/blogs/thetidytrekker.com.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Exploration Corner",
3 | "subtitle": "The Tidy Trekker",
4 | "type": "blog",
5 | "url": "https://thetidytrekker.com/blog.html",
6 | "rss_feed": "https://thetidytrekker.com/blog.xml",
7 | "photo_url": "https://thetidytrekker.com/assets/EC-Header.gif",
8 | "description": "A mix of R Stats, general coding, and personal content",
9 | "language": "en",
10 | "authors": [
11 | {
12 | "name": "Meghan Harris",
13 | "social_media": [{
14 | "twitter": "meghansharris",
15 | "mastodon": "@meghansharris@fosstodon.org",
16 | "github": "Meghansaha",
17 | "website": "https://thetidytrekker.com",
18 | "linkedin": "meghan-harris",
19 | "orcid": "0000-0003-3922-8101"
20 | }]
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/blogs/yabellini.netlify.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Yanina Bellini Saibene",
3 | "type": "blog",
4 | "url": "https://yabellini.netlify.app/blog/",
5 | "rss_feed": "https://yabellini.netlify.app/categories/rstats/index.xml",
6 | "description": "Writings about my interests and my work: R, education, communities of practice, research, data science, experiences, talks and some more personal stuff.",
7 | "language": "en",
8 | "authors": [
9 | {
10 | "name": "Yanina Bellini Saibene",
11 | "social_media": [{
12 | "mastodon": "@yabellini@fosstodon.org",
13 | "bluesky": "yabellini.bsky.social",
14 | "github": "yabellini",
15 | "instagram": "yanina.bellini",
16 | "youtube": "yabellini",
17 | "website": "https://yabellini.netlify.app/",
18 | "linkedin": "/in/yabellini/",
19 | "orcid": "0000-0002-4522-7466"
20 | }]
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/blogs/youtube.com.c.ggnot2.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Melissa Van Bussel (ggnot2)'s YouTube channel about R",
3 | "type": "youtube",
4 | "url": "https://www.youtube.com/c/ggnot2",
5 | "photo_url": "https://images.squarespace-cdn.com/content/v1/615e5d6733744f26a45a0916/dbb29443-45e7-4f7c-b8d8-ab721631d225/selectedEdit_2.png",
6 | "description": "Melissa Van Bussel (ggnot2)'s YouTube channel that contains tutorials about R programming and Data Science",
7 | "language": "en",
8 | "rss_feed": "https://www.youtube.com/feeds/videos.xml?channel_id=UCWPCd6tPtoLJYzQQ681pe5Q",
9 | "authors": [
10 | {
11 | "name": "Melissa Van Bussel",
12 | "social_media": [{
13 | "youtube": "ggnot2",
14 | "twitter": "melvanbussel",
15 | "linkedin": "melissavanbussel",
16 | "github": "melissavanbussel",
17 | "website": "https://www.melissavanbussel.com"
18 | }]
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/images/contrib_newfile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rladies/awesome-rladies-blogs/c2df9cf9f6fc9c24090a9d4c8330f4aa42a6505e/images/contrib_newfile.png
--------------------------------------------------------------------------------
/images/contrib_patch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rladies/awesome-rladies-blogs/c2df9cf9f6fc9c24090a9d4c8330f4aa42a6505e/images/contrib_patch.png
--------------------------------------------------------------------------------
/renv.lock:
--------------------------------------------------------------------------------
1 | {
2 | "R": {
3 | "Version": "4.3.3",
4 | "Repositories": [
5 | {
6 | "Name": "CRAN",
7 | "URL": "https://cran.rstudio.com"
8 | }
9 | ]
10 | },
11 | "Packages": {
12 | "R6": {
13 | "Package": "R6",
14 | "Version": "2.5.1",
15 | "Source": "Repository",
16 | "Repository": "RSPM",
17 | "Requirements": [
18 | "R"
19 | ],
20 | "Hash": "470851b6d5d0ac559e9d01bb352b4021"
21 | },
22 | "Rcpp": {
23 | "Package": "Rcpp",
24 | "Version": "1.0.13-1",
25 | "Source": "Repository",
26 | "Repository": "CRAN",
27 | "Requirements": [
28 | "methods",
29 | "utils"
30 | ],
31 | "Hash": "6b868847b365672d6c1677b1608da9ed"
32 | },
33 | "V8": {
34 | "Package": "V8",
35 | "Version": "6.0.0",
36 | "Source": "Repository",
37 | "Repository": "CRAN",
38 | "Requirements": [
39 | "Rcpp",
40 | "curl",
41 | "jsonlite",
42 | "utils"
43 | ],
44 | "Hash": "6603bfcbc7883a5fed41fb13042a3899"
45 | },
46 | "base64enc": {
47 | "Package": "base64enc",
48 | "Version": "0.1-3",
49 | "Source": "Repository",
50 | "Repository": "RSPM",
51 | "Requirements": [
52 | "R"
53 | ],
54 | "Hash": "543776ae6848fde2f48ff3816d0628bc"
55 | },
56 | "bslib": {
57 | "Package": "bslib",
58 | "Version": "0.8.0",
59 | "Source": "Repository",
60 | "Repository": "CRAN",
61 | "Requirements": [
62 | "R",
63 | "base64enc",
64 | "cachem",
65 | "fastmap",
66 | "grDevices",
67 | "htmltools",
68 | "jquerylib",
69 | "jsonlite",
70 | "lifecycle",
71 | "memoise",
72 | "mime",
73 | "rlang",
74 | "sass"
75 | ],
76 | "Hash": "b299c6741ca9746fb227debcb0f9fb6c"
77 | },
78 | "cachem": {
79 | "Package": "cachem",
80 | "Version": "1.1.0",
81 | "Source": "Repository",
82 | "Repository": "RSPM",
83 | "Requirements": [
84 | "fastmap",
85 | "rlang"
86 | ],
87 | "Hash": "cd9a672193789068eb5a2aad65a0dedf"
88 | },
89 | "cli": {
90 | "Package": "cli",
91 | "Version": "3.6.3",
92 | "Source": "Repository",
93 | "Repository": "CRAN",
94 | "Requirements": [
95 | "R",
96 | "utils"
97 | ],
98 | "Hash": "b21916dd77a27642b447374a5d30ecf3"
99 | },
100 | "curl": {
101 | "Package": "curl",
102 | "Version": "6.0.1",
103 | "Source": "Repository",
104 | "Repository": "CRAN",
105 | "Requirements": [
106 | "R"
107 | ],
108 | "Hash": "e8ba62486230951fcd2b881c5be23f96"
109 | },
110 | "digest": {
111 | "Package": "digest",
112 | "Version": "0.6.37",
113 | "Source": "Repository",
114 | "Repository": "CRAN",
115 | "Requirements": [
116 | "R",
117 | "utils"
118 | ],
119 | "Hash": "33698c4b3127fc9f506654607fb73676"
120 | },
121 | "evaluate": {
122 | "Package": "evaluate",
123 | "Version": "1.0.1",
124 | "Source": "Repository",
125 | "Repository": "CRAN",
126 | "Requirements": [
127 | "R"
128 | ],
129 | "Hash": "3fd29944b231036ad67c3edb32e02201"
130 | },
131 | "fastmap": {
132 | "Package": "fastmap",
133 | "Version": "1.2.0",
134 | "Source": "Repository",
135 | "Repository": "RSPM",
136 | "Hash": "aa5e1cd11c2d15497494c5292d7ffcc8"
137 | },
138 | "fontawesome": {
139 | "Package": "fontawesome",
140 | "Version": "0.5.3",
141 | "Source": "Repository",
142 | "Repository": "CRAN",
143 | "Requirements": [
144 | "R",
145 | "htmltools",
146 | "rlang"
147 | ],
148 | "Hash": "bd1297f9b5b1fc1372d19e2c4cd82215"
149 | },
150 | "fs": {
151 | "Package": "fs",
152 | "Version": "1.6.5",
153 | "Source": "Repository",
154 | "Repository": "CRAN",
155 | "Requirements": [
156 | "R",
157 | "methods"
158 | ],
159 | "Hash": "7f48af39fa27711ea5fbd183b399920d"
160 | },
161 | "glue": {
162 | "Package": "glue",
163 | "Version": "1.8.0",
164 | "Source": "Repository",
165 | "Repository": "CRAN",
166 | "Requirements": [
167 | "R",
168 | "methods"
169 | ],
170 | "Hash": "5899f1eaa825580172bb56c08266f37c"
171 | },
172 | "here": {
173 | "Package": "here",
174 | "Version": "1.0.1",
175 | "Source": "Repository",
176 | "Repository": "RSPM",
177 | "Requirements": [
178 | "rprojroot"
179 | ],
180 | "Hash": "24b224366f9c2e7534d2344d10d59211"
181 | },
182 | "highr": {
183 | "Package": "highr",
184 | "Version": "0.11",
185 | "Source": "Repository",
186 | "Repository": "RSPM",
187 | "Requirements": [
188 | "R",
189 | "xfun"
190 | ],
191 | "Hash": "d65ba49117ca223614f71b60d85b8ab7"
192 | },
193 | "htmltools": {
194 | "Package": "htmltools",
195 | "Version": "0.5.8.1",
196 | "Source": "Repository",
197 | "Repository": "RSPM",
198 | "Requirements": [
199 | "R",
200 | "base64enc",
201 | "digest",
202 | "fastmap",
203 | "grDevices",
204 | "rlang",
205 | "utils"
206 | ],
207 | "Hash": "81d371a9cc60640e74e4ab6ac46dcedc"
208 | },
209 | "jquerylib": {
210 | "Package": "jquerylib",
211 | "Version": "0.1.4",
212 | "Source": "Repository",
213 | "Repository": "RSPM",
214 | "Requirements": [
215 | "htmltools"
216 | ],
217 | "Hash": "5aab57a3bd297eee1c1d862735972182"
218 | },
219 | "jsonlite": {
220 | "Package": "jsonlite",
221 | "Version": "1.8.9",
222 | "Source": "Repository",
223 | "Repository": "CRAN",
224 | "Requirements": [
225 | "methods"
226 | ],
227 | "Hash": "4e993b65c2c3ffbffce7bb3e2c6f832b"
228 | },
229 | "jsonvalidate": {
230 | "Package": "jsonvalidate",
231 | "Version": "1.3.2",
232 | "Source": "Repository",
233 | "Repository": "CRAN",
234 | "Requirements": [
235 | "V8"
236 | ],
237 | "Hash": "cdc2843ef7f44f157198bb99aea7552d"
238 | },
239 | "knitr": {
240 | "Package": "knitr",
241 | "Version": "1.49",
242 | "Source": "Repository",
243 | "Repository": "CRAN",
244 | "Requirements": [
245 | "R",
246 | "evaluate",
247 | "highr",
248 | "methods",
249 | "tools",
250 | "xfun",
251 | "yaml"
252 | ],
253 | "Hash": "9fcb189926d93c636dea94fbe4f44480"
254 | },
255 | "lifecycle": {
256 | "Package": "lifecycle",
257 | "Version": "1.0.4",
258 | "Source": "Repository",
259 | "Repository": "CRAN",
260 | "Requirements": [
261 | "R",
262 | "cli",
263 | "glue",
264 | "rlang"
265 | ],
266 | "Hash": "b8552d117e1b808b09a832f589b79035"
267 | },
268 | "memoise": {
269 | "Package": "memoise",
270 | "Version": "2.0.1",
271 | "Source": "Repository",
272 | "Repository": "RSPM",
273 | "Requirements": [
274 | "cachem",
275 | "rlang"
276 | ],
277 | "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c"
278 | },
279 | "mime": {
280 | "Package": "mime",
281 | "Version": "0.12",
282 | "Source": "Repository",
283 | "Repository": "RSPM",
284 | "Requirements": [
285 | "tools"
286 | ],
287 | "Hash": "18e9c28c1d3ca1560ce30658b22ce104"
288 | },
289 | "rappdirs": {
290 | "Package": "rappdirs",
291 | "Version": "0.3.3",
292 | "Source": "Repository",
293 | "Repository": "RSPM",
294 | "Requirements": [
295 | "R"
296 | ],
297 | "Hash": "5e3c5dc0b071b21fa128676560dbe94d"
298 | },
299 | "renv": {
300 | "Package": "renv",
301 | "Version": "1.0.2",
302 | "Source": "Repository",
303 | "Repository": "CRAN",
304 | "Requirements": [
305 | "utils"
306 | ],
307 | "Hash": "4b22ac016fe54028b88d0c68badbd061"
308 | },
309 | "rlang": {
310 | "Package": "rlang",
311 | "Version": "1.1.4",
312 | "Source": "Repository",
313 | "Repository": "RSPM",
314 | "Requirements": [
315 | "R",
316 | "utils"
317 | ],
318 | "Hash": "3eec01f8b1dee337674b2e34ab1f9bc1"
319 | },
320 | "rmarkdown": {
321 | "Package": "rmarkdown",
322 | "Version": "2.29",
323 | "Source": "Repository",
324 | "Repository": "CRAN",
325 | "Requirements": [
326 | "R",
327 | "bslib",
328 | "evaluate",
329 | "fontawesome",
330 | "htmltools",
331 | "jquerylib",
332 | "jsonlite",
333 | "knitr",
334 | "methods",
335 | "tinytex",
336 | "tools",
337 | "utils",
338 | "xfun",
339 | "yaml"
340 | ],
341 | "Hash": "df99277f63d01c34e95e3d2f06a79736"
342 | },
343 | "rprojroot": {
344 | "Package": "rprojroot",
345 | "Version": "2.0.4",
346 | "Source": "Repository",
347 | "Repository": "CRAN",
348 | "Requirements": [
349 | "R"
350 | ],
351 | "Hash": "4c8415e0ec1e29f3f4f6fc108bef0144"
352 | },
353 | "sass": {
354 | "Package": "sass",
355 | "Version": "0.4.9",
356 | "Source": "Repository",
357 | "Repository": "RSPM",
358 | "Requirements": [
359 | "R6",
360 | "fs",
361 | "htmltools",
362 | "rappdirs",
363 | "rlang"
364 | ],
365 | "Hash": "d53dbfddf695303ea4ad66f86e99b95d"
366 | },
367 | "tinytex": {
368 | "Package": "tinytex",
369 | "Version": "0.54",
370 | "Source": "Repository",
371 | "Repository": "CRAN",
372 | "Requirements": [
373 | "xfun"
374 | ],
375 | "Hash": "3ec7e3ddcacc2d34a9046941222bf94d"
376 | },
377 | "xfun": {
378 | "Package": "xfun",
379 | "Version": "0.49",
380 | "Source": "Repository",
381 | "Repository": "CRAN",
382 | "Requirements": [
383 | "R",
384 | "grDevices",
385 | "stats",
386 | "tools"
387 | ],
388 | "Hash": "8687398773806cfff9401a2feca96298"
389 | },
390 | "yaml": {
391 | "Package": "yaml",
392 | "Version": "2.3.10",
393 | "Source": "Repository",
394 | "Repository": "CRAN",
395 | "Hash": "51dab85c6c98e50a18d7551e9d49f76c"
396 | }
397 | }
398 | }
399 |
--------------------------------------------------------------------------------
/renv/.gitignore:
--------------------------------------------------------------------------------
1 | library/
2 | local/
3 | cellar/
4 | lock/
5 | python/
6 | sandbox/
7 | staging/
8 |
--------------------------------------------------------------------------------
/renv/activate.R:
--------------------------------------------------------------------------------
1 |
2 | local({
3 |
4 | # the requested version of renv
5 | version <- "1.0.2"
6 | attr(version, "sha") <- NULL
7 |
8 | # the project directory
9 | project <- getwd()
10 |
11 | # use start-up diagnostics if enabled
12 | diagnostics <- Sys.getenv("RENV_STARTUP_DIAGNOSTICS", unset = "FALSE")
13 | if (diagnostics) {
14 | start <- Sys.time()
15 | profile <- tempfile("renv-startup-", fileext = ".Rprof")
16 | utils::Rprof(profile)
17 | on.exit({
18 | utils::Rprof(NULL)
19 | elapsed <- signif(difftime(Sys.time(), start, units = "auto"), digits = 2L)
20 | writeLines(sprintf("- renv took %s to run the autoloader.", format(elapsed)))
21 | writeLines(sprintf("- Profile: %s", profile))
22 | print(utils::summaryRprof(profile))
23 | }, add = TRUE)
24 | }
25 |
26 | # figure out whether the autoloader is enabled
27 | enabled <- local({
28 |
29 | # first, check config option
30 | override <- getOption("renv.config.autoloader.enabled")
31 | if (!is.null(override))
32 | return(override)
33 |
34 | # next, check environment variables
35 | # TODO: prefer using the configuration one in the future
36 | envvars <- c(
37 | "RENV_CONFIG_AUTOLOADER_ENABLED",
38 | "RENV_AUTOLOADER_ENABLED",
39 | "RENV_ACTIVATE_PROJECT"
40 | )
41 |
42 | for (envvar in envvars) {
43 | envval <- Sys.getenv(envvar, unset = NA)
44 | if (!is.na(envval))
45 | return(tolower(envval) %in% c("true", "t", "1"))
46 | }
47 |
48 | # enable by default
49 | TRUE
50 |
51 | })
52 |
53 | if (!enabled)
54 | return(FALSE)
55 |
56 | # avoid recursion
57 | if (identical(getOption("renv.autoloader.running"), TRUE)) {
58 | warning("ignoring recursive attempt to run renv autoloader")
59 | return(invisible(TRUE))
60 | }
61 |
62 | # signal that we're loading renv during R startup
63 | options(renv.autoloader.running = TRUE)
64 | on.exit(options(renv.autoloader.running = NULL), add = TRUE)
65 |
66 | # signal that we've consented to use renv
67 | options(renv.consent = TRUE)
68 |
69 | # load the 'utils' package eagerly -- this ensures that renv shims, which
70 | # mask 'utils' packages, will come first on the search path
71 | library(utils, lib.loc = .Library)
72 |
73 | # unload renv if it's already been loaded
74 | if ("renv" %in% loadedNamespaces())
75 | unloadNamespace("renv")
76 |
77 | # load bootstrap tools
78 | `%||%` <- function(x, y) {
79 | if (is.null(x)) y else x
80 | }
81 |
82 | catf <- function(fmt, ..., appendLF = TRUE) {
83 |
84 | quiet <- getOption("renv.bootstrap.quiet", default = FALSE)
85 | if (quiet)
86 | return(invisible())
87 |
88 | msg <- sprintf(fmt, ...)
89 | cat(msg, file = stdout(), sep = if (appendLF) "\n" else "")
90 |
91 | invisible(msg)
92 |
93 | }
94 |
95 | header <- function(label,
96 | ...,
97 | prefix = "#",
98 | suffix = "-",
99 | n = min(getOption("width"), 78))
100 | {
101 | label <- sprintf(label, ...)
102 | n <- max(n - nchar(label) - nchar(prefix) - 2L, 8L)
103 | if (n <= 0)
104 | return(paste(prefix, label))
105 |
106 | tail <- paste(rep.int(suffix, n), collapse = "")
107 | paste0(prefix, " ", label, " ", tail)
108 |
109 | }
110 |
111 | startswith <- function(string, prefix) {
112 | substring(string, 1, nchar(prefix)) == prefix
113 | }
114 |
115 | bootstrap <- function(version, library) {
116 |
117 | friendly <- renv_bootstrap_version_friendly(version)
118 | section <- header(sprintf("Bootstrapping renv %s", friendly))
119 | catf(section)
120 |
121 | # attempt to download renv
122 | catf("- Downloading renv ... ", appendLF = FALSE)
123 | withCallingHandlers(
124 | tarball <- renv_bootstrap_download(version),
125 | error = function(err) {
126 | catf("FAILED")
127 | stop("failed to download:\n", conditionMessage(err))
128 | }
129 | )
130 | catf("OK")
131 | on.exit(unlink(tarball), add = TRUE)
132 |
133 | # now attempt to install
134 | catf("- Installing renv ... ", appendLF = FALSE)
135 | withCallingHandlers(
136 | status <- renv_bootstrap_install(version, tarball, library),
137 | error = function(err) {
138 | catf("FAILED")
139 | stop("failed to install:\n", conditionMessage(err))
140 | }
141 | )
142 | catf("OK")
143 |
144 | # add empty line to break up bootstrapping from normal output
145 | catf("")
146 |
147 | return(invisible())
148 | }
149 |
150 | renv_bootstrap_tests_running <- function() {
151 | getOption("renv.tests.running", default = FALSE)
152 | }
153 |
154 | renv_bootstrap_repos <- function() {
155 |
156 | # get CRAN repository
157 | cran <- getOption("renv.repos.cran", "https://cloud.r-project.org")
158 |
159 | # check for repos override
160 | repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA)
161 | if (!is.na(repos)) {
162 |
163 | # check for RSPM; if set, use a fallback repository for renv
164 | rspm <- Sys.getenv("RSPM", unset = NA)
165 | if (identical(rspm, repos))
166 | repos <- c(RSPM = rspm, CRAN = cran)
167 |
168 | return(repos)
169 |
170 | }
171 |
172 | # check for lockfile repositories
173 | repos <- tryCatch(renv_bootstrap_repos_lockfile(), error = identity)
174 | if (!inherits(repos, "error") && length(repos))
175 | return(repos)
176 |
177 | # retrieve current repos
178 | repos <- getOption("repos")
179 |
180 | # ensure @CRAN@ entries are resolved
181 | repos[repos == "@CRAN@"] <- cran
182 |
183 | # add in renv.bootstrap.repos if set
184 | default <- c(FALLBACK = "https://cloud.r-project.org")
185 | extra <- getOption("renv.bootstrap.repos", default = default)
186 | repos <- c(repos, extra)
187 |
188 | # remove duplicates that might've snuck in
189 | dupes <- duplicated(repos) | duplicated(names(repos))
190 | repos[!dupes]
191 |
192 | }
193 |
194 | renv_bootstrap_repos_lockfile <- function() {
195 |
196 | lockpath <- Sys.getenv("RENV_PATHS_LOCKFILE", unset = "renv.lock")
197 | if (!file.exists(lockpath))
198 | return(NULL)
199 |
200 | lockfile <- tryCatch(renv_json_read(lockpath), error = identity)
201 | if (inherits(lockfile, "error")) {
202 | warning(lockfile)
203 | return(NULL)
204 | }
205 |
206 | repos <- lockfile$R$Repositories
207 | if (length(repos) == 0)
208 | return(NULL)
209 |
210 | keys <- vapply(repos, `[[`, "Name", FUN.VALUE = character(1))
211 | vals <- vapply(repos, `[[`, "URL", FUN.VALUE = character(1))
212 | names(vals) <- keys
213 |
214 | return(vals)
215 |
216 | }
217 |
218 | renv_bootstrap_download <- function(version) {
219 |
220 | sha <- attr(version, "sha", exact = TRUE)
221 |
222 | methods <- if (!is.null(sha)) {
223 |
224 | # attempting to bootstrap a development version of renv
225 | c(
226 | function() renv_bootstrap_download_tarball(sha),
227 | function() renv_bootstrap_download_github(sha)
228 | )
229 |
230 | } else {
231 |
232 | # attempting to bootstrap a release version of renv
233 | c(
234 | function() renv_bootstrap_download_tarball(version),
235 | function() renv_bootstrap_download_cran_latest(version),
236 | function() renv_bootstrap_download_cran_archive(version)
237 | )
238 |
239 | }
240 |
241 | for (method in methods) {
242 | path <- tryCatch(method(), error = identity)
243 | if (is.character(path) && file.exists(path))
244 | return(path)
245 | }
246 |
247 | stop("All download methods failed")
248 |
249 | }
250 |
251 | renv_bootstrap_download_impl <- function(url, destfile) {
252 |
253 | mode <- "wb"
254 |
255 | # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715
256 | fixup <-
257 | Sys.info()[["sysname"]] == "Windows" &&
258 | substring(url, 1L, 5L) == "file:"
259 |
260 | if (fixup)
261 | mode <- "w+b"
262 |
263 | args <- list(
264 | url = url,
265 | destfile = destfile,
266 | mode = mode,
267 | quiet = TRUE
268 | )
269 |
270 | if ("headers" %in% names(formals(utils::download.file)))
271 | args$headers <- renv_bootstrap_download_custom_headers(url)
272 |
273 | do.call(utils::download.file, args)
274 |
275 | }
276 |
277 | renv_bootstrap_download_custom_headers <- function(url) {
278 |
279 | headers <- getOption("renv.download.headers")
280 | if (is.null(headers))
281 | return(character())
282 |
283 | if (!is.function(headers))
284 | stopf("'renv.download.headers' is not a function")
285 |
286 | headers <- headers(url)
287 | if (length(headers) == 0L)
288 | return(character())
289 |
290 | if (is.list(headers))
291 | headers <- unlist(headers, recursive = FALSE, use.names = TRUE)
292 |
293 | ok <-
294 | is.character(headers) &&
295 | is.character(names(headers)) &&
296 | all(nzchar(names(headers)))
297 |
298 | if (!ok)
299 | stop("invocation of 'renv.download.headers' did not return a named character vector")
300 |
301 | headers
302 |
303 | }
304 |
305 | renv_bootstrap_download_cran_latest <- function(version) {
306 |
307 | spec <- renv_bootstrap_download_cran_latest_find(version)
308 | type <- spec$type
309 | repos <- spec$repos
310 |
311 | baseurl <- utils::contrib.url(repos = repos, type = type)
312 | ext <- if (identical(type, "source"))
313 | ".tar.gz"
314 | else if (Sys.info()[["sysname"]] == "Windows")
315 | ".zip"
316 | else
317 | ".tgz"
318 | name <- sprintf("renv_%s%s", version, ext)
319 | url <- paste(baseurl, name, sep = "/")
320 |
321 | destfile <- file.path(tempdir(), name)
322 | status <- tryCatch(
323 | renv_bootstrap_download_impl(url, destfile),
324 | condition = identity
325 | )
326 |
327 | if (inherits(status, "condition"))
328 | return(FALSE)
329 |
330 | # report success and return
331 | destfile
332 |
333 | }
334 |
335 | renv_bootstrap_download_cran_latest_find <- function(version) {
336 |
337 | # check whether binaries are supported on this system
338 | binary <-
339 | getOption("renv.bootstrap.binary", default = TRUE) &&
340 | !identical(.Platform$pkgType, "source") &&
341 | !identical(getOption("pkgType"), "source") &&
342 | Sys.info()[["sysname"]] %in% c("Darwin", "Windows")
343 |
344 | types <- c(if (binary) "binary", "source")
345 |
346 | # iterate over types + repositories
347 | for (type in types) {
348 | for (repos in renv_bootstrap_repos()) {
349 |
350 | # retrieve package database
351 | db <- tryCatch(
352 | as.data.frame(
353 | utils::available.packages(type = type, repos = repos),
354 | stringsAsFactors = FALSE
355 | ),
356 | error = identity
357 | )
358 |
359 | if (inherits(db, "error"))
360 | next
361 |
362 | # check for compatible entry
363 | entry <- db[db$Package %in% "renv" & db$Version %in% version, ]
364 | if (nrow(entry) == 0)
365 | next
366 |
367 | # found it; return spec to caller
368 | spec <- list(entry = entry, type = type, repos = repos)
369 | return(spec)
370 |
371 | }
372 | }
373 |
374 | # if we got here, we failed to find renv
375 | fmt <- "renv %s is not available from your declared package repositories"
376 | stop(sprintf(fmt, version))
377 |
378 | }
379 |
380 | renv_bootstrap_download_cran_archive <- function(version) {
381 |
382 | name <- sprintf("renv_%s.tar.gz", version)
383 | repos <- renv_bootstrap_repos()
384 | urls <- file.path(repos, "src/contrib/Archive/renv", name)
385 | destfile <- file.path(tempdir(), name)
386 |
387 | for (url in urls) {
388 |
389 | status <- tryCatch(
390 | renv_bootstrap_download_impl(url, destfile),
391 | condition = identity
392 | )
393 |
394 | if (identical(status, 0L))
395 | return(destfile)
396 |
397 | }
398 |
399 | return(FALSE)
400 |
401 | }
402 |
403 | renv_bootstrap_download_tarball <- function(version) {
404 |
405 | # if the user has provided the path to a tarball via
406 | # an environment variable, then use it
407 | tarball <- Sys.getenv("RENV_BOOTSTRAP_TARBALL", unset = NA)
408 | if (is.na(tarball))
409 | return()
410 |
411 | # allow directories
412 | if (dir.exists(tarball)) {
413 | name <- sprintf("renv_%s.tar.gz", version)
414 | tarball <- file.path(tarball, name)
415 | }
416 |
417 | # bail if it doesn't exist
418 | if (!file.exists(tarball)) {
419 |
420 | # let the user know we weren't able to honour their request
421 | fmt <- "- RENV_BOOTSTRAP_TARBALL is set (%s) but does not exist."
422 | msg <- sprintf(fmt, tarball)
423 | warning(msg)
424 |
425 | # bail
426 | return()
427 |
428 | }
429 |
430 | catf("- Using local tarball '%s'.", tarball)
431 | tarball
432 |
433 | }
434 |
435 | renv_bootstrap_download_github <- function(version) {
436 |
437 | enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE")
438 | if (!identical(enabled, "TRUE"))
439 | return(FALSE)
440 |
441 | # prepare download options
442 | pat <- Sys.getenv("GITHUB_PAT")
443 | if (nzchar(Sys.which("curl")) && nzchar(pat)) {
444 | fmt <- "--location --fail --header \"Authorization: token %s\""
445 | extra <- sprintf(fmt, pat)
446 | saved <- options("download.file.method", "download.file.extra")
447 | options(download.file.method = "curl", download.file.extra = extra)
448 | on.exit(do.call(base::options, saved), add = TRUE)
449 | } else if (nzchar(Sys.which("wget")) && nzchar(pat)) {
450 | fmt <- "--header=\"Authorization: token %s\""
451 | extra <- sprintf(fmt, pat)
452 | saved <- options("download.file.method", "download.file.extra")
453 | options(download.file.method = "wget", download.file.extra = extra)
454 | on.exit(do.call(base::options, saved), add = TRUE)
455 | }
456 |
457 | url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version)
458 | name <- sprintf("renv_%s.tar.gz", version)
459 | destfile <- file.path(tempdir(), name)
460 |
461 | status <- tryCatch(
462 | renv_bootstrap_download_impl(url, destfile),
463 | condition = identity
464 | )
465 |
466 | if (!identical(status, 0L))
467 | return(FALSE)
468 |
469 | renv_bootstrap_download_augment(destfile)
470 |
471 | return(destfile)
472 |
473 | }
474 |
475 | # Add Sha to DESCRIPTION. This is stop gap until #890, after which we
476 | # can use renv::install() to fully capture metadata.
477 | renv_bootstrap_download_augment <- function(destfile) {
478 | sha <- renv_bootstrap_git_extract_sha1_tar(destfile)
479 | if (is.null(sha)) {
480 | return()
481 | }
482 |
483 | # Untar
484 | tempdir <- tempfile("renv-github-")
485 | on.exit(unlink(tempdir, recursive = TRUE), add = TRUE)
486 | untar(destfile, exdir = tempdir)
487 | pkgdir <- dir(tempdir, full.names = TRUE)[[1]]
488 |
489 | # Modify description
490 | desc_path <- file.path(pkgdir, "DESCRIPTION")
491 | desc_lines <- readLines(desc_path)
492 | remotes_fields <- c(
493 | "RemoteType: github",
494 | "RemoteHost: api.github.com",
495 | "RemoteRepo: renv",
496 | "RemoteUsername: rstudio",
497 | "RemotePkgRef: rstudio/renv",
498 | paste("RemoteRef: ", sha),
499 | paste("RemoteSha: ", sha)
500 | )
501 | writeLines(c(desc_lines[desc_lines != ""], remotes_fields), con = desc_path)
502 |
503 | # Re-tar
504 | local({
505 | old <- setwd(tempdir)
506 | on.exit(setwd(old), add = TRUE)
507 |
508 | tar(destfile, compression = "gzip")
509 | })
510 | invisible()
511 | }
512 |
513 | # Extract the commit hash from a git archive. Git archives include the SHA1
514 | # hash as the comment field of the tarball pax extended header
515 | # (see https://www.kernel.org/pub/software/scm/git/docs/git-archive.html)
516 | # For GitHub archives this should be the first header after the default one
517 | # (512 byte) header.
518 | renv_bootstrap_git_extract_sha1_tar <- function(bundle) {
519 |
520 | # open the bundle for reading
521 | # We use gzcon for everything because (from ?gzcon)
522 | # > Reading from a connection which does not supply a 'gzip' magic
523 | # > header is equivalent to reading from the original connection
524 | conn <- gzcon(file(bundle, open = "rb", raw = TRUE))
525 | on.exit(close(conn))
526 |
527 | # The default pax header is 512 bytes long and the first pax extended header
528 | # with the comment should be 51 bytes long
529 | # `52 comment=` (11 chars) + 40 byte SHA1 hash
530 | len <- 0x200 + 0x33
531 | res <- rawToChar(readBin(conn, "raw", n = len)[0x201:len])
532 |
533 | if (grepl("^52 comment=", res)) {
534 | sub("52 comment=", "", res)
535 | } else {
536 | NULL
537 | }
538 | }
539 |
540 | renv_bootstrap_install <- function(version, tarball, library) {
541 |
542 | # attempt to install it into project library
543 | dir.create(library, showWarnings = FALSE, recursive = TRUE)
544 | output <- renv_bootstrap_install_impl(library, tarball)
545 |
546 | # check for successful install
547 | status <- attr(output, "status")
548 | if (is.null(status) || identical(status, 0L))
549 | return(status)
550 |
551 | # an error occurred; report it
552 | header <- "installation of renv failed"
553 | lines <- paste(rep.int("=", nchar(header)), collapse = "")
554 | text <- paste(c(header, lines, output), collapse = "\n")
555 | stop(text)
556 |
557 | }
558 |
559 | renv_bootstrap_install_impl <- function(library, tarball) {
560 |
561 | # invoke using system2 so we can capture and report output
562 | bin <- R.home("bin")
563 | exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R"
564 | R <- file.path(bin, exe)
565 |
566 | args <- c(
567 | "--vanilla", "CMD", "INSTALL", "--no-multiarch",
568 | "-l", shQuote(path.expand(library)),
569 | shQuote(path.expand(tarball))
570 | )
571 |
572 | system2(R, args, stdout = TRUE, stderr = TRUE)
573 |
574 | }
575 |
576 | renv_bootstrap_platform_prefix <- function() {
577 |
578 | # construct version prefix
579 | version <- paste(R.version$major, R.version$minor, sep = ".")
580 | prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-")
581 |
582 | # include SVN revision for development versions of R
583 | # (to avoid sharing platform-specific artefacts with released versions of R)
584 | devel <-
585 | identical(R.version[["status"]], "Under development (unstable)") ||
586 | identical(R.version[["nickname"]], "Unsuffered Consequences")
587 |
588 | if (devel)
589 | prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r")
590 |
591 | # build list of path components
592 | components <- c(prefix, R.version$platform)
593 |
594 | # include prefix if provided by user
595 | prefix <- renv_bootstrap_platform_prefix_impl()
596 | if (!is.na(prefix) && nzchar(prefix))
597 | components <- c(prefix, components)
598 |
599 | # build prefix
600 | paste(components, collapse = "/")
601 |
602 | }
603 |
604 | renv_bootstrap_platform_prefix_impl <- function() {
605 |
606 | # if an explicit prefix has been supplied, use it
607 | prefix <- Sys.getenv("RENV_PATHS_PREFIX", unset = NA)
608 | if (!is.na(prefix))
609 | return(prefix)
610 |
611 | # if the user has requested an automatic prefix, generate it
612 | auto <- Sys.getenv("RENV_PATHS_PREFIX_AUTO", unset = NA)
613 | if (auto %in% c("TRUE", "True", "true", "1"))
614 | return(renv_bootstrap_platform_prefix_auto())
615 |
616 | # empty string on failure
617 | ""
618 |
619 | }
620 |
621 | renv_bootstrap_platform_prefix_auto <- function() {
622 |
623 | prefix <- tryCatch(renv_bootstrap_platform_os(), error = identity)
624 | if (inherits(prefix, "error") || prefix %in% "unknown") {
625 |
626 | msg <- paste(
627 | "failed to infer current operating system",
628 | "please file a bug report at https://github.com/rstudio/renv/issues",
629 | sep = "; "
630 | )
631 |
632 | warning(msg)
633 |
634 | }
635 |
636 | prefix
637 |
638 | }
639 |
640 | renv_bootstrap_platform_os <- function() {
641 |
642 | sysinfo <- Sys.info()
643 | sysname <- sysinfo[["sysname"]]
644 |
645 | # handle Windows + macOS up front
646 | if (sysname == "Windows")
647 | return("windows")
648 | else if (sysname == "Darwin")
649 | return("macos")
650 |
651 | # check for os-release files
652 | for (file in c("/etc/os-release", "/usr/lib/os-release"))
653 | if (file.exists(file))
654 | return(renv_bootstrap_platform_os_via_os_release(file, sysinfo))
655 |
656 | # check for redhat-release files
657 | if (file.exists("/etc/redhat-release"))
658 | return(renv_bootstrap_platform_os_via_redhat_release())
659 |
660 | "unknown"
661 |
662 | }
663 |
664 | renv_bootstrap_platform_os_via_os_release <- function(file, sysinfo) {
665 |
666 | # read /etc/os-release
667 | release <- utils::read.table(
668 | file = file,
669 | sep = "=",
670 | quote = c("\"", "'"),
671 | col.names = c("Key", "Value"),
672 | comment.char = "#",
673 | stringsAsFactors = FALSE
674 | )
675 |
676 | vars <- as.list(release$Value)
677 | names(vars) <- release$Key
678 |
679 | # get os name
680 | os <- tolower(sysinfo[["sysname"]])
681 |
682 | # read id
683 | id <- "unknown"
684 | for (field in c("ID", "ID_LIKE")) {
685 | if (field %in% names(vars) && nzchar(vars[[field]])) {
686 | id <- vars[[field]]
687 | break
688 | }
689 | }
690 |
691 | # read version
692 | version <- "unknown"
693 | for (field in c("UBUNTU_CODENAME", "VERSION_CODENAME", "VERSION_ID", "BUILD_ID")) {
694 | if (field %in% names(vars) && nzchar(vars[[field]])) {
695 | version <- vars[[field]]
696 | break
697 | }
698 | }
699 |
700 | # join together
701 | paste(c(os, id, version), collapse = "-")
702 |
703 | }
704 |
705 | renv_bootstrap_platform_os_via_redhat_release <- function() {
706 |
707 | # read /etc/redhat-release
708 | contents <- readLines("/etc/redhat-release", warn = FALSE)
709 |
710 | # infer id
711 | id <- if (grepl("centos", contents, ignore.case = TRUE))
712 | "centos"
713 | else if (grepl("redhat", contents, ignore.case = TRUE))
714 | "redhat"
715 | else
716 | "unknown"
717 |
718 | # try to find a version component (very hacky)
719 | version <- "unknown"
720 |
721 | parts <- strsplit(contents, "[[:space:]]")[[1L]]
722 | for (part in parts) {
723 |
724 | nv <- tryCatch(numeric_version(part), error = identity)
725 | if (inherits(nv, "error"))
726 | next
727 |
728 | version <- nv[1, 1]
729 | break
730 |
731 | }
732 |
733 | paste(c("linux", id, version), collapse = "-")
734 |
735 | }
736 |
737 | renv_bootstrap_library_root_name <- function(project) {
738 |
739 | # use project name as-is if requested
740 | asis <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT_ASIS", unset = "FALSE")
741 | if (asis)
742 | return(basename(project))
743 |
744 | # otherwise, disambiguate based on project's path
745 | id <- substring(renv_bootstrap_hash_text(project), 1L, 8L)
746 | paste(basename(project), id, sep = "-")
747 |
748 | }
749 |
750 | renv_bootstrap_library_root <- function(project) {
751 |
752 | prefix <- renv_bootstrap_profile_prefix()
753 |
754 | path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA)
755 | if (!is.na(path))
756 | return(paste(c(path, prefix), collapse = "/"))
757 |
758 | path <- renv_bootstrap_library_root_impl(project)
759 | if (!is.null(path)) {
760 | name <- renv_bootstrap_library_root_name(project)
761 | return(paste(c(path, prefix, name), collapse = "/"))
762 | }
763 |
764 | renv_bootstrap_paths_renv("library", project = project)
765 |
766 | }
767 |
768 | renv_bootstrap_library_root_impl <- function(project) {
769 |
770 | root <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA)
771 | if (!is.na(root))
772 | return(root)
773 |
774 | type <- renv_bootstrap_project_type(project)
775 | if (identical(type, "package")) {
776 | userdir <- renv_bootstrap_user_dir()
777 | return(file.path(userdir, "library"))
778 | }
779 |
780 | }
781 |
782 | renv_bootstrap_validate_version <- function(version, description = NULL) {
783 |
784 | # resolve description file
785 | #
786 | # avoid passing lib.loc to `packageDescription()` below, since R will
787 | # use the loaded version of the package by default anyhow. note that
788 | # this function should only be called after 'renv' is loaded
789 | # https://github.com/rstudio/renv/issues/1625
790 | description <- description %||% packageDescription("renv")
791 |
792 | # check whether requested version 'version' matches loaded version of renv
793 | sha <- attr(version, "sha", exact = TRUE)
794 | valid <- if (!is.null(sha))
795 | renv_bootstrap_validate_version_dev(sha, description)
796 | else
797 | renv_bootstrap_validate_version_release(version, description)
798 |
799 | if (valid)
800 | return(TRUE)
801 |
802 | # the loaded version of renv doesn't match the requested version;
803 | # give the user instructions on how to proceed
804 | remote <- if (!is.null(description[["RemoteSha"]])) {
805 | paste("rstudio/renv", description[["RemoteSha"]], sep = "@")
806 | } else {
807 | paste("renv", description[["Version"]], sep = "@")
808 | }
809 |
810 | # display both loaded version + sha if available
811 | friendly <- renv_bootstrap_version_friendly(
812 | version = description[["Version"]],
813 | sha = description[["RemoteSha"]]
814 | )
815 |
816 | fmt <- paste(
817 | "renv %1$s was loaded from project library, but this project is configured to use renv %2$s.",
818 | "- Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile.",
819 | "- Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.",
820 | sep = "\n"
821 | )
822 | catf(fmt, friendly, renv_bootstrap_version_friendly(version), remote)
823 |
824 | FALSE
825 |
826 | }
827 |
828 | renv_bootstrap_validate_version_dev <- function(version, description) {
829 | expected <- description[["RemoteSha"]]
830 | is.character(expected) && startswith(expected, version)
831 | }
832 |
833 | renv_bootstrap_validate_version_release <- function(version, description) {
834 | expected <- description[["Version"]]
835 | is.character(expected) && identical(expected, version)
836 | }
837 |
838 | renv_bootstrap_hash_text <- function(text) {
839 |
840 | hashfile <- tempfile("renv-hash-")
841 | on.exit(unlink(hashfile), add = TRUE)
842 |
843 | writeLines(text, con = hashfile)
844 | tools::md5sum(hashfile)
845 |
846 | }
847 |
848 | renv_bootstrap_load <- function(project, libpath, version) {
849 |
850 | # try to load renv from the project library
851 | if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE))
852 | return(FALSE)
853 |
854 | # warn if the version of renv loaded does not match
855 | renv_bootstrap_validate_version(version)
856 |
857 | # execute renv load hooks, if any
858 | hooks <- getHook("renv::autoload")
859 | for (hook in hooks)
860 | if (is.function(hook))
861 | tryCatch(hook(), error = warnify)
862 |
863 | # load the project
864 | renv::load(project)
865 |
866 | TRUE
867 |
868 | }
869 |
870 | renv_bootstrap_profile_load <- function(project) {
871 |
872 | # if RENV_PROFILE is already set, just use that
873 | profile <- Sys.getenv("RENV_PROFILE", unset = NA)
874 | if (!is.na(profile) && nzchar(profile))
875 | return(profile)
876 |
877 | # check for a profile file (nothing to do if it doesn't exist)
878 | path <- renv_bootstrap_paths_renv("profile", profile = FALSE, project = project)
879 | if (!file.exists(path))
880 | return(NULL)
881 |
882 | # read the profile, and set it if it exists
883 | contents <- readLines(path, warn = FALSE)
884 | if (length(contents) == 0L)
885 | return(NULL)
886 |
887 | # set RENV_PROFILE
888 | profile <- contents[[1L]]
889 | if (!profile %in% c("", "default"))
890 | Sys.setenv(RENV_PROFILE = profile)
891 |
892 | profile
893 |
894 | }
895 |
896 | renv_bootstrap_profile_prefix <- function() {
897 | profile <- renv_bootstrap_profile_get()
898 | if (!is.null(profile))
899 | return(file.path("profiles", profile, "renv"))
900 | }
901 |
902 | renv_bootstrap_profile_get <- function() {
903 | profile <- Sys.getenv("RENV_PROFILE", unset = "")
904 | renv_bootstrap_profile_normalize(profile)
905 | }
906 |
907 | renv_bootstrap_profile_set <- function(profile) {
908 | profile <- renv_bootstrap_profile_normalize(profile)
909 | if (is.null(profile))
910 | Sys.unsetenv("RENV_PROFILE")
911 | else
912 | Sys.setenv(RENV_PROFILE = profile)
913 | }
914 |
915 | renv_bootstrap_profile_normalize <- function(profile) {
916 |
917 | if (is.null(profile) || profile %in% c("", "default"))
918 | return(NULL)
919 |
920 | profile
921 |
922 | }
923 |
924 | renv_bootstrap_path_absolute <- function(path) {
925 |
926 | substr(path, 1L, 1L) %in% c("~", "/", "\\") || (
927 | substr(path, 1L, 1L) %in% c(letters, LETTERS) &&
928 | substr(path, 2L, 3L) %in% c(":/", ":\\")
929 | )
930 |
931 | }
932 |
933 | renv_bootstrap_paths_renv <- function(..., profile = TRUE, project = NULL) {
934 | renv <- Sys.getenv("RENV_PATHS_RENV", unset = "renv")
935 | root <- if (renv_bootstrap_path_absolute(renv)) NULL else project
936 | prefix <- if (profile) renv_bootstrap_profile_prefix()
937 | components <- c(root, renv, prefix, ...)
938 | paste(components, collapse = "/")
939 | }
940 |
941 | renv_bootstrap_project_type <- function(path) {
942 |
943 | descpath <- file.path(path, "DESCRIPTION")
944 | if (!file.exists(descpath))
945 | return("unknown")
946 |
947 | desc <- tryCatch(
948 | read.dcf(descpath, all = TRUE),
949 | error = identity
950 | )
951 |
952 | if (inherits(desc, "error"))
953 | return("unknown")
954 |
955 | type <- desc$Type
956 | if (!is.null(type))
957 | return(tolower(type))
958 |
959 | package <- desc$Package
960 | if (!is.null(package))
961 | return("package")
962 |
963 | "unknown"
964 |
965 | }
966 |
967 | renv_bootstrap_user_dir <- function() {
968 | dir <- renv_bootstrap_user_dir_impl()
969 | path.expand(chartr("\\", "/", dir))
970 | }
971 |
972 | renv_bootstrap_user_dir_impl <- function() {
973 |
974 | # use local override if set
975 | override <- getOption("renv.userdir.override")
976 | if (!is.null(override))
977 | return(override)
978 |
979 | # use R_user_dir if available
980 | tools <- asNamespace("tools")
981 | if (is.function(tools$R_user_dir))
982 | return(tools$R_user_dir("renv", "cache"))
983 |
984 | # try using our own backfill for older versions of R
985 | envvars <- c("R_USER_CACHE_DIR", "XDG_CACHE_HOME")
986 | for (envvar in envvars) {
987 | root <- Sys.getenv(envvar, unset = NA)
988 | if (!is.na(root))
989 | return(file.path(root, "R/renv"))
990 | }
991 |
992 | # use platform-specific default fallbacks
993 | if (Sys.info()[["sysname"]] == "Windows")
994 | file.path(Sys.getenv("LOCALAPPDATA"), "R/cache/R/renv")
995 | else if (Sys.info()[["sysname"]] == "Darwin")
996 | "~/Library/Caches/org.R-project.R/R/renv"
997 | else
998 | "~/.cache/R/renv"
999 |
1000 | }
1001 |
1002 | renv_bootstrap_version_friendly <- function(version, shafmt = NULL, sha = NULL) {
1003 | sha <- sha %||% attr(version, "sha", exact = TRUE)
1004 | parts <- c(version, sprintf(shafmt %||% " [sha: %s]", substring(sha, 1L, 7L)))
1005 | paste(parts, collapse = "")
1006 | }
1007 |
1008 | renv_bootstrap_exec <- function(project, libpath, version) {
1009 | if (!renv_bootstrap_load(project, libpath, version))
1010 | renv_bootstrap_run(version, libpath)
1011 | }
1012 |
1013 | renv_bootstrap_run <- function(version, libpath) {
1014 |
1015 | # perform bootstrap
1016 | bootstrap(version, libpath)
1017 |
1018 | # exit early if we're just testing bootstrap
1019 | if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA)))
1020 | return(TRUE)
1021 |
1022 | # try again to load
1023 | if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) {
1024 | return(renv::load(project = getwd()))
1025 | }
1026 |
1027 | # failed to download or load renv; warn the user
1028 | msg <- c(
1029 | "Failed to find an renv installation: the project will not be loaded.",
1030 | "Use `renv::activate()` to re-initialize the project."
1031 | )
1032 |
1033 | warning(paste(msg, collapse = "\n"), call. = FALSE)
1034 |
1035 | }
1036 |
1037 |
1038 | renv_bootstrap_in_rstudio <- function() {
1039 | commandArgs()[[1]] == "RStudio"
1040 | }
1041 |
1042 | # Used to work around buglet in RStudio if hook uses readline
1043 | renv_bootstrap_flush_console <- function() {
1044 | tryCatch({
1045 | tools <- as.environment("tools:rstudio")
1046 | tools$.rs.api.sendToConsole("", echo = FALSE, focus = FALSE)
1047 | }, error = function(cnd) {})
1048 | }
1049 |
1050 | renv_json_read <- function(file = NULL, text = NULL) {
1051 |
1052 | jlerr <- NULL
1053 |
1054 | # if jsonlite is loaded, use that instead
1055 | if ("jsonlite" %in% loadedNamespaces()) {
1056 |
1057 | json <- catch(renv_json_read_jsonlite(file, text))
1058 | if (!inherits(json, "error"))
1059 | return(json)
1060 |
1061 | jlerr <- json
1062 |
1063 | }
1064 |
1065 | # otherwise, fall back to the default JSON reader
1066 | json <- catch(renv_json_read_default(file, text))
1067 | if (!inherits(json, "error"))
1068 | return(json)
1069 |
1070 | # report an error
1071 | if (!is.null(jlerr))
1072 | stop(jlerr)
1073 | else
1074 | stop(json)
1075 |
1076 | }
1077 |
1078 | renv_json_read_jsonlite <- function(file = NULL, text = NULL) {
1079 | text <- paste(text %||% read(file), collapse = "\n")
1080 | jsonlite::fromJSON(txt = text, simplifyVector = FALSE)
1081 | }
1082 |
1083 | renv_json_read_default <- function(file = NULL, text = NULL) {
1084 |
1085 | # find strings in the JSON
1086 | text <- paste(text %||% read(file), collapse = "\n")
1087 | pattern <- '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
1088 | locs <- gregexpr(pattern, text, perl = TRUE)[[1]]
1089 |
1090 | # if any are found, replace them with placeholders
1091 | replaced <- text
1092 | strings <- character()
1093 | replacements <- character()
1094 |
1095 | if (!identical(c(locs), -1L)) {
1096 |
1097 | # get the string values
1098 | starts <- locs
1099 | ends <- locs + attr(locs, "match.length") - 1L
1100 | strings <- substring(text, starts, ends)
1101 |
1102 | # only keep those requiring escaping
1103 | strings <- grep("[[\\]{}:]", strings, perl = TRUE, value = TRUE)
1104 |
1105 | # compute replacements
1106 | replacements <- sprintf('"\032%i\032"', seq_along(strings))
1107 |
1108 | # replace the strings
1109 | mapply(function(string, replacement) {
1110 | replaced <<- sub(string, replacement, replaced, fixed = TRUE)
1111 | }, strings, replacements)
1112 |
1113 | }
1114 |
1115 | # transform the JSON into something the R parser understands
1116 | transformed <- replaced
1117 | transformed <- gsub("{}", "`names<-`(list(), character())", transformed, fixed = TRUE)
1118 | transformed <- gsub("[[{]", "list(", transformed, perl = TRUE)
1119 | transformed <- gsub("[]}]", ")", transformed, perl = TRUE)
1120 | transformed <- gsub(":", "=", transformed, fixed = TRUE)
1121 | text <- paste(transformed, collapse = "\n")
1122 |
1123 | # parse it
1124 | json <- parse(text = text, keep.source = FALSE, srcfile = NULL)[[1L]]
1125 |
1126 | # construct map between source strings, replaced strings
1127 | map <- as.character(parse(text = strings))
1128 | names(map) <- as.character(parse(text = replacements))
1129 |
1130 | # convert to list
1131 | map <- as.list(map)
1132 |
1133 | # remap strings in object
1134 | remapped <- renv_json_remap(json, map)
1135 |
1136 | # evaluate
1137 | eval(remapped, envir = baseenv())
1138 |
1139 | }
1140 |
1141 | renv_json_remap <- function(json, map) {
1142 |
1143 | # fix names
1144 | if (!is.null(names(json))) {
1145 | lhs <- match(names(json), names(map), nomatch = 0L)
1146 | rhs <- match(names(map), names(json), nomatch = 0L)
1147 | names(json)[rhs] <- map[lhs]
1148 | }
1149 |
1150 | # fix values
1151 | if (is.character(json))
1152 | return(map[[json]] %||% json)
1153 |
1154 | # handle true, false, null
1155 | if (is.name(json)) {
1156 | text <- as.character(json)
1157 | if (text == "true")
1158 | return(TRUE)
1159 | else if (text == "false")
1160 | return(FALSE)
1161 | else if (text == "null")
1162 | return(NULL)
1163 | }
1164 |
1165 | # recurse
1166 | if (is.recursive(json)) {
1167 | for (i in seq_along(json)) {
1168 | json[i] <- list(renv_json_remap(json[[i]], map))
1169 | }
1170 | }
1171 |
1172 | json
1173 |
1174 | }
1175 |
1176 | # load the renv profile, if any
1177 | renv_bootstrap_profile_load(project)
1178 |
1179 | # construct path to library root
1180 | root <- renv_bootstrap_library_root(project)
1181 |
1182 | # construct library prefix for platform
1183 | prefix <- renv_bootstrap_platform_prefix()
1184 |
1185 | # construct full libpath
1186 | libpath <- file.path(root, prefix)
1187 |
1188 | if (renv_bootstrap_in_rstudio()) {
1189 | # RStudio only updates console once .Rprofile is finished, so
1190 | # instead run code on sessionInit
1191 | setHook("rstudio.sessionInit", function(...) {
1192 | renv_bootstrap_exec(project, libpath, version)
1193 | renv_bootstrap_flush_console()
1194 | })
1195 | } else {
1196 | renv_bootstrap_exec(project, libpath, version)
1197 | }
1198 |
1199 | invisible()
1200 |
1201 | })
1202 |
--------------------------------------------------------------------------------
/scripts/.entry_schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-04/schema#",
3 | "type": "object",
4 | "properties": {
5 | "title": {"type": "string"},
6 | "url": {"type": "string"},
7 | "rss_feed": {"type": "string"},
8 | "type": {"type": "string"},
9 | "photo_url": {"type": "string"},
10 | "description": {"type": "string"},
11 | "language": {"type": "string"},
12 | "authors": {
13 | "type": "array",
14 | "items": [
15 | {
16 | "type": "object",
17 | "properties": {
18 | "name": {"type": "string"},
19 | "social_media": {
20 | "type": "array",
21 | "items": [
22 | {
23 | "type": "object",
24 | "properties": {
25 | "twitter": {"type": "string"},
26 | "mastodon": {"type": "string"},
27 | "bluesky": {"type": "string"},
28 | "linkedin": {"type": "string"},
29 | "facebook": {"type": "string"},
30 | "github": {"type": "string"},
31 | "instagram": {"type": "string"},
32 | "youtube": {"type": "string"},
33 | "tiktok": {"type": "string"},
34 | "periscope": {"type": "string"},
35 | "researchgate": {"type": "string"},
36 | "website": {"type": "string"},
37 | "orcid": {"type": "string"},
38 | "meetup": {"type": "string"}
39 | }
40 | }
41 | ]
42 | }
43 | },
44 | "required": [
45 | "name"
46 | ]
47 | }
48 | ]
49 | }
50 | },
51 | "required": [
52 | "title",
53 | "url",
54 | "type",
55 | "authors",
56 | "language"
57 | ]
58 | }
59 |
--------------------------------------------------------------------------------
/scripts/check-images.R:
--------------------------------------------------------------------------------
1 | library(httr2)
2 |
3 | jfiles <- list.files(here::here("blogs"), "json$", full.names = TRUE)
4 | jcontent <- lapply(jfiles, jsonlite::read_json)
5 | names(jcontent) <- basename(jfiles)
6 |
7 |
8 | check_image <- function(x){
9 | if("photo_url" %in% names(x)){
10 | url_info <- request(x$photo_url) |>
11 | req_error(is_error = function(x){FALSE}) |>
12 | req_perform()
13 |
14 | exists <- resp_status(url_info) == 200
15 | if(!exists){
16 | message(sprintf("%s: photo url returns http status '%s': %s",
17 | x$url, resp_status(url_info), x$photo_url))
18 | return(FALSE)
19 | }
20 |
21 | is_image <- grepl("image", resp_content_type(url_info))
22 | if(!is_image){
23 | message(sprintf("%s: photo url does not return an image: %s",
24 | x$url, x$photo_url))
25 | return(FALSE)
26 | }
27 |
28 | return(all(exists, is_image))
29 | }
30 | }
31 |
32 | images <- sapply(jcontent, check_image, USE.NAMES = TRUE) |>
33 | unlist()
34 |
35 | missing_images <- images[!images]
36 |
37 | if(any(!missing_images)){
38 | stop("There are images in the data that don't return correctly. See build log for more details.", call. = FALSE)
39 | }
40 |
--------------------------------------------------------------------------------
/scripts/validate_jsons.R:
--------------------------------------------------------------------------------
1 | validate_jsons <- function(files, schema){
2 | validate <- jsonvalidate::json_validator(
3 | schema)
4 | k <- sapply(files, validate,
5 | verbose = TRUE,
6 | error = TRUE,
7 | greedy = TRUE)
8 | }
9 |
10 | files <- list.files(
11 | path = here::here("blogs"),
12 | full.names = TRUE
13 | )
14 | ext <- grep("json$", files, invert = TRUE)
15 | if(length(ext) > 0)
16 | stop("File has wrong extention. Please rename to end with 'json'\n",
17 | paste0(basename(files[grep("json$", files, invert = TRUE)]), collapse ="\n"),
18 | call. = FALSE)
19 |
20 | # Validate blog json
21 | validate_jsons(
22 | files,
23 | here::here("scripts/.entry_schema.json")
24 | )
25 |
26 |
27 |
--------------------------------------------------------------------------------