Mapping API Responses to JavaScript Models

One design goal I’ve been having in mind with frontend code for airavata-django-portal is to keep the “business logic” separate from the UI code, especially to keep it separate from any UI framework code. I got this idea from another blog post that I can’t quite find at the moment but the idea is to keep the core application logic separate from the UI framework code, which makes it easier to switch if needed to a different UI framework. It’s also just a good separation of concerns: there’s no need to tie up pure domain logic with Vue or React or Angular specific framework code.

For the most part, this common application logic code is made up of Models and Services. This post focuses on Models and how to instantiate them from REST API responses. Models are client-side representations of server-side models, so one responsibility of model classes is to handle deserialization and serialization of API responses. Another responsibility of models is to implement validation logic. In general any domain specific behavior should be implemented by these model classes.

So one problem is how to efficiently map from a JSON response to properties on these model classes? I’ve been working on that this week. For the most part JSON.parse takes care of the simpler aspects of deserialization: strings, numbers, and booleans are all converted to native data types. But there remain a few additional considerations:

  • Dates aren’t encoded as such in JSON and require special handling. The approach I’ve been taking is to encode dates as strings in ISO-8601 format, in the UTC timezone.
  • Mapping nested data structures to nested model classes.
  • Handling lists of simple data values or nested model instances.

There are potentially other considerations like mapping a property with a certain name in the response to a differently named property on the model, but we’re taking the approach of keeping the property names the same on the responses and model classes.

I created a BaseModel.js that has a constructor that takes two arguments. The first argument is an array of metadata that defines all of the “fields” or properties of the model class. The second argument is optional and is the data, which would typically be an API response.

There are two ways to define a field. The first way is to just specify the name of the field. In this case no special conversion logic is performed: if the field’s value is a string then that is the type of the field, etc. The second way to define a field is to specify not only the name of the field but also its type and optionally whether it is a list and what default value it should have if there is no value for this field in the data.

The implementation of the BaseModel constructor is fairly straightforward. Here’s an example of how the BaseModel class would be used:

import BaseModel from './BaseModel'
import InputDataObjectType from './InputDataObjectType'
import OutputDataObjectType from './OutputDataTypeObject'


const FIELDS = [
    'applicationInterfaceId',
    'applicationName',
    'applicationDescription',
    {
        name: 'applicationModules',
        type: 'string',
        list: true,
    },
    {
        name: 'applicationInputs',
        type: InputDataObjectType,
        list: true,
    },
    {
        name: 'applicationOutputs',
        type: OutputDataObjectType,
        list: true,
    },
    'archiveWorkingDirectory',
    'hasOptionalFileInputs',
];


export default class ApplicationInterfaceDefinition extends BaseModel {


    constructor(data = {}) {
        super(FIELDS, data);
    }
}

Two-factor Authentication for write-enabled Apache GitHub repos

Some Apache projects, such as Apache Airavata just recently, have made their GitHub repos writeable. However, to actually push to an Apache GitHub repo you need to enable two-factor authentication (2FA) in GitHub. With 2FA some additional work is needed to authenticate with GitHub from a Git client.

First Steps

First thing you need to do is link your Apache account with your GitHub account and enable 2FA on GitHub if you haven’t already done that. Go to https://gitbox.apache.org/setup/ and follow the instructions there.

Using a Personal Access Token

Now that you have 2FA enabled on your GitHub account you can no longer use your GitHub username and password to authenticate with GitHub from a Git client. Instead of your GitHub password you can use a Personal Access Token.

Personal Access Token screen
  1. Generate a Personal Access Token in Github.
  2. Give it a name.
  3. Check the repo scope.
  4. Create the token and copy it. (make sure to securely save this token somewhere, you’ll won’t be able to get it back later)
  5. When doing git push provide the GitHub username and this personal access token.

Also, you’ll want to store this personal access token in a keychain type service so you don’t have to provide it each time you do a push. If you haven’t already done so, configure a credential helper for Git.

Using an SSH Key

Alternatively, you can set up an SSH key for authenticating with GitHub. I didn’t do this but Suresh reported that this works as well.

