The new Fullstack website

Fullstack Logo We at FullStack are big on dogfooding so we decided it was time to move away from Wordpress. As our site is just a simple static site with the few random blog post, we decided to build something a lean as possible. This lead us to doing a serverless deployment using AWS, Jekyll, and a few scripts.

One of the great things about going serverless is that there’s no more upgrades and patching, no more security issues to worry about. On top of that it’s costing us less than $15 a year to host a secure and CDN backed site.

So how did we do this?

We used the combination of following AWS services - S3, Cloudfront, Lamdba, API Gateway, and Route53 to host our site that’s assembled with Jekyll.
In later posts I’ll go more into details about some of the not so obvious things. For now, I’m just going to summarize what service are being used.

  • S3 - The place where our site gets severed from.
  • Cloudfront - This provides us with a CDN. It also allows us to host your site with SSL. S3 doesn’t provide you with a way to using an SSL cert with a custom domain.
  • Lamdba - This service runs any scripts our site might need. We just have a little python script to power our contact us form.
  • API Gateway - This allows you to expose your Lamdba script as an API call for your site. We have a tiny python script that we use for our contact form.
  • Route53 - You got to have some DNS.
  • A Bash Script - We have a little bash script that makes updates a breeze. It cleans up the URLs, so we have nice clean ones with an extension. Uploads everything to S3 and then flushes the Cloudfront cache.

Further reading -

  • Jekyll
  • https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html
  • https://aws.amazon.com/blogs/compute/implementing-default-directory-indexes-in-amazon-s3-backed-amazon-cloudfront-origins-using-lambdaedge/
  • https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html

Need some help?

Do you need help with crafting your next high-performance app? Are you struggling to determine the right architecture for your next project? Contact us to discuss how we can help!

Simplify SSH access to your AWS ec2 instances

aws cloud We at FullStack are big on security and only allow SSH access to hosts by the IPs of our engineers.  In AWS we create a single security group (SG) to allow SSH access.  With the use VPNs, travel, and dynamic IPs it can some time be a pain to update a security group with your new IP.  So I wrote a small python script using Boto3 that removes and updates a single ingress rule based on the description value.  You just need to set the SG Id on line 5, and the value of the description on line 6 of the rule you want to update.  We use a user name for the description value as it makes it easy to tell what rule belong to who.

update-ssh-sg.py

Do you need help with your DevOps? Are you struggling with getting AWS to work for you? Contact us to discuss how we can help!

A new github project - pubmed_j

PubMed Logo

I have just released a new GitHub project - pubmed_j.  It fetches and parses PubMed docs into a POJO.  This project was started out of a need to import PubMed documents as references in the MAGICApp.  As I really dislike using SOAP services I wrote this.

Get the goods at - https://github.com/denov/pubmed_j

FullStack gets a shout-out in a BMJ article

British Medical Journal We got a little love in the recent BMJ article, "Decision aids that really promote shared decision making: the pace quickens" for the work we have been doing on the MAGICApp.

Do you need help creating your next high-performance app? Are you struggling to determine the right architecture for your next project? Contact us to discuss how we can help!

Stylish, and accessible, ordered lists with LESS CSS

The design process for most front end designers has evolved over the last few years to remove Photoshop from the workflow, to one where the design goes from wireframe to browser as soon as possible. It allows us to work faster and present a design concept that can be viewed on multiple screens and devices right off the bat.

The basic design concept for the login and signup pages for the MAGICapp project called for a numbered list of the benefits of creating a new account. In years past I might have used icons or images crafted in Photoshop to achieve the desired look, but with what can be achieved in CSS, it's possible to be able to create the design in code that renders well on all screens and devices. Here is a screenshot from the Balsamiq wireframe that shows the basic list design:

Obviously this should be coded as an ordered list. It's semantically correct to do so and it's also nice that it can still be accessible to screen readers. Basically, when the CSS is disabled, it should still render as a numbered list. But, the biggest design challenge with styling ordered lists in CSS is figuring out how to target the numbers separately from the text as shown in the wireframe above. Here's the solution I came up with.

Standard html for the list:

  <ol class="numberedList">
      <li>List item number one</li>
      <li>List item number two</li>
      <li>List item number three</li>
      <li>List item number four</li>
  </ol>

And the basic CSS for the list and first list item:

.numberedList ol {
  list-style-type: none;
}

.numberedList li {
  margin-bottom: 1.75em; // this will depend on your design
  padding-left: 45px; // to make room for the numbers
  position: relative; // for positioning certain numbers more precisely
}

.numberedList li:nth-child(1):before { // this is where the styling of the numbers happens.
  content: "1";
  border: 2px solid #007385;
  color: #007385;
  display: inline-block;
  width: 25px;
  height: 25px;
  -webkit-border-radius: 50%;
  -moz-border-radius: 50%;
  border-radius: 50%;
  margin-right: 15px;
  text-align: center;
  line-height: 25px;
  font-weight: 700;
  font-size: .9em;
  position: absolute;
  top: 0px;
  left: 0px;
}

