{"action":"created","comment":{"url":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls/comments/200092890","pull_request_review_id":134338492,"id":200092890,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwMDA5Mjg5MA==","diff_hunk":"@@ -0,0 +1,204 @@\n+---\n+layout: article\n+section: Blog\n+title: \"Building a PWA with Glimmer.js\"\n+author: \"Marco Otte-Witte\"\n+github-handle: marcoow\n+twitter-handle: marcoow\n+---\n+\n+We recently set out to build a progressive web app with [Glimmer.js](http://glimmerjs.com). Instead of building it with [Ember.js](http://emberjs.com), which is our standard framework of choice, we wanted to see how suitable for prime-time Glimmer.js is and what we'd be able to accomplish with it. To put it short, we are really happy with how building the app went and the result that we were able to achieve. In this series of posts, we will give some insights into how we built the app, why we made particular decisions and what the result looks like.\n+\n+<!--break-->\n+\n+#### Breethe\n+\n+While this project was mostly meant as a technology spike to validate Glimmer's suitability for real projects as well as testing some techniques for running and serving web apps that we had in our minds for some time, we wanted to build something useful and meaningful. What we built is Breethe, a progressive web apps that gives users quick and easy access to air quality data for locations around the world. Pollution and global warming are getting worse rather than better and having easy access to data that shows how bad the situation actually is is the first step for everyone to question their decisions and maybe change a few things that can help improve the situation.\n+\n+![Video of the Breethe PWA](/images/posts/2018-07-03-building-a-pwa-with -glimmer-js/breethe-video.gif)\n+\n+The application is fully open source and [available on GitHub](https://github.com/simplabs/breethe-client).\n+\n+#### Glimmer.js\n+\n+Glimmer.js is a thin component library built on top of Ember.js's rendering engine, the Glimmer VM. It is optimized for small file size and maximum runtime performance and thus a great fit for situations where a full-featured framework like Ember.js is not needed and too heavy weight.\n+\n+Glimmer.js provides functionality for defining, composing and rendering components and keeps the DOM in sync with the component tree's internal state. It uses Ember CLI, the battle-tested command-line interface tool (CLI) from the Ember project, to help create and manage applications. Glimmer.js is written in TypeScript and so are applications built with it.\n+\n+As it is built on the Glimmer VM, it uses Handlebars-like syntax for its templates, e.g.:\n+\n+```hbs {% raw %}\n+{{#each measurementLists.first key=\"@index\"}}\n+\t<MeasurementRow\n+  \t@value={{measurement.value}}\n+\t  @parameter={{measurement.parameter}}\n+\t  @unit={{measurement.unit}}\n+\t/>\n+{{/each}}\n+{% endraw %}```\n+\n+These templates then get compiled to opcodes that the Glimmer VM (yes, this is a full-fledged VM that runs inside your JavaScript VM in the browser) processes and translates into DOM operations in the browser. For a detailed overview of how that works and why it results in very small bundle sizes as well as super fast initial and update renders, watch the talk I gave at the Ember.js Munich meetup last year:\n+\n+<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/vIRZDCyfOJc?rel=0\" frameborder=\"0\" allow=\"autoplay; encrypted-media\" allowfullscreen class=\"video\"></iframe>\n+\n+#### Building Breethe with Glimmer.js\n+\n+The Breethe app consists of two main screens, the Start page with the search form and the results page that shows the data and an air quality score for a particular location. These two screens are implemented in two components that the app's main component renders depending on the current state of the app.\n+\n+![The two main screens of the Breethe PWA](/images/posts/2018-07-03-building-a-pwa-with -glimmer-js/breethe-screens.png)\n+\n+As Glimmer.js is a UI component library only and does not include any routing functionality, we used added the Navigo router to set up logic that maps the current route to the corresponding application state and vice versa:\n+\n+```ts\n+_setupRouting() {\n+  this.router = new Navigo();\n+\n+  this.router\n+    .on('/', () => this.mode = MODE_SEARCH)\n+ \n+    .on('/search', () => this.mode = MODE_SEARCH)\n+\n+    .on('/search/:searchTerm', (params) => {\n+      this.mode = MODE_SEARCH;\n+      this.searchTerm = params.searchTerm;\n+     })\n+ \n+     .on('/location/:locationId/', (params) => {\n+       this.mode = MODE_RESULTS;\n+       this.searchTerm = params.locationId;\n+     })\n+\n+    .resolve(this.appState.route);\n+}\n+```\n+\n+First of all, we create a new router instance. Then we map URLs to the corresponding states of the app. The routes `/`, `/search` and `/search/:searchTerm` all map to the `MODE_SEARCH` mode that renders the search form and search results if there are any. The `/location/:locationId` route maps to the `MODE_RESULTS` mode that renders the component that displays a particular location's data and quality score. We use the `mode` property in two tracked properties `isSearchMode` and `isResultsMode`. [Tracked properties](https://glimmerjs.com/guides/tracked-properties) are Glimmer's equivalent to Ember's computed properties and will result in the component being re-rendered when their value changes.\n+\n+```ts\n+@tracked('mode')\n+get isSearchMode(): boolean {\n+  return this.mode === MODE_SEARCH;\n+}\n+\n+@tracked('mode')\n+get isResultsMode(): boolean {\n+  return this.mode === MODE_RESULTS;\n+}\n+```\n+\n+We can then use these properties in the template to render the respective component for the mode:\n+\n+```hbs {% raw %}\n+{{#if isSearchMode}}\n+  <Search @searchTerm={{searchTerm}}/>\n+{{else if isResultsMode}}\n+  <Location @locationId={{locationId}} />\n+{{/if}}\n+{% endraw %}```\n+\n+You might notice the `@` prefix of the `searchTerm` and `locationId` properties that are set on the components. This prefix distinguishes properties that are to be passed to the component instance as opposed to attributes that will be applied to the component's root DOM element.\n+\n+The `Search` component renders the `SearchForm` component that implements the text field for the search term and the button to submit the search:\n+\n+```hbs {% raw %}\n+<SearchForm\n+  @term={{searchTerm}}\n+  @onSubmit={{action searchByTerm}}\n+/>\n+{% endraw %}```\n+\n+`{% raw %}@onSubmit={{action searchByTerm}}{% endraw %}` assigns the `searchByTerm` method of the `Search` component as an action to the `@onSubmit` property of the `SearchForm` component. Whenever the search form is submitted, the component will invoke the assigned action:\n+\n+```ts\n+submitSearch(event) {\n+  event.preventDefault();\n+  let search = event.target.value;\n+  this.args.onSubmit(search);\n+ }\n+```\n+\n+The last line here calls the assigned action and thus invokes the `searchByTerm` method on the `Search` component. That method enables the loading state on the component, loads locations matching the search term, assigns them to its `locations` property and disables the loading state again:\n+\n+```ts\n+async searchByTerm(searchTerm) {\n+  this.loading = true;\n+  let url = `${__ENV_API_HOST__}/api/locations?filter[name]=${searchTerm}`;\n+  let locationsResponse = await fetch(url);\n+  let locationsPayload: { data: Location[] } = await locationsResponse.json();\n+  this.locations = locationsPayload.data;\n+  this.loading = false;\n+}\n+```\n+\n+The `loading` and `locations` properties are tracked properties so that changing them, results in the component to be re-rendered. They are used in the component's template like this:\n+\n+```hbs {% raw %}\n+<div class=\"results\">\n+  {{#if loading}}\n+    <div class=\"loader search-loader\"></div>\n+  {{else}}\n+    <ul>\n+      {{#each locations key=\"id\" as |location|}}\n+        <li class=\"result\">\n+          <a href=\"/location/{{location.id}}\" class=\"result-link\" data-navigo>\n+            {{location.label}}\n+          </a>\n+        </li>\n+      {{/each}}\n+    </ul>\n+  {{/if}}\n+</div>\n+{% endraw %}```\n+\n+This is just a brief overview of how an application built with Glimmer.js works. We will cover some of these things in more detail in future posts, particularly how we load and manage data with Orbit.js. For a closer look on the inner workings of Breethe, check out the [code on github](https://github.com/simplabs/breethe-client).\n+\n+#### From Glimmer.js Ember.js\n+\n+Besides making the Glimmer VM available to be used outside of Ember.js and offering a solution for situations where bundle size and load time performance is of crucial importance, Glimmer.js also serves as a testbed for new features and changes that will later make their way into the Ember.js framework. It is not bound to the strong stability guarantees that Ember.js makes and thus a great environment for experimenting with new approaches to existing problems that will usually require a few iterations until the API is stable.\n+\n+Some of these new things have already found their way back into Ember.js are (at least in some form):\n+\n+* The `@` syntax as shown above that clearly distinguishes properties that are set on a component instance vs. attributes that are set on a component's root DOM element - [this PR](https://github.com/emberjs/ember.js/commit/4bd3d7b882484919682ab0cdb57f81584abc503a) enables the feature flag by default.\n+* The possibility to use ES2015 classes instead of Ember.js' own object model - see [this blog post](https://medium.com/build-addepar/es-classes-in-ember-js-63e948e9d78e) for more information.\n+* Template-only components that do not have a wrapping `<div>` - can be enabled as an [optional feature](https://github.com/emberjs/ember-optional-features).\n+\n+Eventually it will be possible to seamlessly use Glimmer.js components in Ember.js applications (see the [quest issue](https://github.com/emberjs/ember.js/issues/16301) for more information). That will also enable \"upgrading\" Glimmer.js applications to Ember.js once they reach a certain size and complexity and the additional features and concepts that Ember.js provides over Glimmer.js justify a more heavy-weight framework.\n+\n+#### Testing\n+\n+Glimmer.js uses the new testing APIs that are also now available for Ember.js applications. These allow writing concise tests for asserting components render the expected results for a given set of properties and attributes:\n+\n+```js\n+import { module, test } from 'qunit';\n+import hbs from '@glimmer/inline-precompile';\n+import { setupRenderingTest } from '@glimmer/test-helpers';\n+\n+module('Component: MeasurementRow', function(hooks) {\n+  setupRenderingTest(hooks);\n+\n+  test('PPM Case', async function(assert) {\n+    await this.render(hbs`\n+      <MeasurementRow\n+        @value=12\n+        @parameter=pm25\n+        @unit=ppm\n+      />\n+    `);\n+    let label = this.containerElement.querySelector('[data-test-measurement-label]').textContent.trim();\n+    let value = this.containerElement.querySelector('[data-test-measurement-value]').textContent.trim();\n+    let unit = this.containerElement.querySelector('[data-test-measurement-unit]').textContent.trim();\n+\n+    assert.equal(label, 'PM25', 'Parameter is rendered');\n+    assert.equal(value, `12`, 'Value is rendered');\n+    assert.equal(unit, `ppm`, 'Unit is rendered');\n+  });\n+});\n+```\n+\n+This test case tests the `MeasurementRow` component by passing a set of properties and asserting that the DOM contains the expected elements with the expected content. The key element to be aware here is the invocation of `setupRenderingTest` which sets this test case up as a rendering test, which for example makes the `this.render` method available. For a more detailed overview of these API see the [talk on the topic](https://www.youtube.com/watch?v=8D-O4cSteRk) that [@TobiasBieniek](https://twitter.com/TobiasBieniek) gave at this year's EmberConf.","path":"blog/_posts/2018-07-03-building-a-pwa-with -glimmer-js.md","position":198,"original_position":198,"commit_id":"ce8915d99da7f0a1632c0654a81d714f7573fc0d","original_commit_id":"b9fd427a6eebc64a149eb8931aa018c80a236fcf","user":{"login":"Turbo87","id":141300,"node_id":"MDQ6VXNlcjE0MTMwMA==","avatar_url":"https://avatars2.githubusercontent.com/u/141300?v=4","gravatar_id":"","url":"https://api.github.com/users/Turbo87","html_url":"https://github.com/Turbo87","followers_url":"https://api.github.com/users/Turbo87/followers","following_url":"https://api.github.com/users/Turbo87/following{/other_user}","gists_url":"https://api.github.com/users/Turbo87/gists{/gist_id}","starred_url":"https://api.github.com/users/Turbo87/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Turbo87/subscriptions","organizations_url":"https://api.github.com/users/Turbo87/orgs","repos_url":"https://api.github.com/users/Turbo87/repos","events_url":"https://api.github.com/users/Turbo87/events{/privacy}","received_events_url":"https://api.github.com/users/Turbo87/received_events","type":"User","site_admin":false},"body":"yeah, but the testing APIs are not also used in Glimmer. they may look slightly similar, but they are in fact quite different in some regards.","created_at":"2018-07-04T11:12:36Z","updated_at":"2018-07-04T11:12:36Z","html_url":"https://github.com/simplabs/simplabs.github.io/pull/208#discussion_r200092890","pull_request_url":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls/208","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls/comments/200092890"},"html":{"href":"https://github.com/simplabs/simplabs.github.io/pull/208#discussion_r200092890"},"pull_request":{"href":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls/208"}},"in_reply_to_id":200063201},"pull_request":{"url":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls/208","id":199071552,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk5MDcxNTUy","html_url":"https://github.com/simplabs/simplabs.github.io/pull/208","diff_url":"https://github.com/simplabs/simplabs.github.io/pull/208.diff","patch_url":"https://github.com/simplabs/simplabs.github.io/pull/208.patch","issue_url":"https://api.github.com/repos/simplabs/simplabs.github.io/issues/208","number":208,"state":"open","locked":false,"title":"first blog post about breethe","user":{"login":"marcoow","id":1510,"node_id":"MDQ6VXNlcjE1MTA=","avatar_url":"https://avatars1.githubusercontent.com/u/1510?v=4","gravatar_id":"","url":"https://api.github.com/users/marcoow","html_url":"https://github.com/marcoow","followers_url":"https://api.github.com/users/marcoow/followers","following_url":"https://api.github.com/users/marcoow/following{/other_user}","gists_url":"https://api.github.com/users/marcoow/gists{/gist_id}","starred_url":"https://api.github.com/users/marcoow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/marcoow/subscriptions","organizations_url":"https://api.github.com/users/marcoow/orgs","repos_url":"https://api.github.com/users/marcoow/repos","events_url":"https://api.github.com/users/marcoow/events{/privacy}","received_events_url":"https://api.github.com/users/marcoow/received_events","type":"User","site_admin":false},"body":"This is the first post about how we built Breethe. It covers what Breethe is and the basics of Glimmer.js. See #207 for an outlook of the other posts I'm planning in this series.","created_at":"2018-07-03T20:11:41Z","updated_at":"2018-07-04T11:12:36Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c5efa142a3772526f79e7c0b8075d67c55f7ade8","assignee":null,"assignees":[],"requested_reviewers":[{"login":"pangratz","id":341877,"node_id":"MDQ6VXNlcjM0MTg3Nw==","avatar_url":"https://avatars1.githubusercontent.com/u/341877?v=4","gravatar_id":"","url":"https://api.github.com/users/pangratz","html_url":"https://github.com/pangratz","followers_url":"https://api.github.com/users/pangratz/followers","following_url":"https://api.github.com/users/pangratz/following{/other_user}","gists_url":"https://api.github.com/users/pangratz/gists{/gist_id}","starred_url":"https://api.github.com/users/pangratz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pangratz/subscriptions","organizations_url":"https://api.github.com/users/pangratz/orgs","repos_url":"https://api.github.com/users/pangratz/repos","events_url":"https://api.github.com/users/pangratz/events{/privacy}","received_events_url":"https://api.github.com/users/pangratz/received_events","type":"User","site_admin":false},{"login":"wadie","id":1206307,"node_id":"MDQ6VXNlcjEyMDYzMDc=","avatar_url":"https://avatars0.githubusercontent.com/u/1206307?v=4","gravatar_id":"","url":"https://api.github.com/users/wadie","html_url":"https://github.com/wadie","followers_url":"https://api.github.com/users/wadie/followers","following_url":"https://api.github.com/users/wadie/following{/other_user}","gists_url":"https://api.github.com/users/wadie/gists{/gist_id}","starred_url":"https://api.github.com/users/wadie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wadie/subscriptions","organizations_url":"https://api.github.com/users/wadie/orgs","repos_url":"https://api.github.com/users/wadie/repos","events_url":"https://api.github.com/users/wadie/events{/privacy}","received_events_url":"https://api.github.com/users/wadie/received_events","type":"User","site_admin":false},{"login":"geekygrappler","id":3627301,"node_id":"MDQ6VXNlcjM2MjczMDE=","avatar_url":"https://avatars3.githubusercontent.com/u/3627301?v=4","gravatar_id":"","url":"https://api.github.com/users/geekygrappler","html_url":"https://github.com/geekygrappler","followers_url":"https://api.github.com/users/geekygrappler/followers","following_url":"https://api.github.com/users/geekygrappler/following{/other_user}","gists_url":"https://api.github.com/users/geekygrappler/gists{/gist_id}","starred_url":"https://api.github.com/users/geekygrappler/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/geekygrappler/subscriptions","organizations_url":"https://api.github.com/users/geekygrappler/orgs","repos_url":"https://api.github.com/users/geekygrappler/repos","events_url":"https://api.github.com/users/geekygrappler/events{/privacy}","received_events_url":"https://api.github.com/users/geekygrappler/received_events","type":"User","site_admin":false},{"login":"jessica-jordan","id":8811742,"node_id":"MDQ6VXNlcjg4MTE3NDI=","avatar_url":"https://avatars3.githubusercontent.com/u/8811742?v=4","gravatar_id":"","url":"https://api.github.com/users/jessica-jordan","html_url":"https://github.com/jessica-jordan","followers_url":"https://api.github.com/users/jessica-jordan/followers","following_url":"https://api.github.com/users/jessica-jordan/following{/other_user}","gists_url":"https://api.github.com/users/jessica-jordan/gists{/gist_id}","starred_url":"https://api.github.com/users/jessica-jordan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jessica-jordan/subscriptions","organizations_url":"https://api.github.com/users/jessica-jordan/orgs","repos_url":"https://api.github.com/users/jessica-jordan/repos","events_url":"https://api.github.com/users/jessica-jordan/events{/privacy}","received_events_url":"https://api.github.com/users/jessica-jordan/received_events","type":"User","site_admin":false},{"login":"niklaslong","id":13221615,"node_id":"MDQ6VXNlcjEzMjIxNjE1","avatar_url":"https://avatars0.githubusercontent.com/u/13221615?v=4","gravatar_id":"","url":"https://api.github.com/users/niklaslong","html_url":"https://github.com/niklaslong","followers_url":"https://api.github.com/users/niklaslong/followers","following_url":"https://api.github.com/users/niklaslong/following{/other_user}","gists_url":"https://api.github.com/users/niklaslong/gists{/gist_id}","starred_url":"https://api.github.com/users/niklaslong/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/niklaslong/subscriptions","organizations_url":"https://api.github.com/users/niklaslong/orgs","repos_url":"https://api.github.com/users/niklaslong/repos","events_url":"https://api.github.com/users/niklaslong/events{/privacy}","received_events_url":"https://api.github.com/users/niklaslong/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[{"id":336126252,"node_id":"MDU6TGFiZWwzMzYxMjYyNTI=","url":"https://api.github.com/repos/simplabs/simplabs.github.io/labels/blog%20post","name":"blog post","color":"fbca04","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls/208/commits","review_comments_url":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls/208/comments","review_comment_url":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls/comments{/number}","comments_url":"https://api.github.com/repos/simplabs/simplabs.github.io/issues/208/comments","statuses_url":"https://api.github.com/repos/simplabs/simplabs.github.io/statuses/ce8915d99da7f0a1632c0654a81d714f7573fc0d","head":{"label":"simplabs:breethe-post-1","ref":"breethe-post-1","sha":"ce8915d99da7f0a1632c0654a81d714f7573fc0d","user":{"login":"simplabs","id":56627,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU2NjI3","avatar_url":"https://avatars3.githubusercontent.com/u/56627?v=4","gravatar_id":"","url":"https://api.github.com/users/simplabs","html_url":"https://github.com/simplabs","followers_url":"https://api.github.com/users/simplabs/followers","following_url":"https://api.github.com/users/simplabs/following{/other_user}","gists_url":"https://api.github.com/users/simplabs/gists{/gist_id}","starred_url":"https://api.github.com/users/simplabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/simplabs/subscriptions","organizations_url":"https://api.github.com/users/simplabs/orgs","repos_url":"https://api.github.com/users/simplabs/repos","events_url":"https://api.github.com/users/simplabs/events{/privacy}","received_events_url":"https://api.github.com/users/simplabs/received_events","type":"Organization","site_admin":false},"repo":{"id":10031701,"node_id":"MDEwOlJlcG9zaXRvcnkxMDAzMTcwMQ==","name":"simplabs.github.io","full_name":"simplabs/simplabs.github.io","owner":{"login":"simplabs","id":56627,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU2NjI3","avatar_url":"https://avatars3.githubusercontent.com/u/56627?v=4","gravatar_id":"","url":"https://api.github.com/users/simplabs","html_url":"https://github.com/simplabs","followers_url":"https://api.github.com/users/simplabs/followers","following_url":"https://api.github.com/users/simplabs/following{/other_user}","gists_url":"https://api.github.com/users/simplabs/gists{/gist_id}","starred_url":"https://api.github.com/users/simplabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/simplabs/subscriptions","organizations_url":"https://api.github.com/users/simplabs/orgs","repos_url":"https://api.github.com/users/simplabs/repos","events_url":"https://api.github.com/users/simplabs/events{/privacy}","received_events_url":"https://api.github.com/users/simplabs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/simplabs/simplabs.github.io","description":"The source code for http://simplabs.com","fork":false,"url":"https://api.github.com/repos/simplabs/simplabs.github.io","forks_url":"https://api.github.com/repos/simplabs/simplabs.github.io/forks","keys_url":"https://api.github.com/repos/simplabs/simplabs.github.io/keys{/key_id}","collaborators_url":"https://api.github.com/repos/simplabs/simplabs.github.io/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/simplabs/simplabs.github.io/teams","hooks_url":"https://api.github.com/repos/simplabs/simplabs.github.io/hooks","issue_events_url":"https://api.github.com/repos/simplabs/simplabs.github.io/issues/events{/number}","events_url":"https://api.github.com/repos/simplabs/simplabs.github.io/events","assignees_url":"https://api.github.com/repos/simplabs/simplabs.github.io/assignees{/user}","branches_url":"https://api.github.com/repos/simplabs/simplabs.github.io/branches{/branch}","tags_url":"https://api.github.com/repos/simplabs/simplabs.github.io/tags","blobs_url":"https://api.github.com/repos/simplabs/simplabs.github.io/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/simplabs/simplabs.github.io/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/simplabs/simplabs.github.io/git/refs{/sha}","trees_url":"https://api.github.com/repos/simplabs/simplabs.github.io/git/trees{/sha}","statuses_url":"https://api.github.com/repos/simplabs/simplabs.github.io/statuses/{sha}","languages_url":"https://api.github.com/repos/simplabs/simplabs.github.io/languages","stargazers_url":"https://api.github.com/repos/simplabs/simplabs.github.io/stargazers","contributors_url":"https://api.github.com/repos/simplabs/simplabs.github.io/contributors","subscribers_url":"https://api.github.com/repos/simplabs/simplabs.github.io/subscribers","subscription_url":"https://api.github.com/repos/simplabs/simplabs.github.io/subscription","commits_url":"https://api.github.com/repos/simplabs/simplabs.github.io/commits{/sha}","git_commits_url":"https://api.github.com/repos/simplabs/simplabs.github.io/git/commits{/sha}","comments_url":"https://api.github.com/repos/simplabs/simplabs.github.io/comments{/number}","issue_comment_url":"https://api.github.com/repos/simplabs/simplabs.github.io/issues/comments{/number}","contents_url":"https://api.github.com/repos/simplabs/simplabs.github.io/contents/{+path}","compare_url":"https://api.github.com/repos/simplabs/simplabs.github.io/compare/{base}...{head}","merges_url":"https://api.github.com/repos/simplabs/simplabs.github.io/merges","archive_url":"https://api.github.com/repos/simplabs/simplabs.github.io/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/simplabs/simplabs.github.io/downloads","issues_url":"https://api.github.com/repos/simplabs/simplabs.github.io/issues{/number}","pulls_url":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls{/number}","milestones_url":"https://api.github.com/repos/simplabs/simplabs.github.io/milestones{/number}","notifications_url":"https://api.github.com/repos/simplabs/simplabs.github.io/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/simplabs/simplabs.github.io/labels{/name}","releases_url":"https://api.github.com/repos/simplabs/simplabs.github.io/releases{/id}","deployments_url":"https://api.github.com/repos/simplabs/simplabs.github.io/deployments","created_at":"2013-05-13T12:59:23Z","updated_at":"2018-06-27T09:43:03Z","pushed_at":"2018-07-04T10:56:39Z","git_url":"git://github.com/simplabs/simplabs.github.io.git","ssh_url":"git@github.com:simplabs/simplabs.github.io.git","clone_url":"https://github.com/simplabs/simplabs.github.io.git","svn_url":"https://github.com/simplabs/simplabs.github.io","homepage":"","size":53290,"stargazers_count":1,"watchers_count":1,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":5,"mirror_url":null,"archived":false,"open_issues_count":13,"license":null,"forks":5,"open_issues":13,"watchers":1,"default_branch":"master"}},"base":{"label":"simplabs:master","ref":"master","sha":"6e9bef108c44accac1621ba632a8228f943cbda4","user":{"login":"simplabs","id":56627,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU2NjI3","avatar_url":"https://avatars3.githubusercontent.com/u/56627?v=4","gravatar_id":"","url":"https://api.github.com/users/simplabs","html_url":"https://github.com/simplabs","followers_url":"https://api.github.com/users/simplabs/followers","following_url":"https://api.github.com/users/simplabs/following{/other_user}","gists_url":"https://api.github.com/users/simplabs/gists{/gist_id}","starred_url":"https://api.github.com/users/simplabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/simplabs/subscriptions","organizations_url":"https://api.github.com/users/simplabs/orgs","repos_url":"https://api.github.com/users/simplabs/repos","events_url":"https://api.github.com/users/simplabs/events{/privacy}","received_events_url":"https://api.github.com/users/simplabs/received_events","type":"Organization","site_admin":false},"repo":{"id":10031701,"node_id":"MDEwOlJlcG9zaXRvcnkxMDAzMTcwMQ==","name":"simplabs.github.io","full_name":"simplabs/simplabs.github.io","owner":{"login":"simplabs","id":56627,"node_id":"MDEyOk9yZ2FuaXphdGlvbjU2NjI3","avatar_url":"https://avatars3.githubusercontent.com/u/56627?v=4","gravatar_id":"","url":"https://api.github.com/users/simplabs","html_url":"https://github.com/simplabs","followers_url":"https://api.github.com/users/simplabs/followers","following_url":"https://api.github.com/users/simplabs/following{/other_user}","gists_url":"https://api.github.com/users/simplabs/gists{/gist_id}","starred_url":"https://api.github.com/users/simplabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/simplabs/subscriptions","organizations_url":"https://api.github.com/users/simplabs/orgs","repos_url":"https://api.github.com/users/simplabs/repos","events_url":"https://api.github.com/users/simplabs/events{/privacy}","received_events_url":"https://api.github.com/users/simplabs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/simplabs/simplabs.github.io","description":"The source code for http://simplabs.com","fork":false,"url":"https://api.github.com/repos/simplabs/simplabs.github.io","forks_url":"https://api.github.com/repos/simplabs/simplabs.github.io/forks","keys_url":"https://api.github.com/repos/simplabs/simplabs.github.io/keys{/key_id}","collaborators_url":"https://api.github.com/repos/simplabs/simplabs.github.io/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/simplabs/simplabs.github.io/teams","hooks_url":"https://api.github.com/repos/simplabs/simplabs.github.io/hooks","issue_events_url":"https://api.github.com/repos/simplabs/simplabs.github.io/issues/events{/number}","events_url":"https://api.github.com/repos/simplabs/simplabs.github.io/events","assignees_url":"https://api.github.com/repos/simplabs/simplabs.github.io/assignees{/user}","branches_url":"https://api.github.com/repos/simplabs/simplabs.github.io/branches{/branch}","tags_url":"https://api.github.com/repos/simplabs/simplabs.github.io/tags","blobs_url":"https://api.github.com/repos/simplabs/simplabs.github.io/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/simplabs/simplabs.github.io/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/simplabs/simplabs.github.io/git/refs{/sha}","trees_url":"https://api.github.com/repos/simplabs/simplabs.github.io/git/trees{/sha}","statuses_url":"https://api.github.com/repos/simplabs/simplabs.github.io/statuses/{sha}","languages_url":"https://api.github.com/repos/simplabs/simplabs.github.io/languages","stargazers_url":"https://api.github.com/repos/simplabs/simplabs.github.io/stargazers","contributors_url":"https://api.github.com/repos/simplabs/simplabs.github.io/contributors","subscribers_url":"https://api.github.com/repos/simplabs/simplabs.github.io/subscribers","subscription_url":"https://api.github.com/repos/simplabs/simplabs.github.io/subscription","commits_url":"https://api.github.com/repos/simplabs/simplabs.github.io/commits{/sha}","git_commits_url":"https://api.github.com/repos/simplabs/simplabs.github.io/git/commits{/sha}","comments_url":"https://api.github.com/repos/simplabs/simplabs.github.io/comments{/number}","issue_comment_url":"https://api.github.com/repos/simplabs/simplabs.github.io/issues/comments{/number}","contents_url":"https://api.github.com/repos/simplabs/simplabs.github.io/contents/{+path}","compare_url":"https://api.github.com/repos/simplabs/simplabs.github.io/compare/{base}...{head}","merges_url":"https://api.github.com/repos/simplabs/simplabs.github.io/merges","archive_url":"https://api.github.com/repos/simplabs/simplabs.github.io/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/simplabs/simplabs.github.io/downloads","issues_url":"https://api.github.com/repos/simplabs/simplabs.github.io/issues{/number}","pulls_url":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls{/number}","milestones_url":"https://api.github.com/repos/simplabs/simplabs.github.io/milestones{/number}","notifications_url":"https://api.github.com/repos/simplabs/simplabs.github.io/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/simplabs/simplabs.github.io/labels{/name}","releases_url":"https://api.github.com/repos/simplabs/simplabs.github.io/releases{/id}","deployments_url":"https://api.github.com/repos/simplabs/simplabs.github.io/deployments","created_at":"2013-05-13T12:59:23Z","updated_at":"2018-06-27T09:43:03Z","pushed_at":"2018-07-04T10:56:39Z","git_url":"git://github.com/simplabs/simplabs.github.io.git","ssh_url":"git@github.com:simplabs/simplabs.github.io.git","clone_url":"https://github.com/simplabs/simplabs.github.io.git","svn_url":"https://github.com/simplabs/simplabs.github.io","homepage":"","size":53290,"stargazers_count":1,"watchers_count":1,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":5,"mirror_url":null,"archived":false,"open_issues_count":13,"license":null,"forks":5,"open_issues":13,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls/208"},"html":{"href":"https://github.com/simplabs/simplabs.github.io/pull/208"},"issue":{"href":"https://api.github.com/repos/simplabs/simplabs.github.io/issues/208"},"comments":{"href":"https://api.github.com/repos/simplabs/simplabs.github.io/issues/208/comments"},"review_comments":{"href":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls/208/comments"},"review_comment":{"href":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/simplabs/simplabs.github.io/pulls/208/commits"},"statuses":{"href":"https://api.github.com/repos/simplabs/simplabs.github.io/statuses/ce8915d99da7f0a1632c0654a81d714f7573fc0d"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"Turbo87"}}