See GitHub’s documentation on working with SSH keys for more information about this approach. The gist of it is that you can use an SSH key you already have or you’ll need to generate a new one. Then you’ll need to add the public key portion to GitHub. Finally, GitHub has some instructions on how you can automatically add your private key passphrase to your ssh-agent so you don’t need to ever type your private key passphrase.

Reflections on the SGCI Bootcamp

From October 2nd to the 6th I attended the SGCI (Science Gateways Community Institute) Bootcamp, which is a workshop to help science gateway developers and project leaders to develop a sustainability plan for their gateways. The Bootcamp took place at the Purdue Research Park, just a short distance from the Indianapolis Airport.

I went there with Dr. Sudhakar Padminghampton, the PI of the SEAGrid science gateway. As members of the Science Gateways Research Center there are several projects we have to which we could apply the Bootcamp (the Apache Airavata open source project, our SciGaP “Platform-as-a-Service” hosting project, etc.) but we decided to focus on SEAGrid, which is one of the main science gateways we support.

Day 1

We’re close enough that we drive up to the Purdue Research Park on Monday. Michael Zentner kicks things off by giving an overview of the Bootcamp and the goals for the week. We spend a little time introducing ourselves to each other, but we’ll come to know more about each other and our projects later in the week through the various Bootcamp activities.

What is Sustainability?

Nancy Maron leads the first session, What is Sustainability?. Sustainability is defined as “the ability to get the resources (financial and
otherwise) needed to maintain and increase the value of your gateway”. So one question to ask is, what is the value of our gateway, SEAGrid? And the value of SEAGrid is different for different groups of people.

We need to think about that value SEAGrid provides to

  • end users (e.g., gateway users and developers)
  • stakeholders (e.g., project PIs, institutional leadership)
  • partners (e.g., HPC centers, camputs computing centers, other gateway service providers)
  • volunteers (e.g., open source contributors)

We also need to think about our competition, what are the alternatives out there to the services provided by SEAGrid? That will affect the value that SEAGrid provides as well.

Ultimately we’ll want to develop a strong value proposition, which we’ll come back to later. But a strong value proposition needs to articulate the unique value that our service provides that is compelling, over and above the competition, to our user audience.

Key takeaways:

  • must develop a great idea into a strong value proposition
  • the development and implementation of a sustainability plan is an ongoing process

Napkin Drawing

The next session was led by Juliana Casavan. The idea here is to communicate in a non-technical fashion, mostly using pictures, the value of our gateway to end users. The setup is this: if you had to describe your gateway to someone using only a drawing on a napkin (and refraining from using technical jargon), how would you describe your gateway?

I think this exercise was really helpful and it was probably my favorite exercise of the week. We so often think in very technical terms about our gateway and this was a great way to try to see our gateway from the perspective of an end user.

Key takeaway:

  • When describing your gateway (or product, service, whatever), you don’t need to provide all of the details. Leaving out details creates intrigue. Intrigue leads to your audience asking questions so that they are the ones driving the conversation. This is a much more effective way to communicate your value than simple enumerating each and every little thing your gateway does.

Value Proposition

Nancy leads this session on formulating a value proposition. Nancy gave us a very simple template to work from that goes like this:

  • My product
  • will help who?
  • to do what?
  • by how?

Here’s what we came up with for SEAGrid:

  • SEAGrid Science Gateway
  • will help computational scientists and engineers
  • to set up model systems, define simulation and job parameters and analyze the results and manage execution and data
  • from a single point of access

Key takeway:

  • A value proposition is not something you just make up. It is something that you discover. It starts out as a hypothesis that is then tested by learning from your users what they value or don’t value about your product. And it needs to be reviewed and refined over time.

That concluded our first day. There’s more to say so I’ll write some more about the rest of the week later.

Matrix similarity and eigenvalues

Introduction