It seems a little backwards, but to style the numbers required hiding them from the list by using 'list-style: none' in the CSS and then inserting the numbers as content in the :before tag of each list item. Using nth-child, each list item can now be targeted in order. Then, just make as many nth-children as the list calls for. This becomes very redundant listing out the same CSS values over and over for each list item. Using LESS, these common CSS values can be made as a mixin that can be pulled into the main stylesheet when needed.

The first basic mixin we'll need is one for the border radius of the circled number:

.border-radius (@radius) {
  -webkit-border-radius: @radius;
  -moz-border-radius:    @radius;
  border-radius:         @radius;
}

Next, is a mixin for the circled numbers that are displayed in each of the list items. The .border-radius() mixin being used. Having a common element like this as a LESS mixin allows for much easier style changes across the app, making design in code much more practical. These numbers can be styled however you want.

.circleNumbers () {
  border: 2px solid #007385;
  color: #007385;
  display: inline-block;
  width: 25px;
  height: 25px;
  .border-radius(50%);
  margin-right: 15px;
  text-align: center;
  line-height: 25px;
  font-weight: 700;
  font-size: .9em;
  position: absolute;
  top: 0px;
  left: 0px;
}

And lastly a function that can be called from the main LESS stylesheet to generate the CSS for each of the list items.

.generateOrderedList(@n, @i: 1) when (@i =< @n) {
  &:nth-child(@{i}) {
    &:before {
      content: "@{i}";
      .circleNumbers();
    }
  }

  .generateOrderedList(@n, (@i + 1));
}

So, now anytime in the main LESS stylesheet when I want to use this style of ordered list, I just call the function as you can see in the updated example below. This is for a list with 5 items in it.

ol {
    display: inline-block;
    list-style-type: none;

    li {
      margin-bottom: 1.75em;
      padding-left: 45px;
      position: relative;

      .generateOrderedList(5);
    }
}

And here it is all together. I hope this is helpful to others out there.

See the Pen qDuBl by Rob F (@robfracisco) on CodePen.

Get in touch

Let us know about your CSS tips and tricks in the comments or reach out to us with your web development questions or needs.

Passing arguments to Intern tests

theintern We have started to use Intern to test MAGICapp, a medical guideline authoring application we are currently working on. I wanted the flexibility to run a test against any of our environments and didn't want to hard code the server host name into the test. After looking through the Intern wiki and related blog posts I found nothing to explain how to pass an arguments into a test.

Digging in the source of the Intern I found 'intern/lib/args' which has the following comment in the top of the file:

/**
 * A hash map of arguments passed to the application.
 * This code expects that arguments are passed as key=value
 * pairs, either in the query string (if in browser) or on
 * the command line (if in Node.js). Arguments passed
 * with a key but no value are assumed to be boolean flags.
 * Keys with - or -- prefixes will have the prefix stripped.
 */

So if you include 'intern/lib/args' into your tests you'll be able to pass the host you want to test against. You could pass other things like if the test should be 'read' or 'write' as you may not want to run tests that change data again your production application.

define([
  'intern!object',
  'intern/chai!assert',
  'require',
  'intern/lib/args'
], 
function (registerSuite, assert, require, args) {

Interview on Dojo site for MAGICapp JavaScript development

Our very own Deno Vichas was interviewed by Dylan Schiemann, CEO at SitePen, and co-founder of the Dojo Toolkit for Dojo's Case Study Series.

magicapp2-1024x614Deno talks about managing complex JavaScript web applications and developing rich user interface components using Dojo.

MAGICapp is a cutting edge clinical practice guideline authoring and publishing application used by evidence based medicine practitioners and is featured for the interview.

MAGICapp was developed from the ground up by the Fullstack team and makes extensive use of the Dojo Toolkit.

Read more »

HTML multi select with ordering on JSFiddle

jsfiddle-htmlJSFiddle is a great tool for interactive JavaScript development and prototyping.

I needed an HTML select where the user could change the ordering and select to edit the values. Developing this interactively right in the browser made it easy to quickly see updates.

Here's a live demo on JSFiddle of the finished product implemented in JavaScript with some help from Dojo:

http://jsfiddle.net/denov/ShLrs/

Database restore with Elastic Beanstalk

aws logo So you have an Elastic Beanstalk environment with an RDS instance with automated backup and you just hosed your database and need to restore.

At first you may think this should be a quick and simple process until you try to restore your database. With RDS you can only restore a backup to a new instance. This seems reasonable until you figure out there's no way to change your RDS endpoint in your Beanstalk environment, or at least no solution was readily available in the documentation. You also can't create a new environment from an automated backup.

Here's the steps I used to solve this problem:

  • Restore the database to a new RDS instance.
  • Make a manual backup of this new RDS instance.
  • Create a new Beanstalk environment using your manual RDS backup.
  • Test to make sure everything is working as expected.
  • Update URLs or DNS to make sure traffic is routed to your new environment.

Need some help?

Do you need help with crafting your next high-performance app? Are you struggling to determine the right architecture for your next project? Contact us to discuss how we can help!

SQL IN like query with Dojo stores

Sometime you need a little more that passing an object to query() of a Dojo store to do a simple compare of a property or two. In those cases you can pass a function that returns a boolean. As an example say you want to return the object where the key is in a list. You can use the following: