Repository: twindle-co/twindle Branch: main Commit: 489403a8c761 Files: 416 Total size: 729.3 KB Directory structure: gitextract_rvcqqkjj/ ├── .all-contributorsrc ├── .github/ │ ├── PULL_REQUEST_TEMPLATE.md │ ├── TEMP_ISSUE_TEMPLATE.md │ └── workflows/ │ ├── conflict.yml │ ├── stale.yml │ └── tests.yml ├── .gitignore ├── CNAME ├── LICENSE ├── README.md ├── misc/ │ ├── CONTRIBUTING.md │ ├── docs/ │ │ ├── CHEATSHEET.md │ │ ├── CODE-REVIEW-CHECKLIST.md │ │ ├── FAQ.md │ │ ├── NAMING-CONVENTIONS.md │ │ ├── ONBOARDING.md │ │ ├── README.md │ │ ├── RESOURCES.md │ │ ├── TEAM.md │ │ ├── TWINDLE.md │ │ ├── TWITTER.md │ │ ├── articles/ │ │ │ ├── Process-for-new-contributors.md │ │ │ ├── README.md │ │ │ ├── creating-first-pull-request.md │ │ │ ├── design-guide-for-good-logo.md │ │ │ ├── git -github-related.md │ │ │ ├── handlebar-explained.md │ │ │ ├── javascript-code.md │ │ │ ├── pr-clean-commits.md │ │ │ ├── puppeteer-explained.md │ │ │ ├── setup-prettier-vscode.md │ │ │ ├── solving-forked-commit-ahead.md │ │ │ ├── sync-to-main-repo-using-git-bash.md │ │ │ ├── sync-to-main-repo-using-pull-request.md │ │ │ └── sync-to-main-repo.md │ │ └── images/ │ │ └── README.md │ ├── firstpr/ │ │ ├── abdu_masoudi.md │ │ ├── abhilash_s_s.md │ │ ├── ad3rinto.md │ │ ├── adewale.md │ │ ├── aditya.md │ │ ├── aditya20233.md │ │ ├── aditya786.md │ │ ├── akshay.md │ │ ├── alejandra_pinto.md │ │ ├── alexis.md │ │ ├── ali.md │ │ ├── andrei.md │ │ ├── anujshukla.md │ │ ├── aparna.md │ │ ├── aravind.md │ │ ├── arthurbuhl.md │ │ ├── ashish.md │ │ ├── baijanath.md │ │ ├── bill.md │ │ ├── blessing.md │ │ ├── can.md │ │ ├── chimdie.md │ │ ├── codekumar.md │ │ ├── daniel.md │ │ ├── davabalan.md │ │ ├── deepak.md │ │ ├── deepak1_try2.md │ │ ├── edori.md │ │ ├── edwin.md │ │ ├── eyram.md │ │ ├── fabio.md │ │ ├── franklinulrich.md │ │ ├── fusen.md │ │ ├── habeeb.md │ │ ├── harsha.md │ │ ├── ibrahim.md │ │ ├── jahid.md │ │ ├── jaki.md │ │ ├── jesulayomi.md │ │ ├── jilva.md │ │ ├── joel_vinay_kumar.md │ │ ├── karan.md │ │ ├── karan_khosla.md │ │ ├── kenny.md │ │ ├── kingsley_victor.md │ │ ├── kiran_don.md │ │ ├── krishnadevz.md │ │ ├── krypton.md │ │ ├── lara_noomene.md │ │ ├── layomi.md │ │ ├── lilfatfrank.md │ │ ├── liviza.md │ │ ├── lorennale.md │ │ ├── lukmanokunade.md │ │ ├── luli.md │ │ ├── manohar.md │ │ ├── manuel_alejandro.md │ │ ├── marcus.md │ │ ├── maria_rivera.md │ │ ├── mbui.md │ │ ├── melissa_huerta.md │ │ ├── michael.md │ │ ├── mumbi.md │ │ ├── nahuel.md │ │ ├── nailah.md │ │ ├── naveen.md │ │ ├── neaz_mahmood.md │ │ ├── nishank.md │ │ ├── nitin_kadam.md │ │ ├── nivetha.md │ │ ├── omolo.md │ │ ├── paniagua.md │ │ ├── pavan.md │ │ ├── pr_m.md │ │ ├── prajwal.md │ │ ├── pranav.md │ │ ├── prasanna.md │ │ ├── praveen.md │ │ ├── pravin.md │ │ ├── predrag_stamenkovic.md │ │ ├── prem.md │ │ ├── proful.md │ │ ├── puru.md │ │ ├── rafael.md │ │ ├── rajesh_prajapati.md │ │ ├── rakesh.md │ │ ├── rohitsawai.md │ │ ├── sachin.md │ │ ├── samriddhi.md │ │ ├── samueladeniyi.md │ │ ├── sarvesh.md │ │ ├── sasmita.md │ │ ├── satyaki.md │ │ ├── saurabh_srivastava.md │ │ ├── scott.md │ │ ├── sheetal.md │ │ ├── shekharranjan.md │ │ ├── simrin_joshi.md │ │ ├── sippeybro.md │ │ ├── sravan.md │ │ ├── sunny.md │ │ ├── suraj.md │ │ ├── swatirao.md │ │ ├── teckiegeek.md │ │ ├── therealjimoh.md │ │ ├── titi_olopade.md │ │ ├── tolga.md │ │ ├── trombley.md │ │ ├── tushar.md │ │ ├── tusharkandpal.md │ │ ├── varad.md │ │ ├── vera_nkanmuo.md │ │ ├── vijaya.md │ │ ├── vipin.md │ │ ├── viraj_patil.md │ │ ├── wamuyuwanjohi │ │ └── yash.md │ ├── playground/ │ │ ├── cli/ │ │ │ ├── README.md │ │ │ └── spike/ │ │ │ ├── HackerNews/ │ │ │ │ ├── code.js │ │ │ │ ├── code2.js │ │ │ │ ├── mainindex.js │ │ │ │ └── renderer/ │ │ │ │ ├── index.js │ │ │ │ ├── pdf/ │ │ │ │ │ ├── createpdf.js │ │ │ │ │ └── index.js │ │ │ │ ├── render-template.js │ │ │ │ └── template/ │ │ │ │ └── template.hbs │ │ │ ├── README.md │ │ │ ├── cli-epub/ │ │ │ │ ├── .gitignore │ │ │ │ ├── epub.js │ │ │ │ ├── index.js │ │ │ │ ├── package.json │ │ │ │ └── readme.md │ │ │ ├── cli-example-esm/ │ │ │ │ ├── .gitignore │ │ │ │ ├── index.js │ │ │ │ ├── package.json │ │ │ │ └── readme.md │ │ │ ├── json-to-pdf-cli/ │ │ │ │ ├── Readme.md │ │ │ │ ├── output.css │ │ │ │ ├── output.html │ │ │ │ ├── package.json │ │ │ │ ├── script.js │ │ │ │ ├── tweet_template.mustache │ │ │ │ └── twit_thread.json │ │ │ ├── markdown/ │ │ │ │ └── index.js │ │ │ ├── pdf-from-html-cli/ │ │ │ │ ├── README.md │ │ │ │ ├── create-pdf.js │ │ │ │ ├── examples/ │ │ │ │ │ └── Twindle.html │ │ │ │ ├── index.js │ │ │ │ ├── package.json │ │ │ │ ├── render-template.js │ │ │ │ └── templates/ │ │ │ │ └── Thread.hbs │ │ │ ├── pdf-from-json/ │ │ │ │ ├── Readme.md │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ ├── phase2-server/ │ │ │ │ ├── api/ │ │ │ │ │ └── index.js │ │ │ │ ├── config/ │ │ │ │ │ └── index.js │ │ │ │ ├── environment.js │ │ │ │ ├── index.js │ │ │ │ ├── middlewares/ │ │ │ │ │ ├── index.js │ │ │ │ │ ├── request-logger.js │ │ │ │ │ └── twitter.js │ │ │ │ ├── package.json │ │ │ │ └── router/ │ │ │ │ ├── api/ │ │ │ │ │ └── index.js │ │ │ │ ├── index.js │ │ │ │ └── pages/ │ │ │ │ └── index.js │ │ │ ├── simple-pdf-to-json/ │ │ │ │ ├── README.md │ │ │ │ ├── json2pdf.html │ │ │ │ ├── json2pdf.js │ │ │ │ └── simple-pdf-to-json/ │ │ │ │ ├── newjson2pdf.css │ │ │ │ ├── newjson2pdf.html │ │ │ │ ├── newjson2pdf.js │ │ │ │ └── old codes/ │ │ │ │ ├── oldjson2pdf.html │ │ │ │ └── oldjson2pdf.js │ │ │ ├── twindle-cli-node/ │ │ │ │ ├── README.md │ │ │ │ ├── package.json │ │ │ │ └── twindle.js │ │ │ ├── twindle-hello-world-pdf/ │ │ │ │ ├── package.json │ │ │ │ └── pdf.js │ │ │ ├── twindle-thread/ │ │ │ │ ├── Readme.md │ │ │ │ ├── script.js │ │ │ │ └── twit_thread.json │ │ │ └── twitter-api/ │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── responses/ │ │ │ │ ├── response-version1-searchendpoint.json │ │ │ │ ├── response-version1-user-timeline.json │ │ │ │ ├── response-version2-conversation.json │ │ │ │ └── response-version2-tweetthread.json │ │ │ ├── script-version1-searchendpoint.js │ │ │ ├── script-version1-usertimeline.js │ │ │ └── script-version2-conversation.js │ │ ├── mock/ │ │ │ ├── README.md │ │ │ ├── twit-thread.json │ │ │ ├── twitter-recent-search-api-response.json │ │ │ └── twitter-tweet-api-response.json │ │ ├── tests/ │ │ │ ├── github/ │ │ │ │ ├── giturl.unit.test.js │ │ │ │ └── repo.unit.test.js │ │ │ └── twitter/ │ │ │ ├── api.test.js │ │ │ ├── unit/ │ │ │ │ ├── api/ │ │ │ │ │ ├── helpers/ │ │ │ │ │ │ └── fetch.unit.test.js │ │ │ │ │ └── twitter-endpoints/ │ │ │ │ │ ├── search.unit.test.js │ │ │ │ │ └── tweets.unit.test.js │ │ │ │ └── transformations/ │ │ │ │ └── helpers.unit.test.js │ │ │ └── utils.test.js │ │ └── twindleco/ │ │ ├── header/ │ │ │ ├── header1/ │ │ │ │ ├── header1.css │ │ │ │ └── header1.html │ │ │ ├── header2/ │ │ │ │ ├── header2.css │ │ │ │ └── header2.html │ │ │ ├── header3/ │ │ │ │ ├── header3.css │ │ │ │ └── header3.html │ │ │ ├── header4/ │ │ │ │ └── public/ │ │ │ │ ├── index.html │ │ │ │ └── style.css │ │ │ ├── header5/ │ │ │ │ ├── header_twindle.css │ │ │ │ └── header_twindle.html │ │ │ ├── header6/ │ │ │ │ ├── header6.css │ │ │ │ └── header6.html │ │ │ └── header7/ │ │ │ ├── header7.css │ │ │ └── header7.html │ │ ├── header8/ │ │ │ ├── header8.css │ │ │ └── header8.html │ │ ├── homepage/ │ │ │ ├── homepage1/ │ │ │ │ ├── Twindle Home Page.html │ │ │ │ └── style.css │ │ │ ├── homepage2/ │ │ │ │ ├── README.md │ │ │ │ ├── index.html │ │ │ │ ├── index.js │ │ │ │ ├── style.css │ │ │ │ └── style.scss │ │ │ ├── homepage3/ │ │ │ │ ├── index.css │ │ │ │ └── index.html │ │ │ ├── homepage4/ │ │ │ │ ├── index.html │ │ │ │ └── styles.css │ │ │ ├── homepage6/ │ │ │ │ ├── home.css │ │ │ │ └── home.html │ │ │ └── homepage7/ │ │ │ ├── index.html │ │ │ └── style.css │ │ ├── readme.md │ │ └── team/ │ │ └── team1/ │ │ ├── index.html │ │ └── style.css │ ├── twindle-thread/ │ │ ├── .gitignore │ │ ├── .prettierrc │ │ ├── LICENSE │ │ ├── README.md │ │ ├── backend/ │ │ │ ├── README.md │ │ │ ├── common.d.ts │ │ │ ├── index.js │ │ │ ├── jsconfig.json │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── add-thread.js │ │ │ ├── error/ │ │ │ │ ├── api.js │ │ │ │ ├── base.js │ │ │ │ ├── index.js │ │ │ │ └── validation.js │ │ │ ├── get-thread-data.js │ │ │ ├── get-threads-list.js │ │ │ ├── helpers/ │ │ │ │ ├── connection.js │ │ │ │ ├── error.js │ │ │ │ ├── score.js │ │ │ │ └── setup-db.sql │ │ │ └── twitter/ │ │ │ ├── constants.js │ │ │ ├── helpers/ │ │ │ │ └── fetch.js │ │ │ ├── index.js │ │ │ ├── twitter-endpoints/ │ │ │ │ └── tweets.js │ │ │ ├── types.d.ts │ │ │ └── types.js │ │ ├── jsconfig.json │ │ ├── package.json │ │ ├── public/ │ │ │ ├── css/ │ │ │ │ ├── global.css │ │ │ │ └── theme.css │ │ │ ├── index.html │ │ │ └── robots.txt │ │ ├── snowpack.config.js │ │ ├── src/ │ │ │ ├── App.svelte │ │ │ ├── components/ │ │ │ │ ├── Avatar.svelte │ │ │ │ ├── Button.svelte │ │ │ │ ├── IconButton.svelte │ │ │ │ ├── list/ │ │ │ │ │ ├── List.svelte │ │ │ │ │ ├── ListItem.svelte │ │ │ │ │ └── listElStore.js │ │ │ │ └── utils/ │ │ │ │ └── AppIcon.svelte │ │ │ ├── constants.js │ │ │ ├── helpers/ │ │ │ │ └── fetch.js │ │ │ ├── index.js │ │ │ └── pages/ │ │ │ └── Feed.svelte │ │ ├── types.d.ts │ │ ├── types.js │ │ └── workbox-config.js │ └── twindle-web/ │ ├── .prettierrc │ ├── README.md │ ├── dark-theme.css │ ├── index.html │ ├── index.js │ ├── scripts/ │ │ ├── header.js │ │ └── testimonials.js │ ├── style.css │ └── team_details/ │ ├── README.md │ ├── data.json │ ├── team_details.css │ ├── team_details.html │ └── team_details.js └── twindle-cli/ ├── .gitignore ├── .prettierrc ├── README.md ├── jsconfig.json ├── package.json └── src/ ├── cli.js ├── common.d.ts ├── env.js ├── fileOpener.js ├── github/ │ └── githubparse/ │ ├── app.js │ ├── convert.js │ └── jsonFetchData.js ├── hacker-news/ │ ├── code.js │ └── hn.test.js ├── helpers/ │ ├── error.js │ └── logger.js ├── index.js ├── readability/ │ └── index.js ├── renderer/ │ ├── epub/ │ │ ├── epub.js │ │ ├── index.js │ │ └── render-template.js │ ├── index.js │ ├── md/ │ │ ├── README.md │ │ └── index.js │ ├── mobi/ │ │ ├── README.md │ │ └── index.js │ └── pdf/ │ ├── create-pdf.js │ ├── examples/ │ │ └── Twindle.html │ ├── index.js │ └── render-template.js ├── setup/ │ └── init.js ├── spinner.js ├── twindle.js ├── twitter/ │ ├── api/ │ │ ├── constants.js │ │ ├── helpers/ │ │ │ └── fetch.js │ │ ├── index.js │ │ └── twitter-endpoints/ │ │ ├── search.js │ │ ├── tweets.js │ │ └── user_timeline.js │ ├── error/ │ │ ├── api.js │ │ ├── base.js │ │ ├── index.js │ │ └── validation.js │ ├── index.js │ ├── mock/ │ │ ├── delete-if-not-needed/ │ │ │ ├── data.js │ │ │ └── dataaa.js │ │ ├── twitter-mock-responses/ │ │ │ ├── images-text.json │ │ │ ├── mock.json │ │ │ └── only-links.json │ │ └── twitter-responses/ │ │ ├── gif-retweet.json │ │ ├── only-images.json │ │ ├── only-text.json │ │ ├── response-version2-tweetthread.json │ │ ├── squirrel-pumpkin.json │ │ └── username-hashtag.json │ ├── scraping/ │ │ └── index.js │ ├── transformations/ │ │ ├── helpers.js │ │ ├── helpers.test.js │ │ ├── rich-rendering.js │ │ ├── rich-rendering.test.js │ │ ├── search-endpoint.js │ │ ├── tweet-endpoint.js │ │ ├── tweets-array-Endpoint.test.js │ │ ├── tweets-array-endpoint.js │ │ ├── user-timeline-Endpoint.test.js │ │ └── user-timeline-endpoint.js │ ├── twitter.js │ ├── utils/ │ │ ├── date.js │ │ └── date.test.js │ └── validations/ │ └── tweet-endpoint.js ├── types/ │ └── twitter.ts ├── types.js └── utils/ ├── date.js ├── env.js ├── helpers.js ├── helpers.test.js ├── image.js ├── image.test.js ├── library.js ├── path.js ├── path.test.js ├── send-email.js └── send-to-kindle.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .all-contributorsrc ================================================ { "files": [ "README.md" ], "imageSize": 100, "commit": false, "contributors": [ { "login": "proful", "name": "Proful Sadangi", "avatar_url": "https://avatars2.githubusercontent.com/u/354596?v=4", "profile": "https://github.com/proful", "contributions": [ "code", "ideas" ] }, { "login": "tr0mbl3y", "name": "tr0mbl3y", "avatar_url": "https://avatars2.githubusercontent.com/u/72851843?v=4", "profile": "https://github.com/tr0mbl3y", "contributions": [ "code" ] }, { "login": "PuruVJ", "name": "Puru Vijay", "avatar_url": "https://avatars2.githubusercontent.com/u/47742487?v=4", "profile": "https://puruvj.dev", "contributions": [ "code" ] }, { "login": "johnjacobkenny", "name": "Kenny John Jacob", "avatar_url": "https://avatars1.githubusercontent.com/u/19240564?v=4", "profile": "https://kennyj.me/", "contributions": [ "code" ] }, { "login": "Mira-Alf", "name": "Mira-Alf", "avatar_url": "https://avatars0.githubusercontent.com/u/64691316?v=4", "profile": "https://github.com/Mira-Alf", "contributions": [ "code" ] }, { "login": "Akshay2996", "name": "Akshay Sharma", "avatar_url": "https://avatars0.githubusercontent.com/u/37118877?v=4", "profile": "https://www.developeratease.com/", "contributions": [ "code", "design" ] }, { "login": "shekhar10feb", "name": "Shekhar Ranjan", "avatar_url": "https://avatars0.githubusercontent.com/u/72906055?v=4", "profile": "https://codepen.io/shekhar4nov", "contributions": [ "code" ] }, { "login": "tolgaerdonmez", "name": "Tolga Erdönmez", "avatar_url": "https://avatars0.githubusercontent.com/u/45141388?v=4", "profile": "http://tidible.app", "contributions": [ "code" ] }, { "login": "UnevenCoder", "name": "Ameen Shafeeq", "avatar_url": "https://avatars0.githubusercontent.com/u/49345531?v=4", "profile": "https://m.youtube.com/channel/UCKmIFs7rFKdTE6t1y8bKAHQ/videos", "contributions": [ "code" ] }, { "login": "SarveshKadam", "name": "Sarvesh Kadam", "avatar_url": "https://avatars1.githubusercontent.com/u/66166738?v=4", "profile": "https://www.sarveshkadam.com/", "contributions": [ "code" ] } ], "contributorsPerLine": 7, "projectName": "twindle", "projectOwner": "twindle-co", "repoType": "github", "repoHost": "https://github.com", "skipCi": true } ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ## Description ## Attach Screenshot > Note 2 code reviewer approval needed. Approach in twitter group & discord channel. ================================================ FILE: .github/TEMP_ISSUE_TEMPLATE.md ================================================ # Temporarily disabled > Please provide us with the following information: > --------------------------------------------------------------- ### This issue is for a: (mark with an `x`) - [ ] Merge conflict solution - [ ] feature request - [ ] documentation issue or request - [ ] regression (a behavior that used to work and stopped recently) ### Minimal steps to reproduce > ### Expected/desired behavior > ### Mention any other details that might be useful > --------------------------------------------------------------- > Thanks! ================================================ FILE: .github/workflows/conflict.yml ================================================ name: Add label on merge conflict on: pull_request_target: branches: [ main ] jobs: add-label: runs-on: ubuntu-latest steps: - name: Label Conflicting Pull Requests uses: eps1lon/actions-label-merge-conflict@v2.0.0 with: dirtyLabel: "Merge Conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" commentOnDirty: "This pull request has conflicts, which you need to resolve! :partying_face: Don't need to worry at all, please follow the steps here - https://github.com/twindle-co/twindle/wiki/Resolving-merge-conflicts" commentOnClean: "Conflicts have been resolved. A maintainer will review the pull request shortly." ================================================ FILE: .github/workflows/stale.yml ================================================ name: Mark stale issues and pull requests on: schedule: - cron: "0 0 * * *" jobs: stale: runs-on: ubuntu-latest steps: - uses: actions/stale@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue is getting old :older_adult:' stale-pr-message: 'This PR is getting old :older_adult:' stale-issue-label: 'no-issue-activity' stale-pr-label: 'no-pr-activity' ================================================ FILE: .github/workflows/tests.yml ================================================ name: Node.js Tests on: push: branches: [ main ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest strategy: matrix: node-version: [10.x, 12.x, 14.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - uses: actions/cache@v2 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - name: NPM Install working-directory: ./twindle-cli run: npm install - name: Run Tests working-directory: ./twindle-cli run: npm run test ================================================ FILE: .gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* lerna-debug.log* # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json # Runtime data pids *.pid *.seed *.pid.lock yarn.lock # Confidential email config nodemailer.config.js # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage *.lcov # nyc test coverage .nyc_output # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt # Bower dependency directory (https://bower.io/) bower_components # node-waf configuration .lock-wscript # Compiled binary addons (https://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules/ jspm_packages/ # TypeScript v1 declaration files typings/ # TypeScript cache *.tsbuildinfo # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Microbundle cache .rpt2_cache/ .rts2_cache_cjs/ .rts2_cache_es/ .rts2_cache_umd/ # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity # dotenv environment variables file .env .env.test # parcel-bundler cache (https://parceljs.org/) .cache # Next.js build output .next # Nuxt.js build / generate output .nuxt dist # Gatsby files .cache/ # Comment in the public line in if your project uses Gatsby and *not* Next.js # https://nextjs.org/blog/next-9-1#public-directory-support # public # vuepress build output .vuepress/dist # Serverless directories .serverless/ # FuseBox cache .fusebox/ # DynamoDB Local files .dynamodb/ # TernJS port file .tern-port # Environment variables .env .DS_Store main twindle-web/scss/ twindle-web/style.scss twindle-web/style.css.map ================================================ FILE: CNAME ================================================ www.twindle.co ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020 twindle-co Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # [Twindle](https://twindle-co.github.io/twindle/.) 📖 [![All Contributors](https://img.shields.io/badge/all_contributors-10-orange.svg?style=flat-square)](#contributors-) > ### An open source project for beginners. > > ### Converting twitter threads to pdf, epub and mobi format to be read by Kindle. [![Open Source Love](https://firstcontributions.github.io/open-source-badges/badges/open-source-v1/open-source.svg)](https://github.com/firstcontributions/open-source-badges) [![Pull Requests Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](http://makeapullrequest.com) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ![image](https://visitor-badge.glitch.me/badge?page_id=Twindle-co.twindle) ### Hangout with Twindle developer => Discord [](https://discord.gg/jBj2zMR) ## Want to contribute on twindle cli Pre-requsites - JavaScript - Node.js (basic) Initial code goes into twindle-cli ``` cd twindle-cli npm install cp .env.example .env ``` *Note:* Create .env file under twindle-cli You need Twitter Developer API bearer token ([instructions](https://github.com/twindle-co/twindle/wiki/Applying-for-Developer-Access-from-Twitter)) # How to Run twindle? ``` node . -i 1002103360646823936 ``` ## Reading sources suppoorted ✅ Twitter Thread ✅ Hacker News Comments ✅ Github markdown pages ✅ Any articles (URL) ## Connect with us [](https://twitter.com/twindleco) [](https://www.youtube.com/channel/UCKxUmbHq5P5pd5IyUiZ8MHA) [](https://discord.gg/jBj2zMR) ## Contributors ✨ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):

Proful Sadangi

💻 🤔

tr0mbl3y

💻

Puru Vijay

💻

Kenny John Jacob

💻

Mira-Alf

💻

Akshay Sharma

💻 🎨

Shekhar Ranjan

💻

Tolga Erdönmez

💻

Ameen Shafeeq

💻

Sarvesh Kadam