Recently I was reading Data Science from Scratch by Joel Grus. One of Grus’ prerequisites for doing data science is linear algebra. I took a linear algebra course as a freshman but I didn’t do particularly well in it and what little I learned I’ve long since forgotten. So I’ve decided to brush up on my linear algebra by working through a textbook called Linear Algebra by Jim Hefferon, a free online text book recommended by Grus.

In the fifth and final chapter of Linear Algebra the author’s program is to come up with a kind of normal form of matrices that would become an equivalence class for matrices. The chapter starts by introducing the notion of matrix similarity. If two matrices are similar then they essentially are the same transformation, just in different bases.

The normal form the chapter builds to is the Jordan normal form. There are matrices that are diagonalizable and for these matrices a diagonal matrix is the normal form (more on this later). But not all matrices are diagonalizable. Some are nilpotent. A nilpotent matrix is one that when applied to itself multiple times eventually becomes the zero matrix. The canonical form of nilpotent matrices is all zeros and some ones on the sub-diagonal. Jordan normal form essentially combines these two canonical forms to create a canonical form that can represent any matrix.

That’s about all I want to say about Jordan normal form. Here I’ll be focusing on diagonalizability and how to compute eigenvalues and eigenvectors.

Diagonalizable matrices

I introduced matrix similarity by saying that similar matrices represent the same transformation just in different bases. More formally, two matrices, A and B are similar if there exists a matrix P such that A = P B P^{-1}. This P matrix is a basis conversion matrix and converts from B’s basis to A’s basis; the inverse converts in the opposite direction.

A diagonal matrix is defined as a matrix that is all 0’s except for non-zero entries on the diagonal. A matrix T is diagonalizable if there is a matrix P such that P T P^{-1} is a diagonal matrix. So the diagonal representation of T is similar to T and any matrix that is similar to T is also similar to the diagonal representation of T. Later we’ll see how to determine if a matrix is diagonalizable.

Let’s think a little bit about what a diagonal matrix represents. Let’s say we have a diagonal matrix T with n rows and columns. T is a matrix with all zeroes except that in the i-th row there is a diagonal entry that we’ll call \lambda_i. The basis of the domain and codomain is the same and the vectors that make up this basis we’ll call \beta_i. Then, for each basis vector:

<br /> T \beta_i = \lambda_i \beta_i<br />

Let’s look at an example. Let T be the following diagonal 2×2 matrix with the natural basis:

<br /> \begin{pmatrix}<br /> 2 & 0 \cr<br /> 0 & 3<br /> \end{pmatrix}<br />

So for T, \lambda_1 = 2, \lambda_2 = 3, \beta_1 = (1, 0) and \beta_2 = (0, 1). We can easily show that T \beta_1 = \lambda_1 \beta_1:

<br /> \begin{pmatrix}<br /> 2 & 0 \cr<br /> 0 & 3<br /> \end{pmatrix}<br /> \begin{pmatrix}<br /> 1 \cr<br /> 0<br /> \end{pmatrix}<br /> =<br /> \begin{pmatrix}<br /> 2 \cr<br /> 0<br /> \end{pmatrix}<br /> =<br /> 2<br /> \begin{pmatrix}<br /> 1 \cr<br /> 0<br /> \end{pmatrix}<br /> =<br /> \lambda_1 \beta_1<br />

And likewise for \lambda_2 and \beta_2.

For a diagonal matrix, we’ll call the \lambda_i the eigenvalues and the \beta_i the eigenvectors. If we can develop a way to compute the eigenvalues and their associated eigenvectors for a matrix then we can construct the diagonal representation of a matrix which would simply have the \lambda_i as the diagonal entries and the basis would be the eigenvectors.

Computing Eigenvalues and Eigenvectors

So how do we find eigenvalues? What we’ll do is solve for T \vec{v} = \lambda \vec{v}. This becomes

<br /> T \vec{v} - \lambda \vec{v} = \vec{0}<br /> \\<br /> (T - \lambda I) \vec{v} = \vec{0}<br />

