Repository: engineerapart/TheRemoteFreelancer Branch: master Commit: 849f6c6c3b08 Files: 35 Total size: 105.3 KB Directory structure: gitextract_cb2vatad/ ├── .gitignore ├── LICENSE ├── README.md └── docs/ ├── 404.html ├── CNAME ├── Gemfile ├── _config.yml ├── _data/ │ └── sites.csv ├── _includes/ │ ├── board_listing.html │ ├── board_listing_item.html │ ├── board_listing_item_mobile.html │ ├── footer.html │ ├── google-analytics.html │ ├── head.html │ ├── header.html │ └── logo.html ├── _layouts/ │ ├── default.html │ ├── home.html │ ├── post.html │ └── posts.html ├── _posts/ │ ├── 2017-09-04-difference-between-types.markdown │ └── 2017-09-05-why-people-hate-upwork.md ├── assets/ │ ├── app.css │ └── app.source.css ├── build.sh ├── dev.sh ├── index.md ├── package.json ├── postcss.config.js ├── posts.html ├── scripts/ │ ├── alexa.py │ ├── download_favicons.py │ ├── sites_history_script.py │ └── update.py └── tailwind.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .DS_Store _site/ .sass-cache/ .jekyll-metadata __pycache__ .idea/ node_modules # Local Netlify folder .netlify docs/.netlify docs/.jekyll-cache ================================================ FILE: LICENSE ================================================ This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. 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 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. For more information, please refer to ================================================ FILE: README.md ================================================ # The Remote Freelancer List of community-curated resources to find topical remote freelance & contract work for software developers, web designers, and more! See [Why](#why) and [Contributing](#contributing). Rank: This is an estimation on how popular the site is, with #1 being the most viewed site on the internet in the US. Up until 2022 Alexa was used, Similar web will be used for future ratings. [Graph of changes over time](https://public.tableau.com/profile/andrew.chase#!/vizhome/theremotefreelancer/AlexaRankOverTime?publish=yes) | **Clients** | | | | |------------------------------------------------------------------------------------------|----------------|------------|-------------------------------------------| | **Name** | **Rank** | | **Hires these Types** | | [Upwork](https://upwork.com) | 200 | | Designers, Developers, & Others | | [Freelancer](https://www.freelancer.com/affiliates/andychase) | 700 | | Designers, Developers, & Others | | [PeoplePerHour](https://www.peopleperhour.com) | 2,000 | & Gigs | Designers, Developers, & Others | | [Toptal](https://www.toptal.com/BLjoyn/worlds-top-talent) | 3,000 | | Designers, Developers, & Others | | [Guru.com](http://www.guru.com/) | 5,000 | | Designers, Developers, & Others | | [Turing](https://turing.com/) | 6,000 | | Developers | | [Truelancer](https://www.truelancer.com) | 10,000 | | Designers, Developers, & Others | | [Crossover](https://www.crossover.com) | 10,000 | | Developers & Business Managers | | [arc.dev](https://arc.dev/) | 20,000 | | Developers | | [Scalable Path](https://www.scalablepath.com/) | 70,000 | | Designers & Developers | | [freelancermap](https://www.freelancermap.com/it-projects.html) | 80,000 | | Developers, Engineers, Consultants, Others| | [StoreTasker](https://www.storetasker.com/) | 100,000 | | Shopify Developers | | [Soshace](https://www.soshace.com/) | 100,000 | | Developers | | [Adeva](https://adevait.com/) | 200,000 | | Designers, Developers, & QA | | [Speedlancer](https://speedlancer.com/) | 600,000 | | Designers & Developers | | [Worksome](https://worksome.co.uk/) | 2,000,000 | | Consultants, Data Scientists, & Developers| | **Tutoring** | | | | | [CodeMentor.io](https://www.codementor.io) | 10,000 | Tutoring | Developers | | **Other** | | | | | **Name** | **Rank** | | **Hires these Types** | | [Fiverr](https://www.fiverr.com/) | 100 | Gigs | Variety | | [Bonsai](https://app.hellobonsai.com/users/sign_up?refer=8728021d) | 20,000 | Tools | Designers, Developers, & Others | | [Jobdone.net](https://jobdone.net/explore?) | 1,000,000 | Gigs | Variety | | [\#frontenddevelopers.org](http://frontenddevelopers.org/) | 1,000,000 | Community | Developers | | [Remote One](https://remote.one/) | 1,000,000 | Tools | Designers, Developers, & Others | | [Clarrow](https://clarrow.com/) | 2,000,000 | Tools | Designers, Developer & Others | | **Jobs** | | | | | **Name** | **Rank** | | **Hires these Types** | | [Dribbble Jobs](https://dribbble.com/obs?utf8=%E2%9C%93&anywhere=true&location=Anywhere) | 1,000 | | Designers | | [Angel List Jobs](https://angel.co/jobs#find/f!%7B%22remote%22%3Atrue%7D) | 2,000 | | Variety | | [FlexJobs](https://www.flexjobs.com) | 7,000 | | Variety | | [We Work Remotely](https://weworkremotely.com/) | 10,000 | | Variety | | [Hired](https://hired.com/) | 20,000 | | Designers, Developers, & Product Managers | | [RemoteOK](https://remoteok.io/) | 80,000 | | Developers | | [Himalayas](https://himalayas.app) | 200,000 | | Designers, Developers, & Product Managers | | [No Fluff Jobs](https://nofluffjobs.com/#criteria=remote) | 200,000 | | Developers | | [Golangprojects.com](https://www.golangprojects.com/golang-remote-jobs.html) | 600,000 | | Go/Golang jobs, filter on remote jobs | | [Remotesome.com](https://www.remotesome.com/) | 1,000,000 | | Developers | | [RemoteYeah](https://remoteyeah.com/) | 2,000,000 | | Data Scientists & Developers | | [Jobhunt.ai](https://jobhunt.ai/machinelearning-remote-jobs.html) | 8,000,000 | | AI/Machine learning jobs, filter on remote jobs | | [Team Extension](https://teamextension.io/) | 8,000,000 | | Eastern Euro Developers, Designers, QA | **Agency** | | | | | **Name** | **Rank** | | **Hires these Types** | | [Codeable](https://codeable.io/) | 40,000 | | Wordpress Developers developers | | [Superside](https://www.superside.com/) | 50,000 | | Designers | | [Working Not Working](https://workingnotworking.com/) | 70,000 | | Designers | | [X-Team](http://x-team.com) | 70,000 | | Developers | | [Experfy](https://www.experfy.com/) | 80,000 | | Data Scientists & Developers | | [Gun.io](https://gun.io/) | 100,000 | | Developers | | [Gigster](https://gigster.com/) | 200,000 | | Developers, Project Managers, & Designers | | [DOZ.com](https://www.doz.com) | 500,000 | | Marketing | | [Moonlight](https://www.moonlightwork.com) | 1,000,000 | | Developers | | [10xmanagement](https://www.10xmanagement.com/) | 1,000,000 | | Designers & Developers | | [Lightboard](https://lightboard.io) | 2,000,000 | | Designers | | [MeteorOps.com](https://meteorops.com) | 10,000,000 | | DevOps Engineers | | [Dreamlance](http://dreamlance.io/) | 10,000,000 | | Designers & Developers | | [CodersClan.net](https://codersclan.net) | 10,000,000 | | Developers | ## Regional, or Language-Specific * UK * [Gigged AI](https://gigged.ai) - Newcomer in the space with Clients ready but little Talent. * [devitjobs.uk](https://devitjobs.uk/jobs/all/remote) * Germany * [germantechjobs](https://germantechjobs.de/jobs/all/remote) * Latin America * [Workana](https://www.workana.com) – Largest Latin American freelancer network * French * [Codeur](https://www.codeur.com/) - Leader in France. * [Malt](https://www.malt.fr/) - One of the largest platform for french Freelancers. * [Comet](https://www.comet.co/) - French platform that search and qualify IT freelancers for each mission. * [Laotop](https://www.laotop.fr/) - French platform that search and qualify IT freelancers for each mission. * Denmark * [Worksome](http://www.worksome.dk) - Denmark's largest platform for local freelancers. * Dutch * [Freelance.nl](https://freelance.nl/) - Leader in the Netherlands. * [Marktplaats](http://klussen.marktplaats.nl/diensten-en-vakmensen/klussen/0) - Kind of like Craigslist. * [Funle.nl](https://funle.nl/) - Aggregator of all available IT-specific freelance gigs in the Netherlands * [de Publieke Partner](https://depubliekepartner.nl/) - Agency in dutch Government freelance assignments. * Spanish * [Freelancer MX](https://www.freelancer.mx) - Contrata a freelancers expertos para tu trabajo en l?nea. * Persian * [Ponisha](http://ponisha.ir) - Ponisha is an online network for freelance professionals, in Iran. * Brazilian * [99 Freelas](https://www.99freelas.com.br) - Contrate os melhores freelancers do Brasil. * Russian * [Freelansim](https://freelansim.ru/) - биржа удаленной работы для IT-специалистов. * [FL](https://www.fl.ru/) - профессиональный ресурс, предназначенный для поиска работы или исполнителя на удаленную работу. * [freelance.ru](https://freelance.ru/) - Биржа фриланса, каталог фрилансеров и самозанятых по категориям. * Indonesian * [Projects.co.id](https://projects.co.id/) - Leader in Indonesia. * [Fastwork](https://m.fastwork.id/) - Newcomers. * [Sribu.com](https://sribu.com/) - is For Designer (but sribulancer.com is dead). ## Why This repo was inspired by [this Hacker News thread](https://news.ycombinator.com/item?id=12773282) about one software developer's experience with Upwork. For all those who have had bad experiences with Upwork, I wanted to create a list of additional resources that software developers can use to find freelance, nomadic and contract work. ## Contributing Please please please contribute to the list! If you have freelance work available or know someone who does, feel free to open a pull request to augment this list! Thank you for looking :) Good hunting! ## Differences between types | | Clients | Jobs | Agency | |----------------------------------|--------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------| | Interaction with Clients | Your interaction is with clients directly, organization does little/no communication with clients | You interact with employers directly, organization does little/no communication with clients | Organization handles clients and just gives you work. You have little/no interaction with clients | | Control over working environment | Generally you can work however, using own tools, supplies, set own hours, etc | Employer controls how you work generally. Provides tools, sets hours, tasks, etc. | Agency might direct you on what tasks to do but you have flexibility on how to accomplish them | | Payment | Client pays you, but through the organization (which may takes its cut) | Employer pays you salary (withholding taxes) | Agency pays you | | Choice of Client or Project | Complete control of client/project | Complete control of job selection | Little/no choice of project or client | | Vetting/Interviews | Clients vets you | Companies vet you | Organization vets you, Client wouldn't really vet you individual | ## Other resources ### Aggregators - https://findwork.dev - http://jobscribe.com/ - https://www.hellobonsai.com/gig-list - https://www.folyo.me/ - http://www.lancelist.com/ - https://www.letsmakeapps.io/ - https://freelandr.com/ - https://remotephp.io - https://periodix.net - https://www.remotelyawesomejobs.com - https://www.nynedge.com/ - https://remotework.fyi/ - https://www.vollna.com/ - https://remotebond.com/ ### Bounties based and open source - https://gitcoin.co - https://bountysource.com - https://gitpay.me ### Remote jobs - [lukasz-madonawesome-remote-job](https://github.com/lukasz-madon/awesome-remote-job#job-boards) – A curated list of awesome remote jobs and resources. Inspired by [Awesome Python](https://github.com/vinta/awesome-python). - [HN Hiring (hnhiring.me)](http://hnhiring.me/) - [HNHIRING](https://hnhiring.com/) – All Jobs From Hacker News 'Who is Hiring?'. - [Remote Leaf](https://remoteleaf.com/) – Receive hand-picked remote jobs posted anywhere delivered straight to your inbox. ### Job tracking tools - [Upfeed](https://upfeed.io/) – Smart and personalized Upwork's feed. - [Upwork jobs feed tracker](https://chrome.google.com/webstore/detail/upwork-jobs-feed-tracker/gcjmekbfkkmaccloaoccfiohjnmgkddm) – Convenient way to track new jobs for Upwork freelancers. ## Who [Codinronan](https://github.com/codinronan) originally started this resource, [Andy Chase](https://github.com/andychase) has been maintaining since 2017. Special thanks to everyone who has submitted corrections and new sites. Also thanks to [Georges Kabbouchi](https://github.com/KABBOUCHI) who developed the website version based on a design from [Ovidiu Alexandrescu](https://github.com/owystyle). ## License None. Literally, why would I include a license in this. Copy, paste, skewer, go nuts. (Ok, officially, "The Unlicense") ================================================ FILE: docs/404.html ================================================ --- layout: default sitemap: false ---

