This commit is contained in:
dannyrb committed 2019-07-04 16:12:43 -04:00
1 parent 5ac9048ef0
commit b73ea99971
714 files changed
+32644 -541

No files matched your search

View File
Whitespace-only changes.
-54
View File
@@ -1,54 +0,0 @@
<div class='row'>
<div class='column' style='text-align: right; padding: 0 20px'>
<strong>Looking for a Deploy Preview?</strong>
<a onclick="function redirect() { window.location.href='/demo/'; } redirect();">Deploy Preview for Viewer</a>
</div>
<div class='column' style='text-align: left; padding: 0 20px'>
<a href="https://www.netlify.com">
<img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg"/>
</a>
</div>
</div>
> ATTENTION! You are looking at the docs for the `React` version of the OHIF
> Viewer. If you're looking for the `Meteor` version's documentation (now
> deprecated), select it's version from the dropdown box in the top left corner
> of this page.
# Introduction
The [Open Health Imaging Foundation][ohif-org] (OHIF) Viewer is an open source,
web-based, medical imaging viewer. It can be configured to connect to Image
Archives that support [DicomWeb][dicom-web], and offers support for mapping to
proprietary API formats. OHIF maintained extensions add support for viewing,
annotating, and reporting on DICOM images in 2D (slices) and 3D (volumes).
![OHIF Viewer Screenshot](../assets/img/viewer.png)
<center><i>The <strong>OHIF Viewer</strong>: A general purpose DICOM Viewer (<a href="http://viewer.ohif.org/">Live Demo</a>)</center>
The Open Health Imaging Foundation intends to provide a simple general purpose
DICOM Viewer which can be easily extended for specific uses. If you find
yourself unable to extend the viewer for your purposes, please reach out via our
[GitHub issues][gh-issues]. We are actively seeking feedback on ways to improve
our integration and extension points.
## Where to Next?
Check out these helpful links:
- Ready to dive into some code? Check out our
[Getting Started Guide](./essentials/getting-started.md).
- We're an active, vibrant community.
[Learn how you can be more involved.](./contributing.md)
- Feeling lost? Read our [help page](./help.md).
<!--
Links
-->
<!-- prettier-ignore-start -->
[ohif-org]: https://www.ohif.org
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
[gh-issues]: https://github.com/OHIF/Viewers/issues
<!-- prettier-ignore-end -->
-51
View File
@@ -1,51 +0,0 @@
# OHIF Viewers
- Essentials
- [Getting Started](essentials/getting-started.md)
- [Installation](essentials/installation.md)
- [Data Source](essentials/data-source.md)
- [Configuration](essentials/configuration.md)
- [Themeing](essentials/themeing.md)
- [Translating](essentials/translating.md)
- [Troubleshooting](essentials/troubleshooting.md)
- [Scope of Project](essentials/scope-of-project.md)
---
- [Advanced](advanced/index.md)
- [Architecture](advanced/architecture.md)
- [Overview](advanced/architecture.md#overview)
- [Business Logic](advanced/architecture.md#business-logic)
- [Component Library](advanced/architecture.md#react-component-library)
- [Extensions](advanced/architecture.md#misc-extensions)
- [Diagram](advanced/architecture.md#diagram)
- [Common Questions](advanced/architecture.md#common-questions)
- [Extensions](advanced/extensions.md)
- [Overview](advanced/extensions.md#overview)
- [Modules](advanced/extensions.md#modules)
- [Registering](advanced/extensions.md#registering-extensions)
- [OHIF Maintained](advanced/extensions.md#ohif-maintained-extensions)
- [Custom Tools](advanced/custom-tools.md)
---
- [Deployment](deployment/index.md)
- [Embedded](deployment/index.md#embedded-viewer)
- [Stand-alone](deployment/index.md#stand-alone-viewer)
- [Data](deployment/index.md#data)
- Recipes
- Script Include
- [Embedding the Viewer](deployment/recipes/embedded-viewer.md)
- Stand-Alone
- [Build for Production](deployment/recipes/build-for-production.md)
- [Static](deployment/recipes/static-assets.md)
- [Nginx + Image Archive](deployment/recipes/nginx--image-archive.md)
- [User Account Control](deployment/recipes/user-account-control.md)
- [Google Cloud Healthcare](connecting-to-image-archives/google-cloud-healthcare.md)
---
- [Contributing](contributing.md)
- [FAQ](frequently-asked-questions.md)
- [Roadmap](roadmap.md)
- [Help](help.md)
@@ -1,62 +0,0 @@
<table>
<thead>
<tr>
<th>Extension</th>
<th>Description</th>
<th>Modules</th>
</tr>
</thead>
<tbody>
<!-- CORNERSTONE.js -->
<tr>
<td>
<a href="https://www.npmjs.com/package/ohif-cornerstone-extension">
Cornerstone
</a>
</td>
<td>
A viewport powered by <code>cornerstone.js</code>. Adds support for 2D DICOM rendering and manipulation, as well as support for the tools features in <a href="https://tools.cornerstonejs.org/examples/"><code>cornerstone-tools</code></a>. Also adds "CINE Dialog" to the Toolbar.
</td>
<td>Viewport, Toolbar</td>
</tr>
<!-- VTK.js -->
<tr>
<td>
<a href="https://www.npmjs.com/package/ohif-vtk-extension">
VTK.js
</a>
</td>
<td>
A viewport powered by <code>vtk.js</code>. Adds support for volume renderings and advanced features like MPR. Also adds "3D Rotate" to the Toolbar.
</td>
<td>Viewport, Toolbar</td>
</tr>
<tr>
<td>
<a href="">HTML</a>
</td>
<td>
Renders text and HTML content for <a href="https://github.com/OHIF/Viewers/blob/react/extensions/ohif-dicom-html-extension/src/OHIFDicomHtmlSopClassHandler.js#L7-L15">specific SopClassUIDs</a>.
</td>
<td>Viewport, SopClassHandler</td>
</tr>
<tr>
<td>
<a href="https://www.npmjs.com/package/ohif-dicom-pdf-extension">PDF</a>
</td>
<td>
Renders PDFs for a <a href="https://github.com/OHIF/Viewers/blob/react/extensions/ohif-dicom-pdf-extension/src/OHIFDicomPDFSopClassHandler.js#L8">specific SopClassUID</a>.
</td>
<td>Viewport, SopClassHandler</td>
</tr>
<tr>
<td>
<a href="https://www.npmjs.com/package/ohif-dicom-microscopy-extension">Microscopy</a>
</td>
<td>
Renders Microscopy images for a <a href="https://github.com/OHIF/Viewers/blob/react/extensions/ohif-dicom-microscopy-extension/src/DicomMicroscopySopClassHandler.js#L6">specific SopClassUID</a>.
</td>
<td>Viewport, SopClassHandler</td>
</tr>
</tbody>
</table>
-100
View File
@@ -1,100 +0,0 @@
# Architecture
Looking to extend your instance of the OHIF Viewer? Want learn how to reuse _a
portion_ of the Viewer in your own application? Or maybe you want to get
involved and draft or suggest a new feature? Regardless, you're in the right
place!
The OHIF Viewer aims to be decoupled, configurable, and extensible; while this
allows our code to be used in more ways, it also increases complexity. Below, we
aim to demistify that complexity by providing insight into how our Viewer is
architected, and the role each of it's dependent libraries plays.
## Overview
The [`OHIF/Viewers`](https://github.com/OHIF/Viewers/tree/react) repository
contains the source code for the OHIF Medical Imaging Viewer. It is effectively
a React
[progressive web app](https://developers.google.com/web/progressive-web-apps/)
(PWA) that combines the business logic housed in
[`OHIF/ohif-core`](https://github.com/OHIF/ohif-core) and the components in our
React Component library
[`OHIF/react-viewerbase`](https://github.com/OHIF/react-viewerbase). It provides
customization for common use cases through
[configuration](../essentials/configuration.md) and for adding functionality via
[extensions](./extensions.md).
### Business Logic
Our goal is to maintain the majority of our business logic in
[`OHIF/ohif-core`](https://github.com/OHIF/ohif-core). `ohif-core` offers
pre-packaged solutions for features common to Web-based medical imaging viewers.
For example:
- Hotkeys
- DICOM Web
- Hanging Protocols
- Managing a study's measurements
- Managing a study's DICOM metadata
- A flexible pattern for extensions
- [And many others](https://github.com/OHIF/ohif-core/blob/master/src/index.js#L49-L69)
It does this while remaining decoupled from any particular view library or
rendering logic. While we use it to power our React Viewer, it can be used with
Vue, React, Vanilla JS, or any number of other frameworks.
### React Component Library
[`OHIF/react-viewerbase`](https://github.com/OHIF/react-viewerbase) is a React
Component library that contains the reusable components that power the OHIF
Viewer. It allows us to build, compose, and test components in isolation; easing
the development process by reducing the need to stand-up a local PACS with test
case data.
[Check out our component library!](https://react.ohif.org/)
### Misc. Extensions
Want to add custom logic or UI Components to the OHIF Viewer, but don't want to
maintain a fork? We expose common integration points via
[extensions](./extensions.md) to make that possible. For a list of extensions
maintained by OHIF,
[check out this helpful table](./extensions.html#ohif-maintained-extensions).
If you find yourself thinking "I wish the Viewer could do X", and you can't
accomplish it with an extension today, create a GitHub issue! We're actively
looking for ways to improve our extensibility ^\_^
[Click here to read more about extensions!](./extensions.md)
### Diagram
This diagram is a conceptual illustration of how the Viewer is architected.
0. (optional) `extensions` can be registered with `ohif-core`'s extension
manager
1. `ohif-core` provides bussiness logic and a way for `viewer` to access
registered extensions
1. The `viewer` composes and provides data to components from our component
library (`react-viewerbase`)
1. The `viewer` can be built and served as a stand-alone PWA, or as an
embeddable package
([`ohif-viewer`](https://www.npmjs.com/package/ohif-viewer))
![Architecture Diagram](../assets/img/architecture-diagram.png)
<center><i>architecture diagram</i></center>
## Common Questions
> When should I use the packaged source `ohif-viewer` versus building a PWA from
> the source?
...
> Can I create my own Viewer using Vue.js or Angular.js?
You can, but you will not be able to leverage as much of the existing code and
components. `ohif-core` could still be used for business logic, and to provide a
model for extensions. `react-viewerbase` would then become a guide for the
components you would need to recreate.
-8
View File
@@ -1,8 +0,0 @@
# Tool Management
This is not yet exposed in an easy/convenient way. Most tools are currently
added by creating new Viewport, Toolbar, and SOPInstanceHandler extension
modules. You can read more about that approach in [extensions](./extensions.md).
In the near future, we intend to improve the extensibility of tools for existing
Viewports (like our Cornerstone.js and VTK.js viewports).
-230
View File
@@ -1,230 +0,0 @@
# Extensions
Extensions add new functionality to the viewer by registering one or more
modules. They go one step further than configuration in that they allow us to
inject custom React components, so long as they adhere to the module's
interface. This can be something as simple as adding a new button to the
toolbar, or as complex as a new viewport capable of rendering volumes in 3D.
- [Overview](#overview)
- [Modules](#modules)
- [Commands](#commands)
- [Hotkeys](#hotkeys)
- [Toolbar](#toolbar)
- [Panel](#panel)
- [Viewport](#viewport)
- [SOP Class Handler](#sopclasshandler)
## Overview
At a glance, an extension is a javascript object that has an `id` property, and
one or more "module" methods. You can find an abbreviated extension below, or
[view the source][example-ext-src] of our example extension.
```js
export default {
/**
* Only required property. Should be a unique value across all extensions.
*/
id: 'example-extension',
/**
* Registers one or more named commands scoped to a context. Commands are
* the primary means for...
*/
getCommandsModule() {
return {
defaultContext: 'VIEWER'
actions: { ... },
definitions: { ... }
}
},
/**
* Allows you to provide toolbar definitions that will be merged with any
* existing application toolbar configuration. Used to determine which
* buttons should be visible when, their order, what happens when they're
* clicked, etc.
*/
getToolbarModule() {
return {
definitions: [ ... ],
defaultContext: 'ACTIVE_VIEWPORT::CORNERSTONE'
}
}
/**
* Not yet implemented
*/
getPanelModule: () => null,
/**
* Registers a ReactComponent that should be used to render data in a
* Viewport. The first registered viewport is our "default viewport". If
* more than one viewport is registered, we use `SopClassHandlers` to
* determine which viewport should be used.
*/
getViewportModule: () => reactViewportComponent,
/** Provides a whitelist of SOPClassUIDs the viewport is capable of rendering.
* Can modify default behavior for methods like `getDisplaySetFromSeries` */
getSopClassHandler: () => {
id: 'some-other-unique-id',
sopClassUids: [ ... ],
getDisplaySetFromSeries: (series, study, dicomWebClient, authorizationHeaders) => { ... }
},
}
```
### Modules
There are a few different module types. Each module type allows us to extend the
viewer in a different way, and provides a consistent API for us to do so. You
can find a full list of the different types of modules
[`in ohif-core`][module-types]. Information on each type of module, it's API,
and how we determine when/where it should be used is included below.
> NOTE: Modifying the extensions/modules registered to the OHIF Viewer currently
> requires us to import and pass extensions to the ExtensionManager in
> `src/App.js`, then rebuild the application. Long-term, we intend to make it
> possible to accomplish this without a build step.
#### Commands
The Commands Module allows us to register one or more commands scoped to
specific contexts. Commands can be run by [hotkeys][#], [toolbar buttons][#],
and any registered custom react component (like a [viewport][#] or [panel][#]).
Here is a simple example commands module:
```js
{
getCommandsModule() {
return {
actions: {
speak: ({ viewports, words }) => {
console.log(viewports, words);
},
},
definitions: {
rotateViewportCW: {
commandFn: actions.rotateViewport,
storeContexts: ['viewports'],
options: { rotation: 90 }
},
rotateViewportCCW: {
commandFn: actions.rotateViewport,
storeContexts: ['viewports'],
options: { rotation: -90 },
context: 'ACTIVE_VIEWER::CORNERSTONE'
},
},
defaultContext: 'VIEWER'
}
}
}
```
#### Viewport
An extension can register a Viewport Module by providing a `getViewportModule()`
method that returns a React Component. The React component will receive the
following props:
```js
children: PropTypes.arrayOf(PropTypes.element)
studies: PropTypes.object,
displaySet: PropTypes.object,
viewportData: PropTypes.object, // { studies, displaySet }
viewportIndex: PropTypes.number,
children: PropTypes.node,
customProps: PropTypes.object
```
Viewport components are managed by the `LayoutManager`. Which Viewport component
is used depends on:
- The Layout Configuration
- Registered SopClassHandlers
- The SopClassUID for visible/selected datasets
![Cornerstone Viewport](../assets/img/extensions-viewport.png)
<center><i>An example of three Viewports</i></center>
For a complete example implementation,
[check out the OHIFCornerstoneViewport](https://github.com/OHIF/Viewers/blob/react/extensions/ohif-cornerstone-extension/src/OHIFCornerstoneViewport.js).
#### Toolbar
An extension can register a Toolbar Module by providing a `getToolbarModule()`
method that returns a React Component. The component does not receive any props.
If you want to modify or react to state, you will need to connect to the redux
store.
![Toolbar Extension](../assets/img/extensions-toolbar.gif)
<center><i>A toolbar extension example</i></center>
Toolbar components are rendered in the `ToolbarRow` component.
For a complete example implementation,
[check out the OHIFCornerstoneViewport's Toolbar Module](https://github.com/OHIF/Viewers/blob/react/extensions/ohif-cornerstone-extension/src/ToolbarModule.js).
#### SopClassHandler
...
#### Panel
> The panel module is not yet in use.
#### Hotkeys
...
### Registering Extensions
Extensions are registered for the application at startup. The
`ExtensionManager`, exposed by `ohif-core`, registers a list of extensions with
our application's store. Each module provided by the extension becomes available
via `state.plugins.availablePlugins`, and consists of three parts: id, type
([PLUGIN_TYPE](https://github.com/OHIF/ohif-core/blob/43c08a29eff3fb646a0e83a03a236ddd84f4a6e8/src/plugins.js#L1-L6)),
and the return value of the module method.
In a future version, we will likely expose a way to provide the extensions you
would like included at startup.
_app.js_
```js
import { createStore, combineReducers } from 'redux';
import OHIF from 'ohif-core';
import OHIFCornerstoneExtension from 'ohif-cornerstone-extension';
const combined = combineReducers(OHIF.redux.reducers);
const store = createStore(combined);
const extensions = [new OHIFCornerstoneExtension()];
// Dispatches the `addPlugin` action to the store
// Adding extension modules to `state.plugins.availablePlugins`
ExtensionManager.registerExtensions(store, extensions);
```
## OHIF Maintained Extensions
A small number of powerful extensions for popular use cases are maintained by
OHIF. They're co-located in the
[`OHIF/Viewers`](https://github.com/OHIF/Viewers/tree/react/) repository, in the
top level [`extensions/`](https://github.com/OHIF/Viewers/tree/react/extensions)
directory.
{% include "./_maintained-extensions-table.md" %}
<!--
Links
-->
<!-- prettier-ignore-start -->
[example-ext-src]: https://github.com/OHIF/Viewers/blob/master/extensions/_ohif-example-extension/src/index.js)
[module-types]: https://github.com/OHIF/ohif-core/blob/43c08a29eff3fb646a0e83a03a236ddd84f4a6e8/src/plugins.js#L1-L6
<!-- prettier-ignore-end -->
-3
View File
@@ -1,3 +0,0 @@
# Advanced
Advanced topics go beyond basic configuration and deployment. Their goal is to provide insight into this project's architecture and guidance on leveraging extensions.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

-14
View File
@@ -1,14 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#4d4d4d;
}
</style>
</defs>
<path
style="fill:currentColor;fill-opacity:1;stroke:none"
d="M 7.5 2 A 4.5 4.5 0 0 0 3 6.5 A 4.5 4.5 0 0 0 3.0527344 7.15625 A 3 3 0 0 0 1 10 A 3 3 0 0 0 4 13 L 11.5 13 A 3.5 3.5 0 0 0 15 9.5 A 3.5 3.5 0 0 0 11.970703 6.0351562 A 4.5 4.5 0 0 0 7.5 2 z M 7.5 3 A 3.5 3.5 0 0 1 11 6.5 A 3.5 3.5 0 0 1 10.949219 7.0644531 A 2.5 2.5 0 0 1 11.5 7 A 2.5 2.5 0 0 1 14 9.5 A 2.5 2.5 0 0 1 11.5 12 L 4 12 A 2 2 0 0 1 2 10 A 2 2 0 0 1 4 8 A 2 2 0 0 1 4.3574219 8.0332031 A 3.5 3.5 0 0 1 4 6.5 A 3.5 3.5 0 0 1 7.5 3 z "
id="path4139"
class="ColorScheme-Text"/>
</svg>

Before

Width:  |  Height:  |  Size: 818 B

Binary file not shown.
Binary file not shown.
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="npm" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 780 250" style="enable-background:new 0 0 780 250;" xml:space="preserve">
<style type="text/css">
.st0{fill:#C12127;}
</style>
<path class="st0" d="M240,250h100v-50h100V0H240V250z M340,50h50v100h-50V50z M480,0v200h100V50h50v150h50V50h50v150h50V0H480z
M0,200h100V50h50v150h50V0H0V200z"/>
</svg>

Before

Width:  |  Height:  |  Size: 473 B

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 260.4 82.9" enable-background="new 0 0 260.4 82.9" xml:space="preserve">
<g>
<path fill="#525DF9" d="M31.7,8.9c9.6,0,16.5,4.9,19,13.4l0.1,0.4h9.6l-0.1-0.6C57.6,8.5,46.7,0,31.8,0C13.7,0,0,14.1,0,32.9 s13.7,32.9,31.8,32.9c14.9,0,25.8-8.5,28.6-22.1l0.1-0.6h-9.6l-0.1,0.4c-2.5,8.5-9.5,13.4-19,13.4c-13.1,0-21.9-9.6-21.9-24 C9.8,18.6,18.6,8.9,31.7,8.9z"/>
<path fill="#525DF9" d="M110.1,58c-2.3,0-3.5-1.4-3.5-4.2V32.7c0-8.8-7.2-14.7-17.9-14.7c-7.5,0-16.7,3.9-18.3,14.9l-0.1,0.6h8.4 l0.1-0.4c1.4-5.7,5.8-6.9,9.3-6.9c6,0,9.5,2.7,9.5,7.4v2.6l-13.6,1.4c-7.6,0.8-15.7,5-15.7,14.6c0,8.1,6,13.5,14.8,13.5 c6.5,0,11.8-3.4,15-6.8c1.3,4.2,4.5,6.5,9.1,6.5c1.7,0,3.2-0.3,5.2-0.9l0.3-0.1v-7l-0.6,0.2C111.5,57.9,110.9,58,110.1,58z M97.7,43.5v7.3c-4.6,4.6-8.9,6.7-13.5,6.7c-2,0-6.8-0.6-6.8-5.7c0-3.8,2.8-6.3,7.4-6.9L97.7,43.5z"/>
<path fill="#525DF9" d="M146.5,18c-6.5,0-12,3.1-15.2,6.1v-5.2h-8.9v46h8.9V34.3c2.2-3.2,6.7-8.3,13-8.3c5.6,0,8.7,3.1,8.7,8.8 v30.1h8.9V33.3C161.9,23.7,156.1,18,146.5,18z"/>
<path fill="#525DF9" d="M195.8,18c-6.5,0-12,3.1-15.2,6.1v-5.2h-8.9v46h8.9V34.3c2.2-3.2,6.7-8.3,13-8.3c5.6,0,8.7,3.1,8.7,8.8 v30.1h8.9V33.3C211.2,23.7,205.4,18,195.8,18z"/>
<polygon fill="#525DF9" points="251.3,18.9 238.6,51.8 237.8,47.9 225.6,18.9 216.2,18.9 234.3,62.4 226,82.9 235,82.9 260.4,18.9 "/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

-19
View File
@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 445.9 638" enable-background="new 0 0 445.9 638" xml:space="preserve">
<g>
<g>
<path fill="#5F5DF9" d="M224.5,638C101.1,638,0,537.8,0,414.7V223.3C0,100.2,101.1,0,224.5,0c109.6,0,202.8,78.3,220.9,186.1
c2.9,17.4-8.6,33.8-26,36.8c-17.4,2.9-33.7-8.8-36.7-26.2c-13-77-78.6-132.9-157-132.9c-88.2,0-159.3,71.6-159.3,159.5v191.4
c0,88,71.1,159.5,159.3,159.5c78.3,0,144.2-55.9,157.1-132.9c2.9-17.4,19.3-29.1,36.6-26.2c17.4,2.9,28.6,19.4,25.7,36.7
C427.2,559.7,334,638,224.5,638z"/>
</g>
<g opacity="0.5">
<path fill="#5F5DF9" d="M153.6,347.7c-17.6,0-30.7-14.3-30.7-31.9v-92.3c0-56.8,45.8-103,102.8-103c38.9,0,73.9,21.6,91.7,56.4
c8,15.7,1.7,34.9-14,42.9c-15.7,8-35,1.8-43-13.9c-6.8-13.4-21-21.7-35.8-21.7c-21.8,0-40.2,17.6-40.2,39.2v92.3
C184.3,333.4,171.2,347.7,153.6,347.7z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 355 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 884 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 440 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 MiB

-187
View File
@@ -1,187 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="203px" height="39px" viewBox="0 0 203 39" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
<title>Custom Preset 2 Copy</title>
<desc>Created with Sketch.</desc>
<defs>
<filter x="-22.4%" y="-22.4%" width="144.8%" height="144.8%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.4707441 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-2"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-4"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-6"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-8"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-10"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-12"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-14"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-16"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-18"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-20"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-22"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-24"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-26"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-28"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176" id="path-30"></path>
<path d="M0.103703704,13.9901176 C0.103703704,21.6217647 6.3365037,27.8085294 14.0246815,27.8085294 L14.0246815,27.8085294 C21.7130667,27.8085294 27.9456593,21.6217647 27.9456593,13.9901176 L27.9456593,13.9901176 C27.9456593,6.35805882 21.7130667,0.171294118 14.0246815,0.171294118 L14.0246815,0.171294118 C6.3365037,0.171294118 0.103703704,6.35805882 0.103703704,13.9901176 L0.103703704,13.9901176 Z" id="path-32"></path>
<polyline id="path-34" points="1.7512 17.989 11.9476 17.989 12.85 0.35 0.05 0.1"></polyline>
<polyline id="path-36" points="1.7512 17.989 11.9476 17.989 12.85 0.35 0.05 0.1"></polyline>
<polygon id="path-38" points="1.7512 17.989 11.9476 17.989 12.85 0.35 0.05 0.1"></polygon>
</defs>
<g id="Custom-Preset-2-Copy" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect fill="#FFFFFF" x="0" y="0" width="203" height="39"></rect>
<g id="Group-65" filter="url(#filter-1)" transform="translate(6.000000, 5.000000)">
<g id="Group-49" transform="translate(1.000000, 1.000000)">
<g id="Group-3">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<g id="Clip-2"></g>
<path d="M1.85138074,6.7158 C1.69250667,7.85927059 2.08948444,8.45077059 1.85138074,9.00253529 C1.61306963,9.55450588 1.3349363,10.5402706 1.57324741,11.2104176 C1.81155852,11.8805647 2.16892148,13.3392412 2.48666963,13.3789765 C2.80441778,13.4180941 2.24856593,11.8019176 2.56610667,12.3143588 C2.88406222,12.8270059 2.88406222,13.5893882 3.44012148,14.1150059 C3.99597333,14.6406235 4.75072889,14.5617706 5.34661037,15.0740059 C5.94228444,15.5866529 6.53795852,16.3358588 7.09401778,16.2570059 C7.09401778,16.2570059 7.05419556,16.6510647 6.77626963,17.3214176 C6.4983437,17.9915647 6.45852148,18.7798882 6.81609185,19.2532118 C7.17345481,19.7263294 7.53081778,20.4362118 7.84877333,20.7909471 C8.16652148,21.1456824 8.40483259,23.0381529 8.32518815,23.9841824 C8.24595852,24.9304176 8.68275852,27.0594471 9.67561778,27.5327706 C10.668477,28.0058882 9.67561778,27.2960059 9.47712889,26.7047118 C9.27843259,26.1134176 9.63040296,24.7333882 10.1101363,24.5361529 C10.58904,24.3389176 11.0260474,23.5505941 11.3834104,22.9984176 C11.7409807,22.4466529 12.654403,22.2098882 12.9325363,21.5399471 C13.2106696,20.8698 13.0914104,20.0810647 13.2502844,19.7263294 C13.4091585,19.3713882 13.8461659,18.5828588 12.8927141,18.1097412 C11.939677,17.6366235 11.5424919,17.8733882 11.5026696,17.4395941 C11.4628474,17.0058 11.2245363,16.5328882 10.5496326,16.3358588 C9.87431407,16.1384176 9.27843259,15.7560941 8.52367704,15.6714765 C7.76912889,15.5866529 7.61025481,16.1781529 7.21306963,15.8625353 C6.81609185,15.5473294 6.4983437,15.2317118 6.33926222,14.8376529 C6.18059556,14.4433882 5.70376593,14.6799471 5.74379556,14.4433882 C5.78320296,14.2066235 6.41869926,13.5366824 5.70376593,13.7732412 C4.98904,14.0095941 4.3535437,13.9307412 4.39315852,13.3001235 C4.43318815,12.6693 5.30678815,12.4325353 5.66435852,12.3536824 C6.02151407,12.2748294 6.29964741,12.7084176 6.73665481,12.9847118 C7.17345481,13.2605941 6.77626963,12.5904471 7.01458074,12.1171235 C7.25289185,11.6440059 8.16652148,11.6835353 8.28557333,11.0133882 C8.40483259,10.3432412 8.24595852,9.79106471 8.96089185,9.71221176 C9.67561778,9.63335882 10.4301659,9.75153529 10.5098104,9.39659412 C10.58904,9.04206471 9.67561778,9.51518235 9.63600296,9.08138824 C9.59618074,8.6478 10.4301659,8.05650588 10.668477,8.49009412 C10.9067881,8.92368235 11.5026696,8.96321176 11.5821067,8.8053 C11.6615437,8.6478 11.5821067,8.37191765 11.3039733,7.70156471 C11.0260474,7.03121176 10.7479141,7.22844706 10.5098104,6.47944706 C10.2714993,5.73024118 9.87431407,6.51877059 9.47712889,6.12450588 C9.0799437,5.73024118 8.60332148,4.90218235 8.52367704,5.61206471 C8.44444741,6.32153529 8.44444741,6.7158 8.08708444,7.26777059 C7.72951407,7.81994706 7.57084741,7.38615294 7.25289185,7.03121176 C6.9351437,6.67647647 6.22021037,6.32153529 6.45852148,6.00632941 C6.69683259,5.69071176 6.9351437,4.86285882 7.29250667,5.09962353 C7.65007704,5.33618235 8.2061363,5.33618235 8.12669926,4.94171176 C8.04726222,4.54765294 8.12669926,4.38974118 8.28557333,4.19271176 C8.44444741,3.99547647 9.00050667,3.64053529 9.00050667,4.35041765 C9.00050667,5.06009412 8.92086222,5.25732941 9.47712889,5.33618235 C10.0331881,5.41503529 10.668477,5.45435882 10.6290696,5.09962353 C10.58904,4.74468235 10.7879437,4.82353529 10.6290696,4.23203529 C10.4699881,3.64053529 9.99336593,3.60141765 9.47712889,3.32512353 C8.96089185,3.04924118 8.68275852,2.61565294 8.24595852,2.77335882 C7.80915852,2.93106471 7.76912889,3.08856471 7.72951407,3.52235882 C7.68969185,3.95615294 7.45138074,4.11385882 7.29250667,3.91662353 C7.13384,3.71959412 7.33232889,3.08856471 6.73665481,3.48303529 C6.14077333,3.87709412 5.90266963,4.54765294 5.58492148,4.07432941 C5.26696593,3.60141765 6.0613363,2.77335882 5.22735111,3.1283 C4.39315852,3.48303529 3.79727704,3.87709412 4.23428444,4.03500588 C4.67129185,4.19271176 5.10829926,4.4688 4.67129185,4.62650588 C4.23428444,4.78400588 3.36047704,4.50812353 3.04272889,4.82353529 C2.72498074,5.13874118 1.85138074,6.7158 1.85138074,6.7158" id="Fill-1" fill="#2196F3" mask="url(#mask-3)"></path>
</g>
<g id="Group-6">
<mask id="mask-5" fill="white">
<use xlink:href="#path-4"></use>
</mask>
<g id="Clip-5"></g>
<path d="M1.85138074,6.7158 C1.69250667,7.85927059 2.08948444,8.45077059 1.85138074,9.00253529 C1.61306963,9.55450588 1.3349363,10.5402706 1.57324741,11.2104176 C1.81155852,11.8805647 2.16892148,13.3392412 2.48666963,13.3789765 C2.80441778,13.4180941 2.24856593,11.8019176 2.56610667,12.3143588 C2.88406222,12.8270059 2.88406222,13.5893882 3.44012148,14.1150059 C3.99597333,14.6406235 4.75072889,14.5617706 5.34661037,15.0740059 C5.94228444,15.5866529 6.53795852,16.3358588 7.09401778,16.2570059 C7.09401778,16.2570059 7.05419556,16.6510647 6.77626963,17.3214176 C6.4983437,17.9915647 6.45852148,18.7798882 6.81609185,19.2532118 C7.17345481,19.7263294 7.53081778,20.4362118 7.84877333,20.7909471 C8.16652148,21.1456824 8.40483259,23.0381529 8.32518815,23.9841824 C8.24595852,24.9304176 8.68275852,27.0594471 9.67561778,27.5327706 C10.668477,28.0058882 9.67561778,27.2960059 9.47712889,26.7047118 C9.27843259,26.1134176 9.63040296,24.7333882 10.1101363,24.5361529 C10.58904,24.3389176 11.0260474,23.5505941 11.3834104,22.9984176 C11.7409807,22.4466529 12.654403,22.2098882 12.9325363,21.5399471 C13.2106696,20.8698 13.0914104,20.0810647 13.2502844,19.7263294 C13.4091585,19.3713882 13.8461659,18.5828588 12.8927141,18.1097412 C11.939677,17.6366235 11.5424919,17.8733882 11.5026696,17.4395941 C11.4628474,17.0058 11.2245363,16.5328882 10.5496326,16.3358588 C9.87431407,16.1384176 9.27843259,15.7560941 8.52367704,15.6714765 C7.76912889,15.5866529 7.61025481,16.1781529 7.21306963,15.8625353 C6.81609185,15.5473294 6.4983437,15.2317118 6.33926222,14.8376529 C6.18059556,14.4433882 5.70376593,14.6799471 5.74379556,14.4433882 C5.78320296,14.2066235 6.41869926,13.5366824 5.70376593,13.7732412 C4.98904,14.0095941 4.3535437,13.9307412 4.39315852,13.3001235 C4.43318815,12.6693 5.30678815,12.4325353 5.66435852,12.3536824 C6.02151407,12.2748294 6.29964741,12.7084176 6.73665481,12.9847118 C7.17345481,13.2605941 6.77626963,12.5904471 7.01458074,12.1171235 C7.25289185,11.6440059 8.16652148,11.6835353 8.28557333,11.0133882 C8.40483259,10.3432412 8.24595852,9.79106471 8.96089185,9.71221176 C9.67561778,9.63335882 10.4301659,9.75153529 10.5098104,9.39659412 C10.58904,9.04206471 9.67561778,9.51518235 9.63600296,9.08138824 C9.59618074,8.6478 10.4301659,8.05650588 10.668477,8.49009412 C10.9067881,8.92368235 11.5026696,8.96321176 11.5821067,8.8053 C11.6615437,8.6478 11.5821067,8.37191765 11.3039733,7.70156471 C11.0260474,7.03121176 10.7479141,7.22844706 10.5098104,6.47944706 C10.2714993,5.73024118 9.87431407,6.51877059 9.47712889,6.12450588 C9.0799437,5.73024118 8.60332148,4.90218235 8.52367704,5.61206471 C8.44444741,6.32153529 8.44444741,6.7158 8.08708444,7.26777059 C7.72951407,7.81994706 7.57084741,7.38615294 7.25289185,7.03121176 C6.9351437,6.67647647 6.22021037,6.32153529 6.45852148,6.00632941 C6.69683259,5.69071176 6.9351437,4.86285882 7.29250667,5.09962353 C7.65007704,5.33618235 8.2061363,5.33618235 8.12669926,4.94171176 C8.04726222,4.54765294 8.12669926,4.38974118 8.28557333,4.19271176 C8.44444741,3.99547647 9.00050667,3.64053529 9.00050667,4.35041765 C9.00050667,5.06009412 8.92086222,5.25732941 9.47712889,5.33618235 C10.0331881,5.41503529 10.668477,5.45435882 10.6290696,5.09962353 C10.58904,4.74468235 10.7879437,4.82353529 10.6290696,4.23203529 C10.4699881,3.64053529 9.99336593,3.60141765 9.47712889,3.32512353 C8.96089185,3.04924118 8.68275852,2.61565294 8.24595852,2.77335882 C7.80915852,2.93106471 7.76912889,3.08856471 7.72951407,3.52235882 C7.68969185,3.95615294 7.45138074,4.11385882 7.29250667,3.91662353 C7.13384,3.71959412 7.33232889,3.08856471 6.73665481,3.48303529 C6.14077333,3.87709412 5.90266963,4.54765294 5.58492148,4.07432941 C5.26696593,3.60141765 6.0613363,2.77335882 5.22735111,3.1283 C4.39315852,3.48303529 3.79727704,3.87709412 4.23428444,4.03500588 C4.67129185,4.19271176 5.10829926,4.4688 4.67129185,4.62650588 C4.23428444,4.78400588 3.36047704,4.50812353 3.04272889,4.82353529 C2.72498074,5.13874118 1.85138074,6.7158 1.85138074,6.7158 Z" id="Stroke-4" stroke="#2196F3" mask="url(#mask-5)"></path>
</g>
<g id="Group-9">
<mask id="mask-7" fill="white">
<use xlink:href="#path-6"></use>
</mask>
<g id="Clip-8"></g>
<path d="M6.5378963,2.45802941 C6.53582222,2.89882353 6.65715556,3.24635294 7.05434074,2.85229412 C7.45152593,2.45802941 7.68962963,1.98491176 7.96797037,2.18194118 C8.2458963,2.37917647 8.72251852,2.32667647 8.9208,2.3135 C9.1197037,2.30032353 9.15931852,1.70882353 9.71537778,1.78767647 C10.271437,1.86652941 10.0729481,1.6695 10.6686222,1.35388235 C11.2645037,1.03847059 12.5354963,0.486705882 11.2246815,0.644411765 C9.91386667,0.802117647 9.83442963,0.447176471 8.9208,1.03847059 C8.00758519,1.62997059 7.8090963,1.62997059 7.57078519,1.78767647 C7.33247407,1.94538235 7.05434074,1.31455882 6.73659259,1.78767647 C6.41863704,2.26079412 6.54017778,2.00879412 6.5378963,2.45802941" id="Fill-7" fill="#2196F3" mask="url(#mask-7)"></path>
</g>
<g id="Group-12">
<mask id="mask-9" fill="white">
<use xlink:href="#path-8"></use>
</mask>
<g id="Clip-11"></g>
<path d="M6.5378963,2.45802941 C6.53582222,2.89882353 6.65715556,3.24635294 7.05434074,2.85229412 C7.45152593,2.45802941 7.68962963,1.98491176 7.96797037,2.18194118 C8.2458963,2.37917647 8.72251852,2.32667647 8.9208,2.3135 C9.1197037,2.30032353 9.15931852,1.70882353 9.71537778,1.78767647 C10.271437,1.86652941 10.0729481,1.6695 10.6686222,1.35388235 C11.2645037,1.03847059 12.5354963,0.486705882 11.2246815,0.644411765 C9.91386667,0.802117647 9.83442963,0.447176471 8.9208,1.03847059 C8.00758519,1.62997059 7.8090963,1.62997059 7.57078519,1.78767647 C7.33247407,1.94538235 7.05434074,1.31455882 6.73659259,1.78767647 C6.41863704,2.26079412 6.54017778,2.00879412 6.5378963,2.45802941 Z" id="Stroke-10" stroke="#2196F3" mask="url(#mask-9)"></path>
</g>
<g id="Group-15">
<mask id="mask-11" fill="white">
<use xlink:href="#path-10"></use>
</mask>
<g id="Clip-14"></g>
<path d="M11.3040148,1.23570588 C10.8346519,1.63841176 10.1126667,2.22147059 10.6685185,2.22147059 C11.2245778,2.22147059 11.4946222,1.93241176 11.7966074,2.3135 C12.0985926,2.69438235 11.9791259,3.28588235 11.9791259,3.56176471 C11.9791259,3.83785294 11.8202519,4.46888235 12.2176444,5.25720588 C12.6148296,6.04552941 12.6544444,6.55817647 13.051837,6.04552941 C13.4488148,5.53329412 14.4020593,4.54752941 14.8786815,4.46888235 C15.3553037,4.38982353 15.8323407,4.19258824 16.0704444,3.79832353 C16.3085481,3.40405882 16.0704444,3.02152941 16.4674222,2.73988235 C16.8644,2.45802941 16.784963,2.10308824 16.9044296,1.6695 C17.0232741,1.23570588 18.0959852,1.23570588 17.6191556,0.999352941 C17.1427407,0.762588235 16.2689333,0.604882353 15.2360444,0.723264706 C14.203363,0.841441176 12.1778222,0.486705882 11.3040148,1.23570588" id="Fill-13" fill="#2196F3" mask="url(#mask-11)"></path>
</g>
<g id="Group-18">
<mask id="mask-13" fill="white">
<use xlink:href="#path-12"></use>
</mask>
<g id="Clip-17"></g>
<path d="M11.3040148,1.23570588 C10.8346519,1.63841176 10.1126667,2.22147059 10.6685185,2.22147059 C11.2245778,2.22147059 11.4946222,1.93241176 11.7966074,2.3135 C12.0985926,2.69438235 11.9791259,3.28588235 11.9791259,3.56176471 C11.9791259,3.83785294 11.8202519,4.46888235 12.2176444,5.25720588 C12.6148296,6.04552941 12.6544444,6.55817647 13.051837,6.04552941 C13.4488148,5.53329412 14.4020593,4.54752941 14.8786815,4.46888235 C15.3553037,4.38982353 15.8323407,4.19258824 16.0704444,3.79832353 C16.3085481,3.40405882 16.0704444,3.02152941 16.4674222,2.73988235 C16.8644,2.45802941 16.784963,2.10308824 16.9044296,1.6695 C17.0232741,1.23570588 18.0959852,1.23570588 17.6191556,0.999352941 C17.1427407,0.762588235 16.2689333,0.604882353 15.2360444,0.723264706 C14.203363,0.841441176 12.1778222,0.486705882 11.3040148,1.23570588 Z" id="Stroke-16" stroke="#2196F3" mask="url(#mask-13)"></path>
</g>
<g id="Group-21">
<mask id="mask-15" fill="white">
<use xlink:href="#path-14"></use>
</mask>
<g id="Clip-20"></g>
<path d="M6.93518519,13.4181353 C6.68256296,13.8270176 6.81592593,13.8519294 7.09405926,13.9307824 C7.37198519,14.0096353 6.9748,14.4825471 7.29254815,14.5220765 C7.6102963,14.5618118 8.32522963,14.7588412 8.52371852,14.5220765 C8.72262222,14.2857235 8.20617778,14.3779588 7.84860741,14.1150471 C7.49145185,13.8519294 7.11459259,13.1278412 6.93518519,13.4181353" id="Fill-19" fill="#2196F3" mask="url(#mask-15)"></path>
</g>
<g id="Group-24">
<mask id="mask-17" fill="white">
<use xlink:href="#path-16"></use>
</mask>
<g id="Clip-23"></g>
<path d="M6.93518519,13.4181353 C6.68256296,13.8270176 6.81592593,13.8519294 7.09405926,13.9307824 C7.37198519,14.0096353 6.9748,14.4825471 7.29254815,14.5220765 C7.6102963,14.5618118 8.32522963,14.7588412 8.52371852,14.5220765 C8.72262222,14.2857235 8.20617778,14.3779588 7.84860741,14.1150471 C7.49145185,13.8519294 7.11459259,13.1278412 6.93518519,13.4181353 Z" id="Stroke-22" stroke="#2196F3" mask="url(#mask-17)"></path>
</g>
<g id="Group-27">
<mask id="mask-19" fill="white">
<use xlink:href="#path-18"></use>
</mask>
<g id="Clip-26"></g>
<path d="M26.1584504,19.8445265 C25.7305689,20.0572029 25.9203467,20.3967029 25.5229541,20.6332618 C25.1257689,20.8696147 25.284643,20.9484676 25.1655911,21.5006441 C25.0463319,22.0524088 25.2052059,22.3678206 25.4833393,21.9342324 C25.7614726,21.5006441 26.6350726,19.6081735 26.1584504,19.8445265" id="Fill-25" fill="#2196F3" mask="url(#mask-19)"></path>
</g>
<g id="Group-30">
<mask id="mask-21" fill="white">
<use xlink:href="#path-20"></use>
</mask>
<g id="Clip-29"></g>
<path d="M26.1584504,19.8445265 C25.7305689,20.0572029 25.9203467,20.3967029 25.5229541,20.6332618 C25.1257689,20.8696147 25.284643,20.9484676 25.1655911,21.5006441 C25.0463319,22.0524088 25.2052059,22.3678206 25.4833393,21.9342324 C25.7614726,21.5006441 26.6350726,19.6081735 26.1584504,19.8445265 Z" id="Stroke-28" stroke="#2196F3" mask="url(#mask-21)"></path>
</g>
<g id="Group-33">
<mask id="mask-23" fill="white">
<use xlink:href="#path-22"></use>
</mask>
<g id="Clip-32"></g>
<path d="M26.5159378,11.4075706 C26.3966785,11.5259529 26.1981896,10.8556 26.0791378,10.5401882 C25.9598785,10.2247765 25.9627822,9.67651176 26.29816,9.37180588 C26.7158785,8.99174706 26.5159378,9.86983529 26.5159378,10.3431588 C26.5159378,10.8160706 26.6349896,11.2891882 26.5159378,11.4075706 M25.1254785,10.1854529 C24.8473452,10.0277471 24.331523,10.1854529 23.6960267,10.3824824 C23.060323,10.5797176 23.5688859,9.94374706 23.8549007,9.5151 C24.1106341,9.13195294 23.9739526,9.63327647 24.5302193,9.67280588 C25.0860711,9.71233529 25.4040267,10.3431588 25.1254785,10.1854529 M24.2124711,11.5259529 C24.1726489,11.8411588 24.331523,12.3538059 23.4577156,12.1567765 C22.5839081,11.9595412 22.5839081,11.4864235 22.2265452,11.8411588 C21.8691822,12.1961 21.4321748,12.5113059 20.9157304,11.9595412 C20.3994933,11.4075706 20.4789304,11.2498647 20.2010044,11.2103353 C20.0029304,11.1825412 19.3427526,11.0361588 18.7922933,11.1951 C18.8350193,11.1697765 18.8806489,11.1364235 18.9298044,11.0921588 C19.3269896,10.7374235 19.2475526,10.6190412 19.6843526,10.2247765 C20.1215674,9.83030588 20.4391081,9.47577647 20.7568563,9.83030588 C21.0746044,10.1854529 21.749923,10.2643059 21.5116119,10.6585706 C21.2733007,11.0526294 21.4321748,11.2891882 21.7103081,11.0526294 C21.9880267,10.8160706 22.3854193,10.6585706 22.1074933,10.3431588 C21.8291526,10.0277471 21.5510193,9.19968824 21.9486193,9.75165882 C22.3458044,10.3036294 22.4648563,10.5797176 22.70296,10.8949235 C22.9414785,11.2103353 23.1797896,11.4075706 23.2592267,11.2103353 C23.3386637,11.0133059 23.2194044,10.5797176 23.3386637,10.5008647 C23.4577156,10.4220118 23.3386637,11.1710118 23.6960267,11.2103353 C24.0533896,11.2498647 24.2520859,11.2103353 24.2124711,11.5259529 M28.4224267,13.2213941 C28.3033748,12.5508353 27.4295674,6.47936471 27.4295674,6.47936471 C27.4295674,6.47936471 25.0860711,4.98115882 24.6890933,5.29636471 C24.2917007,5.61198235 23.6165896,5.56442353 23.6960267,5.25312941 C23.7754637,4.94183529 24.2917007,5.02089412 23.4176859,4.42918824 C22.5442933,3.83768824 22.3854193,3.32524706 21.7103081,4.07424706 C21.0347822,4.82345294 20.8761156,5.45427647 20.4789304,5.65151176 C20.0817452,5.84854118 19.763997,6.47936471 20.2010044,6.63707059 C20.6378044,6.79457059 20.6776267,6.63707059 21.0347822,6.95227647 C21.39256,7.26789412 21.8691822,7.18883529 21.9486193,6.99201176 C22.0280563,6.79457059 22.1074933,6.16395294 22.1471081,5.92739412 C22.1869304,5.69083529 22.5905452,4.90230588 22.5474044,5.53312941 C22.5044711,6.16395294 23.1001452,6.16395294 22.70296,6.59754118 C22.3059822,7.03112941 22.5442933,7.38627647 21.749923,7.46512941 C20.9553452,7.54377647 20.9157304,7.07086471 20.4789304,7.30742353 C20.041923,7.54377647 20.0817452,7.70168824 19.9228711,7.93804118 C19.763997,8.1746 18.9298044,8.64771765 18.9298044,8.64771765 C18.9298044,8.64771765 18.2546933,8.41115882 18.5722341,8.84495294 C18.8901896,9.27854118 19.1681156,9.79098235 18.8901896,9.83030588 C18.6120563,9.86983529 17.8573007,9.43624706 17.8573007,9.90936471 C17.8573007,10.3824824 17.7384563,10.8949235 18.0562044,11.0133059 C18.2804119,11.0966882 18.4260119,11.2776588 18.63176,11.2523353 C18.4722637,11.3206882 18.3272859,11.4197176 18.2150785,11.5652765 C17.9058341,11.9661294 18.0958193,12.6692176 17.460323,12.9057765 C16.8250341,13.1425412 16.8250341,13.4182176 16.7055674,13.9308647 C16.586723,14.4433059 16.7055674,15.7442765 16.8644415,15.8626588 C17.0231081,15.9808353 17.3014489,16.9666 17.9767674,16.8875412 C18.6520859,16.8086882 19.3668119,16.7784235 19.605123,16.8922765 C19.8434341,17.0057176 20.2404119,16.6511882 20.3596711,17.5578941 C20.4789304,18.4646 20.7568563,18.5829824 20.9157304,19.0561 C21.0746044,19.5290118 20.8362933,20.5149824 20.9157304,21.1062765 C20.9951674,21.6975706 21.5510193,22.7228647 21.5510193,23.2353059 C21.5510193,23.7477471 22.1471081,23.9843059 22.4648563,23.7872765 C22.7826044,23.5900412 23.4577156,23.1957765 23.7356415,22.5649529 C24.0139822,21.9343353 24.0139822,21.6189235 24.4505748,20.7908647 C24.8873748,19.9630118 24.7685304,19.3715118 24.9668119,18.7406882 C25.1655081,18.1098647 25.6433748,17.6760706 26.29816,16.9666 C26.9527378,16.2571294 26.8349304,15.8626588 26.29816,15.9019824 C25.7613896,15.9413059 25.4034044,15.4290706 25.1254785,14.7982471 C24.8479674,14.1672176 24.5302193,12.5903647 24.7685304,13.1028059 C25.0068415,13.6156588 25.4832563,15.0348059 25.9598785,15.2713647 C26.4365007,15.5079235 27.3105156,14.8692765 27.5090044,14.6366294 C27.7074933,14.4037765 27.6280563,13.7338353 27.1116119,13.4577471 C26.5953748,13.1816588 26.913123,12.9453059 27.4295674,13.2605118 C27.9458044,13.5759235 28.5416859,13.8913353 28.4224267,13.2213941" id="Fill-31" fill="#2196F3" mask="url(#mask-23)"></path>
</g>
<g id="Group-36">
<mask id="mask-25" fill="white">
<use xlink:href="#path-24"></use>
</mask>
<g id="Clip-35"></g>
<path d="M26.5159378,11.4075706 C26.3966785,11.5259529 26.1981896,10.8556 26.0791378,10.5401882 C25.9598785,10.2247765 25.9627822,9.67651176 26.29816,9.37180588 C26.7158785,8.99174706 26.5159378,9.86983529 26.5159378,10.3431588 C26.5159378,10.8160706 26.6349896,11.2891882 26.5159378,11.4075706 Z M25.1254785,10.1854529 C24.8473452,10.0277471 24.331523,10.1854529 23.6960267,10.3824824 C23.060323,10.5797176 23.5688859,9.94374706 23.8549007,9.5151 C24.1106341,9.13195294 23.9739526,9.63327647 24.5302193,9.67280588 C25.0860711,9.71233529 25.4040267,10.3431588 25.1254785,10.1854529 Z M24.2124711,11.5259529 C24.1726489,11.8411588 24.331523,12.3538059 23.4577156,12.1567765 C22.5839081,11.9595412 22.5839081,11.4864235 22.2265452,11.8411588 C21.8691822,12.1961 21.4321748,12.5113059 20.9157304,11.9595412 C20.3994933,11.4075706 20.4789304,11.2498647 20.2010044,11.2103353 C20.0029304,11.1825412 19.3427526,11.0361588 18.7922933,11.1951 C18.8350193,11.1697765 18.8806489,11.1364235 18.9298044,11.0921588 C19.3269896,10.7374235 19.2475526,10.6190412 19.6843526,10.2247765 C20.1215674,9.83030588 20.4391081,9.47577647 20.7568563,9.83030588 C21.0746044,10.1854529 21.749923,10.2643059 21.5116119,10.6585706 C21.2733007,11.0526294 21.4321748,11.2891882 21.7103081,11.0526294 C21.9880267,10.8160706 22.3854193,10.6585706 22.1074933,10.3431588 C21.8291526,10.0277471 21.5510193,9.19968824 21.9486193,9.75165882 C22.3458044,10.3036294 22.4648563,10.5797176 22.70296,10.8949235 C22.9414785,11.2103353 23.1797896,11.4075706 23.2592267,11.2103353 C23.3386637,11.0133059 23.2194044,10.5797176 23.3386637,10.5008647 C23.4577156,10.4220118 23.3386637,11.1710118 23.6960267,11.2103353 C24.0533896,11.2498647 24.2520859,11.2103353 24.2124711,11.5259529 Z M28.4224267,13.2213941 C28.3033748,12.5508353 27.4295674,6.47936471 27.4295674,6.47936471 C27.4295674,6.47936471 25.0860711,4.98115882 24.6890933,5.29636471 C24.2917007,5.61198235 23.6165896,5.56442353 23.6960267,5.25312941 C23.7754637,4.94183529 24.2917007,5.02089412 23.4176859,4.42918824 C22.5442933,3.83768824 22.3854193,3.32524706 21.7103081,4.07424706 C21.0347822,4.82345294 20.8761156,5.45427647 20.4789304,5.65151176 C20.0817452,5.84854118 19.763997,6.47936471 20.2010044,6.63707059 C20.6378044,6.79457059 20.6776267,6.63707059 21.0347822,6.95227647 C21.39256,7.26789412 21.8691822,7.18883529 21.9486193,6.99201176 C22.0280563,6.79457059 22.1074933,6.16395294 22.1471081,5.92739412 C22.1869304,5.69083529 22.5905452,4.90230588 22.5474044,5.53312941 C22.5044711,6.16395294 23.1001452,6.16395294 22.70296,6.59754118 C22.3059822,7.03112941 22.5442933,7.38627647 21.749923,7.46512941 C20.9553452,7.54377647 20.9157304,7.07086471 20.4789304,7.30742353 C20.041923,7.54377647 20.0817452,7.70168824 19.9228711,7.93804118 C19.763997,8.1746 18.9298044,8.64771765 18.9298044,8.64771765 C18.9298044,8.64771765 18.2546933,8.41115882 18.5722341,8.84495294 C18.8901896,9.27854118 19.1681156,9.79098235 18.8901896,9.83030588 C18.6120563,9.86983529 17.8573007,9.43624706 17.8573007,9.90936471 C17.8573007,10.3824824 17.7384563,10.8949235 18.0562044,11.0133059 C18.2804119,11.0966882 18.4260119,11.2776588 18.63176,11.2523353 C18.4722637,11.3206882 18.3272859,11.4197176 18.2150785,11.5652765 C17.9058341,11.9661294 18.0958193,12.6692176 17.460323,12.9057765 C16.8250341,13.1425412 16.8250341,13.4182176 16.7055674,13.9308647 C16.586723,14.4433059 16.7055674,15.7442765 16.8644415,15.8626588 C17.0231081,15.9808353 17.3014489,16.9666 17.9767674,16.8875412 C18.6520859,16.8086882 19.3668119,16.7784235 19.605123,16.8922765 C19.8434341,17.0057176 20.2404119,16.6511882 20.3596711,17.5578941 C20.4789304,18.4646 20.7568563,18.5829824 20.9157304,19.0561 C21.0746044,19.5290118 20.8362933,20.5149824 20.9157304,21.1062765 C20.9951674,21.6975706 21.5510193,22.7228647 21.5510193,23.2353059 C21.5510193,23.7477471 22.1471081,23.9843059 22.4648563,23.7872765 C22.7826044,23.5900412 23.4577156,23.1957765 23.7356415,22.5649529 C24.0139822,21.9343353 24.0139822,21.6189235 24.4505748,20.7908647 C24.8873748,19.9630118 24.7685304,19.3715118 24.9668119,18.7406882 C25.1655081,18.1098647 25.6433748,17.6760706 26.29816,16.9666 C26.9527378,16.2571294 26.8349304,15.8626588 26.29816,15.9019824 C25.7613896,15.9413059 25.4034044,15.4290706 25.1254785,14.7982471 C24.8479674,14.1672176 24.5302193,12.5903647 24.7685304,13.1028059 C25.0068415,13.6156588 25.4832563,15.0348059 25.9598785,15.2713647 C26.4365007,15.5079235 27.3105156,14.8692765 27.5090044,14.6366294 C27.7074933,14.4037765 27.6280563,13.7338353 27.1116119,13.4577471 C26.5953748,13.1816588 26.913123,12.9453059 27.4295674,13.2605118 C27.9458044,13.5759235 28.5416859,13.8913353 28.4224267,13.2213941 Z" id="Stroke-34" stroke="#2196F3" mask="url(#mask-25)"></path>
</g>
<g id="Group-39">
<mask id="mask-27" fill="white">
<use xlink:href="#path-26"></use>
</mask>
<g id="Clip-38"></g>
<path d="M18.8503674,6.59758235 C18.6070785,6.67025882 18.4135674,7.14955294 18.5326193,7.38631765 C18.6520859,7.62267059 18.4135674,7.26772941 18.0958193,7.46496471 C17.7778637,7.66199412 17.3060119,8.21417059 17.7405304,8.25328824 C18.1752563,8.29302353 18.0958193,7.93808235 18.4930044,8.09578824 C18.8901896,8.25328824 19.3269896,8.21417059 19.3269896,7.81990588 C19.3269896,7.42543529 19.2475526,6.47940588 18.8503674,6.59758235" id="Fill-37" fill="#2196F3" mask="url(#mask-27)"></path>
</g>
<g id="Group-42">
<mask id="mask-29" fill="white">
<use xlink:href="#path-28"></use>
</mask>
<g id="Clip-41"></g>
<path d="M18.8503674,6.59758235 C18.6070785,6.67025882 18.4135674,7.14955294 18.5326193,7.38631765 C18.6520859,7.62267059 18.4135674,7.26772941 18.0958193,7.46496471 C17.7778637,7.66199412 17.3060119,8.21417059 17.7405304,8.25328824 C18.1752563,8.29302353 18.0958193,7.93808235 18.4930044,8.09578824 C18.8901896,8.25328824 19.3269896,8.21417059 19.3269896,7.81990588 C19.3269896,7.42543529 19.2475526,6.47940588 18.8503674,6.59758235 Z" id="Stroke-40" stroke="#2196F3" mask="url(#mask-29)"></path>
</g>
<g id="Group-45">
<mask id="mask-31" fill="white">
<use xlink:href="#path-30"></use>
</mask>
<g id="Clip-44"></g>
<path d="M16.2689333,4.78404706 C16.0295852,4.81801765 15.9509778,5.41487059 16.4674222,5.49372353 C16.9838667,5.57257647 17.9082815,5.37534118 17.5652296,5.05992941 C17.2221778,4.74472353 16.8252,4.70519412 16.2689333,4.78404706" id="Fill-43" fill="#2196F3" mask="url(#mask-31)"></path>
</g>
<g id="Group-48">
<mask id="mask-33" fill="white">
<use xlink:href="#path-32"></use>
</mask>
<g id="Clip-47"></g>
<path d="M16.2689333,4.78404706 C16.0295852,4.81801765 15.9509778,5.41487059 16.4674222,5.49372353 C16.9838667,5.57257647 17.9082815,5.37534118 17.5652296,5.05992941 C17.2221778,4.74472353 16.8252,4.70519412 16.2689333,4.78404706 Z" id="Stroke-46" stroke="#2196F3" mask="url(#mask-33)"></path>
</g>
</g>
<g id="Group-54">
<path d="M28.1296528,14.2858085 C28.1296528,21.8560338 21.992681,27.9932099 14.4222514,27.9932099 C6.85182183,27.9932099 0.71485,21.8560338 0.71485,14.2858085 C0.71485,6.71537887 6.85182183,0.578407042 14.4222514,0.578407042 C21.992681,0.578407042 28.1296528,6.71537887 28.1296528,14.2858085 Z" id="Stroke-50" stroke="#2196F3"></path>
<path d="M14.4854387,1.69603028 C7.4461993,1.69603028 1.71931197,7.42291761 1.71931197,14.462157 C1.71931197,21.5013965 7.4461993,27.2280796 14.4854387,27.2280796 C21.5246782,27.2280796 27.2513613,21.5013965 27.2513613,14.462157 C27.2513613,7.42291761 21.5246782,1.69603028 14.4854387,1.69603028 M14.4854387,28.8618824 C6.54536127,28.8618824 0.0855091549,22.4022345 0.0855091549,14.462157 C0.0855091549,6.52187535 6.54536127,0.0622274648 14.4854387,0.0622274648 C22.4255162,0.0622274648 28.8851641,6.52187535 28.8851641,14.462157 C28.8851641,22.4022345 22.4255162,28.8618824 14.4854387,28.8618824" id="Fill-52" fill="#2196F3"></path>
</g>
<g id="Group-64" transform="translate(16.000000, 0.000000)">
<g id="Group-57">
<mask id="mask-35" fill="white">
<use xlink:href="#path-34"></use>
</mask>
<g id="Clip-56"></g>
<path d="M7.92792,7.13868 C7.61952,7.44688 7.25072,7.60088 6.82132,7.60088 C6.39172,7.60088 6.02312,7.44688 5.71492,7.13868 C5.40672,6.83048 5.25232,6.46128 5.25232,6.03208 C5.25232,5.60268 5.40672,5.23948 5.71492,4.94208 C6.02312,4.64488 6.39172,4.49608 6.82132,4.49608 C7.25072,4.49608 7.61952,4.64488 7.92792,4.94208 C8.23592,5.23948 8.39032,5.60268 8.39032,6.03208 C8.39032,6.46128 8.23592,6.83048 7.92792,7.13868 M10.43812,2.53088 C9.44732,1.55088 8.24732,1.06088 6.83792,1.06088 C5.42852,1.06088 4.22852,1.55088 3.23752,2.53088 C2.24652,3.51048 1.75112,4.69428 1.75112,6.08168 C1.75112,6.91828 2.17492,8.31688 3.02292,10.27648 C3.87052,12.23628 4.71832,14.01988 5.56592,15.62728 C6.41412,17.23468 6.83792,18.01648 6.83792,17.97268 C6.96992,17.73048 7.15152,17.40008 7.38272,16.98168 C7.61412,16.56328 8.02152,15.77608 8.60512,14.61988 C9.18852,13.46368 9.70052,12.40108 10.14052,11.43288 C10.58132,10.46368 10.98872,9.46168 11.36292,8.42648 C11.73752,7.39188 11.92432,6.61008 11.92432,6.08168 C11.92432,4.69428 11.42892,3.51048 10.43812,2.53088" id="Fill-55" fill="#FFFFFF" mask="url(#mask-35)"></path>
</g>
<g id="Group-60">
<mask id="mask-37" fill="white">
<use xlink:href="#path-36"></use>
</mask>
<g id="Clip-59"></g>
<path d="M7.92792,7.13868 C7.61952,7.44688 7.25072,7.60088 6.82132,7.60088 C6.39172,7.60088 6.02312,7.44688 5.71492,7.13868 C5.40672,6.83048 5.25232,6.46128 5.25232,6.03208 C5.25232,5.60268 5.40672,5.23948 5.71492,4.94208 C6.02312,4.64488 6.39172,4.49608 6.82132,4.49608 C7.25072,4.49608 7.61952,4.64488 7.92792,4.94208 C8.23592,5.23948 8.39032,5.60268 8.39032,6.03208 C8.39032,6.46128 8.23592,6.83048 7.92792,7.13868 M10.43812,2.53088 C9.44732,1.55088 8.24732,1.06088 6.83792,1.06088 C5.42852,1.06088 4.22852,1.55088 3.23752,2.53088 C2.24652,3.51048 1.75112,4.69428 1.75112,6.08168 C1.75112,6.91828 2.17492,8.31688 3.02292,10.27648 C3.87052,12.23628 4.71832,14.01988 5.56592,15.62728 C6.41412,17.23468 6.83792,18.01648 6.83792,17.97268 C6.96992,17.73048 7.15152,17.40008 7.38272,16.98168 C7.61412,16.56328 8.02152,15.77608 8.60512,14.61988 C9.18852,13.46368 9.70052,12.40108 10.14052,11.43288 C10.58132,10.46368 10.98872,9.46168 11.36292,8.42648 C11.73752,7.39188 11.92432,6.61008 11.92432,6.08168 C11.92432,4.69428 11.42892,3.51048 10.43812,2.53088" id="Fill-58" fill="#FFFFFF" mask="url(#mask-37)"></path>
</g>
<g id="Group-63">
<mask id="mask-39" fill="white">
<use xlink:href="#path-38"></use>
</mask>
<g id="Clip-62"></g>
<path d="M6.82128,4.9961 C6.51968,4.9961 6.27828,5.0933 6.06188,5.3021 C5.85068,5.5057 5.75228,5.7377 5.75228,6.0321 C5.75228,6.3301 5.85268,6.5695 6.06828,6.7851 C6.28368,7.0005 6.52308,7.1009 6.82128,7.1009 C7.11948,7.1009 7.35888,7.0005 7.57448,6.7849 C7.78988,6.5695 7.89028,6.3301 7.89028,6.0321 C7.89028,5.7377 7.79188,5.5057 7.58068,5.3017 C7.36428,5.0933 7.12288,4.9961 6.82128,4.9961 L6.82128,4.9961 Z M6.82128,8.1009 C6.25648,8.1009 5.76528,7.8961 5.36128,7.4921 C4.95728,7.0881 4.75228,6.5969 4.75228,6.0321 C4.75228,5.4639 4.95928,4.9761 5.36748,4.5823 C5.77108,4.1933 6.26008,3.9961 6.82128,3.9961 C7.38228,3.9961 7.87128,4.1933 8.27488,4.5821 C8.68348,4.9763 8.89028,5.4641 8.89028,6.0321 C8.89028,6.5967 8.68548,7.0879 8.28168,7.4921 C7.87728,7.8961 7.38608,8.1009 6.82128,8.1009 L6.82128,8.1009 Z M6.83788,1.5609 C5.55368,1.5609 4.49108,1.9945 3.58908,2.8865 C2.68888,3.7763 2.25108,4.8215 2.25108,6.0817 C2.25108,6.6073 2.46468,7.7273 3.48188,10.0779 C4.31968,12.0155 5.16968,13.8041 6.00828,15.3941 C6.38528,16.1089 6.64868,16.6035 6.83208,16.9447 C6.86828,16.8789 6.90608,16.8105 6.94528,16.7399 C7.17208,16.3295 7.58028,15.5405 8.15888,14.3947 C8.73768,13.2469 9.25128,12.1809 9.68528,11.2259 C10.11888,10.2727 10.52508,9.2735 10.89248,8.2565 C11.33228,7.0427 11.42448,6.4039 11.42448,6.0817 C11.42448,4.8215 10.98668,3.7765 10.08648,2.8865 C9.18468,1.9945 8.12208,1.5609 6.83788,1.5609 L6.83788,1.5609 Z M7.04328,18.4751 L6.83508,18.4745 C6.52208,18.4733 6.46988,18.3767 6.06328,17.6257 C5.85068,17.2335 5.53768,16.6451 5.12388,15.8607 C4.27328,14.2479 3.41208,12.4359 2.56388,10.4749 C1.68068,8.4333 1.25108,6.9963 1.25108,6.0817 C1.25108,4.5619 1.80108,3.2475 2.88588,2.1753 C3.96928,1.1041 5.29908,0.5609 6.83788,0.5609 C8.37688,0.5609 9.70648,1.1041 10.78968,2.1753 C11.87448,3.2477 12.42448,4.5621 12.42448,6.0817 C12.42448,6.6751 12.23108,7.4977 11.83308,8.5967 C11.45648,9.6383 11.04028,10.6623 10.59568,11.6399 C10.15628,12.6071 9.63668,13.6855 9.05148,14.8451 C8.45908,16.0185 8.05648,16.7965 7.82048,17.2235 C7.62348,17.5797 7.46268,17.8721 7.33788,18.1003 L7.33788,18.1803 L7.04328,18.4751 Z" id="Fill-61" fill="#2196F3" mask="url(#mask-39)"></path>
</g>
</g>
</g>
<g id="Translation-Manageme" transform="translate(40.000000, 6.000000)" fill-rule="nonzero">
<path d="M2.688,9.94 L2.688,1.946 L1.42108547e-14,1.946 L1.42108547e-14,0.504 L7.126,0.504 L7.126,1.946 L4.41,1.946 L4.41,9.94 L2.688,9.94 Z M7.462,9.94 L7.462,5.32 C7.462,4.396 7.448,3.724 7.406,3.122 L8.89,3.122 L8.96,4.41 L9.002,4.41 C9.338,3.458 10.136,2.968 10.878,2.968 C11.046,2.968 11.144,2.982 11.284,3.01 L11.284,4.62 C11.13,4.592 10.976,4.578 10.766,4.578 C9.954,4.578 9.38,5.096 9.226,5.88 C9.198,6.034 9.184,6.216 9.184,6.398 L9.184,9.94 L7.462,9.94 Z M17.612,5.852 L17.612,8.302 C17.612,8.918 17.64,9.52 17.724,9.94 L16.17,9.94 L16.044,9.184 L16.002,9.184 C15.596,9.716 14.882,10.094 13.986,10.094 C12.614,10.094 11.844,9.1 11.844,8.064 C11.844,6.356 13.37,5.474 15.89,5.488 L15.89,5.376 C15.89,4.928 15.708,4.186 14.504,4.186 C13.832,4.186 13.132,4.396 12.67,4.69 L12.334,3.57 C12.838,3.262 13.72,2.968 14.798,2.968 C16.982,2.968 17.612,4.354 17.612,5.852 Z M15.932,7.546 L15.932,6.608 C14.714,6.594 13.552,6.846 13.552,7.882 C13.552,8.554 13.986,8.862 14.532,8.862 C15.232,8.862 15.722,8.414 15.89,7.924 C15.932,7.798 15.932,7.672 15.932,7.546 Z M19.432,9.94 L19.432,5.152 C19.432,4.368 19.404,3.71 19.376,3.122 L20.874,3.122 L20.958,4.144 L21,4.144 C21.308,3.612 22.05,2.968 23.184,2.968 C24.374,2.968 25.606,3.738 25.606,5.894 L25.606,9.94 L23.884,9.94 L23.884,6.09 C23.884,5.11 23.52,4.368 22.582,4.368 C21.896,4.368 21.42,4.858 21.238,5.376 C21.182,5.516 21.154,5.726 21.154,5.922 L21.154,9.94 L19.432,9.94 Z M27.02,9.604 L27.37,8.344 C27.748,8.582 28.49,8.848 29.106,8.848 C29.862,8.848 30.198,8.526 30.198,8.078 C30.198,7.616 29.918,7.392 29.078,7.084 C27.748,6.636 27.202,5.908 27.202,5.096 C27.202,3.892 28.196,2.968 29.778,2.968 C30.534,2.968 31.192,3.15 31.598,3.374 L31.248,4.578 C30.968,4.41 30.408,4.186 29.806,4.186 C29.19,4.186 28.854,4.494 28.854,4.914 C28.854,5.348 29.176,5.544 30.044,5.866 C31.29,6.3 31.85,6.93 31.864,7.938 C31.864,9.184 30.898,10.08 29.092,10.08 C28.266,10.08 27.524,9.884 27.02,9.604 Z M33.278,9.94 L33.278,-7.10542736e-15 L35,-7.10542736e-15 L35,9.94 L33.278,9.94 Z M42.168,5.852 L42.168,8.302 C42.168,8.918 42.196,9.52 42.28,9.94 L40.726,9.94 L40.6,9.184 L40.558,9.184 C40.152,9.716 39.438,10.094 38.542,10.094 C37.17,10.094 36.4,9.1 36.4,8.064 C36.4,6.356 37.926,5.474 40.446,5.488 L40.446,5.376 C40.446,4.928 40.264,4.186 39.06,4.186 C38.388,4.186 37.688,4.396 37.226,4.69 L36.89,3.57 C37.394,3.262 38.276,2.968 39.354,2.968 C41.538,2.968 42.168,4.354 42.168,5.852 Z M40.488,7.546 L40.488,6.608 C39.27,6.594 38.108,6.846 38.108,7.882 C38.108,8.554 38.542,8.862 39.088,8.862 C39.788,8.862 40.278,8.414 40.446,7.924 C40.488,7.798 40.488,7.672 40.488,7.546 Z M44.184,1.848 L45.878,1.372 L45.878,3.122 L47.516,3.122 L47.516,4.41 L45.878,4.41 L45.878,7.42 C45.878,8.26 46.102,8.68 46.76,8.68 C47.068,8.68 47.236,8.666 47.432,8.61 L47.46,9.912 C47.208,10.01 46.746,10.094 46.214,10.094 C45.57,10.094 45.052,9.884 44.73,9.534 C44.352,9.142 44.184,8.512 44.184,7.616 L44.184,4.41 L43.218,4.41 L43.218,3.122 L44.184,3.122 L44.184,1.848 Z M50.54,9.94 L48.818,9.94 L48.818,3.122 L50.54,3.122 L50.54,9.94 Z M49.686,0.28 C50.274,0.28 50.638,0.686 50.652,1.218 C50.652,1.722 50.274,2.142 49.672,2.142 C49.098,2.142 48.72,1.722 48.72,1.218 C48.72,0.686 49.112,0.28 49.686,0.28 Z M55.496,2.968 C57.526,2.968 58.884,4.396 58.884,6.468 C58.884,8.974 57.12,10.094 55.384,10.094 C53.466,10.094 51.968,8.778 51.968,6.58 C51.968,4.34 53.438,2.968 55.496,2.968 Z M55.454,4.214 C54.236,4.214 53.746,5.404 53.746,6.538 C53.746,7.854 54.404,8.848 55.44,8.848 C56.42,8.848 57.106,7.896 57.106,6.51 C57.106,5.446 56.63,4.214 55.454,4.214 Z M60.298,9.94 L60.298,5.152 C60.298,4.368 60.27,3.71 60.242,3.122 L61.74,3.122 L61.824,4.144 L61.866,4.144 C62.174,3.612 62.916,2.968 64.05,2.968 C65.24,2.968 66.472,3.738 66.472,5.894 L66.472,9.94 L64.75,9.94 L64.75,6.09 C64.75,5.11 64.386,4.368 63.448,4.368 C62.762,4.368 62.286,4.858 62.104,5.376 C62.048,5.516 62.02,5.726 62.02,5.922 L62.02,9.94 L60.298,9.94 Z M79.422,9.94 L79.24,6.09 C79.184,4.872 79.114,3.402 79.128,2.128 L79.086,2.128 C78.778,3.276 78.386,4.55 77.966,5.74 L76.58,9.828 L75.264,9.828 L74.004,5.796 C73.64,4.592 73.304,3.304 73.052,2.128 L73.024,2.128 C72.982,3.36 72.926,4.858 72.856,6.146 L72.646,9.94 L71.036,9.94 L71.666,0.504 L73.934,0.504 L75.166,4.298 C75.502,5.404 75.796,6.524 76.034,7.574 L76.076,7.574 C76.328,6.552 76.65,5.39 77.014,4.284 L78.316,0.504 L80.556,0.504 L81.102,9.94 L79.422,9.94 Z M88.13,5.852 L88.13,8.302 C88.13,8.918 88.158,9.52 88.242,9.94 L86.688,9.94 L86.562,9.184 L86.52,9.184 C86.114,9.716 85.4,10.094 84.504,10.094 C83.132,10.094 82.362,9.1 82.362,8.064 C82.362,6.356 83.888,5.474 86.408,5.488 L86.408,5.376 C86.408,4.928 86.226,4.186 85.022,4.186 C84.35,4.186 83.65,4.396 83.188,4.69 L82.852,3.57 C83.356,3.262 84.238,2.968 85.316,2.968 C87.5,2.968 88.13,4.354 88.13,5.852 Z M86.45,7.546 L86.45,6.608 C85.232,6.594 84.07,6.846 84.07,7.882 C84.07,8.554 84.504,8.862 85.05,8.862 C85.75,8.862 86.24,8.414 86.408,7.924 C86.45,7.798 86.45,7.672 86.45,7.546 Z M89Line truncated
<path d="M0.91,27.712 L0.91,20.376 C0.91,19.508 0.882,18.808 0.854,18.164 L1.946,18.164 L2.016,19.326 L2.044,19.326 C2.534,18.5 3.346,18.024 4.452,18.024 C6.104,18.024 7.336,19.41 7.336,21.454 C7.336,23.89 5.838,25.094 4.242,25.094 C3.346,25.094 2.562,24.702 2.156,24.03 L2.128,24.03 L2.128,27.712 L0.91,27.712 Z M2.128,21.006 L2.128,22.182 C2.128,22.364 2.142,22.532 2.184,22.686 C2.408,23.54 3.15,24.128 4.032,24.128 C5.334,24.128 6.09,23.064 6.09,21.51 C6.09,20.166 5.376,19.004 4.074,19.004 C3.234,19.004 2.436,19.592 2.212,20.516 C2.17,20.67 2.128,20.852 2.128,21.006 Z M11.746,18.024 C13.692,18.024 15.008,19.438 15.008,21.496 C15.008,24.002 13.258,25.094 11.634,25.094 C9.814,25.094 8.386,23.75 8.386,21.608 C8.386,19.354 9.884,18.024 11.746,18.024 Z M11.718,18.948 C10.276,18.948 9.646,20.292 9.646,21.566 C9.646,23.05 10.486,24.17 11.69,24.17 C12.866,24.17 13.748,23.064 13.748,21.538 C13.748,20.39 13.174,18.948 11.718,18.948 Z M15.694,18.164 L16.954,18.164 L17.864,21.608 C18.046,22.364 18.228,23.064 18.354,23.764 L18.396,23.764 C18.55,23.078 18.774,22.35 18.998,21.622 L20.104,18.164 L21.14,18.164 L22.19,21.552 C22.442,22.364 22.638,23.078 22.792,23.764 L22.834,23.764 C22.946,23.078 23.128,22.364 23.352,21.566 L24.318,18.164 L25.536,18.164 L23.352,24.94 L22.232,24.94 L21.196,21.706 C20.958,20.95 20.762,20.278 20.594,19.48 L20.566,19.48 C20.398,20.292 20.188,20.992 19.95,21.72 L18.858,24.94 L17.738,24.94 L15.694,18.164 Z M32.074,21.776 L27.314,21.776 C27.342,23.442 28.392,24.128 29.638,24.128 C30.52,24.128 31.066,23.974 31.514,23.778 L31.738,24.66 C31.304,24.856 30.548,25.094 29.47,25.094 C27.384,25.094 26.138,23.708 26.138,21.664 C26.138,19.62 27.342,18.024 29.316,18.024 C31.542,18.024 32.116,19.956 32.116,21.202 C32.116,21.454 32.102,21.636 32.074,21.776 Z M27.328,20.894 L30.926,20.894 C30.94,20.124 30.604,18.906 29.218,18.906 C27.958,18.906 27.426,20.04 27.328,20.894 Z M33.642,24.94 L33.642,20.278 C33.642,19.48 33.628,18.794 33.586,18.164 L34.664,18.164 L34.72,19.508 L34.762,19.508 C35.07,18.598 35.826,18.024 36.652,18.024 C36.778,18.024 36.876,18.038 36.988,18.052 L36.988,19.214 C36.862,19.186 36.736,19.186 36.568,19.186 C35.7,19.186 35.084,19.83 34.916,20.754 C34.888,20.922 34.874,21.132 34.874,21.328 L34.874,24.94 L33.642,24.94 Z M43.526,21.776 L38.766,21.776 C38.794,23.442 39.844,24.128 41.09,24.128 C41.972,24.128 42.518,23.974 42.966,23.778 L43.19,24.66 C42.756,24.856 42,25.094 40.922,25.094 C38.836,25.094 37.59,23.708 37.59,21.664 C37.59,19.62 38.794,18.024 40.768,18.024 C42.994,18.024 43.568,19.956 43.568,21.202 C43.568,21.454 43.554,21.636 43.526,21.776 Z M38.78,20.894 L42.378,20.894 C42.392,20.124 42.056,18.906 40.67,18.906 C39.41,18.906 38.878,20.04 38.78,20.894 Z M49.714,15 L50.932,15 L50.932,23.19 C50.932,23.792 50.96,24.478 50.988,24.94 L49.896,24.94 L49.84,23.764 L49.798,23.764 C49.434,24.52 48.622,25.094 47.516,25.094 C45.878,25.094 44.604,23.708 44.604,21.65 C44.59,19.396 46.004,18.024 47.642,18.024 C48.692,18.024 49.378,18.514 49.686,19.046 L49.714,19.046 L49.714,15 Z M49.714,22.098 L49.714,20.922 C49.714,20.768 49.7,20.558 49.658,20.404 C49.476,19.634 48.804,18.99 47.88,18.99 C46.606,18.99 45.85,20.11 45.85,21.594 C45.85,22.966 46.536,24.1 47.852,24.1 C48.678,24.1 49.434,23.54 49.658,22.63 C49.7,22.462 49.714,22.294 49.714,22.098 Z M55.958,23.19 L55.958,15 L57.176,15 L57.176,19.256 L57.204,19.256 C57.638,18.5 58.422,18.024 59.514,18.024 C61.208,18.024 62.384,19.424 62.384,21.468 C62.384,23.89 60.844,25.094 59.332,25.094 C58.352,25.094 57.568,24.716 57.05,23.834 L57.022,23.834 L56.952,24.94 L55.902,24.94 C55.93,24.478 55.958,23.792 55.958,23.19 Z M57.176,21.02 L57.176,22.224 C57.176,22.378 57.19,22.532 57.232,22.672 C57.456,23.526 58.184,24.114 59.08,24.114 C60.382,24.114 61.138,23.064 61.138,21.51 C61.138,20.152 60.438,18.99 59.108,18.99 C58.282,18.99 57.498,19.578 57.246,20.502 C57.204,20.656 57.176,20.824 57.176,21.02 Z M62.93,18.164 L64.274,18.164 L65.744,22.168 C65.912,22.616 66.08,23.148 66.192,23.554 L66.22,23.554 C66.346,23.148 66.486,22.63 66.654,22.14 L67.998,18.164 L69.3,18.164 L67.452,22.994 C66.57,25.318 65.968,26.494 65.128,27.236 C64.512,27.754 63.924,27.964 63.616,28.02 L63.308,26.998 C63.616,26.9 64.022,26.704 64.386,26.396 C64.722,26.13 65.128,25.654 65.422,25.024 C65.478,24.898 65.52,24.8 65.52,24.73 C65.52,24.66 65.492,24.562 65.422,24.408 L62.93,18.164 Z" id="poweredby" fill="#AAAAAA"></path>
<path d="M73.29,24.94 L73.29,15 L75.012,15 L75.012,24.94 L73.29,24.94 Z M79.982,17.968 C82.012,17.968 83.37,19.396 83.37,21.468 C83.37,23.974 81.606,25.094 79.87,25.094 C77.952,25.094 76.454,23.778 76.454,21.58 C76.454,19.34 77.924,17.968 79.982,17.968 Z M79.94,19.214 C78.722,19.214 78.232,20.404 78.232,21.538 C78.232,22.854 78.89,23.848 79.926,23.848 C80.906,23.848 81.592,22.896 81.592,21.51 C81.592,20.446 81.116,19.214 79.94,19.214 Z M89.558,23.456 L89.796,24.73 C89.432,24.898 88.718,25.08 87.864,25.08 C85.736,25.08 84.35,23.708 84.35,21.594 C84.35,19.55 85.75,17.968 88.144,17.968 C88.774,17.968 89.418,18.108 89.81,18.276 L89.502,19.578 C89.222,19.438 88.816,19.312 88.2,19.312 C86.884,19.312 86.1,20.278 86.114,21.524 C86.114,22.924 87.024,23.722 88.2,23.722 C88.788,23.722 89.222,23.596 89.558,23.456 Z M92.792,24.94 L91.07,24.94 L91.07,18.122 L92.792,18.122 L92.792,24.94 Z M91.938,15.28 C92.526,15.28 92.89,15.686 92.904,16.218 C92.904,16.722 92.526,17.142 91.924,17.142 C91.35,17.142 90.972,16.722 90.972,16.218 C90.972,15.686 91.364,15.28 91.938,15.28 Z M94.01,24.94 L94.01,23.946 L96.572,20.67 C96.922,20.25 97.216,19.914 97.566,19.522 L97.566,19.494 L94.262,19.494 L94.262,18.122 L99.666,18.122 L99.666,19.172 L97.174,22.378 C96.838,22.784 96.516,23.176 96.166,23.54 L96.166,23.568 L99.75,23.568 L99.75,24.94 L94.01,24.94 Z M106.638,22.014 L102.074,22.014 C102.116,23.246 103.068,23.778 104.174,23.778 C104.972,23.778 105.532,23.652 106.064,23.47 L106.316,24.646 C105.728,24.898 104.916,25.08 103.936,25.08 C101.724,25.08 100.422,23.722 100.422,21.636 C100.422,19.746 101.57,17.968 103.754,17.968 C105.966,17.968 106.694,19.788 106.694,21.286 C106.694,21.608 106.666,21.86 106.638,22.014 Z M102.074,20.81 L105.07,20.81 C105.084,20.18 104.804,19.144 103.656,19.144 C102.592,19.144 102.144,20.11 102.074,20.81 Z M108.724,25.094 C108.108,25.094 107.674,24.618 107.674,23.988 C107.674,23.344 108.122,22.882 108.738,22.882 C109.368,22.882 109.802,23.33 109.802,23.988 C109.802,24.618 109.382,25.094 108.724,25.094 Z M115.962,23.456 L116.2,24.73 C115.836,24.898 115.122,25.08 114.268,25.08 C112.14,25.08 110.754,23.708 110.754,21.594 C110.754,19.55 112.154,17.968 114.548,17.968 C115.178,17.968 115.822,18.108 116.214,18.276 L115.906,19.578 C115.626,19.438 115.22,19.312 114.604,19.312 C113.288,19.312 112.504,20.278 112.518,21.524 C112.518,22.924 113.428,23.722 114.604,23.722 C115.192,23.722 115.626,23.596 115.962,23.456 Z M120.442,17.968 C122.472,17.968 123.83,19.396 123.83,21.468 C123.83,23.974 122.066,25.094 120.33,25.094 C118.412,25.094 116.914,23.778 116.914,21.58 C116.914,19.34 118.384,17.968 120.442,17.968 Z M120.4,19.214 C119.182,19.214 118.692,20.404 118.692,21.538 C118.692,22.854 119.35,23.848 120.386,23.848 C121.366,23.848 122.052,22.896 122.052,21.51 C122.052,20.446 121.576,19.214 120.4,19.214 Z M125.244,24.94 L125.244,20.152 C125.244,19.368 125.216,18.71 125.188,18.122 L126.658,18.122 L126.742,19.13 L126.784,19.13 C127.106,18.598 127.722,17.968 128.884,17.968 C129.78,17.968 130.48,18.472 130.774,19.228 L130.802,19.228 C131.04,18.85 131.32,18.57 131.628,18.374 C132.02,18.108 132.454,17.968 133.028,17.968 C134.148,17.968 135.296,18.738 135.296,20.922 L135.296,24.94 L133.616,24.94 L133.616,21.174 C133.616,20.04 133.224,19.368 132.398,19.368 C131.81,19.368 131.376,19.788 131.194,20.278 C131.138,20.432 131.11,20.656 131.11,20.852 L131.11,24.94 L129.43,24.94 L129.43,20.992 C129.43,20.04 129.052,19.368 128.254,19.368 C127.61,19.368 127.176,19.872 127.008,20.334 C126.952,20.516 126.924,20.712 126.924,20.908 L126.924,24.94 L125.244,24.94 Z" id="locize.com" fill="#888888"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 994 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 662 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

-50
View File
@@ -1,50 +0,0 @@
{
"title": "OHIF",
"description": "Documentation for the OHIF framework",
"gitbook": ">3.0.0",
"plugins": [
"edit-link",
"theme-cornerstone",
"-fontsettings",
"github",
"ga",
"sitemap",
"anchors",
"versions"
],
"pluginsConfig": {
"edit-link": {
"base": "https://github.com/OHIF/Viewers/edit/master/docs",
"label": "Edit This Page"
},
"github": {
"url": "https://github.com/OHIF/Viewers"
},
"ga": {
"token": "UA-110573590-2"
},
"sitemap": {
"hostname": "https://docs.ohif.org"
},
"versions": {
"gitbookConfigURL": "https://raw.githubusercontent.com/OHIF/Viewers/master/docs/book.json",
"options": [
{
"value": "https://docs.ohif.org/history/v1/",
"text": "Version 1.0.0 (Meteor)"
},
{
"value": "https://docs.ohif.org/",
"text": "Version 2.0.0",
"selected": true
}
]
}
},
"links": {
"sharing": {
"facebook": false,
"twitter": false
}
}
}
@@ -1,124 +0,0 @@
# Google Cloud Healthcare
> ATTENTION: The original documentation for this integration lives in the legacy
> `version 1` Meteor documentation. You can
> [find it here](/history/v1/connecting-to-image-archives/google-cloud-healthcare.html).
> These docs will mirror the Meteor documentation until our `React`
> implementation has been updated to work with Google Cloud Healthcare.
> The [Google Cloud Healthcare API](https://cloud.google.com/healthcare/) is a
> powerful option for storing medical imaging data in the cloud.
An alternative to deploying your own PACS is to use a software-as-a-service
provider such as Google Cloud. The Cloud Healthcare API promises to be a
scalable, secure, cost effective image storage solution for those willing to
store their data in the cloud. It offers an
[almost-entirely complete DICOMWeb API](https://cloud.google.com/healthcare/docs/dicom)
which requires tokens generated via the
[OAuth 2.0 Sign In flow](https://developers.google.com/identity/sign-in/web/sign-in).
Images can even be transcoded on the fly if this is desired. The Cloud
Healthcare API is a very attractive option because it allows us to avoid
deploying the Meteor server entirely. We can just deploy OHIF as a client-only
static site application.
## Setup a Google Cloud Healthcare Project
- Create a Google Cloud account
- Create a project in Google Cloud
- Enable the [Cloud Healthcare API](https://cloud.google.com/healthcare/) for
your project.
- (Optional): Create a Dataset and Data Store for storing your DICOM data
- Enable the
[Cloud Resource Manager API](https://cloud.google.com/resource-manager/) for
your project.
- _Note:_ If you are having trouble finding the APIs, use the search box at
the top of the Cloud console.
- Go to APIs & Services > Credentials to create an OAuth Consent screen and fill
in your application details.
- Under Scopes for Google APIs, click "manually paste scopes".
- Add the following scopes:
- `https://www.googleapis.com/auth/cloudplatformprojects.readonly`
- `https://www.googleapis.com/auth/cloud-healthcare`
- Go to APIs & Services > Credentials to create a new set of credentials:
- Choose the "Web Application" type
- Set up an
[OAuth 2.0 Client ID](https://support.google.com/cloud/answer/6158849?hl=en)
- Add your domain (e.g. `http://localhost:3000`) to Authorized JavaScript
origins.
- Add your domain, plus `_oauth/google` (e.g.
`http://localhost:3000/_oauth/google`) to Authorized Redirect URIs.
- Save your Client ID for later.
- (Optional): Enable Public Datasets that are being hosted by Google:
https://cloud.google.com/healthcare/docs/resources/public-datasets/
## Run the viewer with your OAuth Client ID
1. Open the `config/oidc-googleCloud.json` file and change `YOURCLIENTID` to
your Client ID value.
1. Run the OHIF Viewer using the oidc-googleCloud.json configuration file
```bash
cd OHIFViewer
METEOR_PACKAGE_DIRS="../Packages" meteor npm install
METEOR_PACKAGE_DIRS="../Packages" meteor --settings ../config/oidc-googleCloud.json
```
## Running via Docker
OHIF is also providing a Docker container which can connect to Google Cloud
Healthcare with a Client ID which is provided at runtime. This is a very simple
method to get up and running. Internally, the container is running
[Nginx](https://nginx.org/) to serve the
[Standalone Viewer](../standalone-viewer/usage.md).
1. Install Docker (https://www.docker.com/)
1. Run the Docker container, providing a Client ID as an environment variable.
Client IDs look like `xyz.apps.googleusercontent.com`.
```bash
docker run --env CLIENT_ID=$CLIENT_ID --publish 3000:80 ohif/viewer-google-cloud:latest
```
## Building the ohif/viewer-google-cloud Docker Image
The
[ohif/viewer-google-cloud](https://cloud.docker.com/u/ohif/repository/docker/ohif/viewer-google-cloud)
Docker image is built as follows. The Dockerfile and nginx.conf are in the
`/dockersupport/viewer-google-cloud` folder.
1. [Install Meteor](https://www.meteor.com/install)
1. Clone the repository
```bash
git clone https://github.com/OHIF/Viewers.git
cd Viewers
```
1. Install meteor-build-client-fixed2 so you can build the Standalone Viewer
```bash
npm install -g meteor-build-client-fixed2
```
1. Build the Standalone client-only OHIF Viewer
```bash
cd OHIFViewer/
METEOR_PACKAGE_DIRS="../Packages" meteor npm install
METEOR_PACKAGE_DIRS="../Packages" meteor-build-client-fixed2 ../dockersupport/viewer-google-cloud/build -s ../config/oidc.json
```
1. Build the Docker image
```bash
cd ../dockersupport/viewer-google-cloud
docker build -t ohif/viewer-google-cloud .
```
1. Run the Docker image using an OAuth Client ID
```bash
docker run --env CLIENT_ID={$someID}.apps.googleusercontent.com --publish 3000:80 ohif/viewer-google-cloud
```
-103
View File
@@ -1,103 +0,0 @@
# Contributing
## I would like to contribute code - how do I do this?
Fork the repository, make your change and submit a pull request.
- The OHIF Viewer consists of code from three different repositories. Make sure
your change is modifying the appropriate one:
- `ohif-core`: Business Logic
- `react-viewerbase`: Reusable React Component Library
- `Viewers`: The glue, PWA, and primary extension point
- At a minimum, you may want to read the following documentation:
- [Essentials: Getting Started](./essentials/getting-started.md)
- [Advanced: Architecture](./advanced/architecture.md)
### When changes impact multiple repositories
This is a particularly tricky scenario. We don't want to publish code in one
repository, just so we can test and complete the other half of its requirements
in another. Thankfully, there are a couple of ways you can test unpublished
dependent changes locally before publishing:
- [Use `yarn link`](https://yarnpkg.com/en/docs/cli/link)
For example if you are working on `ohif-core` and would like to use your local
version to debug a problem in `Viewers`, simply run yarn link inside of the
`ohif-core` project.
- If you're experiencing issues with `yarn link`,
[try `yalc`](https://github.com/whitecolor/yalc)
Yalc provides an improved workflow as we add more and more dependent packages
that are "in-progress". This comes into play as we begin working on extensions
and their dependencies.
```js
// Install yalc for the first time
yarn global add yalc
// EXAMPLE: using an in-development version of ohif-core w/ Viewers locally
// 1. Navigate to ohif-core's project root
yarn install
yalc publish
// 2. Run the following after each change to ohif-core
yarn build
yalc push .
// 3. Use the local package in our Viewers project. Navigate to the Viewers
// Project root.
yarn install
yalc add ohif-core
yarn run dev
```
## Any guidance on submitting changes?
While we do appreciate code contributions, triaging and integrating contributed
code changes can be very time consuming. Please consider the following tips when
working on your pull requests:
- Functionality is appropriate for the repository. Consider creating a GitHub
issue to discuss your suggested changes.
- The scope of the pull request is not too large. Please consider separate pull
requests for each feature as big pull requests are very time consuming to
understand.
We will provide feedback on your pull requests as soon as possible. Following
the tips above will help ensure your changes are reviewed.
## Testing contribution pull requests
OHIF uses [netlify](netlify.com) so that pull requests are autogenerated and
available for testing.
For example, [this url][example-url] allows you to test [pull request 237, the
request that created this FAQ entry,][pr-237] using data pulled from Amazon S3.
Replacing the number 237 in the link below with your pull request number should
let you test it as well and you can use this link for discussions on github
without requiring reviewers to download and build your branch.
```bash
https://deploy-preview-237--ohif.netlify.com/viewer/?url=https://s3.eu-central-1.amazonaws.com/ohif-viewer/sampleDICOM.json
```
If you have made a documentation change, a link like this will let you preview
the gitbook generated by the pull request:
```bash
https://deploy-preview-237--ohif.netlify.com/contributing.html
```
<!--
Links
-->
<!-- prettier-ignore-start -->
[example-url]: https://deploy-preview-237--ohif.netlify.com/viewer/?url=https://s3.eu-central-1.amazonaws.com/ohif-viewer/sampleDICOM.json
[pr-237]: https://github.com/OHIF/Viewers/pull/237
<!-- prettier-ignore-end -->
@@ -1,4 +0,0 @@
<div style="text-align: center;">
<img src="/assets/img/embedded-viewer-diagram.png" alt="Embedded Viewer Diagram" style="margin: 0 auto;" />
<div><i>embedded viewer diagram</i></div>
</div>
@@ -1,4 +0,0 @@
<div style="text-align: center;">
<img src="/assets/img/nginx-image-archive.png" alt="request flow example" style="margin: 0 auto;" />
<div><i>simplified request flow diagram</i></div>
</div>
@@ -1,4 +0,0 @@
<div style="text-align: center;">
<img src="/assets/img/user-access-control-request-flow.png" alt="request flow example" style="margin: 0 auto;" />
<div><i>simplified request flow diagram</i></div>
</div>
-210
View File
@@ -1,210 +0,0 @@
# Deployment
The OHIF Viewer can be embedded in other web applications via it's [packaged
script source][ohif-viewer-npm], or served up as a stand-alone PWA ([progressive
web application][pwa-url]) by building and hosting a collection of static
assets. In either case, you will need to configure your instance of the Viewer
so that it can connect to your data source (the database or PACS that provides
the data your Viewer will display).
## Overview
Our goal is to make deployment as simple and painless as possible; however,
there is an inherent amount of complexity in customizing, optimizing, and
deploying web applications. If you find yourself a little lost, please don't
hesitate to [reach out for help](/help.md)
## Deployment Scenarios
### Embedded Viewer
The quickest and easiest way to get the OHIF Viewer up and running is to embed
it into an existing web application. It allows us to forego a "build step", and
add a powerful medical imaging viewer to an existing web page using only a few
include tags.
- Read more about it here: [Embedded Viewer](./recipes/embedded-viewer.md)
- And check out our [live demo on CodeSandbox][code-sandbox]
{% include "./_embedded-viewer-diagram.md" %}
### Stand-alone Viewer
Deploying the OHIF Viewer as a stand-alone web application provides many
benefits, but comes at the cost of time and complexity. Some benefits include:
_Today:_
- Leverage [extensions](/advanced/extensions.md) to drop-in powerful new
features
- Add routes and customize the viewer's workflow
- Finer control over styling and whitelabeling
_In the future:_
- The ability to package the viewer for [App Store distribution][app-store]
- Leverage `service-workers` for offline support and speed benefits from caching
#### Hosted Static Assets
At the end of the day, a production OHIF Viewer instance is a collection of
HTML, CSS, JS, Font Files, and Images. We "build" those files from our
`source code` with configuration specific to our project. We then make those
files publicly accessible by hosting them on a Web Server.
If you have not deployed a web application before, this may be a good time to
[reach out for help](/help.md), as these steps assume prior web development and
deployment experience.
##### Part 1 - Build Production Assets
"Building", or creating, the files you will need is the same regardless of the
web host you choose. You can find detailed instructions on how to configure and
build the OHIF Viewer in our
["Build for Production" guide](./recipes/build-for-production.md).
##### Part 2 - Host Your App
There are a lot of [benefits to hosting static assets][host-static-assets] over
dynamic content. You can find instructions on how to host your build's output
via one of these guides:
_Drag-n-drop_
- [Netlify: Drop](/deployment/recipes/static-assets.md#netlify-drop)
_Easy_
- [Surge.sh](/deployment/recipes/static-assets.md#surgesh)
- [GitHub Pages](/deployment/recipes/static-assets.md#github-pages)
_Advanced_
- [AWS S3 + Cloudfront](/deployment/recipes/static-assets.md#aws-s3--cloudfront)
- [GCP + Cloudflare](/deployment/recipes/static-assets.md#gcp--cloudflare)
- [Azure](/deployment/recipes/static-assets.md#azure)
## Data
The OHIF Viewer is able to connect to any data source that implements the [DICOM
Web Standard][dicom-web-standard]. [DICOM Web][dicom-web] refers to RESTful
DICOM Services -- a recently standardized set of guidelines for exchanging
medical images and imaging metadata over the internet. Not all archives fully
support it yet, but it is gaining wider adoption.
### Configure Connection
If you have an existing archive and intend to host the OHIF Viewer at the same
domain name as your archive, then connecting the two is as simple as following
the steps layed out in our
[Configuration Essentials Guide](./../essentials/configuration.md).
#### What if I don't have an imaging archive?
We provide some guidance on configuring a local image archive in our
[Data Source Essentials](./../essentials/data-source.md) guide. Hosting an
archive remotely is a little trickier. You can check out some of our
[advanced recipes](#recipes) for modeled setups that may work for you.
#### What if I intend to host the OHIF Viewer at a different domain?
There are two important steps to making sure this setup works:
1. Your Image Archive needs to be exposed, in some way, to the open web. This
can be directly, or through a `reverse proxy`, but the Viewer needs _some
way_ to request it's data.
2. \* Your Image Archive needs to have appropriate CORS (Cross-Origin Resource
Sharing) Headers
> \* Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional
> HTTP headers to tell a browser to let a web application running at one origin
> (domain) have permission to access selected resources from a server at a
> different origin. - [MDN Web Docs: Web - Http - CORS][cors]
Most image archives do not provide either of these features "out of the box".
It's common to use IIS, Nginx, or Apache to route incoming requests and append
appropriate headers. You can find an example of this setup in our
[Nginx + Image Archive Deployment Recipe](deployment/recipes/nginx--image-archive.md).
#### What if my archive doesn't support DicomWeb?
> This is possible to do with the OHIF Viewer, but not as straightforward. Look
> out for documentation on this subject in the near future.
...
### Securing Your Data
> Feeling lost? Securing your data is important, and it can be hard to tell if
> you've gotten it right. Don't hesitate to work with professional auditors, or
> [enlist help from experts](./../help.md).
The OHIF Viewer can be configured to work with authorization servers that
support one or more of the OpenID-Connect authorization flows. The Viewer finds
it's OpenID-Connect settings on the `oidc` configuration key. You can set these
values following the instructions laid out in the
[Configuration Essentials Guide](./../essentials/configuration.md).
_Example OpenID-Connect Settings:_
```js
window.config = {
...
oidc: [
{
// ~ REQUIRED
// Authorization Server URL
authority: 'http://127.0.0.1/auth/realms/ohif',
client_id: 'ohif-viewer',
redirect_uri: 'http://127.0.0.1/callback', // `OHIFStandaloneViewer.js`
response_type: 'code', // "Authorization Code Flow"
scope: 'openid', // email profile openid
// ~ OPTIONAL
post_logout_redirect_uri: '/logout-redirect.html',
},
],
}
```
You can find an example of this setup in our
[User Account Control Deployment Recipe](deployment/recipes/user-account-control.md).
#### Choosing a Flow for the Viewer
In general, we recommend using the "Authorization Code Flow" ( [see
`response_type=code` here][code-flows]); however, the "Implicit Flow" ( [see
`response_type=token` here][code-flows]) can work if additonal precautions are
taken. If the flow you've chosen produces a JWT Token, it's validity can be used
to secure access to your Image Archive as well.
### Recipes
We've included a few recipes for common deployment scenarios. There are many,
many possible configurations, so please don't feel limited to these setups.
Please feel free to suggest or contribute your own recipes.
- Script Include
- [Embedding the Viewer](deployment/recipes/embedded-viewer.md)
- Stand-Alone
- [Build for Production](deployment/recipes/build-for-production.md)
- [Static](deployment/recipes/static-assets.md)
- [Nginx + Image Archive](deployment/recipes/nginx--image-archive.md)
- [User Account Control](deployment/recipes/user-account-control.md)
<!--
Links
-->
<!-- prettier-ignore-start -->
[ohif-viewer-npm]: https://www.npmjs.com/package/ohif-viewer
[pwa-url]: https://developers.google.com/web/progressive-web-apps/
[static-assets-url]: https://www.maxcdn.com/one/visual-glossary/static-content/
[app-store]: https://medium.freecodecamp.org/i-built-a-pwa-and-published-it-in-3-app-stores-heres-what-i-learned-7cb3f56daf9b
[dicom-web-standard]: https://www.dicomstandard.org/dicomweb/
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
[host-static-assets]: https://www.netlify.com/blog/2016/05/18/9-reasons-your-site-should-be-static/
[cors]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
[code-flows]: https://medium.com/@darutk/diagrams-of-all-the-openid-connect-flows-6968e3990660
[code-sandbox]: https://codesandbox.io/s/ohif-viewer-script-tag-usage-b3st9
<!-- prettier-ignore-end -->
@@ -1,183 +0,0 @@
# Build for Production
> If you've already followed the
> ["Getting Started" Guide](/essentials/getting-started.md), you can skip ahead
> to [Configuration](#configuration)
## Overview
### Build Machine Requirements
- [Node.js & NPM](https://nodejs.org/en/download/)
- [Yarn](https://yarnpkg.com/lang/en/docs/install/)
- [Git](https://www.atlassian.com/git/tutorials/install-git)
### Getting the Code
_With Git:_
```bash
# Clone the remote repository to your local machine
git clone https://github.com/OHIF/Viewers.git
# Make sure the local code reflects the `react` version of the OHIF Viewer
git checkout react
```
More on: _[`git clone`](https://git-scm.com/docs/git-clone),
[`git checkout`](https://git-scm.com/docs/git-checkout)_
_From .zip:_
[OHIF/Viewers: react.zip](https://github.com/OHIF/Viewers/archive/react.zip)
### Restore Dependencies & Build
Open your terminal, and navigate to the directory containing the source files.
Next run these commands:
```js
// Restore dependencies
yarn install
// Build source code for production
yarn run build:web
```
If everything worked as expected, you should have a new `build/` directory in
the project's folder. It should roughly resemble the following:
```bash
build
├── config/
├── static/
├── index.html
├── manifest.json
├── service-worker.js
└── ...
```
By default, the build output will connect to OHIF's publicly accessible PACS. If
this is your first time setting up the OHIF Viewer, it is recommended that you
test with these default settings. After testing, you can find instructions on
how to configure the project for your own imaging archive below.
### Configuration
> This step assumes you have an imaging archive. If you need assistance setting
> one up, check out the [`Data Source` Guide](./../../essentials/data-source.md)
> or a deployment recipe that contains an open source Image Archive
#### How it Works
The configuration for our project is in the `/public/config` directory. Our
build process knows which configuration file to use based on the
`REACT_APP_CONFIG` environment variable. By default, its value is
[`default.js`](https://github.com/OHIF/Viewers/blob/react/public/config/default.js).
When we build, the `%REACT_APP_CONFIG%` value in
our[`/public/index.html`](https://github.com/OHIF/Viewers/blob/react/public/index.html#L12-L15)
file is substituted for the correct configuration file's name. This sets
the`window.config` equal to our configuration file's value.
#### How do I configure my project?
The simplest way is to update the existing default config:
_/public/config/default.js_
```js
window.config = {
routerBasename: '/',
relativeWebWorkerScriptsPath: '',
servers: {
dicomWeb: [
{
name: 'DCM4CHEE',
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
qidoSupportsIncludeField: true,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
requestOptions: {
requestFromBrowser: true,
},
},
],
},
}
```
You can also create a new config file and specify its path relative to the build
output's root by setting the `REACT_APP_CONFIG` environment variable. You can
set the value of this environment variable a few different ways:
- [Add a temporary environment variable in your shell](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-temporary-environment-variables-in-your-shell)
- [Add environment specific variables in `.env` file(s)](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env)
- Using the `cross-env` package in an npm script:
- `"build": "cross-env REACT_APP_CONFIG=config/my-config.js react-scripts build"`
After updating the configuration, `yarn run build:web` to generate updated build
output.
## Next Steps
### Deploying Build Output
_Drag-n-drop_
- [Netlify: Drop](/deployment/recipes/static-assets.md#netlify-drop)
_Easy_
- [Surge.sh](/deployment/recipes/static-assets.md#surgesh)
- [GitHub Pages](/deployment/recipes/static-assets.md#github-pages)
_Advanced_
- [AWS S3 + Cloudfront](/deployment/recipes/static-assets.md#aws-s3--cloudfront)
- [GCP + Cloudflare](/deployment/recipes/static-assets.md#gcp--cloudflare)
- [Azure](/deployment/recipes/static-assets.md#azure)
### Testing Build Output Locally
A quick way to test your build output locally is to spin up a small webserver.
You can do this by running the following commands in the `build/` output
directory:
```js
// Install http-server as a globally available package
yarn global add http-server
// Serve the files in our current directory
// Accessible at: `http://localhost:8080`
http-server
```
### Automating Builds and Deployments
If you found setting up your environmnent and running all of these steps to be a
bit tedious, then you are in good company. Thankfully, there are a large number
of tools available to assist with automating tasks like building and deploying
web application. For a starting point, check out this repository's own use of:
- [CircleCI][circleci]: [config.yaml][circleci-config]
- [Netlify][netlify]: [netlify.toml][netlify.toml] |
[generateStaticSite.sh][generatestaticsite.sh]
- [Semantic-Release][semantic-release]: [.releaserc][releaserc]
## Troubleshooting
> Issues and resolutions for common GitHub issues will be summarized here
...
<!-- prettier-ignore-start -->
[circleci]: https://circleci.com/gh/OHIF/Viewers
[circleci-config]: https://github.com/OHIF/Viewers/blob/react/.circleci/config.yml
[netlify]: https://app.netlify.com/sites/ohif/deploys
[netlify.toml]: https://github.com/OHIF/Viewers/blob/react/netlify.toml
[generateStaticSite.sh]: https://github.com/OHIF/Viewers/blob/react/generateStaticSite.sh
[semantic-release]: https://semantic-release.gitbook.io/semantic-release/
[releaserc]: https://github.com/OHIF/Viewers/blob/react/.releaserc
<!-- prettier-ignore-end -->
@@ -1,106 +0,0 @@
# Embedded Viewer
The quickest and easiest way to get the OHIF Viewer up and running is to embed
it into an existing web application. It allows us to forego a "build step", and
add a powerful medical imaging viewer to an existing web page using only a few
include tags. Here's how it works:
{% include "./../_embedded-viewer-diagram.md" %}
1. Create a new web page or template that includes the following external
dependencies:
<ul>
<li>
<a href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<code>bootstrap@3.3.7</code>
</a>
</li>
<li>
<a href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700|Sanchez&display=swap">
<code>Google Fonts, Sanchez & Roboto</code>
</a>
</li>
<li>
<a href="https://unpkg.com/react@16/umd/react.production.min.js">
<code>react@16.8.6</code>
</a>
</li>
<li>
<a href="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js">
<code>react-dom@16.8.6</code>
</a>
</li>
<li>
<a href="https://unpkg.com/ohif-viewer/dist/index.umd.js">
<code>ohif-viewer@latest</code>
</a>
</li>
</ul>
<ol start="2">
<li>The <a href="">WADO Image Loader Codecs and Web Worker source code</a>
should be accessible from your server's root</li>
<li>Create a JS Object to hold the OHIF Viewer's configuration. Here are some
example values that would allow the viewer to hit our public PACS:</li>
</ol>
```js
// Set before importing `ohif-viewer`
window.config = {
// default: '/'
routerBasename: '/',
// default: ''
relativeWebWorkerScriptsPath: '',
servers: {
dicomWeb: [
{
name: 'DCM4CHEE',
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
qidoSupportsIncludeField: true,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
requestOptions: {
requestFromBrowser: true,
},
},
],
},
};
```
<ol start="5"><li>
Render the viewer in the web page's target <code>div</code>
</li></ol>
```js
// Made available by the `ohif-viewer` script included in step 1
var Viewer = window.OHIFStandaloneViewer.App;
var app = React.createElement(Viewer, window.config, null);
ReactDOM.render(app, document.getElementById('ohif-viewer-target'));
```
#### Tips & Tricks
> I'm having trouble getting this to work. Where can I go for help?
First, check out this fully functional [CodeSandbox][code-sandbox] example. If
you're still having trouble, feel free to search or GitHub issues. Can't find
anything related your problem? Create a new one.
> When I include bootstrap, other styles on my page no longer work correctly.
> What can I do?
When we include `bootsrap` (and the other dependencies), they are added
globally. This has the potential of causing conflicts with other scripts and
styles on the page. To prevent this, `embed` the viewer in a new/empty web page.
Have that working? Good. Now `embed` that new page using an
[`<iframe>` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe).
This should produce the expected result while also protecting your page from any
globally defined styles/scripts.
[code-sandbox]: https://codesandbox.io/s/ohif-viewer-script-tag-usage-b3st9
@@ -1,245 +0,0 @@
# Nginx + Image Archive
> DISCLAIMER! We make no claims or guarantees of this approach's security. If in
> doubt, enlist the help of an expert and conduct proper audits.
At a certain point, you may want others to have access to your instance of the
OHIF Viewer and its medical imaging data. This post covers one of many potential
setups that accomplish that. Please note, noticably absent is user account
control.
Do not use this recipe to host sensitive medical data on the open web. Depending
on your company's policies, this may be an appropriate setup on an internal
network when protected with a server's basic authentication. For a more robust
setup, check out our [user account control recpie](./user-account-control.md)
that builds on the lessons learned here.
## Overview
Our two biggest hurdles when hosting our image archive and web client are:
- Risks related to exposing our PACS to the netowrk
- Cross-Origin Resource Sharing (CORS) requests
### Handling Web Requests
We mittigate our first issue by allowing [Nginx][nginx] to handle incoming web
requests. Nginx is open source software for web serving, reverse proxying,
caching, and more. It's designed for maximum performance and stability --
allowing us to more reliably serve content than Orthanc's built-in server can.
More specifically, we accomplish this by using a
[`reverse proxy`](https://en.wikipedia.org/wiki/Reverse_proxy) to retrieve
resources from our image archive (Orthanc), and when accessing its web admin.
> A reverse proxy is a type of proxy server that retrieves resources on behalf
> of a client from one or more servers. These resources are then returned to the
> client, appearing as if they originated from the proxy server itself.
### CORS Issues
Cross-Origin Resource Sharing (CORS) is a mechanism that uses HTTP headers to
tell a browser which web applications have permission to access selected
resources from a server at a different origin (domain, protocol, port). IE. By
default, a Web App located at `http://my-website.com` can't access resources
hosted at `http://not-my-website.com`
We can solve this one of two ways:
1. Have our Image Archive located at the same domain as our Web App
2. Add appropriate `Access-Control-Allow-*` HTTP headers
This solution uses the first approach, but you can see an example of the second
in the `docker-compose` bundled with this project for local development:
[HERE](#)
You can read more about CORS in this Medium article: [Understanding
CORS][understanding-cors]
### Diagram
This setup allows us to create a setup similar to the one pictured below:
{% include "./../_nginx-image-archive-diagram.md" %}
- All web requests are routed through `nginx` on our `OpenResty` image
- `/pacs` is a reverse proxy for `orthanc`'s `DICOM Web` endpoints
- `/pacs-admin` is a reverse proxy for `orthanc`'s Web Admin
- All static resources for OHIF Viewer are served up by `nginx` when a matching
route for that resource is requested
## Getting Started
### Requirements
- Docker
- [Docker for Mac](https://docs.docker.com/docker-for-mac/)
- [Docker for Windows](https://docs.docker.com/docker-for-windows/)
_Not sure if you have `docker` installed already? Try running `docker --version`
in command prompt or terminal_
### Setup
_Spin Things Up_
- Navigate to `<project-root>/docker/OpenResty-Orthanc` in your shell
- Run `docker-compose up`
_Upload Your First Study_
- Navigate to `http://127.0.0.1/pacs-admin`
- From the top right, select "Upload"
- Click "Select files to upload..." (DICOM)
- Click "Start the upload"
- Navigate back to `http://127.0.0.1/` to view your studies in the Study List
### Troubleshooting
_Exit code 137_
This means Docker ran out of memory. Open Docker Desktop, go to the `advanced`
tab, and increase the amount of Memory available.
_Cannot create container for service X_
Use this one with caution: `docker system prune`
_X is already running_
Stop running all containers:
- Win: `docker ps -a -q | ForEach { docker stop $_ }`
- Linux: `docker stop $(docker ps -a -q)`
### Configuration
After verifying that everything runs with default configuration values, you will
likely want to update:
- The domain: `http://127.0.0.1`
#### OHIF Viewer
The OHIF Viewer's configuration is imported from a static `.js` file and made
available globally at `window.config`. The configuration we use is set to a
specific file when we build the viewer, and determined by the env variable:
`REACT_APP_CONFIG`. You can see where we set its value in the `dockerfile` for
this solution:
`ENV REACT_APP_CONFIG=config/docker_openresty-orthanc.js`
You can find the configuration we're using here:
`/public/config/docker_openresty-orthanc.js`
To rebuild the `webapp` image created by our `dockerfile` after updating the
Viewer's configuration, you can run:
- `docker-compose build` OR
- `docker-compose up --build`
#### Other
All other files are found in: `/docker/OpenResty-Orthanc/`
| Service | Configuration | Docs |
| ----------------- | ---------------------------------------------- | ------------------------------------------- |
| OHIF Viewer | [dockerfile][dockerfile] / [config.js][config] | You're reading them now! |
| OpenResty (Nginx) | [`/nginx.conf`][config-nginx] | [lua-resty-openidc][lua-resty-openidc-docs] |
| Orthanc | [`/orthanc.json`][config-orthanc] | [Here][orthanc-docs] |
## Next Steps
### Deploying to Production
While these configuration and docker-compose files model an environment suitable
for production, they are not easy to deploy "as is". You can either:
- Manually recreate this environment and deploy built application files **OR**
- Deploy to a cloud kubernetes provider like
[Digital Ocean](https://www.digitalocean.com/products/kubernetes/) **OR**
- [See a full list of cloud providers here](https://landscape.cncf.io/category=cloud&format=card-mode&grouping=category)
- Find and follow your preferred provider's guide on setting up
[swarms and stacks](https://docs.docker.com/get-started/)
### Adding SSL
Adding SSL registration and renewal for your domain with Let's Encrypt that
terminates at Nginx is an incredibly important step toward securing your data.
Here are some resources, specific to this setup, that may be helpful:
- [lua-resty-auto-ssl](https://github.com/GUI/lua-resty-auto-ssl)
- [Let's Encrypt + Nginx](https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/)
While we terminate SSL at Nginx, it may be worth using self signed certificates
for communication between services.
- [SSL Termination for TCP Upstream Servers](https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-tcp/)
### Use PostgresSQL w/ Orthanc
Orthanc can handle a large amount of data and requests, but if you find that
requests start to slow as you add more and more studies, you may want to
configure your Orthanc instance to use PostgresSQL. Instructions on how to do
that can be found in the
[`Orthanc Server Book`](http://book.orthanc-server.com/users/docker.html), under
"PostgreSQL and Orthanc inside Docker"
### Improving This Guide
Here are some improvements this guide would benefit from, and that we would be
more than happy to accept Pull Requests for:
- SSL Support
- Complete configuration with `.env` file (or something similar)
- Any security issues
- One-click deploy to a cloud provider
## Resources
### Misc. Helpful Commands
_Check if `nginx.conf` is valid:_
```bash
docker run --rm -t -a stdout --name my-openresty -v $PWD/config/:/usr/local/openresty/nginx/conf/:ro openresty/openresty:alpine-fat openresty -c /usr/local/openresty/nginx/conf/nginx.conf -t
```
_Interact w/ running container:_
`docker exec -it CONTAINER_NAME bash`
_List running containers:_
`docker ps`
### Referenced Articles
For more documentation on the software we've chosen to use, you may find the
following resources helpful:
- [Orthanc for Docker](http://book.orthanc-server.com/users/docker.html)
- [OpenResty Guide](http://www.staticshin.com/programming/definitely-an-open-resty-guide/)
- [Lua Ngx API](https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/)
For a different take on this setup, check out the repository one of our
community members put together:
- [mjstealey/ohif-orthanc-dimse-docker](https://github.com/mjstealey/ohif-orthanc-dimse-docker)
<!--
Links
-->
<!-- prettier-ignore-start -->
<!-- DOCS -->
[nginx]: https://www.nginx.com/resources/glossary/nginx/
[understanding-cors]: https://medium.com/@baphemot/understanding-cors-18ad6b478e2b
[orthanc-docs]: http://book.orthanc-server.com/users/configuration.html#configuration
[lua-resty-openidc-docs]: https://github.com/zmartzone/lua-resty-openidc
<!-- SRC -->
[config]: #
[dockerfile]: #
[config-nginx]: #
[config-orthanc]: #
<!-- prettier-ignore-end -->
@@ -1,149 +0,0 @@
# Deploy Static Assets
> WARNING! All of these solutions stand-up a publicly accessible web viewer. Do
> not hook your hosted viewer up to a sensitive source of data without
> implementing authentication.
There are a lot of options for deploying static assets. Some services, like
`netlify` and `surge.sh`, specialize in static websites. You'll notice that
deploying with them requires much less time and effort, but comes at the cost of
less product offerings.
While not required, it can simplify things to host your Web Viewer alongside
your image archive. Services with more robust product offerings, like
`Google Cloud`, `Microsoft's Azure`, and `Amazon Web Services (AWS)`, are able
to accomodate this setup.
_Drag-n-drop_
- [Netlify: Drop](#netlify-drop)
_Easy_
- [Surge.sh](#surgesh)
- [GitHub Pages](#github-pages)
_Advanced_
- [AWS S3 + Cloudfront](#aws-s3--cloudfront)
- [GCP + Cloudflare](#gcp--cloudflare)
- [Azure](#azure)
## Drag-n-drop
### Netlify: Drop
> Build, deploy, and manage modern web projects. An all-in-one workflow that
> combines global deployment, continuous integration, and automatic HTTPS. And
> that’s just the beginning.
![netlify-drop example](../../assets/img/netlify-drop.gif)
_GIF demonstrating deployment with Netlify Drop_
1. https://app.netlify.com/drop
2. Drag your `build/` folder on to the drop target
3. ...
4. _annnd you're done_
**Features:**
- Custom domains & HTTPS
- Instant Git integration
- Continuous deployment
- Deploy previews
- Access to add-ons
(Non-free tiers include identity, FaaS, Forms, etc.)
Learn more about [Netlify on their website](https://www.netlify.com/)
## Easy
### Surge.sh
> Static web publishing for Front-End Developers. Simple, single-command web
> publishing. Publish HTML, CSS, and JS for free, without leaving the command
> line.
![surge.sh deploy example](../../assets/img/surge-deploy.gif)
_GIF demonstrating deployment with surge_
```shell
# Add surge command
yarn global add surge
# In the build directory
surge
```
**Features:**
- Free custom domain support
- Free SSL for surge.sh subdomains
- pushState support for single page apps
- Custom 404.html pages
- Barrier-free deployment through the CLI
- Easy integration into your Grunt toolchain
- Cross-origin resource support
- And more…
Learn more about [surge.sh on their website](https://surge.sh/)
### GitHub Pages
> WARNING! While great for project sites and light use, it is not advised to use
> GitHub Pages for production workloads. Please consider using a different
> service for mission critical applications.
> Websites for you and your projects. Hosted directly from your GitHub
> repository. Just edit, push, and your changes are live.
This deploy strategy makes more sense if you intend to maintain your project in
a GitHub repository. It allows you to specify a `branch` or `folder` as the
target for a GitHub Page's website. As you push code changes, the hosted content
updates to reflect those changes.
1. Head over to GitHub.com and create a new repository, or go to an existing
one. Click on the Settings tab.
2. Scroll down to the GitHub Pages section. Choose the `branch` or `folder` you
would like as the "root" of your website.
3. Fire up a browser and go to `http://username.github.io/repository`
Configuring Your Site:
- [Setting up a custom domain](https://help.github.com/en/articles/using-a-custom-domain-with-github-pages)
- [Setting up SSL](https://help.github.com/en/articles/securing-your-github-pages-site-with-https)
Learn more about [GitHub Pages on its website](https://pages.github.com/)
## Advanced
All of these options, while using providers with more service offerings,
demonstrate how to host the viewer with their respective file storage and CDN
offerings. While you can serve your static assets this way, if you're going
through the trouble of using AWS/GCP/Azure, it's more likely you're doing so to
avoid using a proxy or to simplify authentication.
If that is the case, check out some of our more advanced `docker` deployments
that target these providers from the left-hand sidepanel.
These guides can be a bit longer and a update more frequently. To provide
accurate documentation, we will link to each provider's own recommended steps:
### AWS S3 + Cloudfront
- [Host a Static Website](https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html)
- [Speed Up Your Website with Cloudfront](https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-cloudfront-walkthrough.html)
### GCP + Cloudflare
- [Things to Know Before Getting Started](https://code.luasoftware.com/tutorials/google-cloud-storage/things-to-know-before-hosting-static-website-on-google-cloud-storage/)
- [Hosting a Static Website on GCP](https://cloud.google.com/storage/docs/hosting-static-website)
### Azure
- [Host a Static Website](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-static-website)
- [Add SSL Support](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-https-custom-domain-cdn)
- [Configure a Custom Domain](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-custom-domain-name)
@@ -1,289 +0,0 @@
# User Account Control
> DISCLAIMER! We make no claims or guarantees of this approach's security. If in
> doubt, enlist the help of an expert and conduct proper audits.
Making a viewer and its medical imaging data accessible on the open web can
provide a lot of benefits, but requires additional security to make sure
sensitive information can only be viewed by authorized individuals. Most image
archives are equipped with basic security measures, but they are not
robust/secure enough for the open web.
This guide covers one of many potential production setups that secure our
sensitive data.
## Overview
This guide builds on top of our
[Nginx + Image Archive guide](/deployment/recipes/nginx--image-archive.md),
wherein we used a [`reverse proxy`](https://en.wikipedia.org/wiki/Reverse_proxy)
to retrieve resources from our image archive (Orthanc).
To add support for "User Account Control" we introduce
[Keycloak](https://www.keycloak.org/about.html). Keycloak is an open source
Identity and Access Management solution that makes it easy to secure
applications and services with little to no code. We improve upon our
`reverse proxy` setup by integrating Keycloak and Nginx to create an
`authenticating reverse proxy`.
> An authenticating reverse proxy is a reverse proxy that only retrieves the
> resources on behalf of a client if the client has been authenticated. If a
> client is not authenticated they can be redirected to a login page.
This setup allows us to create a setup similar to the one pictured below:
{% include "./../_user-account-control-flow-diagram.md" %}
- All web requests are routed through `nginx` on our `OpenResty` image
- `/pacs` is a reverse proxy for `orthanc`'s `DICOM Web` endpoints
- Requires valid `Authorization: Bearer <token>` header
- `/pacs-admin` is a reverse proxy for `orthanc`'s Web Admin
- `/auth` is a reverse proxy for `keycloak`
- All static resources for OHIF Viewer are unprotected and accessible. We have
application logic that will redirect unauthenticated users to the appropriate
`keycloak` login screen.
## Getting Started
### Requirements
- Docker
- [Docker for Mac](https://docs.docker.com/docker-for-mac/)
- [Docker for Windows](https://docs.docker.com/docker-for-windows/)
_Not sure if you have `docker` installed already? Try running `docker --version`
in command prompt or terminal_
### Setup
_Spin Things Up_
- Navigate to `<project-root>/docker/OpenResty-Orthanc-Keycloak` in your shell
- Run `docker-compose up`
_Create Your First User_
- Navigate to: `http://127.0.0.1/auth/admin`
- Sign in with: `admin`/`password`
- From the top left dropdown, select the `Ohif` realm
- From the left sidebar, under `Manage`, select `Users`
- Click `Add User`
- Username: `test`
- Email Verified: `ON`
- Click `Save`
- Click the `Credentials` Tab
- New Pasword: `test`
- Password Confirmation: `test`
- Temporary: `OFF`
- Click: `Reset Password`
- From the top right dropdown, select `Admin`, then `Sign Out`
_Sign In_
- Navigate to `http://127.0.0.1/`
- Username: `test`, Password: `test`
- Click `Log In`
_Upload Your First Study_
- Navigate to `http://127.0.0.1/pacs-admin`
- If you're not already logged in, use `test`/`test`
- From the top right, select "Upload"
- Click "Select files to upload..." (DICOM)
- Click "Start the upload"
- Navigate back to `http://127.0.0.1/` to view your studies in the Study List
### Troubleshooting
_Exit code 137_
This means Docker ran out of memory. Open Docker Desktop, go to the `advanced`
tab, and increase the amount of Memory available.
_Cannot create container for service X_
Use this one with caution: `docker system prune`
_X is already running_
Stop running all containers:
- Win: `docker ps -a -q | ForEach { docker stop $_ }`
- Linux: `docker stop $(docker ps -a -q)`
### Configuration
After verifying that everything runs with default configuration values, you will
likely want to update:
- The domain: `http://127.0.0.1`
- Set secure, non-default passwords
- Regenerate Keycloak Client Secrets
#### OHIF Viewer
The OHIF Viewer's configuration is imported from a static `.js` file and made
available globally at `window.config`. The configuration we use is set to a
specific file when we build the viewer, and determined by the env variable:
`REACT_APP_CONFIG`. You can see where we set its value in the `dockerfile` for
this solution:
`ENV REACT_APP_CONFIG=config/docker_openresty-orthanc-keycloak.js`
You can find the configuration we're using here:
`/public/config/docker_openresty-orthanc-keycloak.js`
To rebuild the `webapp` image created by our `dockerfile` after updating the
Viewer's configuration, you can run:
- `docker-compose build` OR
- `docker-compose up --build`
#### Other
All other files are found in: `/docker/OpenResty-Orthanc-Keycloak/`
| Service | Configuration | Docs |
| ----------------- | ------------------------------------------------ | ------------------------------------------- |
| OHIF Viewer | [dockerfile][dockerfile] / [config.js][config] | You're reading them now! |
| OpenResty (Nginx) | [`/nginx.conf`][config-nginx] | [lua-resty-openidc][lua-resty-openidc-docs] |
| Orthanc | [`/orthanc.json`][config-orthanc] | [Here][orthanc-docs] |
| Keycloak | [`/ohif-keycloak-realm.json`][config-keycloak]\* | |
- \* These are the seed values for Keycloak. They can be manually updated at
`http://127.0.0.1/auth/admin`
#### Keycloak Themeing
The `Login` screen for the `ohif-viewer` client is using a Custom Keycloak
theme. You can find the source files for it in
`/docker/OpenResty-Orthanc-Keycloak/volumes/keycloak-themes/`. You can see how
we add it to Keycloak in the `docker-compose` file, and you can read up on how
to leverage custom themes in
[Keycloak's own docs](https://www.keycloak.org/docs/latest/server_development/index.html#_themes).
| Default Theme | OHIF Theme |
| ---------------------------------------------------------------------- | ---------------------------------------------------------------- |
| ![Keycloak Default Theme](../../assets/img/keycloak-default-theme.png) | ![Keycloak OHIF Theme](../../assets/img/keycloak-ohif-theme.png) |
## Next Steps
### Deploying to Production
While these configuration and docker-compose files model an environment suitable
for production, they are not easy to deploy "as is". You can either:
- Manually recreate this environment and deploy built application files **OR**
- Deploy to a cloud kubernetes provider like
[Digital Ocean](https://www.digitalocean.com/products/kubernetes/) **OR**
- [See a full list of cloud providers here](https://landscape.cncf.io/category=cloud&format=card-mode&grouping=category)
- Find and follow your preferred provider's guide on setting up
[swarms and stacks](https://docs.docker.com/get-started/)
### Adding SSL
Adding SSL registration and renewal for your domain with Let's Encrypt that
terminates at Nginx is an incredibly important step toward securing your data.
Here are some resources, specific to this setup, that may be helpful:
- [lua-resty-auto-ssl](https://github.com/GUI/lua-resty-auto-ssl)
- [Let's Encrypt + Nginx](https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/)
While we terminate SSL at Nginx, it may be worth using self signed certificates
for communication between services.
- [SSL Termination for TCP Upstream Servers](https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-tcp/)
### Use PostgresSQL w/ Orthanc
Orthanc can handle a large amount of data and requests, but if you find that
requests start to slow as you add more and more studies, you may want to
configure your Orthanc instance to use PostgresSQL. Instructions on how to do
that can be found in the
[`Orthanc Server Book`](http://book.orthanc-server.com/users/docker.html), under
"PostgreSQL and Orthanc inside Docker"
### Improving This Guide
Here are some improvements this guide would benefit from, and that we would be
more than happy to accept Pull Requests for:
- SSL Support
- Complete configuration with `.env` file (or something similar)
- Keycloak Theme improvements
- Any security issues
- One-click deploy to a cloud provider
## Resources
### Misc. Helpful Commands
_Check if `nginx.conf` is valid:_
```bash
docker run --rm -t -a stdout --name my-openresty -v $PWD/config/:/usr/local/openresty/nginx/conf/:ro openresty/openresty:alpine-fat openresty -c /usr/local/openresty/nginx/conf/nginx.conf -t
```
_Interact w/ running container:_
`docker exec -it CONTAINER_NAME bash`
_List running containers:_
`docker ps`
_Clear Keycloak DB so you can re-seed values:_
- `docker volume prune` OR
- `docker volume ls` and `docker volume rm VOLUME_NAME VOLUME_NAME`
### Referenced Articles
The inspiration for our setup was driven largely by these articles:
- [Securing Nginx with Keycloak](https://edhull.co.uk/blog/2018-06-06/keycloak-nginx)
- [Authenticating Reverse Proxy with Keycloak](https://eclipsesource.com/blogs/2018/01/11/authenticating-reverse-proxy-with-keycloak/)
- [Securing APIs with Kong and Keycloak](https://www.jerney.io/secure-apis-kong-keycloak-1/)
For more documentation on the software we've chosen to use, you may find the
following resources helpful:
- [Orthanc for Docker](http://book.orthanc-server.com/users/docker.html)
- [OpenResty Guide](http://www.staticshin.com/programming/definitely-an-open-resty-guide/)
- [Lua Ngx API](https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/)
- [Auth0: Picking a Grant Type](https://auth0.com/docs/api-auth/which-oauth-flow-to-use)
We chose to use a generic OpenID Connect library on the client, but it's worth
noting that Keycloak comes packaged with its own:
- [redux-oidc](https://github.com/maxmantz/redux-oidc) (Which wraps
[oidc-client-js](https://github.com/IdentityModel/oidc-client-js/wiki))
- [Keycloak JavaScript Adapter](https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter)
If you're not already drowning in links, here are some good security resources
for OAuth:
- [Diagrams of OpenID Connect Flows](https://medium.com/@darutk/diagrams-of-all-the-openid-connect-flows-6968e3990660)
- [KeyCloak: OpenID Connect Flows](https://www.keycloak.org/docs/latest/securing_apps/index.html#authorization-code)
- [Good description on SSO Protocols](https://www.keycloak.org/docs/2.5/server_admin/topics/sso-protocols/oidc.html)
For a different take on this setup, check out the repository one of our
community members put together:
- [mjstealey/ohif-orthanc-dimse-docker](https://github.com/mjstealey/ohif-orthanc-dimse-docker)
<!--
Links
-->
<!-- prettier-ignore-start -->
<!-- DOCS -->
[orthanc-docs]: http://book.orthanc-server.com/users/configuration.html#configuration
[lua-resty-openidc-docs]: https://github.com/zmartzone/lua-resty-openidc
<!-- SRC -->
[config]: #
[dockerfile]: #
[config-nginx]: #
[config-orthanc]: #
[config-keycloak]: #
<!-- prettier-ignore-end -->
-57
View File
@@ -1,57 +0,0 @@
# Configuration
> This step assumes you have an imaging archive. If you need assistance setting
> one up, check out the [`Data Source` Guide](./data-source.md) or a deployment
> recipe that contains an open source Image Archive
## How it Works
The configuration for our project is in the `/public/config` directory. Our
build process knows which configuration file to use based on the
`REACT_APP_CONFIG` environment variable. By default, its value is
[`default.js`](https://github.com/OHIF/Viewers/blob/react/public/config/default.js).
When we build, the `%REACT_APP_CONFIG%` value in
our[`/public/index.html`](https://github.com/OHIF/Viewers/blob/react/public/index.html#L12-L15)
file is substituted for the correct configuration file's name. This sets the
`window.config` equal to our configuration file's value.
## How do I configure my project?
The simplest way is to update the existing default config:
_/public/config/default.js_
```js
window.config = {
routerBasename: '/',
relativeWebWorkerScriptsPath: '',
servers: {
dicomWeb: [
{
name: 'DCM4CHEE',
wadoUriRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado',
qidoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
wadoRoot: 'https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/rs',
qidoSupportsIncludeField: true,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
requestOptions: {
requestFromBrowser: true,
},
},
],
},
}
```
You can also create a new config file and specify its path relative to the build
output's root by setting the `REACT_APP_CONFIG` environment variable. You can
set the value of this environment variable a few different ways:
- [Add a temporary environment variable in your shell](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-temporary-environment-variables-in-your-shell)
- [Add environment specific variables in `.env` file(s)](https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#adding-development-environment-variables-in-env)
- Using the `cross-env` package in an npm script:
- `"build": "cross-env REACT_APP_CONFIG=config/my-config.js react-scripts build"`
After updating the configuration, `yarn run build:web` to generate updated build
output.
-161
View File
@@ -1,161 +0,0 @@
# Data Source
After following the steps outlined in [Getting Started](./getting-started.md),
you'll notice that the OHIF Viewer has data for several studies and their
images. You didn't add this data, so where is it coming from?
By default, the viewer is configured to connect to a remote server hosted by the
nice folks over at [dcmjs.org][dcmjs-org]. While convenient for getting started,
the time may come when you want to develop using your own data either locally or
remotely.
## Set up a local DICOM server
> ATTENTION! Already have a remote or local server? Skip to the
> [configuration section](#configuration-learn-more) below.
While the OHIF Viewer can work with any data source, the easiest to configure
are the ones that follow the [DICOMWeb][dicom-web] spec.
1. Choose and install an Image Archive
2. Upload data to your archive (e.g. with DCMTK's [storescu][storescu] or your
archive's web interface)
3. Keep the server running
For our purposes, we will be using `Orthanc`, but you can see a list of
[other Open Source options](#open-source-dicom-image-archives) below.
### Requirements
- Docker
- [Docker for Mac](https://docs.docker.com/docker-for-mac/)
- [Docker for Windows (recommended)](https://docs.docker.com/docker-for-windows/)
- [Docker Toolbox for Windows](https://docs.docker.com/toolbox/toolbox_install_windows/)
_Not sure if you have `docker` installed already? Try running `docker --version`
in command prompt or terminal_
> If you are using `Docker Toolbox` you need to change the _proxy_ parameter in
> _package.json_ to http://192.168.99.100:8042 or the ip docker-machine ip
> throws. This is the value [`react-scripts`][react-proxy] uses to proxy
> requests
### Running Orthanc
_Start Orthanc:_
```bash
# Runs orthanc so long as window remains open
yarn run orthanc:up
```
_Upload your first Study:_
1. Navigate to [Orthanc's web interface](http://localhost:8899) at
`http://localhost:8899` in a web browser.
2. In the top right corner, click "Upload"
3. Click "Select files to upload..." and select one or more DICOM files
4. Click "Start the upload"
#### Orthanc: Learn More
You can see the `docker-compose.yml` file this command runs at
[`<project-root>/docker/Nginx-Docker/`](#), and more on Orthanc for Docker in
[Orthanc's documentation][orthanc-docker].
### Connecting to Orthanc
Now that we have a local Orthanc instance up and running, we need to configure
our web application to connect to it. Open a new terminal window, navigate to
this project's root directory, and run:
```bash
# If you haven't already, restore dependencies
yarn install
# Run our dev command, but with the local orthanc config
yarn run dev:orthanc
```
#### Configuration: Learn More
> For more configuration fun, check out the
> [Essentials Configuration](./configuration.md) guide.
Let's take a look at what's going on under the hood here. `yarn run dev:orthanc`
is running the `dev:orthanc` script in our project's `package.json`. That script
is:
```js
cross-env PORT=5000 REACT_APP_CONFIG=config/docker_nginx-orthanc.js react-scripts start
```
- `cross-env` sets two environment variables
- PORT: 5000
- REACT_APP_CONFIG: `config/docker_nginx-orthanc.js`
- `react-scripts` runs it's `start` script. This is [the de-facto
way][cra-start] to run a "Create React App" in development mode.
The `REACT_APP_CONFIG` value tells our app which file to load on to
`window.config`. By default, our app uses the file at
`<project-root>/public/config/default.js`. Here is what that configuration looks
like:
```js
window.config = {
routerBasename: '/',
relativeWebWorkerScriptsPath: '',
servers: {
dicomWeb: [
{
name: 'Orthanc',
wadoUriRoot: 'http://localhost:8899/wado',
qidoRoot: 'http://localhost:8899/dicom-web',
wadoRoot: 'http://localhost:8899/dicom-web',
qidoSupportsIncludeField: false,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
},
],
},
};
```
To learn more about how you can configure the OHIF Viewer, check out our
[Configuration Guide](./configuration.md).
## Open Source DICOM Image Archives
Our example uses `Orthanc`, but there are a lot of options available to you.
Here are some of the more popular ones:
| Archive | Installation |
| --------------------------------------------- | ---------------------------------- |
| [DCM4CHEE Archive 5.x][dcm4chee] | [W/ Docker][dcm4chee-docker] |
| [Orthanc][orthanc] | [W/ Docker][orthanc-docker] |
| [DICOMcloud][dicomcloud] (**DICOM Web only**) | [Installation][dicomcloud-install] |
| [OsiriX][osirix] (**Mac OSX only**) | Desktop Client |
| [Horos][horos] (**Mac OSX only**) | Desktop Client |
_Feel free to make a Pull Request if you want to add to this list._
<!--
Links
-->
<!-- prettier-ignore-start -->
[dcmjs-org]: https://server.dcmjs.org/dcm4chee-arc/aets/DCM4CHEE/wado
[dicom-web]: https://en.wikipedia.org/wiki/DICOMweb
[storescu]: http://support.dcmtk.org/docs/storescu.html
[cra-start]: https://github.com/facebook/create-react-app#npm-start-or-yarn-start
[react-proxy]: https://facebook.github.io/create-react-app/docs/proxying-api-requests-in-development#configuring-the-proxy-manually
<!-- Archives -->
[dcm4chee]: https://github.com/dcm4che/dcm4chee-arc-light
[dcm4chee-docker]: https://github.com/dcm4che/dcm4chee-arc-light/wiki/Running-on-Docker
[orthanc]: https://www.orthanc-server.com/
[orthanc-docker]: http://book.orthanc-server.com/users/docker.html
[dicomcloud]: https://github.com/DICOMcloud/DICOMcloud
[dicomcloud-install]: https://github.com/DICOMcloud/DICOMcloud#running-the-code
[osirix]: http://www.osirix-viewer.com/
[horos]: https://www.horosproject.org/
<!-- prettier-ignore-end -->
-115
View File
@@ -1,115 +0,0 @@
# Getting Started
## Setup
### Fork & Clone
If you intend to contribute back changes, or if you would like to pull updates
we make to the OHIF Viewer, then follow these steps:
- [Fork][fork-a-repo] the [OHIF/Viewers][ohif-viewers-repo] repository
- [Create a local clone][clone-a-repo] of your fork
- `git clone https://github.com/YOUR-USERNAME/Viewers`
- Add OHIF/Viewers as a [remote repository][add-remote-repo] labled `upstream`
- Navigate to the cloned project's directory
- `git remote add upstream https://github.com/OHIF/Viewers.git`
With this setup, you can now [sync your fork][sync-changes] to keep it
up-to-date with the upstream (original) repository. This is called a "Triangular
Workflow" and is common for Open Source projects. The GitHub blog has a [good
graphic that illustrates this setup][triangular-workflow].
### Private
Alternatively, if you intend to use the OHIF Viewer as a starting point, and you
aren't as concerned with syncing updates, then follow these steps:
1. Navigate to the [OHIF/Viewers/tree/react][ohif-viewers-react-repo] repository
and branch
2. Click `Clone or download`, and then `Download ZIP`
3. Use the contents of the `.zip` file as a starting point for your viewer
> NOTE: It is still possible to sync changes using this approach. However,
> submitting pull requests for fixes and features are best done with the
> separate, forked repository setup described in "Fork & Clone"
## Developing
### Requirements
- [Node.js & NPM](https://nodejs.org/en/)
- [Yarn](https://yarnpkg.com/en/)
### Kick the tires
Navigate to the root of the project's directory in your terminal and run the
following commands:
```bash
# Restore dependencies
yarn install
# Start local development server
yarn start
```
You should see the following output:
```bash
Compiled successfully!
You can now view ohif-viewer in the browser.
Local: http://localhost:5000/
On Your Network: http://10.74.20.83:5000/
Note that the development build is not optimized.
To create a production build, use yarn build.
```
### 🎉 Celebrate 🎉
<center>
<img alt="development server hosted app" src="/assets/img/loading-study.gif" />
<i>Our app, hosted by the development server</i>
</center>
### Building for Production
> More comprehensive guides for building and publishing can be found in our
> [deployment docs](./../deployment/index.md)
```bash
# Build static assets to host a PWA
yarn run build:web
# Build packaged output
yarn run build:package
```
## Next Steps
...
## Troubleshooting
- If you receive a _"No Studies Found"_ message and do not see your studies, try
changing the Study Date filters to a wider range.
- If you see a 'Loading' message which never resolves, check your browser
JavaScript console inside the Developer Tools to identify any errors.
- If you see any errors in your server console, check the
[Troubleshooting](./troubleshooting.md) page for more in depth advice.
<!--
Links
-->
<!-- prettier-ignore-start -->
[fork-a-repo]: https://help.github.com/en/articles/fork-a-repo
[clone-a-repo]: https://help.github.com/en/articles/fork-a-repo#step-2-create-a-local-clone-of-your-fork
[add-remote-repo]: https://help.github.com/en/articles/fork-a-repo#step-3-configure-git-to-sync-your-fork-with-the-original-spoon-knife-repository
[sync-changes]: https://help.github.com/en/articles/syncing-a-fork
[triangular-workflow]: https://github.blog/2015-07-29-git-2-5-including-multiple-worktrees-and-triangular-workflows/#improved-support-for-triangular-workflows
[ohif-viewers-repo]: https://github.com/OHIF/Viewers
[ohif-viewers-react-repo]: https://github.com/OHIF/Viewers/tree/react
<!-- prettier-ignore-end -->
-42
View File
@@ -1,42 +0,0 @@
# Installation
It's important to know that the OHIF Viewer project provides two different build
processes:
```bash
# Static Asset output: For deploying PWAs
yarn run build:web
# Single `.js` script, for embedding viewer into existing apps
yarn run build:package
```
## create-react-app (PWA)
> [create-react-app](https://github.com/facebook/create-react-app) provides
> pre-configured build process for developing front-end applications with
> [React](https://reactjs.org/).
The ohif-viewer package can be run as a create-react-app application. This is
useful for development, debugging, or evolving the OHIF Viewer into your own
custom imaging application.
You can read more about this particular strategy in our
[Build for Production Deployment Guide](./../deployment/recipes/build-for-production.md)
## Rollup (Packaged Script)
> [Rollup](https://rollupjs.org/guide/en) is a module bundler for JavaScript. It
> uses the new standardized format for code modules included in the ES6 revision
> of JavaScript.
The [ohif-viewer](https://www.npmjs.com/package/ohif-viewer) package can be
built with Rollup to provide a set of React components which can be dropped into
a larger application. Specifically, the ohif-viewer package provides a React
component named `OHIFViewer` which is the entire viewer, configurable via React
`props`. This is useful for including the OHIF Viewer in a larger web
application, as the entire application can be provided via a `<script>` tag with
no build process required.
You can read more about this particular strategy in our
[Embedded Viewer Deployment Guide](./../deployment/recipes/embedded-viewer.md)
@@ -1,66 +0,0 @@
# Scope of Project
The OHIF Viewer is a web based medical imaging viewer. This allows it to be used
on almost any device, anywhere. The OHIF Viewer is what is commonly reffered to
as a ["Dumb Client"][simplicable]
> A dumb client is software that fully depends on a connection to a server or
> cloud service for its functionality. Without a network connection, the
> software offers nothing useful. - [simplicable.com][simplicable]
While the Viewer persists some data, it's scope is limited to caching things
like user preferences and previous query paramaters. Because of this, the Viewer
has been built to be highly configurable to work with almost any web accessible
data source.
![scope-of-project diagram](./../assets/img/scope-of-project.png)
To be more specific, the OHIF Viewer is a collection of HTML, JS, and CSS files.
These can be delivered to your end users however you would like:
- From the local networok
- From a remote web server
- From a CDN (content delivery network)
- From a service-worker's cache
- etc.
These "static asset" files are referred to collectively as a "Progressive Web
Application" (PWA), and have the same capabilities and limitations that all PWAs
have.
All studies, series, images, imageframes, metadata, and the images themselves
must come from an external source. There are many, many ways to provide this
information, the OHIF Viewer's scope **DOES NOT** encompass providing _any_
data; only the configuration necessary to interface with one or more of these
many data sources. The OHIF Viewer's scope **DOES** include configuration and
support for services that are protected with OpenID-Connect.
In an effort to aide our users and contributors, we attempt to provide several
[deployment and hosting recipes](./../deployment/index.md) as potential starting
points. These are not meant to be rock solid, production ready, solutions; like
most recipes, they should be augmented to best fit you and your organization's
taste, preferences, etc.
## FAQ
_Am I able to cache studies for offline viewing?_
Not currently. A web page's offline cache capabilities are limited and somewhat
volatile (mostly imposed at the browser vendor level). For more robust offline
caching, you may want to consider a server on the local network, or packaging
the OHIF Viewer as a desktop application.
_Does the OHIF Viewer work with the local filesystem?_
It is possible to accomplish this through extensions; however, for an user
experience that accomodates a large number of studies, you would likely need to
package the OHIF Viewer as an [Electron app][electron].
<!--
Links
-->
<!-- prettier-ignore-start -->
[simplicable]: https://simplicable.com/new/dumb-client
[electron]: https://electronjs.org/
<!-- prettier-ignore-end -->
-97
View File
@@ -1,97 +0,0 @@
# Themeing
Themeing is currently accomplished with color variables that are defined within
the [`:root`](https://css-tricks.com/almanac/selectors/r/root/) selector
(allowing them to cascade across all elements). This repository's components,
and the ones we consume from our
[React Viewerbase component library](https://react.ohif.org/styling-and-theming)
utilize them. We are interested in pursuing more robust themeing options, and
open to pull requests and discussion issues.
```css
:root {
/* Interface UI Colors */
--default-color: #9ccef9;
--hover-color: #ffffff;
--active-color: #20a5d6;
--ui-border-color: #44626f;
--ui-border-color-dark: #3c5d80;
--ui-border-color-active: #00a4d9;
--primary-background-color: #000000;
--box-background-color: #3e5975;
--text-primary-color: #ffffff;
--text-secondary-color: #91b9cd;
--input-background-color: #2c363f;
--input-placeholder-color: #d3d3d3;
--table-hover-color: #2c363f;
--table-text-primary-color: #ffffff;
--table-text-secondary-color: #91b9cd;
--large-numbers-color: #6fbde2;
--state-error: #ffcccc;
--state-error-border: #ffcccc;
--state-error-text: #ffcccc;
/* Common palette */
--ui-yellow: #e29e4a;
--ui-sky-blue: #6fbde2;
/* State palette */
--ui-state-error: #ffcccc;
--ui-state-error-border: #993333;
--ui-state-error-text: #661111;
--ui-gray-lighter: #436270;
--ui-gray-light: #516873;
--ui-gray: #263340;
--ui-gray-dark: #16202b;
--ui-gray-darker: #151a1f;
--ui-gray-darkest: #14202a;
--calendar-day-color: #d3d3d3;
--calendar-day-border-color: #d3d3d3;
--calendar-day-active-hover-background-color: #516873;
--calendar-main-color: #263340;
--viewport-border-thickness: 1px;
}
```
## White Labeling
> A white-label product is a product or service produced by one company (the
> producer) that other companies (the marketers) rebrand to make it appear as if
> they had made it - [Wikipedia: White-Label Product][wikipedia]
Current white-labeling options are limited. We expose the ability to replace the
"Logo" section of the application with a custom "Logo" component. You can do
this by adding a `whiteLabelling` key to your
[configuration file](./configuration.md).
```js
function RadicalImagingLogo() {
return React.createElement(
'a',
{
target: '_blank',
rel: 'noopener noreferrer',
className: 'header-brand',
href: 'http://radicalimaging.com',
},
React.createElement('h5', {}, 'RADICAL IMAGING')
)
}
props.whiteLabelling = {
logoComponent: RadicalImagingLogo(),
}
```
<!--
Links
-->
<!-- prettier-ignore-start -->
[wikipedia]: https://en.wikipedia.org/wiki/White-label_product
<!-- prettier-ignore-end -->
-317
View File
@@ -1,317 +0,0 @@
# Translating
OHIF supports internationalization using [i18next](https://www.i18next.com/)
through the npm package [@ohif/i18n](https://www.npmjs.com/package/@ohif/i18n),
where is the main instance of i18n containing several languages and tools.
<div class='row'>
<div class='column'>
<p>Our translation management is powered by <a href="https://locize.com/" target="_blank" rel="noopener noreferrer">Locize</a> through their generous support of open source.</p>
</div>
<div class='column'>
<a href="https://locize.com/" target="_blank" rel="noopener noreferrer" style='padding: 20px'>
<img src="../assets/img/locizeSponsor.svg" alt="Locize Translation Management Logo">
</a>
</div>
</div>
### Installing
```bash
yarn add @ohif/i18n
# OR
npm install --save @ohif/i18n
```
### How it works
After installing `@ohif/i18n` npm package, the translation function
[t](https://www.i18next.com/overview/api#t) can be used [with](#with-react) or
[without](#without-react) React.
A translation will occur every time a text match happens in a
[t](https://www.i18next.com/overview/api#t) function.
The [t](https://www.i18next.com/overview/api#t) function is responsible for
getting translations using all the power of i18next.
E.g.
Before:
```html
<div>my translated text</div>
```
After:
```html
<div>{t('my translated text')}</div>
```
If the translation.json file contains a key that matches the HTML content e.g.
`my translated text`, it will be replaced automatically by the
[t](https://www.i18next.com/overview/api#t) function.
---
#### With React
This section will introduce you to [react-i18next](https://react.i18next.com/)
basics and show how to implement the [t](https://www.i18next.com/overview/api#t)
function easily.
##### Using HOCs
In most cases we used
[High Order Components](https://react.i18next.com/latest/withtranslation-hoc) to
share the `t` function among OHIF's components.
E.g.
```js
import React from 'react';
import { withTranslation } from '@ohif/i18n';
function MyComponent({ t, i18n }) {
return <p>{t('my translated text')}</p>;
}
export default withTranslation('MyNameSpace')(MyComponent);
```
> Important: if you are using React outside the OHIF Viewer, check the
> [I18nextProvider](#using-outside-of-ohif-viewer) section, `withTranslation`
> HOC doesnt works without a I18nextProvider
##### Using Hooks
Also, it's possible to get the `t` tool using
[React Hooks](https://react.i18next.com/latest/usetranslation-hook), but it
requires at least React > 16.8 😉
#### Using outside of OHIF viewer
OHIF Viewer already sets a main
[I18nextProvider](https://react.i18next.com/latest/i18nextprovider) connected to
the shared i18n instance from `@ohif/i18n`, all extensions inside OHIF Viewer
will share this same provider at the end, you don't need to set new providers at
all.
But, if you need to use it completely outside of OHIF viewer, you can set the
I18nextProvider this way:
```js
import i18n from '@ohif/i18n';
import { I18nextProvider } from 'react-i18next';
import App from './App';
<I18nextProvider i18n={i18n}>
<App />
</I18nextProvider>;
```
After setting `I18nextProvider` in your React App, all translations from
`@ohif/i18n` should be available following the basic [With React](#with-react)
usage.
---
#### Without React
When needed, you can also use available translations _without React_.
E.g.
```js
import { T } from '@ohif/i18n';
console.log(T('my translated text'));
console.log(T('$t(Common:Play) my translated text'));
```
---
# Main Concepts While Translating
## - Namespaces
Namespaces are being used to organize translations in smaller portions, combined
semantically or by use. Each `.json` file inside `@ohif/i18n` npm package
becomes a new namespace automatically.
- Buttons: All buttons translations
- CineDialog: Translations for the toll tips inside the Cine Player Dialog
- Common: all common jargons that can be reused like `t('$t(common:image)')`
- Header: translations related to OHIF's Header Top Bar
- MeasurementTable - Translations for the react-viewerbase Measurement Table
- UserPreferencesModal - Translations for the react-viewerbase Preferences Modal
### How to use another NameSpace inside the current NameSpace?
i18next provides a parsing feature able to get translations strings from any
NameSpace, like this following example getting data from `Common` NameSpace:
```
$t(Common:Reset)
```
## - Extending Languages in @ohif/i18n
Sometimes, even using the same language, some nouns or jargons can change
according to the country, states or even from Hospital to Hospital.
In this cases, you don't need to set an entire language again, you can extend
languages creating a new folder inside a pre existent language folder and
@ohif/i18n will do the hard work.
This new folder must to be called with a double character name, like the `UK` in
the following file tree:
```bash
|-- src
|-- locales
index.js
|-- en
|-- Buttons.json
index.js
| UK
|-- Buttons.js
indes.js
| US
|-- Buttons.js
index.js
...
```
All properties inside a Namespace will be merged in the new sub language, e.g
`en-US` and `en-UK` will merge the props with `en`, using i18next's fallback
languages tool.
You will need to export all Json files in your `index.js` file, mounting an
object like this:
```js
{
en: {
NameSpace: {
keyWord1: 'keyWord1Translation',
keyWord2: 'keyWord2Translation',
keyWord3: 'keyWord3Translation',
}
},
'en-UK': {
NameSpace: {
keyWord1: 'keyWord1DifferentTranslation',
}
}
}
```
Please check the `index.js` files inside locales folder for an example of this
exporting structure.
### - Extending languages dynamically
You have access to the i18next instance, so you can use the
[addResourceBundle](https://www.i18next.com/how-to/add-or-load-translations#add-after-init)
method to add and change language resources as needed.
E.g.
```js
import { i18n } from '@ohif/i18n';
i18next.addResourceBundle('pt-BR', 'Buttons', {
Angle: 'Ângulo',
});
```
---
### How to set a whole new language
To set a brand new language you can do it in two different ways:
- Opening a pull request for `@ohif/i18n` and sharing the translation with the
community. 😍 Please see [Contributing](#contributing-with-new-languages)
section for further information.
- Setting it only in your project or extension:
You'll need a a final object like the following, what is setting French as
language, and send it to `addLocales` method.
```js
const newLanguage =
{
fr: {
Commons: {
"Reset": "Réinitialiser",
"Previous": "Précédent",
},
Buttons: {
"Rectangle": "Rectangle",
"Circle": "Cercle",
}
}
```
To make it easier to translate, you can copy the .json files in the /locales
folder and theirs index.js exporters, keeping same keys and NameSpaces.
Importing the main index.js file, will provide you an Object as expected by the
method `addlocales`;
E.g. of `addLocales` usage
```js
import { addLocales } from '@ohif/i18n';
import locales from './locales/index.js';
addLocales(locales);
```
You can also set them manually, one by one, using this
[method](#extending-languages-dynamically).
---
## Language Detections
@ohif/i18n uses
[i18next-browser-languageDetector](https://github.com/i18next/i18next-browser-languageDetector)
to manage detections, also exports a method called initI18n that accepts a new
detector config as parameter.
### Changing the language
OHIF Viewer accepts a query param called `lng` in the url to change the
language.
E.g.
```
https://docs.ohif.org/demo/?lng=es-MX
```
### Language Persistence
The user's language preference is kept automatically by the detector and stored
at a cookie called 'i18next', and in a localstorage key called 'i18nextLng'.
These names can be changed with a new
[Detector Config](https://github.com/i18next/i18next-browser-languageDetector).
## Debugging translations
There is an environment variable responsible for debugging the translations,
called `REACT_APP_I18N_DEBUG`.
Run the project as following to get full debug information:
```bash
REACT_APP_I18N_DEBUG=true yarn run dev
```
### Contributing with new languages
Contributions of any kind are welcome! Please check the
[instructions](https://docs.ohif.org/contributing.html).
-20
View File
@@ -1,20 +0,0 @@
# Troubleshooting
Common GitHub issues that are not easily remedied with cleaner code or
documentation will be recorded here. Please feel free to make PRs to update this
page.
## Common Problems
| Problem | Most Common Reasons |
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ** Can't retrieve Study List over DICOMWeb** | 1. QIDO root URL is incorrect<br> 2. DICOM Web is not enabled on PACS |
| ** Can't retrieve images** | 1. WADO Root URL is incorrect<br> 2. DICOM Web is not enabled on PACS<br> 3. HTTP Basic Authentication username and password are incorrect or not provided. |
## Debugging Steps
### Can't retrieve Study List over DICOMWeb
1. Check that you can query your PACS using an alternative DICOM Web client
(e.g. cURL, or a Web Browser). If you cannot, then your PACS is configured
incorrectly. Refer to the documentation of the image archive.
-95
View File
@@ -1,95 +0,0 @@
# Frequently Asked Questions
## How do I file a bug?
We accept and triage bug reports through Github primarily.
- [Create a Github account](https://github.com/join)
- Search the current [Issue List](https://github.com/OHIF/Viewers/issues) to
ensure you are not creating a duplicate issue.
- If your issue already exists, post a comment to show us that this issue also
affects you.
- If no prior issue exists,
[Create a New Issue](https://github.com/OHIF/Viewers/issues/new) on the
repository.
Some tips for filing a new issue:
- **Make sure your issue is reproducible**: If we try to reproduce your issue
given your provided steps and we cannot reproduce it, we will not be able to
fix it. _Nobody wants to spend time guessing how to reproduce your issue!_
Before filing, please reproduce your issue more than once and clearly describe
the steps taken.
- **If you are reporting a user interface issue, provide screenshots**: A
picture is worth a thousand words. If your issue concerns the UI, screenshots
will help us identify the issue dramatically faster since it can be extremely
challenging to describe UI bugs with text. _You should still clearly describe
the steps that you took to produce the issue_.
- **Include platform & environment**: Your operating system, web browser, and
web browser version are highly relevant for many bugs. Please provide these
with all bug reports.
- **Include expected and actual result**: Tell us what you expected to happen,
and what actually happened. If you don't do this, we might not consider it a
bug.
### How can I request a new feature?
At the moment we are in the process of defining our roadmap and will do our best
to communicate this to the community. If your requested feature is on the
roadmap, then it will most likely be built at some point. If it is not, you are
welcome to build it yourself and [contribute it](../contributing.md). If you
have resources and would like to fund the development of a feature, please
[contact us](http://www.ohif.org).
### Who should I contact about Academic Collaborations?
[Gordon J. Harris](http://www.dfhcc.harvard.edu/insider/member-detail/member/gordon-j-harris-phd/)
at Massachusetts General Hospital is the primary contact for any academic
collaborators. We are always happy to hear about new groups interested in using
the OHIF framework, and may be able to provide development support if the
proposed collaboration has an impact on cancer research.
### Do you offer commercial support?
The Open Health Imaging Foundation does not offer commercial support, however,
some community members do offer consulting services. The following contacts may
be useful:
- Rob Lewis ([Radical Imaging](http://radicalimaging.com/))
**Please file a Pull Request if you wish to add your name or organization to
this list.**
### I emailed my question to you directly and you did not respond. Why not?
Emailing developers directly is not a shortcut to faster support. Please file
your issues and questions on Github so that everyone can benefit from the
discussion and solutions.
### Do your Viewers have [510(k) Clearance][501k-clearance] from the U.S. F.D.A or [CE Marking][ce-marking] from the European Commission?
**NO.** The OHIF Viewer, Lesion Tracker, and Standalone Viewer, **NOT** F.D.A.
cleared or CE Marked. It is the users responsibility to ensure compliance with
applicable rules and regulations. The
[License](https://github.com/OHIF/Viewers/blob/master/LICENSE) for the OHIF
Framework does not prevent your company or group from seeking F.D.A. clearance
for a product built using the framework.
If you have gone this route (or are going there), please let us know because we
would be interested to hear about your experience.
### Are your Viewers [HIPAA][hipaa] Compliant?
**NO.** The OHIF Viewer, Lesion Tracker, and Standalone Viewer **DO NOT**
fulfill all of the criteria to become HIPAA Compliant. It is the users
responsibility to ensure compliance with applicable rules and regulations.
<!--
Links
-->
<!-- prettier-ignore-start -->
[501k-clearance]: https://www.fda.gov/MedicalDevices/DeviceRegulationandGuidance/HowtoMarketYourDevice/PremarketSubmissions/PremarketNotification510k/
[ce-marking]: https://ec.europa.eu/growth/single-market/ce-marking_en
[hipaa]: https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act
<!-- prettier-ignore-end -->
-39
View File
@@ -1,39 +0,0 @@
# Help
We all need a little help sometimes. Don't let a few roadblocks stand in the way
of you building something awesome.
## Free
If you're a developer looking to contribute code, documentation, or discussion;
we are more than happy to help provide clarification and answer questions via
[GitHub issues][gh-issues] or our [community forum][google-group]. Regular
contributors may also be invited to join our Slack Group to streamline
discussion.
For bug reports and feature requests (including incomplete or confusing
documentation), [GitHub issues][gh-issues] continue to be your best avenue of
communication.
Complex issues specific to your organization/situation are still okay to post,
but they're less likely to receive a response. Unfortunately, we have limited
resources and must be judicious with how we allocate them. If you find yourself
in this situation and in need of assistance, it may be in your best interest to
persue paid support.
## Paid / Commercial
The Open Health Imaging Foundation does not offer commercial support, however,
some community members do offer consulting services:
- Rob Lewis ([Radical Imaging](http://radicalimaging.com/))
**Please file a Pull Request if you wish to add your name or organization to
this list.**
<!--
Links
-->
[gh-issues]: https://github.com/OHIF/Viewers/issues/
[google-group]: https://groups.google.com/forum/#!forum/cornerstone-platform
-44
View File
@@ -1,44 +0,0 @@
{
"name": "ohif-viewer-latest-docs",
"version": "2.0.0",
"description": "Open Health Imaging Foundation Viewers Metarepo for documentation",
"main": ".eslintrc.js",
"directories": {
"doc": "docs"
},
"scripts": {
"docs": "gitbook install && gitbook serve"
},
"repository": {
"type": "git",
"url": "git+https://github.com/OHIF/Viewers.git"
},
"keywords": [
"dicom",
"cornerstone",
"OHIF",
"zero",
"footprint",
"medical",
"imaging",
"viewer"
],
"author": "Open Health Imaging Foundation",
"license": "MIT",
"bugs": {
"url": "https://github.com/OHIF/Viewers/issues"
},
"homepage": "https://github.com/OHIF/Viewers#readme",
"dependencies": {
"gitbook-plugin-anchors": "^0.7.1",
"gitbook-plugin-edit-link": "^2.0.2",
"gitbook-plugin-ga": "^2.0.0",
"gitbook-plugin-github": "^3.0.0",
"gitbook-plugin-sitemap": "^1.2.0",
"gitbook-plugin-theme-cornerstone": "^1.1.4",
"gitbook-plugin-versions": "^2.1.4"
},
"devDependencies": {
"gitbook-cli": "^2.3.2"
}
}
-15
View File
@@ -1,15 +0,0 @@
# Measurements Package (ohif-measurements)
## Package design
## Usage
## How to define a Measurement tool
## How to validate Measurements
## Data exchange concepts
## Longitudinal Measurements
## Timepoints
-25
View File
@@ -1,25 +0,0 @@
# Roadmap
If you want to know what's planned for the very near future,
[check out our roadmap](https://ohif.canny.io/). The best way to influence when
and what is worked on is to contribute to the conversation by creating GitHub
issues, and contributing code through pull requests. OHIF's high level
priorities for the near future are:
- Feature parity with version 1
- Extension and configuration improvements with key integration partners
- Continued Developer Experience Improvements
- Segmentation Tools, and improved VTK.js support
More granular information will make it's way to the backlog as these items
become scoped for development by core maintainers.
> Don't hesitate to ask questions, propose features, or create pull requests.
> We're here, we're listening, and we're ready to build the best open source
> medical imaging viewer on the web.
### Roadmap Generously Powered by Canny.io
<a href="https://ohif.canny.io/">
<img height="30" src="assets/img/canny-full.png" />
</a>
File diff suppressed because it is too large. Load diff