(T - \lambda I) \vec{v} = \vec{0} is a homogeneous system and the only solution for \vec{v} is \vec{0} if T - \lambda I is nonsingular. (A nonsingular matrix is one that has a unique solution but for a homogeneous system the only unique solution is \vec{0}). That’s not what we want; we want non-zero solutions for \vec{v}. That will only happen if T - \lambda I is singular, which is true when |T-\lambda I| = 0, that is, when the determinant of T - \lambda I is 0.1 This equation, |T-\lambda I| = 0 is called the characteristic equation.

Let’s look at an example. Let T be

<br /> \begin{pmatrix}<br /> 3 && 0 \cr<br /> 8 && -1<br /> \end{pmatrix}<br />

Then

<br /> |T - \lambda I| =<br /> \begin{vmatrix}<br /> 3 - \lambda && 0 \cr<br /> 8 && -1 - \lambda<br /> \end{vmatrix}<br /> = (3 - \lambda) (-1 - \lambda) - 0 * 8 = (3-\lambda)(-1-\lambda)= 0<br />

This equation has two solutions, \lambda = -1, 3. (Note: computing a determinant for a matrix of dimension 2 is relatively simple. To compute a determinant in higher dimensions see Laplace’s expansion.)

For each eigenvalue we can find a corresponding set of eigenvectors. Let’s start with the eigenvalue -1. We want to find vectors for which T\vec{v} = -1\vec{v}.

<br /> \begin{pmatrix}<br /> 3 && 0 \cr<br /> 8 && -1<br /> \end{pmatrix}<br /> \begin{pmatrix}<br /> a \cr<br /> b<br /> \end{pmatrix}<br /> =<br /> -1<br /> \begin{pmatrix}<br /> a \cr<br /> b<br /> \end{pmatrix}<br />

This becomes the following set of equations:

<br /> 3a = -a \\<br /> 8a - b = -b<br />

The only solution for the first equation is a = 0. The second equation then reduces to b=b which has an infinite number of solutions. Therefore the following is the set of eigenvectors for eigenvalue -1.

<br /> \lbrace<br /> \begin{pmatrix}<br /> 0 \cr<br /> b<br /> \end{pmatrix}<br /> |<br /> b \in \mathbb{R}<br /> \}<br />

This last is called an eigenspace. We can use any non-zero vector from this space to be an eigenvector, for example if we want to get a basis vector.

Similarly, plugging in the eigenvalue 3 yields

<br /> 3a = 3a \\<br /> 8a - b = 3b<br />

The first equation has an infinite number of solutions. The second equation reduces to b = 2a. Therefore the following is the set of eigenvectors for the eigenvalue 3.

<br /> \lbrace<br /> \begin{pmatrix}<br /> a \cr<br /> 2a<br /> \end{pmatrix}<br /> |<br /> a \in \mathbb{R}<br /> \}<br />

So the diagonal representation of T is

<br /> \begin{pmatrix}<br /> -1 && 0\cr<br /> 0 && 3<br /> \end{pmatrix}<br />

We can choose two eigenvectors, corresponding in order with the eigenvalues in the above matrix, to make up the basis:

<br /> \langle<br /> \begin{pmatrix}<br /> 0 \cr<br /> 1<br /> \end{pmatrix},<br /> \begin{pmatrix}<br /> 1 \cr<br /> 2<br /> \end{pmatrix}<br /> \rangle<br />

Now that we can compute eigenvalues we can easily determine if a matrix is diagonalizable: a matrix of dimension n is diagonalizable if it has n distinct eigenvalues because we can use those eigenvalues to make up the diagonal entries of the matrix and the eigenvectors associated with them make up the basis. Let P be the matrix whose column vectors are these basis vectors. Then the diagonalization of T is \hat{T}:

<br /> \hat{T} = P^{-1} T P<br />

Conclusion

Now we can not only determine if a matrix is diagonalizable but also produce the diagonal representation of a matrix and its basis. Why would we want to diagonalize a matrix? For a diagonalizable matrix, the diagonal representation is the easiest to work with. One example of how diagonal matrices are easier to work with is matrix exponentiation. If you have a diagonal matrix T with diagonal entries \lambda_i then T^n is a diagonal matrix with diagonal entries \lambda_i^n. Thus T^n is very easy to compute. If on the other hand T isn’t diagonal but it is diagonalizable, and \hat{T} is the diagonal representation of T, then T^n is