💻
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! ================================================ FILE: misc/CONTRIBUTING.md ================================================ # How to contribute You can contribute by first forking the repository and then, - Creating Pull Requests - Creating Issues - Reviewing Pull Requests ## Contributing through PRs You should keep these points in mind while contributing - Any changes in the documentation are most welcome - For convenience it's recommended that you don't change more than 2 or 3 files per PR - You should respect Twindle contributors' coding style - Any other obvious rules must be followed - Pull requests of all kind are accepted. Just make sure you provide all the changes with reason in comments after opening the PR ## Contributing through Issues - Make sure that there is not similiar issue available already, if so please comment any other similiar issue there itself - No harsh language allowed. - Do not hesitate to ask questions. ## Contributing in firstpr folder - Make sure to use lowercase letters and avoid use of numbers or special characters while naming your files. ================================================ FILE: misc/docs/CHEATSHEET.md ================================================ ![Markdown cheatsheet](./images/markdown.png) ![git cheatsheet](./images/git.png) ![Terminal commands cheatsheet](./images/term.jpg) ================================================ FILE: misc/docs/CODE-REVIEW-CHECKLIST.md ================================================ # List down things to look for in a PR ### Code Review Checklist - [x] For your first PR, please use all lower case for the file name. - [x] Please use `firstname.md` as file name. Replace `firstname` with your actual first name. - [x] In case there is already a file with same name, then use `firstname_lastname.md`. - [x] Using `.md` file extension is a must. - [x] Please add some basic bio about yourself in the first PR. - [x] For the second PR, you can update the same file and add more details. - [x] Approve PR carefully as they may not show any merge conflict but still there can be some error. - [x] Check for repeated names too in `TEAM.md` as sometimes the same names are getting repeated 1-2 times. - [x] You need to create your second PR from your local machine by cloning your the forked repo and saying few things about yourself in the doc folder. - [x] Then create your PR again from your local machine this time you have update your forked repo from the main repo. - [x] After that you state your experience whether you are a beginner ,intermediate or mentor in the TEAM.md file in doc folder. - [x] if you having any difficulties in creating the second and third PR click this https://www.youtube.com/channel/UCKxUmbHq5P5pd5IyUiZ8MHA to help ================================================ FILE: misc/docs/FAQ.md ================================================ # FAQs 1. [General](#general-) 2. [Git](#Git-) 3. [Github](#github-octocat) 4. [Google Meet](#google-meet-) 5. [Logo](#logo-) ### General 👥 **What is our tech stack?** - HTML, CSS & JavaScript. - No framework. - No extra dependency. **How tasks will be distributed?** - We will came up with a process to distribute tasks. 🕑 - Basically, there will be 4 parts: A) Beginner B) Independent C) Active D) Expert - Tasks will be distributed accordingly in small groups. **When will we start working on this?** - We can start within a week because there are many beginners who would need assistance. Hang on with us :) **Is there any pre-requisite to be a part of Twindle?** - No, you can contribute to the project in these ways: Team: Helping each other, speaking up, pair programming, making and sharing videos (for this project). Github: Updating the first PR and README.md, posting questions, or discussing in the issues created. ### Git **What is git branching in git?** Git branches are alternative working directory system within git repository. In essence, they are the backbone of version control and code management feature provided by git. Here's a video explaining the git branch in short [![tutorial](https://img.youtube.com/vi/PipalhI9yWY/0.jpg)](https://youtu.be/PipalhI9yWY) ### Github :octocat: **What to do next after creating a GitHub account?** - Fork the project from this [link](https://github.com/twindle-co/twindle) - Create the first PR. **How to make a PR(Pull Request)?** - For the first 3 tasks after you joined, you can check the [ONBOARDING page](https://github.com/twindle-co/twindle/blob/main/docs/ONBOARDING.md). - For a general PR, this tutorial will walk you throught using VSCode and GUI: [![tutorial](https://img.youtube.com/vi/ZQqfZt1RIpA/0.jpg)](https://youtu.be/ZQqfZt1RIpA) - PR needs 2 code reviewer in order to be approved, if you made a PR, copy the link and share it into the Twitter group so people can assign it to themselves and approve it. - We have a Github Team for all the members and more and more contributions are welcomed. **Tips for your PR** `close, closes, closed, fix, fixes, fixed, resolve, resolves, resolved` e.g. `closes #102, closes #33, closes #14` e.g. `closes #102 #33 #14` ### Google Meet 📹 **Rules** - Mute yourself - Unmute only if you are speaking - Stay in a noise-free environment - If you are in a noisy environment don't speak **What will be the Google Meet timing?** - 5 pm IST **How to know what happened during that Google meet if I missed?** - Someone will take notes and share it with the team. - You can also watch the videos on this [list](https://youtu.be/i90UeTiEKQk) of the YT channel. ### Logo 🎨 **Where to make the logo from?** - May use free platforms like Canva, Gimp, or Inkspace - Use photoshop (if you already have the software) **How to share the logo I made?** - Comment on the issue **#4 "We need a logo"** raised by johnjacobkenny - Share in the respective twitter group you belong to. **Is it necessary to make a logo?** - No, it is just a part of the project. So, if you are not comfortable with it, its okay. ================================================ FILE: misc/docs/NAMING-CONVENTIONS.md ================================================ # File Name Conventions ## Possible characters ### Use dashes as delimiters - You should use dashes (-) as delimiters. - Periods are allowed in some cases, such as for languages and conditions. - Never use spaces or underscores. Spaces are converted to %20 in URLs or can break an URL when shared. Underscores are difficult to see when the file name is displayed as an underlined link. Although the use of underscores does not impact your ranking that much, [Google advices not to use underscores](https://www.youtube.com/watch?v=AQcSFsQyct8). **Right:** ``` file-name-with-dashes.en.min.html ``` ### Do not use special characters Avoid using non-alphanumeric characters in file names, such as: '*' ':' '\' '/' '<' '>' '|' '"' '!' '?' '[' ']' ';' '=' '+' '&' '£' '$' '€' '%' or ','. These characters can have special meaning in programming languages or can cause problems with different operating systems. ### Use lowercase, never uppercase We should always consider URLs as case-sensitive according to [W3.org](http://www.w3.org/TR/WD-html40-970708/htmlweb.html). Therefore, use lowercase to reduces errors when typing URLs. # Commit Message Naming Consist of two parts: - Subject: Short informative summary of the commit - Body: More detailed explanatory text if needed ## Subject: - Short and descriptive (max 50 chars) - Capitalized - In imperative present tense - Not end with period Example: ``` Implement access right management ``` ## Body: - Separated with a blank line from the subject - Explain what, why, etc. - Max 72 chars - Each paragraph capitalized Example: ``` Implement proper authorization for each service on development phase to validate during the API call. Access right management is used to check proper authorization to access an API by an employee or the employer. ``` # Pull Request Naming Consists of two parts: - Title: Short informative summary of the pull request - Description: More detailed explanatory text describing the PR for the reviewer ## Subject: - Short and descriptive summary - Start with corresponding ticket/story id (GitHub issue) - Should be capitalized and written in imperative present tense - Not end with period Suggested Format: *#[Ticket_ID] PR description* Example: ``` #CLS-23 Add Edit on Github button to all the pages ``` ## Description: - Separated with a blank line from the subject - Explain what, why, etc. - Max 72 chars - Each paragraph capitalized Example: ``` This pull request is part of the work to make it easier for people to contribute to naming convention guides. One of the easiest way to make small changes would be using the Edit on Github button. To achieve this, we needed to: - Find the best Gitbook plugin which can do the work - Integrate it in all the pages to redirect the user to the right page on GitHub for editing - Make it visible on the page so users can notice it easily ``` ================================================ FILE: misc/docs/ONBOARDING.md ================================================ # I joined! What to do next? Welcome to the twindle team 🥳 , this is a beginner friendly project, please follow these steps to start! ## Connect with the team 📱 Once you are part of the twindle team, please join us here to keep in touch. 1. Follow us in twitter: [](https://twitter.com/twindleco) 2. Subscribe to YT channel: [](https://www.youtube.com/channel/UCKxUmbHq5P5pd5IyUiZ8MHA) 3. Join discord [](https://discord.com/invite/jBj2zMR)
## Start working 👩🏽‍💻👨🏽‍💻 1. Fork Twindle's github [repository](https://github.com/twindle-co/twindle) 2. Do your first PR **What is the first PR about?** - Create a new file `firstname_lastname.md` inside the `firstpr` directory, commit your change and raise your first Pull Request through Github. **How to do the first PR?** - Pictures of step by step [here](https://github.com/twindle-co/twindle/issues/57) - Video of PR steps: [![tutorial](https://img.youtube.com/vi/bzaBiQQl6fU/0.jpg)](https://youtu.be/bzaBiQQl6fU). ----- 3. Do your second PR **What is the second PR about?** 2️⃣ - Make few changes in the file `firstname_lastname.md` inside the `firstpr` directory, `add`, `commit` and `push` your changes through the CLI (command line interface) and raise your second Pull Request. **How to do the second PR?** - If you use Github Desktop, check this step by step [tutorial](https://github.com/twindle-co/twindle/issues/177). - If you are using git bash/command prompt, chick this step by step [tutorial](https://github.com/twindle-co/twindle/issues/163) with screenshots or this [tutorial](https://github.com/twindle-co/twindle/issues/156) which has the commands documented. - If you are using terminal(Mac) or command prompt(windows), watch this step by step video: [![tutorial](https://img.youtube.com/vi/7I9StcZt5cI/0.jpg)](https://youtu.be/7I9StcZt5cI).
[![tutorial](https://img.youtube.com/vi/bPBTumdMhyQ/0.jpg)](https://youtu.be/bPBTumdMhyQ)
--- ----- 4. Do the third PR
**What is the third PR about?** - Make few changes in the file `TEAM.md` inside the `docs` directory, commit, through the CLI (command line interface) and raise your third Pull Request. **How to do the third PR?** - [Step by Step tutorial](https://github.com/twindle-co/twindle/issues/226) - Video of the tutorial using vsCode and GitLens: [![here](https://img.youtube.com/vi/U2bOwEY-vKo/0.jpg)](https://youtu.be/7I9StcZt5cI). --- 5. Do the fourth PR **What is the fourth PR about?** - Upload your profile image into /docs/images/team folder. - Give the name same as your first pr file name & use extension jpg, jpeg or png e.g., 'proful.png'. - Edit TEAM.md to link to your image. Someone experienced with markdown come up with an initial design (size & placement). Other follow. This will improve your knowledge of merging. **How to do the fourth PR?** - Follow the steps for third PR and add your image to the TEAM.md
--- For further questions, check the [FAQ](https://github.com/twindle-co/twindle/blob/main/docs/FAQ.md) documentation. ======= ================================================ FILE: misc/docs/README.md ================================================ # Documentation ## Table of Contents - [FAQs](/docs/FAQ.md) - [Naming Conventions](/docs/NAMING-CONVENTIONS.md) - [Resources](/docs/RESOURCES.md) - [Teams](/docs/TEAM.md) - [Why Use Twindle?](/docs/TWINDLE.md) - *Google Meet Link* - https://meet.google.com/gna-hvym-tfj **Time 5 PM IST** [Time Zone Converter](https://time.is/compare/1700_in_IST) ================================================ FILE: misc/docs/RESOURCES.md ================================================ # Resources This page contains the list of resources that can help you get started. You can also contribute by providing useful resources from **Youtube or Blogs** to help others learn & understand the basic concepts. ### Blogs - This is a simple guide about how to start with git. **Roger Dudler.** [git - the simple guide](https://rogerdudler.github.io/git-guide/index.html) - Free GitHub Learning Labs A to Z of Web Development including (Git and Github)🐱‍🏍 👉[Article Link🌊](https://dev.to/krishnakakade/free-github-learning-labs-a-to-z-of-web-development-3501) by **krishnadevz** - Sync a GitHub Repo: How To Ensure Your GitHub Fork Is Up To Date. **Earthdatascience.org - by Leah Wasser, Jenny Palomino, Max Joseph** [Article Link](https://www.earthdatascience.org/courses/intro-to-earth-data-science/git-github/github-collaboration/update-github-repositories-with-changes-by-others/#:~:text=You%20can%20update%20your%20fork,be%20updated%20in%20your%20fork) - [How to publish packages to npm (the way the industry does things)](https://zellwk.com/blog/publish-to-npm/) ### Youtube Links - Get started with the most popular Code Editor [VsCode](https://www.youtube.com/watch?v=WPqXP_kLzpo&t=382s) - Learn the fundamentals of [JavaScript](https://www.youtube.com/watch?v=W6NZfCO5SIk&t=1s) - Get started with the new features of [JavaScript](https://www.youtube.com/watch?v=hdI2bqOjy3c) like ES5, ES6 features & more. - Learn about [Asynchronous JavaScript](https://www.youtube.com/playlist?list=PL4cUxeGkcC9jx2TTZk3IGWKSbtugYdrlu) and its advance features. - Get yourself started with [Node.js](https://www.youtube.com/watch?v=fBNz5xF-Kx4) - Learn [Git & Github](https://www.youtube.com/watch?v=RGOj5yH7evk&t=339s) - How to create PDFs using Puppeteer & Handlebars with HTML, watch this [video](https://youtu.be/llkkwRABN-s) - Configure git bash and complete your second pull request. [Video](https://www.youtube.com/watch?v=cBigFcoAXZg) - Software Engineering is Overwhelming [Video](https://www.youtube.com/watch?v=MbDjrztWtX4) - GitHub Actions Tutorial - Basic Concepts and CI/CD Pipeline with Docker [Video](https://www.youtube.com/watch?v=R8_veQiYBjI) ### Github Repositories for learning - [Best practices for Nodejs](https://github.com/goldbergyoni/nodebestpractices) - [You don't know JavaScript book for have strong fundamentals](https://github.com/getify/You-Dont-Know-JS) - [Best Practices for Clean Code in JavaScript](https://github.com/ryanmcdermott/clean-code-javascript) ================================================ FILE: misc/docs/TEAM.md ================================================ ## Beginner | Image | Name | Description | | -------------------------------------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | | [Pranav Goel](https://github.com/pranavgoel29) | I'm from India, Have basic knowledge of HTML, CSS, C++ and C, I'm currently learning Javascript. | | | [Adewale Abiola](https://github.com/princehaybee) | I am a Nigerian. I have basic knowledge of HTML,CSS and Javascript. | | | [Micheal Aderinto](https://github.com/ad3rinto) | Manchester UK, Hoping this will be my first step in the world of solving world problems with code. | | | Usha Kiran ([K!r@nD0n](https://twitter.com/ushakiran_m)) | I am a student from India. I just started my OpenSource journey with TWINDLE. I am currently learning #JavaScript. | | | [Eyram ](https://twitter.com/Ey_kwasi) | I am from Ghana and I have no experience, started learning web development some months ago. I am participating to learn and also make twindle a success. | | | [Michael Osajeh](https://github.com/michaelcosj) | I am from Lagos, Nigeria, second year Computer Science Undergraduate, started learning web and mobile development this year. I have basic knowledge of javascript, python, c++, dart and golang. | | | [Tushar Kandpal](https://github.com/tusharkandpal) | From India, Contributing in making **twindle** a succees, Always a Learner :v: | | ![avatar](https://github.com/RafaelBatman55.png?size=80) | [Rafael Rodrigues](https://github.com/RafaelBatman55) | Less than 1 yr of experience From small city in Rio de Janeiro State - Braz.I'm very excited to learn and helf in this project! | | | [Yaksh Bariya](https://www.github.com/thunder-coding) | I am from India. A 14 year old technology lover. I create amazing things using the knowledge I have gained so far. Currently, I want to explore more of JavaScript/TypeScript. | | | [Nishank Navelkar](https://www.github.com/nishanknavelkar) | Im from India, Basic knoweledge of Python, C, C++, HTML, CSS, Electrical engineer, Here to learn and Contribute. | | | [Manohar Rajaram](https://github.com/manohar52) | I am from India but currently pursuing my Masters in computer science in US. I am quite new to Javascript. I have some experience in HTML, CSS and PHP. | | | [Naveen Kala](https://github.com/naveenkala) | I'm an engineering student from India. Having basic knowledge of HTML, CSS and JavaScript. Currently I am learning Reactjs. | | | [Alasi Habeeb](https://github.com/Holaryeankar007) | I'm from Nigeria, I have experience in HTML and CSS but i'm currently learning Javascript. | | ![avatar](https://github.com/Sheetal777.png?size=80) | [Sheetal Pandey](https://github.com/Sheetal777) | A keen learner from India pursuing engineering. Good with Python and new to Web Developement. | | | [Regina Gachomba](https://github.com/MumbiGachomba04) | I am a Kenyan undergraduate student currently based in Ankara, Turkey. During my first year in college I learnt C,C++ and python. I am currently learning Java OOP for my coursework and teaching myself HTML,CSS and Javascript. Looking forward to master front-end development at the moment, then hopefully I can begin learning back-end. | | | [Swati Rao](https://github.com/SwatiRaoDataEnthusiast) | I am from India,I am familiar with HTML,CSS and can learn Node.JS, javascript etc. This is the my first open source project TWINDLE. Really excited!! | | | [Prathap](https://github.com/codeprm) | From India. Newbie to UI tech. CS Student, 4+ exp. | | ![avatar](https://github.com/lh536.png?size=80) | [Fabio Duarte](https://github.com/lh536) | I am from Colombia. I have some experience with HTML, CSS and JavaScript. Lately I've been learning Tailwindcss, ParcelJS, NodeJS and a first lesson of VueJS. I like listen to music (play guitar and drums), airplanes, cooking, video/photography and science; actually I'm biologist, but I love coding since I was in the school. I hope I can contribute to twindle. I'm always learning. | | | [Nahuel Alfano](https://github.com/NahuelAlfano) | I am from Argentina, beginner at github and open source projects. I have basic knowledge of HTML, CSS, Javascript, C#, C++, currently learning Python. | | | [Tr0mbley](https://github.com/tr0mbl3y) | learning how things works! nothing to share much | | | [Sippeybro](https://github.com/sippeybro) | I'm from Maldives, Have basic knowledge of HTML, CSS, php and I'm currently learning Javascript. | | | [Titi Olopade](https://github.com/teckiegeek) | I am from the United Kingdom. My background is Computing and Statistics with a MSc. in Agile Project Management and PRINCE2 certified,i SCRUM Master Certified. I have several years professional experience with few years career break. I started learning HTML and CSS coding 6months ago. I plan a change in career to be a Front-end developer. Here to learn and contribute to success of "twindle". | | | [luli](https://github.com/ululi) | I'm from zambia,have some basic knowledge of html, css and js, am here to learn more about web development. | | | [Ashish](https://github.com/kambleaa007) | 3+ yr of experience in .Net Java JavaScript Testing, Pune, India SoReady2Help :partying_face: | | | [Nneyen ](https://github.com/Na-ilah) | I am from Nigeria. I am beginner at github and open source projects. I have basic knowlege of Python, HTML and CSS. I don't remember much about programming even if I have a degree in computing. I would like to be able to contribute to the open source community and build educational solutions. | | | [Harsha Vardhan](https://github.com/Harsha-Ambati) | I am a student from India, recently came into this web development field, had basic knowledge in HTML, CSS, JavaScript. | | | [Maria Rivera](https://github.com/GorettiRivera) | I have basic knowledge of Javascript, HTML and CSS. Currently working in different open source projects | | | [Neaz Mahmood](https://github.com/Neaz-Mahmood) | I am from Dhaka, Bangladesh. I am a second year Computer Science undergraduate. I know basic html, css, javascript. I am here to learn & contribute to 'twindle'. This is my first open source project. | | | [Predrag](https://github.com/stamenkovic-dev) | I'm from Serbia, and I have only basic knowledge of HTML and CSS, but I'm here to learn more about web development and team play at coding. | | | [Franklin U.O. Ohaegbulam](https://github.com/frankiefab100) | I'm comfortable working with HTML and CSS, with basic knowledge of JavaScript. I'm from Nigeria and love talking about accessibility, inclusive design and web animation. | | | [Aravind Sivasailam](https://github.com/aravindsivasailam) | I'm a product engineer living in US with 2 years of experience in software testing and project management. New to software development and wish to improve in HTML, CSS and JS. | | | [Edwin Mancipe](https://github.com/efmg0325) | I am from Colombia. I have a bit of knowledge about HTML, CSS, Javascript, Python and SQL. I love to listeninng to Heavy Metal music. I like second life web browser games. | | | [Edori Atiri](https://github.com/EdoriAtiri) | From Nigeria. Began to learn Web Development this year. I hope to learn and contribute while I'm here. | | | [Lorenna Leon](https://github.com/lorennaleon) | I am Peruvian, I have knowledge in html, css and javascripts I hope to learn a lot from you | | | [Fusen Ye](https://github.com/Yexiansen66) | I'm a beginner from China. I know HTML,CSS and JavaScript.I want to learn more advanced knowledge and contribute to twindle. | | | [OmoloG](https://github.com/geowen74) | From Nairobi, Kenya. Have Knowledge on HTML, CSS and some basic on javascript and Mysql. Aspiring to be a full-stack developer. Currently learning javascript. | | | [Shekhar Ranjan](https://github.com/shekhar10feb) | I'm from India, have basic knowledge of Java, SQL, HTML, CSS and still learning JavaScript, want to learn more and explore advance stuffs. | | | [Chioma Vera Nkanmuo](https://github.com/chiomavera) | Hi,I'm Chioma Vera Nkanmuo, Beginner Web developer from Nigeria with basic knowledge of HTML and CSS. I am currently in my penultimate level in university. Learning while contributing in making twindle a success. | ---
## Intermediate | Image | Name | Description | | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | | [Tolga Erdönmez](https://github.com/tolgaerdonmez) | I'm from Turkey. I'm a student. I've been programming for 4 years but no proffessional experience. | | | [Ameen](https://github.com/UnevenCoder) | 3+ yrs of experience ,From India , born & brought up in Jeddah [ I am 15 yrs old :)], An Extrovert & A Feeler :) | | | [Krypton](https://github.com/madhusudanbabar) | I'm an engineering student from India, passionate for web technologies, especially nuxtJS. I love blogging (technical articles & CTF walkthroughs mostly as I'm also interested in cyber security). | | | [Rakesh](https://github.com/Rakesh-4) | Software Developer have 3+ years of experience in C#, JavaScript and Angular Framework | | | [Samriddhi](https://github.com/sammjainn) | I'm a student from India. Here to learn and work together! | | | [PraveenKumar](https://github.com/praveen2896) | I'm from India, having 3 years of professional experience in Backend, new to JS,HTML,CSS ,Planning to learn React in future with the help of #twindle. | | | [Vipin Rawat](https://github.com/aesthytik) | I'm a frontend Engineer from Punjab,India. 2+ years experience in React Native and React js. I create Logos and graphics for fun.Happy to help :) | | | [Satyaki Bose](https://github.com/satyaki07) | I'm a newbie in MERN stack from Kolkata, India with 1+ years of experience. :) | | ![avatar](https://github.com/Mira-Alf.png?size=80) | [Aparna Sivasailam](https://github.com/Mira-Alf) | I'm from Bengaluru, India. Tech woman on a career break with 6 years of Java Experience. Trying to upskill myself with Javascript and UI/UX design | | | [Rajesh](https://github.com/rkumar1904) | I'm a Lead frontend developer from Mumbai, India. Total 9+ years experience in front end technology. Currently working on ReactJS & Flutter. Initially, I started my career as a Programming Faculty. | | | [Sunny](https://github.com/SunnyDev7) | I am Sunny from India and a engineering student. And i am working on MERN stack and also comfortable with html, css and vanilla js and am Here to learn, collaborate and help. | | | [Akshay Sharma](https://github.com/Akshay2996) | I'm a Frontend Developer from Bangalore, India. Total 1+ years of experience in the industry. Contributing to Twindle to make it successful. | | | [Karan Parsnani](https://github.com/LilFatFrank) | From Mumbai, India. Here to learn and contribute. | | | [Lukman Okunade](https://github.com/lokunade) | From Lagos, Nigeria. I am joining the twindle open source to learn and contribute. | | | [krishnadevz](https://github.com/lokunade) | I am krishna 4 years of experience in web-development Current skills(HTML/CSS/JS/REACTJS/C/bootstrap4) from india currrently i am final year CS gradd student and Learning MERN✡ Stack Developer SelfTaught-Dev/Opensourcer🛠 #100DaysOfCode(R2) FOSS❤ I like to build things & Write things related to Web🌐⚙ #webdev 🐱‍💻 | | | [Melissa Huerta](https://github.com/piratelicorne) | Hi! I'm Systems Engineer from Perú, 3+ yrs of experience in IT Infrastructure, I have knowledge in C and Javascript. I recently started in Development as Flutter Developer, currently working on side projects 👩🏽‍💻 and blogging for #WomenWhoCodeSV | | | [Abdou Masoudi](https://github.com/uplancer) | a selft-taught Web Developer. | | | [Viraj](https://github.com/viraj-patil) | I'm a full stack developer from Pune, India. Total 9+ years of experience in software industry as a developer. | | | [Joel Vinay Kumar](https://github.com/JoelVinayKumar) | I'm a FullStack Developer from Hyderabad, India. Worked on building microservices, web apps and mobile apps. I learned UI design out of passion. I'm proud of any small contribution to Twindle | | | [Saurabh Srivastava](https://github.com/vasudeveloper001) | From India, 18 months Software Development Experience mainly in backend PHP development. Know about JavaScript, HTML, CSS, Nodejs, Python basics as well. Learning JAVA currently and starting a YouTube Channel on coding. | | | [Nitin Kadam](https://github.com/ni3-kdm) | Full stack developer from Pune, India. 5+ years of experience in the web development 👩🏽‍💻. | | | [Marcus](https://github.com/mar-code) | I'm a self taught frontend developer from Lagos, Nigeria with experience in HTML/CSS, Javascript, React, Redux, bootstrap and d3 data presentation. i am currently learning NodeJs. | | | [Samuel Adeniyi](https://github.com/samueladeniyi) | I am proficient in HTML, CSS and Javascript. I am comfortable with react. I intend to become a fullstack developer with the MERN stack. I am from Nigeria. | | | [Aditya Satpute](https://github.com/Foxtrot-1418) | I'm a Full Stack Web Developer From Nashik, Maharashtra, India. I've experience in HTML, CSS, JS, Jquery, Bootstrap, PHP and currently working fo r Multinational Company as AWS Developer. | | [Samuel Adeniyi](https://github.com/samueladeniyi) | I am proficient in HTML, CSS and Javascript. I am comfortable with react. I intend to become a fullstack developer with the MERN stack. I am from Nigeria. ---
## Mentor | Image | Name | Description | | -------------------------------------------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------- | | | [Proful](https://github.com/proful) | 15 yr of experience From India, Living in Sydney Actively participating to make twindle a success. | | ![avatar](https://github.com/johnjacobkenny.png?size=80) | Kenny John Jacob | 4+ yrs of experience. From Kerala, India. Here to help :partying_face: | | | Kingsley | 3+ yrs of experience. Based in Nigeria and here to help :man_technologist: | | | [Pratham](https://github.com/prasoonpratham) | 2+ experience in JavaScript, always open to help :smile: | | | [Sarath](http://http://www.sarathnagaraj.ca/) | 6+ experience in JavaScript, Currently working on a side project using ReactJS :man_technologist: | |![Puru's profile pic](https://github.com/puruvj.png?size=80) | [Puru Vijay](https://github.com/puruvj) | 5+ experience in HTML, CSS, JS, Angular, React, Svelte, NodeJS, Python, StencilJS, Firebase, feel free to ping me for help 😁 | ================================================ FILE: misc/docs/TWINDLE.md ================================================ # Why should twitter users consider Twindle to read through Twitter thread? Before we dive into what Twindle aims to solve and why to consider Twindle as the first set of choices to read through informative threads on Twitter, let's take a look at the existing problem in reading through or following a long thread on Twitter. ### The Problem Twitter threads are a common way, nowadays, to share informative content about diverse subjects quickly instead of writing up a blog post on Medium or a personal website. On every clock tick, the twitter feed volume grows exponentially; thus, keeping tracking of the threads that users find useful has become a painstaking process; ### Existing Solutions Widely used approaches are to track is to retweet, like the tweet revisit later by scrolling through your likes feed. Alternatively, a Twitter bot named threadreaderapp was introduced to address the pain point by allowing users to retweet on the original post and get a link that combines all the information related to the thread in one place through a URL. Non-twitter users can also access the URL. ### Limitations of threadreaderapp Although the threadreaderapp alleviates the pain point, there are some limitations in using the threadreaderapp bot as follows. - If the thread owner blocks the threadreaderapp bot, it will not access the thread content. - If the thread owner is a private user, the bot will not access the thread content. - The threadreaderapp bot can only access up to 3000 tweets per user - Threads get deleted from the app when they are deleted by the author or Twitter because the app site is in sync with Twitter. The only way to avoid this is a premium membership which allows threads to be saved as PDF files. - Finally, the reader must connect to the internet to access the URL ### Twindle: Access thread content offline as well In walks Twindle, a web application allows users to convert threads on Twitter to pdf or ePub format. - The users can store the pdf/ePub on a digital device - The users can store the pdf/ePub on cloud services i.e, Dropbox, Google Drive and access offline, - Otherwise, print a hard copy and read like a good-old-traditional-reader. ================================================ FILE: misc/docs/TWITTER.md ================================================ # 18 OCT 2029 How to make a PR directly from vscode @Pranavgoel_29 #twindle https://www.youtube.com/watch?v=ZQqfZt1RIpA ================================================ FILE: misc/docs/articles/Process-for-new-contributors.md ================================================ Hi everyone :wave:, usually when people get connected to an open-source project(which is yes, pretty much exciting :open_mouth: ), they are mostly unware about the project. Sure, they have some knowledge about the project but not enough to contribute to it. So, they must have enough knowledge about the project and the process, like to do what or where should they first start, etc. That's where this article comes in handy :metal: , as suggested by @Proful to write. So, let's go and try to know every process step by step. ### Step 1 From the [twindle-co](https://github.com/twindle-co/twindle) to get a copy of that github account in your account. ### Step 2 Download [Git](https://git-scm.com/) and [connect the github account to it](https://linuxize.com/post/how-to-configure-git-username-and-email/). ### Step 3 Fork Twindle repository by clicking on the `Fork` button on top right corner. This will make your own copy of Twindle's code, and it will be synced up to the upstream(i.e, `twindle-co/twindle` in this case). ### Step 4 Clone the git repository from your github account into your local machine using git `bash`/ terminal (Most likely, it's git bash for windows users).There are different ways to clone a repository into your local machine, like you can use HTTPS, SSH or GitHub CLI, but this below will do it for everyone. ```bash git clone https://github.com/[YOUR_USERNAME]/twindle.git ``` Replace `[YOUR_USERNAME]` with your git username. The whole repository will be copied in that folder. > :mushroom: Tip: Always remember to work or make changes in a new branch, for this, you have to create a new branch and then, work in it like make changes or add something. What is Pull Request and why should we raise one? :confused: Pull Request(PR) is just you requesting from the authority, the original upstream branch, whose application you have forked, and in that forked application, you have done some changes or added some codes. To incorporate those changes in the main file, you have to raise a pull request(pr) to the authority. So, just making some meaningful changes and save it in your account won't be beneficial until those changes are added in to the main file. That's where pull request(pr) comes into the picture. ### Step 5 Make a new branch in your fork. > :mushroom: Tip: Before raising a pr from the main branch in order to merge your changes into the main file, always update your repository by pulling latest code from upstream branch by running this 👇 ```bash git pull upstream main ``` And you can update your github account with the parent repository by following this amazing article written by @SarveshKadam [Sync to main repo using pull request](https://github.com/twindle-co/twindle/blob/main/docs/articles/sync-to-main-repo-using-pull-request.md). ### Step 6 Now, we are ready to raise our first PR in upstream. So, we need to do this by using our github account by following the steps given below: - Switch to our new branch - Go to firstpr - Click on the add file button(on upper right hand side) - Click Create new file - Give a name of your file like yourName.md, where .md is the name of the markdown extension - Now, write about yourself in the space given below. Here, you have to use markdown language. > :mushroom: Tip: Markdown Language is a simple markup language, one can use to format any doucment. If you want to learn basic syntax, you can go here :point_right: [Markdown Language](https://www.markdownguide.org/basic-syntax/). ### Step 7 Now, we are going for the 2nd pr but this time, we are raising a pr through our local machine. For this, again update your repo first in your both local as well as remote account and you should follow this, `twindle/docs/Team.md` in your local branch. This is about the team members, where one has to write his/her name with github account link and some description about himself/herself using markdown language. For pushing the changes from your local machine to your github account, you need to execute this command, ```bash git push origin [new-branch] ``` where, `origin` is the remote name. Please go here, if you want to know more [Gt Commands](https://github.com/twindle-co/twindle/blob/main/docs/articles/git%20-github-related.md). > :mushroom: Tip: If you are facing pr commit issue then, please go through this very nice article written by @PuruVJ [PR Clean Commits](https://github.com/twindle-co/twindle/blob/main/docs/articles/pr-clean-commits.md). ### Step 8 :sound: So, you are about to raise your 3rd pr. In the 3rd pr, you will add your photo in the `Team.md`. First, you need to upload your photo here, `twindle/docs/images/team` through new branch by raising pr. After merging the changes, update your repo(it's compulsory) and then, go to `twindle/docs/TEAM.md` in your new branch and edit the page, put this code `` in the image section in front of your name, according to the markdown syntax. > :mushroom: Tip: In between doing these things, you can write article also, where you can share simple approach of doing the steps, where you feel difficulties. This wiil surely give you confidence to express yourself and makes it easier for people to learn new things :relaxed: . ### Step 9 Now, you can select any of the section like either you can go to twindle-cli, twindl-web or twindle-thread according to your choice. Suggestions are welcome !! :blush: ================================================ FILE: misc/docs/articles/README.md ================================================ # Articles Create an article here and add it as a link on the main project readme file. This will show up on the website as links. ================================================ FILE: misc/docs/articles/creating-first-pull-request.md ================================================ I hope the following screenshots will help with your first pull request. Firstly create your account on github and goto twindle repository page [here](https://github.com/twindle-co/twindle) Now you can follow the following steps. Step 1 ![1](https://user-images.githubusercontent.com/5336488/96012183-7b689480-0e61-11eb-94b9-289c30811210.png) Step 2 ![2](https://user-images.githubusercontent.com/5336488/96012298-9a672680-0e61-11eb-8aa5-2c35611d6a77.png) Step 3 ![3](https://user-images.githubusercontent.com/5336488/96012404-b10d7d80-0e61-11eb-82d0-8a1fa147f7cd.png) Step 4 ![4](https://user-images.githubusercontent.com/5336488/96012445-bc60a900-0e61-11eb-8305-08d03a22fc85.png) Step 5 ![5](https://user-images.githubusercontent.com/5336488/96012476-c4b8e400-0e61-11eb-818d-705dafbe5cc1.png) Step 6 ![6](https://user-images.githubusercontent.com/5336488/96012512-ce424c00-0e61-11eb-8a03-a4d9d9e12d57.png) Step 7 ![7](https://user-images.githubusercontent.com/5336488/96012535-d4382d00-0e61-11eb-9b2c-319407fa7758.png) Step 8 ![8](https://user-images.githubusercontent.com/5336488/96012559-da2e0e00-0e61-11eb-8b1d-c7cfd39bccee.png) Step 9 ![9](https://user-images.githubusercontent.com/5336488/96012586-e0bc8580-0e61-11eb-906f-5577f5c2b075.png) Step10 ![10](https://user-images.githubusercontent.com/5336488/96012608-e619d000-0e61-11eb-9869-84e739b4b808.png) ================================================ FILE: misc/docs/articles/design-guide-for-good-logo.md ================================================ There are some teams and logos you see, no matter where you are in the world, and you know exactly who they are and what they mean. ## Hi everyone, this is Vipin, a frontend dev from Punjab, India with good knowledge of design and UI/UX. Twindle has got a lot of overwhelming response from the dev community and and begginers have also flooded their ideas for branding and logos. As we are designing a logo, some things should be taken in my mind (of course there is no hard and fast rule 😅) # 1. LOGO DESIGN MUST REFLECT YOUR BUSINESS Your logo needs to help your business stand out in a crowd, but in a way where the person looking at it can easily identify that it is your unique company. If you can incorporate into the logo key elements that your business represents, you have a better chance of people remembering it. # 2. KEEP IT SIMPLE Stop with all that clutter. Trying to squeeze too much into a logo can have a negative impact. # 3. MAKE A STATEMENT IN BLACK & WHITE AND COLOUR Make certain that your logo works well - both in colour and in black and white. If the logo loses impact in black and white, it is going to be a problem when you have to print in newspapers or utilise services that only use black ink. Ensure that a colourful logo design translates well visually into black & white. # 4. A SCALABLE SOLUTION our logo has to be scalable to be effective. Your logo might look great on your letterhead, but what happens when you have to reduce the size for a business card or online forum? The rule of thumb when it comes to scalable logos, is that your logo should look good - whether on a business card or a billboard. If you can accomplish that, you have a great logo design. # 5. KEEP IT BALANCED Your logo should be designed to stand the test of time too. Ensure that your design does not make overt use of fashion trends - or you may find your logo is quickly dated. Once you have decided what logo is perfect for your business, be sure to have it converted in JPG, GIF, and EPS format. This way you can easily use the logo for your printed materials and website. Once you have all these key elements in place, we come to the most important part of a successful logo design and brand statement. Now that you have your logo, and it has been broadcast to the world, it is vital you always use your logo in a consistent manner. Don't alter your logo for certain flyers or brochures. Not only will this confuse your audience, it risks looking less than professional. You can reduce and enlarge the logo for different formats, but never change the essence of the design. ================================================ FILE: misc/docs/articles/git -github-related.md ================================================ Hello friends :wave: :smiley: , when we talk about **git** and **github** then, there are lot of confusion :confused: exist in our mind. Especially, when we talk about their commands. I also encountered with the same issue and mentors helped me and motivate me to face this and gave me some suggestions in order to overcome this. And thanks to the mentors, who suggested me to write an article about it. So, here I am writing about some concepts, which are related to **github** and **git** and some commands(which you can use it in _git bash_, _cmd_ or _vscode terminal_) too, which, I hope, would be very helpful for everyone. So, here we are discussing about following terms, which might be very important: - Fork - Branches - Push commit to a remote repository ### Fork When we **fork** a repository, in our case we **fork** the **Twindle** repository then, we get a personal copy of the repository in our **github** account, where we are free to make changes without affecting the main project. When we do some changes in our own repository and want to implement these changes in the main project then, we raise pull request(PR). The authority of the main project review the changes and if they think it is good to include this change in the main project then, they add it( you everytime want this to happen ) otherwise, reject it( sorry, but it happens too ). ### Branches **Branches** are almost like a new copy of our code at the current state( it means you forked a repository, which becomes "master" version in your repository and then, you make a copy of your "master" version ), which can then be used to develop new code.For example, whenever we need to create a new feature, or rewrite any of our code, it's a good thing to create a new branch so that none of our changes affect the "master" version of the code. This is important since it can be very difficult to revert code changes from memory, especially in complex systems. And also there are many changes happen in the "master" version of the main repository like in **Twindle**, people work on the code and raise PR requests. If we try to raise PR request from our "master" version then, the PR requests raised by the people will also get added in our raised PR and this creates mess. So, to avoid these problems, we need to create a branch, raise PR request from that branch, this will avoid others' PR requests and _when the PR request is approved then, that branch must be deleted._ First of all, when we are creating a branch using _git bash_ then, we must assure that we are in the main branch as shown below: ![git9](https://user-images.githubusercontent.com/72906055/99707614-b5f9c880-2ac2-11eb-8fdd-5a6b3bbd2175.JPG) Here, in the above photo, "(main)" shows that we are in the main branch. Now, there are certain commands we should know and these are as follows: - To initialize a repository for a new or existing project, git init - To create a branch from the current branch git branch this makes a copy of main branch, ![git10](https://user-images.githubusercontent.com/72906055/99710208-4685d800-2ac6-11eb-9b6b-1f7604abc9e4.JPG) - To see how many branches in the git or local, git branch ![git11](https://user-images.githubusercontent.com/72906055/99710273-5bfb0200-2ac6-11eb-9946-dc823f3811a2.JPG) By seeing the photo, we also conclude that we are in the main branch because of the * . - To see all the branches (local as well as remote), git branch -a ![git12](https://user-images.githubusercontent.com/72906055/99759139-79f15280-2b18-11eb-87d1-8a63767bc8d9.JPG) From the above picture, we can see the local as well as remote branches(in red color). - To switch from current branch to another branch, git checkout ![git13](https://user-images.githubusercontent.com/72906055/99766351-ea9f6b80-2b26-11eb-8534-63440b2c6ff0.JPG) Here, first we in main branch, see all branches in the local and then, we switch to another branch. - To delete the branch but first, you need to go into the master or main branch then, git branch -d ![git14](https://user-images.githubusercontent.com/72906055/99766796-d5770c80-2b27-11eb-8bb6-cdd08c268e5f.JPG) And again check how many branches are in your local. Note: if it shows error: The branch is not fully merged then, please use, git branch -D - To add one or more files to staging(index) area, git add - To list the files you have changed and those still need to add or commit, git status - To remove files from staging area(unstage), git rm --cached - To commit changes to head(here, head means where you are), git commit -m "commit message" - To see the total commits you have done, git log ### Push commit to a remote repository Commit means to save your changes in our local repository. When we do commit in the local repository then, we need to push this commit in remote repository or our github account. We use `git push` to push commits to do this. The `git push` command takes two arguments: - A remote name, for example, `origin` - A branch name, for example, `branch1` `git push origin branch1` then, go to the github account where, we can see a branch of same name is created with the changes we did in the local. From that same branch that is, branch1, raise pull request. _This PR would be clean and without any mess. After approval or rejection, please remove that branch from remote and local._ I urge everyone to please come forward and add more commands, if possible try to add it with suitable examples so that, it gives the better idea about it. Suggestions are welcome :blush: !! ================================================ FILE: misc/docs/articles/handlebar-explained.md ================================================ ### **Why do we need Handlebars?** For converting twitter threads to PDFs, we initially need to compose HTML comprising of that twitter thread with some styling and then we can consequently convert it to PDF. > Twitter thread --> HTML --> PDF To compose that HTML from twitter thread we cannot directly give tweet text to PDF because it would just look like a pile of text. So we will be using a template in which we can input this twitter thread content. For creating that HTML from a template and we will be using Handlebars ### **What is Handlebars?** Handlebars is a simple templating language. It generates HTML from a template which contains placeholders containing Handlebars expressions. Lets see in detail. For example, below is a template that has two two Handlebars expressions ```

{{firstname}} {{lastname}}

``` If applied to the input object ``` { firstname: "Vijaya", lastname: "Bhaskar", } ``` the expressions will be replaced by the corresponding properties. The result is then ```

Vijaya Bhaskar

``` ( React JS people can already feel familiar with this by props-components thing 😃 ) ### **How to utilize Handlebars in Twindle project?** Already @tolgaerdonmez has implemented Handlebars to create a HTML from a template. Lets decode his code 😄 Following is the code from the template [Thread.hbs](https://github.com/twindle-co/twindle/blob/main/playground/cli/pdf-from-html-cli/templates/Thread.hbs) ```

Twindle Thread

    {{!-- uses the twit mock object from mock API --}} {{#each thread}}
  • {{twitterHandle}}

    {{name}} - @{{twitterHandle}}

    {{createdAt}}

    {{tweet}}

  • {{/each}}
``` In the above code we can see expressions like {{image}} {{twiiterHandle}} {{tweet}} where we input content using a JSON here. This template when given the JSON input of twitter thread data generates HTML. Now, lets see how the template rendering is done. Following is the code from [render-template.js](https://github.com/twindle-co/twindle/blob/main/playground/cli/pdf-from-html-cli/render-template.js) ``` const hbs = require("handlebars"); const fs = require("fs"); const path = require("path"); // renders the html template with the given data and returns the html string function renderTemplate(data, templateName) { const html = fs.readFileSync(path.join(__dirname, `templates/${templateName}.hbs`), { encoding: "utf-8", }); // creates the Handlebars template object const template = hbs.compile(html); // renders the html template with the given data const rendered = template(data); return rendered; } module.exports = renderTemplate; ``` In the above code there are three main blocks, lets see one by one.
Block 1: We are primarily are reading the file contents of the template here by giving the template name. ``` const html = fs.readFileSync(path.join(__dirname, `templates/${templateName}.hbs`), { encoding: "utf-8", }); ```
Block 2: Compiling the template so it can be executed immediately. ``` const template = hbs.compile(html); ```
Block 3: When given input data it would generate the HTML using the template. ``` const rendered = template(data); return rendered; ```
And finally in [index.js](https://github.com/twindle-co/twindle/blob/main/playground/cli/pdf-from-html-cli/index.js), we are inputting "../mock/twit-thread.json" data to "Thread.hbs" Handlebars template to generate required html. ``` const htmlContent = renderTemplate({ thread: mockData }, "Thread"); ```
Thanks to @tolgaerdonmez for the amazing code.
Hope you understood Handlebars and how to render HTML using a template.
Let me know :thumbsup: or :thumbsdown: ================================================ FILE: misc/docs/articles/javascript-code.md ================================================ Hello everyone :wave: here, I am writing some questions and try to give the answer( if you think you have better answer then, you are welcome!! ) regarding **JavaScript** codes (thanks to **Kenny** :grinning:, who encouraged me to do this), which beginners(like me) mostly face problems to understand and will add new questions/answers in future and I highly suggest everyone to come forward and add your questions/answers :love_you_gesture:. --- ## Problem no. 1 We are here to understand how the code in the last lines are working, which is in the link [here](https://github.com/twindle-co/twindle/blob/7315f9fa05ef55a2278ee73c1634392653fea635/twindle-web/team_details/team_details.js) , as shown below: async function pushToDom() { let fetchData = await fetch('https://raw.githubusercontent.com/twindle-co/twindle/main/twindle-web/team_details/data.json'); let data = await fetchData.json(); let users = data.users; let html = ''; users.forEach(info => html += generateCard(info) ) cards.innerHTML = html; } pushToDom(); I asked about this code to **@UnevenCoder**. He hepled me in understanding the code by writing this code again with *comments* to understand in a better way. Thank you **Ameen** :grinning:. Firstly, we need to understand about **async** and **await** as both are used for **promise**: - Async makes code to execute in a unserialized manner. - Javascript runs moves the next line without ending the firsts , so to stop it at a line we use awaits , we use it in an async function. --- And now we are ready to understand the code: async function pushToDom() { Makes the function asynchronous let fdata = await fetch('https://raw.githubusercontent.com/UnevenCoder/twindle/main/twindle-web/team_details/data.json'); This is the raw data that the api sends , like it will be in all quotations let data = await fdata.json(); Now converting raw data in json , that can be read and worked on by us easily [ await here because we first need the data to run this ] let users = data.users; From an api you receive tons of data so you are saying the thing you want let str = " "; Empty string users.forEach(data => str += generateCard(data)); looping through each item of an array , generate card is a function that returns a card component in string format like

hi

cards.innerHTML = str; after str has all the cards we just add / inject it in DOM [ basically the website ] } --- From here, we are getting **data.users**: { "users": [{ "id": 1, "name": "Akshay Sharma", "img": "https://avatars0.githubusercontent.com/u/37118877?v=4", "links": { "website": "https://www.developeratease.com/", "linkedin": "https://www.linkedin.com/in/akshay-sharma-7962ab13a/", "github": "https://github.com/Akshay2996", "twitter": "https://twitter.com/AkshayS2909" }, "title": "FrontEnd Developer", "location": { "city": "Bangalore", "state": "Karnataka", "country": "India" } }, { "id": 2, "name": "Satyaki Bose", "img": "https://avatars1.githubusercontent.com/u/25426670?s=400&u=7cc72ca148ae88bf19a10b8f36b21806504ffe34&v=4", "links": { "website": "", "linkedin": "https://www.linkedin.com/in/satyaki07/", "github": "https://github.com/satyaki07", "twitter": "https://twitter.com/satyaki_07" }, "title": "Developer", "location": { "city": "Kolkata", "state": "West Bengal", "country": "India" } }, { "id": 3, "name": "Rafael Rodrigues", "img": "https://avatars3.githubusercontent.com/u/46648727?v=4", "links": { "website": "", "linkedin": "https://www.linkedin.com/in/rafaelrodrigues55/", "github": "https://github.com/RafaelBatman55", "twitter": "https://twitter.com/rafa_55" }, "title": "FrontEnd Developer", "location": { "city": "Resende", "state": "Rio de Janeiro", "country": "Brazil" } }, { "id": 4, "name": "Ameen Shafeeq", "img": "https://avatars0.githubusercontent.com/u/49345531?v=4", "links": { "website": "https://ameencodes.tech/", "linkedin": "", "github": "https://github.com/unevencoder", "twitter": "https://twitter.com/crafter_coder" }, "title": "Student", "location": { "city": "Jeddah", "state": "", "country": "Saudi Arabia" } }] } --- ## **Problem no. 2** Could you please explain what is the *function* of these brackets{} in the below code? module.exports = { createPdf }; In *JavaScript*, we can create *objects* using brackets like `{ name: "Twindle" }` It is an *object*. Suppose we save this *object* into a *variable* me `const me = { name: "Twindle" }` Then, we will be able to print this in the *console* `console.log(me.name);` Because there's an *object* called "me" and in the *object*, there is a *property* called "name". There is a concept in *JavaScript*. Here we did, `{ name: "Twindle" }` Instead, if we already have something like this `const name = "Twindle";` Then, we can use that *variable* to create an *object* e.g. `const me = { name: name };` (Please pay special attention here, we have already created "name" *variable* and we are assigning that "name" *variable* as value in the "name" *property* in the *object*.) Then, you will still be able to print this in the *console*, :golfing: `console.log(me.name);` And it will work the same way. So, now we have `const me = { name: name };` In the above code, `name:name` looks odd. So, *JavaScript* made the syntax shorter. e.g. `const me = { name };` This means find the existing "name" *variable*. And store that with the same *variable* name and the *variable* value. Then, we will be still able to do this console.log(me.name); We will get the same result. So, we have to write the same name as the *variable* or you need to create the *variable* name as needed in the *object*. Suggestions are welcome :blush:!! ================================================ FILE: misc/docs/articles/pr-clean-commits.md ================================================ Take a look at the image below ![A PR](./images/fork-ahead-upstream-header-image.png) It's a PR I opened recently. I made only 2 commits related to this PR, but as you can see, this includes a lot of commits (19 to be exact). The thing is that it was 15 commits in the previous PR, and around 13 in the one before. As you can see, these commits are just adding on. The next PR I make would have all these included plus the new commits. So, how do you make these disappear? Read on! # Why does it happen? It happens primarily when you make a PR from your `main` branch, or just push commits from it. A word: > Never push changes from main. Your `main` exists only to sync latest changes from the upstream branch. Always make a new branch, edit code there, and make the PR from that branch only. # Yeah, but tell me how to get rid of those stowaway commits! Right! All you have to do is run these commands ```bash git checkout main git reset --hard upstream/main git push --force ``` These above should do it. But remember! You shouldn't have any changes in your working repo, as they might get deleted. Better make a new branch, then go back to `main` and run these commands then. ================================================ FILE: misc/docs/articles/puppeteer-explained.md ================================================ ### **What is Puppeteer?** Puppeteer From the documentation > Puppeteer is a Node library which provides a high-level API to control headless Chrome or Chromium over the DevTools Protocol. In other words, it is a Node library that we can use to control a headless Chrome instance. That means we are actually using Chrome, but programmatically using JavaScript. And "headless Chrome" is Chrome without the graphical user interface. (OK, thats alot of Chromes :hammer: :grinning: ) ### **Why do we need Puppeteer?** We know that using Twindle we convert long twitter threads to readable PDFs/ePubs. So in that process we create HTML from Twitter thread content and then convert that HTML to PDFs > Twitter thread --> HTML --> PDF [Previously](https://github.com/twindle-co/twindle/issues/415) we have seen how we can use Handlebars to compose HTML from Twitter thread content and will now convert that HTML to PDF with the help of Puppeteer ( atleast for now :grinning: ) > We need Puppeteer to render the HTML content in the headless browser so that we can perform print operation to convert the content to PDF. ### **How to utilize Puppeteer in Twindle project?** Already @tolgaerdonmez has implemented Puppeteer to generate PDF from HTML. Lets dissect the code :grinning: :hocho: Following is the code from [create-pdf.js](https://github.com/twindle-co/twindle/blob/main/playground/cli/pdf-from-html-cli/create-pdf.js) ``` const puppeteer = require("puppeteer"); const fs = require("fs"); // Creates a pdf document from htmlContent and saves it to outputPath async function createPdf(outputPath, htmlContent) { // launchs a puppeteer browser instance and opens a new page const browser = await puppeteer.launch(); const page = await browser.newPage(); // sets the html of the page to htmlContent argument await page.setContent(htmlContent); // Prints the html page to pdf document and saves it to given outputPath await page.emulateMediaType("print"); await page.pdf({ path: outputPath, format: "A4" }); // Closing the puppeteer browser instance await browser.close(); } module.exports = createPdf; ``` In the code above we are basically using headless Chrome browser to print content to PDF. Though the code is self explanatory, let me explain it ( atleast for the sake of this issue :grimacing: ) Firstly we are including modules: puppeteer -- for rendering HTML and printing to PDF. fs -- Node.js file system module to work with the file system on your computer. And we are creating an async function here with await as we have to perform each step after execution of the previous one. As simple as we cannot print content without first loading the content. Lets see the process in 3 simple steps. Step 1: Launching a new browser instance and then opening a new page. ``` const browser = await puppeteer.launch(); const page = await browser.newPage(); ```
Step 2: Setting the page content to our HTML content.

``` await page.setContent(htmlContent); ```
Step 3: Setting media type to print that enables the page to be in print mode and next step would be printing the page in given "outputPath" and format of the print "A5". At the end, closing the browser.

``` await page.emulateMediaType("print"); await page.pdf({ path: outputPath, format: "A5" }); await browser.close(); ```
And finally in [index.js](https://github.com/twindle-co/twindle/blob/main/playground/cli/pdf-from-html-cli/index.js), we are creating PDF using below code that will generate Twindle.pdf with the twitter thread content. ``` await createPdf("Twindle.pdf", htmlContent); ``` ### **What are Pros, Cons and Alternatives for Puppeteer?** **Pros** - As Puppeteer is a Chrome automation tool written in NodeJS, the generated PDF is by Chrome itself and its hard to find a better PDF generation tool for web than this. - Fully functional and robust. - Popular and maintained by Chrome DevTools team and used internally by Google. **Cons** - The only disadvantage is that using Puppeteer means we are installing a full Chrome browser in server and it might have a larger footprint. Though there is "puppeteer-core" which is a lightweight version of Puppeteer, we need a browser installation already or a remote one for connecting which again might not fully relieve from server load. **Alternatives for Puppeteer** - [PhantomJS](https://github.com/ariya/phantomjs) is the only alternative to Puppeteer with ~ 28k stars on Github but it has been [archived](https://github.com/ariya/phantomjs/issues/15344) and its not maintained. Thanks to @tolgaerdonmez for the amazing code. Hope you understood Puppeteer and how to generate PDFs using rendered HTML. Let me know 👍 or 👎 ================================================ FILE: misc/docs/articles/setup-prettier-vscode.md ================================================ # Setting up auto-formatting in VSCode in 5 minutes > Originally published on [puruvj.dev](https://puruvj.dev/blog/setup-prettier-vscode) ![Ugly vs Clean](https://puruvj.dev/media/prettier-setup-ugly-vs-clean/large.jpg) look at the image above ☝. What do you see? On the left, there is a very clean table chair, and very orderly. It's the kind of place where people would wanna sit and have a chat together. It's place where this 👇 happens ![Tony and Cap Shake hand](https://puruvj.dev/media/tony-cap-handshake-endgame.gif) On the right, it's a mess. A total mess. You simply can't expect to collaborate with anyone in here. You'd probably scare them off! No good conversation, no collaboration, nothing, NADA!! ![Tony punch Cap in his perfect teeth](https://puruvj.dev/media/tony-punch-cap-perfect-teeth.gif) This is the same situation with well-formatted code, and unformatted code. A little letter to those who have written unformatted code/still write them: > The code may look ugly, but it's still **your** code. You wrote it with the sweat of your brows and strength of your fingers. It's your child, as Scott Tolinsky would say. Having written unformatted code doesn't make you a bad developer. If you're the only one involved in the project, sure go ahead and write unformatted code. Nobody minds(And ignore those who do). But if you are in a team or in some situation where multiple developers are collaborating on the code, you need to have properly formatted code, whether by yourself by hand, or by having it auto-formatted by the tooling. And it's better if it's auto-formatted. And it's good to have formatted code, even when you're on your own. Higher readability, Higher productivity. And this is where Prettier comes in. # What is Prettier? Prettier is basically a tool that automatically formats the code you've written, saving you the headache of fixing spaces and brackets positioning yourselves. ## So it's a VSCode extension? Off course, as the title says 😋. It's a very good extension that saves you a lot of trouble. All you have to know is one shortcut key combo to automatically format the code, and boom, you're done. But it's more than an extension. it's actually an NPM package as well as a CLI originally, on top of which the VSCode extension has been written. It can be run as easily as ```powershell prettier --write filename.js ``` or, to format all kinds of files all at once ```powershell prettier --write "src/**/*.{html,css,js,json,jsx,tsx}" ``` ## Why should I bother with the NPM package? VSCode extension is much easier and better in terms of Developer Experience, but it can only format one file at a time. If you're adding prettier in a pre-existing large-enough project, you simply can't bother with opening every single file yourselves, and hitting the magic keys. You need to bulk-format them. That's where Prettier Node CLI comes in. There's also the fact that VSCode is a memory hog, and adding extensions to it makes everything slower. You don't need to bother with this point if you have a 8 GB RAM, i5 CPU with blazing-fast SSD laptop, it can take any extension (These specs are just my laptop's specs, these are not hard limits in any way). But if you have a slow system and don't wanna add any extensions, No Problem 👍. You'll just need to learn to use the CLI. And it's simple enough. I'll cover that below. Now let's cut to the chase. # Setting up the VSCode extension All right, open up your VSCode 1. Hit `Ctrl+P` (Or `Cmd+P` if on MacOS) 2. Type `ext install esbenp.prettier-vscode` in the input box that opens up, and hit enter. 3. This will install the extension. If it opens up a dialog box about syncing this extension, choose your sync preference for this extension. If you're not sure what that means, I recommend just choosing `Yes`. That should be good enough There, now you have Prettier installed as an extension in VSCode ## How to use it? Easy. Open up any file you wish to format. Any JavaScript file for example. Right click anywhere in the code, and you'll see the Format Document option in the context menu. Click on it, and your document will be auto-formatted, like this 👇 ![VSCode right click to format](https://puruvj.dev/media/prettier-setup-format-option-vscode.gif) Magic, right? ## Shortcut keys This is a tricky one. You see, the shortcut keys are different for different Operating Systems and sometimes even for different environments. You'll have to see for yourself. Look at the GIF above. You can the see the shortcut key combo right next to the Format Document option. It's Alt+Shift+F for me. ## Optional You can modify your settings to format the document whenever you hit `Ctrl+S`. Just open up your VSCode settings, search for `"Format on Save"`, and check the option as true. ![Format on Save](https://puruvj.dev/media/format-on-save.gif) > Note: If you have autosave turned on, beware, for whenever you type, your code may jump around like crazy, as prettier tries to format your document at the instant you're typing. # Using it with the CLI This section is dedicated to how to format using the Prettier CLI ## Installing the CLI There 2 ways to install the CLI 👉 ### Global It can be installed globally: ```powershell npm install -g prettier ``` This approach is fine. However, if you're a new linux user and getting permission errors, don't worry for now. Just read the next section to install prettier locally. ### Local Local here means you install prettier in the folder you're working on right now, and run it locally. This is actually the recommended way, and better than the global approach, in my opinion ¯\\\_(ツ)\_/¯ ```powershell npm install --save-dev prettier ``` ## Running it ```powershell npx prettier --write file.js ``` This is for the locally installed prettier. For global, remove `npx`: ```powershell prettier --write file.js ``` You can tell it to run prettify all JS files directly in the directory ```powershell npx prettier --write "./src/*.js" ``` Or recursively prettify all the JS files, no matter how deeply embedded in folders ```powershell npx prettier --write "./src/**/*.js" ``` You can target multiple file formats too ```powershell npx prettier --write "./src/**/*.{js,ts,html,css,json}" ``` The possibilities are endless. # .prettierrc Lastly, you can add your own `.prettierrc` file to the your workspace. It is basically a little config file telling prettier how it should handle the formatting. Here's mine: ```json { "singleQuote": true, "trailingComma": "all", "printWidth": 100 } ``` As you see, this file is tiny. And that's the best thing about prettier. Prettier comes with very sensible defaults, and will get you very good formatting even without the config file # Conclusion Hoped this article helped 😁 ================================================ FILE: misc/docs/articles/solving-forked-commit-ahead.md ================================================ ## Scenario > - You fetch the upstream/main to your local repo > - You pull the upstream/main to your local repo > - You push the changes to origin/main > - Now your origin/main is few commits ahead of upstream/main even though they are both same. ## Solution ```console $ > git checkout main $ > git fetch upstream $ > git reset --hard upstream/main $ > git push --force ``` > This will sync your origin/main with upstream/main and resolve the commit ahead issue. ================================================ FILE: misc/docs/articles/sync-to-main-repo-using-git-bash.md ================================================ --- I assume you already forked the main repo and clone into your local Initially it has a default remote called origin,that points to your fork on GitHub git remote -v # Need to do - Fetch the changes from main Repo to local - Merge the changes in your local - push the merged changes to you forked Repo **Step 1:** - To keep track of the original repo, you need to add another remote named upstream git remote add upstream **Step 2:** - Fetch the changes from main Repo to local git fetch upstream **Step 3:** - Merge the changes in your local git merge upstream/main **Step 4:** - push the merged changes to you forked Repo git push origin ================================================ FILE: misc/docs/articles/sync-to-main-repo-using-pull-request.md ================================================ In this post, you will learn how to use Github pull request to synchronize your forked repository with the parent repository by following below steps. 1️⃣ Open and navigate to your forked repo on GitHub and generate a pull request ![image](https://user-images.githubusercontent.com/66166738/99892638-daa99800-2c9c-11eb-9e0b-0c3fb256287c.png)
2️⃣ Enter your fork repo as base repo ![image](https://user-images.githubusercontent.com/66166738/99892736-05482080-2c9e-11eb-8e3b-7900e93b4870.png)
3️⃣ Once you enter the base as your fork repo, you will be navigated to the "Comparing changes" section, just click "compare across forks" ![image](https://user-images.githubusercontent.com/66166738/99892706-8ce15f80-2c9d-11eb-9de0-f9a879a5b3b5.png)
4️⃣ Enter the original/main repo as the head repository and click on "create pull request". ![image](https://user-images.githubusercontent.com/66166738/99892752-4a6c5280-2c9e-11eb-8674-336b7f7ac675.png)
5️⃣ Enter the title of your pull request and press again on the "create pull request". ![image](https://user-images.githubusercontent.com/66166738/99893151-8dc8c000-2ca2-11eb-9ec2-ca2be173eeea.png)
6️⃣ It will perform some checks, and once all the tests are passed, click on the Merge pull request. ![image](https://user-images.githubusercontent.com/66166738/99892833-3e34c500-2c9f-11eb-8b6b-1090b7539bfb.png)
7️⃣ It's going to ask again to confirm the merger. Just press the "confirm merge" button ![image](https://user-images.githubusercontent.com/66166738/99892887-12fea580-2ca0-11eb-90d7-994dcaa9fc18.png)
8️⃣ Now you've successfully merged the file ![image](https://user-images.githubusercontent.com/66166738/99892927-77216980-2ca0-11eb-89d4-4e92a869da32.png)
9️⃣ Now we need to update the local clone repository as we sync our fork repo. Navigate to the clone directory on your local machine and make sure you have opened the same branch you built the PR with, for me it was 'main'  and execute the command 'git pull' ![image](https://user-images.githubusercontent.com/66166738/99893023-80f79c80-2ca1-11eb-910c-93539ce2135c.png)
You've now updated your local clone with the changes you merged from the original GitHub repository into your fork. ================================================ FILE: misc/docs/articles/sync-to-main-repo.md ================================================ Here, I am assuming that you have already connected your **GitHub** account with the **Visual Studio Code**. **Step 1:** - First, Open the folder in **Visual Studio Code**, which is connected to your **GitHub** account. ![Screen1](https://user-images.githubusercontent.com/72906055/96881417-e1759d00-149b-11eb-932f-16e1fd2844c1.JPG) **Step 2:** - Then, click on the **Source Control** button ![Screen2](https://user-images.githubusercontent.com/72906055/96881465-eb979b80-149b-11eb-91f0-dc08aa8db16b.JPG) **Step 3:** - After clicking the **Source Control** Button, you will see **Three dots**, click it then a **Dropdown** will appear like shown below, ![Screen3](https://user-images.githubusercontent.com/72906055/96881506-f81bf400-149b-11eb-9fd2-939b3aff9626.png) **Step 4:** - Click **Pull, Push** button then another **Dropdown** will appear where you have to click **Pull from...** button ![Screen4](https://user-images.githubusercontent.com/72906055/96881545-023df280-149c-11eb-800f-f634c1856065.png) **Step 5:** - Here, you will see a **Box** with two options and you have to select **Upstream** option because **Origin** option is what you set it from your **GitHub** account, where you forked it from the main branch. Click **Upstream** option two times and wait for some times. Now, your local repository is synced with main repo. ![Screen5](https://user-images.githubusercontent.com/72906055/96881590-0ec24b00-149c-11eb-95d5-6e6b8adb2b7a.png) ================================================ FILE: misc/docs/images/README.md ================================================ store document related image in this folder ================================================ FILE: misc/firstpr/abdu_masoudi.md ================================================ ## Hello :) My name is *Abdu* and I'm a self-taught Web Developer. ================================================ FILE: misc/firstpr/abhilash_s_s.md ================================================ ### Hey 👋🏽, ##### I'm [Abhilash S S](https://github.com/itsmeAB) from Kerala, India. I am looking forward with this project to learn and explore more. ================================================ FILE: misc/firstpr/ad3rinto.md ================================================ ******************************ad3rinto**************** Based in manchester , UK twitter/ad3rinto Codenewbie ================================================ FILE: misc/firstpr/adewale.md ================================================ I am Adewale. I am a beginner with basic knowledge of HTML, CSS and Javascript. I don't stop acquiring new knowledge. Check me out on [GitHub] https://github.com/princehaybee. This is just my 2nd PR. Trying to see if it goes well. I am now working on the third PR. this is still my 2nd PR. ================================================ FILE: misc/firstpr/aditya.md ================================================ 🤓 Aditya Satpute From Nashik, Maharashtra, India. I'm having 2+ years of experience in Web Dev. And Trying to learn javascript to work as Full Stack Dev. 💻 Also working as a freelancer. 🖥 AWS Cloud Developer ================================================ FILE: misc/firstpr/aditya20233.md ================================================ Aditya Lodhi-Python Begginer second PR,changes from github ================================================ FILE: misc/firstpr/aditya786.md ================================================ ================================================ FILE: misc/firstpr/akshay.md ================================================ # Hi! I'm [Akshay Sharma](https://github.com/Akshay2996) 👋 - ☯ I'm a **Developer / Thinker / Creator / Learner** - 👨‍💻 FrontEnd Developer contributing to my first **Open Source Project**. - 🔖 I would love to make some new & strong connections with people. - 🌱 Learning new things everyday. ### Languages & Tools: Visual Studio Code HTML5 CSS3 Javascript React Python SQL Git Markdown Excel ================================================ FILE: misc/firstpr/alejandra_pinto.md ================================================ ### Hi there 👋 My name is Alejandra, I´m Developer in process... ---- - 🔭 I’m currently working on Projects startup - 🌱 I’m currently learning Dart, Flutter and Phyton - 👯 I’m looking to collaborate on Mobile Apps. - 🤔 I’m looking for help with Haskell - 💬 Ask me about Java, c++ and Git. ================================================ FILE: misc/firstpr/alexis.md ================================================ I'm Alexis Rivas from México, a just graduated Computer Systems Engineer and a newbie in the open source development, I hope learn and contribute everything what I can. ================================================ FILE: misc/firstpr/ali.md ================================================ Ali Ka from Sénégal. CS student, comfortable with HTML/CSS bootstrap and javascript. ================================================ FILE: misc/firstpr/andrei.md ================================================ Andrei Dan From Romania beginner to html, css and javvascript ================================================ FILE: misc/firstpr/anujshukla.md ================================================ Hey this is Anuj from Kushinagar India, I am currently an undergrad at VIT Vellore, India. I love the frontend development and I aspire to become a full stack developer. Other than code and coffee I really like traveling and reading books ================================================ FILE: misc/firstpr/aparna.md ================================================ Aparna a tech woman on break living in Bangalore with five years of experience in Java and Java EE. Trying to get into ES6 Javascript and building projects with it. My second PR update. ================================================ FILE: misc/firstpr/aravind.md ================================================ My name is Aravind. I'm a product engineer living in US with 2 years of experience in software testing and project management. New to software development and wish to improve in HTML, CSS and JS. ================================================ FILE: misc/firstpr/arthurbuhl.md ================================================ ### Hi there 👋 I am Arthur Buhl. Web developer with basic knowledge of HTML, CSS and JS. ### Learning PR - This is my second PR using terminal. ================================================ FILE: misc/firstpr/ashish.md ================================================ Hello I'm ashish, A former QA engineer, now a front-end developer Looking forward to contribute on twindle. ================================================ FILE: misc/firstpr/baijanath.md ================================================ Hey, I am Baijanath Tharu from Nepal. I have been learning MERN stack for few months. I am comfortable with HTML, CSS, JavaScript, ReactJs and NodeJs. I am really excited to make some contributions to this project. ================================================ FILE: misc/firstpr/bill.md ================================================ # Hello 👋 I am Bill from Indonesia. Aspired to become a front-end web developer. I learned web programming for the first time in the early August 2020. I have learned HTML, CSS, JavaScript, and React so far. Looking forward to make meaningful contribution in this project ‼ ================================================ FILE: misc/firstpr/blessing.md ================================================ Olaleye Blessing, student. Little bit comfortable with HTML, CSS and JS ================================================ FILE: misc/firstpr/can.md ================================================ Can Koçman, From Turkey, Student and Developer. local PR ================================================ FILE: misc/firstpr/chimdie.md ================================================ _That really felt good once again._ ================================================ FILE: misc/firstpr/codekumar.md ================================================ Ashish Kamble, ( kambleaa007.github.io ) Full Stack Developer - 3+ Years of experience in coding ================================================ FILE: misc/firstpr/daniel.md ================================================ Hello! I'm Daniel, currently a CS student and a web developer. ================================================ FILE: misc/firstpr/davabalan.md ================================================ Davabalan ================================================ FILE: misc/firstpr/deepak.md ================================================ Deepak - From Barh, Patna, language : C > HTML > JS : Beginner ================================================ FILE: misc/firstpr/deepak1_try2.md ================================================ Deepak- i have no experience in coding except C at college level and HTML & JS as hobby ( Self taught). ================================================ FILE: misc/firstpr/edori.md ================================================ Hello, I am Edori from Nigeria. I started learning how to use HTML, CSS and Javascript this year. This is the second PR ================================================ FILE: misc/firstpr/edwin.md ================================================ My name is Edwin Mancipe. I am from Colombia. I am 43 years old. I have some experience with javascript and python. I am beginner Twindle rocks! 2ndPR take 3 :| ================================================ FILE: misc/firstpr/eyram.md ================================================ hi, Eyram is name from Ghana.i started learning web develop some months ago. Second pr. ================================================ FILE: misc/firstpr/fabio.md ================================================ #### Fabio Duarte I'm from Colombia. I'm a beginner with some experience in HTML, CSS and JavaScript. Lately I've been using Tailwindcss. I can code a simple webpage from scratch but I don't know how to connect it with backend. I really appreciate all your advices and experience in order to improve my knowledge. ================================================ FILE: misc/firstpr/franklinulrich.md ================================================ Hello I'm [Franklin](https://twitter.com/frankiefab100), a multidisciplinary Designer and UI Developer from a Biological sciences background. ================================================ FILE: misc/firstpr/fusen.md ================================================ I am Fusen Ye from China. A beginner of HTML,CSS and JavaScript. I want to contribute to the project. This my first pr. if I make some mistakes,please forgive me. I like hot weather. I want to make a little progress every day. ================================================ FILE: misc/firstpr/habeeb.md ================================================ I am Alasi. I have basic knowledge of HTML and CSS but currently learning Javascript. ================================================ FILE: misc/firstpr/harsha.md ================================================ ## Hello World! Twitter Linkdein Github Telegram
### I am Harsha Vardhan - An Cyber security enthusiast - A Computer Engineering Undergraduate Student. - Currently working on some of my cool side projects based on Web Development and Security. - I'm currently looking for opportunities. I love to learn and contribute in any and every possible way. ⭐️ From [harsha](https://github.com/harsha-ambati) ----- ================================================ FILE: misc/firstpr/ibrahim.md ================================================ Hi, this is ibrahim from jordan ================================================ FILE: misc/firstpr/jahid.md ================================================ # I am Jahid Hasan, from Bangladesh. # I am an independent learner and coder without no prior work experience. ================================================ FILE: misc/firstpr/jaki.md ================================================ Mohamad Arif Mujaki as Jaki From Jakarta, Indonesia with less 1 year of development experience. I still newbie. ================================================ FILE: misc/firstpr/jesulayomi.md ================================================ Adetola Jesulayomi, Law Student - a bit of experience in coding ================================================ FILE: misc/firstpr/jilva.md ================================================ Hi everyone, I am Jilva Sheth from India. I am a Java developer and interested to learn more about HTML, CSS and Javascript. second pr changes from git bash terminal. ================================================ FILE: misc/firstpr/joel_vinay_kumar.md ================================================ I'm Joel Vinay Kumar, a software engineer in Auzmor Inc. Find all about me in my [website](http://joel.swecha.io) ================================================ FILE: misc/firstpr/karan.md ================================================ Hello I am Karan Oza from Pune, India. I have 1 year experience in Angular Front-End development. ================================================ FILE: misc/firstpr/karan_khosla.md ================================================ Karan Khosla I'm from India I've over 9 years of experience but not in front end domain ================================================ FILE: misc/firstpr/kenny.md ================================================ Hi everyone, Kenny here ================================================ FILE: misc/firstpr/kingsley_victor.md ================================================ [Kingsley Victor](https://github.com/kingsley-einstein) Full-stack software engineer proficient in Java, Javascript and Typescript. Observed a national diploma programme in computer science at Yaba College Of Technology in Lagos, Nigeria. Presently in first year at Federal University Of Technology, Akure. Studying software engineering. ================================================ FILE: misc/firstpr/kiran_don.md ================================================ ## Hello! This is [Usha Kiran](https://twitter.com/ushakiran_m) from Andhra Pradesh, India. ### I am a second year computer science student, not having much experience in open source, projects and contribution things. ### This is my first ever pull request. ## Second PR Added this line using git CLI locally... Hope it goes well! ================================================ FILE: misc/firstpr/krishnadevz.md ================================================

Hello World👋

WebsiteTwitterLinkedin

* SelfTaught-Dev/Opensourcer🛠 I like to build things & Write things related to Web🌐🐱‍👤. * I'm ready for discussions and making new projects.I like to Contribute to the Opensource projects.🌠 * Check it out my latest blogs/articles here on 👉 [Dev.to](https://dev.to/krishnakakade) * Find More details about me :-[Website](https://krishnadevz.github.io) * You can reach me at [krishnadevz@protonmail.com](mailto:krishnadevz@protonmail.com). **Languages:** [![Top Langs](https://github-readme-stats.vercel.app/api/top-langs/?username=krishnadevz&layout=compact&theme=dracula)](https://github.com/anuraghazra/github-readme-stats) ![krishna's github stats](https://github-readme-stats.vercel.app/api?username=krishnadevz&show_icons=true&theme=dracula) [![trophy](https://github-profile-trophy.vercel.app/?username=krishnadevz&theme=onedark)](https://github.com/krishnadevz/github-profile-trophy)

Trophies

================================================ FILE: misc/firstpr/krypton.md ================================================ ### Hi there 👋 ##### I'm Kryptöñ, An engineering student with great passion for UI/UX designing, i love to create beautiful user interfaces. i also have interest in cyber security, competitive programming, and embedded systems. - 🔭 I’m currently working on UI/UX - 🌱 I’m currently learning nuxtJS. - 📫 How to reach me: - LinkedIn:-https://www.linkedin.com/in/madhusudan-babar/ - medium:- https://medium.com/@madhusudanbabar - Instagram:- https://instagram.com/madhu_babar - Portfolio:- https://madhusudan.live/ - blog:- https://blog.madhusudan.live ================================================ FILE: misc/firstpr/lara_noomene.md ================================================ I am a junior developer student, I am following some programming courses and wish to learn more through this project. ================================================ FILE: misc/firstpr/layomi.md ================================================ Adetola Jesulayomi, Law Student - a bit of experience in coding ================================================ FILE: misc/firstpr/lilfatfrank.md ================================================ Karan Parsnani Experience with React and JavaScript. Mumbai, India. ================================================ FILE: misc/firstpr/liviza.md ================================================ am luli, a newBie web-developer, this is my second PR. ================================================ FILE: misc/firstpr/lorennale.md ================================================ ### Hello World! My name is Lorenna Leon, I'm a Software Developer in process but I have a lot of desire to learn everything I can I´m from Lima.Perú ---- :telescope: I am a bootcamp student. :seedling: I’m currently learning react,javascript, html and css . :mag_right: I’m looking to collaborate with open source projects. :thinking: I’m looking for help with React. :smile: Pronouns: she/her :zap: Fun fact: I would like to have a web development company :computer: :mailbox: How to reach me:     ---- ![](https://github-readme-stats.vercel.app/api?username=lorennaleon&show_icons=true&theme=buefy) ![](https://github-readme-stats.vercel.app/api/top-langs/?username=lorennaleon&hide=jupyter%20notebook&layout=compact) ================================================ FILE: misc/firstpr/lukmanokunade.md ================================================ Lukman Okunade, from Nigeria. I am proficient using HTML, CSS and JavaScript. I can work with NodeJs and React too ================================================ FILE: misc/firstpr/luli.md ================================================ #hi! am luli , a beginner with some basics in html5,css3 and js ================================================ FILE: misc/firstpr/manohar.md ================================================ **Manohar, new developer, looking forward to learn from this project** ================================================ FILE: misc/firstpr/manuel_alejandro.md ================================================ I'm Manuel , from Cuba. I have knowledge in HTML,CSS, JS and a little bit of React. This is my first experience in source project. Hello, i made some change for the second PR. ================================================ FILE: misc/firstpr/marcus.md ================================================ Marcus Ojetunde from Lagos, Nigeria with less than 1 year experience in web development I use React as my Js framework ================================================ FILE: misc/firstpr/maria_rivera.md ================================================ Hello, My name is Maria and I'm a Software Engineer student at 42 Silicon Valley. ================================================ FILE: misc/firstpr/mbui.md ================================================ **Githaka Mbui - Software engineer** ================================================ FILE: misc/firstpr/melissa_huerta.md ================================================ ### Hello World! My name is Melissa H, I'm a Game/Software Developer in process... Previously worked in the IT Infrastructure department but I came to **THE DARK SIDE**. (Development) ---- 🔭 I’m currently working on 'Printf' (42 project), WebSite built with React(WWC Project). 🌱 I’m currently learning C#, Unity. 👯 I’m looking to collaborate on Mobile Apps, Gaming Apps. 🤔 I’m looking for help with C#, Unity. 💬 Ask me about C, Javascript, Git & Flutter 🤓. 😄 Pronouns: she/her ⚡ Fun fact: Sometimes I make decisions based on my 8 Ball. 🎱 📫 How to reach me:     ================================================ FILE: misc/firstpr/michael.md ================================================ My name is Michael from Nigeria and I love coding. ================================================ FILE: misc/firstpr/mumbi.md ================================================ **Basic Intro** Name : Regina Mumbi Gachomba I am a kenyan student currently studying in Turkey for my undergrad degree in computer engineering Proficient in C,C++ and python. Currently doing Java OOP as part of my course work. I have basic skills in HTML,CSS and javascript from an online course that I am currently doing. Main reason for joining this open source project is to get an idea of how these projects work and to learn from senior developers. ================================================ FILE: misc/firstpr/nahuel.md ================================================ Hi everyone! I am Nahuel from Argentina, I am 24 years old. I am a beginner and this is my first time working in a project and using GitHub, have basic knowledge of c++, c #, html5, css and javascript. I apologize if my english is not very good, I will do my best to help. this will help me practice the language. I modified this from my local repo! so this will be the 2nd PR Thanks for the opportunity! ================================================ FILE: misc/firstpr/nailah.md ================================================ Nneyen Umana from Nigeria, With a few months of developing experience. This is my attempt at a PR... I messed up the first one and deleted the entire fork. Update : This is to test out my second PR.... let's see how it goes. ================================================ FILE: misc/firstpr/naveen.md ================================================ I am Naveen, an engineering student. Begineer in html , CSS, javascript and React. ================================================ FILE: misc/firstpr/neaz_mahmood.md ================================================ I couldnot my 1st pr file named neaz.md. Maybe It was not marged yet. So I made this file. I am using git bash for this pr. ================================================ FILE: misc/firstpr/nishank.md ================================================ Nishank , Beginner , Basics of Python, C, C++, I can do basic HTML, CSS by searching and getting things done by internet search . Second PR, Changes implemented from Github Desktop ================================================ FILE: misc/firstpr/nitin_kadam.md ================================================ ### Hi there 👋 Nitin Kadam From Pune, India. 5+ years of experience in the web development. Moderate level in the Front End Technologies like JavaScript, HTML, CSS. ================================================ FILE: misc/firstpr/nivetha.md ================================================ Hi, this is Nivetha from India. **Things about me** - I am a Computer Science graduate and looking for a job opportunity. - I am currently learning JavaScript and ReactJS. - Contact me at nivetharath@gmail.com - [Resume](https://drive.google.com/file/d/1w34GFk5Y_nEz6Jz5yBo76fZHFQ6RuXwJ/view?usp=sharing) Second PR, Changes implemented from GitHub Desktop ================================================ FILE: misc/firstpr/omolo.md ================================================ Passionate about technology and currently learning to be a full-stack developer. Am based in Nairobi, Kenya ================================================ FILE: misc/firstpr/paniagua.md ================================================ I'm from Dominican Rep. I have knowledge in HTML,CSS, JS and a little bit of React. I'm kind of new here in git and this will be my first contribution in an open source proyect! ================================================ FILE: misc/firstpr/pavan.md ================================================ # Hi! I'm Pavan Kallati - I'm a **Developer / Problem Solver / learner** - Trying to be a better Full Stack Developer using JS. - Learning new things everyday. ### Languages & Tools: HTML5 CSS3 Javascript React MongoDB MongoDB ================================================ FILE: misc/firstpr/pr_m.md ================================================ #Prathap CS Student. Now a working professional for a big bank. I never got a chance to work on open source or UI dev project. So, trying to improve my skills through this project. ================================================ FILE: misc/firstpr/prajwal.md ================================================ Prajwal Pradhan From Nepal, 2 years of developement experience. Specialise in React.js. ================================================ FILE: misc/firstpr/pranav.md ================================================ ## Pranav Goel From Uttar Pradesh, India ### Skills HTML, CSS, C++, C - I am just starting with javascript. ================================================ FILE: misc/firstpr/prasanna.md ================================================ Prasanna from Tamil Nadu , India with 5 years of development experience in .Net ================================================ FILE: misc/firstpr/praveen.md ================================================ Praveen from TamilNadu Having 3 years of experience as a Backend developer ================================================ FILE: misc/firstpr/pravin.md ================================================ Pravinraj - Sofware Engineer focused on frontend technologies ================================================ FILE: misc/firstpr/predrag_stamenkovic.md ================================================ Predrag Stamenkovic,a HTML and CSS beginner My name is Predrag Stamenkovic from Belgrade - Serbia. I work as Purchasing Manager in Jokey company, but very determined to become web developer in near future. Currently learning HTML and CSS. You can reach me: - mail: pedja_stamenkovic@yahoo.com - twiter: @Stamenkovic_P #twindle ================================================ FILE: misc/firstpr/prem.md ================================================ Hi all, This is Prem (MrVoicer) from India. I create WordPress Website and Speed optimize them to load fast ================================================ FILE: misc/firstpr/proful.md ================================================ Proful Sadangi From India, Living in Sydney 15 yr of developement experience ================================================ FILE: misc/firstpr/puru.md ================================================ Puru Vijay from Jaipur, Rajasthan, India. 5 years of experience. Has worked in HTML, CSS, JS, StencilJS, React, Svelte, Angular.js, Angular, JQuery, Bootstrap, PHP, NodeJS, Python, Django, Firebase ================================================ FILE: misc/firstpr/rafael.md ================================================ I'm Rafael Rodrigues from Brazil. I'm a beginner in the programming world. I started to learn HTML+CSS+JavaScript about 5 months ago. I hope I can help and learn a lot in this project! ================================================ FILE: misc/firstpr/rajesh_prajapati.md ================================================ ### Hi there 👋 - 🔭 I’m currently working on ...#React & #Flutter - 🌱 I’m currently learning ...Javascript & Dart - 👯 I’m looking to collaborate on ...Github People 👨🏻‍💻 - 🤔 I’m looking for help with ... space 🛰 - 💬 Ask me about ...#coding ✅ - 📫 How to reach me: ...@rkumar1904 - 😄 Pronouns: ...RjLooper - ⚡ Fun fact: ... ![Rajesh's github stats](https://github-readme-stats.vercel.app/api?username=rkumar1904&show_icons=true&count_private=true) ================================================ FILE: misc/firstpr/rakesh.md ================================================ ### Hey Internet,
I'm [Rakesh!](https://github.com/Rakesh-4) Software Developer have 3+ years of experience in C#, JavaScript and Angular Framework ---
> Apart from coding, I am an introvert.(So I like to keep my profile low) ================================================ FILE: misc/firstpr/rohitsawai.md ================================================ Hello Everyone, This is Rohit Sawai, from Beed, Maharashtra. I'm Software Engineer and like to develop such products which will save time my time and the time of my client by making manual task automatic. ================================================ FILE: misc/firstpr/sachin.md ================================================ Sachin from India, 6 months of experience in JavaScript, Html, Css, Node, React. ================================================ FILE: misc/firstpr/samriddhi.md ================================================ ## Hi! I'm Samriddhi, a 3rd year CSE undergrad 👨‍🎓 I am currently learning MERN stack 💻📚 Glad to be here ✨ Find me on [GitHub](https://github.com/sammjainn) ================================================ FILE: misc/firstpr/samueladeniyi.md ================================================ hello, i am samuel adeniyi from nigeria, i am comfortable with HTML, CSS, Javascript, React amd Node ================================================ FILE: misc/firstpr/sarvesh.md ================================================ Sarvesh Kadam from Mumbai,India. QA Engineer currently learning Web Developement ================================================ FILE: misc/firstpr/sasmita.md ================================================ I am web Designer love to create web page in figma and photoshop and also ready to learn .I am beginner stage. ================================================ FILE: misc/firstpr/satyaki.md ================================================ # Hi, I'm Satyaki ! I am a MERN stack developer. Find me on [Github](https://github.com/satyaki07) ================================================ FILE: misc/firstpr/saurabh_srivastava.md ================================================ # **Namaste to all of you** My name is Saurabh Srivastava B.TECH is CSE. Graduate of 2018. From India, Uttar Pradesh. Have 18 months Software Development Experience using LAMP Stack. Know Front End Technologies like JavaScript, HTML5, CSS3 in moderation, enough to get the task done. ## **Skills** * HTML5 & CSS3 * JavaScript, jQuery * Basic Nodejs working * PHP and MySQL ## **Contact me here** Github | Twitter | LinkedIn ✉ vasudeveloper001@gmail.com ================================================ FILE: misc/firstpr/scott.md ================================================ I am Scott a frontend developer from johannesburg ,south africa. i am self taught with some knowledge of css,html, javascript , python , and node js.. ================================================ FILE: misc/firstpr/sheetal.md ================================================ ### Hey there! :) #### I am Sheetal Pandey, an engineering student from India. I basically work with Python but I am also good with HTML5 and CSS3. Though I am yet to learn JavaScript. Happy to collaborate and learn together. ================================================ FILE: misc/firstpr/shekharranjan.md ================================================ Shekhar Ranjan - Learning JavaScript and a beginner in GitHub. I have basic knowledge of Java and SQL.This is 2nd PR and I am doing this from GitHub Desktop. ================================================ FILE: misc/firstpr/simrin_joshi.md ================================================ I am a passionate professional focussed on full stack developement. I have 1.5 years of experience in Angular, HTML, CSS , JS, Java and MySQL. I am looking forward to actively contribute to Twindle. ================================================ FILE: misc/firstpr/sippeybro.md ================================================ Hi im sippey bro ================================================ FILE: misc/firstpr/sravan.md ================================================ sravan-html,css andjs enthusiast.Open to learn new things. This is my second pr from my local machine.... ================================================ FILE: misc/firstpr/sunny.md ================================================ ### hey there **second pr** i am sunny, from India and a Engineering student.. and am very much comfortable in HTML, CSS and JavaScript. And am currently Working on MERN Stack. You can reach me out on @sunny_dev_01 is my twitter handle.!!! ================================================ FILE: misc/firstpr/suraj.md ================================================ ### Hi folks, I'm Suraj! :sun_with_face: Suraj Chandgude | Linkedin Suraj Chandgude | Twitter Suraj Chandgude | Instagram Suraj Chandgude | Gmail

Hi, I'm Suraj Chandgude, a passionate sapien who writes computer programs and resides on earth for now! - :100:   Take a look at my portfolio site: https://iamsurajdc.js.org :globe_with_meridians: - 🌱   I’m currently diving into Vue.js - 💬   Give me shoutout [here](https://twitter.com/iamsurajdc) - :page_facing_up:   yes, I read sometime. #### Cheers! ================================================ FILE: misc/firstpr/swatirao.md ================================================ Hi, I am swati from mumbai. Know basics of html,css. excited to learn something new ================================================ FILE: misc/firstpr/teckiegeek.md ================================================ Titi Olopade from United Kingdom. My background is computing with few years career break. I came back and got PRINCE2 certification (project management) and started learning coding less than a year ago. My HTML and CSS are at an intermediate level. Here is how I created my second PR. Use GIT Bash for Microsoft Windows environment to run GIT from my commandline. From the twindle repository page on GitHub, click the green button labeled Clone or download. In the “Clone with HTTPs” section, copy the URL for the repository. On your laptop, open your GIT bash shell. Type 'cd desktop' to change to to desktop directory where you want to install the cloned repository Next, type 'git clone (URL for the repository)' Once completed, it will display 'done' Type 'ls -a' to view all the files in the repository (Do not edit any file from the command line). Now go back and make some changes and save. Then commit on your laptop by typing 'git commit' Then push to your fork and then on your fork you make pull request, just like for 1st PR. ================================================ FILE: misc/firstpr/therealjimoh.md ================================================ Abdullah Jimoh, from Nigeria. I am a beginner in Front-end development. ================================================ FILE: misc/firstpr/titi_olopade.md ================================================ Titi Olopade from United Kingdom. My background is computing with few years career break. I came back and got PRINCE2 certification (project management) and started learning coding less than a year ago. My HTML and CSS are at an intermediate level. Here is how I created my second PR. Use GIT Bash for Microsoft Windows environment to run GIT from my commandline. From the twindle repository page on GitHub, click the green button labeled Clone or download. In the “Clone with HTTPs” section, copy the URL for the repository. On your laptop, open your GIT bash shell. Type 'cd desktop' to change to to desktop directory where you want to install the cloned repository Next, type 'git clone (URL for the repository)' Once completed, it will display 'done' Type 'ls -a' to view all the files in the repository (Do not edit any file from the command line). Now go back and make some changes and save. Then commit on your laptop by typing 'git commit' Then push to your fork and then on your fork you make pull request, just like for 1st PR. ================================================ FILE: misc/firstpr/tolga.md ================================================ Tolga Erdönmez, From Turkey, Student and developer :) I like javascript, go, python, Building web & desktop apps, automating stuff, CLIs ================================================ FILE: misc/firstpr/trombley.md ================================================ I am trombley!just making a beginning #update one This is a second PR ================================================ FILE: misc/firstpr/tushar.md ================================================ Tushar Kashyap from India, good with HTML, CSS, JS and React. ================================================ FILE: misc/firstpr/tusharkandpal.md ================================================ # **Hey Folks!** I'm Tushar Kandpal 👨‍💻! An Electrical Engineer from Uttarakhand, India. Also a beginner in Front-End field. *** ## **Skills** * HTML, CSS, Java * Familiar with JavaScript, C++, DS, MySql * **Frameworks:** Bootstrap * **Technologies:** Git, VS Code *** ## **Catch Me Here** Github | Twitter | LinkedIn ✉ kandpal.tushar@gmail.com ================================================ FILE: misc/firstpr/varad.md ================================================ Varad Karpe from India Recently graduated as a Computer Science Engineer Experience: I have worked on a few Java projects during my internships(2). Skills: Java, HTML, CSS, Python, Javascript, C, C++, SQL ================================================ FILE: misc/firstpr/vera_nkanmuo.md ================================================ Hi,I'm Chioma Vera Nkanmuo, Beginner Web developer from Nigeria with basic knowledge of HTML and CSS. I am currently in my penultimate level in university. Aside from coding, I love to read alot. FUN FACT: I am a fitness ethusiast. I love to teach (because i believe in sharing knowlege, you gain knowlege), so you may reach out to me for help, and I will be delighed to help. Connect with me: verachioma39@yahoo.com / verayahoo5@gmail.com follow me instagram and twitter; @dev_chivee ================================================ FILE: misc/firstpr/vijaya.md ================================================ Vijaya Bhaskar from Hyderbad, India with 9 years of development experience. This is a second pull request. ================================================ FILE: misc/firstpr/vipin.md ================================================ Hi i am vipin, A frontend developer from Punjab mostly working on react native trying to learn advance javascript and nodejs. ![Vipin's github stats](https://github-readme-stats.vercel.app/api?username=aesthytik) ================================================ FILE: misc/firstpr/viraj_patil.md ================================================ ** Second PR ** Hi, I'm Viraj Patil, with 9 years of experience in software development. Currently working as fullstack developer. Aside from coding, I love to read alot. You can reach me out on: e-mail: mr.virajpatil@gmail.com twitter: @mr_viraj ================================================ FILE: misc/firstpr/wamuyuwanjohi ================================================ Wamuyu Wanjohi : Kenyan Junior Data NAalyst who enjoys a bit of DS ================================================ FILE: misc/firstpr/yash.md ================================================ Yash Gupta from India. Web developer and currently in Final year of college. Skill-HTML, CSS, Javascript, React, NodeJs. My first pull request to twindle ================================================ FILE: misc/playground/cli/README.md ================================================ # Folder Naming Convention > Place your code inside a folder ### Use dashes(-) as delimiters ### Use lowercase letters ### Create a readme file explaining the steps to run the code ================================================ FILE: misc/playground/cli/spike/HackerNews/code.js ================================================ const fetch = require("node-fetch"); async function searchFor(searchTerm) { const queryResult = []; const url = `http://hn.algolia.com/api/v1/search?query=${searchTerm}&tags=story`; const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); queryResult.push(result); return queryResult[0].hits; } async function captureCommentsId(keyword) { const elements = await searchFor(`${keyword}`); const Time = []; const Titles = []; const Urls = []; const StoryIds = []; for (const [k] of elements.entries()) { Time.push(elements[k].created_at); Titles.push(elements[k].title); Urls.push(elements[k].url); StoryIds.push(elements[k].objectID); } return [Time, Titles, Urls, StoryIds]; } async function searchForStoriesComments(keyword) { const [Time, Titles, Urls, StoryId] = await captureCommentsId(`${keyword}`); const commentsDump = []; for (const [, value] of StoryId.entries()) { const api = `https://hn.algolia.com/api/v1/search?tags=comment,story_${value}`; const response = await fetch(api); const Page = await response.json(); commentsDump.push(Page); } return [commentsDump, Titles, Urls, Time]; } //searchForStoriesComments() async function dumpEverything(keyword) { const [comments, Titles, Urls, Time] = await searchForStoriesComments( `${keyword}` ); const commentsText = []; for (const [, element] of comments.entries()) { //console.log(`${id} and ${element}`) const single = element.hits; for (const [, val] of single.entries()) { //console.log(`${key} and ${val}`) let commentval = val.comment_text; commentsText.push(commentval); } } return [commentsText, Titles, Urls, Time]; } //dumpEverything() async function constructObjectArray(keyword) { const [Comments, Titles, Urls, Time] = await dumpEverything(`${keyword}`); const arrayOfStories = []; for (let i = 0; i < Titles.length; i++) { if (i != 0) { spin(Comments, 20); } arrayOfStories.push({ Story: Titles[i], Date: Time[i], Website: Urls[i], discussion: Comments.slice(0, 20), }); } //console.log(arrayOfStories); return arrayOfStories; } //constructObjectArray(); function spin(array, window) { const gone = array.splice(0, window); return [...array, ...gone]; } module.exports = { constructObjectArray }; ================================================ FILE: misc/playground/cli/spike/HackerNews/code2.js ================================================ const fetch = require("node-fetch"); //only story ids async function searchFor() { const frontStoryIDs = []; const url = `https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty`; const response = await fetch(url); const result = await response.json(); const sliced = result.slice(0, 4); frontStoryIDs.push(sliced); return frontStoryIDs; } //response from all storyids async function StoriesOnFrontPage() { const [frontStoryids] = await searchFor(); const StoryIDs = []; const kidos = []; const Title = []; const Url = []; const requests = frontStoryids.map((x) => fetch(`https://hacker-news.firebaseio.com/v0/item/${x}.json?print=pretty`) ); const response = await Promise.all(requests); const filter = await Promise.all(response.map((res) => res.json())); for (const [k, v] of filter.entries()) { StoryIDs.push(v.id); kidos.push(v.kids); Url.push(v.url); Title.push(v.title); } return [StoryIDs, kidos, Title, Url]; } //front comment +id with parentid=storyid async function frontComments() { const CommentsText = []; const OwnId = []; //frontcomments own id const ParentId = []; //or storyid const Ownkids = []; //front comment kids const kidolen = []; const [, kidos, Title, Url] = await StoriesOnFrontPage(); const allkids = [].concat(...kidos); const requests = allkids.map((x) => fetch(`https://hacker-news.firebaseio.com/v0/item/${x}.json?print=pretty`) ); const response = await Promise.all(requests); const filter = await Promise.all(response.map((res) => res.json())); for (const [k, v] of filter.entries()) { if (v.deleted !== true) { CommentsText.push(v.text); OwnId.push(v.id); ParentId.push(v.parent); Ownkids.push(v.kids); } else { OwnId.push(v.id); ParentId.push(v.parent); } } return [OwnId, ParentId, Ownkids, CommentsText, kidolen]; //OwnId:frontcomments own id //ParentId:or storyid //Ownkids:kids of front comment } //all frontend Comments are here in commentText(); async function midcomments() { const [ OwnIdorSecondPartid, firstparentid, Ownkidsid, , ] = await frontComments(); const subsequentComments = []; const ourkids = []; const subparentid = []; const ownid2 = []; //const Ownkidlen = []; const furthercomments = [].concat(...Ownkidsid).filter((e) => e !== undefined); //fetch childrens of first comment const requests = furthercomments.map((x) => fetch(`https://hacker-news.firebaseio.com/v0/item/${x}.json?print=pretty`) ); const response = await Promise.all(requests); const filter = await Promise.all(response.map((res) => res.json())); for (const [k, v] of filter.entries()) { if (v === null) { console.log("null val"); } else if (v.deleted !== true) { subsequentComments.push(v.text); ownid2.push(v.id); subparentid.push(v.parent); ourkids.push(v.kids); } else { console.log("undefined"); subparentid.push(v.parent) ownid2.push(v.id) } //return [ourkids,subparentid,subsequentComments] //subsequentcomments:childrens of front comments //subparent:frontcomments } return [ownid2, ourkids, subparentid, subsequentComments]; } midcomments(); async function lastlayercomments() { const [, ourkids, ,] = await midcomments(); const lastlayerComments = []; const ownid3 = []; const ownparentid = []; const secondlayer = [].concat(...ourkids).filter((e) => e !== undefined); const requests = secondlayer.map((x) => fetch(`https://hacker-news.firebaseio.com/v0/item/${x}.json?print=pretty`) ); const response = await Promise.all(requests); const filter = await Promise.all(response.map((res) => res.json())); for (const [k, v] of filter.entries()) { lastlayerComments.push(v.text); ownid3.push(v.id); ownparentid.push(v.parent); } return [ownid3, ownparentid, lastlayerComments]; } lastlayercomments(); async function constructObjectArray() { const everything = []; const [StoryIDs, , Title, Url] = await StoriesOnFrontPage(); const [OwnId, ParentId, , CommentsText] = await frontComments(); const [ownid2, , subparentid, subsequentComments] = await midcomments(); const [ownid3, ownparentid, lastlayerComments] = await lastlayercomments(); //StoryIDs==ParentId(parent of 1st level comments) //Ownid(means 1st commment)==subparentid(parent of mid comments):means first comments are parent of midlevel ones //ownid2(mid comment)==ownparentid(parent of last layer) : //creating some key-value relationship between using parent and child ID //to align comments const objfirstlevel = {}; for (let i = 0; i < CommentsText.length; i++) { objfirstlevel[CommentsText[i]] = ParentId[i]; } const attachfisttomiddle = {}; for (let i = 0; i < OwnId.length; i++) { attachfisttomiddle[OwnId[i]] = ownid2[i]; } const objmidlevel = {}; for (let i = 0; i < subsequentComments.length; i++) { objmidlevel[subsequentComments[i]] = subparentid[i]; } const attachmidtolast = {}; for (let i = 0; i < ownid2.length; i++) { attachmidtolast[ownid2[i]] = ownid3[i]; } const objlastlevel = {}; for (let i = 0; i < lastlayerComments.length; i++) { objlastlevel[lastlayerComments[i]] = ownparentid[i]; } } constructObjectArray(); ================================================ FILE: misc/playground/cli/spike/HackerNews/mainindex.js ================================================ const { constructObjectArray } = require("./code"); const Renderer = require("./renderer"); async function news(keyword) { const data = await constructObjectArray(`${keyword}`); const outputFilePath = `${__dirname}/news.pdf`; await Renderer.render(data, outputFilePath); console.log(`your pdf saved to ${outputFilePath}`); } news("medicine"); ================================================ FILE: misc/playground/cli/spike/HackerNews/renderer/index.js ================================================ //const { generateEpub } = require("./epub/index"); const { generatePDF } = require("./pdf"); //const spinner = require("../spinner"); const render = async (tweets, outputFilePath) => { return generatePDF(tweets, outputFilePath); /*case "epub": return generateEpub(tweets, outputFilePath);*/ //default: //spinner.fail("Error: This renderer is not implemented yet"); //console.error("Error: This renderer is not implemented yet"); }; module.exports = { render, }; ================================================ FILE: misc/playground/cli/spike/HackerNews/renderer/pdf/createpdf.js ================================================ // @ts-check const puppeteer = require("puppeteer"); function footerMarkup() { return ` `; } /** * Creates a pdf document from htmlContent and saves it to outputPath * @param {string} outputPath * @param {string} htmlContent */ async function createPdf(outputPath, htmlContent) { try { // launches a headless puppeteer browser instance and opens a new page const browser = await puppeteer.launch({ args: ["--no-sandbox"], headless: true, }); const page = await browser.newPage(); // sets the html of the page to htmlContent argument await page.setContent(htmlContent); // Prints the html page to pdf document and saves it to given outputPath await page.emulateMediaType("print"); await page.pdf({ path: outputPath, format: "A5", margin: { bottom: 52, // minimum required for footer msg to display left: 20, right: 20, top: 10, }, printBackground: true, displayHeaderFooter: true, footerTemplate: footerMarkup(), headerTemplate: "
", }); // Closing the puppeteer browser instance await browser.close(); } catch (error) { console.error(error); } } module.exports = { createPdf }; ================================================ FILE: misc/playground/cli/spike/HackerNews/renderer/pdf/index.js ================================================ const { renderTemplate } = require("../render-template"); const { createPdf } = require("./createpdf"); async function generatePDF(data, outputPath) { const parameter ={Story: data}; // creates the html content const htmlContent = await renderTemplate( parameter, "template" ); // creates the pdf from html and saves it to Twindle.pdf await createPdf(outputPath, htmlContent); return; } //generatePDF() module.exports = { generatePDF }; ================================================ FILE: misc/playground/cli/spike/HackerNews/renderer/render-template.js ================================================ const { readFile, writeFile } = require("fs").promises; const hbs = require("handlebars"); const { tmpdir } = require("os"); const { join } = require("path"); /** * Renders the html template with the given data and returns the html string * @param {CustomTweetsObject} data * @param {string} templateName */ async function renderTemplate(data, templateName) { const html = await readFile(`${__dirname}/template/${templateName}.hbs`, "utf-8"); // creates the Handlebars template object const template = hbs.compile(html, { strict: true, }); // renders the html template with the given data const rendered = template(data); const tmpPath = join(tmpdir(), "hello.html"); await writeFile(tmpPath, rendered, "utf-8"); await writeFile(tmpdir() + "/x.json", JSON.stringify(data, null, 2), "utf-8"); console.log("rendered saved to ", tmpPath); return rendered; } module.exports = { renderTemplate}; ================================================ FILE: misc/playground/cli/spike/HackerNews/renderer/template/template.hbs ================================================

Stories from Hacker News

    {{!-- discussion forum HN --}} {{#each Story }}

    {{Story}}

    {{Date}}
    {{/if}} {{/each}}
================================================ FILE: misc/playground/cli/spike/README.md ================================================ # Spike or POC ================================================ FILE: misc/playground/cli/spike/cli-epub/.gitignore ================================================ #node modules node_modules/ #ebook files *.mobi *.pdf *.epub ================================================ FILE: misc/playground/cli/spike/cli-epub/epub.js ================================================ import epub from 'epub-gen'; const options = { title: 'The Hello World', author: 'Hello MacWorld', content: [ { title: 'Chapter 1: First Hello', data: `

Lorem Ipsum dolor sit amet, consectetur adipsicing elite. Got it? Neither did we. In the publishing and design industries, “lorem ipsum” is used as dummy text in visual designs. Using placeholder copy like this helps designers and clients alike focus on layout, imagery, typography, and design rather than on the actual wording of content. Dummy copy is great, but what’s with all the Latin? Turns out, the original Lorem Ipsum comes from bits and pieces of Cicero’s De Finibus bonorum et Malorum (On the Ends of Goods and Evils).

` } ] }; export function generateEpub (directory) { return new epub(options, directory) } ================================================ FILE: misc/playground/cli/spike/cli-epub/index.js ================================================ import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; import { generateEpub } from "./epub.js"; const options = yargs(hideBin(process.argv)) .usage("Usage: -o -n ") .option({ o: { alias: "output", demandOption: false, describe: "Output file format", choices: ["mobi", "epub", "pdf"], type: "string", default: "epub", }, n: { alias: "filename", demandOption: true, describe: "Filename for the output file", type: "string", }, }).argv; switch (options.output) { case 'epub': generateEpub(`./${options.filename}.epub`); break; case 'pdf': console.log('Sorry this format is not supported yet') break; case 'mobi': console.log('Sorry this format is not supported yet') break; default: break; } ================================================ FILE: misc/playground/cli/spike/cli-epub/package.json ================================================ { "name": "cli-epub", "version": "1.0.0", "description": "Generate cli from text input", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "billgufran", "license": "ISC", "dependencies": { "epub-gen": "^0.1.0", "yargs": "^16.1.0" }, "type": "module" } ================================================ FILE: misc/playground/cli/spike/cli-epub/readme.md ================================================ To start `node index -o -n ` Options: ``` --help Show help --version Show version number -o, --output Output file format [string] [choices: "mobi", "epub", "pdf"] [default: "epub"] -n, --filename Filename for the output file [string] [required] ``` It only support epub for now. ================================================ FILE: misc/playground/cli/spike/cli-example-esm/.gitignore ================================================ #node modules node_modules/ ================================================ FILE: misc/playground/cli/spike/cli-example-esm/index.js ================================================ import axios from 'axios'; const getBreeds = async () => { try { return await axios.get('https://dog.ceo/api/breeds/list/all') } catch (error) { console.error(error) } } const countBreeds = async () => { const breeds = await getBreeds() if (breeds.data.message) { console.log(`Got ${Object.entries(breeds.data.message).length} breeds`) } } countBreeds() ================================================ FILE: misc/playground/cli/spike/cli-example-esm/package.json ================================================ { "name": "cli-example-esm", "version": "1.0.0", "description": "Example of how to use ES6+ syntax to run node scripts", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node -r esm index.js" }, "keywords": [], "author": "Aravind", "license": "ISC", "dependencies": { "axios": "^0.20.0", "esm": "^3.2.25" } } ================================================ FILE: misc/playground/cli/spike/cli-example-esm/readme.md ================================================ ### Intro This playground script is to give proof of concept idea to show we can write ES6+ syntax in JS files and run with Node. This script has: - Import statement - Async/Await syntax instead of a regular promise. ### Instructions To start `npm start` or `yarn start` Package.json has a start script that's defined as: `node -r esm index.js` For more options on esm, read here: https://www.npmjs.com/package/esm#options ================================================ FILE: misc/playground/cli/spike/json-to-pdf-cli/Readme.md ================================================ # Theme - Simple nodejs CLI application for convert the JSON files to PDF # Requirements - Node.js 10.x.x # workflow - Convert JSON to HTML - Convert HTML to PDF # npm modules used - # create-html used to convert content to html file - # mustache Mustache is a logic-less template syntax. It can be used for HTML, config files, source code - anything - # html-to-pdf used to convert a html file to pdf ### Installation Install the dependencies: - npm i - npm start ### Options: Options: --version: Show version number -o, --option: twindle command line options, choices ['pdf', 'epub', 'mobi', 'md'] -f, --file path: file path of the json that is to be converted -h, --help: Show help # Usage `node script -f -o ` # Example: `node script -f ./twit_thread.json -o pdf` PDF Succesfully saved in F:\Projects\JS\Twindle\fetch-json-data\output.pdf ================================================ FILE: misc/playground/cli/spike/json-to-pdf-cli/output.css ================================================ #title { text-align: center; } ul li { list-style: none; } .tweetContainer { display: flex; flex-direction: column; margin-bottom: 30px; border-style: solid; padding: 20px; } .tweetContainer * { margin: 0; padding: 0; } .tweetContainer .header { display: flex; flex-direction: row; align-items: center; margin-bottom: 10px; } .tweetContainer .header img { width: 75px; height: 75px; border-radius: 50%; margin-right: 10px; } .tweetContainer .header > div { display: flex; flex-direction: column; align-items: flex-start; justify-content: center; } .tweetContainer .header > div p { font-size: 14px; } .tweetContainer .header > div span { font-style: italic; color: rgb(45, 45, 45); } ================================================ FILE: misc/playground/cli/spike/json-to-pdf-cli/output.html ================================================ Twindle

Twindle

  • Pranav

    Pranav - @Pranav

    How to Get Rich (without getting lucky) in the world:

  • naval

    Naval - @naval

    Seek wealth, not money or status. Wealth is having assets that earn while you sleep. Money is how we transfer time and wealth. Status is your place in the social hierarchy.

  • naval

    Naval - @naval

    Understand that ethical wealth creation is possible. If you secretly despise wealth, it will elude you.

  • naval

    Naval - @naval

    Ignore people playing status games. They gain status by attacking people playing wealth creation games.

================================================ FILE: misc/playground/cli/spike/json-to-pdf-cli/package.json ================================================ { "name": "fetch-json-data", "version": "1.0.0", "description": "convert json data to pdf", "main": "script.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "PraveenKumar", "license": "ISC", "dependencies": { "create-html": "^4.1.0", "html-to-pdf": "^0.1.11", "jquery": "^3.5.1", "mustache": "^4.0.1", "yargs": "^16.1.0" } } ================================================ FILE: misc/playground/cli/spike/json-to-pdf-cli/script.js ================================================ const Mustache = require("mustache"); const fs = require("fs"); const createHTML = require("create-html"); const htmlToPdf = require("html-to-pdf"); const yargs = require("yargs"); const { resolve } = require("path"); const args = yargs .options({ o: { alias: "option", describe: "twindle command line options\n choices 'pdf', 'epub', 'mobi', 'md'", demandOption: true, }, f: { alias: "file path", describe: "file path of json to be converted to pdf", demandOption: true, }, }) .help() .alias("help", "h") .usage("node script -f -o ").argv; if (args["o"] === "pdf" && fs.existsSync(resolve(args["f"]))) { console.log("JSON file is available in the path " + resolve(args["f"])); main(); } else { console.log("PDF only supported " + args["o"]); } function main() { data = require("./twit_thread.json"); //console.log(data); let tweetData = { tweets: data, }; getHtml(tweetData); } function getHtml(tweetData) { //console.log("TweetData", tweetData); //get external mustache template fs.readFile("tweet_template.mustache", "utf8", function (err, data) { if (err) { console.log(err); return; } //render the View data in the Mustache template let info = Mustache.render(data, tweetData); //create an HTMLContent let htmlContent = createHTML({ title: "Twindle", body: info, css: "output.css", //external css }); getPdf(htmlContent); }); } function getPdf(htmlContent) { //console.log("HTML ",htmlContent); //create html file and write the htmlcontent which we are getting from Mustache template fs.writeFile("output.html", htmlContent, function (err) { if (err) { console.log(err); return; } }); //convert the HTML Content/HTML Page to PDF htmlToPdf.convertHTMLFile("output.html", "output.pdf", function (error) { if (error) { console.log("Error Occured ", error); return; } console.log("PDF Succesfully saved in " + process.cwd() + "\\output.pdf"); }); } ================================================ FILE: misc/playground/cli/spike/json-to-pdf-cli/tweet_template.mustache ================================================

Twindle

    {{!-- uses the twit mock object from mock API --}} {{#tweets}}
  • {{twitterHandle}}

    {{name}} - @{{twitterHandle}}

    {{createdAt}}

    {{tweet}}

  • {{/tweets}}
================================================ FILE: misc/playground/cli/spike/json-to-pdf-cli/twit_thread.json ================================================ [ { "name": "Pranav", "twitterHandle": "Pranav", "image": "https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg", "createAt": "2018-05-31", "tweet": "How to Get Rich (without getting lucky) in the world:" }, { "name": "Naval", "twitterHandle": "naval", "image": "https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg", "createAt": "2018-05-31", "tweet": "Seek wealth, not money or status. Wealth is having assets that earn while you sleep. Money is how we transfer time and wealth. Status is your place in the social hierarchy." }, { "name": "Naval", "twitterHandle": "naval", "image": "https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg", "createAt": "2018-05-31", "tweet": "Understand that ethical wealth creation is possible. If you secretly despise wealth, it will elude you." }, { "name": "Naval", "twitterHandle": "naval", "image": "https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg", "createAt": "2018-05-31", "tweet": "Ignore people playing status games. They gain status by attacking people playing wealth creation games." } ] ================================================ FILE: misc/playground/cli/spike/markdown/index.js ================================================ const markdown = (name , tweet , url , username)=>{ return( '### ' + tweet + '\n'+'![img]('+url+')'+'\n'+name+' | '+username ) } console.log( markdown('naval','How to Get Rich (without getting lucky)','https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg','@naval') ) ================================================ FILE: misc/playground/cli/spike/pdf-from-html-cli/README.md ================================================ # Creating PDFs from HTML using Puppeteer ## This simple module creates pdf documents using tweet threads ### To Run ```shell yarn start ``` outputs `Twindle.pdf` ### How it works - First, handlebars module creates the html with the given tweets - Then, we convert and save the html file as pdf document using puppeteer. ### Example documents And example pdf document and the static version of the handlebar template can be found in `examples` ================================================ FILE: misc/playground/cli/spike/pdf-from-html-cli/create-pdf.js ================================================ const puppeteer = require("puppeteer"); const fs = require("fs"); // Creates a pdf document from htmlContent and saves it to outputPath async function createPdf(outputPath, htmlContent) { // launchs a puppeteer browser instance and opens a new page const browser = await puppeteer.launch(); const page = await browser.newPage(); // sets the html of the page to htmlContent argument await page.setContent(htmlContent); // Prints the html page to pdf document and saves it to given outputPath await page.emulateMediaType("print"); await page.pdf({ path: outputPath, format: "A4" }); // Closing the puppeteer browser instance await browser.close(); } module.exports = createPdf; ================================================ FILE: misc/playground/cli/spike/pdf-from-html-cli/examples/Twindle.html ================================================

Twindle Thread

  • naval

    Naval - @naval

    2018-05-31

    How to Get Rich (without getting lucky):

  • naval

    Naval - @naval

    2018-05-31

    How to Get Rich (without getting lucky):

  • naval

    Naval - @naval

    2018-05-31

    How to Get Rich (without getting lucky):

================================================ FILE: misc/playground/cli/spike/pdf-from-html-cli/index.js ================================================ const renderTemplate = require("./render-template"); const createPdf = require("./create-pdf"); // const fs = require("fs"); const mockData = require("../../mock/twit-thread.json"); async function main() { // creates the html content const htmlContent = renderTemplate({ thread: mockData }, "Thread"); // creates the pdf from html and saves it to Twindle.pdf await createPdf("Twindle.pdf", htmlContent); // example line for saving the html version // fs.writeFileSync("Twindle.html", htmlContent); } main(); ================================================ FILE: misc/playground/cli/spike/pdf-from-html-cli/package.json ================================================ { "name": "pdf-from-html-cli", "version": "1.0.0", "description": "Creates pdf from html using puppeteer and handlebars template", "main": "index.js", "author": "Tolga Erdönmez", "license": "MIT", "scripts": { "start": "node ." }, "dependencies": { "handlebars": "^4.7.6", "puppeteer": "^5.3.1" } } ================================================ FILE: misc/playground/cli/spike/pdf-from-html-cli/render-template.js ================================================ const hbs = require("handlebars"); const fs = require("fs"); const path = require("path"); // renders the html template with the given data and returns the html string function renderTemplate(data, templateName) { const html = fs.readFileSync(path.join(__dirname, `templates/${templateName}.hbs`), { encoding: "utf-8", }); // creates the Handlebars template object const template = hbs.compile(html); // renders the html template with the given data const rendered = template(data); return rendered; } module.exports = renderTemplate; ================================================ FILE: misc/playground/cli/spike/pdf-from-html-cli/templates/Thread.hbs ================================================

Twindle Thread

    {{!-- uses the twit mock object from mock API --}} {{#each thread}}
  • {{twitterHandle}}

    {{name}} - @{{twitterHandle}}

    {{createdAt}}

    {{tweet}}

  • {{/each}}
================================================ FILE: misc/playground/cli/spike/pdf-from-json/Readme.md ================================================ # How to run To run this file, clone or download this folder. In command line, after navigating to this folder, run: `npm i` and then `node index.js` ================================================ FILE: misc/playground/cli/spike/pdf-from-json/index.js ================================================ // can import this from json const data = [ { name: 'Naval', twitterHandle: 'naval', image: 'https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg', createAt: '2018-05-31', tweet: 'How to Get Rich (without getting lucky):' } ]; // setting available fonts const fonts = { Courier: { normal: 'Courier', bold: 'Courier-Bold', italics: 'Courier-Oblique', bolditalics: 'Courier-BoldOblique' }, Helvetica: { normal: 'Helvetica', bold: 'Helvetica-Bold', italics: 'Helvetica-Oblique', bolditalics: 'Helvetica-BoldOblique' }, Times: { normal: 'Times-Roman', bold: 'Times-Bold', italics: 'Times-Italic', bolditalics: 'Times-BoldItalic' }, Symbol: { normal: 'Symbol' }, ZapfDingbats: { normal: 'ZapfDingbats' } }; const PdfPrinter = require('pdfmake'); const printer = new PdfPrinter(fonts); const fs = require('fs'); // document const docDefinition = { content: [ { columns: [{ text: 'Name: ', bold: true }, data[0].name] }, { columns: [ { text: 'Twitter Handle: ', bold: true }, `@${data[0].twitterHandle}` ] }, { columns: [{ text: 'Tweet: ', bold: true }, data[0].tweet] } ], image: data[0].image, defaultStyle: { font: 'Helvetica' } }; const pdfDoc = printer.createPdfKitDocument(docDefinition); pdfDoc.pipe(fs.createWriteStream('./tweet.pdf')); pdfDoc.end(); // console.log(data); ================================================ FILE: misc/playground/cli/spike/pdf-from-json/package.json ================================================ { "name": "pdf", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "fs": "0.0.1-security", "jspdf": "^2.1.1", "pdfmake": "^0.1.68" } } ================================================ FILE: misc/playground/cli/spike/phase2-server/api/index.js ================================================ const { default: Axios } = require("axios"); class API { static async getTwitterThread(req, res) { try { // Obtain variables injected into request alongside the request body. These injected variables are made available by the custom Twitter middleware. const { twitterUrl, twitterApiKey, opts, body } = req; const response = await Axios.get(twitterUrl + "/2/tweets/" + body.id, { headers: { ...opts.headers, "Authorization": `Bearer ${twitterApiKey}` } }); res.status(200).json({ statusCode: 200, response: response.data.data }); } catch (error) { // console.log(error); res.status(500).json({ statusCode: 500, response: error.message }); } } } module.exports.API = API; ================================================ FILE: misc/playground/cli/spike/phase2-server/config/index.js ================================================ const express = require("express"); const { loggingMiddleware, twitterMiddleware } = require("../middlewares"); const { pages, api } = require("../router"); module.exports = (app) => { // Use middlewares app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(loggingMiddleware); app.use(twitterMiddleware); app.use("/pages", pages); app.use("/api", api); return app; }; ================================================ FILE: misc/playground/cli/spike/phase2-server/environment.js ================================================ const Env = require("dotenv"); Env.config(); // Inject the Twitter api endpoint from the environment module.exports.TWITTER_API_URL = process.env.TWITTER_API_URL; // Inject Twitter api key or token from the environment module.exports.TWITTER_API_KEY = process.env.TWITTER_API_KEY; ================================================ FILE: misc/playground/cli/spike/phase2-server/index.js ================================================ const express = require("express") let app = express(); const log = require("debug")("app"); const config = require("./config"); const port = parseInt(process.env.PORT || "5000"); app = config(app); app.listen(port, () => log(`Express server is running on port: ${port}`)); ================================================ FILE: misc/playground/cli/spike/phase2-server/middlewares/index.js ================================================ module.exports.twitterMiddleware = require("./twitter").http; module.exports.loggingMiddleware = require("./request-logger").logger; ================================================ FILE: misc/playground/cli/spike/phase2-server/middlewares/request-logger.js ================================================ const log = require("debug")("requests"); module.exports.logger = (req, res, next) => { // Log request details and response code res.on("finish", () => { log(`${req.method}: ${req.path} ====== ${res.statusCode}`); }); next(); }; ================================================ FILE: misc/playground/cli/spike/phase2-server/middlewares/twitter.js ================================================ const { TWITTER_API_URL, TWITTER_API_KEY } = require("../environment"); module.exports.http = (req, res, next) => { try { // Inject the Twitter api url into every request req.twitterUrl = TWITTER_API_URL; // Inject the Twitter api key into every request req.twitterApiKey = TWITTER_API_KEY; // console.log(TWITTER_API_URL); // Inject options into every request. These options would be made available as configuration parameters to axios req.opts = { headers: { "Content-Type": "application/json" } }; // Pass control to the next function next(); } catch (error) { res.status(500).json({ statusCode: 500, response: error.message }); } }; ================================================ FILE: misc/playground/cli/spike/phase2-server/package.json ================================================ { "name": "server", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "cross-env DEBUG=app,requests node index.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "axios": "^0.20.0", "cross-env": "^7.0.2", "debug": "^4.2.0", "dotenv": "^8.2.0", "express": "^4.17.1" } } ================================================ FILE: misc/playground/cli/spike/phase2-server/router/api/index.js ================================================ const { Router } = require("express"); const { API } = require("../../api"); const router = Router(); router.post("/convert", API.getTwitterThread); module.exports.apiRouter = router; ================================================ FILE: misc/playground/cli/spike/phase2-server/router/index.js ================================================ module.exports.api = require("./api").apiRouter; module.exports.pages = require("./pages").pagesRouter; ================================================ FILE: misc/playground/cli/spike/phase2-server/router/pages/index.js ================================================ const { Router } = require("express"); const router = Router(); router.get("/*", (req, res) => { res.send({ message: "This is the homepage" }); }); module.exports.pagesRouter = router; ================================================ FILE: misc/playground/cli/spike/simple-pdf-to-json/README.md ================================================ # What this does ? - convert JSON files to pdf # Requirements - a Browser on your PC or try it with any online IDEs within the browser - ensure that all thes files are in same folder when you run the html file on pc # Dependency - html+css+javscript no other dependency # why NO Dependency ? - you are free to use one! but why use it when you can do that job without it # way to do it - paste the code and you are good to go! - There is a button provided to print and you can select the format in which you want to save the print like pdf ================================================ FILE: misc/playground/cli/spike/simple-pdf-to-json/json2pdf.html ================================================ TWEETS IN PDF FORMAT
NameTwitterHandleimagecreatedAttweet
================================================ FILE: misc/playground/cli/spike/simple-pdf-to-json/json2pdf.js ================================================ //data const data =[ { name: 'Naval', twitterHandle: 'naval', image: 'https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg', createAt: '2018-05-31', tweet: 'How to Get Rich (without getting lucky):' }, { name: 'Naval', twitterHandle: 'naval', image: 'https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg', createAt: '2018-05-31', tweet: 'How to Get Rich 1(without getting lucky):' } ]; function displayTable(tweets){ // accessing table element const table = document.getElementById('tweetsTable'); //loop over the tweets tweets.forEach(function (currentTweet) { const row =document.createElement('tr'); //creating row const k =['name','twitterHandle','image','createAt','tweet']; //key(k) of tweets //loop over them and add them to cells and later add cells to rows for(let j=0;j div { display: flex; flex-direction: column; align-items: flex-start; justify-content: center; } .tweetContainer .header > div p { font-size: 14px; } .tweetContainer .header > div span { font-style: italic; color: rgb(45, 45, 45); } ================================================ FILE: misc/playground/cli/spike/simple-pdf-to-json/simple-pdf-to-json/newjson2pdf.html ================================================

Your Tweet Thread

    ================================================ FILE: misc/playground/cli/spike/simple-pdf-to-json/simple-pdf-to-json/newjson2pdf.js ================================================ //'{"name": "Naval","twitterHandle": "naval", "city":"New York","image":"abs.jpg","tweet": "Tweet1","createAt": "2018-05-31"}') //parse json before using it as data var data = [ { name: "Adam ", twitterHandle: "@horse", createdAt: "2018-05-31", tweet: "How to Get Rich (without getting lucky) 1", image: "http://placekitten.com/g/200/300", }, { name: "Kate ", twitterHandle: "@cat", createdAt: "2018-05-31", tweet: "How to Get Rich (without getting lucky) 2", image: "http://placekitten.com/g/200/300", }, { name: "Jenny ", twitterHandle: "@squirrel", createdAt: "2018-05-31", tweet: "How to Get Rich (without getting lucky) 3", image: "http://placekitten.com/g/200/300", }, ]; function display(_tweet) { let myUl = document.querySelector("ul"); data.forEach(function (obj) { //This is just creating the skeleton const myList = document.createElement("li"); //first division creation const div1 = document.createElement("div"); div1.className = "tweetContainer"; myList.appendChild(div1); //second divison creation const div2 = document.createElement("div"); div2.className = "header"; div1.appendChild(div2); let p1 = document.createElement("p"); //sibling of div2 p1.textContent = obj.tweet; div1.insertBefore(p1, div1.firstElementChild.nextSibling); //insertafter() property is not there //sibling of div2 attached let image = document.createElement("img"); image.src = obj.image; div2.appendChild(image); const div3 = document.createElement("div"); div2.insertBefore(div3, div2.firstElementChild.nextSibling); const h3 = document.createElement("h3"); div3.appendChild(h3); let p2 = document.createElement("p"); div3.insertBefore(p2, div3.firstElementChild.nextSibling); let span1 = document.createElement("span"); span1.textContent = obj.twitterHandle; h3.textContent = obj.name; h3.appendChild(span1); let span2 = document.createElement("span"); span2.textContent = obj.createdAt; p2.appendChild(span2); myUl.appendChild(myList); }); } display(data); //printing function let button = document.querySelector("#myButton"); button.addEventListener("click", function () { document.querySelector("ul"); window.print(); }); ================================================ FILE: misc/playground/cli/spike/simple-pdf-to-json/simple-pdf-to-json/old codes/oldjson2pdf.html ================================================ TWEETS IN PDF FORMAT
    NameTwitterHandleimagecreatedAttweet
    ================================================ FILE: misc/playground/cli/spike/simple-pdf-to-json/simple-pdf-to-json/old codes/oldjson2pdf.js ================================================ //data const data =[ { name: 'Naval', twitterHandle: 'naval', image: 'https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg', createAt: '2018-05-31', tweet: 'How to Get Rich (without getting lucky):' }, { name: 'Naval', twitterHandle: 'naval', image: 'https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg', createAt: '2018-05-31', tweet: 'How to Get Rich 1(without getting lucky):' } ]; function displayTable(tweets){ // accessing table element const table = document.getElementById('tweetsTable'); //loop over the tweets tweets.forEach(function (currentTweet) { const row =document.createElement('tr'); //creating row const k =['name','twitterHandle','image','createAt','tweet']; //key(k) of tweets //loop over them and add them to cells and later add cells to rows for(let j=0;j -o ` # Example: `node twindle --thread-id 1279940000004973111 -o pdf` generates a pdf document from the text ================================================ FILE: misc/playground/cli/spike/twindle-cli-node/package.json ================================================ { "name": "twindle_cli_node", "version": "1.0.0", "description": "", "main": "twindle.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "yargs": "^16.1.0" } } ================================================ FILE: misc/playground/cli/spike/twindle-cli-node/twindle.js ================================================ //yargs is a npm module that makes passing command line arguments easy //require the module in your package to use it const yargs = require("yargs"); //create a variable that'll contain the yargs object and pass in its methods that you'll need const args = yargs.options({ "o": { alias: "option", describe: "twindle command line options\n choices 'pdf', 'epub', 'mobi', 'md'", demandOption: true }, "t": { alias: "thread-id", describe: "thread id of twitter thread that is to be converted", demandOption: true } }).help().alias("help", "h") .usage("node twindle --thread-id -o ").argv; /* --YARGS METHODS-- -options() creates the command line options for the application -help() parameter logs a usage string and the options to console and exits the app, without parameters --help option will be used -alias() sets an alternate name for an option -usage() creates usage string that'll be logged when --help is called */ //if/elif block to check what options were passed and log a message if (args.option === "pdf") { console.log("pdf generated from thread " + args["t"]); } else if (args.option === "epub") { console.log("epub document generated from thread " + args["t"]); } else if (args.option === "md") { console.log("markdown document generated from thread " + args["t"]); } else if (args.option === "mobi") { console.log("mobi document generated from thread " + args["t"]); } else{ console.error("incorrect choise") } ================================================ FILE: misc/playground/cli/spike/twindle-hello-world-pdf/package.json ================================================ { "name": "twindle_hello_world_pdf", "version": "1.0.0", "description": "", "main": "pdf.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "pdfjs": "^2.4.1" } } ================================================ FILE: misc/playground/cli/spike/twindle-hello-world-pdf/pdf.js ================================================ //pdfjs is a pdf generation npm module that is easy to use and has alot of features const pdf = require('pdfjs') //fs is the default node js filesystem module const fs = require('fs') //create a new pdf document object and pass in some options const doc = new pdf.Document({ font: require('pdfjs/font/Helvetica'), padding: 10, fontSize: 20, properties: { title: "Hello World", author: "Michaelcosj@Twindle" } }) //pipe means to pass information from one process to another //here the newly created write stream is passed to the doc object doc.pipe(fs.createWriteStream('helloworld.pdf')); //pass a text to the doc object, the link property makes the text link to a url doc.text("Hello World!", {link: "https://github.com/twindle-co/twindle"}); //finish writing the pdf document doc.end() ================================================ FILE: misc/playground/cli/spike/twindle-thread/Readme.md ================================================ node twindle thread-id -o pdf aaa ================================================ FILE: misc/playground/cli/spike/twindle-thread/script.js ================================================ main(); function main(){ var myData; myData=require("./twit_thread.json"); console.log("Tweets",myData); } ================================================ FILE: misc/playground/cli/spike/twindle-thread/twit_thread.json ================================================ [ { "name": "Naval", "twitterHandle": "naval", "image": "https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg", "createdAt": "2018-05-31", "tweet": "How to Get Rich (without getting lucky):" }, { "name": "Naval", "twitterHandle": "naval", "image": "https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg", "createdAt": "2018-05-31", "tweet": "How to Get Rich 1(without getting lucky):" } ] ================================================ FILE: misc/playground/cli/spike/twitter-api/README.md ================================================ Making REST Calls to Twitter Endpoints - output being written to the console right now Code Structure: playground -> cli -> a new folder called twitter-api has been included This is a NodeJS module but except for node-fetch no other module has been used There are three scripts: > script-version2-conversation.js: Contains hard-coded Twitter Endpoints for version 2. Process - using a sample Tweet URL, extract the tweet id and twitter handle name, make a Tweet lookup call to get the first tweet's details and particularly the conversationId. If the first tweet is older than 7 days I am logging an error - then make a second call to get the tweets on the conversation using the conversationId but also made by the same user(this will exclude replies) - from the response, find the direct replies one by one > script-version1-usertimeline.js: Contains hard coded Twitter Endpoints for getting the user's Twitter timeline. Process - using a sample Tweet URL, extract the tweet id and twitter handle name, make a Tweet lookup call to get the first tweet's details. If the first tweet is older than 7 days I am logging an error. Since there is no way to track a particular conversation's thread(no conversationId), we hit the user timeline endpoint and ask for all tweets made by the user since the first tweet. Now from the response, we filter with a field called in_reply_to_id_str pointing to the parent tweet. Thus we construct the chain of responses. Caveat: Only 200 max tweets can be returned and so all replies are not guaranteed - particularly if the user is super active. > script-version1-searchendpoint.js: Contains hard coded Twitter Search Endpoints. Process - using a sample Tweet URL, extract the tweet id and twitter handle name, make a Tweet lookup call to get the first tweet's details. If the first tweet is older than 7 days I am logging an error. Since there is no way to track a particular conversation's thread(no conversationId), we hit the search endpoint by constructing a standard query using the operators from:twitterHandle+to:twitterHandle - this will only return replies made by the user to himself - from the response we filter with a field called in_reply_to_id_str pointing to the parent tweet. Thus we construct the chain of responses. Caveat: Only 200 max tweets can be returned and so all replies are not guaranteed - particularly if the user is super active. Standard responses from the Twitter endpoints have also been saved under the folder responses - includes all tweet fields - so we can use whatever field is needed in the output file. Things to do to test the scripts: > Please remove at the top of the script files and replace with the Auth Header Token provided by the twitter API > I have used a sample Tweet that was made at the time of testing the script - please pick a recent tweet and replace SAMPLE_TWEET with that tweet. > The function getTweets(SAMPLE_TWEET) is being called - and that is the starting point of execution I am not an expert in Javascript coding - so any issues including coding styles and standards can be raised on this PR. Thank @UnevenCoder for his inputs in writing this. ## Attach Screenshot: ![screenshot](https://user-images.githubusercontent.com/64691316/97374048-62d69080-18dd-11eb-9884-194bd9c02d9a.png) > Note 2 code reviewer approval needed. Approach in twitter group & discord channel. ================================================ FILE: misc/playground/cli/spike/twitter-api/package.json ================================================ { "name": "twitter-api", "version": "1.0.0", "description": "", "main": "script.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "node-fetch": "^2.6.1" } } ================================================ FILE: misc/playground/cli/spike/twitter-api/responses/response-version1-searchendpoint.json ================================================ { "statuses":[ { "created_at":"Tue Oct 27 13:51:42 +0000 2020", "id":1321087179939057665, "id_str":"1321087179939057665", "full_text":"I hope people understand how serious a threat to democracy this is: Kavanaugh is now \u201cswing justice\u201d on 6-3 court & he\u2019s spreading same disinformation about counting mail ballots as Trump\n\nWe need to vote in record numbers to overcome rigged Supreme Court https:\/\/t.co\/Elnsnvqr4u", "truncated":false, "display_text_range":[ 0, 283 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ { "url":"https:\/\/t.co\/Elnsnvqr4u", "expanded_url":"https:\/\/www.motherjones.com\/2020-elections\/2020\/10\/brett-kavanaugh-lays-out-a-plan-to-help-trump-steal-the-election\/", "display_url":"motherjones.com\/2020-elections\u2026", "indices":[ 260, 283 ] } ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1320899108606017539, "in_reply_to_status_id_str":"1320899108606017539", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":126, "favorite_count":313, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Tue Oct 27 12:19:01 +0000 2020", "id":1321063854504353794, "id_str":"1321063854504353794", "full_text":"Given persistent USPS delays (it takes an average of 10 days for letter to be delivered in Wisconsin), I would urge voters to drop off their mail ballots or vote in person rather than risk mail ballot not being counted because USPS didn\u2019t deliver by Election Day", "truncated":false, "display_text_range":[ 0, 262 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"http:\/\/twitter.com\/download\/iphone\" rel=\"nofollow\"\u003eTwitter for iPhone\u003c\/a\u003e", "in_reply_to_status_id":1321060511245606914, "in_reply_to_status_id_str":"1321060511245606914", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":752, "favorite_count":1549, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Tue Oct 27 01:36:52 +0000 2020", "id":1320902249846083586, "id_str":"1320902249846083586", "full_text":"If you\u2019re feeling despair tonight (and I know I am), remember massive turnout can overcome massive suppression \n\nWe don\u2019t have to accept an illegitimate system, we can vote to change it", "truncated":false, "display_text_range":[ 0, 185 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"http:\/\/twitter.com\/download\/iphone\" rel=\"nofollow\"\u003eTwitter for iPhone\u003c\/a\u003e", "in_reply_to_status_id":1320783852219105287, "in_reply_to_status_id_str":"1320783852219105287", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":1267, "favorite_count":5716, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Tue Oct 27 01:24:23 +0000 2020", "id":1320899108606017539, "id_str":"1320899108606017539", "full_text":"Kagan dissent in Wisconsin case: \"the Court\u2019s decision will disenfranchise large numbers of responsible voters in the midst of hazardous pandemic conditions\" https:\/\/t.co\/Q4pEXmDN96", "truncated":false, "display_text_range":[ 0, 157 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ], "media":[ { "id":1320898952183619584, "id_str":"1320898952183619584", "indices":[ 158, 181 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElTGmT0XIAAAaiH.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElTGmT0XIAAAaiH.png", "url":"https:\/\/t.co\/Q4pEXmDN96", "display_url":"pic.twitter.com\/Q4pEXmDN96", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320899108606017539\/photo\/1", "type":"photo", "sizes":{ "large":{ "w":834, "h":476, "resize":"fit" }, "medium":{ "w":834, "h":476, "resize":"fit" }, "small":{ "w":680, "h":388, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "extended_entities":{ "media":[ { "id":1320898952183619584, "id_str":"1320898952183619584", "indices":[ 158, 181 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElTGmT0XIAAAaiH.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElTGmT0XIAAAaiH.png", "url":"https:\/\/t.co\/Q4pEXmDN96", "display_url":"pic.twitter.com\/Q4pEXmDN96", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320899108606017539\/photo\/1", "type":"photo", "sizes":{ "large":{ "w":834, "h":476, "resize":"fit" }, "medium":{ "w":834, "h":476, "resize":"fit" }, "small":{ "w":680, "h":388, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1320883524954660867, "in_reply_to_status_id_str":"1320883524954660867", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":539, "favorite_count":2148, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Tue Oct 27 00:22:27 +0000 2020", "id":1320883524954660867, "id_str":"1320883524954660867", "full_text":"Insane rhetoric from Kavanaugh decrying \"chaos & suspicions of impropriety that can ensue if thousands of absentee ballots flow in after election day and potentially flip the results of an election\"\n\nThis comes on some night Trump tweets winner of election must be announced Nov 3 https:\/\/t.co\/Y9iZcBGOGy", "truncated":false, "display_text_range":[ 0, 284 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ], "media":[ { "id":1320882150552571905, "id_str":"1320882150552571905", "indices":[ 285, 308 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElS3UU3XEAEDo-9.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElS3UU3XEAEDo-9.png", "url":"https:\/\/t.co\/Y9iZcBGOGy", "display_url":"pic.twitter.com\/Y9iZcBGOGy", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320883524954660867\/photo\/1", "type":"photo", "sizes":{ "large":{ "w":415, "h":410, "resize":"fit" }, "medium":{ "w":415, "h":410, "resize":"fit" }, "small":{ "w":415, "h":410, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "extended_entities":{ "media":[ { "id":1320882150552571905, "id_str":"1320882150552571905", "indices":[ 285, 308 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElS3UU3XEAEDo-9.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElS3UU3XEAEDo-9.png", "url":"https:\/\/t.co\/Y9iZcBGOGy", "display_url":"pic.twitter.com\/Y9iZcBGOGy", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320883524954660867\/photo\/1", "type":"photo", "sizes":{ "large":{ "w":415, "h":410, "resize":"fit" }, "medium":{ "w":415, "h":410, "resize":"fit" }, "small":{ "w":415, "h":410, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1320877150770241541, "in_reply_to_status_id_str":"1320877150770241541", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":695, "favorite_count":1855, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Mon Oct 26 23:57:08 +0000 2020", "id":1320877150770241541, "id_str":"1320877150770241541", "full_text":"Kavanaugh cites Bush v. Gore to justify making it harder to vote in Wisconsin\n\nKavanaugh, Roberts & Barrett all served on George W. Bush legal team in Florida 2000 recount & worked to make sure only GOP votes counted https:\/\/t.co\/NhNessbwoB", "truncated":false, "display_text_range":[ 0, 224 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ], "media":[ { "id":1320876915889262592, "id_str":"1320876915889262592", "indices":[ 225, 248 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElSyjoOX0AAr1jk.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElSyjoOX0AAr1jk.png", "url":"https:\/\/t.co\/NhNessbwoB", "display_url":"pic.twitter.com\/NhNessbwoB", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320877150770241541\/photo\/1", "type":"photo", "sizes":{ "large":{ "w":412, "h":448, "resize":"fit" }, "medium":{ "w":412, "h":448, "resize":"fit" }, "small":{ "w":412, "h":448, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "extended_entities":{ "media":[ { "id":1320876915889262592, "id_str":"1320876915889262592", "indices":[ 225, 248 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElSyjoOX0AAr1jk.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElSyjoOX0AAr1jk.png", "url":"https:\/\/t.co\/NhNessbwoB", "display_url":"pic.twitter.com\/NhNessbwoB", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320877150770241541\/photo\/1", "type":"photo", "sizes":{ "large":{ "w":412, "h":448, "resize":"fit" }, "medium":{ "w":412, "h":448, "resize":"fit" }, "small":{ "w":412, "h":448, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1320872258085310466, "in_reply_to_status_id_str":"1320872258085310466", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":2198, "favorite_count":3993, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Mon Oct 26 19:41:04 +0000 2020", "id":1320812709613588480, "id_str":"1320812709613588480", "full_text":"\"Anger over perceived voter suppression tactics is fueling Black voters eagerness to cast early ballots in Georgia\"\n\n2.7 million Georgia voters have cast a ballot already \u2014 a nearly 110 percent increase from 2016 https:\/\/t.co\/rdjblfw3XV", "truncated":false, "display_text_range":[ 0, 236 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ { "url":"https:\/\/t.co\/rdjblfw3XV", "expanded_url":"https:\/\/www.politico.com\/news\/2020\/10\/26\/georgia-voter-suppression-black-turnout-432405?nname=playbook&nid=0000014f-1646-d88f-a1cf-5f46b7bd0000&nrid=0000014e-f109-dd93-ad7f-f90d0def0000&nlid=63031", "display_url":"politico.com\/news\/2020\/10\/2\u2026", "indices":[ 213, 236 ] } ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1320058134753402880, "in_reply_to_status_id_str":"1320058134753402880", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":40, "favorite_count":137, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Mon Oct 26 17:46:24 +0000 2020", "id":1320783852219105287, "id_str":"1320783852219105287", "full_text":"While he steals another Supreme Court seat for Trump, Mitch McConnell has been blocking coronavirus relief legislation for 164 days, legislation to restore Voting Rights Act for 324 days & legislation to prevent foreign election interference for 368 days", "truncated":false, "display_text_range":[ 0, 258 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1320727906600030218, "in_reply_to_status_id_str":"1320727906600030218", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":1517, "favorite_count":3949, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Mon Oct 26 00:41:42 +0000 2020", "id":1320525980411301889, "id_str":"1320525980411301889", "full_text":"While he packs the courts for Trump, Mitch McConnell has been blocking coronavirus relief legislation for 163 days, legislation to restore Voting Rights Act for 323 days & legislation to prevent foreign election interference for 367 days", "truncated":false, "display_text_range":[ 0, 241 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"http:\/\/twitter.com\/download\/iphone\" rel=\"nofollow\"\u003eTwitter for iPhone\u003c\/a\u003e", "in_reply_to_status_id":1320410270225829889, "in_reply_to_status_id_str":"1320410270225829889", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":202, "favorite_count":486, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Sat Oct 24 17:42:39 +0000 2020", "id":1320058134753402880, "id_str":"1320058134753402880", "full_text":".@MrPruneJuice waited 5 hours 7 min to vote on 1st day of early voting in GA but after \"horror stories\" of voter suppression in @staceyabrams race \"I wanted to get my early vote in\" he told me\n\n2.5 million early votes already cast in GA, exceeding total 2016 early voting turnout https:\/\/t.co\/Q87PROZj0t", "truncated":false, "display_text_range":[ 0, 279 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ { "screen_name":"MrPruneJuice", "name":"Matt", "id":104184684, "id_str":"104184684", "indices":[ 1, 14 ] }, { "screen_name":"staceyabrams", "name":"Stacey Abrams", "id":216065430, "id_str":"216065430", "indices":[ 128, 141 ] } ], "urls":[ ], "media":[ { "id":1320057887746592775, "id_str":"1320057887746592775", "indices":[ 280, 303 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElHJp6oWkAc9rMP.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElHJp6oWkAc9rMP.png", "url":"https:\/\/t.co\/Q87PROZj0t", "display_url":"pic.twitter.com\/Q87PROZj0t", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320058134753402880\/photo\/1", "type":"photo", "sizes":{ "small":{ "w":599, "h":439, "resize":"fit" }, "medium":{ "w":599, "h":439, "resize":"fit" }, "large":{ "w":599, "h":439, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "extended_entities":{ "media":[ { "id":1320057887746592775, "id_str":"1320057887746592775", "indices":[ 280, 303 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElHJp6oWkAc9rMP.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElHJp6oWkAc9rMP.png", "url":"https:\/\/t.co\/Q87PROZj0t", "display_url":"pic.twitter.com\/Q87PROZj0t", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320058134753402880\/photo\/1", "type":"photo", "sizes":{ "small":{ "w":599, "h":439, "resize":"fit" }, "medium":{ "w":599, "h":439, "resize":"fit" }, "large":{ "w":599, "h":439, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1319804181457371136, "in_reply_to_status_id_str":"1319804181457371136", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":114, "favorite_count":477, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Sat Oct 24 00:53:32 +0000 2020", "id":1319804181457371136, "id_str":"1319804181457371136", "full_text":"Harris Co clerk @CGHollins deserves lot of credit for making voting easier:\n\n-3x early voting locations\n\n-drive-through voting\n\n-24\/7 voting\n\n-arenas as polling places\n\n\"Voters are responding by saying, \u2018I\u2019ll show you,\u2019 & coming out in record numbers to have their voices heard.\u201d https:\/\/t.co\/KLXPb8wK1E", "truncated":false, "display_text_range":[ 0, 283 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ { "screen_name":"CGHollins", "name":"Chris Hollins", "id":30976233, "id_str":"30976233", "indices":[ 16, 26 ] } ], "urls":[ ], "media":[ { "id":1319804109403361281, "id_str":"1319804109403361281", "indices":[ 284, 307 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElDi2EoWkAE6I3w.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElDi2EoWkAE6I3w.png", "url":"https:\/\/t.co\/KLXPb8wK1E", "display_url":"pic.twitter.com\/KLXPb8wK1E", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1319804181457371136\/photo\/1", "type":"photo", "sizes":{ "medium":{ "w":593, "h":224, "resize":"fit" }, "large":{ "w":593, "h":224, "resize":"fit" }, "small":{ "w":593, "h":224, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "extended_entities":{ "media":[ { "id":1319804109403361281, "id_str":"1319804109403361281", "indices":[ 284, 307 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElDi2EoWkAE6I3w.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElDi2EoWkAE6I3w.png", "url":"https:\/\/t.co\/KLXPb8wK1E", "display_url":"pic.twitter.com\/KLXPb8wK1E", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1319804181457371136\/photo\/1", "type":"photo", "sizes":{ "medium":{ "w":593, "h":224, "resize":"fit" }, "large":{ "w":593, "h":224, "resize":"fit" }, "small":{ "w":593, "h":224, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1319777914947276800, "in_reply_to_status_id_str":"1319777914947276800", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":343, "favorite_count":1491, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Fri Oct 23 23:09:09 +0000 2020", "id":1319777914947276800, "id_str":"1319777914947276800", "full_text":"More than 1 million votes have already been cast in Harris County TX, exceeding 2016 early voting total with a week of early voting left\n\n@LinaHidalgoTX told me Greg Abbott's plan closing mail dropoff sites backfired on GOP\n\n\"It was so transparently about suppression,\u201d she said.", "truncated":false, "display_text_range":[ 0, 279 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ { "screen_name":"LinaHidalgoTX", "name":"Lina Hidalgo", "id":247174365, "id_str":"247174365", "indices":[ 138, 152 ] } ], "urls":[ ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1319763016452395009, "in_reply_to_status_id_str":"1319763016452395009", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":1155, "favorite_count":4393, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Thu Oct 22 01:58:30 +0000 2020", "id":1319095755219607553, "id_str":"1319095755219607553", "full_text":"Blocking legislation to prevent foreign election interference is one of 29 ways GOP making it harder to vote https:\/\/t.co\/duQ3ZM8Ofb", "truncated":false, "display_text_range":[ 0, 132 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ { "url":"https:\/\/t.co\/duQ3ZM8Ofb", "expanded_url":"https:\/\/www.motherjones.com\/politics\/2020\/10\/29-ways-trump-and-the-gop-are-making-it-harder-to-vote\/", "display_url":"motherjones.com\/politics\/2020\/\u2026", "indices":[ 109, 132 ] } ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"http:\/\/twitter.com\/download\/iphone\" rel=\"nofollow\"\u003eTwitter for iPhone\u003c\/a\u003e", "in_reply_to_status_id":1319063702361018376, "in_reply_to_status_id_str":"1319063702361018376", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":170, "favorite_count":404, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Thu Oct 22 00:48:13 +0000 2020", "id":1319078067424399361, "id_str":"1319078067424399361", "full_text":"Sotomayor dissent quotes Howard Porter Jr., a Black man in 70s with asthma & Parkinson\u2019s Disease: \"So many of my [ancestors] even died to vote. And while I don\u2019t mind dying to vote, I think we\u2019re past that time.\"\n\nRoberts Court forcing voters to choose between vote & lives https:\/\/t.co\/NT4lUDzWle", "truncated":false, "display_text_range":[ 0, 281 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ], "media":[ { "id":1319077754390925318, "id_str":"1319077754390925318", "indices":[ 282, 305 ], "media_url":"http:\/\/pbs.twimg.com\/media\/Ek5OOpWXUAYdtvv.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/Ek5OOpWXUAYdtvv.png", "url":"https:\/\/t.co\/NT4lUDzWle", "display_url":"pic.twitter.com\/NT4lUDzWle", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1319078067424399361\/photo\/1", "type":"photo", "sizes":{ "medium":{ "w":414, "h":623, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" }, "small":{ "w":414, "h":623, "resize":"fit" }, "large":{ "w":414, "h":623, "resize":"fit" } } } ] }, "extended_entities":{ "media":[ { "id":1319077754390925318, "id_str":"1319077754390925318", "indices":[ 282, 305 ], "media_url":"http:\/\/pbs.twimg.com\/media\/Ek5OOpWXUAYdtvv.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/Ek5OOpWXUAYdtvv.png", "url":"https:\/\/t.co\/NT4lUDzWle", "display_url":"pic.twitter.com\/NT4lUDzWle", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1319078067424399361\/photo\/1", "type":"photo", "sizes":{ "medium":{ "w":414, "h":623, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" }, "small":{ "w":414, "h":623, "resize":"fit" }, "large":{ "w":414, "h":623, "resize":"fit" } } } ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1319075187581747200, "in_reply_to_status_id_str":"1319075187581747200", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":310, "favorite_count":745, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Wed Oct 21 23:51:08 +0000 2020", "id":1319063702361018376, "id_str":"1319063702361018376", "full_text":"SHIELD Act - requiring campaigns to notify FBI & FEC if contacted by foreign actors - was passed by House October 23, 2019. McConnell has been blocking a vote on it for a year", "truncated":false, "display_text_range":[ 0, 179 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1319061747358142467, "in_reply_to_status_id_str":"1319061747358142467", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":525, "favorite_count":1329, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Tue Oct 20 18:02:49 +0000 2020", "id":1318613659287982081, "id_str":"1318613659287982081", "full_text":"Trump says he wants SCOTUS to \"look at the ballots\"\n\n4 conservative justices voted yesterday to reject mail ballots in PA\n\nGOP rushing to confirm Amy Coney Barrett so she's 5th vote for Trump in post-election dispute\n\nPay attention\n\nhttps:\/\/t.co\/9EA67qvVrn", "truncated":false, "display_text_range":[ 0, 256 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ { "url":"https:\/\/t.co\/9EA67qvVrn", "expanded_url":"https:\/\/www.motherjones.com\/2020-elections\/2020\/10\/supreme-court-hints-at-a-bush-v-gore-redux-with-barrett-breaking-the-tie\/", "display_url":"motherjones.com\/2020-elections\u2026", "indices":[ 233, 256 ] } ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1318336526363856898, "in_reply_to_status_id_str":"1318336526363856898", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":193, "favorite_count":301, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Mon Oct 19 23:41:36 +0000 2020", "id":1318336526363856898, "id_str":"1318336526363856898", "full_text":"The fact that 4 conservative justices would've overruled PA Supreme Court is very bad sign for voting rights & shows why GOP so desperate to confirm Amy Coney Barrett before election. They want to do Bush v Gore on steroids https:\/\/t.co\/E4pKYWwz6z", "truncated":false, "display_text_range":[ 0, 251 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ { "url":"https:\/\/t.co\/E4pKYWwz6z", "expanded_url":"https:\/\/www.motherjones.com\/politics\/2020\/10\/trump-wants-a-repeat-of-bush-v-gore-amy-coney-barrett-might-make-it-happen\/", "display_url":"motherjones.com\/politics\/2020\/\u2026", "indices":[ 228, 251 ] } ] }, "metadata":{ "iso_language_code":"en", "result_type":"recent" }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1318330577871904769, "in_reply_to_status_id_str":"1318330577871904769", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159657, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":670, "favorite_count":1556, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" } ], "search_metadata":{ "completed_in":0.036, "max_id":1321087179939057665, "max_id_str":"1321087179939057665", "next_results":"?max_id=1318336526363856897&q=from%3AAriBerman%20to%3AAriBerman&count=100&include_entities=1", "query":"from%3AAriBerman+to%3AAriBerman", "refresh_url":"?since_id=1321087179939057665&q=from%3AAriBerman%20to%3AAriBerman&include_entities=1", "count":100, "since_id":0, "since_id_str":"0" } } ================================================ FILE: misc/playground/cli/spike/twitter-api/responses/response-version1-user-timeline.json ================================================ [ { "created_at":"Tue Oct 27 15:03:12 +0000 2020", "id":1321105172400087040, "id_str":"1321105172400087040", "full_text":"GOP: we shouldn't count votes that are mailed too close to Election Day, but we should absolutely confirm a Supreme Court justice 8 days before Nov 3 when 65 million already voted https:\/\/t.co\/Elnsnvqr4u", "truncated":false, "display_text_range":[ 0, 203 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ { "url":"https:\/\/t.co\/Elnsnvqr4u", "expanded_url":"https:\/\/www.motherjones.com\/2020-elections\/2020\/10\/brett-kavanaugh-lays-out-a-plan-to-help-trump-steal-the-election\/", "display_url":"motherjones.com\/2020-elections\u2026", "indices":[ 180, 203 ] } ] }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":null, "in_reply_to_status_id_str":null, "in_reply_to_user_id":null, "in_reply_to_user_id_str":null, "in_reply_to_screen_name":null, "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":106, "favorite_count":304, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Tue Oct 27 14:44:30 +0000 2020", "id":1321100463660507137, "id_str":"1321100463660507137", "full_text":"Mitch McConnell rushed through Amy Coney Barrett\u2019s nomination in 30 days but he\u2019s been blocking coronavirus relief legislation for 165 days & counting https:\/\/t.co\/PYVrdpPaky", "truncated":false, "display_text_range":[ 0, 154 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ { "url":"https:\/\/t.co\/PYVrdpPaky", "expanded_url":"https:\/\/twitter.com\/jesselehrich\/status\/1320901441272373250", "display_url":"twitter.com\/jesselehrich\/s\u2026", "indices":[ 155, 178 ] } ] }, "source":"\u003ca href=\"http:\/\/twitter.com\/download\/iphone\" rel=\"nofollow\"\u003eTwitter for iPhone\u003c\/a\u003e", "in_reply_to_status_id":null, "in_reply_to_status_id_str":null, "in_reply_to_user_id":null, "in_reply_to_user_id_str":null, "in_reply_to_screen_name":null, "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":true, "quoted_status_id":1320901441272373250, "quoted_status_id_str":"1320901441272373250", "quoted_status_permalink":{ "url":"https:\/\/t.co\/PYVrdpPaky", "expanded":"https:\/\/twitter.com\/jesselehrich\/status\/1320901441272373250", "display":"twitter.com\/jesselehrich\/s\u2026" }, "quoted_status":{ "created_at":"Tue Oct 27 01:33:39 +0000 2020", "id":1320901441272373250, "id_str":"1320901441272373250", "full_text":"McConnell adjourned the Senate until 11\/9 with no COVID relief.", "truncated":false, "display_text_range":[ 0, 63 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "source":"\u003ca href=\"https:\/\/about.twitter.com\/products\/tweetdeck\" rel=\"nofollow\"\u003eTweetDeck\u003c\/a\u003e", "in_reply_to_status_id":null, "in_reply_to_status_id_str":null, "in_reply_to_user_id":null, "in_reply_to_user_id_str":null, "in_reply_to_screen_name":null, "user":{ "id":26186655, "id_str":"26186655", "name":"Jesse Lehrich", "screen_name":"JesseLehrich", "location":"Chicago, by way of Boston", "description":"co-founder of @accountabletech \u2013 trying to make the internet less bad & more truthy. former foreign policy spokesman for @HillaryClinton.", "url":null, "entities":{ "description":{ "urls":[ ] } }, "protected":false, "followers_count":56505, "friends_count":913, "listed_count":798, "created_at":"Tue Mar 24 05:45:39 +0000 2009", "favourites_count":14158, "utc_offset":null, "time_zone":null, "geo_enabled":true, "verified":true, "statuses_count":32819, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0099B9", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme4\/bg.gif", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme4\/bg.gif", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1040437265237852160\/h8PVbmgq_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1040437265237852160\/h8PVbmgq_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/26186655\/1536894883", "profile_link_color":"0099B9", "profile_sidebar_border_color":"5ED4DC", "profile_sidebar_fill_color":"95E8EC", "profile_text_color":"3C3940", "profile_use_background_image":true, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":12053, "favorite_count":25390, "favorited":false, "retweeted":false, "lang":"en" }, "retweet_count":133, "favorite_count":300, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Tue Oct 27 13:51:42 +0000 2020", "id":1321087179939057665, "id_str":"1321087179939057665", "full_text":"I hope people understand how serious a threat to democracy this is: Kavanaugh is now \u201cswing justice\u201d on 6-3 court & he\u2019s spreading same disinformation about counting mail ballots as Trump\n\nWe need to vote in record numbers to overcome rigged Supreme Court https:\/\/t.co\/Elnsnvqr4u", "truncated":false, "display_text_range":[ 0, 283 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ { "url":"https:\/\/t.co\/Elnsnvqr4u", "expanded_url":"https:\/\/www.motherjones.com\/2020-elections\/2020\/10\/brett-kavanaugh-lays-out-a-plan-to-help-trump-steal-the-election\/", "display_url":"motherjones.com\/2020-elections\u2026", "indices":[ 260, 283 ] } ] }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1320899108606017539, "in_reply_to_status_id_str":"1320899108606017539", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":125, "favorite_count":313, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Tue Oct 27 13:19:17 +0000 2020", "id":1321079019668967431, "id_str":"1321079019668967431", "full_text":"In chilling opinion yesterday Brett Kavanaugh signaled he's willing to help Trump delegitimize election & throw out mail ballots cast heavily by Dems\n\nKavanaugh & Barrett worked on Florida 2000 recount for Bush & could do Bush v Gore 2.0 for Trump https:\/\/t.co\/Elnsnvqr4u", "truncated":false, "display_text_range":[ 0, 283 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ { "url":"https:\/\/t.co\/Elnsnvqr4u", "expanded_url":"https:\/\/www.motherjones.com\/2020-elections\/2020\/10\/brett-kavanaugh-lays-out-a-plan-to-help-trump-steal-the-election\/", "display_url":"motherjones.com\/2020-elections\u2026", "indices":[ 260, 283 ] } ] }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":null, "in_reply_to_status_id_str":null, "in_reply_to_user_id":null, "in_reply_to_user_id_str":null, "in_reply_to_screen_name":null, "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":317, "favorite_count":466, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Tue Oct 27 12:19:01 +0000 2020", "id":1321063854504353794, "id_str":"1321063854504353794", "full_text":"Given persistent USPS delays (it takes an average of 10 days for letter to be delivered in Wisconsin), I would urge voters to drop off their mail ballots or vote in person rather than risk mail ballot not being counted because USPS didn\u2019t deliver by Election Day", "truncated":false, "display_text_range":[ 0, 262 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "source":"\u003ca href=\"http:\/\/twitter.com\/download\/iphone\" rel=\"nofollow\"\u003eTwitter for iPhone\u003c\/a\u003e", "in_reply_to_status_id":1321060511245606914, "in_reply_to_status_id_str":"1321060511245606914", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":745, "favorite_count":1531, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Tue Oct 27 12:05:44 +0000 2020", "id":1321060511245606914, "id_str":"1321060511245606914", "full_text":"Very important: today is deadline USPS recommends for sending back your mail ballot to make sure it\u2019s counted. Better yet, drop it off if you can. 30 states require ballots to be received by Election Day (as SCOTUS ruled in Wisconsin yesterday)", "truncated":false, "display_text_range":[ 0, 244 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "source":"\u003ca href=\"http:\/\/twitter.com\/download\/iphone\" rel=\"nofollow\"\u003eTwitter for iPhone\u003c\/a\u003e", "in_reply_to_status_id":null, "in_reply_to_status_id_str":null, "in_reply_to_user_id":null, "in_reply_to_user_id_str":null, "in_reply_to_screen_name":null, "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":6300, "favorite_count":8000, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Tue Oct 27 01:36:52 +0000 2020", "id":1320902249846083586, "id_str":"1320902249846083586", "full_text":"If you\u2019re feeling despair tonight (and I know I am), remember massive turnout can overcome massive suppression \n\nWe don\u2019t have to accept an illegitimate system, we can vote to change it", "truncated":false, "display_text_range":[ 0, 185 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "source":"\u003ca href=\"http:\/\/twitter.com\/download\/iphone\" rel=\"nofollow\"\u003eTwitter for iPhone\u003c\/a\u003e", "in_reply_to_status_id":1320783852219105287, "in_reply_to_status_id_str":"1320783852219105287", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":1267, "favorite_count":5713, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Tue Oct 27 01:24:23 +0000 2020", "id":1320899108606017539, "id_str":"1320899108606017539", "full_text":"Kagan dissent in Wisconsin case: \"the Court\u2019s decision will disenfranchise large numbers of responsible voters in the midst of hazardous pandemic conditions\" https:\/\/t.co\/Q4pEXmDN96", "truncated":false, "display_text_range":[ 0, 157 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ], "media":[ { "id":1320898952183619584, "id_str":"1320898952183619584", "indices":[ 158, 181 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElTGmT0XIAAAaiH.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElTGmT0XIAAAaiH.png", "url":"https:\/\/t.co\/Q4pEXmDN96", "display_url":"pic.twitter.com\/Q4pEXmDN96", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320899108606017539\/photo\/1", "type":"photo", "sizes":{ "large":{ "w":834, "h":476, "resize":"fit" }, "medium":{ "w":834, "h":476, "resize":"fit" }, "small":{ "w":680, "h":388, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "extended_entities":{ "media":[ { "id":1320898952183619584, "id_str":"1320898952183619584", "indices":[ 158, 181 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElTGmT0XIAAAaiH.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElTGmT0XIAAAaiH.png", "url":"https:\/\/t.co\/Q4pEXmDN96", "display_url":"pic.twitter.com\/Q4pEXmDN96", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320899108606017539\/photo\/1", "type":"photo", "sizes":{ "large":{ "w":834, "h":476, "resize":"fit" }, "medium":{ "w":834, "h":476, "resize":"fit" }, "small":{ "w":680, "h":388, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1320883524954660867, "in_reply_to_status_id_str":"1320883524954660867", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":539, "favorite_count":2148, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Tue Oct 27 01:20:01 +0000 2020", "id":1320898012391055360, "id_str":"1320898012391055360", "full_text":"Trump campaign has filed lawsuits before Supreme Court to challenge ballots in states like PA & NC that Barrett could rule on as soon as tomorrow. This White House event is total conflict of interest. She is even more illegitimate now than before", "truncated":false, "display_text_range":[ 0, 250 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "source":"\u003ca href=\"http:\/\/twitter.com\/download\/iphone\" rel=\"nofollow\"\u003eTwitter for iPhone\u003c\/a\u003e", "in_reply_to_status_id":null, "in_reply_to_status_id_str":null, "in_reply_to_user_id":null, "in_reply_to_user_id_str":null, "in_reply_to_screen_name":null, "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":1358, "favorite_count":3607, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Tue Oct 27 01:13:26 +0000 2020", "id":1320896353904562176, "id_str":"1320896353904562176", "full_text":"GOP traded 225,000 American lives for 220 Trump judges", "truncated":false, "display_text_range":[ 0, 54 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":null, "in_reply_to_status_id_str":null, "in_reply_to_user_id":null, "in_reply_to_user_id_str":null, "in_reply_to_screen_name":null, "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":3793, "favorite_count":12430, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Tue Oct 27 00:34:54 +0000 2020", "id":1320886657156026369, "id_str":"1320886657156026369", "full_text":"Crazy fact: 52 GOP senators who voted to confirm Amy Coney Barrett represent 17 million fewer people than 47 Dems & Collins who voted no", "truncated":false, "display_text_range":[ 0, 140 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":null, "in_reply_to_status_id_str":null, "in_reply_to_user_id":null, "in_reply_to_user_id_str":null, "in_reply_to_screen_name":null, "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":5873, "favorite_count":14768, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Tue Oct 27 00:22:27 +0000 2020", "id":1320883524954660867, "id_str":"1320883524954660867", "full_text":"Insane rhetoric from Kavanaugh decrying \"chaos & suspicions of impropriety that can ensue if thousands of absentee ballots flow in after election day and potentially flip the results of an election\"\n\nThis comes on some night Trump tweets winner of election must be announced Nov 3 https:\/\/t.co\/Y9iZcBGOGy", "truncated":false, "display_text_range":[ 0, 284 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ], "media":[ { "id":1320882150552571905, "id_str":"1320882150552571905", "indices":[ 285, 308 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElS3UU3XEAEDo-9.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElS3UU3XEAEDo-9.png", "url":"https:\/\/t.co\/Y9iZcBGOGy", "display_url":"pic.twitter.com\/Y9iZcBGOGy", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320883524954660867\/photo\/1", "type":"photo", "sizes":{ "large":{ "w":415, "h":410, "resize":"fit" }, "medium":{ "w":415, "h":410, "resize":"fit" }, "small":{ "w":415, "h":410, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "extended_entities":{ "media":[ { "id":1320882150552571905, "id_str":"1320882150552571905", "indices":[ 285, 308 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElS3UU3XEAEDo-9.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElS3UU3XEAEDo-9.png", "url":"https:\/\/t.co\/Y9iZcBGOGy", "display_url":"pic.twitter.com\/Y9iZcBGOGy", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320883524954660867\/photo\/1", "type":"photo", "sizes":{ "large":{ "w":415, "h":410, "resize":"fit" }, "medium":{ "w":415, "h":410, "resize":"fit" }, "small":{ "w":415, "h":410, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1320877150770241541, "in_reply_to_status_id_str":"1320877150770241541", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":695, "favorite_count":1855, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" }, { "created_at":"Tue Oct 27 00:13:23 +0000 2020", "id":1320881243756597250, "id_str":"1320881243756597250", "full_text":"Truly astonishing: with Amy Coney Barrett\u2019s confirmation 5 of 6 conservative Supreme Court justices appointed by GOP presidents who initially lost popular vote & confirmed by senators who do not represent a majority of Americans", "truncated":false, "display_text_range":[ 0, 232 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ] }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":null, "in_reply_to_status_id_str":null, "in_reply_to_user_id":null, "in_reply_to_user_id_str":null, "in_reply_to_screen_name":null, "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":2438, "favorite_count":7334, "favorited":false, "retweeted":false, "lang":"en" }, { "created_at":"Mon Oct 26 23:57:08 +0000 2020", "id":1320877150770241541, "id_str":"1320877150770241541", "full_text":"Kavanaugh cites Bush v. Gore to justify making it harder to vote in Wisconsin\n\nKavanaugh, Roberts & Barrett all served on George W. Bush legal team in Florida 2000 recount & worked to make sure only GOP votes counted https:\/\/t.co\/NhNessbwoB", "truncated":false, "display_text_range":[ 0, 224 ], "entities":{ "hashtags":[ ], "symbols":[ ], "user_mentions":[ ], "urls":[ ], "media":[ { "id":1320876915889262592, "id_str":"1320876915889262592", "indices":[ 225, 248 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElSyjoOX0AAr1jk.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElSyjoOX0AAr1jk.png", "url":"https:\/\/t.co\/NhNessbwoB", "display_url":"pic.twitter.com\/NhNessbwoB", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320877150770241541\/photo\/1", "type":"photo", "sizes":{ "large":{ "w":412, "h":448, "resize":"fit" }, "medium":{ "w":412, "h":448, "resize":"fit" }, "small":{ "w":412, "h":448, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "extended_entities":{ "media":[ { "id":1320876915889262592, "id_str":"1320876915889262592", "indices":[ 225, 248 ], "media_url":"http:\/\/pbs.twimg.com\/media\/ElSyjoOX0AAr1jk.png", "media_url_https":"https:\/\/pbs.twimg.com\/media\/ElSyjoOX0AAr1jk.png", "url":"https:\/\/t.co\/NhNessbwoB", "display_url":"pic.twitter.com\/NhNessbwoB", "expanded_url":"https:\/\/twitter.com\/AriBerman\/status\/1320877150770241541\/photo\/1", "type":"photo", "sizes":{ "large":{ "w":412, "h":448, "resize":"fit" }, "medium":{ "w":412, "h":448, "resize":"fit" }, "small":{ "w":412, "h":448, "resize":"fit" }, "thumb":{ "w":150, "h":150, "resize":"crop" } } } ] }, "source":"\u003ca href=\"https:\/\/mobile.twitter.com\" rel=\"nofollow\"\u003eTwitter Web App\u003c\/a\u003e", "in_reply_to_status_id":1320872258085310466, "in_reply_to_status_id_str":"1320872258085310466", "in_reply_to_user_id":15952856, "in_reply_to_user_id_str":"15952856", "in_reply_to_screen_name":"AriBerman", "user":{ "id":15952856, "id_str":"15952856", "name":"Ari Berman", "screen_name":"AriBerman", "location":"New York", "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https:\/\/t.co\/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "url":null, "entities":{ "description":{ "urls":[ { "url":"https:\/\/t.co\/q5tNcCdQjy", "expanded_url":"http:\/\/amzn.to\/2asHld2", "display_url":"amzn.to\/2asHld2", "indices":[ 77, 100 ] } ] } }, "protected":false, "followers_count":159648, "friends_count":2782, "listed_count":2703, "created_at":"Sat Aug 23 01:46:02 +0000 2008", "favourites_count":17410, "utc_offset":null, "time_zone":null, "geo_enabled":false, "verified":true, "statuses_count":26571, "lang":null, "contributors_enabled":false, "is_translator":false, "is_translation_enabled":false, "profile_background_color":"0A4778", "profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme1\/bg.png", "profile_background_tile":false, "profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/1286763565412753409\/KkQAmz2N_normal.jpg", "profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/15952856\/1470151342", "profile_link_color":"C7124B", "profile_sidebar_border_color":"FFFFFF", "profile_sidebar_fill_color":"FF1D2E", "profile_text_color":"7A3060", "profile_use_background_image":false, "has_extended_profile":true, "default_profile":false, "default_profile_image":false, "following":null, "follow_request_sent":null, "notifications":null, "translator_type":"none" }, "geo":null, "coordinates":null, "place":null, "contributors":null, "is_quote_status":false, "retweet_count":2197, "favorite_count":3990, "favorited":false, "retweeted":false, "possibly_sensitive":false, "lang":"en" } ] ================================================ FILE: misc/playground/cli/spike/twitter-api/responses/response-version2-conversation.json ================================================ { "data":[ { "conversation_id":"1320872258085310466", "lang":"en", "id":"1320872258085310466", "created_at":"2020-10-26T23:37:41.000Z", "possibly_sensitive":false, "text":"Minutes before Amy Coney Barrett is confirmed Supreme Court rules 5-3 to throw out ballots in Wisconsin that are postmarked by Election Day but arrive after. 80,000 ballots were counted in primary that arrived after Election Day but were postmarked by then https://t.co/qEZGQBzpOv", "author_id":"15952856", "entities":{ "annotations":[ { "start":15, "end":31, "probability":0.9516, "type":"Person", "normalized_text":"Amy Coney Barrett" }, { "start":46, "end":58, "probability":0.9123, "type":"Organization", "normalized_text":"Supreme Court" }, { "start":94, "end":102, "probability":0.9795, "type":"Place", "normalized_text":"Wisconsin" }, { "start":127, "end":138, "probability":0.4046, "type":"Other", "normalized_text":"Election Day" }, { "start":216, "end":227, "probability":0.5778, "type":"Other", "normalized_text":"Election Day" } ], "urls":[ { "start":257, "end":280, "url":"https://t.co/qEZGQBzpOv", "expanded_url":"https://twitter.com/stevenmazie/status/1320870358900158466", "display_url":"twitter.com/stevenmazie/st…" } ] }, "public_metrics":{ "retweet_count":10045, "reply_count":937, "like_count":15745, "quote_count":2155 }, "source":"Twitter Web App", "context_annotations":[ { "domain":{ "id":"10", "name":"Person", "description":"Named people in the world like Nelson Mandela" }, "entity":{ "id":"1314602198932750336", "name":"Amy Coney Barrett" } } ], "referenced_tweets":[ { "type":"quoted", "id":"1320870358900158466" } ] } ] } ================================================ FILE: misc/playground/cli/spike/twitter-api/responses/response-version2-tweetthread.json ================================================ { "data":[ { "public_metrics":{ "retweet_count":137, "reply_count":12, "like_count":347, "quote_count":15 }, "text":"I hope people understand how serious a threat to democracy this is: Kavanaugh is now “swing justice” on 6-3 court & he’s spreading same disinformation about counting mail ballots as Trump\n\nWe need to vote in record numbers to overcome rigged Supreme Court https://t.co/Elnsnvqr4u", "lang":"en", "in_reply_to_user_id":"15952856", "source":"Twitter Web App", "created_at":"2020-10-27T13:51:42.000Z", "possibly_sensitive":false, "author_id":"15952856", "referenced_tweets":[ { "type":"replied_to", "id":"1320899108606017539" } ], "entities":{ "annotations":[ { "start":68, "end":76, "probability":0.9533, "type":"Person", "normalized_text":"Kavanaugh" }, { "start":182, "end":186, "probability":0.9978, "type":"Person", "normalized_text":"Trump" }, { "start":242, "end":254, "probability":0.5928, "type":"Organization", "normalized_text":"Supreme Court" } ], "urls":[ { "start":260, "end":283, "url":"https://t.co/Elnsnvqr4u", "expanded_url":"https://www.motherjones.com/2020-elections/2020/10/brett-kavanaugh-lays-out-a-plan-to-help-trump-steal-the-election/", "display_url":"motherjones.com/2020-elections…", "images":[ { "url":"https://pbs.twimg.com/news_img/1321079020184809474/XbL5QJjE?format=jpg&name=orig", "width":1200, "height":630 }, { "url":"https://pbs.twimg.com/news_img/1321079020184809474/XbL5QJjE?format=jpg&name=150x150", "width":150, "height":150 } ], "status":200, "title":"Brett Kavanaugh just laid out his plan to help Trump steal the election", "description":"A Bush v. Gore 2.0 crisis just became much more likely.", "unwound_url":"https://www.motherjones.com/2020-elections/2020/10/brett-kavanaugh-lays-out-a-plan-to-help-trump-steal-the-election/" } ] }, "id":"1321087179939057665", "context_annotations":[ { "domain":{ "id":"10", "name":"Person", "description":"Named people in the world like Nelson Mandela" }, "entity":{ "id":"799022225751871488", "name":"Donald Trump", "description":"US President Donald Trump" } }, { "domain":{ "id":"10", "name":"Person", "description":"Named people in the world like Nelson Mandela" }, "entity":{ "id":"1016678775298260992", "name":"Brett Kavanaugh", "description":"US Supreme Court nominee Brett Kavanaugh" } }, { "domain":{ "id":"35", "name":"Politician", "description":"Politicians in the world, like Joe Biden" }, "entity":{ "id":"799022225751871488", "name":"Donald Trump", "description":"US President Donald Trump" } }, { "domain":{ "id":"35", "name":"Politician", "description":"Politicians in the world, like Joe Biden" }, "entity":{ "id":"1016678775298260992", "name":"Brett Kavanaugh", "description":"US Supreme Court nominee Brett Kavanaugh" } }, { "domain":{ "id":"88", "name":"Political Body", "description":"A section of a government, like The Supreme Court" }, "entity":{ "id":"867872043672326144", "name":"Supreme Court of the United States", "description":"Conversation about the Supreme Court and justices" } } ], "conversation_id":"1320872258085310466" }, { "attachments":{ "media_keys":[ "3_1320898952183619584" ] }, "public_metrics":{ "retweet_count":552, "reply_count":60, "like_count":2177, "quote_count":41 }, "text":"Kagan dissent in Wisconsin case: \"the Court’s decision will disenfranchise large numbers of responsible voters in the midst of hazardous pandemic conditions\" https://t.co/Q4pEXmDN96", "lang":"en", "in_reply_to_user_id":"15952856", "source":"Twitter Web App", "created_at":"2020-10-27T01:24:23.000Z", "possibly_sensitive":false, "author_id":"15952856", "referenced_tweets":[ { "type":"replied_to", "id":"1320883524954660867" } ], "entities":{ "annotations":[ { "start":17, "end":25, "probability":0.9873, "type":"Place", "normalized_text":"Wisconsin" } ], "urls":[ { "start":158, "end":181, "url":"https://t.co/Q4pEXmDN96", "expanded_url":"https://twitter.com/AriBerman/status/1320899108606017539/photo/1", "display_url":"pic.twitter.com/Q4pEXmDN96" } ] }, "id":"1320899108606017539", "context_annotations":[ { "domain":{ "id":"123", "name":"Ongoing News Story", "description":"Ongoing News Stories like 'Brexit'" }, "entity":{ "id":"1220701888179359745", "name":"COVID-19" } }, { "domain":{ "id":"10", "name":"Person", "description":"Named people in the world like Nelson Mandela" }, "entity":{ "id":"867887467902283776", "name":"Elena Kagan", "description":"US Supreme Court Justice Elena Kagan" } }, { "domain":{ "id":"35", "name":"Politician", "description":"Politicians in the world, like Joe Biden" }, "entity":{ "id":"867887467902283776", "name":"Elena Kagan", "description":"US Supreme Court Justice Elena Kagan" } } ], "conversation_id":"1320872258085310466" }, { "attachments":{ "media_keys":[ "3_1320882150552571905" ] }, "public_metrics":{ "retweet_count":696, "reply_count":108, "like_count":1875, "quote_count":152 }, "text":"Insane rhetoric from Kavanaugh decrying \"chaos & suspicions of impropriety that can ensue if thousands of absentee ballots flow in after election day and potentially flip the results of an election\"\n\nThis comes on some night Trump tweets winner of election must be announced Nov 3 https://t.co/Y9iZcBGOGy", "lang":"en", "in_reply_to_user_id":"15952856", "source":"Twitter Web App", "created_at":"2020-10-27T00:22:27.000Z", "possibly_sensitive":false, "author_id":"15952856", "referenced_tweets":[ { "type":"replied_to", "id":"1320877150770241541" } ], "entities":{ "annotations":[ { "start":21, "end":29, "probability":0.6753, "type":"Person", "normalized_text":"Kavanaugh" }, { "start":225, "end":229, "probability":0.9984, "type":"Person", "normalized_text":"Trump" } ], "urls":[ { "start":285, "end":308, "url":"https://t.co/Y9iZcBGOGy", "expanded_url":"https://twitter.com/AriBerman/status/1320883524954660867/photo/1", "display_url":"pic.twitter.com/Y9iZcBGOGy" } ] }, "id":"1320883524954660867", "context_annotations":[ { "domain":{ "id":"10", "name":"Person", "description":"Named people in the world like Nelson Mandela" }, "entity":{ "id":"799022225751871488", "name":"Donald Trump", "description":"US President Donald Trump" } }, { "domain":{ "id":"10", "name":"Person", "description":"Named people in the world like Nelson Mandela" }, "entity":{ "id":"1016678775298260992", "name":"Brett Kavanaugh", "description":"US Supreme Court nominee Brett Kavanaugh" } }, { "domain":{ "id":"35", "name":"Politician", "description":"Politicians in the world, like Joe Biden" }, "entity":{ "id":"799022225751871488", "name":"Donald Trump", "description":"US President Donald Trump" } }, { "domain":{ "id":"35", "name":"Politician", "description":"Politicians in the world, like Joe Biden" }, "entity":{ "id":"1016678775298260992", "name":"Brett Kavanaugh", "description":"US Supreme Court nominee Brett Kavanaugh" } } ], "conversation_id":"1320872258085310466" }, { "attachments":{ "media_keys":[ "3_1320876915889262592" ] }, "public_metrics":{ "retweet_count":2255, "reply_count":226, "like_count":4100, "quote_count":414 }, "text":"Kavanaugh cites Bush v. Gore to justify making it harder to vote in Wisconsin\n\nKavanaugh, Roberts & Barrett all served on George W. Bush legal team in Florida 2000 recount & worked to make sure only GOP votes counted https://t.co/NhNessbwoB", "lang":"en", "in_reply_to_user_id":"15952856", "source":"Twitter Web App", "created_at":"2020-10-26T23:57:08.000Z", "possibly_sensitive":false, "author_id":"15952856", "referenced_tweets":[ { "type":"replied_to", "id":"1320872258085310466" } ], "entities":{ "annotations":[ { "start":0, "end":8, "probability":0.9211, "type":"Person", "normalized_text":"Kavanaugh" }, { "start":16, "end":19, "probability":0.9427, "type":"Person", "normalized_text":"Bush" }, { "start":24, "end":27, "probability":0.7073, "type":"Person", "normalized_text":"Gore" }, { "start":68, "end":76, "probability":0.6797, "type":"Organization", "normalized_text":"Wisconsin" }, { "start":79, "end":87, "probability":0.7773, "type":"Person", "normalized_text":"Kavanaugh" }, { "start":90, "end":96, "probability":0.9675, "type":"Person", "normalized_text":"Roberts" }, { "start":100, "end":106, "probability":0.9509, "type":"Person", "normalized_text":"Barrett" }, { "start":122, "end":135, "probability":0.9268, "type":"Person", "normalized_text":"George W. Bush" }, { "start":151, "end":157, "probability":0.9004, "type":"Place", "normalized_text":"Florida" }, { "start":199, "end":201, "probability":0.8738, "type":"Organization", "normalized_text":"GOP" } ], "urls":[ { "start":225, "end":248, "url":"https://t.co/NhNessbwoB", "expanded_url":"https://twitter.com/AriBerman/status/1320877150770241541/photo/1", "display_url":"pic.twitter.com/NhNessbwoB" } ] }, "id":"1320877150770241541", "context_annotations":[ { "domain":{ "id":"10", "name":"Person", "description":"Named people in the world like Nelson Mandela" }, "entity":{ "id":"921071164469911552", "name":"George W. Bush", "description":"Former US President George W. Bush" } }, { "domain":{ "id":"35", "name":"Politician", "description":"Politicians in the world, like Joe Biden" }, "entity":{ "id":"921071164469911552", "name":"George W. Bush", "description":"Former US President George W. Bush" } } ], "conversation_id":"1320872258085310466" } ], "includes":{ "users":[ { "url":"", "id":"15952856", "username":"AriBerman", "name":"Ari Berman", "protected":false, "public_metrics":{ "followers_count":159733, "following_count":2782, "tweet_count":26572, "listed_count":2705 }, "entities":{ "description":{ "urls":[ { "start":77, "end":100, "url":"https://t.co/q5tNcCdQjy", "expanded_url":"http://amzn.to/2asHld2", "display_url":"amzn.to/2asHld2" } ], "mentions":[ { "start":109, "end":121, "username":"motherjones" } ] } }, "description":"Author: Give Us the Ballot: The Modern Struggle for Voting Rights in America https://t.co/q5tNcCdQjy Writer: @motherjones Speaking: annette@speakersforall.com", "profile_image_url":"https://pbs.twimg.com/profile_images/1286763565412753409/KkQAmz2N_normal.jpg", "verified":true, "pinned_tweet_id":"1159848529038364672", "location":"New York", "created_at":"2008-08-23T01:46:02.000Z" } ] }, "meta":{ "newest_id":"1321087179939057665", "oldest_id":"1320877150770241541", "result_count":4 } } ================================================ FILE: misc/playground/cli/spike/twitter-api/script-version1-searchendpoint.js ================================================ const { url } = require("inspector"); const fetch = require("node-fetch"); const BEARER_TOKEN = 'Bearer '; const TWEET_LOOKUP_ENDPOINT = 'https://api.twitter.com/1.1/statuses/show.json?id=&tweet_mode=extended'; const SEARCH_ENDPOINT = 'https://api.twitter.com/1.1/search/tweets.json?q=from:+to:&count=200&tweet_mode=extended'; const SAMPLE_TWEET = 'https://twitter.com/AriBerman/status/1320872258085310466'; var tweets = []; var tweet_id = ""; var screen_name = ""; var conversation_id = ""; getTweets(SAMPLE_TWEET); function getTweetId(tweet_url) { return tweet_url.substring(tweet_url.lastIndexOf("/") + 1); } function getScreenName(tweet_url) { tweet_url = tweet_url.substring(0, tweet_url.lastIndexOf("/status")); return tweet_url.substring(tweet_url.lastIndexOf("/")+1); } function getURL(url_type) { var url = ""; if(url_type == 'tweet-lookup') url = TWEET_LOOKUP_ENDPOINT.replace("", tweet_id); else if(url_type == 'search-tweets') { url = SEARCH_ENDPOINT.replace("", screen_name); url = url.replace("", screen_name); } return url; } function getTweets(tweet_url) { tweet_id = getTweetId(tweet_url); screen_name = getScreenName(tweet_url); var url_type = 'tweet-lookup'; var url = getURL(url_type); fetchURL(url, url_type); } function processResponse(url_type, responseJSON) { if(url_type == 'tweet-lookup') processTweetLookup(responseJSON); else if(url_type == 'search-tweets') processSearchResponse(responseJSON); } function processTweetLookup(responseJSON) { var tweet = getTweetObject(responseJSON); if(isTweetNotOlderThanSevenDays(tweet)) { createCustomTweet(getTweetObject(responseJSON), getUserObject(responseJSON)); var url_type = 'search-tweets'; var url = getURL(url_type); fetchURL(url, url_type); } } function processSearchResponse(responseJSON) { var directReply = getTweetArray(responseJSON).filter((tweet)=> tweet.in_reply_to_screen_name == screen_name && tweet.in_reply_to_status_id_str == tweet_id); while(directReply.length > 0) { var tweet = directReply[0]; var replyId = tweet.id_str; createCustomTweet(tweet, tweet.user); directReply = getTweetArray(responseJSON).filter((tweet)=> tweet.in_reply_to_screen_name == screen_name && tweet.in_reply_to_status_id_str == replyId); } console.log(tweets); console.log(tweets.length); } function getTweetObject(responseJSON) { return responseJSON; } function getTweetArray(responseJSON) { return responseJSON.statuses; } function getUserObject(responseJSON) { return responseJSON.user; } function createCustomTweet(tweet_object, user_object) { var customTweet = {}; customTweet.name = user_object.name; customTweet.twitterHandle = user_object.screen_name; customTweet.image = user_object.profile_image_url_https; customTweet.createdAt = tweet_object.created_at; customTweet.tweet = tweet_object.full_text; tweets.push(customTweet); } function isTweetNotOlderThanSevenDays(tweet) { var dateOfTweet = new Date(tweet.created_at); var currentDate = new Date(); var differenceInDays = (currentDate.getTime() - dateOfTweet.getTime())/(1000*3600*24); if(differenceInDays >= 7) { console.log("cannot retrieve tweet thread"); return false; } return true; } async function fetchURL(url, url_type) { var myHeaders = {}; myHeaders.Authorization = BEARER_TOKEN; var requestOptions = { method : 'GET', headers: myHeaders, redirect: 'follow' }; console.log(url); await fetch(url, requestOptions) .then((response)=>response.json()) .then((result)=>processResponse(url_type, result)) .catch((error)=>console.log("error", error)); } ================================================ FILE: misc/playground/cli/spike/twitter-api/script-version1-usertimeline.js ================================================ const { url } = require("inspector"); const fetch = require("node-fetch"); const BEARER_TOKEN = 'Bearer '; const TWEET_LOOKUP_ENDPOINT = 'https://api.twitter.com/1.1/statuses/show.json?id=&tweet_mode=extended'; const USER_TIMELINE_ENDPOINT = 'https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=&since_id=&tweet_mode=extended&count=200'; const SAMPLE_TWEET = 'https://twitter.com/AriBerman/status/1320872258085310466'; var tweets = []; var tweet_id = ""; var screen_name = ""; var conversation_id = ""; getTweets(SAMPLE_TWEET); function getTweetId(tweet_url) { return tweet_url.substring(tweet_url.lastIndexOf("/") + 1); } function getScreenName(tweet_url) { tweet_url = tweet_url.substring(0, tweet_url.lastIndexOf("/status")); return tweet_url.substring(tweet_url.lastIndexOf("/")+1); } function getURL(url_type) { var url = ""; if(url_type == 'tweet-lookup') url = TWEET_LOOKUP_ENDPOINT.replace("", tweet_id); else if(url_type == 'search-tweets') { url = USER_TIMELINE_ENDPOINT.replace("", tweet_id); url = url.replace("", screen_name); } return url; } function getTweets(tweet_url) { tweet_id = getTweetId(tweet_url); screen_name = getScreenName(tweet_url); var url_type = 'tweet-lookup'; var url = getURL(url_type); fetchURL(url, url_type); } function processResponse(url_type, responseJSON) { if(url_type == 'tweet-lookup') processTweetLookup(responseJSON); else if(url_type == 'search-tweets') processSearchResponse(responseJSON); } function processTweetLookup(responseJSON) { var tweet = getTweetObject(responseJSON); if(isTweetNotOlderThanSevenDays(tweet)) { createCustomTweet(getTweetObject(responseJSON), getUserObject(responseJSON)); var url_type = 'search-tweets'; var url = getURL(url_type); fetchURL(url, url_type); } } function processSearchResponse(responseJSON) { var directReply = getTweetArray(responseJSON).filter((tweet)=> tweet.in_reply_to_screen_name == screen_name && tweet.in_reply_to_status_id_str == tweet_id); while(directReply.length > 0) { var tweet = directReply[0]; var replyId = tweet.id_str; createCustomTweet(tweet, tweet.user); directReply = getTweetArray(responseJSON).filter((tweet)=> tweet.in_reply_to_screen_name == screen_name && tweet.in_reply_to_status_id_str == replyId); } console.log(tweets); console.log(tweets.length); } function getTweetObject(responseJSON) { return responseJSON; } function getTweetArray(responseJSON) { return responseJSON; } function getUserObject(responseJSON) { return responseJSON.user; } function createCustomTweet(tweet_object, user_object) { var customTweet = {}; customTweet.name = user_object.name; customTweet.twitterHandle = user_object.screen_name; customTweet.image = user_object.profile_image_url_https; customTweet.createdAt = tweet_object.created_at; customTweet.tweet = tweet_object.full_text; tweets.push(customTweet); } function isTweetNotOlderThanSevenDays(tweet) { var dateOfTweet = new Date(tweet.created_at); var currentDate = new Date(); var differenceInDays = (currentDate.getTime() - dateOfTweet.getTime())/(1000*3600*24); if(differenceInDays >= 7) { console.log("cannot retrieve tweet thread"); return false; } return true; } async function fetchURL(url, url_type) { var myHeaders = {}; myHeaders.Authorization = BEARER_TOKEN; var requestOptions = { method : 'GET', headers: myHeaders, redirect: 'follow' }; console.log(url); await fetch(url, requestOptions) .then((response)=>response.json()) .then((result)=>processResponse(url_type, result)) .catch((error)=>console.log("error", error)); } ================================================ FILE: misc/playground/cli/spike/twitter-api/script-version2-conversation.js ================================================ const { url } = require("inspector"); const fetch = require("node-fetch"); const BEARER_TOKEN = 'Bearer '; const ENDPOINT_TO_FETCH_CONVERSATION_ID = 'https://api.twitter.com/2/tweets?ids=' const TWEET_FIELDS = '&tweet.fields=attachments,author_id,context_annotations,conversation_id,created_at,entities,geo,in_reply_to_user_id,lang,possibly_sensitive,public_metrics,referenced_tweets,source,withheld'; const USER_FIELDS = '&user.fields=created_at,description,entities,location,pinned_tweet_id,profile_image_url,protected,public_metrics,url,verified,withheld'; const MEDIA_FIELDS = '&media.fields=duration_ms,height,preview_image_url,public_metrics,width'; const POLL_FIELDS = '&poll.fields=duration_minutes,end_datetime,voting_status'; const PLACE_FIELDS = '&place.fields=contained_within,country,country_code,geo,name,place_type'; const EXPANSIONS = '&expansions=author_id'; const ENDPOINT_TO_FETCH_CONVERSATION_TWEETS = 'https://api.twitter.com/2/tweets/search/recent?query=conversation_id:+from:'; const SAMPLE_TWEET = 'https://twitter.com/AriBerman/status/1320872258085310466'; var tweets = []; var tweet_id = ""; var screen_name = ""; var conversation_id = ""; getTweets(SAMPLE_TWEET); function getTweetId(tweet_url) { return tweet_url.substring(tweet_url.lastIndexOf("/") + 1); } function getScreenName(tweet_url) { tweet_url = tweet_url.substring(0, tweet_url.lastIndexOf("/status")); return tweet_url.substring(tweet_url.lastIndexOf("/")+1); } function getURL(url_type) { var url = ""; if(url_type == 'tweet-lookup') url += ENDPOINT_TO_FETCH_CONVERSATION_ID + tweet_id; else if(url_type == 'search-tweets') { url = ENDPOINT_TO_FETCH_CONVERSATION_TWEETS.replace("", conversation_id); url = url.replace("", screen_name); } url += TWEET_FIELDS + EXPANSIONS + USER_FIELDS + MEDIA_FIELDS + PLACE_FIELDS + POLL_FIELDS; return url; } function getTweets(tweet_url) { tweet_id = getTweetId(tweet_url); screen_name = getScreenName(tweet_url); var url_type = 'tweet-lookup'; var url = getURL(url_type); fetchURL(url, url_type); } function processResponse(url_type, responseJSON) { if(url_type == 'tweet-lookup') processTweetLookup(responseJSON); else if(url_type == 'search-tweets') processSearchResponse(responseJSON); } function processTweetLookup(responseJSON) { var tweetArray = responseJSON.data; var tweet = tweetArray[0]; if(isTweetNotOlderThanSevenDays(tweet)) { createCustomTweet(getTweetObject(responseJSON), getUserObject(responseJSON)); conversation_id = getTweetObject(responseJSON).conversation_id; var url_type = 'search-tweets'; var url = getURL(url_type); fetchURL(url, url_type); } } function processSearchResponse(responseJSON) { var directReplies = getTweetArray(responseJSON).filter((tweet)=> tweet.referenced_tweets.filter((ref)=>ref.type == 'replied_to' && ref.id == tweet_id).length > 0); while(directReplies.length > 0) { var reply_id = directReplies[0].id; createCustomTweet(directReplies[0], getUserObject(responseJSON)); directReplies = getTweetArray(responseJSON).filter((tweet)=> tweet.referenced_tweets.filter((ref)=> ref.type == 'replied_to' && ref.id == reply_id).length > 0); } console.log(tweets); console.log(tweets.length); } function getTweetObject(responseJSON) { return responseJSON.data[0]; } function getTweetArray(responseJSON) { return responseJSON.data; } function getUserObject(responseJSON) { return responseJSON.includes.users[0]; } function createCustomTweet(tweet_object, user_object) { var customTweet = {}; customTweet.name = user_object.name; customTweet.twitterHandle = user_object.username; customTweet.image = user_object.profile_image_url; customTweet.createdAt = tweet_object.created_at; customTweet.tweet = tweet_object.text; tweets.push(customTweet); } function isTweetNotOlderThanSevenDays(tweet) { var dateOfTweet = new Date(tweet.created_at); var currentDate = new Date(); var differenceInDays = (currentDate.getTime() - dateOfTweet.getTime())/(1000*3600*24); if(differenceInDays >= 7) { console.log("cannot retrieve tweet thread"); return false; } return true; } async function fetchURL(url, url_type) { var myHeaders = {}; myHeaders.Authorization = BEARER_TOKEN; var requestOptions = { method : 'GET', headers: myHeaders, redirect: 'follow' }; console.log(url); await fetch(url, requestOptions) .then((response)=>response.json()) .then((result)=>processResponse(url_type, result)) .catch((error)=>console.log("error", error)); } ================================================ FILE: misc/playground/mock/README.md ================================================ # mock Here is the test thread link https://twitter.com/johnjacobkenny/status/1320972620817260544 Here is the code for the endpoint which fetches the first tweet data. Response is in `./twitter-tweet-api-response.json` ```javascript var myHeaders = new Headers(); myHeaders.append("Authorization", "Bearer "); var requestOptions = { method: "GET", headers: myHeaders, redirect: "follow", }; fetch( "https://api.twitter.com/2/tweets/1320972620817260544?tweet.fields=author_id,created_at,entities,geo,id,in_reply_to_user_id,text,conversation_id,referenced_tweets&expansions=author_id,in_reply_to_user_id,referenced_tweets.id&user.fields=name,username", requestOptions ) .then((response) => response.text()) .then((result) => console.log(result)) .catch((error) => console.log("error", error)); ``` Here is the code for the endpoint which fetches the conversation tweet data. Response is in `twitter-recent-search-api-response.json` ```javascript var myHeaders = new Headers(); myHeaders.append("Authorization", "Bearer "); var requestOptions = { method: "GET", headers: myHeaders, redirect: "follow", }; fetch( "https://api.twitter.com/2/tweets/search/recent?tweet.fields=author_id,created_at,entities,geo,id,in_reply_to_user_id,text,conversation_id,referenced_tweets&expansions=author_id,in_reply_to_user_id,referenced_tweets.id&query=conversation_id:1320972620817260544", requestOptions ) .then((response) => response.text()) .then((result) => console.log(result)) .catch((error) => console.log("error", error)); ``` ================================================ FILE: misc/playground/mock/twit-thread.json ================================================ [ { "name": "Naval", "twitterHandle": "naval", "image": "https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg", "createdAt": "2018-05-31", "tweet": "How to Get Rich (without getting lucky):" }, { "name": "Naval", "twitterHandle": "naval", "image": "https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg", "createdAt": "2018-05-31", "tweet": "Seek wealth, not money or status. Wealth is having assets that earn while you sleep. Money is how we transfer time and wealth. Status is your place in the social hierarchy." }, { "name": "Naval", "twitterHandle": "naval", "image": "https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg", "createdAt": "2018-05-31", "tweet": "Understand that ethical wealth creation is possible. If you secretly despise wealth, it will elude you." }, { "name": "Naval", "twitterHandle": "naval", "image": "https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg", "createdAt": "2018-05-31", "tweet": "Ignore people playing status games. They gain status by attacking people playing wealth creation games.:" }, { "name": "Naval", "twitterHandle": "naval", "image": "https://pbs.twimg.com/profile_images/1256841238298292232/ycqwaMI2_400x400.jpg", "createdAt": "2018-05-31", "tweet": "Ignore people playing status games. They gain status by attacking people playing wealth creation games.:" } ] ================================================ FILE: misc/playground/mock/twitter-recent-search-api-response.json ================================================ { "data": [ { "conversation_id": "1320972620817260544", "id": "1320974447952547840", "text": "@lucifierpraveen Hehe 😜 Yeah it was kinda boring, but in the end we all learnt something valuable!", "author_id": "391224534", "referenced_tweets": [ { "type": "replied_to", "id": "1320974110826979328" } ], "created_at": "2020-10-27T06:23:45.000Z", "entities": { "mentions": [ { "start": 0, "end": 16, "username": "lucifierpraveen" } ] }, "in_reply_to_user_id": "2933420017" }, { "conversation_id": "1320972620817260544", "entities": { "hashtags": [ { "start": 76, "end": 84, "tag": "twindle" } ], "mentions": [ { "start": 0, "end": 15, "username": "johnjacobkenny" } ] }, "id": "1320974110826979328", "text": "@johnjacobkenny I am also one of the guy who taste the merge conflicts 😅 in #twindle lol", "author_id": "2933420017", "referenced_tweets": [ { "type": "replied_to", "id": "1320972623031906306" } ], "created_at": "2020-10-27T06:22:25.000Z", "in_reply_to_user_id": "391224534" }, { "conversation_id": "1320972620817260544", "id": "1320973015539093505", "text": "Anyone can join at anytime, we have a lot of people joining daily, though we started a couple of weeks ago.", "author_id": "391224534", "referenced_tweets": [ { "type": "replied_to", "id": "1320972624965427200" } ], "created_at": "2020-10-27T06:18:04.000Z", "in_reply_to_user_id": "391224534" }, { "conversation_id": "1320972620817260544", "id": "1320972624965427200", "text": "3\n\nEveryone is encouraged to ask questions and contribute to create documentation and to help others out wherever they can!\n\nCheck it out @twindleco", "author_id": "391224534", "referenced_tweets": [ { "type": "replied_to", "id": "1320972623031906306" } ], "created_at": "2020-10-27T06:16:30.000Z", "entities": { "mentions": [ { "start": 138, "end": 148, "username": "twindleco" } ] }, "in_reply_to_user_id": "391224534" }, { "conversation_id": "1320972620817260544", "id": "1320972623031906306", "text": "2\n\nWe are mostly a community of beginners with a few mentors guiding the product development. Everyone created their first PR and experienced the horrors of having a merge conflict, which was super fun tbh 🥳\n\nContd ...", "author_id": "391224534", "referenced_tweets": [ { "type": "replied_to", "id": "1320972620817260544" } ], "created_at": "2020-10-27T06:16:30.000Z", "in_reply_to_user_id": "391224534" } ], "includes": { "users": [ { "id": "391224534", "name": "Kenny Jacob ⚡", "username": "johnjacobkenny" }, { "id": "2933420017", "name": "PraveenKumar", "username": "lucifierpraveen" } ], "tweets": [ { "conversation_id": "1320972620817260544", "entities": { "hashtags": [ { "start": 76, "end": 84, "tag": "twindle" } ], "mentions": [ { "start": 0, "end": 15, "username": "johnjacobkenny" } ] }, "id": "1320974110826979328", "text": "@johnjacobkenny I am also one of the guy who taste the merge conflicts 😅 in #twindle lol", "author_id": "2933420017", "referenced_tweets": [ { "type": "replied_to", "id": "1320972623031906306" } ], "created_at": "2020-10-27T06:22:25.000Z", "in_reply_to_user_id": "391224534" }, { "conversation_id": "1320972620817260544", "id": "1320972623031906306", "text": "2\n\nWe are mostly a community of beginners with a few mentors guiding the product development. Everyone created their first PR and experienced the horrors of having a merge conflict, which was super fun tbh 🥳\n\nContd ...", "author_id": "391224534", "referenced_tweets": [ { "type": "replied_to", "id": "1320972620817260544" } ], "created_at": "2020-10-27T06:16:30.000Z", "in_reply_to_user_id": "391224534" }, { "conversation_id": "1320972620817260544", "id": "1320972624965427200", "text": "3\n\nEveryone is encouraged to ask questions and contribute to create documentation and to help others out wherever they can!\n\nCheck it out @twindleco", "author_id": "391224534", "referenced_tweets": [ { "type": "replied_to", "id": "1320972623031906306" } ], "created_at": "2020-10-27T06:16:30.000Z", "entities": { "mentions": [ { "start": 138, "end": 148, "username": "twindleco" } ] }, "in_reply_to_user_id": "391224534" }, { "conversation_id": "1320972620817260544", "entities": { "hashtags": [ { "start": 145, "end": 153, "tag": "twindle" } ], "annotations": [ { "start": 81, "end": 87, "probability": 0.8492, "type": "Product", "normalized_text": "Twitter" }, { "start": 133, "end": 139, "probability": 0.8567, "type": "Product", "normalized_text": "Twitter" } ] }, "id": "1320972620817260544", "text": "Please ignore this tweet thread. It is for testing purposes only. Trying out the Twitter v2 beta API for fetching tweet threads from Twitter for #twindle project.\n\nTwindle is the place where beginners contribute to open source by building a product in the open. Contd ...", "author_id": "391224534", "created_at": "2020-10-27T06:16:29.000Z" } ] }, "meta": { "newest_id": "1320974447952547840", "oldest_id": "1320972623031906306", "result_count": 5 } } ================================================ FILE: misc/playground/mock/twitter-tweet-api-response.json ================================================ { "data": { "text": "Please ignore this tweet thread. It is for testing purposes only. Trying out the Twitter v2 beta API for fetching tweet threads from Twitter for #twindle project.\n\nTwindle is the place where beginners contribute to open source by building a product in the open. Contd ...", "author_id": "391224534", "id": "1320972620817260544", "conversation_id": "1320972620817260544", "entities": { "annotations": [ { "start": 81, "end": 87, "probability": 0.8492, "type": "Product", "normalized_text": "Twitter" }, { "start": 133, "end": 139, "probability": 0.8567, "type": "Product", "normalized_text": "Twitter" } ], "hashtags": [ { "start": 145, "end": 153, "tag": "twindle" } ] }, "created_at": "2020-10-27T06:16:29.000Z" }, "includes": { "users": [ { "id": "391224534", "name": "Kenny Jacob ⚡", "username": "johnjacobkenny" } ] } } ================================================ FILE: misc/playground/tests/github/giturl.unit.test.js ================================================ const { validateGithubURL } = require("../../../../twindle-cli/src/cli"); const mockURL = "https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/README.html"; test("verify github url extension", async () => { await expect(() => validateGithubURL(mockURL)).rejects.toThrow(Error); }); ================================================ FILE: misc/playground/tests/github/repo.unit.test.js ================================================ const { getHtml } = require("../../src/github/githubparse/app"); const mockURL = "https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/ch1.md"; test("fetch function return repo details in json", async () => { const data = await getHtml(mockURL); expect(data).toMatchObject(/{}/); }); ================================================ FILE: misc/playground/tests/twitter/api.test.js ================================================ const { getTweetById, getConversationById } = require("../../src/twitter/api"); const { ApiErrors } = require("../../src/twitter/error"); describe("api module", () => { it("should throw an error if called without tweet id", () => { expect(() => getTweetById()).toThrow(ApiErrors.TweetIDNotProvidedError); expect(() => getConversationById()).toThrow(ApiErrors.TweetIDNotProvidedError); }); // it("#getConversationByID() should throw error if screen name not provided", () => { // expect(() => getConversationById("1324263512621883393", undefined, "API Key")).toThrow( // ApiErrors.UserScreenNameInvalid // ); // }); // see https://github.com/facebook/jest/issues/5538#issuecomment-461013424 // it("should throw an error if called without token", async () => { // await expect(() => getTweetById("1324263512621883393")).rejects.toThrow( // ApiErrors.TokenNotProvidedError // ); // await expect(() => getConversationById("1324263512621883393")).rejects.toThrow( // ApiErrors.TokenNotProvidedError // ); // }); }); ================================================ FILE: misc/playground/tests/twitter/unit/api/helpers/fetch.unit.test.js ================================================ const { ApiErrors } = require("../../../../../src/twitter/error"); const { fetch } = require("../../../../../src/twitter/api/helpers/fetch"); const mockURL = "https://api.twitter.com/2/tweets?ids=1326680823559380992,1325817877585387521&tweet.fields=attachments,author_id,context_annotations,conversation_id,created_at,entities,geo,in_reply_to_user_id,lang,possibly_sensitive,public_metrics,referenced_tweets,source,withheld&expansions=author_id,attachments.media_keys&user.fields=created_at,description,entities,location,pinned_tweet_id,profile_image_url,protected,public_metrics,url,verified,withheld&media.fields=duration_ms,height,preview_image_url,url,media_key,public_metrics,width&place.fields=contained_within,country,country_code,geo,name,place_type&poll.fields=duration_minutes,end_datetime,voting_status"; describe("twitter |> api |> helpers |> fetch module", () => { it("should throw error if called without token", async () => { await expect(() => fetch(mockURL)).rejects.toThrow(ApiErrors.TokenNotProvidedError); }); it("should throw error if token is invalid", async () => { await expect(() => fetch(mockURL, "blah blah blah")).rejects.toThrow( ApiErrors.InvalidTokenError ); }); }); ================================================ FILE: misc/playground/tests/twitter/unit/api/twitter-endpoints/search.unit.test.js ================================================ const { ApiErrors } = require("../../../../../src/twitter/error"); const { getConversationById } = require("../../../../../src/twitter/api/twitter-endpoints/search"); describe("twitter |> api |> twitter-endpoints |> search", () => { it("should throw error if ID is falsey(undefined, null, false, etc)", () => { expect(() => getConversationById()).toThrow(ApiErrors.TweetIDNotProvidedError); }); it("should throw error if screenName is falsey", () => { expect(() => getConversationById("Tweet ID")).toThrow(ApiErrors.UserScreenNameInvalid); }); }); ================================================ FILE: misc/playground/tests/twitter/unit/api/twitter-endpoints/tweets.unit.test.js ================================================ const { ApiErrors } = require("../../../../../src/twitter/error"); const { getTweetById } = require("../../../../../src/twitter/api/twitter-endpoints/tweets"); describe("twitter |> api |> twitter-endpoints |> tweets module", () => { it("should throw error if tweet id is falsey", () => { expect(() => getTweetById()).toThrow(ApiErrors.TweetIDNotProvidedError); }); }); ================================================ FILE: misc/playground/tests/twitter/unit/transformations/helpers.unit.test.js ================================================ describe("helpers module", () => { it("2 + 2 == 4", () => { expect(2 + 2).toBe(4); }); }); ================================================ FILE: misc/playground/tests/twitter/utils.test.js ================================================ const { formatTimestamp } = require("../../src/twitter/utils/date"); describe("utils module", () => { describe("date module", () => { it("#format() should correctly format the date", () => { const aDate = new Date("2020-01-01T00:00:00"); const transformedDate = formatTimestamp(aDate); const expectedOutput = "Jan 1, 2020"; expect(transformedDate).toEqual(expectedOutput); }); }); }); ================================================ FILE: misc/playground/twindleco/header/header1/header1.css ================================================ *{ box-sizing: border-box; margin: o; padding: 0; background-color: #212121; } li,a,button{ font-family: Arial, Helvetica, sans-serif; font-weight: 500; font-size: 16px; color: #edf0f1; text-decoration: none; } header{ display: flex; justify-content: space-between; align-items: center; padding: 30px 10%; } .logo{ cursor: pointer; color: #32e0c4; } .nav-links{ list-style:none ; } .nav-links li{ display: inline-block; padding: 0px 20px; } .nav-links li a{ transition: all 0.3s ease 0s; } .nav-links li a:hover{ color: #0088a9; } button{ padding: 9px 25px; background-color: rgba(0,136,169,1); border: none; border-radius: 50px; cursor: pointer; transition: all 0.3s ease 0s; } button:hover{ background-color: rgba(0,136,169,0.8); } ================================================ FILE: misc/playground/twindleco/header/header1/header1.html ================================================ HEADER

    TWINDLE

    ================================================ FILE: misc/playground/twindleco/header/header2/header2.css ================================================ * { margin: 0; padding: 0; box-sizing: border-box; } html, body { background-color: #fff; color: #000; font-family: 'Lato', 'Arial', sans-serif; font-size: 20px; font-weight: 300; } header { background-color: #E0F6F6; } nav { height: 20vh; padding: 20px; display: flex; justify-content: space-between; align-items: center } .main-nav { list-style: none; padding: 10px; display: flex; align-items: flex-end; } .main-nav li { display: inline-block; margin-left: 40px; } .main-nav li a:link, .main-nav li a:visited { padding: 8px 0; color: #095a5a; text-decoration: none; text-transform: uppercase; border-bottom: 2px solid transparent; transition: border-bottom 0.2s; } .main-nav li a:hover, .main-nav li a:active { border-bottom: 2px solid #095a5a; } ================================================ FILE: misc/playground/twindleco/header/header2/header2.html ================================================ Twindle
    ================================================ FILE: misc/playground/twindleco/header/header3/header3.css ================================================ @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@500;700&display=swap'); *{ margin: 0; padding: 0; font-family: 'Montserrat', sans-serif; } /* Header */ header{ display: flex; } /* Logo */ #logo{ background-color: rgb(168, 28, 28); font-weight: bolder; font-size: 2.5rem; padding: 10px; } #logo a{ text-decoration: none; position: relative; left: 102px; color: white; } /* Menu List */ header ul{ list-style: none; display: flex; position: relative; left: 100px; } header ul li{ text-align: center; font-size: 1.2rem; width: 150px; padding: 23px 0px; } li a{ text-decoration: none; color: black; } li a:hover{ color: rgb(168, 28, 28); } ================================================ FILE: misc/playground/twindleco/header/header3/header3.html ================================================ Header
    ================================================ FILE: misc/playground/twindleco/header/header4/public/index.html ================================================ CodePen - A Pen by Marcus ================================================ FILE: misc/playground/twindleco/header/header4/public/style.css ================================================ @charset "UTF-8"; .container { height: 100vh; width: 100vw; padding: 10px; padding-top: 0px; background-color: white; margin-left: -10px; } .header { position: fixed; top: 0px; left: 0px; right: 0px; width: 100vw; height: 50px; background-color: white; padding-left: 30px; padding-right: 30px; padding: 10px; display: flex; flex-direction: row; } .header h1 { display: block; border: 2px solid transparent; width: 70px; height: 66px; margin-left: -10px; padding-left: 30px; padding-right: 20px; margin-top: -10px; background-color: #E01C15; display: flex; align-items: center; } .logo { color: white; text-decoration: none; font-size: 20px; font-family: 'Sansita Swashed', cursive; } .links-container { position: absolute; right: 5%; } .links-container .links { display: flex; flex-direction: row; } .links-container .links a { color: rgba(0, 0, 0, 0.9); text-decoration: none; } .links-container .links li { font-size: 15px; margin-right: 3vw; list-style: none; font-family: 'Sansita Swashed', cursive; } .links-container .links a:hover { border-bottom: 2px solid rgba(0, 0, 0, 0.6); } .links-container .links button { padding: 5px; color: white; background-color: cyan; border-radius: 5px; border-color: transparent; font-size: 15px; font-weight: bold; position: relative; cursor: pointer; } .links-container .links button::before { content: "↖ IT'S FREE!"; position: absolute; color: rgba(0, 0, 0, 0.4); top: 39px; right: 2px; font-size: 10px; } .links-container .links button:hover { padding: 6.6px; } .body { height: 100vh; display: flex; align-items: center; justify-content: center; } .body img { margin-top: 100px; width: 40%; height: 100%; } @media screen and (max-width: 1000px) { li { font-size: 5px; margin-right: 1vw; } } ================================================ FILE: misc/playground/twindleco/header/header5/header_twindle.css ================================================ @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@700&display=swap'); #header { position: relative; height: 10vh; width: 100vw; background-color: rgb(116, 22, 139); } #logo { width: 100px; height: 80%; margin: 5px 21px; background-color: white; position: absolute; } #logo img { height: 52px; width: 100%;; } nav { position: absolute; display: flex; align-items: center; justify-content: flex-end; top: 0; height: 10vh; margin-left: 6vw; width: 94vw; } ul { display: flex; justify-content: flex-end; align-items: center; height: 100%; } body, header, ul{ margin: 0; } li { list-style-type: none; margin: 0 2vw; font-size: 2.5vh; } a{ text-decoration: none; color: white; padding: 1.2vw; font-family: 'Noto Sans JP', sans-serif; } a:hover { background-color: rgb(135, 75, 150); border-radius: 5px; } ================================================ FILE: misc/playground/twindleco/header/header5/header_twindle.html ================================================ Header ================================================ FILE: misc/playground/twindleco/header/header6/header6.css ================================================ body { margin: 0; font-family: Arial, Helvetica, sans-serif; } .box { display: flex; flex-wrap: nowrap; background-color: #f1f1f1; } .box > div { text-align: center; font-size: 30px; padding: 20px 10px; } .box a { color: black; text-align: center; padding: 12px; text-decoration: none; font-size: 18px; line-height: 25px; border-radius: 4px; } .box a:hover { background-color: #ddd; color: black; } .logo { font-size: 30px; font-weight: bold; } .push{ margin-left :auto; } ================================================ FILE: misc/playground/twindleco/header/header6/header6.html ================================================ Welcome to Twindle ================================================ FILE: misc/playground/twindleco/header/header7/header7.css ================================================ *{ padding: 0; margin: 0; } li, a{ font-size: 18px; color: #3b98d5; } header{ display: flex; justify-content: flex-end; align-items: center; background-color: #eef9ff; height: 50px; padding: 25px; position: fixed; top: 0; left: 0; right: 0; box-shadow: 10px 15px 15px #D3D3D3; } .link{ list-style: none; } .link,li{ display: inline-block; padding: 0px 20px; } #logo{ margin-right: auto; color: #3b98d5; } li,a:hover{ color: #586066; } ================================================ FILE: misc/playground/twindleco/header/header7/header7.html ================================================ Header
    ================================================ FILE: misc/playground/twindleco/header8/header8.css ================================================ * { margin: 0; padding: 0; } .navbar { width: 100%; overflow: hidden; height: 70px; line-height: 70px; background: rgb(62, 121, 155); border-bottom: 2px solid blue; position: fixed; z-index: 9999; } .logo{ width: 100px; height: 70px; float: left; } .menu { float: right; } .menu li { float: left; width: 120px; height: 70px; line-height: 70px; text-align: center; list-style-type: none; } .menu li a { color: whitesmoke; text-decoration: none; list-style: none; font-family: Calibri; text-transform: capitalize; display: block; } .menu li a:hover { background: rgb(40, 54, 179); } ================================================ FILE: misc/playground/twindleco/header8/header8.html ================================================ Twindle ================================================ FILE: misc/playground/twindleco/homepage/homepage1/Twindle Home Page.html ================================================ Twindle - Home Twindle - Home
    twindle logo

    Export your tweets to pdf or epub with the click of a button







    How is a Twitter thread converted to PDF or EPUB?


    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras vitae urna porttitor, dignissim magna et, lobortis dui. Sed ullamcorper quam eget ultrices efficitur. Aliquam vulputate a urna vel bibendum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse varius, ex a vehicula fringilla, libero purus blandit ex, eget bibendum risus mi sit amet nisl. Nam viverra scelerisque arcu, nec ultrices eros molestie quis. Pellentesque vestibulum pharetra turpis, et sodales justo tempus sit amet. Integer semper lectus sit amet eros volutpat faucibus. Proin sed eros nec est mollis efficitur at quis arcu. Vivamus iaculis lobortis molestie. Etiam ut dignissim sem, quis aliquam ligula. Aenean vehicula dapibus eros vitae egestas. Donec sed lectus id libero gravida sodales. Donec eu finibus erat, sed lacinia arcu. Vestibulum consequat augue at mattis sagittis. Nullam sit amet quam aliquet, rutrum erat a, ornare lacus. Duis in elit in ex semper vestibulum sed in velit. Vivamus lobortis arcu non libero ultrices, id sollicitudin velit eleifend. Aenean efficitur, odio quis facilisis posuere, lacus lorem volutpat risus, a malesuada augue elit vitae erat.