404

Page not found :(

The requested page could not be found.

================================================ FILE: docs/CNAME ================================================ theremotefreelancer.com ================================================ FILE: docs/Gemfile ================================================ source "https://rubygems.org" gem 'github-pages', group: :jekyll_plugins ================================================ FILE: docs/_config.yml ================================================ # Welcome to Jekyll! # # This config file is meant for settings that affect your whole blog, values # which you are expected to set up once and rarely edit after that. If you find # yourself editing this file very often, consider using Jekyll's data files # feature for the data you need to update frequently. # # For technical reasons, this file is *NOT* reloaded automatically when you use # 'bundle exec jekyll serve'. If you change this file, please restart the server process. # Site settings # These are used to personalize your new site. If you look in the HTML files, # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. # You can create any custom variable you would like, and they will be accessible # in the templates via {{ site.myvariable }}. title: The Remote Freelancer author: Andy Chase email: hi@theremotefreelancer.com description: > # this means to ignore newlines until "baseurl:" List of community-curated resources to find topical remote freelance & contract work for software developers, web designers, and more! baseurl: "" # the subpath of your site, e.g. /blog url: "https://theremotefreelancer.com" # the base hostname & protocol for your site, e.g. http://example.com twitter_username: tr_freelancer github_username: andychase google_analytics: UA-105858060-1 # Build settings markdown: kramdown plugins: - jekyll-sitemap - jekyll-seo-tag - jekyll-postcss # Exclude from processing. # The following items will not be processed, by default. Create a custom list # to override the default setting. # exclude: # - Gemfile # - Gemfile.lock # - node_modules # - vendor/bundle/ # - vendor/cache/ # - vendor/gems/ # - vendor/ruby/ exclude: - Gemfile - Gemfile.lock - node_modules - yarn.lock - package-lock.json - README.md - postcss.config.js - .gitignore ================================================ FILE: docs/_data/sites.csv ================================================ netloc,name,url,rank,section,type,opinions,affiliate_link,screening,sdescription,support,jobterm upwork.com,Upwork,https://upwork.com,200,Clients,Clients,[Why people hate Upwork](/2017/09/04/why-people-hate-upwork.html),,Open,"Fixed or hourly projects. Largest client listing. Lots of low-paid competition. Horrible Support. Guaranteed payment for hourly 20%/10%/5% depending on engagement length.
Why do people hate Upwork?",4,4 freelancer.com,Freelancer,https://www.freelancer.com/,700,Clients,Clients,,https://www.freelancer.com/affiliates/andychase,Open,Much like upwork but their pricing is more around paying per listing/application. ,4,5 www.peopleperhour.com,PeoplePerHour,https://www.peopleperhour.com,"2,000",Clients,Clients & Gigs,,,Open,Emphasis on shorter projects. Spec work also.,4,2 www.guru.com,Guru,http://www.guru.com/,"5,000",Clients,Clients,,,Open,"Larger profile section for freelancers. Payment on completion with ""resolution process"" if client is unhappy.",3,4 www.toptal.com,Toptal,https://www.toptal.com/,"6,000",Clients,Clients,,https://www.toptal.com/BLjoyn/worlds-top-talent,Screening,"Can be hard to actually get jobs. Big name clients. Hourly or weekly engagements. Recruiters sell you to clients. Some sense of ""community"".",2,4 www.truelancer.com,Truelancer,https://www.truelancer.com,"9,000",Clients,Clients,,,,,4,4 www.crossover.com,Crossover,https://www.crossover.com,"20,000",Clients,Clients,,,Screening,Emphasis on long term engagements.,2,3 turing.com,Turing,https://turing.com,"20,000",Clients,Clients,,,,,4,4 arc.dev,Arc,https://arc.dev/,"40,000",Clients,Clients,,https://www.codementor.io/i/2kz84aesbl,Screening,Get paid for short tutoring sessions or find clients. Bit of a vetting process. For client projects payments aren't guaranteed.,4,4 storetasker.com,StoreTasker,https://www.storetasker.com/,"40,000",Clients,Clients,,,,,3,4 www.scalablepath.com,Scalable Path,https://www.scalablepath.com,"90,000",Clients,Clients,,,,,4,4 www.soshace.com,Soshace,https://www.soshace.com,"100,000",Clients,Clients,,,,,4,3 adevait.com,Adeva,https://adevait.com/,"200,000",Clients,Clients,,,,,4,4 speedlancer.com,Speedlancer,https://speedlancer.com,"600,000",Clients,Clients,,,,,4,4 worksome.co.uk,Worksome,https://worksome.co.uk,"2,000,000",Clients,Clients,,,,,4,4 codementor.io,CodeMentor,https://codementor.io/,"10,000",Tutoring,Tutoring,,https://www.codementor.io/i/2kz84aesbl,,,1,5 www.fiverr.com,Fiverr,https://www.fiverr.com/,100,Other,Gigs,,http://track.fiverr.com/visit/?bta=15132&nci=5490,Open,,4,4 jobdone.net,JobDone,https://jobdone.net/explore?,"1,000,000",Other,Gigs,,,,,5,4 frontenddevelopers.org,#frontenddevelopers.org,http://frontenddevelopers.org/,"1,000,000",Other,Community,,,,,4,4 remote.one,Remote One,https://remote.one/,"1,000,000",Other,Tools,,,,,4,4 clarrow.com,Clarrow,https://clarrow.com/,"2,000,000",Other,Tools,,,,,4,4 freelance.chat,#freelance,http://freelance.chat/,"6,000,000",Other,Community,,,,,4,4 hellobonsai.com,Bonsai,https://www.hellobonsai.com/,"10,000,000",Other,Tools,,https://app.hellobonsai.com/users/sign_up?refer=8728021d,,,4,5 hypelance.com,Hypelance,https://hypelance.com/,"10,000,000",Other,Community,,,,,4,4 codeable.io,Codeable,https://codeable.io/,"40,000",Agency,Agency,,,,,4,4 superside.com,Superside,https://www.superside.com/,"50,000",Agency,Agency,,,,,4,4 workingnotworking.com,Working Not Working,https://workingnotworking.com/,"70,000",Agency,Agency,,,,,3,4 x-team.com,X-Team,http://x-team.com,"70,000",Agency,Agency,,,,,4,4 www.experfy.com,Experfy,https://www.experfy.com/,"80,000",Agency,Agency,,,,,4,4 gun.io,Gun.io,https://gun.io/,"100,000",Agency,Agency,,,,,4,4 gigster.com,Gigster,https://gigster.com,"200,000",Agency,Agency,,https://gigs.to/r/Dz2vevg,,,4,4 pilot.co,Pilot,https://pilot.co/,"200,000",Agency,Agency,,,,,4,4 www.doz.com,DOZ.com,https://www.doz.com,"500,000",Agency,Agency,,,,,4,4 www.moonlightwork.com,Moonlight,https://www.moonlightwork.com,"1,000,000",Agency,Agency,,,,,4,4 www.10xmanagement.com,10xmanagement,https://www.10xmanagement.com/,"1,000,000",Agency,Agency,,,,,4,4 lightboard.io,Lightboard,https://lightboard.io,"2,000,000",Agency,Agency,,,,,4,4 meteorops.com,MeteorOps,https://meteorops.com,"10,000,000",Agency,Agency,,,Open,"DevOps Engineering Projects",4,4 dreamlance.io,Dreamlance,http://dreamlance.io/,"10,000,000",Agency,Agency,,,,,4,4 codersclan.net,CodersClan.net,https://codersclan.net,"10,000,000",Agency,Agency,,,,,4,4 careers.stackoverflow.com,Stack Overflow Careers,http://careers.stackoverflow.com/jobs/remote,60,Jobs,Jobs,,,,,4,4 dribbble.com,Dribbble Jobs,https://dribbble.com/obs?utf8=%E2%9C%93&anywhere=true&location=Anywhere,"1,000",Jobs,Jobs,,,,,4,4 angel.co,Angel List Jobs,https://angel.co/jobs#find/f!%7B%22remote%22%3Atrue%7D,"2,000",Jobs,Jobs,,,,,4,4 www.flexjobs.com,FlexJobs,https://www.flexjobs.com,"7,000",Jobs,Jobs,,,,,4,4 weworkremotely.com,We Work Remotely,https://weworkremotely.com/,"10,000",Jobs,Jobs,,,,,4,4 hired.com,Hired,https://hired.com/,"20,000",Jobs,Jobs,,,,,4,4 remoteok.io,RemoteOK,https://remoteok.io/,"80,000",Jobs,Jobs,,,,,4,4 nofluffjobs.com,No Fluff Jobs,https://nofluffjobs.com/#criteria=remote,"200,000",Jobs,Jobs,,,,,4,4 www.golangprojects.com,Golangprojects.com,https://www.golangprojects.com/golang-remote-jobs.html,"600,000",Jobs,Jobs,,,,,4,4 jobhunt.ai,Jobhunt.ai,https://jobhunt.ai/machinelearning-remote-jobs.html,"8,000,000",Jobs,Jobs,,,,,4,4 teamextension.io,Team Extension,https://teamextension.io/,"8,000,000",Jobs,Jobs,,,,,4,4 ================================================ FILE: docs/_includes/board_listing.html ================================================
{% include board_listing_item_mobile.html section='Clients' %}
================================================ FILE: docs/_includes/board_listing_item.html ================================================ {{ section }} {% assign listings = site.data.sites | where:'section', include.section %} {% for listing in listings %}
{{listing.name}}
Alexa Rank
{{listing.rank}}
SUMMARY
{% if listing.sdescription == "" or listing.sdescription == nil %} - {% else %} {{listing.sdescription}} {% endif %}
Type {{ listing.type }}
SUPPORT {% assign support = listing.support | plus: 0 %} {% for i in (1..5) %} {% if i <= support and support <= 3 %}
{% elsif i <= support and support > 3 %}
{% else %}
{% endif %} {% endfor %}
JOB TERM {% assign jobterm = listing.jobterm | plus: 0 %} {% for i in (1..5) %} {% if i <= jobterm and jobterm <= 3 %}
{% elsif i <= jobterm and jobterm > 3 %}
{% else %}
{% endif %} {% endfor %}
SCREENING {% if listing.screening == 'Open' %} {% else %} {% endif %}
{% endfor %} ================================================ FILE: docs/_includes/board_listing_item_mobile.html ================================================ {{ section }} {% assign listings = site.data.sites | where:'section', include.section %} {% for listing in listings %}
{{listing.rank}}
Alexa Rank
{{listing.name}}
Type {{ listing.type }}
SUPPORT
{% assign support = listing.support | plus: 0 %} {% for i in (1..5) %} {% if i <= support and support <= 3 %}
{% elsif i <= support and support > 3 %}
{% else %}
{% endif %} {% endfor %}
JOB TERM
{% assign jobterm = listing.jobterm | plus: 0 %} {% for i in (1..5) %} {% if i <= jobterm and jobterm <= 3 %}
{% elsif i <= jobterm and jobterm > 3 %}
{% else %}
{% endif %} {% endfor %}
SCREENING {% if listing.screening == 'Open' %} {% else %} {% endif %}
SUMMARY
{% if listing.sdescription == "" or listing.sdescription == nil %} - {% else %} {{listing.sdescription}} {% endif %}
{% endfor %} ================================================ FILE: docs/_includes/footer.html ================================================ ================================================ FILE: docs/_includes/google-analytics.html ================================================ ================================================ FILE: docs/_includes/head.html ================================================ {%- seo -%} {%- if jekyll.environment == 'production' and site.google_analytics -%} {%- include google-analytics.html -%} {%- endif -%} ================================================ FILE: docs/_includes/header.html ================================================ ================================================ FILE: docs/_includes/logo.html ================================================ ================================================ FILE: docs/_layouts/default.html ================================================ {% include head.html %} {{ site.title }} {{ content }} ================================================ FILE: docs/_layouts/home.html ================================================ --- layout: default ---
{% include logo.html %}

Top Services
For Freelancers

{{ site.description }}

{% include board_listing.html %}

Recent Articles

{% for post in site.posts limit:3 %} {{ post.title }} {% endfor %}
{% include footer.html %}
================================================ FILE: docs/_layouts/post.html ================================================ {% include head.html %}

{{ page.title }}

{{ content }}
{% include footer.html %} ================================================ FILE: docs/_layouts/posts.html ================================================ {% include head.html %}

{{ page.title }}

{{ content }}
{% include footer.html %} ================================================ FILE: docs/_posts/2017-09-04-difference-between-types.markdown ================================================ --- layout: post title: "What's the difference between the different types of boards out there?" date: 2017-09-04 10:35:01 -0700 published: true ---
  Clients Jobs Agency
Interaction with Clients You interaction is with clients directly, organization does little/no communication with clients You interact with employers directly, organization does little/no communication with clients Organization handles clients and just gives you work. You have little/no interaction with clients
Control over working environment Generally you can work however, using own tools, supplies, set own hours, etc Employer controls how you work generally. Provides tools, sets hours, tasks, etc. Agency might direct you on what tasks to do but you have flexibility on how to accomplish them
Payment Client pays you, but through the organization (which may takes its cut) Employer pays you salary (withholding taxes) Agency pays you
Choice of Client or Project Complete control of client/project Complete control of job selection Little/no choice of project or client
Vetting/Interviews Clients vets you Companies vet you Organization vets you, Client wouldn’t really vet you individually
================================================ FILE: docs/_posts/2017-09-05-why-people-hate-upwork.md ================================================ --- layout: post title: "Why do people hate Upwork?" date: 2017-09-04 10:35:01 -0700 published: true --- My name is [Andy Chase][andychase]. I've been working as a freelance software engineer for about 5 years. When I started working I used Upwork (then called oDesk) to find clients. See my list of [alternatives to upwork here](/)! # Upwork is the Tinder of Freelance Of course you could go out and in person to networking events, build up a network of random people and tell everyone you are looking for work. The problem is, you're not going to do that . You're not a marketer or a networking expert. You just want work. So that's why you end up on Upwork. There's a lot of competition of Upwork, competing both on price and on quality. More than likely, clients who don't know a lot about software engineering are comparing you purely based on stereotypes and marketing hype. There's also a bit of a game to it, where putting a focused message out there to a wide range of people is more successful then only only applying to the few jobs that you're actually qualified for. In real life, when you cold-call your friend's dad who needs someone to do data entry for his small business, he's comparing you to absolutely no one. It's presumed you can do the job (otherwise you wouldn't have come to him), and social pressures and sheer convenience will likely sway him to your favor. That person doesn't have the feeling like they are choosing between 30 good options, they instead have the feeling like cosmic graces have smiled on them and the perfect choice has appeared in front them ready to go. # The biggest problem with Upwork in my opinion is their customer service Upwork is a glorified job board. Unlike Craigslist they don't have a benevolent attitude towards their purpose. They view customer service as a cost center and anything that can't be solved by a $5/hr wage support rep isn't going to be solved. Michelle wrote [Someone stole my identity on Upwork and all I got was this lousy blog post][stole-my-identity], while it sounds like an exception situation in general, for Upwork customer support that's about the level of support (little to none). # Upwork has some advantages Here's reasons Upwork can actually be a decent deal: * It's democratic * If you apply to a job, you are listed as a possibility. * Services like [Toptal][toptal] decides what you can work on and what you can't. While if a recruiter does like you they will try and sell you, if they don't then its a closed door. And recruiters will strongly type-cast you to a position based on your prior experience and what your profile looks like. You're full stack but mostly work on backend stuff? They're probably not going to list you for a front-end job. * Transparent pricing * Unlike an agency or a spread-based network, you have complete control over your rate. You can negotiate it client-by-client taking into many factors of each client. * They guarantee payment * By yourself, it can actually be hard to get clients to pay you. Personally, when I was on my own it was always a battle to have new clients to try get as much as they can before they ghosted (usually they ended up with a prototype and an estimate). * Upwork (if you follow the rules, hourly contracts, detailed memos, automatically tracked time, verified payment), they will pay you. I've had clients have "issues" with their method of Payment and Upwork paid me on time like always (they also told me to take a break from working until they could figure it out.) * Being paid on time no matter what is not something to be underestimated, it's something that turns freelancing from a hobby into a real job honestly. It's something you can depend on and plan your life around. * Upwork also pays fast. 10-17 days from the moment you log time each week. With [toptal][toptal] it's more like 4-6 weeks. * Popularity * More popular job boards means it can be easier to find interested clients looking for someone like you. * Upwork is the 50th most visited site in the world according to Alexa (based on data from people who have the Alexa toolbar installed). [andychase]: https://andychase.me [mrdfx]: https://www.reddit.com/r/freelance/comments/6y9gn3/burned_by_upwork_make_sure_to_submit_a_complaint/dmmchwu/?utm_content=permalink&utm_medium=front&utm_source=reddit&utm_name=freelance [stole-my-identity]: https://hackernoon.com/someone-stole-my-identity-on-upwork-and-all-i-got-was-this-lousy-blog-post-d63aab2b4c90 [toptal]: https://www.toptal.com/#amass-nothing-but-top-notch-software-architects ================================================ FILE: docs/assets/app.css ================================================ /*! tailwindcss v2.2.19 | MIT License | https://tailwindcss.com */ /*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */ /* Document ======== */ /** Use a better box model (opinionated). */ *, ::before, ::after { box-sizing: border-box; } /** Use a more readable tab size (opinionated). */ html { -moz-tab-size: 4; -o-tab-size: 4; tab-size: 4; } /** 1. Correct the line height in all browsers. 2. Prevent adjustments of font size after orientation changes in iOS. */ html { line-height: 1.15; /* 1 */ -webkit-text-size-adjust: 100%; /* 2 */ } /* Sections ======== */ /** Remove the margin in all browsers. */ body { margin: 0; } /** Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) */ body { font-family: system-ui, -apple-system, /* Firefox supports this but not yet `system-ui` */ 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'; } /* Grouping content ================ */ /** 1. Add the correct height in Firefox. 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) */ hr { height: 0; /* 1 */ color: inherit; /* 2 */ } /* Text-level semantics ==================== */ /** Add the correct text decoration in Chrome, Edge, and Safari. */ abbr[title] { -webkit-text-decoration: underline dotted; text-decoration: underline dotted; } /** Add the correct font weight in Edge and Safari. */ b, strong { font-weight: bolder; } /** 1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) 2. Correct the odd 'em' font sizing in all browsers. */ code, kbd, samp, pre { font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace; /* 1 */ font-size: 1em; /* 2 */ } /** Add the correct font size in all browsers. */ small { font-size: 80%; } /** Prevent 'sub' and 'sup' elements from affecting the line height in all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.5em; } /* Tabular data ============ */ /** 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) */ table { text-indent: 0; /* 1 */ border-color: inherit; /* 2 */ } /* Forms ===== */ /** 1. Change the font styles in all browsers. 2. Remove the margin in Firefox and Safari. */ button, input, optgroup, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 1 */ line-height: 1.15; /* 1 */ margin: 0; /* 2 */ } /** Remove the inheritance of text transform in Edge and Firefox. 1. Remove the inheritance of text transform in Firefox. */ button, select { /* 1 */ text-transform: none; } /** Correct the inability to style clickable types in iOS and Safari. */ button, [type='button'] { -webkit-appearance: button; } /** Remove the inner border and padding in Firefox. */ ::-moz-focus-inner { border-style: none; padding: 0; } /** Restore the focus styles unset by the previous rule. */ /** Remove the additional ':invalid' styles in Firefox. See: https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737 */ /** Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers. */ legend { padding: 0; } /** Add the correct vertical alignment in Chrome and Firefox. */ progress { vertical-align: baseline; } /** Correct the cursor style of increment and decrement buttons in Safari. */ ::-webkit-inner-spin-button, ::-webkit-outer-spin-button { height: auto; } /** 1. Correct the odd appearance in Chrome and Safari. 2. Correct the outline style in Safari. */ /** Remove the inner padding in Chrome and Safari on macOS. */ ::-webkit-search-decoration { -webkit-appearance: none; } /** 1. Correct the inability to style clickable types in iOS and Safari. 2. Change font properties to 'inherit' in Safari. */ ::-webkit-file-upload-button { -webkit-appearance: button; /* 1 */ font: inherit; /* 2 */ } /* Interactive =========== */ /* Add the correct display in Chrome and Safari. */ summary { display: list-item; } /** * Manually forked from SUIT CSS Base: https://github.com/suitcss/base * A thin layer on top of normalize.css that provides a starting point more * suitable for web applications. */ /** * Removes the default spacing and border for appropriate elements. */ blockquote, dl, dd, h1, h2, h3, h4, h5, h6, hr, figure, p, pre { margin: 0; } button { background-color: transparent; background-image: none; } fieldset { margin: 0; padding: 0; } ol, ul { list-style: none; margin: 0; padding: 0; } /** * Tailwind custom reset styles */ /** * 1. Use the user's configured `sans` font-family (with Tailwind's default * sans-serif font stack as a fallback) as a sane default. * 2. Use Tailwind's default "normal" line-height so the user isn't forced * to override it to ensure consistency even when using the default theme. */ html { font-family: Montserrat, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 1 */ line-height: 1.5; /* 2 */ } /** * Inherit font-family and line-height from `html` so users can set them as * a class directly on the `html` element. */ body { font-family: inherit; line-height: inherit; } /** * 1. Prevent padding and border from affecting element width. * * We used to set this in the html element and inherit from * the parent element for everything else. This caused issues * in shadow-dom-enhanced elements like
where the content * is wrapped by a div with box-sizing set to `content-box`. * * https://github.com/mozdevs/cssremedy/issues/4 * * * 2. Allow adding a border to an element by just adding a border-width. * * By default, the way the browser specifies that an element should have no * border is by setting it's border-style to `none` in the user-agent * stylesheet. * * In order to easily add borders to elements by just setting the `border-width` * property, we change the default border-style for all elements to `solid`, and * use border-width to hide them instead. This way our `border` utilities only * need to set the `border-width` property instead of the entire `border` * shorthand, making our border utilities much more straightforward to compose. * * https://github.com/tailwindcss/tailwindcss/pull/116 */ *, ::before, ::after { box-sizing: border-box; /* 1 */ border-width: 0; /* 2 */ border-style: solid; /* 2 */ border-color: currentColor; /* 2 */ } /* * Ensure horizontal rules are visible by default */ hr { border-top-width: 1px; } /** * Undo the `border-style: none` reset that Normalize applies to images so that * our `border-{width}` utilities have the expected effect. * * The Normalize reset is unnecessary for us since we default the border-width * to 0 on all elements. * * https://github.com/tailwindcss/tailwindcss/issues/362 */ img { border-style: solid; } textarea { resize: vertical; } input::-moz-placeholder, textarea::-moz-placeholder { opacity: 1; color: #9ca3af; } input:-ms-input-placeholder, textarea:-ms-input-placeholder { opacity: 1; color: #9ca3af; } input::placeholder, textarea::placeholder { opacity: 1; color: #9ca3af; } button, [role="button"] { cursor: pointer; } /** * Override legacy focus reset from Normalize with modern Firefox focus styles. * * This is actually an improvement over the new defaults in Firefox in our testing, * as it triggers the better focus styles even for links, which still use a dotted * outline in Firefox by default. */ table { border-collapse: collapse; } h1, h2, h3, h4, h5, h6 { font-size: inherit; font-weight: inherit; } /** * Reset links to optimize for opt-in styling instead of * opt-out. */ a { color: inherit; text-decoration: inherit; } /** * Reset form element properties that are easy to forget to * style explicitly so you don't inadvertently introduce * styles that deviate from your design system. These styles * supplement a partial reset that is already applied by * normalize.css. */ button, input, optgroup, select, textarea { padding: 0; line-height: inherit; color: inherit; } /** * Use the configured 'mono' font family for elements that * are expected to be rendered with a monospace font, falling * back to the system monospace stack if there is no configured * 'mono' font family. */ pre, code, kbd, samp { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; } /** * 1. Make replaced elements `display: block` by default as that's * the behavior you want almost all of the time. Inspired by * CSS Remedy, with `svg` added as well. * * https://github.com/mozdevs/cssremedy/issues/14 * * 2. Add `vertical-align: middle` to align replaced elements more * sensibly by default when overriding `display` by adding a * utility like `inline`. * * This can trigger a poorly considered linting error in some * tools but is included by design. * * https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210 */ img, svg, video, canvas, audio, iframe, embed, object { display: block; /* 1 */ vertical-align: middle; /* 2 */ } /** * Constrain images and videos to the parent width and preserve * their intrinsic aspect ratio. * * https://github.com/mozdevs/cssremedy/issues/14 */ img, video { max-width: 100%; height: auto; } /** * Ensure the default browser behavior of the `hidden` attribute. */ [hidden] { display: none; } *, ::before, ::after { --tw-border-opacity: 1; border-color: rgba(229, 231, 235, var(--tw-border-opacity)); } .container { width: 100%; } @media (min-width: 640px) { .container { max-width: 640px; } } @media (min-width: 768px) { .container { max-width: 768px; } } @media (min-width: 1024px) { .container { max-width: 1024px; } } @media (min-width: 1280px) { .container { max-width: 1280px; } } @media (min-width: 1536px) { .container { max-width: 1536px; } } .prose { color: #374151; max-width: 65ch; } .prose a { color: #111827; text-decoration: underline; font-weight: 500; } .prose strong { color: #111827; font-weight: 600; } .prose ol[type="a"] { --list-counter-style: lower-alpha; } .prose ol[type="a" s] { --list-counter-style: lower-alpha; } .prose ol[type="I"] { --list-counter-style: upper-roman; } .prose ol[type="i"] { --list-counter-style: lower-roman; } .prose ol[type="I" s] { --list-counter-style: upper-roman; } .prose ol[type="i" s] { --list-counter-style: lower-roman; } .prose ol[type="1"] { --list-counter-style: decimal; } .prose ol > li { position: relative; padding-left: 1.75em; } .prose ol > li::before { content: counter(list-item, var(--list-counter-style, decimal)) "."; position: absolute; font-weight: 400; color: #6b7280; left: 0; } .prose ul > li { position: relative; padding-left: 1.75em; } .prose ul > li::before { content: ""; position: absolute; background-color: #d1d5db; border-radius: 50%; width: 0.375em; height: 0.375em; top: calc(0.875em - 0.1875em); left: 0.25em; } .prose hr { border-color: #e5e7eb; border-top-width: 1px; margin-top: 3em; margin-bottom: 3em; } .prose blockquote { font-weight: 500; font-style: italic; color: #111827; border-left-width: 0.25rem; border-left-color: #e5e7eb; quotes: "\201C""\201D""\2018""\2019"; margin-top: 1.6em; margin-bottom: 1.6em; padding-left: 1em; } .prose blockquote p:first-of-type::before { content: open-quote; } .prose blockquote p:last-of-type::after { content: close-quote; } .prose h1 { color: #111827; font-weight: 800; font-size: 2.25em; margin-top: 0; margin-bottom: 0.8888889em; line-height: 1.1111111; } .prose h2 { color: #111827; font-weight: 700; font-size: 1.5em; margin-top: 2em; margin-bottom: 1em; line-height: 1.3333333; } .prose h3 { color: #111827; font-weight: 600; font-size: 1.25em; margin-top: 1.6em; margin-bottom: 0.6em; line-height: 1.6; } .prose h4 { color: #111827; font-weight: 600; margin-top: 1.5em; margin-bottom: 0.5em; line-height: 1.5; } .prose figure figcaption { color: #6b7280; font-size: 0.875em; line-height: 1.4285714; margin-top: 0.8571429em; } .prose code { color: #111827; font-weight: 600; font-size: 0.875em; } .prose code::before { content: "`"; } .prose code::after { content: "`"; } .prose a code { color: #111827; } .prose pre { color: #e5e7eb; background-color: #1f2937; overflow-x: auto; font-size: 0.875em; line-height: 1.7142857; margin-top: 1.7142857em; margin-bottom: 1.7142857em; border-radius: 0.375rem; padding-top: 0.8571429em; padding-right: 1.1428571em; padding-bottom: 0.8571429em; padding-left: 1.1428571em; } .prose pre code { background-color: transparent; border-width: 0; border-radius: 0; padding: 0; font-weight: 400; color: inherit; font-size: inherit; font-family: inherit; line-height: inherit; } .prose pre code::before { content: none; } .prose pre code::after { content: none; } .prose table { width: 100%; table-layout: auto; text-align: left; margin-top: 2em; margin-bottom: 2em; font-size: 0.875em; line-height: 1.7142857; } .prose thead { color: #111827; font-weight: 600; border-bottom-width: 1px; border-bottom-color: #d1d5db; } .prose thead th { vertical-align: bottom; padding-right: 0.5714286em; padding-bottom: 0.5714286em; padding-left: 0.5714286em; } .prose tbody tr { border-bottom-width: 1px; border-bottom-color: #e5e7eb; } .prose tbody tr:last-child { border-bottom-width: 0; } .prose tbody td { vertical-align: top; padding-top: 0.5714286em; padding-right: 0.5714286em; padding-bottom: 0.5714286em; padding-left: 0.5714286em; } .prose { font-size: 1rem; line-height: 1.75; } .prose p { margin-top: 1.25em; margin-bottom: 1.25em; } .prose img { margin-top: 2em; margin-bottom: 2em; } .prose video { margin-top: 2em; margin-bottom: 2em; } .prose figure { margin-top: 2em; margin-bottom: 2em; } .prose figure > * { margin-top: 0; margin-bottom: 0; } .prose h2 code { font-size: 0.875em; } .prose h3 code { font-size: 0.9em; } .prose ol { margin-top: 1.25em; margin-bottom: 1.25em; } .prose ul { margin-top: 1.25em; margin-bottom: 1.25em; } .prose li { margin-top: 0.5em; margin-bottom: 0.5em; } .prose > ul > li p { margin-top: 0.75em; margin-bottom: 0.75em; } .prose > ul > li > *:first-child { margin-top: 1.25em; } .prose > ul > li > *:last-child { margin-bottom: 1.25em; } .prose > ol > li > *:first-child { margin-top: 1.25em; } .prose > ol > li > *:last-child { margin-bottom: 1.25em; } .prose ul ul, .prose ul ol, .prose ol ul, .prose ol ol { margin-top: 0.75em; margin-bottom: 0.75em; } .prose hr + * { margin-top: 0; } .prose h2 + * { margin-top: 0; } .prose h3 + * { margin-top: 0; } .prose h4 + * { margin-top: 0; } .prose thead th:first-child { padding-left: 0; } .prose thead th:last-child { padding-right: 0; } .prose tbody td:first-child { padding-left: 0; } .prose tbody td:last-child { padding-right: 0; } .prose > :first-child { margin-top: 0; } .prose > :last-child { margin-bottom: 0; } .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; } .absolute { position: absolute; } .relative { position: relative; } .mx-auto { margin-left: auto; margin-right: auto; } .mt-2 { margin-top: 0.5rem; } .mt-3 { margin-top: 0.75rem; } .mt-4 { margin-top: 1rem; } .mt-5 { margin-top: 1.25rem; } .mt-8 { margin-top: 2rem; } .mr-1 { margin-right: 0.25rem; } .mr-2 { margin-right: 0.5rem; } .block { display: block; } .inline-block { display: inline-block; } .flex { display: flex; } .table { display: table; } .grid { display: grid; } .hidden { display: none; } .h-1 { height: 0.25rem; } .h-2 { height: 0.5rem; } .h-5 { height: 1.25rem; } .h-6 { height: 1.5rem; } .h-12 { height: 3rem; } .h-16 { height: 4rem; } .h-2\.5 { height: 0.625rem; } .h-full { height: 100%; } .min-h-screen { min-height: 100vh; } .w-2 { width: 0.5rem; } .w-5 { width: 1.25rem; } .w-6 { width: 1.5rem; } .w-9 { width: 2.25rem; } .w-12 { width: 3rem; } .w-auto { width: auto; } .w-2\.5 { width: 0.625rem; } .w-full { width: 100%; } .max-w-5xl { max-width: 64rem; } .max-w-7xl { max-width: 80rem; } .flex-1 { flex: 1 1 0%; } .flex-shrink-0 { flex-shrink: 0; } .transform { --tw-translate-x: 0; --tw-translate-y: 0; --tw-rotate: 0; --tw-skew-x: 0; --tw-skew-y: 0; --tw-scale-x: 1; --tw-scale-y: 1; transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } @-webkit-keyframes spin { to { transform: rotate(360deg); } } @keyframes spin { to { transform: rotate(360deg); } } @-webkit-keyframes ping { 75%, 100% { transform: scale(2); opacity: 0; } } @keyframes ping { 75%, 100% { transform: scale(2); opacity: 0; } } @-webkit-keyframes pulse { 50% { opacity: .5; } } @keyframes pulse { 50% { opacity: .5; } } @-webkit-keyframes bounce { 0%, 100% { transform: translateY(-25%); -webkit-animation-timing-function: cubic-bezier(0.8,0,1,1); animation-timing-function: cubic-bezier(0.8,0,1,1); } 50% { transform: none; -webkit-animation-timing-function: cubic-bezier(0,0,0.2,1); animation-timing-function: cubic-bezier(0,0,0.2,1); } } @keyframes bounce { 0%, 100% { transform: translateY(-25%); -webkit-animation-timing-function: cubic-bezier(0.8,0,1,1); animation-timing-function: cubic-bezier(0.8,0,1,1); } 50% { transform: none; -webkit-animation-timing-function: cubic-bezier(0,0,0.2,1); animation-timing-function: cubic-bezier(0,0,0.2,1); } } .cursor-pointer { cursor: pointer; } .grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } .flex-row-reverse { flex-direction: row-reverse; } .flex-col { flex-direction: column; } .items-center { align-items: center; } .justify-end { justify-content: flex-end; } .justify-center { justify-content: center; } .justify-between { justify-content: space-between; } .gap-2 { gap: 0.5rem; } .space-x-3 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(0.75rem * var(--tw-space-x-reverse)); margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse))); } .space-x-4 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(1rem * var(--tw-space-x-reverse)); margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); } .space-x-5 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(1.25rem * var(--tw-space-x-reverse)); margin-left: calc(1.25rem * calc(1 - var(--tw-space-x-reverse))); } .space-x-6 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(1.5rem * var(--tw-space-x-reverse)); margin-left: calc(1.5rem * calc(1 - var(--tw-space-x-reverse))); } .space-y-5 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(1.25rem * calc(1 - var(--tw-space-y-reverse))); margin-bottom: calc(1.25rem * var(--tw-space-y-reverse)); } .overflow-hidden { overflow: hidden; } .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .rounded-md { border-radius: 0.375rem; } .rounded-full { border-radius: 9999px; } .border { border-width: 1px; } .border-r { border-right-width: 1px; } .border-b-2 { border-bottom-width: 2px; } .border-b { border-bottom-width: 1px; } .border-transparent { border-color: transparent; } .border-gray-200 { --tw-border-opacity: 1; border-color: rgba(229, 231, 235, var(--tw-border-opacity)); } .border-gray-300 { --tw-border-opacity: 1; border-color: rgba(209, 213, 219, var(--tw-border-opacity)); } .border-brand { --tw-border-opacity: 1; border-color: rgba(242, 182, 50, var(--tw-border-opacity)); } .border-brand-gray-2 { --tw-border-opacity: 1; border-color: rgba(235, 238, 241, var(--tw-border-opacity)); } .bg-white { --tw-bg-opacity: 1; background-color: rgba(255, 255, 255, var(--tw-bg-opacity)); } .bg-gray-800 { --tw-bg-opacity: 1; background-color: rgba(31, 41, 55, var(--tw-bg-opacity)); } .bg-brand { --tw-bg-opacity: 1; background-color: rgba(242, 182, 50, var(--tw-bg-opacity)); } .bg-brand-light { --tw-bg-opacity: 1; background-color: rgba(255, 198, 1, var(--tw-bg-opacity)); } .bg-brand-gray-1 { --tw-bg-opacity: 1; background-color: rgba(249, 250, 250, var(--tw-bg-opacity)); } .bg-brand-gray-2 { --tw-bg-opacity: 1; background-color: rgba(235, 238, 241, var(--tw-bg-opacity)); } .bg-brand-gray-10 { --tw-bg-opacity: 1; background-color: rgba(37, 40, 57, var(--tw-bg-opacity)); } .bg-brand-green { --tw-bg-opacity: 1; background-color: rgba(91, 188, 46, var(--tw-bg-opacity)); } .object-cover { -o-object-fit: cover; object-fit: cover; } .object-center { -o-object-position: center; object-position: center; } .p-1 { padding: 0.25rem; } .p-6 { padding: 1.5rem; } .p-12 { padding: 3rem; } .px-4 { padding-left: 1rem; padding-right: 1rem; } .px-6 { padding-left: 1.5rem; padding-right: 1.5rem; } .px-8 { padding-left: 2rem; padding-right: 2rem; } .py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; } .py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; } .py-6 { padding-top: 1.5rem; padding-bottom: 1.5rem; } .py-8 { padding-top: 2rem; padding-bottom: 2rem; } .py-10 { padding-top: 2.5rem; padding-bottom: 2.5rem; } .py-12 { padding-top: 3rem; padding-bottom: 3rem; } .py-14 { padding-top: 3.5rem; padding-bottom: 3.5rem; } .py-20 { padding-top: 5rem; padding-bottom: 5rem; } .text-center { text-align: center; } .font-sans { font-family: Montserrat, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; } .text-xs { font-size: 0.75rem; line-height: 1rem; } .text-sm { font-size: 0.875rem; line-height: 1.25rem; } .text-base { font-size: 1rem; line-height: 1.5rem; } .text-lg { font-size: 1.125rem; line-height: 1.75rem; } .text-xl { font-size: 1.25rem; line-height: 1.75rem; } .text-3xl { font-size: 1.875rem; line-height: 2.25rem; } .font-extralight { font-weight: 200; } .font-light { font-weight: 300; } .font-medium { font-weight: 500; } .font-semibold { font-weight: 600; } .uppercase { text-transform: uppercase; } .tracking-wide { letter-spacing: 0.025em; } .text-white { --tw-text-opacity: 1; color: rgba(255, 255, 255, var(--tw-text-opacity)); } .text-gray-100 { --tw-text-opacity: 1; color: rgba(243, 244, 246, var(--tw-text-opacity)); } .text-gray-300 { --tw-text-opacity: 1; color: rgba(209, 213, 219, var(--tw-text-opacity)); } .text-gray-400 { --tw-text-opacity: 1; color: rgba(156, 163, 175, var(--tw-text-opacity)); } .text-brand { --tw-text-opacity: 1; color: rgba(242, 182, 50, var(--tw-text-opacity)); } .text-brand-light { --tw-text-opacity: 1; color: rgba(255, 198, 1, var(--tw-text-opacity)); } .text-brand-gray-3 { --tw-text-opacity: 1; color: rgba(114, 128, 141, var(--tw-text-opacity)); } .text-brand-gray-4 { --tw-text-opacity: 1; color: rgba(164, 174, 183, var(--tw-text-opacity)); } .text-brand-gray-9 { --tw-text-opacity: 1; color: rgba(35, 45, 54, var(--tw-text-opacity)); } .text-brand-green { --tw-text-opacity: 1; color: rgba(91, 188, 46, var(--tw-text-opacity)); } .hover\:text-gray-500:hover { --tw-text-opacity: 1; color: rgba(107, 114, 128, var(--tw-text-opacity)); } .underline { text-decoration: underline; } .hover\:underline:hover { text-decoration: underline; } .antialiased { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .hover\:opacity-75:hover { opacity: 0.75; } *, ::before, ::after { --tw-shadow: 0 0 #0000; } .shadow { --tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } .shadow-md { --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } *, ::before, ::after { --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; } @media (min-width: 640px) { .sm\:px-6 { padding-left: 1.5rem; padding-right: 1.5rem; } } @media (min-width: 768px) { .md\:flex { display: flex; } .md\:w-1\/4 { width: 25%; } .md\:flex-row { flex-direction: row; } .md\:flex-col { flex-direction: column; } .md\:justify-start { justify-content: flex-start; } .md\:justify-between { justify-content: space-between; } .md\:px-4 { padding-left: 1rem; padding-right: 1rem; } .md\:text-lg { font-size: 1.125rem; line-height: 1.75rem; } } @media (min-width: 1024px) { .lg\:mx-0 { margin-left: 0px; margin-right: 0px; } .lg\:mt-0 { margin-top: 0px; } .lg\:block { display: block; } .lg\:inline-block { display: inline-block; } .lg\:flex { display: flex; } .lg\:hidden { display: none; } .lg\:h-screen { height: 100vh; } .lg\:w-auto { width: auto; } .lg\:w-1\/3 { width: 33.333333%; } .lg\:w-2\/3 { width: 66.666667%; } .lg\:max-w-md { max-width: 28rem; } .lg\:items-center { align-items: center; } .lg\:justify-between { justify-content: space-between; } .lg\:space-x-6 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(1.5rem * var(--tw-space-x-reverse)); margin-left: calc(1.5rem * calc(1 - var(--tw-space-x-reverse))); } .lg\:overflow-scroll { overflow: scroll; } .lg\:p-6 { padding: 1.5rem; } .lg\:px-8 { padding-left: 2rem; padding-right: 2rem; } .lg\:py-0 { padding-top: 0px; padding-bottom: 0px; } .lg\:py-1 { padding-top: 0.25rem; padding-bottom: 0.25rem; } .lg\:text-left { text-align: left; } } @media (min-width: 1280px) { .xl\:w-2\/5 { width: 40%; } .xl\:w-3\/5 { width: 60%; } .xl\:gap-4 { gap: 1rem; } } @media (min-width: 1536px) { .\32xl\:mt-6 { margin-top: 1.5rem; } .\32xl\:mt-10 { margin-top: 2.5rem; } .\32xl\:mt-16 { margin-top: 4rem; } .\32xl\:w-1\/2 { width: 50%; } .\32xl\:p-10 { padding: 2.5rem; } .\32xl\:text-lg { font-size: 1.125rem; line-height: 1.75rem; } .\32xl\:text-2xl { font-size: 1.5rem; line-height: 2rem; } .\32xl\:text-5xl { font-size: 3rem; line-height: 1; } } ================================================ FILE: docs/assets/app.source.css ================================================ @import "tailwindcss/base"; @import "tailwindcss/components"; @import "tailwindcss/utilities"; ================================================ FILE: docs/build.sh ================================================ #!/bin/sh NODE_ENV=production ./node_modules/.bin/postcss ./assets/app.source.css -o ./assets/app.css bundle exec jekyll build ================================================ FILE: docs/dev.sh ================================================ #!/bin/sh bundle exec jekyll serve --livereload --drafts --future --port 5000 --livereload_port 35729 "$@" ================================================ FILE: docs/index.md ================================================ --- layout: home --- ================================================ FILE: docs/package.json ================================================ { "name": "docs", "version": "1.0.0", "devDependencies": { "@fullhuman/postcss-purgecss": "^4.0.2", "@tailwindcss/line-clamp": "^0.2.0", "@tailwindcss/typography": "^0.4.0", "autoprefixer": "^10.2.5", "cssnano": "^4.1.10", "postcss": "^8.2.10", "postcss-cli": "^8.3.1", "postcss-import": "^14.0.0", "tailwindcss": "^2.0.3" }, "dependencies": { "yarn": "^1.22.17" } } ================================================ FILE: docs/postcss.config.js ================================================ module.exports = { plugins: { 'postcss-import': {}, tailwindcss: {}, autoprefixer: {}, } } ================================================ FILE: docs/posts.html ================================================ --- layout: posts ---

Posts

    {% for post in site.posts %}
  • {% assign date_format = site.minima.date_format | default: "%b %-d, %Y" %}

    {{ post.title | escape }}

  • {% endfor %}
================================================ FILE: docs/scripts/alexa.py ================================================ import base64 import collections import hashlib import hmac import os import re import urllib.error import urllib.parse import xml.etree.ElementTree as ET import requests from aws_requests_auth.aws_auth import AWSRequestsAuth rank_search = re.compile("(.*?)") def get_awi_url_info(url): access_key = os.environ.get("AWS_ACCESS_KEY_ID") secret_key = os.environ.get("AWS_SECRET_ACCESS_KEY") params = { 'Action': 'UrlInfo', 'ResponseGroup': "Rank", 'Url': url } ordered_params = collections.OrderedDict(sorted(params.items())) query_params = "&".join( ["%s=%s" % (k, urllib.parse.quote(v, '[^A-Za-z0-9\-_.~]')) for k, v in ordered_params.items()]) auth = AWSRequestsAuth(access_key, secret_key, "awis.us-west-1.amazonaws.com", 'us-west-1', 'awis') query_url = f"https://awis.us-west-1.amazonaws.com/api?{query_params}" result = requests.get(url=query_url, auth=auth) return ET.fromstring(result.content) def download_aws_rank(url): result = get_awi_url_info(url).findtext(".//{http://awis.amazonaws.com/doc/2005-07-11}Rank") if result: return int(result) else: return 10_000_000 def get_rank(url): url_without = url.replace("www.", "") if "www." in url: return min(download_aws_rank(url_without), download_aws_rank(url)) else: return download_aws_rank(url) ================================================ FILE: docs/scripts/download_favicons.py ================================================ #!python3 """ This script downloads the favicons Usage: python3 update_alexa path/to/data.csv """ import os import requests favicon_path = os.path.join(os.path.dirname(__file__), "..", "icons") def download_favicons(links): for link in links: netloc = link['netloc'] url = 'http://' + netloc new_favicon_path = os.path.join(favicon_path, netloc + ".ico") if not os.path.exists(new_favicon_path): try: print(url) response = requests.get( "https://realfavicongenerator.p.rapidapi.com/favicon/icon", params={'platform': 'desktop', "site": url}, headers={'X-Mashape-Key': os.environ.get("mashape_key")} ) except: pass else: if response: with open(new_favicon_path, 'wb') as f: f.write(response.content) ================================================ FILE: docs/scripts/sites_history_script.py ================================================ from pathlib import Path import pandas import pydriller from git import Repo import io repo_path = Path(__file__).parent.parent.parent site_data = repo_path / "docs" / "_data" / "sites.csv" repo = Repo(str(repo_path)) df = None def get_change_hashes(): for commit in pydriller.RepositoryMining(str(repo_path), filepath='docs/_data/sites.csv').traverse_commits(): yield commit.hash, commit.author_date for hash, date in get_change_hashes(): commit = repo.commit(hash) try: target_file = commit.tree / "docs" / "_data" / "sites.csv" except KeyError: continue with io.BytesIO(target_file.data_stream.read()) as f: new_df = pandas.read_csv(f) new_df['date'] = date if df is None: df = new_df else: df = pandas.concat([df, new_df]) df.to_csv("ranking_history.csv") ================================================ FILE: docs/scripts/update.py ================================================ #!python3 """ This script updates the alexa rankings and sort the csv file. Usage: python3 update.py """ import csv import sys import os import itertools import math import alexa from download_favicons import download_favicons sites_path = os.path.join(os.path.dirname(__file__), "..", "_data", "sites.csv") update_blank_only = os.environ.get("update_blank_only", "false") == "true" def add_commas_to_rank(number): if number: if isinstance(number, str): number = remove_commas(number) return "{:,}".format(number) def round_rank(rank: int): return round(rank, 1 - (1 + int(math.log10(abs(rank))))) def remove_commas(string_number): return int(string_number.replace(",", "")) def update_alexa(links): for link in links: link['rank'] = add_commas_to_rank(link['rank']) if link['rank'] and update_blank_only: continue print("Updating {}.. ".format(link['netloc']), end="") sys.stdout.flush() rank = alexa.get_rank(link['netloc']) if rank: link['rank'] = add_commas_to_rank(round_rank(rank)) print(link['rank']) return links def get_groups(links): links.sort(key=lambda _: _['section']) for group_name, group_data in itertools.groupby(links, lambda _: _['section']): group_data = list(group_data) group_data.sort(key=lambda _: remove_commas(_['rank'])) yield group_name, group_data def get_groups_in_order(links): rank_sorted_groups = dict(get_groups(links)) for group in ["Clients", "Tutoring", "Other", "Agency", "Jobs"]: yield from rank_sorted_groups[group] def sort(links): return list(get_groups_in_order(links)) def main(func): with open(sites_path, 'r') as csvfile: links = list(csv.DictReader(csvfile)) links = func(links) if not links: return with open(sites_path, 'w') as csvfile: fieldnames = list(links[0].keys()) writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() writer.writerows(links) if __name__ == "__main__": main(update_alexa) main(sort) main(download_favicons) ================================================ FILE: docs/tailwind.config.js ================================================ const defaultTheme = require("tailwindcss/defaultTheme"); module.exports = { purge: [ './_includes/**/*.html', './_layouts/**/*.html', './_posts/*.md', './*.html', ], darkMode: false, theme: { extend: { colors :{ 'brand' : '#F2B632', 'brand-light' : '#FFC601', 'brand-gray' : { 1 : '#F9FAFA', 2 : '#EBEEF1', 3 : '#72808D', 4 : '#A4AEB7', 9 : '#232D36', 10 : '#252839', }, 'brand-green' : '#5BBC2E' }, fontFamily: { sans: ["Montserrat", ...defaultTheme.fontFamily.sans] } }, }, variants: {}, plugins: [ require('@tailwindcss/typography'), require('@tailwindcss/line-clamp'), ], }