<br /> (P\hat{T}P^{-1})(P\hat{T}P^{-1})...(P\hat{T}P^{-1}) = P \hat{T^n} P^{-1}<br />

Since computing \hat{T^n} is very simple, it is worth it to transform into its basis and back again as a way of computing T^n.

In addition to practical applications can we also develop an intuition about eigenvectors from the preceding discussion? Since a linear transformation applied to an eigenvector doesn’t change its direction, the eigenvectors of a linear transformation can be thought as “axes” of the linear transformation. We can see that from how the eigenvectors of a matrix are used to form the basis vectors for the diagonal representation. The associated eigenvalues can be thought of as the amount of “skew” along those axes that the linear transformation imparts to vectors to which it is applied. So in a sense the eigenvectors and eigenvalues describe the action of a linear transformation on vectors to which it is applied, and this description appears to be as succinct as possible.


  1. Why is a matrix singular if the determinant is 0? Recall that singular matrices do not have a unique solution. One way to determine if a matrix is singular is to reduce it via Gaussian elimination to echelon form. If the result does not have leading coefficients for each row then it will not have a unique solution. But if it is missing a leading coefficient in one row then it must have a zero on that diagonal entry. One way to compute a determinant is to reduce a matrix to echelon form and then take the product of the diagonal entries. So the determinant will be 0 only if there is a 0 on the diagonal which happens when there is a missing leading coefficient. 

Escaping data in PHP pages

What does it mean to “escape” data that is put into a web page?

By escape I mean formatting the data in such a way that it doesn’t interfere with any of the code or markup of a web page. For example, let’s say a user entered their first name like so into a text input box

<b>Mary</b>

If the web page redisplays this data after the form is submitted, and it doesn’t escape it, then it will be rendered something like

<p>First Name: <b>Mary</b></p>

which will display as

First Name: Mary

instead of as

First Name: <b>Mary</b>

That is, as a web developer you want to display to the user exactly what they provided. The way to make sure you display to the user exactly what they provided is to escape any characters that could be interpreted as part of the web page markup, like so

First Name: &lt;b&gt;Mary&lt;/b&gt;

which will render as

First Name: <b>Mary</b>

Why is it important to escape data included in a web page?

There are two main problems that can arise when data isn’t escaped in a web page. We’ve already looked at one, namely that characters that are part of the markup or programming language (as we’ll see with JavaScript later) can mess up that actual markup or program code. So for the sake of correctness, data included in the web page must be escaped.

The second problem is that failure to escape data in a web page can make possible various kinds of security attacks. Keeping with our example, suppose a user entered as their first name

Mary<script>alert("Hijacked!");</script>

Displaying this directly in a web page would result in that script being executed. And the JavaScript so injected could do lots of nefarious things, such as reading a user’s cookies.

What are the different ways of escaping data?

There are several different ways in which data is added to a web page, and they require different techniques to properly escape them. I’ll cover three cases in this blog:

  • HTML data
  • JavaScript strings and JSON
  • URL components

For each of these I’ll show how to escape these in PHP (specifically when using Laravel), but the techniques here are applicable to other languages and frameworks. Most languages and frameworks will have similar utilities to escape web page data.

How to escape HTML data

For the most part what we need to do is replace the following characters

  • < to &lt;
  • > to &gt;
  • ” to &quot;
  • & to &amp;
  • etc.

In a Laravel controller you can escape data to be put into a web page with the htmlspecialchars. In a Blade template you can escape data by using triple curly braces, for example, {{{ $first_name }}}.

To go along with the example we started with, here’s how to write the Blade template to display the first name:

<p>First Name: {{{ $first_name }}}</p>

If you are dynamically generating a web page using JavaScript then you also need to be careful when creating DOM elements. Don’t use .innerHTML because that won’t escape any HTML special characters. There’s a simple way to handle data that you want to put into the DOM that may have special HTML characters and that is to use the special .textContent property of the DOM element.

