{"componentChunkName":"component---src-templates-page-tsx","path":"/page/1","result":{"pageContext":{"searchData":[{"id":"cjjg9ui0t303s010375m42b9w","title":"Turn a Browser Window into a Notepad with This One-Liner","slug":"/turn-a-browser-window-into-a-notepad-with-this-one-liner","avatar":"https://s3.amazonaws.com/contentkit/static/cjjg9ui0t303s010375m42b9w/OYIaJ1KK_400x400(1).png","date":"July 1, 2020"},{"id":"cjiy7xl9o17w701039gvl18a5","title":"Creating a Collaborative Editor with Draftjs for Fun","slug":"/draft-js-collaborative-editor","avatar":"https://s3.amazonaws.com/contentkit/static/cjiy7xl9o17w701039gvl18a5/draft-js.png","date":"June 28, 2020"},{"id":"cjeqgfsdsnmx90167n7j290kt","title":"How To Include SASS In Your React Project","slug":"/sass-react-webpack","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfsdsnmx90167n7j290kt/parcel-bundler.png","date":"May 1, 2020"},{"id":"cjiy4tseq0tnw0103bc5s7sxj","title":"How to Add a Loading Indicator to Material Ui's Component","slug":"/creating-a-material-ui-button-with-spinner-that-reflects-loading-state","avatar":"https://s3.amazonaws.com/contentkit/static/cjiy4tseq0tnw0103bc5s7sxj/material-ui.png","date":"January 28, 2020"},{"id":"cjkq4u7470ihr0157ad175b12","title":"Connecting to AWS Lambda via WebSockets","slug":"/connecting-to-aws-lambda-via-websockets","avatar":"https://s3.amazonaws.com/contentkit/static/cjkq4u7470ihr0157ad175b12/MQTT.js.png","date":"January 12, 2020"},{"id":"cjeqgfnhknnpe0199zbfwwkd8","title":"6 Really Cool APIs to Have Fun With","slug":"/cool-apis-to-have-fun-with","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfnhknnpe0199zbfwwkd8/scale-api.png","date":"January 1, 2020"},{"id":"cjeqgftvknnr30199dvw266qh","title":"Installing Node Canvas in AWS Lambda","slug":"/node-canvas-aws-lambda","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgftvknnr30199dvw266qh/aws-lambda.jpg","date":"December 31, 2019"},{"id":"cjn5fv8kl0pfj0124wwebufms","title":"GoLang Cheatsheet","slug":"/golang-cheatsheet","avatar":"https://s3.amazonaws.com/contentkit/static/cjn5fv8kl0pfj0124wwebufms/golang.png","date":"October 13, 2019"},{"id":"cjn15y8740liw0175u3s707eh","title":"Scheduled Jobs & Work Queues With Postgresql","slug":"/scheduled-jobs-work-queues-with-postgresql","avatar":"https://s3.amazonaws.com/contentkit/static/cjn15y8740liw0175u3s707eh/kxHkAenZ_400x400.jpg","date":"October 8, 2019"},{"id":"cjmym86fh0jy1013398nfzuqu","title":"Creating a Bot to Refill Parking Meters Using AWS Lambda","slug":"/creating-a-bot-to-refill-parking-meters-using-aws-lambda","avatar":"https://s3.amazonaws.com/contentkit/static/cjmym86fh0jy1013398nfzuqu/prwHMlRn_400x400.jpg","date":"October 7, 2019"},{"id":"cjmsaqt6l09le01046qeukpp9","title":"The USPS Tracking API: How To Track Packages","slug":"/usps-tracking-api","avatar":"https://s3.amazonaws.com/contentkit/static/cjmsaqt6l09le01046qeukpp9/usps.png","date":"October 3, 2019"},{"id":"cjeqgfuyenmy20167rycnmiql","title":"Stormpath vs Firebase - A Side-By-Side Comparison","slug":"/stormpath-vs-firebase-a-side-by-side-comparison","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfuyenmy20167rycnmiql/m3cEA33V_400x400.jpg","date":"September 2, 2019"},{"id":"cjeqgfv88nnrt01997wxd4rnl","title":"Sending emails with Firebase Cloud Functions","slug":"/firebase-functions-sending-emails","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfv88nnrt01997wxd4rnl/firebase.jpg","date":"September 2, 2019"},{"id":"cjeqgfqjknnq20199oe3zwi37","title":"Deploying To DigitalOcean From Travis","slug":"/deploying-to-digitalocean-travis","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfqjknnq20199oe3zwi37/digitalocean.jpeg","date":"August 25, 2019"},{"id":"cjkvpbr6p06z50181fg7xvsc3","title":"Circumventing AWS Lambda's Bundle Size Limit","slug":"/circumventing-aws-lambdas-bundle-size-limit","avatar":"https://s3.amazonaws.com/contentkit/static/cjkvpbr6p06z50181fg7xvsc3/b2lWK7c0_400x400.png","date":"August 15, 2019"},{"id":"cjiy45h7m0iba0111f5imt5em","title":"A Quick Way to List All Unicode Characters (Javascript)","slug":"/unicode-characters-javascript","avatar":"https://s3.amazonaws.com/contentkit/static/cjiy45h7m0iba0111f5imt5em/unicode.png","date":"July 29, 2019"},{"id":"ci1rxc41tm8yi7nd156pz9dom","title":"Kibana Rest API","slug":"/kibana-rest-api","avatar":"https://s3.amazonaws.com/contentkit/static/ci1rxc41tm8yi7nd156pz9dom/elastic.png","date":"July 24, 2019"},{"id":"cjeqgfjgennmw0199wha3j6u0","title":"Airtable As A Database For Middleman [Tutorial]","slug":"/airtable-middleman-database","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfjgennmw0199wha3j6u0/airtable-books.png","date":"June 1, 2019"},{"id":"cjeqgfj5qnnmr0199vzd85xuo","title":"Building A Multiplayer Game With Three.Js + WebSockets","slug":"/multiplayer-game-threejs","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfj5qnnmr0199vzd85xuo/three.jpg","date":"June 1, 2019"},{"id":"cjeqgfi8hnnml0199f1jyo1p5","title":"The Best Sketch Plugins","slug":"/the-best-sketch-plugins","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfi8hnnml0199f1jyo1p5/sketch.png","date":"June 1, 2019"},{"id":"d9920hsu8y7365frf2c6fxrx2","title":"Configuring Vault by Hashicorp in AWS EC2","slug":"/configuring-vault-by-hashicorp-in-aws-ec2","avatar":"https://s3.amazonaws.com/contentkit/static/d9920hsu8y7365frf2c6fxrx2/vault.png","date":"April 15, 2019"},{"id":"cjeqgfvsfnns00199mlbff48i","title":"Best Zapier Alternatives","slug":"/best-zapier-alternatives","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfvsfnns00199mlbff48i/zapier-alternative-workato.png","date":"January 31, 2019"},{"id":"cjn3l18390lyt0158i8qxs5dc","title":"Running A Simple Node Web Server On AWS EC2","slug":"/running-a-simple-node-web-server-on-aws-ec2","avatar":"https://s3.amazonaws.com/contentkit/static/cjn3l18390lyt0158i8qxs5dc/aws.png","date":"October 11, 2018"},{"id":"cjeqgfr4snmwz01673m8l4i51","title":"Graph.Cool vs Firebase","slug":"/graphcool-vs-firebase","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfr4snmwz01673m8l4i51/graphcool.png","date":"October 7, 2018"},{"id":"cjklurup00k0201739mflg9sz","title":"Accessing Redis on an Aws EC2 Instance from the Outside\t","slug":"/accessing-redis-on-an-aws-ec2-instance-from-the-outside","avatar":"https://s3.amazonaws.com/contentkit/static/cjklurup00k0201739mflg9sz/logo.jpeg","date":"August 9, 2018"},{"id":"cjkfzvvxt08up0191l38aadq4","title":"Using PDFtk in AWS Lamba","slug":"/using-pdftk-in-aws-lamba","avatar":"https://s3.amazonaws.com/contentkit/static/cjkfzvvxt08up0191l38aadq4/pdftk.png","date":"August 4, 2018"},{"id":"cjeqgfqsgnnq70199l4vc6vim","title":"Configuring WebSockets on Elastic Beanstalk/EC2","slug":"/websockets-aws-elasticbeanstalk-ec2","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfqsgnnq70199l4vc6vim/aws.png","date":"July 15, 2018"},{"id":"cjit96q2yk0is0111qpbmw66s","title":"Getting Started With Gmail API","slug":"/gmail-api-quickstart","avatar":"https://s3.amazonaws.com/contentkit/static/cjit96q2yk0is0111qpbmw66s/gmail.png","date":"June 28, 2018"},{"id":"cjeqgfo23nmwd0167ynqe7xi8","title":"5 Tips For Using NextJs","slug":"/5-tips-for-using-nextjs","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfo23nmwd0167ynqe7xi8/bHjpwZem_400x400.png","date":"June 1, 2018"},{"id":"cjhxixcyhw4ze01035butoukz","title":"React unstable_deferredUpdates","slug":"/react-unstable_deferredupdates","avatar":"https://s3.amazonaws.com/contentkit/static/cjhxixcyhw4ze01035butoukz/OYIaJ1KK_400x400(1).png","date":"June 1, 2018"},{"id":"cjeqgflpnnnoy01993y7aez8a","title":"Simple Web Scraping With Javascript","slug":"/simple-web-scraping","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgflpnnnoy01993y7aez8a/developer-tools-scraping.png","date":"May 1, 2018"},{"id":"cjeqgfk9lnnn101994ll4ursr","title":"Easy: Add Firebase Facebook Login To Your React App","slug":"/firebase-facebook-login-react","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfk9lnnn101994ll4ursr/firebase.png","date":"May 1, 2018"},{"id":"cjeqgfiqrnmtj0167dmz5g5dg","title":"The 5 Best Static Site Web Hosts","slug":"/the-5-best-static-site-web-hosts","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfiqrnmtj0167dmz5g5dg/digital-ocean.png","date":"May 1, 2018"},{"id":"cjeqgfmi2nmvs01670pgebekn","title":"Tips and Tricks For Using NightmareJs","slug":"/nightmare-js","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfmi2nmvs01670pgebekn/nightmare.png","date":"May 1, 2018"},{"id":"cjeqgfkqennn60199707yp1fb","title":"Why You Should Create Your Next React Web App With Firebase","slug":"/firebase-react-tutorial","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfkqennn60199707yp1fb/firebase.jpg","date":"May 1, 2018"},{"id":"cjeqgfpr6nnpx019978qzmaok","title":"How to Flush Data From Heroku Redis","slug":"/heroku-redis-flushall","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfpr6nnpx019978qzmaok/3wgIDj3j_400x400.png","date":"April 1, 2018"},{"id":"cjeqgfm8xnnp30199vxndhkgh","title":"5 Ways To Style React Components","slug":"/5-ways-to-style-react-components","avatar":null,"date":"April 1, 2018"},{"id":"cjeqgflz7nmvm0167yo7wsjg3","title":"Delete Spreadsheet Rows For Google Sheets","slug":"/delete-rows-google-sheets","avatar":null,"date":"April 1, 2018"},{"id":"cjeqgfp84nnps0199dvru09ll","title":"Make An Uptime Monitoring Microservice In Under 50 Lines of Code","slug":"/twilio-uptime-monitoring-node-tutorial","avatar":null,"date":"April 1, 2018"},{"id":"cjeqgfri4nnqd0199zsv6a9fl","title":"Hexo - The Best Static Site Generator? ","slug":"/deploy-a-hexo-blog","avatar":null,"date":"April 1, 2018"},{"id":"cjeqgfoygnnpn0199f31dgk9m","title":"Airtable As A Minimum Viable Database For Your ReactJs Project","slug":"/airtable-reactjs","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfoygnnpn0199f31dgk9m/airtable-screenshot.png","date":"March 2, 2018"},{"id":"cjeqgfn6pnmw0016793f81hpx","title":"The Advanced Guide To ReactJs Checkboxes","slug":"/reactjs-checkboxes","avatar":null,"date":"January 20, 2018"},{"id":"cjeqgfe8znnly01991jo5xkxx","title":"Minimum Viable GraphQL QuickStart","slug":"/minimum-viable-graphql-quickstart","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfe8znnly01991jo5xkxx/graphcool-schema.png","date":"January 1, 2018"},{"id":"cjeqgfgegnnmb0199jp3hv2xx","title":"How To Add A Contact Form To Your Ghost Blog","slug":"/ghost-blog-contact-form","avatar":null,"date":"November 1, 2017"},{"id":"cjeqgfmvxnnp90199bdti4r8n","title":"PHP Scraping Tutorial - Scrape Reddit With Goutte","slug":"/php-scraping-tutorial-scrape-reddit-with-goutte","avatar":null,"date":"October 7, 2017"},{"id":"cjeqgfpz1nmwp0167c5j46eij","title":"Cannot read property 'loose' of undefined","slug":"/cannot-read-property-loose-of-undefined","avatar":null,"date":"August 25, 2017"},{"id":"cjeqgftlanmxg0167zipvfzp1","title":"Airtable API Example & Tutorial - Generating Charts","slug":"/airtable-api-example-tutorial","avatar":null,"date":"January 31, 2017"},{"id":"cjeqgfphbnmwk0167ldz2mv2q","title":"React onClick Example and Tutorial","slug":"/react-onclick-example-and-tutorial","avatar":null,"date":"January 2, 2017"},{"id":"cjeqgfq8ynmwu0167z6c51ynp","title":"React Tables - How To Render Tables In ReactJS","slug":"/reactjs-tables","avatar":null,"date":"January 2, 2017"},{"id":"cjeqgfuoznmxu0167ayt2zkc3","title":"How To Add A Class in ReactJS","slug":"/reactjs-add-class","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgfu6gnnrb0199nyrddra0","title":"Fetching Github Blame with the GraphQL API V4","slug":"/github-blame-graphql-api-v4","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgfsmsnnqo0199o2x7dl4x","title":"How To Add Meta Descriptions to Middleman Pages","slug":"/middleman-meta-descriptions","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgfs2wnnqi0199rco2vvz2","title":"Zapier Webhook Post Example & Tutorial","slug":"/zapier-webhook-post-example-tutorial","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgfvhunmy90167t6ouqfmb","title":"Setting Up A Job Queue For A Node App [Tutorial]","slug":"/job-queue-node","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgftbcnnqy0199nc1f92te","title":"NextJs vs Create-React-App - A Side-By-Side Comparison","slug":"/nextjs-vs-create-react-app","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgft2pnnqt01990ty8fmeu","title":"How To Create A Modal In ReactJS [Tutorial]","slug":"/reactjs-modal","avatar":null,"date":"March 14, 2018"},{"id":"cjeqgfugpnnrj0199x7anb33t","title":"How To Use Twilio With ReactJS","slug":"/reactjs-twilio-example-tutorial","avatar":null,"date":"March 14, 2018"}],"page":1,"offset":5,"total":57,"nodes":[{"id":"cjeqgfnhknnpe0199zbfwwkd8","title":"6 Really Cool APIs to Have Fun With","slug":"cool-apis-to-have-fun-with","published_at":"2020-01-01T05:00:00","created_at":"2018-03-14T02:16:35","excerpt":"Some of the most fun I've had with Javascript has involved combining publicly available APIs in int","image":{"id":"cjfxj3t8i55ot0169n1qnaf35","url":"static/cjeqgfnhknnpe0199zbfwwkd8/scale-api.png"},"posts_tags":[{"tag":{"id":"7bqseccu1tz3st4fd51z","name":"Lob"}}],"date":"January 1, 2020","html":"
Some of the most fun I've had with Javascript has involved combining publicly available APIs in interesting ways.
\nThe instant gratification of APIs got me hooked on hobby projects and helped me learn Javascript without even realizing it. If you have an itch to make something or expand your knowledge but don't know what to build, experimenting with APIs is a great place to start.
\nHere are some of the publically accessible APIs that I've played with for inspiration.
\nWhat is Lob?
\nLob is snail mail as a service. Lob enables postcards, letters, invoices, and checks to be sent programmatically.
\nI live in a tiny apartment and refuse to get a printer because they take up a lot of space. I only need to print like 5 documents a year. So I started using Lob as a proxy for printing. I issue a POST request to lob's /letters endpoint with a url to your document, and I get a printout in the mail a few days later.
\nI think there's a lot of fun to be had with APIs that provide a physical service.
\nLob can print and ship PDF and html documents and is pretty cheap (pricing starts around $1 + 10 cents a page).
\nScale is kind of like a Amazon Mechanical Turk with a smooth API reminiscent of Stripe.
\nThose tasks that can't be automated you can break down into units and delegate to Scale's mercenary workforce. Need a human to scan a comment and tell you whether it's spam? With Scale it's just a matter of issuing a post request with the task details and deadline. There is something very appealing about an API for human intelligence tasks.
\nTo use Scale's API you need to be pretty granular about the task. For example, I used Scale to handle exceptions when scrapings Amazon product pages. When the scraper couldn't find the information it was looking for, my application would create a new Scale task asking a laborer to look at the product page and check to see if the information was presented differently.
\nSome human intelligence tasks can't easily be broken into discrete units. Such tasks aren't well-suited to Scale. Also, Scale isn't cheap and tasks are obviously not completed instantaneously. When you create a task you provide a webhook URL that gets pinged when the task is done.
\nGmail's API was a bitch to work with. It has lots of quirks and authorization via service accounts vs tokens was poorly documented. However, once you're up and running it was a blast to use Gmail's API.
\nI wanted to use the Gmail api to programmatically filter all messages that aren't from actual people. At the time I had 5000+ unread messages. It was just too painful to sift through them. So I made a more aggressive version of what Gmail already does with the Promotions tab.
\nGoogle has slowly sunsetted programmatic access to their search results pages. The Google search API is slowly being phased out and was prohibitively expensive to begin with.
\nYou know when you starting typing a query Google lists some best guesses about what you're after in the search input field? You can unofficially fetch these suggestions.
\nMy use case was hunting for available exact match domain names based on some seed keyword. So if you were interested in antique cars, you'd start with that keyword, fetch the suggestions from Google's undocumented autosuggest API and then run each suggestion against a domain registrar for availability.
\nGoogle Flights API shutdown recently with little advanced warning.
\nIt's surprisingly difficult to find reliable flight information if you don't have deep pockets and aren't a big brand.
\nSkyscanner's API is one of the few remaining ways for the hobbyist to gain access to flight information.
\nThe folks behind Graph.Cool developed Chromeless to solve the problem of headless browsing encapsulated by a lambda function.
\nMaybe you've heard of Nightmare.js?
\nNightmare is a wrapper around electron with a nice, chainable API that lets you programmatically do things in a browser window. Some of nightmare's use-cases are application testing, screenshotting, scraping, etc. It's trivially easy to navigate to an arbitrary web page with nightmare and take a screenshot.
\nRunning nightmare locally is straightforward but it's a pain to run on AWS, Digital Ocean, etc. It would be much cleaner to run nightmare in lambda than a customized EC2 instance or Digital Ocean droplet. The problem is nightmare's dependency on electron which results in a massize bundle size.
\nChromeless solves this problem by duplicating nightmare's slick API but instead depends on chromium instead of electron.
\nThe crazy thing is that you don't even need to run a specific sequence of commands in a lambda function.
\nChromeless enables you to deploy a remote client that will execute any command you send it. On your local machine or web server you establish a WebSocket connection with your remote lambda client and start issuing commands. Behind the scenes theses commands are sent to your Chromeless remote as JSON.
\nTwilio belongs on this list because there are all sorts of cool things you can do by interfacing with SMS. I started experimenting with Twilio to send myself SMS reminders.
","avatar":"https://s3.amazonaws.com/contentkit/static/cjeqgfnhknnpe0199zbfwwkd8/scale-api.png"},{"id":"cjeqgftvknnr30199dvw266qh","title":"Installing Node Canvas in AWS Lambda","slug":"node-canvas-aws-lambda","published_at":"2019-12-31T05:00:00","created_at":"2018-03-14T02:16:43","excerpt":" Using node-canvas on AWS Lambda can be a pain because node-canvas has dependencies. A simple yarn ","image":{"id":"cjfwjtmf1177g01692ug3tzwl","url":"static/cjeqgftvknnr30199dvw266qh/aws-lambda.jpg"},"posts_tags":[{"tag":{"id":"3pl7ejawubufz70vjnad","name":"AWS"}},{"tag":{"id":"2spo553zykbgxgq4vkk3","name":"Javascript"}}],"date":"December 31, 2019","html":"Using node-canvas on AWS Lambda can be a pain because node-canvas has dependencies. A simple yarn add or npm install will not suffice.
\n\nAutomattic's node-canvas extends the familiar canvas API in the browser to Node. With node-canvas you can draw shapes, apply text and overlay images. The data types node-canvas interfaces with are interchangeable. For example, you can apply text and images to a canvas and stream the canvas PDF, png, jpg, array buffer, and so forth.
\nAWS Lambda is runs on Amazon's special flavor of linux.
\nNode-canvas requires a few packages like Cairo and Pango to function. To get Node-canvas up and running on AWS lambda, you need to compile native libraries in an identical EC2 instance. Next, copy the binaries from the server to your local machine and include them in your package that you upload to AWS lambda.
\nThe quick and dirty solution is to git clone this repo: https://github.com/unshift/canvas-lambda.git
\nThe lib directory includes the .so files and a latest, precompiled version of canvas (v1.6.7 - the latest as of this writing).
\nThe trick to getting AWS lambda to recognize the path to the native modules is to modify the environmental variables PATH, LD_LIBRARY_PATH, PKG_CONFIG_PATH.
\nprocess.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT'] + '/lib';\nprocess.env['LD_LIBRARY_PATH'] = process.env['LAMBDA_TASK_ROOT'] + '/lib';\nprocess.env['PKG_CONFIG_PATH'] = process.env['LAMBDA_TASK_ROOT'] + '/lib';
\nNext, drop the binaries in the lib directory of the root of your lambda function, e.g.:
\nUse this bash script to install dependencies: https://gist.github.com/unshift/cdebd9a1da98816514789b62cbe7797d
\ninstall_node_canvas_binaries.sh installs the following at /canvas/:
\nNext it copies the native modules to /var/task/lib.
\n/var/task is where Lambda functions live.
\nThe last step is to npm install canvas (discussed below).
\nsudo su -.
sudo yum install nodejs npm --enablerepo=epel
cd /tmp\nwget https://gist.githubusercontent.com/unshift/cdebd9a1da98816514789b62cbe7797d/raw/57a11195bb6ab9aae13dc4f97eec8ce2b0b5a771/install_node_canvas_binaries.sh\nsh install_node_canvas_binaries.sh\ncd /var/task/lib\nnpm install canvas\ncd node_modules/canvas\nnode-gyp rebuild
\ntype Data struct {\n Id string `json:\"id\"`\n}\nvar data Data\njson.Unmarshal(\"{ \\\"id\\\": \\\"123\\\" }\", &data)
\ntype Data struct {}\nvar data = Data{}\nstr, _ := json.Marshal(data)
\ntype Data struct {\n Id int\n}\nvar data Data{Id: 123}\nfmt.Printf(\"%+v\\n\", data)
\nout, _ := exec.Commmand(\"ls\").Output()
\nfunc main() {\n http.HandleFunc(func (w http.ResponseWriter, r *http.Request) {\n w.Write([]byte(\"ok\"))\n })\n err := http.ListenAndServe(\":1234\", nil)\n if err != nil {\n fmt.Println(err)\n }\n}
\nres, _ := ioutil.ReadFile(\"/tmp/test.txt\")\nfmt.Println(string(res))
\nres, _ := ioutil.WriteFile(\"/tmp/test.txt\", []byte(\"Hello\"), 0644)
\nargs := os.Args[1:]
\nfunc main() {\n numbers := []int{1, 2, 3}\n for x, y := range numbers {\n fmt.Println(x, y)\n }\n}
\nfunc main() {\n done := make(chan bool, 1)\n tick := time.Tick(1 * time.Second)\n timeout := time.After(5 * time.Second)\n go func() {\n for {\n select {\n case <-tick:\n fmt.Println(\"tick\")\n case <-timeout:\n done <- true\n fmt.Println(\"timeout!\")\n return \n }\n }\n }()\n <-done\n}
\nfunc fetch() {\n res, _ := http.Get(\"https://jsonplaceholder.typicode.com/todos/1\")\n body, _ := ioutil.ReadAll(res.Body)\n raw := string(body)\n return raw\n}
\nbody := strings.NewReader(\"{ \\\"message\\\": \\\"ok\\\" }\")\nhttp.Post(\"http://requestbin.fullcontact.com/1hp80td1\", \"application/json\", body)
\nstr := \"ab cd ef\"\narr := strings.Split(str, \" \")
","avatar":"https://s3.amazonaws.com/contentkit/static/cjn5fv8kl0pfj0124wwebufms/golang.png"},{"id":"cjn15y8740liw0175u3s707eh","title":"Scheduled Jobs & Work Queues With Postgresql","slug":"scheduled-jobs-work-queues-with-postgresql","published_at":"2019-10-08T04:00:00","created_at":"2018-10-09T03:26:12","excerpt":"With the help of an extension or two, it's easy to use Postgresql for scheduled work.","image":{"id":"nhxb5t4oodinrq9cqrg6y39gw","url":"static/cjn15y8740liw0175u3s707eh/kxHkAenZ_400x400.jpg"},"posts_tags":[{"tag":{"id":"4u88cmgqidmqnv2ucke8","name":"Posstgres"}}],"date":"October 8, 2019","html":"With the help of an extension or two, it's easy to use Postgresql for scheduled work.
\nFor example, using the extensions pg_cron and pgsql-http, you can issue a post request to a web service at regular intervals:
\n\ncron.schedule accepts two arguments, (1) the cron schedule expression and (2) the dollar-quoted sql script to be executed.
\nWhile it's inadvisable to be interacting with web services in postgresql triggers, using pgsql-http in a Postgresql cron job is a perfect use-case.
\nNote that the above code snippet only works after installing pgsql-http and pg_cron:
\n\nFor pg_cron, you'll also need to edit postgres.conf by uncommenting shared_preload_libraries and setting it to 'pg_cron' and adding a line that specifies the database that should be used by pg_cron (e.g., cron.database_name = 'postgres').
\npg_cron uses the familiar crontab syntax. You can view cron jobs like so:
\nselect * from cron.job;
\nAlso don't forget that you can debug the output of cron jobs at /var/lib/pgsql/10/data/log (assuming that you've installed postgresql 10).
","avatar":"https://s3.amazonaws.com/contentkit/static/cjn15y8740liw0175u3s707eh/kxHkAenZ_400x400.jpg"},{"id":"cjmym86fh0jy1013398nfzuqu","title":"Creating a Bot to Refill Parking Meters Using AWS Lambda","slug":"creating-a-bot-to-refill-parking-meters-using-aws-lambda","published_at":"2019-10-07T04:00:00","created_at":"2018-10-07T08:38:32","excerpt":"I decided to make a bot that tops off the parking meter for me - here's how.","image":{"id":"a3unw65b88o5hj757k1va1afn","url":"static/cjmym86fh0jy1013398nfzuqu/prwHMlRn_400x400.jpg"},"posts_tags":[{"tag":{"id":"3pl7ejawubufz70vjnad","name":"AWS"}}],"date":"October 7, 2019","html":"I get a shameful number of parking tickets from failing to refill parking meters on time. So one day I decided to make a bot that tops off the parking meter for me. Yes, I'm probably breaking some terms and conditions. But for now that's a risk I'm willing to accept.
\nSo here's the situation. My car is parked on the street in a suburb of Washington DC. I need to refill the parking meter every two hours. These meters limit the parking reservation limit to two hours. So every two hours during business hours (9 AM to 6 PM, Monday to Friday) I need to refill the meter.
\nParkMobile is one of a few apps that allow you to pay for parking on a device. But even with a convenience of re-reserving your parking space remotely from your computer of phone, it's still a pain to do every two hours on weekdays.
\nHere's what the ParkMobile UI looks like for reserving a parking space:
\n\nIt's not too complicated at first glance.
\nYou just need to set the zone id, select a location, selection a parking duration, select a time block and then click start parking.
\nI opted to use chromeless to automate reserving a parking space. Chromeless is a browser automation library with an API akin to nightmare.js that uses Chrome Canary instead of Electron.
\nMy rationale for using Chromeless is that I wanted to run the lot in AWS Lambda and not locally on my machine for obvious reasons.
\nThe hardest part turned out to be logging in to ParkMobile. I encountered the following obstacles automating the login flow:
\nHere's what the code looks like for logging in:
\nconst INPUT = {\n LOGIN: 'input#ctl00_ContentPlaceHolder1_UcUserLoginControl1_userName',\n PASSWORD: 'input#ctl00_ContentPlaceHolder1_UcUserLoginControl1_password'\n}\nconst login = async (chromeless) => {\n let cookies = await chromeless\n .setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36')\n .goto('https://parkmobile.io/login')\n .cookies()\n await chromeless\n .goto('https://dlweb.parkmobile.us/Phonixx/')\n .setCookies(cookies)\n .type(process.env.LOGIN, INPUT.LOGIN)\n .type(process.env.PASSWORD, INPUT.PASSWORD)\n .wait(500)\n .evaluate(() => {\n WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ContentPlaceHolder1$UcUserLoginControl1$lbLogon\", \"\", true, \"\", \"\", false, true))\n })\n}
\nThe code above logins into ParkMobile. Here's what it looks like when run:\n
\n\nI won't bore you with the remaining implementation details. In brief I deployed the project to AWS lambda using serverless. I scheduled it to run every 5 minutes and used redis to keep track of state. I also used Twilio to send myself confirmation text messages every time the space was reserved.
\nAWS lambda makes cron jobs trivially easy:
\nfunctions:\n handler:\n events:\n - schedule: rate(5 minutes)
\nFor the curious, here is the github repository for the project.
","avatar":"https://s3.amazonaws.com/contentkit/static/cjmym86fh0jy1013398nfzuqu/prwHMlRn_400x400.jpg"}]}}}