-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 PGP Key Transition Statement José Padilla Fri Jul 28 12:54:01 UTC 2017 I have created a new OpenPGP key and will be transitioning away from my old key. The old key has not been compromised and will continue to be valid for some time, but I prefer all future correspondence to be encrypted to the new key, and will be making signatures with the new key going forward. I would like this new key to be re-integrated into the web of trust. This message is signed by both keys to certify the transition. My new and old keys are signed by each other. If you have signed my old key, I would appreciate signatures on my new key as well, provided that your signing policy permits that without re-authenticating me. The old key, which I am transitioning away from, is: pub 2048R/9B2987B1 2014-03-04 Key fingerprint = 6120 BB14 9792 D8E9 A371 B03C AAE3 EF57 9B29 87B1 The new key, to which I am transitioning, is: pub 4096R/B55434E2 2017-07-28 Key fingerprint = 58FD 4723 5047 E944 BDE3 4DC7 9A11 1405 B554 34E2 I disown all other and prior keys, so please don't use them. Specifically, the following keys are not valid for me: * 0x33CFB6D79478C173 * 0x56921E75F4A66D4C * 0x7C09FCF380E5AFA3 * 0x55FCA69C27265701 * 0xAAE3EF579B2987B1 (as provided above) The entire key may be downloaded from: https://keybase.io/jpadilla/pgp_keys.asc?fingerprint=58fd47235047e944bde34dc79a111405b55434e2 To fetch the full new key from a public key server using GnuPG, run: gpg --keyserver keys.gnupg.net --recv-key B55434E2 If you already know my old key, you can now verify that the new key is signed by the old one: gpg --check-sigs B55434E2 If you are satisfied that you've got the right key, and the User IDs match what you expect, I would appreciate it if you would sign my key: gpg --sign-key B55434E2 You can upload your signatures to a public keyserver directly: gpg --keyserver pgp.mit.edu --send-key B55434E2 Or email [email protected] (possibly encrypted) the output from: gpg --armor --export B55434E2 If you'd like any further verification or have any questions about the transition please contact me directly. /jpadilla -----BEGIN PGP SIGNATURE----- iQEcBAEBCgAGBQJZezRFAAoJEKrj71ebKYexuL0H/RG388KJwp+fWA8hR0jMrSFX OC4zgsMB6GLsSiZJhivDvYTXJdcFc2x6l9Cgh4YQTZwsDLsK2O7+Ao+AxcUAC5rQ zb2UIX6GzEly7i7+2HNKpv2AKcpdI5yNwuvjvTJMeivDAnSr9ymSTkbzIMyUuGkh bEuIodVuuf0jvrgECw8I8DLsyKPt3KkVPYjc1Ji3Q0w0uVtQhndvaD1Etc7wO3Vw h28Rkw7a6bK8Dt/ZmC+PI50/rKMDWPlSV2+ATCpitKZrDvEyk843d4ue39NaZ6uo rKLn6Fv0kZLZzX2VnEi64TKUfu7s2LzTOoKLT4km6M2ExcT7rj84nNlPCZrICluJ AhwEAQEKAAYFAll7NEUACgkQN2XJ6h5H7264vRAAtn7Z3rey+Hsi1g7tBEeYs0wY pjrn3hPQ5Ej1A+V5kpZuTH0Hh8TaW1LxmClRLE0jmMZV9bhRbCfyG9GMaSFeJp1W NXZAfXW2vtNurCKgsyBJhtk1MNZg7pbURvcaXifq+gt/Z7UZ6X/YlAfPLsmp22e+ wVA7i0TUlXYcQOtNwhhDD2N/hoG1lMgB2XkC8uzvRIOn06kSneFORzegyeK60rBw GdbzhuQrkzqZ0inhuEIXzDHFA7yIfOKg3aabx4Mc/K++42iy+bBZzx9UDHGoKay3 RSdnzRNCiQAL2S0Ckk+qo56rHzTqsz0XFtaLdMjp/c58knrLnVekMnPMJMXnnxwj dAzV31Lyxk4VZomw2z2PA/1R/C9bY2msJ5hCggqICguwM2bnRzn17mEawwAKTY0S rCK/744woagAa57muhVZyQk7eVXKxiS7EVjNGVM83jk0hwuUBv+v55Zawi3hm8fL RUMXwxIkv+HHD76x//mBmLOrjkdHMlZ1WyPiOFbRQrthpUabZ3V27h7IObsOZcbv S9e5hh69jEcOZffL/I5iuu4zc6Wcq3F7G5oiMoVGPUSUQUxhZtZX9OK1PzrMQezw 2ejhY3+1ktS5rsPTMw6qjiei0E0MIa+Yluw2u6CeT7oxQlJXuSFKCQB1CAnEOE/l iWstOpXJiOkvoLtMrPM= =hyse -----END PGP SIGNATURE-----
Update Kubernetes Deployment after pushing image to Docker Hub
I recently moved FilePreviews.io’s workers deployment to Kubernetes in Google Container Engine. After setting the workers up as a Deployment I wondered how this would fit with my current setup for continuous deployment. On a previous setup, I relied on Docker Hub to automatically build, push tagged images, and notify Rancher via a webhook.
I ended up writing a small server to handle the webhook event from Docker Hub and PATCH the container’s image tags in the Kubernetes deployment which triggers a rollout.
These are the slides for my PyCaribbean 2017 keynote on Developer Ergonomics where I talk about the current state of package managers in Python vs in other ecosystems like Node and Rust.
On March 12th, I married my high school sweetheart. We’d been together for around 9 years and engaged for like 4 of those. Best day ever.
During the last quarter of 2015, we cofounded Alias Payments to build Gasolina Móvil. We became part of Parallel18′s first cohort and after six months we were closing a deal with PumaEnergy.
On August, my wife and I packed our things and moved to Hartford, CT for her doctoral internship. Its our first time living away from Puerto Rico, but we’re making it work. I’m still finding the right balance when working mostly from home. Since living in the East Coast, we drove to Québec City for my wife’s birthday, visited beautiful Boston way too many times, spent Thanksgiving in NYC with new friends, visited Stars Hollow(Washington Depot, CT), hiked some local trails, visited the casino at Mohegan Sun and more.
During 2016, Blimp was rebranded as a consulting company with products of it’s own. We knew we could help more companies and digital agencies build awesome things and we did. We made our first two hires, a developer and a project manager. We’ve worked on many interesting consulting projects during this year and the next couple of months look very promising.
Moving forward
During the past couple of months I’ve had to split my time between consulting projects and our ongoing products. I let this constant context switching burn me out constantly for a while there. As a result of this, I’ll start dedicating most of my time to our products and phase out from the consulting part of the business.
There’s no doubt I love building products and somewhere in there is where I’m best at and have the most impact. This is why it makes the most sense to me to spend more time doing so.
Last year I also contributed way less to open source projects, mostly because of the lack of time. Looking forward to have some more time again to do so.
On February, I’ll be speaking at PyCaribbean. If you haven’t get your tickets now, this year it’ll be happening in Puerto Rico!
On March, I’ll be attending EmberConf with @gcollazo.
Sometime later in 2017, my wife is graduating. Hello future Dr. Conde-Padilla PsyD. I’m very proud of you!
Here’s to family and friends, being healthy, happy, and better, more learning, more reading. Here’s to 2017.
Upload files to S3 and generate previews using Laravel
I recently put together a PHP client library for FilePreviews and immediately thought about putting together a blog post on how I’d use it. After 6 years, according to this repo, of not writing a single line of PHP, I looked into Laravel since it seems to be the rave these days. Alright, let’s get to it.
This is a step by step guide on how to use Laravel to upload files to S3, and generate previews and extract metadata using FilePreviews.io. If you are already uploading files to S3 with Laravel, check out how to integrate with FilePreviews.
Create a Laravel project
I’m assuming you’ll probably have composer already installed.
We'll use sqlite in this example instead of Laravel's default which is MySQL. Set DB_CONNECTION to sqlite in your project's .env file.
You'll also need to create an empty sqlite database file: storage/database.sqlite.
Model
Now we need to create a Document model. Our Document model will have a name, file(a URL on S3 to our original file), preview_url(a URL to a preview generated by FilePreviews), and preview(a JSON string containing all the results and metadata generated by FilePreviews.
First we'll generate our model and it's pertaining migration file.
$ php artisan make:model Document --migration
We need to add the rest of our fields to that migration before running it. You'll find the migration inside the database/migrations directory. It'll be named something like 2015_11_25_125309_create_documents_table.php.
Make sure the up() function looks like the following.
public function up() { Schema::create('documents', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('file'); $table->string('preview_url')->nullable(); $table->json('preview')->nullable(); $table->timestamps(); }); }
Now run your migrations.
$ php artisan migrate
Controllers
Our simple application will allow you to list existing documents and create new ones. To simplify things a bit we'll generate a resource controller.
Next we'll configure our controller's functions, index which will render our list of documents, and create which will render our form.
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Document; use App\Http\Requests; use App\Http\Controllers\Controller; class DocumentController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { $documents = Document::all(); return view('documents.index', compact('documents')); } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { return view('documents.create'); } }
Note: Make sure to import/alias our Document model by adding use App\Document;. Things like this always got me.
Views
Now our controller is missing the templates/views for both index and create.
Create resources/views/documents/index.blade.php. All this view does is list created documents, showing the id, name, and preview_url if available. We'll also add a link to our create route.
Create resources/views/documents/create.blade.php. All this view does is show any errors with the form, and allow submitting a form with a file input field.
Note: Make sure the form has the correct enctype or else you'll have issues uploading files.
Uploading to S3 and storing Document
Now the fun starts! Let's add the store function to our DocumentController.
<?php namespace App\Http\Controllers; use Storage; use Illuminate\Http\Request; use App\Document; use App\Http\Requests; use App\Http\Controllers\Controller; class DocumentController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { $documents = Document::all(); return view('documents.index', compact('documents')); } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { return view('documents.create'); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $this->validate($request, [ 'file' => 'required' ]); $file = $request->file('file'); if ($file->isValid()) { $name = $file->getClientOriginalName(); $key = 'documents/' . $name; Storage::disk('s3')->put($key, file_get_contents($file)); $document = new Document; $document->name = $name; $document->file = $key; $document->save(); } return redirect('documents'); } }
Note: Make sure to import/alias our Document model by adding use Storage;.
A couple of things going on here, let's break it down.
Validate our file field is present.
Make sure file is valid.
Store file in S3. This file stored on S3 are private by default, meaning that we'll need to generate a temporary URL to access them.
Create Document using file name and key where file was stored in S3.
Redirect to /documents.
Since our files are stored privately on S3 we'll need a way to generate that temporary secure URL to access them. A good place to add this is in our model. We'll append a dynamic property to our model called url. By using the underlying AWS client library, we can create a presigned URL that expires in 20 minutes. We access this property like any other, e.g. $document->url.
<?php namespace App; use Storage; use Config; use Illuminate\Database\Eloquent\Model; class Document extends Model { protected $appends = ['url']; public function getUrlAttribute() { return $this->getFileUrl($this->attributes['file']); } private function getFileUrl($key) { $s3 = Storage::disk('s3'); $client = $s3->getDriver()->getAdapter()->getClient(); $bucket = Config::get('filesystems.disks.s3.bucket'); $command = $client->getCommand('GetObject', [ 'Bucket' => $bucket, 'Key' => $key ]); $request = $client->createPresignedRequest($command, '+20 minutes'); return (string) $request->getUri(); } }
If you run php artisan serve and navigate to http://localhost:8000/documents/create, pick a file, and submit, you should be redirected to http://localhost:8000/documents. You'll now see the created Document. If you click on the file's name you should be redirected to your file on S3 using our presigned URL. Success!
So we still haven't actually done anything with FilePreviews at this point. This example until nows serves as an idea of what most people would be actually doing already. Now we'll see how FilePreviews fits into all this.
Integrating with FilePreviews.io
We've put together a package that'll help you implement FilePreviews in your Laravel projects. Let's install that.
To customize the configuration file, publish the package configuration by running php artisan vendor:publish.
Signup for a FilePreviews.io account by going to https://api.filepreviews.io/auth/signup/. Create a free application and get your Server API Key and Server API Secret from you application's settings. Add those to your project's .env.
Now we need to request generating a preview after our file has been uploaded and our Document created. Let's add a function to our model which will then call from our controller.
We're asking FilePreviews to generate a request for a file, extract the file's checksum and OCR. We're also adding our document id. We'll use this later so we can identify what preview/metadata belongs to what document.
After creating our document, we are calling our $document->requestPreview() to let FilePreviews know what we want.
If you run php artisan serve and navigate to http://localhost:8000/documents/create, pick a file, and submit, you should be redirected to http://localhost:8000/documents. You'll now see the created Document, but you'll still see "No Preview". Why is that?
If you recall our requestPreview() function we call $fp->generate($url, $options);. This lets FilePreviews know what we want extracted from our file, we get a confirmation, but no results just yet. This is a fire and forget operation, since it could possibly take a few minutes depending on the file size and requested metadata. We could poll FilePreviews for our results but that's not really efficient. This is why FilePreviews allows you to subscribe to your application's webhook by setting a Callback URL.
Webhooks
Let's go ahead and setup our application to handle webhooks. With filepreviews-laravel this is really easy. Add the following route to app/Http/routes.php:
Since FilePreviews webhooks need to bypass Laravel's CSRF verification, be sure to list the URI as an exception in your app/Http/MiddlewareVerifyCsrfToken.php middleware:
<?php namespace App\Http\Middleware; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier; class VerifyCsrfToken extends BaseVerifier { /** * The URIs that should be excluded from CSRF verification. * * @var array */ protected $except = [ 'filepreviews/webhook' ]; }
The FilePreviews webhook controller we registered fires two events: filepreviews.success and filepreviews.error. Let's create a Listener(app/Listeners/FilePreviewsSuccess.php) to handle the filepreviews.success event.
<?php namespace App\Listeners; use Event; use App\Document; class FilePreviewsSuccess { /** * Handle the event. * * @param array $results * @return void */ public function handle($results) { $document_id = $results['user_data']['document_id']; $document = Document::find($document_id); $document->preview_url = $results['preview']['url']; $document->preview = json_encode($results); $document->save(); } }
Let's setup the event listener mappings for this application in app/Providers/EventServiceProvider.php.
Our listener will react to the filepreviews.success event, look for a Document that matches document_id and update it.
To try this out locally I recommend using something like ngrok.
With php artisan serve running, on another tab/window run ngrok localhost:8000. Setup ngrok's forwarding URL as your Callback URL on your FilePreviews application's settings. Once that's done navigate to http://localhost:8000/documents/create, pick a file, and submit. In a few seconds you should see a request logged in ngrok with the status 200 OK. If you then navigate to http://localhost:8000/documents you should see a link "Preview" instead of "No Preview". Click that and you'll see an image of the file you previously uploaded. Super cool stuff, right?
Bonus: Realtime with Pusher
Just because I'm really liking Laravel, I'll show you how to add some realtime goodness using Pusher to what we already have working. Once we're done we won't need to refresh to see whenever our documents get previews.
Let's add support for broadcasting events to Pusher.
$ composer require pusher/pusher-php-server
Go signup for a free account on Pusher, create an app, and set credentials in your project's .env.
Let's create an event app/Events/FilePreviewsGenerated.php. This event will broadcast on the filepreviews channel an event called filepreviews.generated
<?php namespace App\Events; use Illuminate\Queue\SerializesModels; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use App\Events\Event; use App\Document; class FilePreviewsGenerated extends Event implements ShouldBroadcast { use SerializesModels; public $document; /** * Create a new event instance. * * @return void */ public function __construct(Document $document) { $this->document = $document; } /** * Get the channels the event should be broadcast on. * * @return array */ public function broadcastOn() { return ['filepreviews']; } /** * Get the broadcast event name. * * @return string */ public function broadcastAs() { return 'filepreviews.generated'; } }
We'll tweak our FilePreviewsSuccess.php listener to fire a FilePreviewsGenerated event after saving our document.
<?php namespace App\Listeners; use Event; use App\Document; use App\Events\FilePreviewsGenerated; class FilePreviewsSuccess { /** * Handle the event. * * @param array $results * @return void */ public function handle($results) { $document_id = $results['user_data']['document_id']; $document = Document::find($document_id); $document->preview_url = $results['preview']['url']; $document->preview = json_encode($results); $document->save(); Event::fire(new FilePreviewsGenerated($document)); } }
All that's left is add the Pusher JavaScript code on our index view.
Programmers solve problems and most of the time use a keyboard to do so.
I firmly believe you need to be able to efficiently express yourself through typing. There’s probably nothing more fundamental in programming than being able to think of something and expressing it in code without losing your train of thought.
I say efficiently and not perfectly. You don’t have to be the fastest typist in the west but speed helps. I could make up a couple of “imagine a surgeon that didn’t know the way around a scalpel” or “a baseball player that didn’t know how to swing” but I wont, you probably get the picture.
I was lucky enough to take typing lessons back in computer class in school. They gave use those orange covers you placed on top of the keyboard to hide all the keys. We’d use this with Mavis Beacon Teaches Typing and some other variation as a fun game. While most people lifted up the cover while the teacher wasn’t looking I just simply dealt with the damn thing and learned how to type instead of hunt and peck typing my way through it.
Before trying to become a great programmer, I suggest spending some time practicing, after all the only way to become a touch typist is through typing quite a lot. Check out: Typing.io, Mavis Beacon Teaches Typing for Mac, Typing.lk.
Next you time you go to a programming workshop, you’ll be able to look at whatever the instructor is doing up front while you type, keeping up with everyone just fine.
A month ago I decided to take another stab at proposing a solution to allow all of us to keep working on great programming workshops.
Personally, the biggest headache in each and every one of the workshops that I have organized or participated in is the time and effort it takes to configure and setup the attendees' computers. This results in attendees and instructors loosing valuable time that can be spent actually sharing knowledge. Various other people have shared the same worries and feelings about this, so might as well try and do something about it.
Juice Box is virtual machine with a common environment that every workshop attendee can download and use before ever getting to the actual workshop.
What's installed by default in Juice Box
Git
Python 2.7 with pip, virtualenv, and virtualenvwrapper
io.js with nvm
MongoDB
Redis
PostgreSQL
Docker
Sublime Text 3
Google Chrome
Firefox
What this project is trying to accomplish
Provide the most simple instructions possible so that attendees at every level can get started easily.
Reduce the need of a great network connection during the event.
Guarantee that all attendees have the same environment, tools and applications, making the process easier for all.
Reuse the same virtual machine between different groups and workshops.
Distribution
We built OVA files for Juice Box which allows us to simply distribute one file that contains the virtual machine. This file can be imported to VirtualBox with few clicks. We'll be building and uploading each release so attendees can just download the resulting OVA file. We've optimized the size of this file to achieve the smallest size possible but I'm sure it could be better. It's smaller than an MP4 movie "shared" on TPB. Organizers might now require attendees to bring their Juice Box already downloaded and imported. Obviously, we might still have users that couldn't download it, so just have a few USB flash drives with VirtualBox downloads for different operating systems and Juice Box's OVA file.
InstallFests
Technical workshops shouldn't be about installing a development environment in Linux, Windows, OS X, or whatever else. Unless that's what they are about, this takes way to much time from everyone and it's a pain. I propose that we organize InstallFests, events that are specific to helping users install development environments into their preferred operating system.
Open Source
Juice Box is completely open source under The MIT License and everything used to create the virtual machine is available on GitHub. If you're a workshop organizer, make sure you "watch" the repository, this way you'll get notified of new releases.
Feedback
Go download Juice Box and try it out out. This project might not be the best or correct solution, but it's a start. Thanks to everyone that has already provided feedback. I'd love keep the conversation going and to have more feedback on this, wether you're a workshop organizer or usually an attendee.
Sponsor
This project is sponsored by Blimp, a software products design and development agency. Blimp also organizes community workshops like Ember.js Puerto Rico and private trainings.
Logo by Jomarie Alvelo. Website and design by Giovanni Collazo.
Update
Just released v1.2.0! Juice Box now has support for Ruby with RVM.
Three weeks ago today, on an unfortunate accident, Mako my 6 year old Siberian Husky escaped from home, and we noticed just a couple of hours later. After endless hours, driving around different possible routes, talking to people, calling out his name, posting hundreds of flyers, hundreds of people sharing on Facebook and Twitter, we haven’t found him yet.
Mako is more than a dog or pet to me, he’s a loyal friend, and we’ve been through a lot. This past weeks have been eternally tough for us. We’re still looking for him every day, we’re still receiving calls of people who’ve seen similar dogs around, I drive with my windows down in hope of hearing that beautiful distinct howl. We’re hopeful that perhaps a loving and caring family found him, rescued him, and has fallen in love with him. But we’re still not giving up.
While our search continues, we’ve brought along a new addition to the family to help. He’s not a substitute or replacement, nor is he a way to forget. Ana thought he’d be of great company, and surprised me with him. She was right and I’m so glad she did. We've name him Oliver. He’s a beautiful, happy, and intelligent 2 month old Miniature Dachshund. We’ve been together for two weeks now, he’s kept us company, brought us happiness and laughter, has helped make everything less bitter. He’s saved us and I love him so much.
In midst of it all, the people that really care about us have shined. I’ll be eternally grateful for everyone that showed support one way or another. And you, Ana, I love you so much, thank you for holding my hand along the way.
PS: Ana shared with me some helping points for when things don’t go your way. Might help you out some day too.
Take a step back and evaluate
Vent if you have to, but don’t linger on the problem
Realize there are others out there facing this too
Process your thoughts/emotions
Acknowledge your thoughts
Give yourself a break
Uncover what you’re really upset about
See this as an obstacle to be overcome
Analyze the situation – Focus on actionable steps
Identify how it occurred (so it won’t occur again next time)
Last year around this same date I started The Hacker and Designer News newsletter as a weekly curated recap of the what I thought were the best articles from Hacker News and Designer News on startups, entrepreneurship, hacks, programming, design, etc. I built and open sourced an aggregator to help me collect posts. I later built news.hdn.io using that same aggregator to view the current top posts on both sites side-by-side.
Learned a couple of things from building a newsletter, missed a couple along the way, but definitely looking forward to ramp up subscribers throughout 2015. If you still haven't, feel free to check out past issues and subscribe.
Check out below the Top 20 Hacker and Designer News for 2014.
Supporting Internet Explorer is always kind of a drag, but sometimes you just have to. Adding to the mixture file uploads via AJAX and CORS only make it that much more fun.
If the origin domain is different than the file upload server domain, CORS comes into play and there are some known limitations and issues on IE 8 and IE 9. In Internet Explorer 8, the XDomainRequest object was introduced to allow safe AJAX cross-origin requests directly by ensuring that HTTP Responses can only be read by the current page if the data source indicates that the response is public. Responses indicate their willingness to allow cross domain access by including the Access-Control-Allow-Origin HTTP response header with value *, or the exact origin of the calling page.This blog post lists and describes the restrictions and reasoning behind them, but these two are the ones that bit me recently.
Only text/plain is supported for the request's Content-Type header - This means that your API endpoint will have to be adjusted to be able to parse whatever data you send in the request. In my case I was returning a JSON response with an application/json content type, but after figuring this out I had to change the content type of that response to text/plain. On the client side that meant manually parsing the response data as JSON using $.parseJSON.
Requests must be targeted to the same scheme as the hosting page - Once I thought I had everything working I was still getting hit by a couple of errors. Turns out I was generating a request from http to an https endpoint on different domain.
The target URL must be accessed using only the HTTP methods GET and POST
Now comes jQuery File Upload into play.
File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.
Cross-domain file uploads on IE 8 and 9 use the Iframe Transport plugin that requires a redirect back to the origin server to retrieve the upload results. The example implementation includes a result.html that works for this. The repository includes the jQuery XDomainRequest Transport plugin which is required to enable cross-domain AJAX requests in IE 8 and 9. Internet Explorer 10 and above supports CORS using XMLHTTPRequest.
The tricky part here for me was ;“requires a redirect back to the origin server”. I had the results.html file in place but nothing was happening. Taking a look at the sample server implementations I noticed that in order for this to work I had to redirect the response to the location of the results.html including the response JSON I would normally return as a response but as a query parameter. The results.html enables jQuery File Upload to access the results from the iframe.
Here are a couple of excerpts that might help understand.
Recently I remember I was keeping a backup of my OpenPGP keys on an external hard drive that any day now could just cease to work. After my first attempts with PGP/GPG where I lost my private keys and could no longer revoke them, I wasn't planning on loosing another one again.
After reading what others did to store their private PGP keys, I figured that the best way to store them was on paper. That's where paperkey comes along. Paperkey is an OpenPGP key archiver by David Shaw, one of the main GPG developers.
What does paperkey do?
Due to metadata and redundancy, OpenPGP secret keys are significantly larger than just the "secret bits". In fact, the secret key contains a complete copy of the public key. Since the public key generally doesn't need to be escrowed (most people have many copies of it on various keyservers, web pages, etc), only extracting the secret parts can be a real advantage.
Paperkey extracts just those secret bytes and prints them. To reconstruct, you re-enter those bytes (whether by hand, OCR, QR code, or the like) and paperkey can use them to transform your existing public key into a secret key.
So to try it out, I installed it via homebrew.
brew install paperkey
Take the secret key in secret-key.gpg and generate a text file my-key-text-file.txt that contains the secret data:
I had a great time at DjangoCon US 2014. Lots of first times.
First time at DjangoCon
First time speaking at DjangoCon
First time speaking in front of "large" crowd.
First time visiting the west coast
First time visiting Portland
Special thanks to Blimp for enabling me to do this. Thanks to the DSF's grant which made the trip financially possible. Thanks Froi and Sasha for coming along, all the support, and making the trip way more fun.
Last but not least thanks to my beautiful fiancée, Ana, for always supporting me and still loving me even though I missed her birthday for the first time because of this trip.
Here's the video
You can find the slides on Speaker Deck.
We also got a few attendees to help us write down some notes during the event. Check them out.
There also a couple photos I took of the whole trip on Facebook.
This'll be my first time attending and speaking at DjangoCon US. I'll be talking about JSON Web Tokens, Django, and Django REST Framework.
I've been talking about working on a Sprint for Django REST Framework with Tom Christie on Twitter. Tom pointed out a list of decent candidates to work on if we get some people together. We'll have a tagged list of obvious bug candidates before the sprint. He's also planning on helping us out remotely those days.
It seems like a great idea to celebrate the successful Django REST framework 3 campaign on Kickstarter and with the timing of DjangoCon, "kickstart" the development of upcoming versions.
So, I'm recruiting anyone who'd be interested and available in working together. Everyone’s welcome to join in - if you use Django REST framework and would like to become more familiar with its internals while working together with other developers with various levels of expertise. Sprints will be held Friday and Saturday Sep 5-6.
If you're interested please send me an email so we can start getting organized. If you know someone who might be interested please share this with them.
Update
Issues have been tagged and include a brief description of how to progress the ticket for the sprint.
I've been using Python for a quite a few years as my main go-to language for building web apps, RESTful API's, utilities, and much more. It's the driving power for most of our backends at our startup: Blimp, Blimp Boards, and FilePreviews. I have very few bad things I could argue about Python, but I won't.
I've recently felt the need to dig into newer programming languages and technologies. One of the languages I've been wanting to try out for a while now is Go. So I did, and here's why and a couple of resources that helped me out. The first thing I did was read up about Go for a few days.
The Go programming language is an open source project to make programmers more productive.
Go is expressive, concise, clean, and efficient. Its concurrency mechanisms make it easy to write programs that get the most out of multicore and networked machines, while its novel type system enables flexible and modular program construction. Go compiles quickly to machine code yet has the convenience of garbage collection and the power of run-time reflection. It's a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language.
This perfectly describes Go.
It's pretty easy to understand for new developers, fast and with a good toolset for debugging and performance tuning.
Statically typed and compiled you end up with fewer bugs
Easy to profile for speed and memory leaks
Built-in code formatting
Small memory footprint
Simple language design
Natively multithreaded
Built for and actively developed by Google
And more...
A Tour of Go
A great resource to get started with Go is A Tour of Go. The interactive tour is divided into three sections: basic concepts, methods and interfaces, and concurrency, that can be compiled and ran right from the browser.
Go by Example
Go by Example is a hands-on introduction to Go using annotated example programs by Mark McGranaghan.
Go Tool
Go is a tool for managing Go source code. Available go commands are:
build - compiles packages and dependencies
clean - removes object files
env - prints Go environment information
fix - runs go tool fix on packages
fmt - runs gofmt on package sources
get - downloads and installs packages and dependencies
install - compiles and installs packages and dependencies
list - lists packages
run - compiles and runs Go program
test - tests packages
tool - runs specified go tool
version - prints Go version
vet - runs go tool vet on packages
Godoc
Godoc extracts and generates documentation for Go programs, it parses Go source code and produces documentation as HTML or plain text. After generating your docs you can use GoDoc to host it. You can read more in the Godoc: documenting Go code blog post.
Package Management
With the go get command you can install remote packages directly from version control. One of the things you'll notice when starting out with Go is that there isn't a builtin package manager tool like we'd see with package managers like Bundler, Pip and NPM. There are third party tools for for managing Go packages and their dependencies. The Go project recommends vendoring, taking the 3rd party source code that is referenced in your project and making a copy of that code inside a new folder within the project.
Check out godep, a well-maintained tool for managing vendored dependencies. Some additional resources:
List of Package Management Tools
Go Package Management
Go and Package Versioning
Manage Dependencies with GODEP
GoUsers
There quite a couple of startups and organizations using Go that blog about or open source packages and tools. A couple of my favorites are:
Bitly
Disqus
Drone
Dropbox
Embedly
Heroku
Useful resources
Official docs
How to Write Go Code
Effective Go
Get Your Development Team Started With Go
Go After 2 Years in Production at Iron.io
Google Go: The Good, the Bad, and the Meh
How to Convince Your Company to Go With Golang
Discovering projects and packages
Package discovery has been a pain for me. Since there's no main index, packages can be hosted many different places. You'll quickly notice that you won't really need that many external packages, but when you do you'll be searching around.
Awesome Go - A curated list of awesome Go frameworks, libraries and software
Projects - A list of Go projects
Go Search - A search engine specifically designed for Go
Go Walker - Displays API documentation for Go projects
Sourcegraph - Shows you real examples of how functions and classes are used by other open-source projects.
I'm still learning the best way I know. I've already started a new project that I'll be launching in a few weeks, developed a few packages in the way that I'll be open sourcing soon.
What resources have you found useful while working with Go? Please share them in the comments below.
Update
Mentioned resources by others.
MetaCasts - Weekly screencasts that focus on Go and JavaScript. Thanks to Mark Bates!
I played around with Ember.js on and off last year and after building some quick demos I decided to invest some real time in building real web apps with it. I have been keeping track of some useful tips and resources for people starting out with Ember.js.
Ember.js Guides
The official Ember.js Guides and Tutorials walks you through the very basic concepts for someone starting out, and slowly getting into more "advanced" concepts and features. Those guides are truly written in a simple to understand tone only using technical jargon where necessary. I definitely suggest going over these guides before starting out with Ember. I've kept them handy since they are also useful for future reference.
The guides also have a very useful section, Cookbook. It provides answers and solutions to common Ember questions and problems.
Ember.js API
The Ember.js API is usually my second go-to website. It's very useful to learn about the different available classes that make up Ember. It contains usage examples for methods, properties, and events. They also link directly to where they are defined, if you are into checking out the source code.
Ember CLI
Ember CLI is an Ember.js command line utility. It provides an ideal project structure based on Ember App Kit. For building anything more than a simple demo using Ember CLI makes a lot of sense and makes building with Ember way easier.
Useful content
Built With Ember
Getting started resources for Ember.js by Giovanni Collazo
Videos from Ember Camp 2013
Ember Watch
Ember Weekly
Embercasts
EmberFlare
Ember Hot Seat
Learning by doing
I've always found that the best way to get started with new technology is to pick a project and just work on it.
Learning from others
Learning from other people's work is also very helpful. There are many people that are really active on the Ember.js community either because they are part of the core team or just love the framework and contribute back to other open source projects. When in doubt check out some of these influential organization's/individual's open source projects.
Ryan Florence
Stefan Penner
Alex Matchneer
Erik Bryn
Addepar
DockYard
Brian Cardarella
Robert Jackson
Robin Ward
Trek Glowacki
Getting Help
The Ember community uses StackOverflow to track questions. So its a good rule of thumb to search on SO before asking around. You can also join the Ember.js Discussion Forum which is usually a good place to discuss features and best practices.
The IRC channel #emberjs on Freenode is usually very active and is a good place to find people that might help you out. Apart from being polite, it's usually a good idea to have code that you can show, so others can reproduce your problem. Don't copy code on IRC, instead use something like JS Bin.
Let me know if you have any other useful tips, resources, etc...
Last Barcamp we organized was back in 2012 in Mayagüez. The one before that was in 2011, and the first one was back in 2010.
We already have a date for the next Barcamp Viejo San Juan, Tuesday, June 3 at 7PM. This time we'll be meeting at Piloto151 in Old San Juan.
For those that don't know what a Barcamp is, Barcamp is a conference in which the guests become the event speakers. We expect everybody to make a 10 minute presentation to the rest of the audience. The idea is to encourage the exchange of ideas in an open and interactive environment.
Even though the ideal situation would be that everybody gets a chance to present, we know it's not possible. We'll have 20 reserved spaces and they will be available on a first come-first served basis. If there's not enough time or you are not ready to present, the least we expect is for everybody to interact with questions, suggestions, and help create an environment of interaction with the presenters.
The format for presentations will be 10 minutes and focused around the topics like:
Web development & design
iPhone / iPad application design & development
Software development in general
Mobile application design & development
Interaction Design, information architecture, user experience
Tech startups & venture capital
Spots for presenting are limited so if you'd like to present you should arrive early. Like always, we'll do everything possible to make this event another #win.
We'll have beers, some hors d'oeuvres, and t-shirts. Please let us know you plan to attend by RSVP’ing on the Eventbrite event page. This helps us plan for space and food accordingly.
A couple of weeks ago soynerdito soynerdito shared a bot he made to tweet internet connection speed results every now and then.
I then remembered I had a Raspberry Pi I wasn't using at all. So I built a small app that runs speed tests every 3 hours. It's based on speedtest-cli which is a Command line interface for testing internet bandwidth using speedtest.net.
The only difference with the one I built is that instead of tweeting the results, it posted all available data to an endpoint. I built a Flask app that can be used to store those results for different users as well as share them via a JSON API.
If you're interested in running your own, check this Gist out. It contains a README file that will help you setup your box(doesn't have to be a Raspberry Pi). It also includes a sample Flask app to store your own results. If you're interested in using the one I'm hosting you could do so, just let me know and I'll send you a URL to store results and one to share or consume. It'd be interesting to see different kinds of results at a larger scale, not just my own.
Here are the results graphed since I started running it. Interesting to see how so many spikes in my download speeds. Those are probably related to download in other computers or probably streaming Netflix. Upload speed as expected doesn't really fluctuate that much.