var p = document.createElement('p');
p.textContent = '<b>Mary</b>';
// then append the p somewhere in the DOM

You can do the same in jQuery with the .text() function.

How to escape JavaScript strings and JSON data

With JavaScript strings you want to make sure that you escape quote characters in the string. If the user’s first name value is Mary" and you put this directly into a JavaScript string like so

<script>
var firstName = "{{ $first_name }}";
</script>

it will get rendered as

<script>
var firstName = "Mary"";
</script>

which is invalid JavaScript. The double quote in the $first_name variable prematurely terminates the JavaScript string.

In PHP, the way to deal with this is to use the json_encode method. You can use this for JavaScript strings:

<script>
var firstName = "{{ json_encode($first_name) }}";
</script>

You can also use it to encoding PHP data structures like arrays to JSON:

<script>
var userData = "{{ json_encode($userdata) }}";
</script>

How to escape values placed in URLs

When placing data into a URL, care has to be taken to encode any characters that are special to URLs such as

  • forward slash (/)
  • ampersand (&)
  • question mark (?)
  • etc.

URL encoding is the process of converting these special characters using something called percent-encoding. For example / gets encoded as %2F. Notice that this encoding format is different from the HTML encoding above so you’ll need different functions and techniques to do percent-encoding.

Let’s say you have a $project_name variable with the value This&that project and you want to create a link with the project name in it:

<a href="/projects?name={{ $project_name }}">Go to {{{ $project_name }}}</a>

This renders as

<a href="/projects?name=This&that project">Go to This&that project</a>

But this won’t work. When someone clicks on the link the server will interpret the URLs parameters like so

  • name=This is the first parameter name and value
  • that project is another parameter without a value

Instead use urlencode to properly encode the URL data.

<a href="/projects?name={{ urlencode($project_name) }}">Go to {{{ $project_name }}}</a>

This renders as

<a href="/projects?name=This%26that%20project">Go to This&that project</a>

The server will interpret these URL parameters as

  • name=This&that project as the sole name value pair

If you are constructing URLs in JavaScript code, use encodeURIComponent to do percent-encoding on URL data.

Resources

ECSS Symposium – CILogon and Keycloak

Note: I originally wrote this back in April but forgot to publish it. The presentation below was given on April 18, 2017.

At work, the beginning of this week was busy for me as I prepared for the ECSS Symposium. ECSS stands for Extended Collaborative Support Services and it is a way for XSEDE users to get expert help with running scientific applications on XSEDE resources. I talked about our recent work integrating CILogon with Keycloak and how we use it to secure access to Airavata services. My presentation is the second one and it starts about 24 minutes in:

The Philosopher’s Handbook

Bought the book The Philosopher’s Handbook by Stanley Rosen (editor) today at Barnes & Noble. It is a kind of introduction to philosophy organized in 6 sections corresponding to the following 6 divisions of philosophy:

  • social and political philosophy
  • philosophy of religion
  • aesthetics
  • metaphysics
  • epistemology
  • philosophy of science

Each section starts with an introduction by an expert in that particular branch of philosophy and then follows with a selection of readings from famous philosophers on the topic.

Today I read the introduction by Stanley Rosen. I’ll try to sum it up. Dr. Rosen begins with Socrates and defines philosophy as the pursuit of knowledge about what it means to live the good life. However, this approach to philosophy has been under attack in more recent years from two fronts: first, from science which posits a reduction of human impulses to merely the result of biological, chemical, physical forces, and second from cultural relativism which sees the values of different cultures as relevant for only those cultures, only understandable within those cultures.

Put differently, within science we can ask questions about natural phenomena and explore various hypotheses. Different practitioners can propose theories or attempt to confirm or falsify the theories of others. Can we do something similar with questions like “What does it mean to live a good life?” This is the fundamental question the author raises in the introduction. Likewise, do the answers to questions of this sort necessarily only make sense within the context of the cultures within which the questions are entertained?

The presentation of these questions is engaging but my head is kind of spinning and I’m not sure how to answer these questions. Are there fundamental universal truths about what the good life is and how to best live it? Can we know these truths with the same certainty that we know the gravitational constant? I’m intrigued and look forward to reading the rest of the book. I’ve been wanting for some time to read a good introduction to philosophy. My feeling is that this book won’t have breadth of coverage, but with the excerpts from classic texts I expect it to make several deep dives and be a starting point for further investigations.

Facebook’s BSD+PATENTS license no longer Apache compatible

So Apache has decided that the PATENTS grant in the ReactJS license is incompatible with the Apache license. The ReactJS PATENTS grant is mutually exclusive: you are granted use of patents that may be used by ReactJS but the moment you sue Facebook for any patent infringement your grant to the ReactJS patents is revoked.

The PATENTS grant seems both fairly innocuous, reasonable but also understandable how this could be interpreted as being incompatible with the Apache license.

Apparently what started this discussion is a question about the user of RocksDB, some sort of persistent key-value storage (of which I had never heard before all of this). Some good news: the RocksDB team has already merged a pull request that makes the project dual-licensed: GPL 2.0 or Apache licensed.

There is an open issue in the ReactJS Github to consider making the same change. Here’s hoping they do.

This is particularly relevant to me because I’ve been planning to use ReactJS with Django for the upcoming new PGA implementation for Apache Airavata. If this PATENTS situation isn’t resolved what options would we have in Airavata?

  • Preact or some other React compatible library. That would allow us to use the React API and if the PATENTS situation gets eventually resolved then perhaps we could even move back to use React.
  • VueJS. I’ve heard great things about VueJS and from what I’ve seen it looks good. Like React it keeps things simple, indeed it is probably simpler and easier for newcomers. This would be another good alternative.

More discussion on HN.

LA Trip, Day 3

Monday, December 5, 2016

The third day of our family vacation to Los Angeles.

Breakfast

Still a little jet lagged, we wake up by 6:30. We’re staying in a Fairfield Inn that has a food court area and we go there to buy breakfast sandwiches.  We eat the sandwiches in our room.

We a little anxious to get to Disneyland, but it doesn’t open until 9am. So we’re twiddling our thumbs…

Disneyland!

We arrive at the baggage check outside of Disneyland (and California Adventure). It takes a while to get through baggage check. Seems like a lot of family have loaded up their strollers like a pack mule, so there is a lot for the security staff to check.  When we get to baggage check we breeze through since the Tracy and the girls only have one bag each and I have nothing.

We’re in line waiting to get into Disneyland by 8:15. At 8:30 they start letting folks in. Since this is our first day, they take our pictures and associate them with our paper passes (no magic bands!).  On subsequent days they will just scan our passes and visually check to make sure that we’re the same people.

The park doesn’t actually open until 9am. While we wait we get our “first visit” buttons on main street. We also stopped to look at these beautiful moving displays in some of the windows.  They display scenes from Disney movies and every once in a while they rotate around and the scene completely changes. My picture won’t do it justice but here’s a scene from Princess and the Frog:

Princess and the Frog

The rope drops at 9am separating Main Street from Tomorrowland. First ride, Hyperspace mountain! Ceilidh has been looking forward to this for months. At one point she was convinced they wouldn’t have the Hyperspace overlay during our trip and instead it would be just plain Space Mountain, but fortunately they still have the Hyperspace overlay.

Excited to go on Hyperspace Mountain!

Next is the Buzz Lightyear ride. We find this version more enjoyable than the Disney World one. You have more range of motion because the guns aren’t attached to the cart.  I, of course, got the high score out of our family 😉

Before lunch we checked out Autopia, which is like Disney World’s Tomorrowland Speedway. Then Mr Toad’s Wild Ride, the Matterhorn and Star Tours.  Unfortunately the Matterhorn temporarily shut down just after we got into the bobsleds.  We enjoyed seeing BB-8 from The Force Awakens in the Star Tours ride.

Keira’s first driver’s license
Sadly, seconds later they ask us to get off

We then hiked over to California Adventure for lunch. I’m trying to remember now, I think Keira and I got pizza but Ceilidh and Tracy went to get corn dogs.  From where we were sitting we could see most of the latin themed parade out front.  We also picked up Radiator Springs fast passes that we would use later that day.

At this point we were pretty tired, but we did go to the Little Mermaid ride before heading back to the hotel to rest.

We crashed pretty hard and when we woke up and got back to California Adventure it was time for dinner so we went to Cocina Cucamonga. Our family loves Mexican food so this little quick serve restaurant really hit the spot.  Generally I really enjoyed the food at Disneyland.

After dinner we rode Toy Story Mania, Radiator Springs Racers and Luigi’s Rollickin’ Roadsters.  We ended the day by getting churros and watching the fireworks back in Magic Kingdom.

Don’t wanna brag, but that’s my score on the right
The girls at Radiator Springs

LA Trip, Day 2

Sunday, December 4, 2016

The second day of our family vacation to Los Angeles.

Breakfast

Since we’re still jet lagged we wake up early. The hotel breakfast doesn’t start until 7, so to tide us over, Ceilidh and I walk to a nearby Yum Yum Donuts shop. We each got a donut and I think the consensus is that the chocolate glazed twist donuts were the best of the bunch.

Afterwards we went downstairs for the hotel breakfast. It was good too. I had the biscuits and sausage gravy.

Pacific Coast Highway

This morning we want to see the ocean. So we plan to drive north and take the Pacific Coast Highway (PCH) south and eventually we’ll arrive at Santa Monica Pier.

Not long after getting on the PCH we find a beautiful, quiet place to pull over and watch the ocean waves crash against the rocks. It was very relaxing and peaceful. We took pictures and also just enjoyed the scenery for a while.  This was our first stop but little did we know that it would become our favorite spot along the PCH. No other spot was so beautiful and peaceful.

It’s hypnotic, really

We continued driving up the coast, looking for another good spot to pull over. However, what we found was that the coast quickly gets more densely populated, so we didn’t have much luck.  But the view was nice.

Santa Monica Pier

And we make it to the Santa Monica Pier.  First stop is the bathroom 🙂 Then, since we ate breakfast so early, we’re hungry. Fortunately the restaurant we planned to eat at, Rusty’s, opened at 11:30, about the time we got there.

Rusty’s is good eats. It’s decked out with a lot of surf boards. In the corner is a small stage and looks like they have live music on most nights.

I’m so glad to have a beer

After Rusty’s we walk around and take in the sights of the pier.  There are several street performers playing music as well as vendors making pieces of art.  Keira buys a piece of art that is a picture of dolphins painted on a small piece of glass.  We also just spent some time looking out over the water.

Ceilidh, wearing her “I (heart) LA” sweatshirt
The pier

Keira and I decide we want to wade into the water for a little while. It’s a little chilly so Tracy and Ceilidh decide to sit this one out.  Keira and I take off our shoes and find a same place to put them and then we start to walk into the water. The idea is to just wade in the water and to not get wet since we need to get back in the car and keep driving soon. However it’s not too long until the water rolls in and Keira tries to quickly backpedal away from the rising water. She trips and falls down, getting her pants all wet. It was a pretty funny moment for us. I take off my jacket and she wraps it around her waist.  Then we get back into the water, this time a little wiser about how to deal with the waves rolling in.

Soon after we get back in the car and head to our Fairfield Inn, which is just across the street from Disneyland.

Downtown Disney

As is our tradition whenever we go to Disney World, the night before actually going into the parks we got check out Downtown Disney.  We get a bite to eat at Earl of Sandwich. I got the Original 1762 which is a hot roast beef with cheese and horseradish sauce. It is so savory and spicy, so good.

The girls in front of a Christmas tree at Downtown Disney

And then the shopping begins. All of the Christie girls love shopping and I like helping them find cute things to buy.  Ceilidh finds a stuffed Eeyore that she instantly falls in love with. Usually she would wait until she also sees what other things she might want to buy that are in the park, but she absolutely adores this Eeyore, love at first sight, so she buys it right then and there.

He’s so cute!