diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..b1b3020
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# R wants HTML files to have UNIX line endings ie. just \n or LF
+*.html text eol=lf
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 510e150..809c3fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -144,11 +144,22 @@ vignettes/*.pdf
rsconnect/
/dags/r_scripts/credentials.json
-/dags/galileo/*.csv
+*.csv
/data
/.idea/
airflow.cfg
*.avro
/shiny/observatory/htpasswd
-/tools/warcraider/*.warc
-/shiny/observatory/*.csv
+htpasswd
+.htpasswd
+*.warc
+*.csv
+*.rdata
+*.xls
+*.xlsx
+*.gexf
+*.graphml
+Staticfile.auth
+*.iml
+*.ipr
+*.iws
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..17e15f2
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,15 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Python: Current File",
+ "type": "python",
+ "request": "launch",
+ "program": "${file}",
+ "console": "integratedTerminal"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..8e1c55b
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,6 @@
+{
+ "python.linting.pylintEnabled": false,
+ "python.linting.pep8Enabled": false,
+ "python.linting.enabled": true,
+ "python.linting.flake8Enabled": true
+}
\ No newline at end of file
diff --git a/AIRFLOW101.md b/AIRFLOW101.md
new file mode 100644
index 0000000..265760c
--- /dev/null
+++ b/AIRFLOW101.md
@@ -0,0 +1,130 @@
+# Airflow 101
+
+## Our Environment
+
+Our analytics pipeline runs on open source [Apache Airflow](http://airflow.apache.org/tutorial.html) which is written in Python. This means we can deploy it to other clouds or inhouse if we need.
+
+We have some special configuration:
+- using latest beta version composer-1.6.1-airflow-1.10.1
+- using Python 3
+- google-api-python-client, tablib, python-igraph, plotly pypi packages preinstalled
+- slack_default and bigquery_default connection
+- special docker image that includes google cloud SDK and R with tidyverse/ggplot2
+- sendgrid enabled to allow warning and other messages to be sent.
+
+## Getting Started
+To access "Cloud Composer" (the Google branding for Airflow), visit https://console.cloud.google.com/composer/environments
+From this page you can access the Airflow webserver and the DAGs folder
+
+Read https://cloud.google.com/composer/docs/ for more information.
+
+## How to write a new workflow
+
+### DAGs
+Each pipeline is defined in a DAG file. (A Directed Acyclical Graph is a graph describing a process that goes step by step forward only with no infinite recursion or "cycles".)
+DAG files are technically Python code but use some special keywords and operators to describe data processes. Each pipeline can have a schedule and a SLA (maximum expected run time).
+
+DAG files are made up of Tasks that run Operators and can draw from Connections (via Hooks) and Variables. Definitions @ http://airflow.apache.org/concepts.html
+
+Tutorials http://airflow.apache.org/tutorial.html and https://cloud.google.com/composer/docs/how-to/using/writing-dags and https://cloud.google.com/blog/products/gcp/how-to-aggregate-data-for-bigquery-using-apache-airflow
+
+Tips for designing a workflow: https://en.wikipedia.org/wiki/SOLID
+
+### Header
+
+
+Set email_on_failure to True to send an email notification when an operator in the DAG fails.
+```
+default_dag_args = {
+
+ # Email whenever an Operator in the DAG fails.
+ 'email': models.Variable.get('email'),
+ 'email_on_failure': True,
+ 'email_on_retry': False,
+ 'retries': 1,
+ 'retry_delay': datetime.timedelta(minutes=5)
+}
+```
+
+Schedule, start date and SLA
+
+**WARNING: if the start date is in the past, it will try to catch up running jobs for the schedule period (eg. daily) the first time the DAG is loaded **
+
+If the task takes longer than the SLA, an alert email is triggered.
+
+```
+with models.DAG(
+ 'ga_quarterly_reporter',
+ schedule_interval=datetime.timedelta(days=90),
+ sla=datetime.timedelta(hours=1),
+ default_args=default_dag_args) as dag:
+```
+
+ ### Variables
+
+ Variables are configured via the webserver under Admin -> Variables. A variable can be a string, Python list/array or Python dict.
+ The second parameter of the .get() function is the default value if the variable isn't found.
+ You can use variables in the python string formatting functions https://docs.python.org/3/library/string.html#formatexamples
+```
+from airflow import models
+
+'dataflow_default_options': {
+ 'project': models.Variable.get('GCP_PROJECT','dta-ga-bigquery'),
+ 'tempLocation': 'gs://staging.%s.appspot.com/' % models.Variable.get('GCP_PROJECT','dta-ga-bigquery')
+ }
+```
+
+### Operators
+
+Full listing at http://airflow.apache.org/_api/airflow/operators/index.html and http://airflow.apache.org/_api/airflow/contrib/operators/index.html includes operators for Bash scripts, JIRA, S3, SQL databases etc.
+
+**Our favourite operators:**
+
+- PythonOperator
+http://airflow.apache.org/howto/operator/python.html
+
+- BigQueryOperator and BigQueryToCloudStorageOperator
+
+Our environment automatically has a connection to bigquery so no credentials are needed.
+
+http://airflow.apache.org/_api/airflow/contrib/operators/bigquery_operator/index.html
+
+- KubernetesPodOperator
+Perfect for running an R script or a Python script that needs system packages like chart/graph rendering.
+
+We run a custom docker image with extra R packages described in docker/Dockerfile
+
+https://airflow.apache.org/_api/airflow/contrib/operators/kubernetes_pod_operator/index.html#airflow.contrib.operators.kubernetes_pod_operator.KubernetesPodOperator
+
+**Honorable Mentions:**
+
+- DataFlowOperator
+
+uses the google cloud branded implementation of Apache Beam, another
+- SlackWebHookOperator
+
+- EmailOperator
+Gmail seems to take 5 or 6 minutes to virus scan attachments before they appear.
+
+
+## Dependencies and Deployment
+
+At the end of the file, in the indented "with DAG:" section you can define dependencies between operators (else they will all run concurrently):
+```
+A >> B >> C
+
+or
+A >> B
+B >> C
+
+or
+
+A >> B
+C << B
+
+```
+
+Once you have a DAG, can drag drop it into the folder via the web browser and soon it will be visible in the webserver. When updating a DAG, there is also a Refresh (recycling icon) button.
+You can either trigger the whole DAG or "clear" a task to make that task and all dependent tasks be retried.
+
+Once it is good, check it into Git!
\ No newline at end of file
diff --git a/README.md b/README.md
index 265760c..aee5b39 100644
--- a/README.md
+++ b/README.md
@@ -1,130 +1,2 @@
-# Airflow 101
-
-## Our Environment
-
-Our analytics pipeline runs on open source [Apache Airflow](http://airflow.apache.org/tutorial.html) which is written in Python. This means we can deploy it to other clouds or inhouse if we need.
-
-We have some special configuration:
-- using latest beta version composer-1.6.1-airflow-1.10.1
-- using Python 3
-- google-api-python-client, tablib, python-igraph, plotly pypi packages preinstalled
-- slack_default and bigquery_default connection
-- special docker image that includes google cloud SDK and R with tidyverse/ggplot2
-- sendgrid enabled to allow warning and other messages to be sent.
-
-## Getting Started
-To access "Cloud Composer" (the Google branding for Airflow), visit https://console.cloud.google.com/composer/environments
-From this page you can access the Airflow webserver and the DAGs folder
-
-Read https://cloud.google.com/composer/docs/ for more information.
-
-## How to write a new workflow
-
-### DAGs
-Each pipeline is defined in a DAG file. (A Directed Acyclical Graph is a graph describing a process that goes step by step forward only with no infinite recursion or "cycles".)
-DAG files are technically Python code but use some special keywords and operators to describe data processes. Each pipeline can have a schedule and a SLA (maximum expected run time).
-
-DAG files are made up of Tasks that run Operators and can draw from Connections (via Hooks) and Variables. Definitions @ http://airflow.apache.org/concepts.html
-
-Tutorials http://airflow.apache.org/tutorial.html and https://cloud.google.com/composer/docs/how-to/using/writing-dags and https://cloud.google.com/blog/products/gcp/how-to-aggregate-data-for-bigquery-using-apache-airflow
-
-Tips for designing a workflow: https://en.wikipedia.org/wiki/SOLID
-
-### Header
-
-
-Set email_on_failure to True to send an email notification when an operator in the DAG fails.
-```
-default_dag_args = {
-
- # Email whenever an Operator in the DAG fails.
- 'email': models.Variable.get('email'),
- 'email_on_failure': True,
- 'email_on_retry': False,
- 'retries': 1,
- 'retry_delay': datetime.timedelta(minutes=5)
-}
-```
-
-Schedule, start date and SLA
-
-**WARNING: if the start date is in the past, it will try to catch up running jobs for the schedule period (eg. daily) the first time the DAG is loaded **
-
-If the task takes longer than the SLA, an alert email is triggered.
-
-```
-with models.DAG(
- 'ga_quarterly_reporter',
- schedule_interval=datetime.timedelta(days=90),
- sla=datetime.timedelta(hours=1),
- default_args=default_dag_args) as dag:
-```
-
- ### Variables
-
- Variables are configured via the webserver under Admin -> Variables. A variable can be a string, Python list/array or Python dict.
- The second parameter of the .get() function is the default value if the variable isn't found.
- You can use variables in the python string formatting functions https://docs.python.org/3/library/string.html#formatexamples
-```
-from airflow import models
-
-'dataflow_default_options': {
- 'project': models.Variable.get('GCP_PROJECT','dta-ga-bigquery'),
- 'tempLocation': 'gs://staging.%s.appspot.com/' % models.Variable.get('GCP_PROJECT','dta-ga-bigquery')
- }
-```
-
-### Operators
-
-Full listing at http://airflow.apache.org/_api/airflow/operators/index.html and http://airflow.apache.org/_api/airflow/contrib/operators/index.html includes operators for Bash scripts, JIRA, S3, SQL databases etc.
-
-**Our favourite operators:**
-
-- PythonOperator
-http://airflow.apache.org/howto/operator/python.html
-
-- BigQueryOperator and BigQueryToCloudStorageOperator
-
-Our environment automatically has a connection to bigquery so no credentials are needed.
-
-http://airflow.apache.org/_api/airflow/contrib/operators/bigquery_operator/index.html
-
-- KubernetesPodOperator
-Perfect for running an R script or a Python script that needs system packages like chart/graph rendering.
-
-We run a custom docker image with extra R packages described in docker/Dockerfile
-
-https://airflow.apache.org/_api/airflow/contrib/operators/kubernetes_pod_operator/index.html#airflow.contrib.operators.kubernetes_pod_operator.KubernetesPodOperator
-
-**Honorable Mentions:**
-
-- DataFlowOperator
-
-uses the google cloud branded implementation of Apache Beam, another
-- SlackWebHookOperator
-
-- EmailOperator
-Gmail seems to take 5 or 6 minutes to virus scan attachments before they appear.
-
-
-## Dependencies and Deployment
-
-At the end of the file, in the indented "with DAG:" section you can define dependencies between operators (else they will all run concurrently):
-```
-A >> B >> C
-
-or
-A >> B
-B >> C
-
-or
-
-A >> B
-C << B
-
-```
-
-Once you have a DAG, can drag drop it into the folder via the web browser and soon it will be visible in the webserver. When updating a DAG, there is also a Refresh (recycling icon) button.
-You can either trigger the whole DAG or "clear" a task to make that task and all dependent tasks be retried.
-
-Once it is good, check it into Git!
\ No newline at end of file
+# Observatory
+To run the HTML version, download augov.gexf from /data on Google Cloud Storage, put it in html/observatory/data and run html/observatory/run.sh
\ No newline at end of file
diff --git a/dags/ga_benchmark.py b/dags/ga_benchmark.py
index d3e70b8..cee4cfd 100644
--- a/dags/ga_benchmark.py
+++ b/dags/ga_benchmark.py
@@ -14,15 +14,12 @@
'start_date': yesterday,
}
-
with models.DAG(
'ga_benchmark',
schedule_interval=datetime.timedelta(days=1),
default_args=default_dag_args) as dag:
- project_id = models.Variable.get('GCP_PROJECT','dta-ga-bigquery')
+ project_id = models.Variable.get('GCP_PROJECT', 'dta-ga-bigquery')
- view_id = '69211100'
- timestamp = '20190425'
temp_table = 'benchmark_%s_%s' % (view_id, timestamp)
query = """
CREATE TABLE `{{params.project_id}}.tmp.{{ params.temp_table }}`
@@ -58,6 +55,7 @@
export_benchmark_to_gcs = bigquery_to_gcs.BigQueryToCloudStorageOperator(
task_id='export_benchmark_to_gcs',
source_project_dataset_table="%s.tmp.%s" % (project_id, temp_table),
- destination_cloud_storage_uris=["gs://us-central1-maxious-airflow-64b78389-bucket/data/%s.csv" % (temp_table,)],
+ destination_cloud_storage_uris=["gs://%s/data/%s.csv" % (
+ models.Variable.get('AIRFLOW_BUCKET', 'us-east1-dta-airflow-b3415db4-bucket'), temp_table)],
export_format='CSV')
query_benchmark >> export_benchmark_to_gcs
diff --git a/dags/ga_daily_reporter.py b/dags/ga_daily_reporter.py
index e1e46df..2d83c8b 100644
--- a/dags/ga_daily_reporter.py
+++ b/dags/ga_daily_reporter.py
@@ -3,7 +3,6 @@
import glob
import os
-
from airflow import models
from airflow.operators import python_operator
from airflow.contrib.operators import slack_webhook_operator
@@ -17,10 +16,10 @@
'start_date': datetime.datetime(2019, 4, 26),
# http://airflow.apache.org/_api/airflow/contrib/operators/dataflow_operator/index.html
'dataflow_default_options': {
- 'project': models.Variable.get('GCP_PROJECT','dta-ga-bigquery'),
+ 'project': models.Variable.get('GCP_PROJECT', 'dta-ga-bigquery'),
'region': 'us-central1',
'zone': 'us-central1-b',
- 'tempLocation': 'gs://staging.%s.appspot.com/' % models.Variable.get('GCP_PROJECT','dta-ga-bigquery')
+ 'tempLocation': 'gs://staging.%s.appspot.com/' % models.Variable.get('GCP_PROJECT', 'dta-ga-bigquery')
}
}
@@ -32,12 +31,12 @@
def combine_tally():
from tablib import Dataset
data = Dataset()
- for f in glob.glob(DATA_DIR+'tally_69211100_20190425.csv-*'):
+ for f in glob.glob(DATA_DIR + 'tally_69211100_20190425.csv-*'):
d = Dataset().load(open(f, 'rt').read())
for row in d:
data.append(row)
- with open(DATA_DIR+'tally_69211100_20190425.csv', 'wt') as f:
+ with open(DATA_DIR + 'tally_69211100_20190425.csv', 'wt') as f:
f.write('path,hits\n')
f.write(data.csv)
@@ -45,36 +44,36 @@ def combine_tally():
def generate_plotly_chart():
from tablib import Dataset
- df = Dataset().load(open(DATA_DIR+'tally_69211100_20190425.csv', 'r').read()).df.sort_values(by=['hits'])
+ df = Dataset().load(open(DATA_DIR + 'tally_69211100_20190425.csv', 'r').read()).df.sort_values(by=['hits'])
df = df[df['hits'] > 30]
import plotly
import plotly.graph_objs as go
plotly.offline.plot({
- "data": [go.Bar(x=df.path, y=df.hits)]}, filename=DATA_DIR+"temp-plot.html", auto_open=False)
+ "data": [go.Bar(x=df.path, y=df.hits)]}, filename=DATA_DIR + "temp-plot.html", auto_open=False)
def generate_graph():
-
import igraph
g = igraph.Graph()
g.add_vertices(3)
- g.add_edges([(0,1), (1,2)])
+ g.add_edges([(0, 1), (1, 2)])
print(g)
- g.write_graphml(DATA_DIR+"social_network.graphml")
+ g.write_graphml(DATA_DIR + "social_network.graphml")
def find_number_one():
from tablib import Dataset
- df = Dataset().load(open(DATA_DIR+'tally_69211100_20190425.csv', 'r').read()).df.sort_values(by=['hits'])
+ df = Dataset().load(open(DATA_DIR + 'tally_69211100_20190425.csv', 'r').read()).df.sort_values(by=['hits'])
return df.values[-1][0], df.values[-1][1]
def tell_slack(context):
o = slack_webhook_operator.SlackWebhookOperator(task_id="tell_slack", http_conn_id='slack_default',
- message="Number one page today is %s (%s hits)" % (find_number_one()))
+ message="Number one page today is %s (%s hits)" % (
+ find_number_one()))
return o.execute(context)
@@ -92,7 +91,9 @@ def tell_slack(context):
# https://stackoverflow.com/questions/52054427/how-to-integrate-apache-airflow-with-slack
tell_slack = slack_webhook_operator.SlackWebhookOperator(task_id="tell_slack", http_conn_id='slack_default',
message="A new report is out: "
- "https://storage.cloud.google.com/us-central1-maxious-airflow-64b78389-bucket/data/tally_69211100_20190425.csv")
+ "https://%s/data/tally_69211100_20190425.csv" % (
+ models.Variable.get('AIRFLOW_BUCKET',
+ 'us-east1-dta-airflow-b3415db4-bucket')))
generate_graph = python_operator.PythonOperator(
task_id='generate_graph',
@@ -105,16 +106,19 @@ def tell_slack(context):
from airflow.contrib.operators.kubernetes_pod_operator import KubernetesPodOperator
kubetest = KubernetesPodOperator(
- task_id='pod-ex-minimum',
- name='pod-ex-minimum',
- namespace='default',
- image='gcr.io/%s/galileo' % models.Variable.get('GCP_PROJECT','dta-ga-bigquery'),
- image_pull_policy="Always",
- cmds=['bash', '-c'],
- arguments=['gsutil cp gs://%s/data/tally_69211100_20190425.csv . && ' % models.Variable.get('AIRFLOW_BUCKET', 'us-east1-dta-airflow-b3415db4-bucket') +
- 'gsutil cp gs://%s/dags/r_scripts/csvggplot.R . && ' % models.Variable.get('AIRFLOW_BUCKET', 'us-east1-dta-airflow-b3415db4-bucket') +
- 'R -f csvggplot.R && '
- 'gsutil cp tally_69211100_20190425.png gs://%s/data/' % models.Variable.get('AIRFLOW_BUCKET', 'us-east1-dta-airflow-b3415db4-bucket') ],)
+ task_id='pod-ex-minimum',
+ name='pod-ex-minimum',
+ namespace='default',
+ image='gcr.io/%s/galileo' % models.Variable.get('GCP_PROJECT', 'dta-ga-bigquery'),
+ image_pull_policy="Always",
+ cmds=['bash', '-c'],
+ arguments=['gsutil cp gs://%s/data/tally_69211100_20190425.csv . && ' % models.Variable.get('AIRFLOW_BUCKET',
+ 'us-east1-dta-airflow-b3415db4-bucket') +
+ 'gsutil cp gs://%s/dags/r_scripts/csvggplot.R . && ' % models.Variable.get('AIRFLOW_BUCKET',
+ 'us-east1-dta-airflow-b3415db4-bucket') +
+ 'R -f csvggplot.R && '
+ 'gsutil cp tally_69211100_20190425.png gs://%s/data/' % models.Variable.get('AIRFLOW_BUCKET',
+ 'us-east1-dta-airflow-b3415db4-bucket')], )
benchmark_tally >> combine_tally
combine_tally >> generate_plotly_chart
diff --git a/dags/ga_daily_reporter_test.py b/dags/ga_daily_reporter_test.py
index 1970fa4..992b6cc 100644
--- a/dags/ga_daily_reporter_test.py
+++ b/dags/ga_daily_reporter_test.py
@@ -10,7 +10,7 @@ def test_dag_import():
if __package__ is None:
import sys
from os import path
- sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
+ sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
import ga_daily_reporter as module
else:
from . import ga_daily_reporter as module
@@ -18,4 +18,4 @@ def test_dag_import():
if __name__ == '__main__':
- test_dag_import()
\ No newline at end of file
+ test_dag_import()
diff --git a/dags/ga_quarterly_reporter.py b/dags/ga_quarterly_reporter.py
index 19fdcdf..1641de8 100644
--- a/dags/ga_quarterly_reporter.py
+++ b/dags/ga_quarterly_reporter.py
@@ -23,7 +23,7 @@
def send_report():
datestamp = datetime.datetime.now().strftime('%d%b%Y')
- report_file = DATA_DIR+'GA360-%s.csv' % datestamp
+ report_file = DATA_DIR + 'GA360-%s.csv' % datestamp
table = Dataset().load(open(report_file, 'rt').read()).export('df').to_html()
@@ -47,10 +47,13 @@ def send_report():
image='gcr.io/%s/galileo' % models.Variable.get('GCP_PROJECT', 'dta-ga-bigquery'),
cmds=['bash', '-c'],
image_pull_policy="Always",
- arguments=['gsutil cp gs://%s/data/credentials.json . && '% models.Variable.get('AIRFLOW_BUCKET','us-east1-dta-airflow-b3415db4-bucket') +
- 'gsutil cp gs://%s/dags/r_scripts/extractaccinfo.R . && ' % models.Variable.get('AIRFLOW_BUCKET','us-east1-dta-airflow-b3415db4-bucket') +
+ arguments=['gsutil cp gs://%s/data/credentials.json . && ' % models.Variable.get('AIRFLOW_BUCKET',
+ 'us-east1-dta-airflow-b3415db4-bucket') +
+ 'gsutil cp gs://%s/dags/r_scripts/extractaccinfo.R . && ' % models.Variable.get('AIRFLOW_BUCKET',
+ 'us-east1-dta-airflow-b3415db4-bucket') +
'R -f extractaccinfo.R && '
- 'gsutil cp GA360*.csv gs://%s/data/' % models.Variable.get('AIRFLOW_BUCKET','us-east1-dta-airflow-b3415db4-bucket') ])
+ 'gsutil cp GA360*.csv gs://%s/data/' % models.Variable.get('AIRFLOW_BUCKET',
+ 'us-east1-dta-airflow-b3415db4-bucket')])
email_summary = PythonOperator(
task_id='email_summary',
diff --git a/dags/galileo/__init__.py b/dags/galileo/__init__.py
index e69de29..d90ca6d 100644
--- a/dags/galileo/__init__.py
+++ b/dags/galileo/__init__.py
@@ -0,0 +1,5 @@
+import re
+
+
+def domain_slug(domain):
+ return re.sub(r"http(s)|:|\/|www.?|\.", "", domain)
diff --git a/dags/galileo/ga.py b/dags/galileo/ga.py
index d623b74..a423492 100644
--- a/dags/galileo/ga.py
+++ b/dags/galileo/ga.py
@@ -1,25 +1,14 @@
-from apiclient.discovery import build
-from oauth2client.service_account import ServiceAccountCredentials
-import os
import tablib
-DATA_DIR = '/home/airflow/gcs/data/'
-if not os.path.isdir(DATA_DIR):
- DATA_DIR = '../../data/'
-
-def get_service(api_name, api_version, scopes):
- credentials = ServiceAccountCredentials.from_json_keyfile_name(
- DATA_DIR+'/credentials.json', scopes=scopes)
-
- # Build the service object.
- service = build(api_name, api_version, credentials=credentials)
-
- return service
+try:
+ from . import galileo
+except ImportError:
+ import galileo
def generate_accounts_views_index():
# Authenticate and construct service.
- service = get_service(
+ service = galileo.get_service(
api_name='analytics',
api_version='v3',
scopes=['https://www.googleapis.com/auth/analytics.readonly'])
@@ -29,27 +18,71 @@ def generate_accounts_views_index():
accounts = service.management().accounts().list().execute()
for account in accounts.get('items'):
- #print 'account', account['id'], account['name']
+ # print 'account', account['id'], account['name']
# Get a list of all the properties for the first account.
properties = service.management().webproperties().list(
accountId=account['id']).execute()
for property in properties.get('items'):
- #print ' property', property['id'],property['name']
+ # print ' property', property['id'],property['name']
# Get a list of all views (profiles) for the first property.
profiles = service.management().profiles().list(
accountId=account['id'],
webPropertyId=property['id']).execute()
for view in profiles.get('items'):
- #print ' view',view['id'], view['name']
+ # print ' view',view['id'], view['name']
# return the first view (profile) id.
data.append([account['id'], account['name'], property['id'], property['name'],
property.get('level'), property.get('websiteUrl'),
property.get('defaultProfileId'), view['id'], view['name']])
- with open(DATA_DIR+'/ga_accounts_views_index.csv', 'wb') as f:
+ with open(galileo.DATA_DIR + '/ga_accounts_views_index.csv', 'wt') as f:
f.write(data.csv)
+def get_events(name, view_id, category, action):
+ print('fetching', name, 'for', view_id)
+ service = galileo.get_service(api_name='analyticsreporting', api_version='v4',
+ scopes=['https://www.googleapis.com/auth/analytics.readonly'])
+ response = service.reports().batchGet(
+ body={
+ 'reportRequests': [
+ {
+ 'viewId': view_id,
+ 'dateRanges': [{'startDate': '30daysAgo', 'endDate': 'today'}],
+ 'metrics': [{'expression': 'ga:totalEvents'}],
+ 'dimensions': [{'name': 'ga:eventLabel'}],
+ 'orderBys': [{"fieldName": 'ga:totalEvents', "sortOrder": "DESCENDING"}],
+ 'filtersExpression': 'ga:totalEvents>10;ga:eventCategory==' + category + ';ga:eventAction==' + action,
+ 'pageSize': 100000
+ }]
+ }
+ ).execute()
+ result = []
+ for row in response.get('reports', [])[0].get('data', {}).get('rows', []):
+ if row:
+ # print(row['dimensions'][0], row['metrics'][0]['values'][0])
+ result.append({"query": row['dimensions'][0], name: int(row['metrics'][0]['values'][0])})
+
+ return result
+
+
if __name__ == '__main__':
- generate_accounts_views_index()
\ No newline at end of file
+ # generate_accounts_views_index()
+
+ searches = get_events('impressions', '114274207', "ElasticSearch-Results", "Successful Search")
+ search_clicks = get_events('clicks', '114274207', "ElasticSearch-Results Clicks", "Page Result Click")
+ from collections import defaultdict
+
+ d = defaultdict(dict)
+ for l in (searches, search_clicks):
+ for elem in l:
+ d[elem['query'].lower()].update(elem)
+ data = tablib.Dataset(headers=['query', 'impressions', 'clicks'])
+ for l in d.values():
+ data.append((l['query'], l.get('impressions'), l.get('clicks')))
+ import datetime
+
+ with open(galileo.DATA_DIR + 'internalsearch_114274207_' + datetime.datetime.now().strftime('%Y%m%d') + '.csv',
+ 'wt') as f:
+ f.write(data.csv)
diff --git a/dags/galileo/galileo.py b/dags/galileo/galileo.py
new file mode 100644
index 0000000..882893f
--- /dev/null
+++ b/dags/galileo/galileo.py
@@ -0,0 +1,26 @@
+import os
+import re
+from apiclient.discovery import build
+from oauth2client.service_account import ServiceAccountCredentials
+
+DATA_DIR = '/home/airflow/gcs/data/'
+if not os.path.isdir(DATA_DIR):
+ DATA_DIR = '../../data/'
+
+
+def get_service(api_name, api_version, scopes):
+ if scopes == ['https://www.googleapis.com/auth/webmasters.readonly']:
+ credentials = ServiceAccountCredentials.from_json_keyfile_name(
+ DATA_DIR + '/test-credentials.json', scopes=scopes)
+ else:
+ credentials = ServiceAccountCredentials.from_json_keyfile_name(
+ DATA_DIR + '/credentials.json', scopes=scopes)
+
+ # Build the service object.
+ service = build(api_name, api_version, credentials=credentials)
+
+ return service
+
+
+def domain_slug(domain):
+ return re.sub(r"http(s)|:|\/|www.?|\.", "", domain)
diff --git a/dags/galileo/searchconsole.py b/dags/galileo/searchconsole.py
new file mode 100644
index 0000000..ca5891e
--- /dev/null
+++ b/dags/galileo/searchconsole.py
@@ -0,0 +1,81 @@
+import tablib
+import datetime
+import os
+
+try:
+ from . import galileo
+except ImportError:
+ import galileo
+
+
+def generate_web_search_query_report(property_uri,
+ days=10,
+ end_date=datetime.date.today()):
+ # Authenticate and construct service.
+ service = galileo.get_service(
+ api_name='webmasters',
+ api_version='v3',
+ scopes=['https://www.googleapis.com/auth/webmasters.readonly'])
+ start_date = (end_date - datetime.timedelta(days=days)).strftime('%Y-%m-%d')
+ end_date = end_date.strftime('%Y-%m-%d')
+ print(property_uri)
+ # First run a query to learn which dates we have data for. You should
+ # always check which days in a date range have data
+ # before running your main query.
+ # This query shows data for the entire range, grouped and sorted by day,
+ # descending; any days without data will be missing from the results.
+ request = {
+ 'startDate': start_date,
+ 'endDate': end_date,
+ 'dimensions': ['date']
+ }
+ response = service.searchanalytics().query(
+ siteUrl=property_uri, body=request).execute()
+ # print(response)
+ # data_start_date = response['rows'][-days-1]['keys'][0]
+ data_start_date = response['rows'][0]['keys'][0]
+ data_end_date = response['rows'][-1]['keys'][0]
+ print("loading from", data_start_date, "to", data_end_date) # , "(", days, "days )")
+ data = tablib.Dataset()
+ data.headers = ["query", "page", "clicks", "impressions",
+ "click_thru_ratio", "search_result_position"]
+ page_start = 0
+ last_rows = 1
+ while last_rows > 0:
+ request = {
+ 'startDate': data_start_date,
+ 'endDate': data_end_date,
+ 'dimensions': ['query', 'page'],
+ 'rowLimit': 25000,
+ 'startRow': page_start
+ }
+ response = service.searchanalytics().query(
+ siteUrl=property_uri, body=request).execute()
+
+ last_rows = 0
+ if 'rows' in response:
+ for row in response['rows']:
+ last_rows += 1
+ query = row['keys'][0].encode("ascii", errors="ignore").decode()
+ page = row['keys'][1].encode("ascii", errors="ignore").decode()
+ data.append([query, page, row['clicks'],
+ row['impressions'], row['ctr'], row['position']])
+ print(page_start + last_rows, "received...")
+ page_start += 25000
+ else:
+ print("done ", property_uri)
+ if not os.path.isdir(galileo.DATA_DIR + '/searchqueries'):
+ os.mkdir(galileo.DATA_DIR + '/searchqueries')
+ with open(galileo.DATA_DIR + '/searchqueries/{}_websearch_{}_{}.csv'.format(
+ galileo.domain_slug(property_uri),
+ data_start_date.replace('-', ''),
+ data_end_date.replace('-', ''),
+ ), 'wt', newline='') as f:
+ f.write(data.csv)
+
+
+if __name__ == '__main__':
+ generate_search_query_report("https://data.gov.au")
+ generate_search_query_report("https://www.dta.gov.au")
+ generate_search_query_report("https://www.domainname.gov.au/")
+ generate_search_query_report("https://marketplace.service.gov.au")
diff --git a/dags/galileo/unit_testing.py b/dags/galileo/unit_testing.py
index 6b5f34f..b051a85 100644
--- a/dags/galileo/unit_testing.py
+++ b/dags/galileo/unit_testing.py
@@ -31,4 +31,4 @@ def assert_has_valid_dag(module):
if no_dag_found:
raise AssertionError('module does not contain a valid DAG')
-# [END composer_dag_unit_testing]
\ No newline at end of file
+# [END composer_dag_unit_testing]
diff --git a/dags/observatory.py b/dags/observatory.py
index 4cd1b33..d23718e 100644
--- a/dags/observatory.py
+++ b/dags/observatory.py
@@ -32,9 +32,18 @@
image_pull_policy="Always",
image=DOCKER_IMAGE,
cmds=['bash', '-c'],
- arguments=['mkdir deploy && '
+ arguments=['git clone https://github.com/govau/GAlileo --depth=1 && '
+ 'cp -rv GAlileo/shiny/observatory deploy &&'
'cd deploy && '
- 'gsutil cp -r gs://{GCS_BUCKET}/dags/shiny/observatory/* . && '
+ 'gsutil cp -r gs://{GCS_BUCKET}/data/observatory/* . && '
'htpasswd -b -c htpasswd observatory {HTPASSWD} && '
'cf login -a https://api.system.y.cld.gov.au -u $CF_USERNAME -p $CF_PASSWORD && '
- 'cf push observatory'.format(GCS_BUCKET=GCS_BUCKET,HTPASSWD=htpasswd)])
+ 'cf unmap-route observatory-green apps.y.cld.gov.au -n observatory &&'
+ 'cf v3-apply-manifest -f manifest.yml &&'
+ 'cf v3-push observatory-green &&'
+ 'cf map-route observatory-green apps.y.cld.gov.au -n observatory &&'
+ 'cf unmap-route observatory-blue apps.y.cld.gov.au -n observatory &&'
+ 'cf v3-push observatory-blue &&'
+ 'cf map-route observatory-blue apps.y.cld.gov.au -n observatory &&'
+ 'cf unmap-route observatory-blue apps.y.cld.gov.au -n observatory-green'
+ .format(GCS_BUCKET=GCS_BUCKET, HTPASSWD=htpasswd)])
diff --git a/dags/pipelines/benchmark_tally.py b/dags/pipelines/benchmark_tally.py
index d8274b8..fad8670 100644
--- a/dags/pipelines/benchmark_tally.py
+++ b/dags/pipelines/benchmark_tally.py
@@ -9,17 +9,18 @@
from apache_beam.options.pipeline_options import PipelineOptions
from apache_beam.options.pipeline_options import SetupOptions
+
def run(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument('--input',
dest='input',
default='gs://us-central1-maxious-airflow-64b78389-bucket/data/benchmark_69211100_20190425.csv',
- #'../../data/benchmark_69211100_20190425.csv',
+ # '../../data/benchmark_69211100_20190425.csv',
help='Input file to process.')
parser.add_argument('--output',
dest='output',
default='gs://us-central1-maxious-airflow-64b78389-bucket/data/tally_69211100_20190425.csv',
- #'../../data/tally_69211100_20190425.csv',
+ # '../../data/tally_69211100_20190425.csv',
help='Output file to write results to.')
known_args, pipeline_args = parser.parse_known_args(argv)
@@ -57,4 +58,4 @@ def format_result(path_count):
if __name__ == '__main__':
logging.getLogger().setLevel(logging.INFO)
- run()
\ No newline at end of file
+ run()
diff --git a/dags/r_scripts/csvggplot.R b/dags/r_scripts/csvggplot.R
index b3cb495..19308dd 100644
--- a/dags/r_scripts/csvggplot.R
+++ b/dags/r_scripts/csvggplot.R
@@ -4,7 +4,7 @@ library(tidyverse)
d <- read.csv("tally_69211100_20190425.csv")
d <- filter(d, hits > 1)
d$path = str_wrap(d$path, width = 50)
-p <- ggplot(d, aes(y=path, x=hits)) +geom_point()
+p <- ggplot(d, aes(y = path, x = hits)) + geom_point()
png("tally_69211100_20190425.png")
print(p)
dev.off()
\ No newline at end of file
diff --git a/dags/r_scripts/extractaccinfo.R b/dags/r_scripts/extractaccinfo.R
index f5352db..4610c65 100644
--- a/dags/r_scripts/extractaccinfo.R
+++ b/dags/r_scripts/extractaccinfo.R
@@ -7,9 +7,9 @@ options(googleAuthR.scopes.selected = "https://www.googleapis.com/auth/analytics
gar_auth_service("credentials.json")
gg <- ga_account_list() %>%
- select(accountId, internalWebPropertyId,websiteUrl, webPropertyId, level, type, viewId, viewName) %>%
- filter(level=="PREMIUM" & type == "WEB") %>%
+ select(accountId, internalWebPropertyId, websiteUrl, webPropertyId, level, type, viewId, viewName) %>%
+ filter(level == "PREMIUM" & type == "WEB") %>%
distinct(webPropertyId, .keep_all = TRUE)
name <- paste0("GA360-", format(Sys.time(), '%d%b%Y'), ".csv")
-write.csv(gg,name)
+write.csv(gg, name)
diff --git a/dags/web_search_reporter.py b/dags/web_search_reporter.py
new file mode 100644
index 0000000..f4a8f24
--- /dev/null
+++ b/dags/web_search_reporter.py
@@ -0,0 +1,105 @@
+from __future__ import print_function
+import datetime
+import time
+import os
+import tablib
+
+from airflow import models
+from airflow.operators import python_operator
+from airflow.contrib.operators import bigquery_to_gcs
+from airflow.contrib.operators import bigquery_operator
+
+from galileo import galileo, searchconsole, ga
+
+default_dag_args = {
+ # The start_date describes when a DAG is valid / can be run. Set this to a
+ # fixed point in time rather than dynamically, since it is evaluated every
+ # time a DAG is parsed. See:
+ # https://airflow.apache.org/faq.html#what-s-the-deal-with-start-date
+ 'start_date': datetime.datetime(2019, 7, 4),
+}
+
+
+def export_search_events():
+ searches = ga.get_events('impressions', '114274207', "ElasticSearch-Results", "Successful Search")
+ search_clicks = ga.get_events('clicks', '114274207', "ElasticSearch-Results Clicks", "Page Result Click")
+ from collections import defaultdict
+ d = defaultdict(dict)
+ for l in (searches, search_clicks):
+ for elem in l:
+ d[elem['query'].lower()].update(elem)
+ data = tablib.Dataset(headers=['query', 'impressions', 'clicks'])
+ for l in d.values():
+ data.append((l['query'], l.get('impressions'), l.get('clicks')))
+ if not os.path.isdir(galileo.DATA_DIR + '/searchqueries'):
+ os.mkdir(galileo.DATA_DIR + '/searchqueries')
+ with open(galileo.DATA_DIR + '/searchqueries/114274207_internalsearch_' + datetime.datetime.now().strftime(
+ '%Y%m%d') + '.csv',
+ 'wt') as f:
+ f.write(data.csv)
+
+
+with models.DAG(
+ 'search_reporter',
+ schedule_interval=datetime.timedelta(days=7),
+ default_args=default_dag_args) as dag:
+ event_searchqueries = python_operator.PythonOperator(
+ task_id='web_searchqueries_events',
+ python_callable=export_search_events)
+
+ for domain in ["https://data.gov.au", "https://www.dta.gov.au", "https://www.domainname.gov.au/",
+ "https://marketplace.service.gov.au"]:
+ web_searchqueries = python_operator.PythonOperator(
+ task_id='web_searchqueries_' + galileo.domain_slug(domain),
+ python_callable=searchconsole.generate_web_search_query_report,
+ op_args=[domain])
+ for d in [
+ {"domain": "https://www.dta.gov.au", "view_id": 99993137, "search_param": "keys"},
+ {"domain": "https://data.gov.au", "view_id": 69211100, "search_param": "q"},
+ {"domain": "https://marketplace.service.gov.au", "view_id": 130142010, "search_param": "keyword"}
+ ]:
+ project_id = models.Variable.get('GCP_PROJECT', 'dta-ga-bigquery')
+ start = (datetime.date.today() - datetime.timedelta(days=30)).strftime("%Y%m%d")
+ end = (datetime.date.today() - datetime.timedelta(days=2)).strftime("%Y%m%d")
+ temp_table = '%s_internalsearch_%s' % (galileo.domain_slug(d['domain']), end)
+
+ query = """
+ CREATE TABLE `{{params.project_id}}.tmp.{{params.temp_table}}_{{ ts_nodash }}`
+ OPTIONS(
+ expiration_timestamp=TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)
+ ) AS
+ SELECT lower(replace(REGEXP_EXTRACT(page.pagePath, r"{{ params.search_param }}=(.*?)(?:&|$)"),"+"," ")) query,
+ count(*) impressions
+ FROM
+ `dta-ga-bigquery.{{params.view_id}}.ga_sessions_*`,
+ UNNEST(hits)
+
+ WHERE
+ _TABLE_SUFFIX BETWEEN '{{params.start}}' AND '{{params.end}}'
+ AND REGEXP_CONTAINS(page.pagePath, r"{{ params.search_param }}=(.*?)(?:&|$)")
+ group by query
+ order by count(*) desc
+ """
+
+ query_internalsearch = bigquery_operator.BigQueryOperator(
+ task_id='query_internalsearch_' + galileo.domain_slug(d['domain']),
+ bql=query, use_legacy_sql=False, params={
+ 'project_id': project_id,
+ 'view_id': d['view_id'],
+ 'start': start,
+ 'end': end,
+ 'temp_table': temp_table,
+ 'search_param': d['search_param']
+ })
+ export_internalsearch_to_gcs = bigquery_to_gcs.BigQueryToCloudStorageOperator(
+ task_id='export_internalsearch_to_gcs_' + galileo.domain_slug(d['domain']),
+ source_project_dataset_table="{{params.project_id}}.tmp.{{params.temp_table}}_{{ ts_nodash }}",
+ params= {
+ 'project_id': project_id,
+ 'temp_table': temp_table
+ },
+ destination_cloud_storage_uris=[
+ "gs://%s/data/searchqueries/%s.csv" % (
+ models.Variable.get('AIRFLOW_BUCKET', 'us-east1-dta-airflow-b3415db4-bucket'), temp_table)],
+ export_format='CSV')
+ query_internalsearch >> export_internalsearch_to_gcs
diff --git a/dags/wildebeest.py b/dags/wildebeest.py
index a57894e..b23ff92 100644
--- a/dags/wildebeest.py
+++ b/dags/wildebeest.py
@@ -21,7 +21,7 @@
# to get view ids query "SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA where schema_name < 'a'"
view_ids = set(['34154705', '100180008', '88992271', '71597546', '101713735', '69211100', '86149663',
- '99993137', '34938005', '70635257', '80842702', '101163468', '90974611',
+ '99993137', '34938005', '70635257', '80842702', '101163468', '90974611',
'77664740', '104411629', '100832347', '95074916', '53715324', '95014024', '134969186',
'31265425', '47586269', '95068310', '98362688', '104395490', '100095673', '5289745', '100136570',
'77084214', '100095166', '85844330', '98349896', '129200625', '69522323', '98360372', '98349897'])
@@ -103,10 +103,9 @@ def generate_url_query(view_ids):
'wildebeest',
schedule_interval=datetime.timedelta(days=7),
default_args=default_dag_args) as dag:
-
query, subqueries, temp_table = generate_host_query(view_ids)
query_wildebeest_host = bigquery_operator.BigQueryOperator(
- task_id='query_wildebeest_host' ,
+ task_id='query_wildebeest_host',
bql=query, use_legacy_sql=False, params={
'project_id': project_id,
'temp_table': temp_table,
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 64c5b40..e03503c 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -6,11 +6,10 @@ RUN sudo apt install -y curl gnupg
RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
RUN sudo apt-get update
## install cloudfoundry tools
-RUN curl -v -L -o cf-cli_amd64.deb 'https://cli.run.pivotal.io/stable?release=debian64&source=github'
-RUN sudo dpkg -i cf-cli_amd64.deb
+RUN curl -v -L -o cf-cli_amd64.deb 'https://cli.run.pivotal.io/stable?release=debian64&source=github' && sudo dpkg -i cf-cli_amd64.deb
## install google cloud SDK and common R packages
-RUN sudo apt install -y google-cloud-sdk r-cran-ggplot2 r-cran-stringr apache2-utils
+RUN sudo apt install -y google-cloud-sdk r-cran-ggplot2 r-cran-stringr r-cran-plyr r-cran-magrittr r-cran-lubridate apache2-utils
## install some R packages directly from CRAN
RUN install2.r --error \
-r 'http://cran.rstudio.com' \
@@ -20,11 +19,11 @@ RUN install2.r --error \
gmailr \
googleCloudStorageR \
bigQueryR
+
RUN install2.r --error \
-r 'http://cran.rstudio.com' \
rsconnect
-
## clean up
RUN apt-get clean && rm -rf /var/lib/apt/lists/ && rm -rf /tmp/downloaded_packages/ /tmp/*.rds
diff --git a/html/observatory/.eslintrc b/html/observatory/.eslintrc
new file mode 100644
index 0000000..e0d8a85
--- /dev/null
+++ b/html/observatory/.eslintrc
@@ -0,0 +1,207 @@
+
+{
+ "parserOptions": {
+ "ecmaVersion": 2018,
+ "ecmaFeatures": {
+ "jsx": true
+ },
+ "sourceType": "module"
+ },
+
+ "env": {
+ "es6": true,
+ "node": true
+ },
+
+ "plugins": [
+ "import",
+ "node",
+ "promise",
+ "standard"
+ ],
+
+ "globals": {
+ "document": false,
+ "navigator": false,
+ "window": false
+ },
+
+ "rules": {
+ "accessor-pairs": "error",
+ "arrow-spacing": ["error", { "before": true, "after": true }],
+ "block-spacing": ["error", "always"],
+ "brace-style": ["error", "1tbs", { "allowSingleLine": true }],
+ "camelcase": ["error", { "properties": "never" }],
+ "comma-dangle": ["error", {
+ "arrays": "never",
+ "objects": "never",
+ "imports": "never",
+ "exports": "never",
+ "functions": "never"
+ }],
+ "comma-spacing": ["error", { "before": false, "after": true }],
+ "comma-style": ["error", "last"],
+ "constructor-super": "error",
+ "curly": ["error", "multi-line"],
+ "dot-location": ["error", "property"],
+ "eol-last": "error",
+ "eqeqeq": ["error", "always", { "null": "ignore" }],
+ "func-call-spacing": ["error", "never"],
+ "generator-star-spacing": ["error", { "before": true, "after": true }],
+ "handle-callback-err": ["error", "^(err|error)$" ],
+ "indent": ["error", 2, {
+ "SwitchCase": 1,
+ "VariableDeclarator": 1,
+ "outerIIFEBody": 1,
+ "MemberExpression": 1,
+ "FunctionDeclaration": { "parameters": 1, "body": 1 },
+ "FunctionExpression": { "parameters": 1, "body": 1 },
+ "CallExpression": { "arguments": 1 },
+ "ArrayExpression": 1,
+ "ObjectExpression": 1,
+ "ImportDeclaration": 1,
+ "flatTernaryExpressions": false,
+ "ignoreComments": false
+ }],
+ "key-spacing": ["error", { "beforeColon": false, "afterColon": true }],
+ "keyword-spacing": ["error", { "before": true, "after": true }],
+ "new-cap": ["error", { "newIsCap": true, "capIsNew": false }],
+ "new-parens": "error",
+ "no-array-constructor": "error",
+ "no-caller": "error",
+ "no-class-assign": "error",
+ "no-compare-neg-zero": "error",
+ "no-cond-assign": "error",
+ "no-const-assign": "error",
+ "no-constant-condition": ["error", { "checkLoops": false }],
+ "no-control-regex": "error",
+ "no-debugger": "error",
+ "no-delete-var": "error",
+ "no-dupe-args": "error",
+ "no-dupe-class-members": "error",
+ "no-dupe-keys": "error",
+ "no-duplicate-case": "error",
+ "no-empty-character-class": "error",
+ "no-empty-pattern": "error",
+ "no-eval": "error",
+ "no-ex-assign": "error",
+ "no-extend-native": "error",
+ "no-extra-bind": "error",
+ "no-extra-boolean-cast": "error",
+ "no-extra-parens": ["error", "functions"],
+ "no-fallthrough": "error",
+ "no-floating-decimal": "error",
+ "no-func-assign": "error",
+ "no-global-assign": "error",
+ "no-implied-eval": "error",
+ "no-inner-declarations": ["error", "functions"],
+ "no-invalid-regexp": "error",
+ "no-irregular-whitespace": "error",
+ "no-iterator": "error",
+ "no-label-var": "error",
+ "no-labels": ["error", { "allowLoop": false, "allowSwitch": false }],
+ "no-lone-blocks": "error",
+ "no-mixed-operators": ["error", {
+ "groups": [
+ ["==", "!=", "===", "!==", ">", ">=", "<", "<="],
+ ["&&", "||"],
+ ["in", "instanceof"]
+ ],
+ "allowSamePrecedence": true
+ }],
+ "no-mixed-spaces-and-tabs": "error",
+ "no-multi-spaces": "error",
+ "no-multi-str": "error",
+ "no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 0 }],
+ "no-negated-in-lhs": "error",
+ "no-new": "error",
+ "no-new-func": "error",
+ "no-new-object": "error",
+ "no-new-require": "error",
+ "no-new-symbol": "error",
+ "no-new-wrappers": "error",
+ "no-obj-calls": "error",
+ "no-octal": "error",
+ "no-octal-escape": "error",
+ "no-path-concat": "error",
+ "no-proto": "error",
+ "no-redeclare": "error",
+ "no-regex-spaces": "error",
+ "no-return-assign": ["error", "except-parens"],
+ "no-return-await": "error",
+ "no-self-assign": "error",
+ "no-self-compare": "error",
+ "no-sequences": "error",
+ "no-shadow-restricted-names": "error",
+ "no-sparse-arrays": "error",
+ "no-tabs": "error",
+ "no-template-curly-in-string": "error",
+ "no-this-before-super": "error",
+ "no-throw-literal": "error",
+ "no-trailing-spaces": "error",
+ "no-undef": "error",
+ "no-undef-init": "error",
+ "no-unexpected-multiline": "error",
+ "no-unmodified-loop-condition": "error",
+ "no-unneeded-ternary": ["error", { "defaultAssignment": false }],
+ "no-unreachable": "error",
+ "no-unsafe-finally": "error",
+ "no-unsafe-negation": "error",
+ "no-unused-expressions": ["error", { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true }],
+ "no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }],
+ "no-use-before-define": ["error", { "functions": false, "classes": false, "variables": false }],
+ "no-useless-call": "error",
+ "no-useless-computed-key": "error",
+ "no-useless-constructor": "error",
+ "no-useless-escape": "error",
+ "no-useless-rename": "error",
+ "no-useless-return": "error",
+ "no-whitespace-before-property": "error",
+ "no-with": "error",
+ "object-curly-spacing": ["error", "always"],
+ "object-property-newline": ["error", { "allowMultiplePropertiesPerLine": true }],
+ "one-var": ["error", { "initialized": "never" }],
+ "operator-linebreak": ["error", "after", { "overrides": { "?": "before", ":": "before" } }],
+ "padded-blocks": ["error", { "blocks": "never", "switches": "never", "classes": "never" }],
+ "prefer-promise-reject-errors": "error",
+ "quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }],
+ "rest-spread-spacing": ["error", "never"],
+ "semi": ["error", "never"],
+ "semi-spacing": ["error", { "before": false, "after": true }],
+ "space-before-blocks": ["error", "always"],
+ "space-before-function-paren": ["error", "always"],
+ "space-in-parens": ["error", "never"],
+ "space-infix-ops": "error",
+ "space-unary-ops": ["error", { "words": true, "nonwords": false }],
+ "spaced-comment": ["error", "always", {
+ "line": { "markers": ["*package", "!", "/", ",", "="] },
+ "block": { "balanced": true, "markers": ["*package", "!", ",", ":", "::", "flow-include"], "exceptions": ["*"] }
+ }],
+ "symbol-description": "error",
+ "template-curly-spacing": ["error", "never"],
+ "template-tag-spacing": ["error", "never"],
+ "unicode-bom": ["error", "never"],
+ "use-isnan": "error",
+ "valid-typeof": ["error", { "requireStringLiterals": true }],
+ "wrap-iife": ["error", "any", { "functionPrototypeMethods": true }],
+ "yield-star-spacing": ["error", "both"],
+ "yoda": ["error", "never"],
+
+ "import/export": "error",
+ "import/first": "error",
+ "import/no-duplicates": "error",
+ "import/no-named-default": "error",
+ "import/no-webpack-loader-syntax": "error",
+
+ "node/no-deprecated-api": "error",
+ "node/process-exit-as-throw": "error",
+
+ "promise/param-names": "error",
+
+ "standard/array-bracket-even-spacing": ["error", "either"],
+ "standard/computed-property-even-spacing": ["error", "even"],
+ "standard/no-callback-literal": "error",
+ "standard/object-curly-even-spacing": ["error", "either"]
+ }
+ }
+
\ No newline at end of file
diff --git a/html/observatory/.htaccess b/html/observatory/.htaccess
new file mode 100644
index 0000000..e2974bc
--- /dev/null
+++ b/html/observatory/.htaccess
@@ -0,0 +1,2 @@
+AddType application/json json
+AddType text/xml gexf
diff --git a/html/observatory/Staticfile b/html/observatory/Staticfile
new file mode 100644
index 0000000..e69de29
diff --git a/html/observatory/config_augov.json b/html/observatory/config_augov.json
new file mode 100644
index 0000000..b96efde
--- /dev/null
+++ b/html/observatory/config_augov.json
@@ -0,0 +1,37 @@
+{
+ "type": "network",
+ "data":"augov.gexf",
+ "version": "1.0",
+ "agency": {
+ "name": "Digital Transformation Agency",
+ "lifeEvents": [],
+ "websites":[
+ "www.dta.gov.au",
+ "www.homeaffairs.gov.au",
+ "www.humanservices.gov.au",
+ "www.australia.gov.au",
+ "www.passports.gov.au",
+ "www.casa.gov.au",
+ "www.apsc.gov.au",
+ "data.gov.au"
+ ]
+ },
+
+ "legend": {
+ "nodeLabel":"Government website",
+ "edgeLabel":"Link between two government websites",
+ "colorLabel":"Color is an automated grouping of sites"
+ },
+ "features": {
+ "search": {
+ "enabled": true
+ },
+ "hoverBehaviour": "dim",
+ "groupSelector": {
+ "enabled": true
+ }
+ },
+ "informationPanel": {
+ "groupByEdgeDirection": false
+ }
+}
diff --git a/html/observatory/css/designsystem.min.css b/html/observatory/css/designsystem.min.css
new file mode 100644
index 0000000..a291b64
--- /dev/null
+++ b/html/observatory/css/designsystem.min.css
@@ -0,0 +1,20 @@
+
+/*! @gov.au/core v3.4.2 *//*! @gov.au/accordion v7.0.8 */@media print{.au-accordion{border-color:#000 !important;color:#000 !important}.au-accordion__title{background:#fff !important;color:#000 !important;border:1px !important}.au-accordion__title:after{display:none}.au-accordion__body-wrapper{border-color:#000 !important}.au-accordion__body{height:auto !important;display:block !important}}.au-accordion{font-size:16px;font-size:1rem;line-height:1.5;display:block;border:1px solid gray;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#313131;padding:0}*+.au-accordion{margin-top:16px;margin-top:1rem}.au-accordion .au-accordion__title{background-color:#f5f5f5}.au-accordion.au-accordion--dark{border-color:#89afb8;color:#fff}.au-accordion.au-accordion--dark .au-accordion__title{background-color:#104f5f}.au-accordion+.au-accordion{margin-top:0;border-top:0}.au-body .au-accordion__title,.au-accordion__title{font-size:20px;font-size:1.25rem;line-height:1.2;padding:16px 40px 16px 16px;padding:1rem 2.5rem 1rem 1rem;width:100%;display:block;color:#00698f;text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto;font-weight:bold;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;cursor:pointer;border:none;text-align:left;font-family:inherit}.au-body .au-accordion__title:hover,.au-accordion__title:hover{text-decoration:none;color:#313131}.au-body .au-accordion__title:hover:after,.au-accordion__title:hover:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 128 128'%3E%3Cpath fill='%23313131' d='M64 0l64 64-16 16-64-64'/%3E%3Cpath fill='%23313131' d='M64 0l16 16-64 64L0 64'/%3E%3C/svg%3E")}.au-body .au-accordion__title:focus,.au-accordion__title:focus{outline:3px solid #9263DE;outline-offset:2px}.au-body .au-accordion__title::-moz-focus-inner,.au-accordion__title::-moz-focus-inner{border:0}.au-body .au-accordion__title:focus,.au-accordion__title:focus{z-index:100}.au-body .au-accordion__title::-webkit-details-marker,.au-accordion__title::-webkit-details-marker{display:none}.au-body .au-accordion__title:after,.au-accordion__title:after{content:' ';position:absolute;top:50%;margin-top:-8px;margin-top:-.5rem;right:16px;right:1rem;width:16px;width:1rem;height:16px;height:1rem;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 128 128'%3E%3Cpath fill='%2300698f' d='M64 0l64 64-16 16-64-64'/%3E%3Cpath fill='%2300698f' d='M64 0l16 16-64 64L0 64'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:center;z-index:101;-webkit-transition:-webkit-transform 0.25s ease-in;transition:-webkit-transform 0.25s ease-in;transition:transform 0.25s ease-in;transition:transform 0.25s ease-in, -webkit-transform 0.25s ease-in}.au-body .au-accordion__title.au-accordion--closed:after,.au-accordion__title.au-accordion--closed:after{-webkit-transform:rotate(-180deg);-ms-transform:rotate(-180deg);transform:rotate(-180deg)}.ie8 .au-body .au-accordion__title:after,.lt-ie8 .au-body .au-accordion__title:after,.ie8 .au-accordion__title:after,.lt-ie8 .au-accordion__title:after{content:' ▼ '}.ie8 .au-body .au-accordion__title.au-accordion--open:after,.lt-ie8 .au-body .au-accordion__title.au-accordion--open:after,.ie8 .au-accordion__title.au-accordion--open:after,.lt-ie8 .au-accordion__title.au-accordion--open:after{content:' ▲ '}.au-body.au-body--dark .au-accordion__title,.au-accordion.au-accordion--dark .au-accordion__title{color:#61daff}.au-body.au-body--dark .au-accordion__title:hover,.au-accordion.au-accordion--dark .au-accordion__title:hover{color:#fff}.au-body.au-body--dark .au-accordion__title:hover:after,.au-accordion.au-accordion--dark .au-accordion__title:hover:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 128 128'%3E %3Cpath fill='%23fff' d='M64 0l64 64-16 16-64-64'/%3E %3Cpath fill='%23fff' d='M64 0l16 16-64 64L0 64'/%3E%3C/svg%3E")}.au-body.au-body--dark .au-accordion__title:focus,.au-accordion.au-accordion--dark .au-accordion__title:focus{outline:3px solid #C390F9}.au-body.au-body--dark .au-accordion__title::-moz-focus-inner,.au-accordion.au-accordion--dark .au-accordion__title::-moz-focus-inner{border:0}.au-body.au-body--dark .au-accordion__title:after,.au-accordion.au-accordion--dark .au-accordion__title:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 128 128'%3E %3Cpath fill='%2361daff' d='M64 0l64 64-16 16-64-64'/%3E %3Cpath fill='%2361daff' d='M64 0l16 16-64 64L0 64'/%3E%3C/svg%3E")}.au-accordion__body{font-size:16px;font-size:1rem;line-height:1.5;overflow:hidden}.js .au-accordion__body.au-accordion--open{display:block;height:auto}.js .au-accordion__body.au-accordion--closed{display:none;height:0}.au-accordion__body-wrapper{padding:16px;padding:1rem;border-top:1px solid gray}.au-accordion--dark .au-accordion__body-wrapper{border-top:1px solid #89afb8}.au-accordion-group{list-style:none;padding:0}/*! @gov.au/body v2.2.0 */@media print{.au-body *,.au-body{text-shadow:none !important;color:#000 !important;background-color:transparent !important;-webkit-box-shadow:none !important;box-shadow:none !important;border-color:#000 !important}.au-body a,.au-body a:visited{text-decoration:underline}.au-body a[href]:after{content:" (" attr(href) ")" !important;display:inline !important}.au-body a[href^="javascript:"]:after,.au-body a[href^="#"]:after{content:"" !important}.au-body abbr[title]:after{content:" (" attr(title) ")"}.au-body pre,.au-body blockquote{border:1px solid #000;padding:6px;page-break-inside:avoid}.au-body thead{display:table-header-group}.au-body tr,.au-body img{page-break-inside:avoid}.au-body img{max-width:100% !important}.au-body p,.au-body h2,.au-body h3{orphans:3;widows:3}.au-body h2,.au-body h3{page-break-after:avoid}.au-body p a{word-wrap:break-word}.au-body select{background:#fff !important}}.au-body{font-size:16px;font-size:1rem;line-height:1.5;margin:0;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;-ms-text-size-adjust:100%;text-size-adjust:100%;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#313131;background-color:#fff}.au-body a{color:#00698f;text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}.au-body a:hover{color:#313131;text-decoration:none}.au-body a:focus{outline:3px solid #9263DE;outline-offset:2px}.au-body a::-moz-focus-inner{border:0}.au-body [tabindex="0"]:focus,.au-body :target{outline:3px solid #9263DE;outline-offset:2px}.au-body mark{color:#fff;background-color:#00698f}.au-body ::-moz-selection{color:#fff;background-color:rgba(0,105,143,0.99)}.au-body ::selection{color:#fff;background-color:rgba(0,105,143,0.99)}.au-body img::-moz-selection,.au-body video::-moz-selection,.au-body iframe::-moz-selection{background-color:rgba(0,105,143,0.75)}.au-body img::selection,.au-body video::selection,.au-body iframe::selection{background-color:rgba(0,105,143,0.75)}.au-body p{max-width:42em;margin:0}.au-body *+p{margin-top:24px;margin-top:1.5rem}.au-body ul:not([class]),.au-body ol:not([class]),.au-body dl:not([class]),.au-body pre{margin:0}.au-body *+ul:not([class]),.au-body *+ol:not([class]),.au-body *+dl:not([class]),.au-body *+pre{margin-top:24px;margin-top:1.5rem}.au-body ul:not([class])>li,.au-body ol:not([class])>li{margin-top:8px;margin-top:.5rem}.au-body ul:not([class])>li>ul:not([class]),.au-body ul:not([class])>li>ol:not([class]),.au-body ol:not([class])>li>ul:not([class]),.au-body ol:not([class])>li>ol:not([class]){margin-top:8px;margin-top:.5rem}.au-body ul:not([class])>ul:not([class]),.au-body ol:not([class])>ul:not([class]){list-style-type:disc}.au-body dl:not([class])>dd{margin-top:8px;margin-top:.5rem;padding-left:8px;padding-left:.5rem;margin-left:0;border-left:solid 1px}.au-body dl:not([class])>dt{margin-top:24px;margin-top:1.5rem;font-weight:bold}.au-body dl:not([class])>dt:first-of-type{margin-top:0}.au-body .written-by:after{content:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEiIHZpZXdCb3g9IjAgMCA2NTggMTgiPjx0ZXh0IHg9IjEzIiB5PSIxMyIgZm9udC1zaXplPSIxMyI+TWVzc3JzLCBEb20sIFBhZ2V5LCBUcmViLCBQYXQgYW5kIEtsZXBhcyBhcmUgcHJvdWQgdG8gcHJlc2VudCB0aGUgR09MRCBkZXNpZ24gc3lzdGVtLiAtIE1pc2NoaWVmIG1hbmFnZWQ8L3RleHQ+PC9zdmc+");color:#BADA55}.au-body em,.au-body i{font-style:italic}.au-body strong,.au-body b{font-weight:bold}.au-body small{font-size:14px;font-size:.875rem;line-height:1.42857143}.au-body s,.au-body del{text-decoration:line-through}.au-body ins{-webkit-text-decoration-line:underline;text-decoration-line:underline;-webkit-text-decoration-style:dashed;text-decoration-style:dashed;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}.au-body dfn{font-style:normal}.au-body abbr,.au-body abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.au-body abbr[title]{cursor:help}.au-body a abbr{padding-bottom:1px}.au-body var{padding:0 1px;font-style:italic;font-family:serif}.au-body var sup,.au-body var sub{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;padding:0 1px}.au-body sub,.au-body sup{font-size:14px;font-size:.875rem;line-height:1.14285714;position:relative;vertical-align:baseline}.au-body sub{bottom:-0.25em}.au-body sup{top:-0.5em}.au-body kbd,.au-body code,.au-body samp{font-size:14px;font-size:.875rem;line-height:1.42857143;padding:4px;padding:.25rem;font-family:"SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;display:inline-block;border-radius:4px;background-color:#f5f5f5;color:#313131}.au-body pre{font-family:"SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace}.au-body pre code{padding:16px;padding:1rem;display:block;-moz-tab-size:4;-o-tab-size:4;tab-size:4}.au-body hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible;border:none;border-top:1px solid gray;margin-bottom:24px;margin-bottom:1.5rem}.au-body *+hr{margin-top:24px;margin-top:1.5rem}.au-body.au-body--alt{background:#ebebeb}.au-body.au-body--alt kbd,.au-body.au-body--alt code,.au-body.au-body--alt samp{background-color:#e0e0e0}.au-body.au-body--dark{background:#135E70;color:#fff}.au-body.au-body--dark ::-moz-selection{color:#135E70;background-color:rgba(97,218,255,0.99)}.au-body.au-body--dark ::selection{color:#135E70;background-color:rgba(97,218,255,0.99)}.au-body.au-body--dark img::-moz-selection,.au-body.au-body--dark video::-moz-selection,.au-body.au-body--dark iframe::-moz-selection{background-color:rgba(97,218,255,0.75)}.au-body.au-body--dark img::selection,.au-body.au-body--dark video::selection,.au-body.au-body--dark iframe::selection{background-color:rgba(97,218,255,0.75)}.au-body.au-body--dark a{color:#61daff}.au-body.au-body--dark a:hover{color:#fff}.au-body.au-body--dark a:focus{outline:3px solid #C390F9}.au-body.au-body--dark a::-moz-focus-inner{border:0}.au-body.au-body--dark [tabindex="0"]:focus,.au-body.au-body--dark :target{outline:3px solid #C390F9}.au-body.au-body--dark mark{background-color:#61daff;color:#135E70}.au-body.au-body--dark hr{border-top-color:#89afb8}.au-body.au-body--dark code,.au-body.au-body--dark kbd,.au-body.au-body--dark samp{color:#fff;background-color:#104f5f}.au-body.au-body--dark.au-body--alt{background:#0d414d}.au-body.au-body--dark.au-body--alt code,.au-body.au-body--dark.au-body--alt kbd,.au-body.au-body--dark.au-body--alt samp{background-color:#0a323c}/*! @gov.au/link-list v3.0.8 */.au-link-list{font-size:16px;font-size:1rem;line-height:1.5;display:block;list-style-type:none;margin:0;padding:4px 0;padding:.25rem 0}.au-body .au-link-list{margin:0;padding:4px 0;padding:.25rem 0}.au-link-list>li{display:block;margin:4px;margin:.25rem}.au-link-list.au-link-list--inline{display:inline-block}.au-link-list.au-link-list--inline>li{display:inline-block}/*! @gov.au/breadcrumbs v3.0.5 */@media print{.au-breadcrumbs>.au-link-list>li:after{content:">" !important;background-image:none !important}}.au-breadcrumbs{font-size:14px;font-size:.875rem;line-height:1.14285714;width:100%;margin:0;color:#313131;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"}*+.au-breadcrumbs{margin-top:16px;margin-top:1rem}@media (min-width: 768px){.au-breadcrumbs{display:inline-block}}.au-breadcrumbs>.au-link-list>li{margin:0}.au-breadcrumbs>.au-link-list>li:after{content:' ';display:inline-block;width:8px;width:.5rem;height:8px;height:.5rem;margin:0 8px;margin:0 .5rem;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 128 128'%3E%3Cpath fill='gray' d='M128 64l-64 64-16-16 64-64'/%3E%3Cpath fill='gray' d='M128 64l-16 16-64-64L64 0'/%3E%3C/svg%3E");background-size:100%;background-repeat:no-repeat}.au-breadcrumbs>.au-link-list>li:last-child:after{display:none}.ie8 .au-breadcrumbs>.au-link-list>li:after,.lt-ie8 .au-breadcrumbs>.au-link-list>li:after{content:' > ';display:inline-block}.au-breadcrumbs.au-breadcrumbs--dark{color:#fff}.au-breadcrumbs.au-breadcrumbs--dark>.au-link-list>li:not(:last-child):after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 128 128'%3E%3Cpath fill='%2389afb8' d='M128 64l-64 64-16-16 64-64'/%3E%3Cpath fill='%2389afb8' d='M128 64l-16 16-64-64L64 0'/%3E%3C/svg%3E")}/*! @gov.au/buttons v3.0.7 */@media print{.au-btn{background-color:#fff !important;border:2px solid #000 !important;color:#000 !important;text-decoration:none !important}.au-btn[disabled]{background-color:#ccc !important;border:2px solid #ccc !important}.au-btn:disabled{background-color:#ccc !important;border:2px solid #ccc !important}}.au-btn,a.au-btn{font-size:16px;font-size:1rem;line-height:1.5;padding:8px 24px;padding:.5rem 1.5rem;display:inline-block;-webkit-appearance:none;-moz-appearance:none;appearance:none;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#fff;text-decoration:none;border-radius:4px;background-color:#00698f;border:3px solid #00698f;cursor:pointer;vertical-align:middle;-webkit-transition:background 0.1s ease, border 0.1s ease, color 0.1s ease;transition:background 0.1s ease, border 0.1s ease, color 0.1s ease}.au-body .au-btn,.au-body a.au-btn{color:#fff;text-decoration:none}.au-btn.au-btn--block+.au-btn.au-btn--block,.au-btn.au-btn--block+a.au-btn.au-btn--block,a.au-btn.au-btn--block+.au-btn.au-btn--block,a.au-btn.au-btn--block+a.au-btn.au-btn--block{margin-top:8px;margin-top:.5rem}.au-btn:focus,a.au-btn:focus{outline:3px solid #9263DE;outline-offset:2px}.au-btn::-moz-focus-inner,a.au-btn::-moz-focus-inner{border:0}.au-btn:focus,a.au-btn:focus{border-radius:0}.au-btn[disabled],a.au-btn[disabled]{cursor:not-allowed;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";opacity:0.3}.au-btn:disabled,a.au-btn:disabled{cursor:not-allowed;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";opacity:0.3}.au-btn:hover:not(:disabled),a.au-btn:hover:not(:disabled){background-color:#313131;border-color:#313131;text-decoration:underline;color:#fff}.ie8 .au-btn:hover,.ie8 a.au-btn:hover{background-color:#313131;border-color:#313131;color:#fff;text-decoration:underline}.au-btn.au-btn--dark,a.au-btn.au-btn--dark{color:#135E70;background-color:#61daff;border-color:#61daff}.au-body .au-btn.au-btn--dark,.au-body a.au-btn.au-btn--dark{color:#135E70}.au-btn.au-btn--dark:hover:not(:disabled),a.au-btn.au-btn--dark:hover:not(:disabled){color:#135E70;border-color:#fff;background-color:#fff}.ie8 .au-btn.au-btn--dark:hover,.ie8 a.au-btn.au-btn--dark:hover{color:#135E70;border-color:#fff;background-color:#fff}.au-btn.au-btn--dark:focus,a.au-btn.au-btn--dark:focus{outline:3px solid #C390F9}.au-btn.au-btn--dark::-moz-focus-inner,a.au-btn.au-btn--dark::-moz-focus-inner{border:0}.au-btn.au-btn--secondary,a.au-btn.au-btn--secondary{color:#00698f;background-color:transparent;border-color:#00698f}.au-body .au-btn.au-btn--secondary,.au-body a.au-btn.au-btn--secondary{color:#00698f}.ie8 .au-body .au-btn.au-btn--secondary:hover,.ie8 .au-body a.au-btn.au-btn--secondary:hover{color:#fff}.au-btn.au-btn--secondary:hover:not(:disabled),a.au-btn.au-btn--secondary:hover:not(:disabled){background-color:transparent;border-color:#313131;color:#313131}.au-btn.au-btn--secondary.au-btn--dark,a.au-btn.au-btn--secondary.au-btn--dark{border-color:#61daff;color:#61daff}.au-btn.au-btn--secondary.au-btn--dark:hover:not(:disabled),a.au-btn.au-btn--secondary.au-btn--dark:hover:not(:disabled){border-color:#fff;color:#fff}.ie8 .au-body .au-btn.au-btn--secondary.au-btn--dark:hover,.ie8 .au-body a.au-btn.au-btn--secondary.au-btn--dark:hover{color:#135E70}.au-btn.au-btn--tertiary,a.au-btn.au-btn--tertiary{color:#00698f;background-color:transparent;border-color:transparent;text-decoration:underline}.au-btn.au-btn--tertiary:hover:not(:disabled),a.au-btn.au-btn--tertiary:hover:not(:disabled){background-color:transparent;color:#313131;border-color:transparent;text-decoration:none}.au-btn.au-btn--tertiary.au-btn--dark,a.au-btn.au-btn--tertiary.au-btn--dark{color:#61daff}.au-btn.au-btn--tertiary.au-btn--dark:hover:not(:disabled),a.au-btn.au-btn--tertiary.au-btn--dark:hover:not(:disabled){color:#fff}.au-btn.au-btn--pride,a.au-btn.au-btn--pride{background:-webkit-gradient(linear, left top, left bottom, color-stop(16.66666667%, rgba(255,62,24,0.5)), color-stop(16.66666667%, rgba(252,154,0,0.5)), color-stop(33.33333333%, rgba(252,154,0,0.52)), color-stop(33.33333333%, rgba(255,216,0,0.5)), color-stop(33.33333333%, rgba(255,216,0,0.5)), color-stop(50%, rgba(255,216,0,0.5)), color-stop(50%, rgba(57,234,124,0.5)), color-stop(66.66666667%, rgba(57,234,124,0.5)), color-stop(66.66666667%, rgba(11,178,255,0.5)), color-stop(83.33333333%, rgba(11,178,255,0.5)), color-stop(83.33333333%, rgba(152,90,255,0.5)));background:linear-gradient(to bottom, rgba(255,62,24,0.5) 16.66666667%, rgba(252,154,0,0.5) 16.66666667%, rgba(252,154,0,0.52) 33.33333333%, rgba(255,216,0,0.5) 33.33333333%, rgba(255,216,0,0.5) 33.33333333%, rgba(255,216,0,0.5) 50%, rgba(57,234,124,0.5) 50%, rgba(57,234,124,0.5) 66.66666667%, rgba(11,178,255,0.5) 66.66666667%, rgba(11,178,255,0.5) 83.33333333%, rgba(152,90,255,0.5) 83.33333333%);color:#313131}.au-btn.au-btn--block,a.au-btn.au-btn--block{display:block;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center}/*! @gov.au/cta-link v2.2.0 */@media print{.au-cta-link{color:#000 !important}.au-cta-link:after{background-image:none !important;content:' > ' !important;border:none !important;-webkit-transform:rotate(0deg) !important;-ms-transform:rotate(0deg) !important;transform:rotate(0deg) !important}}.au-cta-link{font-size:20px;font-size:1.25rem;line-height:1.6;margin-top:16px;margin-top:1rem;font-weight:bold;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#00698f;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:none;padding:0;cursor:pointer;text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}.au-cta-link:focus{outline:3px solid #9263DE;outline-offset:2px}.au-cta-link::-moz-focus-inner{border:0}.au-cta-link:after{content:' ';width:16px;width:1rem;height:16px;height:1rem;margin:0 4px 0 3px;margin:0 .25rem 0 .2rem;-webkit-transition:margin 0.2s ease;transition:margin 0.2s ease;display:inline-block;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 128 128'%3E%3Cpath fill='%2300698f' d='M128 64l-64 64-16-16 64-64'/%3E%3Cpath fill='%2300698f' d='M128 64l-16 16-64-64L64 0'/%3E%3C/svg%3E")}.ie8 .au-cta-link:after,.lt-ie8 .au-cta-link:after{content:' > '}.au-cta-link:hover{color:#313131;text-decoration:none}.au-cta-link:hover:after{margin-left:6px;margin-left:.4rem;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 128 128'%3E%3Cpath fill='%23313131' d='M128 64l-64 64-16-16 64-64'/%3E%3Cpath fill='%23313131' d='M128 64l-16 16-64-64L64 0'/%3E%3C/svg%3E")}.au-cta-link.au-cta-link--dark{color:#61daff}.au-cta-link.au-cta-link--dark:focus{outline:3px solid #C390F9}.au-cta-link.au-cta-link--dark::-moz-focus-inner{border:0}.au-cta-link.au-cta-link--dark:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 128 128'%3E%3Cpath fill='%2361daff' d='M128 64l-64 64-16-16 64-64'/%3E%3Cpath fill='%2361daff' d='M128 64l-16 16-64-64L64 0'/%3E%3C/svg%3E")}.au-cta-link.au-cta-link--dark:hover{color:#fff}.au-cta-link.au-cta-link--dark:hover:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 128 128'%3E%3Cpath fill='%23fff' d='M128 64l-64 64-16-16 64-64'/%3E%3Cpath fill='%23fff' d='M128 64l-16 16-64-64L64 0'/%3E%3C/svg%3E")}/*! @gov.au/callout v3.0.2 */@media print{.au-callout{border-left-width:16px !important;border-left-width:1rem !important;border:1px solid #000 !important;color:#000 !important;background-color:transparent !important}}.au-callout{font-size:16px;font-size:1rem;line-height:1.5;padding:24px;padding:1.5rem;border-left:4px solid gray;border-left:.25rem solid gray;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#313131;background-color:#f5f5f5;word-wrap:break-word}*+.au-callout{margin-top:32px;margin-top:2rem}.au-callout p{margin:0}.au-callout *+p{margin-top:16px;margin-top:1rem}.au-callout+p{margin-top:32px;margin-top:2rem}.au-callout.au-callout--dark{color:#fff;border-color:#89afb8;background-color:#104f5f}.au-callout.au-callout--alt{background-color:#e0e0e0}.au-callout.au-callout--dark.au-callout--alt{background-color:#0a323c}.au-callout__heading{font-size:20px;font-size:1.25rem;line-height:1.6;margin:0}.au-callout__heading.au-callout__heading--sronly{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.au-callout__heading.au-callout__heading--sronly+*{margin-top:0}.au-callout--calendar-event{background-color:#f5f5f5}.au-callout--calendar-event__lede{font-size:16px;font-size:1rem;line-height:1;margin:0}.au-callout--calendar-event__time,.au-callout--calendar-event__name{font-size:32px;font-size:2rem;line-height:1.25}.au-callout--calendar-event__time{font-weight:bold}.au-callout--calendar-event__lede,.au-callout--calendar-event__time,.au-callout--calendar-event__name{display:block}*+.au-callout--calendar-event__time,*+.au-callout--calendar-event__name,*+.au-callout--calendar-event__lede{margin-top:8px;margin-top:.5rem}/*! @gov.au/control-input v3.0.1 */@media print{.au-control-input__text{color:#000 !important}.au-control-input__text:before,.au-control-input__text:after{display:none !important}}.au-control-input{display:inline-block;position:relative}.au-control-input.au-control-input--block{display:block}.au-control-input.au-control-input--block:before,.au-control-input.au-control-input--block:after{content:" ";display:table}.au-control-input.au-control-input--block:after{clear:both}.au-control-input.au-control-input--block+.au-control-input--block{margin-top:16px;margin-top:1rem}.au-control-input__input{position:absolute;left:8px;left:.5rem;top:8px;top:.5rem;cursor:pointer;margin:0}.au-control-input--small .au-control-input__input{left:4px;left:.25rem;top:4px;top:.25rem}.au-control-input__input+.au-control-input__text{cursor:pointer}.au-control-input__input:invalid+.au-control-input__text{background-color:#fdf2f2}.au-control-input__input:invalid+.au-control-input__text:after{border-color:#d60000}.au-control-input--invalid .au-control-input__input+.au-control-input__text{background-color:#fdf2f2}.au-control-input--invalid .au-control-input__input+.au-control-input__text:after{border-color:#d60000}.au-control-input--dark .au-control-input__input:invalid+.au-control-input__text{background-color:#30505f}.au-control-input--dark.au-control-input--invalid .au-control-input__input+.au-control-input__text{background-color:#30505f}.au-control-input--alt.au-control-input--invalid .au-control-input__input+.au-control-input__text{background-color:#f0d0d0}.au-control-input--dark.au-control-input--alt .au-control-input__input:invalid+.au-control-input__text{background-color:#2b3742}.au-control-input--alt.au-control-input--dark.au-control-input--invalid .au-control-input__input+.au-control-input__text{background-color:#2b3742}.au-control-input--valid .au-control-input__input+.au-control-input__text{background-color:#f3faf8}.au-control-input--valid .au-control-input__input+.au-control-input__text:after{border-color:#0b996c}.au-control-input--dark.au-control-input--valid .au-control-input__input+.au-control-input__text{background-color:#12676f}.au-control-input--alt.au-control-input--valid .au-control-input__input+.au-control-input__text{background-color:#d2e7e0}.au-control-input--alt.au-control-input--dark.au-control-input--valid .au-control-input__input+.au-control-input__text{background-color:#0d4e52}.au-control-input__input[type=radio]+.au-control-input__text:before,.au-control-input__input[type=radio]+.au-control-input__text:after{border-radius:50%}.au-control-input__input[disabled]{cursor:not-allowed}.au-control-input__input[disabled]+.au-control-input__text{cursor:not-allowed}.au-control-input__input[disabled]+.au-control-input__text{color:#636363}.au-control-input__input:disabled{cursor:not-allowed}.au-control-input__input:disabled+.au-control-input__text{cursor:not-allowed}.au-control-input__input:disabled+.au-control-input__text{color:#636363}.au-control-input--dark .au-control-input__input[disabled]+.au-control-input__text{color:#b8cfd4}.au-control-input--dark .au-control-input__input:disabled+.au-control-input__text{color:#b8cfd4}.au-control-input__input[type=checkbox]+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23313131' d='M0,0h32v32H0V0z'/%3E%3Cpath fill='%23fff' d='M2,2h28v28H2V2z'/%3E%3C/svg%3E")}.au-control-input__input[type=checkbox]+.au-control-input__text:after{background-image:none}.au-control-input__input[type=checkbox]:checked+.au-control-input__text:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23313131' d='M25.6,11.4c0.2-0.2,0.2-0.5,0-0.7l-2.3-2.3c-0.2-0.2-0.5-0.2-0.7,0L14,17l-3.6-3.6c-0.2-0.2-0.5-0.2-0.7,0l-2.3,2.3 c-0.2,0.2-0.2,0.5,0,0.7l6.3,6.3c0.2,0.2,0.5,0.2,0.7,0L25.6,11.4L25.6,11.4z'/%3E%3C/svg%3E")}.au-control-input--alt .au-control-input__input[type=checkbox]+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23313131' d='M0,0h32v32H0V0z'/%3E%3Cpath fill='%23ebebeb' d='M2,2h28v28H2V2z'/%3E%3C/svg%3E")}.au-control-input--alt .au-control-input__input[type=checkbox]:disabled+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23cecece' d='M0,0h32v32H0V0z'/%3E%3Cpath fill='%23e0e0e0' d='M2,2h28v28H2V2z'/%3E%3C/svg%3E")}.au-control-input__input[type=checkbox]:disabled+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23cecece' d='M0,0h32v32H0V0z'/%3E%3Cpath fill='%23ebebeb' d='M2,2h28v28H2V2z'/%3E%3C/svg%3E")}.au-control-input__input[type=checkbox]:disabled:checked+.au-control-input__text:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23cecece' d='M25.6,11.4c0.2-0.2,0.2-0.5,0-0.7l-2.3-2.3c-0.2-0.2-0.5-0.2-0.7,0L14,17l-3.6-3.6c-0.2-0.2-0.5-0.2-0.7,0l-2.3,2.3 c-0.2,0.2-0.2,0.5,0,0.7l6.3,6.3c0.2,0.2,0.5,0.2,0.7,0L25.6,11.4L25.6,11.4z'/%3E%3C/svg%3E")}.au-control-input__input[type=checkbox]:focus+.au-control-input__text:before{outline:3px solid #9263DE;outline-offset:2px;outline-offset:2px}.au-control-input--dark .au-control-input__input[type=checkbox]+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23fff' d='M0,0h32v32H0V0z'/%3E%3Cpath fill='%23135E70' d='M2,2h28v28H2V2z'/%3E%3C/svg%3E")}.au-control-input--dark .au-control-input__input[type=checkbox]:checked+.au-control-input__text:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23fff' d='M25.6,11.4c0.2-0.2,0.2-0.5,0-0.7l-2.3-2.3c-0.2-0.2-0.5-0.2-0.7,0L14,17l-3.6-3.6c-0.2-0.2-0.5-0.2-0.7,0l-2.3,2.3 c-0.2,0.2-0.2,0.5,0,0.7l6.3,6.3c0.2,0.2,0.5,0.2,0.7,0L25.6,11.4L25.6,11.4z'/%3E%3C/svg%3E")}.au-control-input--dark .au-control-input__input[type=checkbox]:disabled+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%2340727f' d='M0,0h32v32H0V0z'/%3E%3Cpath fill='%23104f5f' d='M2,2h28v28H2V2z'/%3E%3C/svg%3E")}.au-control-input--dark .au-control-input__input[type=checkbox]:disabled:checked+.au-control-input__text:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%2340727f' d='M25.6,11.4c0.2-0.2,0.2-0.5,0-0.7l-2.3-2.3c-0.2-0.2-0.5-0.2-0.7,0L14,17l-3.6-3.6c-0.2-0.2-0.5-0.2-0.7,0l-2.3,2.3 c-0.2,0.2-0.2,0.5,0,0.7l6.3,6.3c0.2,0.2,0.5,0.2,0.7,0L25.6,11.4L25.6,11.4z'/%3E%3C/svg%3E")}.au-control-input--dark .au-control-input__input[type=checkbox]:focus+.au-control-input__text:before{outline:3px solid #C390F9;outline-offset:2px}.au-control-input--alt.au-control-input--dark .au-control-input__input[type=checkbox]+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%23fff' d='M0,0h32v32H0V0z'/%3E%3Cpath fill='%230d414d' d='M2,2h28v28H2V2z'/%3E%3C/svg%3E")}.au-control-input--alt.au-control-input--dark .au-control-input__input[type=checkbox]:disabled+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%233d6771' d='M0,0h32v32H0V0z'/%3E%3Cpath fill='%230a323c' d='M2,2h28v28H2V2z'/%3E%3C/svg%3E")}.au-control-input--alt.au-control-input--dark .au-control-input__input[type=checkbox]:disabled:checked+.au-control-input__text:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath fill='%233d6771' d='M25.6,11.4c0.2-0.2,0.2-0.5,0-0.7l-2.3-2.3c-0.2-0.2-0.5-0.2-0.7,0L14,17l-3.6-3.6c-0.2-0.2-0.5-0.2-0.7,0l-2.3,2.3 c-0.2,0.2-0.2,0.5,0,0.7l6.3,6.3c0.2,0.2,0.5,0.2,0.7,0L25.6,11.4L25.6,11.4z'/%3E%3C/svg%3E")}.au-control-input__input[type=radio]+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%23313131' cx='16' cy='16' r='16'/%3E%3Ccircle fill='%23fff' cx='16' cy='16' r='14'/%3E%3C/svg%3E")}.au-control-input__input[type=radio]+.au-control-input__text:after{background-image:none}.au-control-input__input[type=radio]:checked+.au-control-input__text:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%23313131' cx='16' cy='16' r='11'/%3E%3C/svg%3E")}.au-control-input--alt .au-control-input__input[type=radio]+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%23313131' cx='16' cy='16' r='16'/%3E%3Ccircle fill='%23ebebeb' cx='16' cy='16' r='14'/%3E%3C/svg%3E")}.au-control-input--alt .au-control-input__input[type=radio]:disabled+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%23cecece' cx='16' cy='16' r='16'/%3E%3Ccircle fill='%23e0e0e0' cx='16' cy='16' r='14'/%3E%3C/svg%3E")}.au-control-input__input[type=radio]:disabled+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%23cecece' cx='16' cy='16' r='16'/%3E%3Ccircle fill='%23ebebeb' cx='16' cy='16' r='14'/%3E%3C/svg%3E")}.au-control-input__input[type=radio]:disabled:checked+.au-control-input__text:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%23cecece' cx='16' cy='16' r='11'/%3E%3C/svg%3E")}.au-control-input__input[type=radio]:focus+.au-control-input__text:before{-webkit-box-shadow:0 0 0 4px #9263DE;box-shadow:0 0 0 4px #9263DE;-webkit-box-shadow:0 0 0 .25rem #9263DE;box-shadow:0 0 0 .25rem #9263DE}.ie8 .au-control-input__input[type=radio]:focus+.au-control-input__text:before,.lt-ie8 .au-control-input__input[type=radio]:focus+.au-control-input__text:before{outline:3px solid #9263DE;outline-offset:2px;outline-offset:2px}.au-control-input--dark .au-control-input__input[type=radio]+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%23fff' cx='16' cy='16' r='16'/%3E%3Ccircle fill='%23135E70' cx='16' cy='16' r='14'/%3E%3C/svg%3E")}.au-control-input--dark .au-control-input__input[type=radio]:checked+.au-control-input__text:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%23fff' cx='16' cy='16' r='11'/%3E%3C/svg%3E")}.au-control-input--dark .au-control-input__input[type=radio]:disabled+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%2340727f' cx='16' cy='16' r='16'/%3E%3Ccircle fill='%23104f5f' cx='16' cy='16' r='14'/%3E%3C/svg%3E")}.au-control-input--dark .au-control-input__input[type=radio]:disabled:checked+.au-control-input__text:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%2340727f' cx='16' cy='16' r='11'/%3E%3C/svg%3E")}.au-control-input--dark .au-control-input__input[type=radio]:focus+.au-control-input__text:before{-webkit-box-shadow:0 0 0 4px #C390F9;box-shadow:0 0 0 4px #C390F9;-webkit-box-shadow:0 0 0 .25rem #C390F9;box-shadow:0 0 0 .25rem #C390F9}.ie8 .au-control-input--dark .au-control-input__input[type=radio]:focus+.au-control-input__text:before,.lt-ie8 .au-control-input--dark .au-control-input__input[type=radio]:focus+.au-control-input__text:before{outline:3px solid #C390F9;outline-offset:2px}.au-control-input--alt.au-control-input--dark .au-control-input__input[type=radio]+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%23fff' cx='16' cy='16' r='16'/%3E%3Ccircle fill='%230d414d' cx='16' cy='16' r='14'/%3E%3C/svg%3E")}.au-control-input--alt.au-control-input--dark .au-control-input__input[type=radio]:disabled+.au-control-input__text:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%233d6771' cx='16' cy='16' r='16'/%3E%3Ccircle fill='%230a323c' cx='16' cy='16' r='14'/%3E%3C/svg%3E")}.au-control-input--alt.au-control-input--dark .au-control-input__input[type=radio]:disabled:checked+.au-control-input__text:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle fill='%233d6771' cx='16' cy='16' r='11'/%3E%3C/svg%3E")}.au-control-input__text{font-size:16px;font-size:1rem;line-height:1.5;padding:4px 8px 8px 40px;padding:.25rem .5rem .5rem 2.5rem;margin-right:16px;margin-right:1rem;display:block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#313131}.au-control-input__text:before,.au-control-input__text:after{width:38px;width:2.375rem;height:38px;height:2.375rem;content:' ';display:block;position:absolute;-webkit-box-sizing:border-box;box-sizing:border-box;background-repeat:no-repeat;z-index:100;left:-3px;top:-3px;border:3px solid transparent}.au-control-input--small .au-control-input__text:before,.au-control-input--small .au-control-input__text:after{width:28px;width:1.75rem;height:28px;height:1.75rem}.au-control-input--small .au-control-input__text{padding:3px 8px 0 31px;padding:.2rem .5rem 0 1.95rem;margin-right:16px;margin-right:1rem;font-size:16px;font-size:1rem;line-height:1}.au-control-input__text:after{z-index:101}.au-control-input--dark .au-control-input__text{color:#fff}/*! @gov.au/direction-links v2.2.0 */@media print{.au-direction-link{color:#000 !important}.au-direction-link:after{content:'→' !important}.au-direction-link--left:before{content:'←' !important}.au-direction-link--up:after{content:'↑' !important}.au-direction-link--down:after{content:'↓' !important}}.au-direction-link{font-size:16px;font-size:1rem;line-height:1.5;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#00698f;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:none;padding:0;cursor:pointer;text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}.au-direction-link:hover{text-decoration:none;color:#313131}.au-direction-link:focus{outline:3px solid #9263DE;outline-offset:2px}.au-direction-link::-moz-focus-inner{border:0}.au-direction-link.au-direction-link--dark{color:#61daff}.au-direction-link.au-direction-link--dark:hover{color:#fff}.au-direction-link.au-direction-link--dark:focus{outline:3px solid #C390F9}.au-direction-link.au-direction-link--dark::-moz-focus-inner{border:0}.au-direction-link:after{width:16px;width:1rem;height:16px;height:1rem;margin:0 0 0 4px;margin:0 0 0 .25rem;content:'→';display:inline-block;width:auto;height:auto}.au-direction-link--left:after{display:none}.au-direction-link--left:before{content:'←';display:inline-block;width:16px;width:1rem;height:16px;height:1rem;margin:0 4px 0 0;margin:0 .25rem 0 0}.au-direction-link--up:after{content:'↑'}.au-direction-link--down:after{content:'↓'}/*! @gov.au/footer v3.0.5 */@media print{.au-footer{color:#000 !important;background:#fff !important;border-color:#000 !important}}.au-footer{font-size:16px;font-size:1rem;line-height:1.5;padding:48px 0 48px;padding:3rem 0 3rem;border-top:4px solid gray;border-top:.25rem solid gray;background-color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#313131}.au-footer p:last-child{margin:0}.au-footer.au-footer--alt{background-color:#ebebeb}.au-footer.au-footer--dark{color:#fff;border-color:#89afb8;background-color:#135E70}.au-footer.au-footer--dark.au-footer--alt{background-color:#0d414d}.au-footer__navigation .au-link-list>li{margin-left:0}.au-footer__end{padding-top:16px;padding-top:1rem;margin-top:16px;margin-top:1rem;border-top:1px solid gray}.au-footer--dark .au-footer__end{border-top:1px solid #89afb8}/*! @gov.au/form v0.1.4 */.au-form-group--invalid{border-left:solid 5px #d60000;padding-left:15px}.au-form-group+.au-form-group{margin-top:20px;margin-top:1.25rem}.au-label{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#313131;display:block;font-size:16px;font-size:1rem;line-height:1.5}.au-label+.au-select,.au-label+input,.au-label+textarea{margin-top:4px;margin-top:.25rem}.au-label--inline{display:inline-block}.au-label--inline+.au-select,.au-label--inline+input,.au-label--inline+textarea{margin-top:0}.au-label--dark{color:#fff}.au-hint-text{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#6f777b;display:block;font-size:16px;font-size:1rem;line-height:1.5}*+.au-hint-text{margin-top:6px;margin-top:.4rem}.au-hint-text+.au-select,.au-hint-text+input,.au-hint-text+textarea{margin-top:4px;margin-top:.25rem}.au-hint-text--dark{color:#b8cfd4}.au-hint-text--alt{color:#61696B}.au-error-text{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-weight:bold;font-size:16px;font-size:1rem;line-height:1.5;color:#d60000;display:block}*+.au-error-text{margin-top:6px;margin-top:.4rem}.au-error-text+.au-select,.au-error-text+input,.au-error-text+textarea{margin-top:4px;margin-top:.25rem}.au-error-text--inline{display:inline-block}.au-error-text--inline+.au-select,.au-error-text--inline+input,.au-error-text--inline+textarea{margin-top:0}.au-error-text--hidden{display:none}.au-fieldset{margin:0;padding:0;border:0}.au-fieldset__legend{margin-bottom:12px;margin-bottom:.75rem}/*! @gov.au/grid-12 v2.1.0 */.au-grid .container{-webkit-box-sizing:border-box;box-sizing:border-box}@media (min-width: 768px){.au-grid .container{width:744px}}@media (min-width: 992px){.au-grid .container{width:968px}}@media (min-width: 1200px){.au-grid .container{width:1176px}}.au-grid .container,.au-grid .container-fluid{-webkit-box-sizing:border-box;box-sizing:border-box;margin-right:auto;margin-left:auto;padding-left:12px;padding-right:12px}.au-grid .container:before,.au-grid .container:after,.au-grid .container-fluid:before,.au-grid .container-fluid:after{content:" ";display:table}.au-grid .container:after,.au-grid .container-fluid:after{clear:both}.au-grid .row{margin-left:-12px;margin-right:-12px}.au-grid .row:before,.au-grid .row:after{content:" ";display:table}.au-grid .row:after{clear:both}.au-grid .col-xs-1,.au-grid .col-sm-1,.au-grid .col-md-1,.au-grid .col-lg-1,.au-grid .col-xs-2,.au-grid .col-sm-2,.au-grid .col-md-2,.au-grid .col-lg-2,.au-grid .col-xs-3,.au-grid .col-sm-3,.au-grid .col-md-3,.au-grid .col-lg-3,.au-grid .col-xs-4,.au-grid .col-sm-4,.au-grid .col-md-4,.au-grid .col-lg-4,.au-grid .col-xs-5,.au-grid .col-sm-5,.au-grid .col-md-5,.au-grid .col-lg-5,.au-grid .col-xs-6,.au-grid .col-sm-6,.au-grid .col-md-6,.au-grid .col-lg-6,.au-grid .col-xs-7,.au-grid .col-sm-7,.au-grid .col-md-7,.au-grid .col-lg-7,.au-grid .col-xs-8,.au-grid .col-sm-8,.au-grid .col-md-8,.au-grid .col-lg-8,.au-grid .col-xs-9,.au-grid .col-sm-9,.au-grid .col-md-9,.au-grid .col-lg-9,.au-grid .col-xs-10,.au-grid .col-sm-10,.au-grid .col-md-10,.au-grid .col-lg-10,.au-grid .col-xs-11,.au-grid .col-sm-11,.au-grid .col-md-11,.au-grid .col-lg-11,.au-grid .col-xs-12,.au-grid .col-sm-12,.au-grid .col-md-12,.au-grid .col-lg-12{-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;min-height:1px;padding-left:12px;padding-right:12px}.au-grid .col-xs-1,.au-grid .col-xs-2,.au-grid .col-xs-3,.au-grid .col-xs-4,.au-grid .col-xs-5,.au-grid .col-xs-6,.au-grid .col-xs-7,.au-grid .col-xs-8,.au-grid .col-xs-9,.au-grid .col-xs-10,.au-grid .col-xs-11,.au-grid .col-xs-12{float:left}.au-grid .col-xs-1{width:8.33333333%}.au-grid .col-xs-2{width:16.66666667%}.au-grid .col-xs-3{width:25%}.au-grid .col-xs-4{width:33.33333333%}.au-grid .col-xs-5{width:41.66666667%}.au-grid .col-xs-6{width:50%}.au-grid .col-xs-7{width:58.33333333%}.au-grid .col-xs-8{width:66.66666667%}.au-grid .col-xs-9{width:75%}.au-grid .col-xs-10{width:83.33333333%}.au-grid .col-xs-11{width:91.66666667%}.au-grid .col-xs-12{width:100%}.au-grid .col-xs-pull-0{right:auto}.au-grid .col-xs-pull-1{right:8.33333333%}.au-grid .col-xs-pull-2{right:16.66666667%}.au-grid .col-xs-pull-3{right:25%}.au-grid .col-xs-pull-4{right:33.33333333%}.au-grid .col-xs-pull-5{right:41.66666667%}.au-grid .col-xs-pull-6{right:50%}.au-grid .col-xs-pull-7{right:58.33333333%}.au-grid .col-xs-pull-8{right:66.66666667%}.au-grid .col-xs-pull-9{right:75%}.au-grid .col-xs-pull-10{right:83.33333333%}.au-grid .col-xs-pull-11{right:91.66666667%}.au-grid .col-xs-pull-12{right:100%}.au-grid .col-xs-push-0{left:auto}.au-grid .col-xs-push-1{left:8.33333333%}.au-grid .col-xs-push-2{left:16.66666667%}.au-grid .col-xs-push-3{left:25%}.au-grid .col-xs-push-4{left:33.33333333%}.au-grid .col-xs-push-5{left:41.66666667%}.au-grid .col-xs-push-6{left:50%}.au-grid .col-xs-push-7{left:58.33333333%}.au-grid .col-xs-push-8{left:66.66666667%}.au-grid .col-xs-push-9{left:75%}.au-grid .col-xs-push-10{left:83.33333333%}.au-grid .col-xs-push-11{left:91.66666667%}.au-grid .col-xs-push-12{left:100%}.au-grid .col-xs-offset-0{margin-left:0%}.au-grid .col-xs-offset-1{margin-left:8.33333333%}.au-grid .col-xs-offset-2{margin-left:16.66666667%}.au-grid .col-xs-offset-3{margin-left:25%}.au-grid .col-xs-offset-4{margin-left:33.33333333%}.au-grid .col-xs-offset-5{margin-left:41.66666667%}.au-grid .col-xs-offset-6{margin-left:50%}.au-grid .col-xs-offset-7{margin-left:58.33333333%}.au-grid .col-xs-offset-8{margin-left:66.66666667%}.au-grid .col-xs-offset-9{margin-left:75%}.au-grid .col-xs-offset-10{margin-left:83.33333333%}.au-grid .col-xs-offset-11{margin-left:91.66666667%}.au-grid .col-xs-offset-12{margin-left:100%}@media (min-width: 768px){.au-grid .col-sm-1,.au-grid .col-sm-2,.au-grid .col-sm-3,.au-grid .col-sm-4,.au-grid .col-sm-5,.au-grid .col-sm-6,.au-grid .col-sm-7,.au-grid .col-sm-8,.au-grid .col-sm-9,.au-grid .col-sm-10,.au-grid .col-sm-11,.au-grid .col-sm-12{float:left}.au-grid .col-sm-1{width:8.33333333%}.au-grid .col-sm-2{width:16.66666667%}.au-grid .col-sm-3{width:25%}.au-grid .col-sm-4{width:33.33333333%}.au-grid .col-sm-5{width:41.66666667%}.au-grid .col-sm-6{width:50%}.au-grid .col-sm-7{width:58.33333333%}.au-grid .col-sm-8{width:66.66666667%}.au-grid .col-sm-9{width:75%}.au-grid .col-sm-10{width:83.33333333%}.au-grid .col-sm-11{width:91.66666667%}.au-grid .col-sm-12{width:100%}.au-grid .col-sm-pull-0{right:auto}.au-grid .col-sm-pull-1{right:8.33333333%}.au-grid .col-sm-pull-2{right:16.66666667%}.au-grid .col-sm-pull-3{right:25%}.au-grid .col-sm-pull-4{right:33.33333333%}.au-grid .col-sm-pull-5{right:41.66666667%}.au-grid .col-sm-pull-6{right:50%}.au-grid .col-sm-pull-7{right:58.33333333%}.au-grid .col-sm-pull-8{right:66.66666667%}.au-grid .col-sm-pull-9{right:75%}.au-grid .col-sm-pull-10{right:83.33333333%}.au-grid .col-sm-pull-11{right:91.66666667%}.au-grid .col-sm-pull-12{right:100%}.au-grid .col-sm-push-0{left:auto}.au-grid .col-sm-push-1{left:8.33333333%}.au-grid .col-sm-push-2{left:16.66666667%}.au-grid .col-sm-push-3{left:25%}.au-grid .col-sm-push-4{left:33.33333333%}.au-grid .col-sm-push-5{left:41.66666667%}.au-grid .col-sm-push-6{left:50%}.au-grid .col-sm-push-7{left:58.33333333%}.au-grid .col-sm-push-8{left:66.66666667%}.au-grid .col-sm-push-9{left:75%}.au-grid .col-sm-push-10{left:83.33333333%}.au-grid .col-sm-push-11{left:91.66666667%}.au-grid .col-sm-push-12{left:100%}.au-grid .col-sm-offset-0{margin-left:0%}.au-grid .col-sm-offset-1{margin-left:8.33333333%}.au-grid .col-sm-offset-2{margin-left:16.66666667%}.au-grid .col-sm-offset-3{margin-left:25%}.au-grid .col-sm-offset-4{margin-left:33.33333333%}.au-grid .col-sm-offset-5{margin-left:41.66666667%}.au-grid .col-sm-offset-6{margin-left:50%}.au-grid .col-sm-offset-7{margin-left:58.33333333%}.au-grid .col-sm-offset-8{margin-left:66.66666667%}.au-grid .col-sm-offset-9{margin-left:75%}.au-grid .col-sm-offset-10{margin-left:83.33333333%}.au-grid .col-sm-offset-11{margin-left:91.66666667%}.au-grid .col-sm-offset-12{margin-left:100%}}@media (min-width: 992px){.au-grid .col-md-1,.au-grid .col-md-2,.au-grid .col-md-3,.au-grid .col-md-4,.au-grid .col-md-5,.au-grid .col-md-6,.au-grid .col-md-7,.au-grid .col-md-8,.au-grid .col-md-9,.au-grid .col-md-10,.au-grid .col-md-11,.au-grid .col-md-12{float:left}.au-grid .col-md-1{width:8.33333333%}.au-grid .col-md-2{width:16.66666667%}.au-grid .col-md-3{width:25%}.au-grid .col-md-4{width:33.33333333%}.au-grid .col-md-5{width:41.66666667%}.au-grid .col-md-6{width:50%}.au-grid .col-md-7{width:58.33333333%}.au-grid .col-md-8{width:66.66666667%}.au-grid .col-md-9{width:75%}.au-grid .col-md-10{width:83.33333333%}.au-grid .col-md-11{width:91.66666667%}.au-grid .col-md-12{width:100%}.au-grid .col-md-pull-0{right:auto}.au-grid .col-md-pull-1{right:8.33333333%}.au-grid .col-md-pull-2{right:16.66666667%}.au-grid .col-md-pull-3{right:25%}.au-grid .col-md-pull-4{right:33.33333333%}.au-grid .col-md-pull-5{right:41.66666667%}.au-grid .col-md-pull-6{right:50%}.au-grid .col-md-pull-7{right:58.33333333%}.au-grid .col-md-pull-8{right:66.66666667%}.au-grid .col-md-pull-9{right:75%}.au-grid .col-md-pull-10{right:83.33333333%}.au-grid .col-md-pull-11{right:91.66666667%}.au-grid .col-md-pull-12{right:100%}.au-grid .col-md-push-0{left:auto}.au-grid .col-md-push-1{left:8.33333333%}.au-grid .col-md-push-2{left:16.66666667%}.au-grid .col-md-push-3{left:25%}.au-grid .col-md-push-4{left:33.33333333%}.au-grid .col-md-push-5{left:41.66666667%}.au-grid .col-md-push-6{left:50%}.au-grid .col-md-push-7{left:58.33333333%}.au-grid .col-md-push-8{left:66.66666667%}.au-grid .col-md-push-9{left:75%}.au-grid .col-md-push-10{left:83.33333333%}.au-grid .col-md-push-11{left:91.66666667%}.au-grid .col-md-push-12{left:100%}.au-grid .col-md-offset-0{margin-left:0%}.au-grid .col-md-offset-1{margin-left:8.33333333%}.au-grid .col-md-offset-2{margin-left:16.66666667%}.au-grid .col-md-offset-3{margin-left:25%}.au-grid .col-md-offset-4{margin-left:33.33333333%}.au-grid .col-md-offset-5{margin-left:41.66666667%}.au-grid .col-md-offset-6{margin-left:50%}.au-grid .col-md-offset-7{margin-left:58.33333333%}.au-grid .col-md-offset-8{margin-left:66.66666667%}.au-grid .col-md-offset-9{margin-left:75%}.au-grid .col-md-offset-10{margin-left:83.33333333%}.au-grid .col-md-offset-11{margin-left:91.66666667%}.au-grid .col-md-offset-12{margin-left:100%}}@media (min-width: 1200px){.au-grid .col-lg-1,.au-grid .col-lg-2,.au-grid .col-lg-3,.au-grid .col-lg-4,.au-grid .col-lg-5,.au-grid .col-lg-6,.au-grid .col-lg-7,.au-grid .col-lg-8,.au-grid .col-lg-9,.au-grid .col-lg-10,.au-grid .col-lg-11,.au-grid .col-lg-12{float:left}.au-grid .col-lg-1{width:8.33333333%}.au-grid .col-lg-2{width:16.66666667%}.au-grid .col-lg-3{width:25%}.au-grid .col-lg-4{width:33.33333333%}.au-grid .col-lg-5{width:41.66666667%}.au-grid .col-lg-6{width:50%}.au-grid .col-lg-7{width:58.33333333%}.au-grid .col-lg-8{width:66.66666667%}.au-grid .col-lg-9{width:75%}.au-grid .col-lg-10{width:83.33333333%}.au-grid .col-lg-11{width:91.66666667%}.au-grid .col-lg-12{width:100%}.au-grid .col-lg-pull-0{right:auto}.au-grid .col-lg-pull-1{right:8.33333333%}.au-grid .col-lg-pull-2{right:16.66666667%}.au-grid .col-lg-pull-3{right:25%}.au-grid .col-lg-pull-4{right:33.33333333%}.au-grid .col-lg-pull-5{right:41.66666667%}.au-grid .col-lg-pull-6{right:50%}.au-grid .col-lg-pull-7{right:58.33333333%}.au-grid .col-lg-pull-8{right:66.66666667%}.au-grid .col-lg-pull-9{right:75%}.au-grid .col-lg-pull-10{right:83.33333333%}.au-grid .col-lg-pull-11{right:91.66666667%}.au-grid .col-lg-pull-12{right:100%}.au-grid .col-lg-push-0{left:auto}.au-grid .col-lg-push-1{left:8.33333333%}.au-grid .col-lg-push-2{left:16.66666667%}.au-grid .col-lg-push-3{left:25%}.au-grid .col-lg-push-4{left:33.33333333%}.au-grid .col-lg-push-5{left:41.66666667%}.au-grid .col-lg-push-6{left:50%}.au-grid .col-lg-push-7{left:58.33333333%}.au-grid .col-lg-push-8{left:66.66666667%}.au-grid .col-lg-push-9{left:75%}.au-grid .col-lg-push-10{left:83.33333333%}.au-grid .col-lg-push-11{left:91.66666667%}.au-grid .col-lg-push-12{left:100%}.au-grid .col-lg-offset-0{margin-left:0%}.au-grid .col-lg-offset-1{margin-left:8.33333333%}.au-grid .col-lg-offset-2{margin-left:16.66666667%}.au-grid .col-lg-offset-3{margin-left:25%}.au-grid .col-lg-offset-4{margin-left:33.33333333%}.au-grid .col-lg-offset-5{margin-left:41.66666667%}.au-grid .col-lg-offset-6{margin-left:50%}.au-grid .col-lg-offset-7{margin-left:58.33333333%}.au-grid .col-lg-offset-8{margin-left:66.66666667%}.au-grid .col-lg-offset-9{margin-left:75%}.au-grid .col-lg-offset-10{margin-left:83.33333333%}.au-grid .col-lg-offset-11{margin-left:91.66666667%}.au-grid .col-lg-offset-12{margin-left:100%}}/*! @gov.au/header v4.1.12 */@media print{.au-header{background:#fff !important}.au-header a img{border:0 !important}.au-header,.au-header__brand,.au-header__subline{color:#000 !important}.au-header__brand-image{display:none !important}}.au-header{font-size:16px;font-size:1rem;line-height:1.5;padding:24px 0;padding:1.5rem 0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#313131;background:#fff}@media (min-width: 768px){.au-header{font-size:20px;font-size:1.25rem;line-height:1.6}}@media (min-width: 768px){.au-header{padding:48px 0;padding:3rem 0}}.au-header.au-header--alt{background-color:#f5f5f5}.au-header.au-header--dark{color:#fff;background-color:#135E70}.au-header.au-header--alt.au-header--dark{color:#fff;background-color:#0d414d}.au-header__heading{font-size:20px;font-size:1.25rem;line-height:1.6;font-weight:bold;margin:0;padding:0}@media (min-width: 768px){.au-header__heading{font-size:32px;font-size:2rem;line-height:1.5}}.au-header__subline{max-width:42em;color:#636363}.au-header--dark .au-header__subline{color:#b8cfd4}.au-header__brand{min-width:192px;min-width:12rem}.au-header__brand:before,.au-header__brand:after{content:" ";display:table}.au-header__brand:after{clear:both}.au-header__brand .au-header__brand-image{display:block;border-style:none;max-width:192px;max-width:12rem}.au-header__brand .au-header__brand-image+.au-header__text{margin-top:16px;margin-top:1rem}@media (min-width: 768px){.au-header__brand{min-width:256px;min-width:16rem}.au-header__brand .au-header__brand-image{float:left;max-width:256px;max-width:16rem;margin-right:-256px;margin-right:-16rem}.au-header__brand .au-header__brand-image+.au-header__text{padding-left:16px;padding-left:1rem;margin-left:272px;margin-left:17rem;margin-top:0;float:left;border-left:1px solid gray}.au-header--dark .au-header__brand .au-header__brand-image+.au-header__text{border-left-color:#89afb8}}a.au-header__brand{display:inline-block;color:#313131;text-decoration:none}a.au-header__brand:focus{outline:3px solid #9263DE;outline-offset:2px}a.au-header__brand::-moz-focus-inner{border:0}a.au-header__brand:hover .au-header__text{text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}.au-header--dark a.au-header__brand{color:#fff}.au-header--dark a.au-header__brand:focus{outline:3px solid #C390F9}.au-header--dark a.au-header__brand::-moz-focus-inner{border:0}.au-header.au-header--hero{padding:48px 0 56px 0;padding:3rem 0 3.5rem 0}.au-header.au-header--hero .au-header__brand .au-header__brand-image{float:none}.au-header.au-header--hero .au-header__brand-image+.au-header__text{margin-top:32px;margin-top:2rem;border:0;margin:0;padding:0}.au-header.au-header--hero .au-header__brand-image+.au-header__text .au-header__heading{margin-top:32px;margin-top:2rem}.au-header.au-header--hero .au-header__heading{font-size:20px;font-size:1.25rem;line-height:1.6}@media (min-width: 768px){.au-header.au-header--hero .au-header__heading{font-size:40px;font-size:2.5rem;line-height:1.5}}.au-header.au-header--hero .au-header__heading+.au-header__subline{margin-top:12px;margin-top:.75rem}/*! @gov.au/headings v2.0.11 */.au-display-xxxl,.au-display-xxl,.au-display-xl,.au-display-lg,.au-display-md,.au-display-sm,.au-display-xs,.au-body h1,.au-body h2,.au-body h3,.au-body h4,.au-body h5,.au-body h6{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";display:block;font-weight:bold;margin:0}.au-body .au-display-xxxl,.au-display-xxxl{font-size:48px;font-size:3rem;line-height:1.25}.au-body h1,.au-body .au-display-xxl,.au-display-xxl{font-size:40px;font-size:2.5rem;line-height:1.3}.au-body h2,.au-body .au-display-xl,.au-display-xl{font-size:32px;font-size:2rem;line-height:1.25}.au-body h3,.au-body .au-display-lg,.au-display-lg{font-size:24px;font-size:1.5rem;line-height:1.33333333}.au-body h4,.au-body .au-display-md,.au-display-md{font-size:20px;font-size:1.25rem;line-height:1.2}.au-body h5,.au-body .au-display-sm,.au-display-sm{font-size:16px;font-size:1rem;line-height:1.25}.au-body h6,.au-body .au-display-xs,.au-display-xs{font-size:14px;font-size:.875rem;line-height:1.14285714}*+.au-display-xxxl,*+.au-display-xxl,*+.au-display-xl,*+.au-display-lg,*+.au-display-md,*+.au-display-sm,*+.au-display-xs{margin-top:16px;margin-top:1rem}.au-body *+h1,.au-body *+.au-display-xxl{margin-top:48px;margin-top:3rem}.au-body *+h2,.au-body *+.au-display-xl{margin-top:48px;margin-top:3rem}.au-body h1+h2,.au-body h2+h3,.au-body .au-display-xxl+h2,.au-body .au-display-xl+h3,.au-body h1+.au-display-xl,.au-body h2+.au-display-lg,.au-body .au-display-xxl+.au-display-xl,.au-body .au-display-xl+.au-display-lg,.au-body *+h3,.au-body *+h4,.au-body *+h5,.au-body *+h6,.au-body *+.au-display-md,.au-body *+.au-display-sm,.au-body *+.au-display-xs{margin-top:24px;margin-top:1.5rem}/*! @gov.au/inpage-nav v3.0.6 */.au-inpage-nav-links{font-size:16px;font-size:1rem;line-height:1.5;padding-left:24px;padding-left:1.5rem;margin-bottom:48px;margin-bottom:3rem;border-left:4px solid #00698f}*+.au-inpage-nav-links{margin-top:48px;margin-top:3rem}.au-body .au-inpage-nav-links>ul,.au-body .au-inpage-nav-links>ol{margin-top:16px;margin-top:1rem;list-style-type:none;padding:0}.au-body .au-inpage-nav-links>ul li,.au-body .au-inpage-nav-links>ol li{margin:0}.au-body .au-inpage-nav-links>ul *+li,.au-body .au-inpage-nav-links>ol *+li{margin-top:8px;margin-top:.5rem;margin-left:0}.au-inpage-nav-links.au-inpage-nav-links--dark{border-color:#61daff}.au-inpage-nav-links__heading,.au-body .au-inpage-nav-links__heading{font-weight:bold;font-size:1em}.au-inpage-nav-section{position:relative;padding-right:128px;padding-right:8rem}.au-inpage-nav-section-link{font-size:14px;font-size:.875rem;line-height:1.14285714;top:4px;top:.25rem;position:absolute;right:0;font-weight:normal}/*! @gov.au/keyword-list v3.0.5 */.au-keyword-list{font-size:24px;font-size:1.5rem;line-height:1.5}.au-keyword-list:before,.au-keyword-list:after{content:"";display:table}.au-keyword-list:after{clear:both}*+.au-keyword-list{margin-top:16px;margin-top:1rem}.au-body .au-keyword-list>li{margin-top:16px;margin-top:1rem;float:left;clear:both;list-style:none;margin-left:0}.au-keyword-list>li{font-weight:bold}.au-keyword-list>li>a{display:block}.au-keyword-list__small{font-size:16px;font-size:1rem;line-height:1;display:block;font-weight:normal}.au-body .au-keyword-list__small{color:#313131}.au-keyword-list--dark .au-keyword-list__small{color:#fff}/*! @gov.au/main-nav v1.0.7 */@media print{.au-main-nav{background:transparent !important;border-bottom:none !important}.au-main-nav a{color:#000 !important}.au-main-nav a:hover{background:transparent !important}.au-main-nav .active a{text-decoration:underline;border-color:#fff !important;background-color:transparent !important}.au-main-nav .au-link-list>li{border-color:#000 !important}.au-main-nav .au-link-list>li:last-of-type{border-bottom:1px solid !important}}@media print and (min-width: 992px){.au-main-nav{border-bottom:8px solid #000 !important;border-bottom:.5rem solid #000 !important}.au-main-nav .au-link-list>li:last-of-type{border-bottom:none !important}}@media print{.au-main-nav__toggle{display:none !important}.au-main-nav__menu{background:transparent !important;position:static !important;display:block !important;width:auto !important}.au-main-nav__menu .au-main-nav__menu-inner{padding:0 !important}}.au-main-nav{font-size:16px;font-size:1rem;line-height:1.5;border-bottom:8px solid #00698f;border-bottom:.5rem solid #00698f;background-color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#313131}.au-main-nav a,.au-main-nav .au-main-nav__toggle{padding:16px;padding:1rem;font-size:14px;font-size:.875rem;line-height:1.42857143;color:#00698f;text-decoration:none}.au-main-nav a:focus,.au-main-nav .au-main-nav__toggle:focus{outline:3px solid #9263DE;outline-offset:2px}.au-main-nav a::-moz-focus-inner,.au-main-nav .au-main-nav__toggle::-moz-focus-inner{border:0}.au-main-nav a:hover,.au-main-nav .au-main-nav__toggle:hover{text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto;color:#313131;background-color:#f5f5f5}.au-main-nav a{display:block}.au-main-nav .active a{font-weight:bold;color:#313131}.au-main-nav .active a:hover{border-color:#f5f5f5}.au-main-nav .au-link-list{margin:0;padding:0}.au-main-nav .au-link-list:before,.au-main-nav .au-link-list:after{content:" ";display:table}.au-main-nav .au-link-list:after{clear:both}.au-main-nav .au-link-list li{margin:0}.au-main-nav .au-link-list>li{border-top:1px solid gray}.au-main-nav.au-main-nav--alt{background-color:#ebebeb}.au-main-nav.au-main-nav--alt a:hover,.au-main-nav.au-main-nav--alt .au-main-nav__toggle:hover{background-color:#e0e0e0}.au-main-nav.au-main-nav--alt .active a{border-color:#ebebeb}.au-main-nav.au-main-nav--alt .active a:hover{border-color:#e0e0e0}.au-main-nav.au-main-nav--dark{background-color:#135E70;border-color:#61daff}.au-main-nav.au-main-nav--dark a,.au-main-nav.au-main-nav--dark .au-main-nav__toggle{color:#61daff}.au-main-nav.au-main-nav--dark a:focus,.au-main-nav.au-main-nav--dark .au-main-nav__toggle:focus{outline:3px solid #C390F9}.au-main-nav.au-main-nav--dark a::-moz-focus-inner,.au-main-nav.au-main-nav--dark .au-main-nav__toggle::-moz-focus-inner{border:0}.au-main-nav.au-main-nav--dark a:hover,.au-main-nav.au-main-nav--dark .au-main-nav__toggle:hover{color:#fff;background-color:#104f5f}.au-main-nav.au-main-nav--dark .active a{color:#fff;border-color:#135E70}.au-main-nav.au-main-nav--dark .active a:hover{border-color:#104f5f}.au-main-nav.au-main-nav--dark .au-link-list>li{border-color:#89afb8}.au-main-nav.au-main-nav--dark.au-main-nav--alt{background-color:#0d414d}.au-main-nav.au-main-nav--dark.au-main-nav--alt a:hover,.au-main-nav.au-main-nav--dark.au-main-nav--alt .au-main-nav__toggle:hover{background-color:#0a323c}.au-main-nav.au-main-nav--dark.au-main-nav--alt .active a{border-color:#0d414d}.au-main-nav.au-main-nav--dark.au-main-nav--alt .active a:hover{border-color:#0a323c}@media (min-width: 992px){.au-main-nav .au-link-list>li{display:block;float:left;border:none}.au-main-nav a,.au-main-nav .au-main-nav__toggle{font-size:16px;font-size:1rem;line-height:1.5;padding:16px;padding:1rem}.au-main-nav .active a{border-bottom:8px solid #fff;border-bottom:.5rem solid #fff;margin-bottom:-8px;margin-bottom:-.5rem;font-weight:normal}}.au-main-nav__toggle{padding:8px 16px 8px;padding:.5rem 1rem .5rem;font-size:14px;font-size:.875rem;line-height:1.14285714;border:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;cursor:pointer;display:none}.au-main-nav__toggle:before{font-size:16px;font-size:1rem;line-height:1;margin-bottom:4px;margin-bottom:.25rem;display:block;text-align:center}.au-main-nav__toggle.au-main-nav__toggle--open:before{content:"☰"}.au-main-nav__toggle.au-main-nav__toggle--close:before{content:"✕"}.js .au-main-nav__toggle{display:inline-block}@media (min-width: 992px){.js .au-main-nav__toggle{display:none}}.js .au-main-nav__content.au-main-nav__content--open .au-main-nav__menu{left:0;display:block}.js .au-main-nav__content.au-main-nav__content--open .au-main-nav__overlay{opacity:0.8;left:0;display:block}@media (min-width: 992px){.js .au-main-nav__content.au-main-nav__content--open .au-main-nav__overlay{display:none}}.js .au-main-nav__menu{background-color:#fff;display:none;overflow:auto;position:fixed;top:0;bottom:0;left:-280px;width:280px;z-index:200}.js .au-main-nav__menu .au-main-nav__menu-inner{padding:16px;padding:1rem}.au-main-nav.au-main-nav--alt .au-main-nav__menu{background-color:#ebebeb}.au-main-nav.au-main-nav--dark .au-main-nav__menu{background-color:#135E70}.au-main-nav.au-main-nav--alt.au-main-nav--dark .au-main-nav__menu{background-color:#0d414d}@media (min-width: 992px){.js .au-main-nav__menu{position:static;display:block;width:auto;overflow:inherit;background-color:transparent}.js .au-main-nav__menu .au-main-nav__menu-inner{padding:0}}.au-main-nav__overlay{-webkit-transition:opacity 0.25s ease-out;transition:opacity 0.25s ease-out;background-color:#000;cursor:pointer;position:fixed;top:0;left:0;bottom:0;width:100%;z-index:190;opacity:0.4;display:none}.ie8 .au-main-nav__overlay{filter:alpha(opacity=80)}.js .au-main-nav__scroll--locked{overflow:hidden}@media (min-width: 992px){.js .au-main-nav__scroll--locked{overflow:visible}}/*! @gov.au/page-alerts v2.1.3 */@media print{.au-page-alerts{border-color:#000 !important;background-color:#fff !important;border-left:2px solid #000 !important;padding-top:3em !important}.au-page-alerts:after{background:none !important;content:'info' !important;top:1em !important;left:0 !important;font-size:12px !important;border-right:1px solid #000 !important;border-bottom:1px solid #000 !important;padding:0.5em !important;width:auto !important}.au-page-alerts--success:after{content:'success' !important}.au-page-alerts--warning:after{content:'warning' !important}.au-page-alerts--error:after{content:'error' !important}}.au-page-alerts{padding:16px;padding:1rem;font-size:16px;font-size:1rem;line-height:1.5;position:relative;border:solid 3px #00bfe9;border-left-width:48px;border-left-width:3rem;border-radius:4px;word-wrap:break-word}*+.au-page-alerts{margin-top:16px;margin-top:1rem}.au-page-alerts:before,.au-page-alerts:after{content:' ';position:absolute;top:50%;left:-36px;left:-2.25rem;width:24px;width:1.5rem;height:24px;height:1.5rem;margin-top:-12px;margin-top:-.75rem;border-left-width:-12px;border-left-width:-.75rem;display:block;background-repeat:no-repeat;background-color:#fff}.ie8 .au-page-alerts:before,.lt-ie8 .au-page-alerts:before,.ie8 .au-page-alerts:after,.lt-ie8 .au-page-alerts:after{background:none;text-align:center;background-color:#313131;color:#fff;font-weight:bold}.au-page-alerts:after{background-color:transparent;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23313131' d='M11 17.8h2v-8h-2v8zm0-11.6v2h2v-2h-2z'/%3E%3C/svg%3E")}.ie8 .au-page-alerts:after,.lt-ie8 .au-page-alerts:after{content:'i'}.au-page-alerts:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%2300bfe9' d='M0,0v24h24V0H0z M12,23C5.9,23,1,18.1,1,12C1,5.9,5.9,1,12,1s11,4.9,11,11C23,18.1,18.1,23,12,23z'/%3E%3C/svg%3E")}.au-page-alerts.au-page-alerts--alt:before{background-color:#f5f5f5}.au-page-alerts.au-page-alerts--dark:before{background-color:#135E70}.au-page-alerts.au-page-alerts--dark:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M11 17.8h2v-8h-2v8zm0-11.6v2h2v-2h-2z'/%3E%3C/svg%3E")}.au-page-alerts.au-page-alerts--alt.au-page-alerts--dark:before{background-color:#104f5f}.au-page-alerts--success{border-color:#0b996c}.au-page-alerts--success:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%230b996c' d='M0,0v24h24V0H0z M12,23C5.9,23,1,18.1,1,12C1,5.9,5.9,1,12,1s11,4.9,11,11C23,18.1,18.1,23,12,23z'/%3E%3C/svg%3E")}.au-page-alerts--success:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23313131' d='M10.4 16.9l-4.7-4.7 1.4-1.4 3.3 3.3 6.3-6.3 1.4 1.4z'/%3E%3C/svg%3E")}.ie8 .au-page-alerts--success:after,.lt-ie8 .au-page-alerts--success:after{content:'✓'}.au-page-alerts--success.au-page-alerts--dark:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M10.4 16.9l-4.7-4.7 1.4-1.4 3.3 3.3 6.3-6.3 1.4 1.4z'/%3E%3C/svg%3E")}.au-page-alerts--warning{border-color:#f69900}.au-page-alerts--warning:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23f69900' d='M0,24h24v-3.2H0V24z M12,0l12,20.8V0H12z M0,0v20.8L12,0H0z'/%3E%3C/svg%3E")}.au-page-alerts--warning:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23313131' d='M11 17h2v-2h-2v2zm0-8.6v5h2v-5h-2z'/%3E%3C/svg%3E")}.ie8 .au-page-alerts--warning:after,.lt-ie8 .au-page-alerts--warning:after{content:'!'}.au-page-alerts--warning.au-page-alerts--dark:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M11 17h2v-2h-2v2zm0-8.6v5h2v-5h-2z'/%3E%3C/svg%3E")}.au-page-alerts--error{border-color:#d60000}.au-page-alerts--error:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23d60000' d='M0,0v24h24V0H0z M22.9,16.6L16.5,23H7.4L1,16.5V7.4L7.4,1h9.2l6.3,6.4V16.6z'/%3E%3C/svg%3E")}.au-page-alerts--error:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23313131' d='M17 8.4L15.6 7 12 10.6 8.4 7 7 8.4l3.6 3.6L7 15.6 8.4 17l3.6-3.6 3.6 3.6 1.4-1.4-3.6-3.6z'/%3E%3C/svg%3E")}.ie8 .au-page-alerts--error:after,.lt-ie8 .au-page-alerts--error:after{content:'!'}.au-page-alerts--error.au-page-alerts--dark:after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M17 8.4L15.6 7 12 10.6 8.4 7 7 8.4l3.6 3.6L7 15.6 8.4 17l3.6-3.6 3.6 3.6 1.4-1.4-3.6-3.6z'/%3E%3C/svg%3E")}.au-page-alerts__sronly{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}/*! @gov.au/progress-indicator v3.1.7 */@media print{.au-progress-indicator{border-top-color:#000 !important}.au-body .au-progress-indicator__link,.au-progress-indicator__link{color:#000 !important;border-bottom-color:#000 !important;border-left-color:transparent !important;padding-left:6px !important}.au-body .au-progress-indicator__link.au-progress-indicator__link--doing,.au-progress-indicator__link.au-progress-indicator__link--doing{border-left-color:#000 !important}.au-body .au-progress-indicator__link:after,.au-progress-indicator__link:after{display:none}.au-progress-indicator__status{color:#000 !important}}.au-body .au-progress-indicator,.au-progress-indicator{font-size:16px;font-size:1rem;line-height:1.25;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";list-style:none;padding:0;border-top:1px solid gray}.au-body .au-progress-indicator>li,.au-progress-indicator>li{margin:0}.au-body .au-progress-indicator.au-progress-indicator--dark,.au-progress-indicator.au-progress-indicator--dark{border-color:#89afb8}*+.au-progress-indicator,.au-body *+.au-progress-indicator{margin-top:16px;margin-top:1rem}.au-body .au-progress-indicator__link,.au-progress-indicator__link{font-size:16px;font-size:1rem;line-height:1.25;padding:12px 12px 12px 44px;padding:.75rem .75rem .75rem 2.75rem;position:relative;display:block;color:#313131;text-decoration:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;text-align:left;border:none;border-bottom:1px solid gray;border-left:3px solid transparent;-webkit-transition:background-color 0.1s ease-in-out;transition:background-color 0.1s ease-in-out;cursor:pointer}.au-body .au-progress-indicator__link:hover,.au-progress-indicator__link:hover{background-color:#f5f5f5}.au-body .au-progress-indicator__link:focus,.au-progress-indicator__link:focus{outline:3px solid #9263DE;outline-offset:2px}.au-body .au-progress-indicator__link::-moz-focus-inner,.au-progress-indicator__link::-moz-focus-inner{border:0}.au-body .au-progress-indicator__link:after,.au-progress-indicator__link:after{left:8px;left:.5rem;width:24px;width:1.5rem;content:'';position:absolute;top:0;bottom:0;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23636363' d='M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.6 0 12 0zm0 22C6.5 22 2 17.5 2 12S6.5 2 12 2s10 4.5 10 10-4.5 10-10 10z'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:0 center}.ie8 .au-body .au-progress-indicator__link:after,.lt-ie8 .au-body .au-progress-indicator__link:after,.ie8 .au-progress-indicator__link:after,.lt-ie8 .au-progress-indicator__link:after{top:6px;content:'-'}.au-body .au-progress-indicator__link.au-progress-indicator__link--doing,.au-progress-indicator__link.au-progress-indicator__link--doing{border-left-color:#00698f;font-weight:bold}.au-body .au-progress-indicator__link.au-progress-indicator__link--doing:after,.au-progress-indicator__link.au-progress-indicator__link--doing:after{background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%2300698f' d='M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.6 0 12 0zm0 22C6.5 22 2 17.5 2 12S6.5 2 12 2s10 4.5 10 10-4.5 10-10 10z'/%3E%3Ccircle fill='%2300698f' cx='6.5' cy='12' r='1.5'%3E%3C/circle%3E%3Ccircle fill='%2300698f' cx='12' cy='12' r='1.5'%3E%3C/circle%3E%3Ccircle fill='%2300698f' cx='17.5' cy='12' r='1.5'%3E%3C/circle%3E%3C/svg%3E")}.ie8 .au-body .au-progress-indicator__link.au-progress-indicator__link--doing:after,.lt-ie8 .au-body .au-progress-indicator__link.au-progress-indicator__link--doing:after,.ie8 .au-progress-indicator__link.au-progress-indicator__link--doing:after,.lt-ie8 .au-progress-indicator__link.au-progress-indicator__link--doing:after{content:'...'}.au-body .au-progress-indicator__link.au-progress-indicator__link--done:after,.au-progress-indicator__link.au-progress-indicator__link--done:after{background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%2300698f' d='M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.6 0 12 0zm0 22C6.5 22 2 17.5 2 12S6.5 2 12 2s10 4.5 10 10-4.5 10-10 10z'/%3E%3Cpath fill='%2300698f' d='M18.744186,9.23753281 C18.744186,9.48293963 18.6627907,9.71391076 18.5,9.88713911 L11.3895349,17.7257218 C11.2267442,17.8989501 10.996124,18 10.7655039,18 C10.5484496,18 10.3178295,17.8989501 10.1550388,17.7257218 L5.24418605,12.5 C5.08139535,12.3267717 5,12.0958005 5,11.8503937 C5,11.6049869 5.08139535,11.3595801 5.24418605,11.1863517 L6.47868217,9.88713911 C6.64147287,9.71391076 6.85852713,9.61286089 7.08914729,9.61286089 C7.31976744,9.61286089 7.53682171,9.71391076 7.6996124,9.88713911 L10.7655039,13.1496063 L16.0445736,7.27427822 C16.2073643,7.10104987 16.4244186,7 16.6550388,7 C16.8856589,7 17.1027132,7.10104987 17.2655039,7.27427822 L18.5,8.57349081 C18.6627907,8.74671916 18.744186,8.99212598 18.744186,9.23753281 Z'/%3E%3C/svg%3E")}.ie8 .au-body .au-progress-indicator__link.au-progress-indicator__link--done:after,.lt-ie8 .au-body .au-progress-indicator__link.au-progress-indicator__link--done:after,.ie8 .au-progress-indicator__link.au-progress-indicator__link--done:after,.lt-ie8 .au-progress-indicator__link.au-progress-indicator__link--done:after{content:'✓'}.au-body--dark .au-progress-indicator--dark .au-body .au-progress-indicator__link,.au-progress-indicator--dark .au-body .au-progress-indicator__link,.au-body--dark .au-progress-indicator--dark .au-progress-indicator__link,.au-progress-indicator--dark .au-progress-indicator__link{color:#fff;border-bottom-color:#89afb8}.au-body--dark .au-progress-indicator--dark .au-body .au-progress-indicator__link:focus,.au-progress-indicator--dark .au-body .au-progress-indicator__link:focus,.au-body--dark .au-progress-indicator--dark .au-progress-indicator__link:focus,.au-progress-indicator--dark .au-progress-indicator__link:focus{outline:3px solid #C390F9}.au-body--dark .au-progress-indicator--dark .au-body .au-progress-indicator__link::-moz-focus-inner,.au-progress-indicator--dark .au-body .au-progress-indicator__link::-moz-focus-inner,.au-body--dark .au-progress-indicator--dark .au-progress-indicator__link::-moz-focus-inner,.au-progress-indicator--dark .au-progress-indicator__link::-moz-focus-inner{border:0}.au-body--dark .au-progress-indicator--dark .au-body .au-progress-indicator__link:hover,.au-progress-indicator--dark .au-body .au-progress-indicator__link:hover,.au-body--dark .au-progress-indicator--dark .au-progress-indicator__link:hover,.au-progress-indicator--dark .au-progress-indicator__link:hover{background-color:#104f5f}.au-body--dark .au-progress-indicator--dark .au-body .au-progress-indicator__link:after,.au-progress-indicator--dark .au-body .au-progress-indicator__link:after,.au-body--dark .au-progress-indicator--dark .au-progress-indicator__link:after,.au-progress-indicator--dark .au-progress-indicator__link:after{background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%23b8cfd4' d='M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.6 0 12 0zm0 22C6.5 22 2 17.5 2 12S6.5 2 12 2s10 4.5 10 10-4.5 10-10 10z'/%3E%3C/svg%3E")}.au-body--dark .au-progress-indicator--dark .au-body .au-progress-indicator__link.au-progress-indicator__link--done:after,.au-progress-indicator--dark .au-body .au-progress-indicator__link.au-progress-indicator__link--done:after,.au-body--dark .au-progress-indicator--dark .au-progress-indicator__link.au-progress-indicator__link--done:after,.au-progress-indicator--dark .au-progress-indicator__link.au-progress-indicator__link--done:after{background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%2361daff' d='M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.6 0 12 0zm0 22C6.5 22 2 17.5 2 12S6.5 2 12 2s10 4.5 10 10-4.5 10-10 10z'/%3E%3Cpath fill='%2361daff' d='M18.744186,9.23753281 C18.744186,9.48293963 18.6627907,9.71391076 18.5,9.88713911 L11.3895349,17.7257218 C11.2267442,17.8989501 10.996124,18 10.7655039,18 C10.5484496,18 10.3178295,17.8989501 10.1550388,17.7257218 L5.24418605,12.5 C5.08139535,12.3267717 5,12.0958005 5,11.8503937 C5,11.6049869 5.08139535,11.3595801 5.24418605,11.1863517 L6.47868217,9.88713911 C6.64147287,9.71391076 6.85852713,9.61286089 7.08914729,9.61286089 C7.31976744,9.61286089 7.53682171,9.71391076 7.6996124,9.88713911 L10.7655039,13.1496063 L16.0445736,7.27427822 C16.2073643,7.10104987 16.4244186,7 16.6550388,7 C16.8856589,7 17.1027132,7.10104987 17.2655039,7.27427822 L18.5,8.57349081 C18.6627907,8.74671916 18.744186,8.99212598 18.744186,9.23753281 Z'/%3E%3C/svg%3E")}.au-body--dark .au-progress-indicator--dark .au-body .au-progress-indicator__link.au-progress-indicator__link--doing,.au-progress-indicator--dark .au-body .au-progress-indicator__link.au-progress-indicator__link--doing,.au-body--dark .au-progress-indicator--dark .au-progress-indicator__link.au-progress-indicator__link--doing,.au-progress-indicator--dark .au-progress-indicator__link.au-progress-indicator__link--doing{border-left-color:#61daff}.au-body--dark .au-progress-indicator--dark .au-body .au-progress-indicator__link.au-progress-indicator__link--doing:after,.au-progress-indicator--dark .au-body .au-progress-indicator__link.au-progress-indicator__link--doing:after,.au-body--dark .au-progress-indicator--dark .au-progress-indicator__link.au-progress-indicator__link--doing:after,.au-progress-indicator--dark .au-progress-indicator__link.au-progress-indicator__link--doing:after{background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%2361daff' d='M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.6 0 12 0zm0 22C6.5 22 2 17.5 2 12S6.5 2 12 2s10 4.5 10 10-4.5 10-10 10z'/%3E%3Ccircle fill='%2361daff' cx='6.5' cy='12' r='1.5'%3E%3C/circle%3E%3Ccircle fill='%2361daff' cx='12' cy='12' r='1.5'%3E%3C/circle%3E%3Ccircle fill='%2361daff' cx='17.5' cy='12' r='1.5'%3E%3C/circle%3E%3C/svg%3E")}.au-progress-indicator__status{font-size:14px;font-size:.875rem;line-height:1.14285714;display:block;font-weight:normal;color:#636363}.au-progress-indicator--dark .au-progress-indicator__status{color:#b8cfd4}/*! @gov.au/responsive-media v2.0.14 */.au-responsive-media-vid{position:relative;display:block;height:0;padding:0;overflow:hidden}.au-responsive-media-vid>.au-responsive-media-vid__item{position:absolute;top:0;left:0;height:100%;width:100%;border:0}.au-responsive-media-vid.au-responsive-media-vid--16x9{padding-bottom:56.25%}.au-responsive-media-vid.au-responsive-media-vid--4x3{padding-bottom:75%}*+.au-responsive-media-vid{margin-top:16px;margin-top:1rem}.au-responsive-media-img,.au-body img,.au-responsive-media img{max-width:100%;height:auto}*+.au-responsive-media-img,.au-body *+img,.au-responsive-media *+img{margin-top:16px;margin-top:1rem}/*! @gov.au/select v2.0.11 */@media print{.au-select{border-color:#000 !important;background-image:url("data:image/svg+xml,%3Csvg fill='%23000' width='1.5em' height='auto' viewBox='0 0 28 12' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1.9 1.1L8 7.2l6.1-6.1L16 2.9l-8 8-8-8 1.9-1.8z'/%3E%3Cpath fill='none' d='M2-5.8h24v24H2v-24z'/%3E%3C/svg%3E") !important}}.au-select{font-size:16px;font-size:1rem;line-height:1.5;padding:8px 36px 8px 12px;padding:.5rem 2.25rem .5rem .75rem;height:46px;height:2.875rem;position:relative;vertical-align:middle;display:inline-block;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:3px solid gray;text-indent:0.01px;text-overflow:'';background-color:#fff;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;cursor:pointer;background-image:url("data:image/svg+xml,%3Csvg fill='%2300698f' width='1.5em' height='auto' viewBox='0 0 28 12' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1.9 1.1L8 7.2l6.1-6.1L16 2.9l-8 8-8-8 1.9-1.8z'/%3E%3Cpath fill='none' d='M2-5.8h24v24H2v-24z'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right center;background-size:1.5em auto;vertical-align:middle}.au-select:focus{outline:3px solid #9263DE;outline-offset:2px}.au-select::-moz-focus-inner{border:0}.au-select:focus{border-radius:0}.au-select[disabled]{cursor:not-allowed;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";opacity:0.3}.au-select:disabled{cursor:not-allowed;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";opacity:0.3}.au-select.au-select--dark:invalid,.au-select:invalid{background-color:#fdf2f2;border-color:#d60000}.au-select.au-select--dark.au-select--invalid,.au-select.au-select--invalid{background-color:#fdf2f2;border-color:#d60000}.au-select.au-select--dark.au-select--valid,.au-select.au-select--valid{background-color:#f3faf8;border-color:#0b996c}.ie8 .au-select:after,.ie9 .au-select:after{display:none}.au-select::-ms-expand{display:none}.ie8 .au-select,.ie9 .au-select{padding-right:4px;padding-right:.25rem}.au-select.au-select--dark{border-color:#fff}.au-select.au-select--dark:focus{outline:3px solid #C390F9}.au-select.au-select--dark::-moz-focus-inner{border:0}.au-select.au-select--block{width:100%}.au-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #000}html>body .au-select,x:-moz-any-link,x:default{padding-right:16px;padding-right:1rem}@supports (-moz-osx-font-smoothing: auto){html body .au-select{padding-right:36px;padding-right:2.25rem}}/*! @gov.au/side-nav v5.0.7 */@media print{.au-side-nav{background:transparent !important}.au-side-nav a{color:#000 !important;text-decoration:underline !important}.au-side-nav a:hover{background:transparent !important}.au-side-nav .au-accordion__title{display:none}.au-side-nav__content ul ul ul a:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23000' d='M2 10h12v1H2zM2 5h1v5H2z'/%3E%3C/svg%3E") !important}.au-side-nav__content>ul>li{border-color:#000 !important}}.au-side-nav{font-size:16px;font-size:1rem;line-height:1.5;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";background-color:#ebebeb;border-radius:4px;overflow:hidden;border:0}.au-side-nav a,.au-side-nav .active>span{padding:16px;padding:1rem;font-size:14px;font-size:.875rem;line-height:1.42857143;color:#636363;display:block}.au-side-nav a{text-decoration:none}.au-side-nav a:hover{text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto;background-color:#e0e0e0}.au-side-nav a:focus{outline:3px solid #9263DE;outline-offset:2px}.au-side-nav a::-moz-focus-inner{border:0}.au-side-nav .au-link-list{padding:0;margin:0}.au-side-nav .au-link-list li{margin:0}.au-side-nav .au-accordion__body{overflow:visible}.au-side-nav .au-accordion__title{font-size:16px;font-size:1rem;line-height:1.5;color:#00698f;font-weight:normal;text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto;background-color:inherit}.au-side-nav .au-accordion__title:hover{text-decoration:none}.au-side-nav .au-accordion__title:focus{outline-offset:-3px}.no-js .au-side-nav .au-accordion__title{display:none}.au-side-nav .au-accordion__body-wrapper{border:0;padding:0}@media (min-width: 768px){.au-side-nav{background:transparent;border-radius:0;overflow:visible}.au-side-nav .au-accordion__body.au-accordion--closed{display:block;height:auto}.au-side-nav a:hover{background-color:#f5f5f5}.au-side-nav .au-accordion__title{display:none}}.au-side-nav__content{margin:0 16px;margin:0 1rem}.au-side-nav__content ul ul a{padding-left:32px;padding-left:2rem}.au-side-nav__content ul ul ul a{padding-left:60px;padding-left:3.75rem}.au-side-nav__content ul ul ul ul a{padding-left:80px;padding-left:5rem}.au-side-nav__content ul ul .active>span{padding-left:32px;padding-left:2rem}.au-side-nav__content ul ul ul .active>span{padding-left:60px;padding-left:3.75rem}.au-side-nav__content ul ul ul ul .active>span{padding-left:80px;padding-left:5rem}.au-side-nav__content .active>span{font-weight:bold;color:#313131}.au-side-nav__content ul ul ul a:before,.au-side-nav__content ul ul ul .active>span:before{content:" ";width:16px;width:1rem;height:16px;height:1rem;background-size:16px;background-size:1rem;margin-left:-24px;margin-left:-1.5rem;display:block;float:left;background-repeat:no-repeat;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='gray' d='M2 10h12v1H2zM2 5h1v5H2z'/%3E%3C/svg%3E")}.au-side-nav__content>ul>li{border-bottom:1px solid gray}.au-side-nav__content>ul>li:last-of-type{border:none}@media (min-width: 768px){.au-side-nav__content{margin:0}}.au-sidenav__title{margin:0}.au-sidenav__title a{font-size:16px;font-size:1rem;line-height:1.5;color:#313131;border-bottom:2px solid gray}.au-side-nav.au-side-nav--alt{background:#fff}.au-side-nav.au-side-nav--alt a:hover{background:#f5f5f5}@media (min-width: 768px){.au-side-nav.au-side-nav--alt{background:transparent}.au-side-nav.au-side-nav--alt a:hover{background-color:#e0e0e0}}.au-side-nav.au-side-nav--dark{background:#0d414d}.au-side-nav.au-side-nav--dark .au-accordion__title{color:#61daff;background-color:inherit}.au-side-nav.au-side-nav--dark a{color:#b8cfd4}.au-side-nav.au-side-nav--dark a:hover{background:#0a323c}.au-side-nav.au-side-nav--dark a:focus{outline:3px solid #C390F9}.au-side-nav.au-side-nav--dark a::-moz-focus-inner{border:0}.au-side-nav.au-side-nav--dark .au-side-nav__content .active>span{color:#fff}.au-side-nav.au-side-nav--dark .au-side-nav__content ul ul ul a:before,.au-side-nav.au-side-nav--dark .au-side-nav__content ul ul ul .active>span:before{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%2389afb8' d='M2 10h12v1H2zM2 5h1v5H2z'/%3E%3C/svg%3E")}.au-side-nav.au-side-nav--dark .au-side-nav__content>ul>li{border-color:#89afb8}.au-side-nav.au-side-nav--dark .au-sidenav__title a{border-color:#89afb8;color:#fff}@media (min-width: 768px){.au-side-nav.au-side-nav--dark{background:transparent}.au-side-nav.au-side-nav--dark a:hover{background-color:#104f5f}}.au-side-nav.au-side-nav--dark.au-side-nav--alt{background:#135E70}.au-side-nav.au-side-nav--dark.au-side-nav--alt a:hover{background:#104f5f}@media (min-width: 768px){.au-side-nav.au-side-nav--dark.au-side-nav--alt{background:transparent}.au-side-nav.au-side-nav--dark.au-side-nav--alt a:hover{background-color:#0a323c}}/*! @gov.au/skip-link v2.0.16 */@media print{.au-skip-link__link{background:#fff !important}}.au-skip-link{font-size:20px;font-size:1.25rem;line-height:1;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#313131}.au-skip-link__link{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.au-skip-link__link:active,.au-skip-link__link:focus{outline:3px solid #9263DE;outline-offset:2px;top:16px;top:1rem;left:16px;left:1rem;padding:24px;padding:1.5rem;clip:auto;height:auto;margin:0;overflow:visible;position:absolute;width:auto;color:#fff;background-color:#00698f;text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto;z-index:600}.au-body .au-skip-link__link:hover,.au-skip-link__link:hover{text-decoration:none;color:#fff}/*! @gov.au/table v0.1.3 */.au-table{font-size:16px;font-size:1rem;line-height:1.5;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";width:100%;border-collapse:collapse;border-spacing:0}.au-table .au-table__caption{font-size:20px;font-size:1.25rem;line-height:1.6;font-weight:bold;text-align:left;display:table-caption;padding-bottom:8px;padding-bottom:.5rem}.au-table .au-table__head{display:table-header-group;border-bottom:4px solid #BBB;border-bottom:.25rem solid #BBB}.au-table .au-table__head .au-table__header{text-align:left;padding:12px;padding:.75rem}.au-table .au-table__head .au-table__header.au-table__header--width-10{width:10%}.au-table .au-table__head .au-table__header.au-table__header--width-20{width:20%}.au-table .au-table__head .au-table__header.au-table__header--width-25{width:25%}.au-table .au-table__head .au-table__header.au-table__header--width-33{width:33%}.au-table .au-table__head .au-table__header.au-table__header--width-50{width:50%}.au-table .au-table__head .au-table__header.au-table__header--width-75{width:75%}.au-table .au-table__head .au-table__header.au-table__header--numeric{text-align:right}.au-table .au-table__head .au-table__header:focus{outline:3px solid #9263DE}.au-table .au-table__row{display:table-row}.au-table .au-table__body{display:table-row-group}.au-table .au-table__body .au-table__cell{padding:12px;padding:.75rem;text-align:left;border-bottom:1px solid silver}.au-table .au-table__body .au-table__cell.au-table__cell--numeric{text-align:right;font-variant:tabular-nums}.au-table .au-table__body .au-table__cell:focus{outline:3px solid #9263DE}.au-table.au-table--striped .au-table__body .au-table__row:nth-last-child(odd){background-color:#F2F2F2}.au-table__wrapper{overflow-x:auto}/*! @gov.au/tags v3.1.7 */@media print{.au-tags{color:#000 !important}.au-tags__item{border-color:#000 !important}.au-tags__item a{color:#000 !important}}.au-tags{font-size:16px;font-size:1rem;line-height:1.5;display:block;margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#313131}.au-tags.au-tags--dark{color:#fff}.au-tags>li{margin:8px 4px 0 0;margin:.5rem .25rem 0 0;padding:0 8px;padding:0 .5rem;border:1px solid #00698f;border-radius:4px;display:inline-block}.au-tags>li>a,.au-tags>li>button{margin:0 -8px;margin:0 -.5rem;padding:0 8px;padding:0 .5rem;color:#00698f;display:inline-block;border-radius:4px}.au-tags>li>a:hover,.au-tags>li>button:hover{color:#313131;text-decoration:none;background-color:#f5f5f5}.au-tags>li>a:focus,.au-tags>li>button:focus{outline:3px solid #9263DE;outline-offset:2px}.au-tags>li>a::-moz-focus-inner,.au-tags>li>button::-moz-focus-inner{border:0}.au-tags>li>a:focus,.au-tags>li>button:focus{outline-offset:-1px}.au-tags.au-tags--dark>li{border-color:#61daff}.au-tags.au-tags--dark>li>a,.au-tags.au-tags--dark>li>button{color:#61daff}.au-tags.au-tags--dark>li>a:hover,.au-tags.au-tags--dark>li>button:hover{color:#fff;background-color:#104f5f}.au-tags.au-tags--dark>li>a:focus,.au-tags.au-tags--dark>li>button:focus{outline:3px solid #C390F9}.au-tags.au-tags--dark>li>a::-moz-focus-inner,.au-tags.au-tags--dark>li>button::-moz-focus-inner{border:0}/*! @gov.au/text-inputs v2.1.1 */@media print{.au-text-input{border-color:#000 !important}.au-text-input[disabled]{color:#636363 !important;background-color:#ccc !important;border:2px solid #ccc !important}.au-text-input:disabled{color:#636363 !important;background-color:#ccc !important;border:2px solid #ccc !important}}.au-text-input{-webkit-box-sizing:border-box;box-sizing:border-box;font-size:16px;font-size:1rem;line-height:1;padding:8px 16px;padding:.5rem 1rem;height:46px;height:2.875rem;border:3px solid gray;background-color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";color:#313131;border-radius:4px;vertical-align:middle;-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;max-width:205px;max-width:12.8125rem}.au-text-input.au-text-input--dark:invalid,.au-text-input:invalid{background-color:#fdf2f2;border-color:#d60000}.au-text-input.au-text-input--dark.au-text-input--invalid,.au-text-input.au-text-input--invalid{background-color:#fdf2f2;border-color:#d60000}.au-text-input.au-text-input--dark.au-text-input--valid,.au-text-input.au-text-input--valid{background-color:#f3faf8;border-color:#0b996c}.au-text-input[disabled]{cursor:not-allowed;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";opacity:0.3}.au-text-input:disabled{cursor:not-allowed;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";opacity:0.3}.au-text-input:focus{outline:3px solid #9263DE;outline-offset:2px}.au-text-input::-moz-focus-inner{border:0}.au-text-input:focus{border-radius:0;background-color:#fff}.au-text-input.au-text-input--dark{border-color:#fff}.au-text-input.au-text-input--dark[disabled]{-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";opacity:0.3}.au-text-input.au-text-input--dark:disabled{-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";opacity:0.3}.au-text-input.au-text-input--dark:focus{outline:3px solid #C390F9}.au-text-input.au-text-input--dark::-moz-focus-inner{border:0}.au-text-input.au-text-input--width-xs{max-width:69px;max-width:4.3rem}.au-text-input.au-text-input--width-sm{max-width:101px;max-width:6.3rem}.au-text-input.au-text-input--width-md{max-width:160px;max-width:10rem}.au-text-input.au-text-input--width-lg{max-width:288px;max-width:18rem}.au-text-input.au-text-input--width-xl{max-width:384px;max-width:24rem}.au-text-input.au-text-input--block{display:block;max-width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.au-text-input.au-text-input--number{font-family:"SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;letter-spacing:2px}textarea.au-text-input{font-size:16px;font-size:1rem;line-height:1.5;height:auto;min-height:6em}
+body {
+ border: 2rem red;
+}
+
+.navbar-default{
+ background-color: #313131;
+ border-color: #45c2f0;
+}
+
+.au-header.au-header--dark{
+ color:#fff;
+ background-color:#313131;
+}
+
+.au-footer.au-footer--dark{
+ color:#fff;
+ background-color:#313131;
+}
diff --git a/html/observatory/css/style.css b/html/observatory/css/style.css
new file mode 100644
index 0000000..66a05f0
--- /dev/null
+++ b/html/observatory/css/style.css
@@ -0,0 +1,465 @@
+
+html,body {
+ width: 100%;
+ height: 100%;
+ margin: 0px;
+ padding: 0px;
+}
+main.au-body {
+ background: #eee !important;
+ padding: 0 20px 0 20px;
+}
+.explanation {
+ margin-top: 2rem;
+ margin-bottom: 2rem;
+}
+.sigma-parent {
+ position: relative;
+ height: 100%;
+ min-height: 800px !important;
+ background: white;
+}
+
+.sigma-expand {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+canvas#sigma_bg_1 {
+ display: none;
+}
+
+#attributepane {
+ display: none;
+ height:auto;
+
+ background-color: #fff;
+ margin: 0;
+ word-wrap: break-word;
+ background-color:rgba(255,255,255,0.8);
+ padding: 0px 18px 0px 18px;
+ z-index: 1;
+ width: 80%;
+}
+
+
+#attributepane .text {
+ height:83%;
+}
+
+#attributepane .headertext {
+ color: #000;
+ margin-bottom: 5px;
+ height: 14px;
+ border-bottom: 1px solid #999;
+ padding: 0px 0 10px 0;
+ font-size:16px;
+ font-weight:bold;
+}
+
+
+#attributepane .returntext em {
+ background-image: url('../images/sprite.png');
+ background-repeat: no-repeat;
+ display: block;
+ width: 20px;
+ height: 20px;
+ background-position: -91px -13px;
+ float: left;
+}
+
+#attributepane .returntext span {
+ padding-left: 5px;
+ display: block;
+}
+
+#attributepane .close {
+ padding-left: 14px;
+ margin-top: 10px;
+}
+
+#attributepane .close .c {
+ border-top: 2px solid #999;
+ padding: 10px 0 14px 0;
+}
+
+#attributepane .close em {
+background-image: url('../images/sprite.png');
+background-repeat: no-repeat;
+background-position: -11px -13px;
+display: block;
+width: 24px;
+height: 16px;
+float: left;
+}
+
+#attributepane .close span {
+display: block;
+width: 151px;
+float: left;
+}
+
+#attributepane .nodeattributes {
+ display:block;
+ max-width: 13em;
+ max-height: 400px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ border-bottom:1px solid #999;
+}
+
+#attributepane .name {
+font-size: 14px;
+cursor: default;
+padding-bottom: 10px;
+padding-top: 18px;
+font-weight:bold;
+}
+
+#attributepane .data {
+
+}
+
+#attributepane .data .plus {
+background-repeat: no-repeat;
+background-image: url('../images/sprite.png');
+background-position: -171px -122px;
+width: 22px;
+height: 20px;
+float: left;
+display: block;
+}
+
+#attributepane .link {
+padding: 0 0 0 4px;
+}
+
+#attributepane .link li {
+padding-top: 2px;
+cursor:pointer;
+}
+
+#attributepane .p {
+padding-top: 10px;
+font-weight: bold;
+font-size:14px;
+}
+
+.left-close {
+background-image: url('../images/fancybox_sprite.png');
+float: right;
+z-index:99999;
+cursor: pointer;
+padding-left:31px;
+line-height:36px;
+background-repeat: no-repeat;
+font-weight: bold;
+font-size:14px;
+
+}
+
+#developercontainer {
+ margin-left:25px;
+ margin-bottom:25px;
+ position:fixed;
+ bottom:0;
+}
+
+
+
+
+
+
+#search {
+ padding: 20px 0 0px 2px;
+}
+
+#search input[name=search] {
+border: 1px solid #999;
+background-color: #fff;
+padding: 5px 7px 4px 7px;
+width: 205px;
+color: #000;
+}
+
+#search input.empty {
+color: #000;
+}
+
+#search .state {
+width: 14px;
+height: 14px;
+background-image: url('../images/sprite.png');
+float: right;
+margin-top: 6px;
+cursor: pointer;
+background-position: -131px -13px;
+}
+
+#search .state.searching {
+background-position: -11px -13px;
+}
+
+#search .results {
+ display: none;
+/* border: 1px solid #999;*/
+ margin: 6px;
+ height: 150px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+}
+
+#search .results b {
+padding-left: 2px;
+}
+
+#search .results a {
+padding: 1px 2px;
+display: block;
+cursor: pointer;
+text-decoration: none;
+color: #000;
+}
+
+#search .results a:hover {
+background-color: #999;
+color: #fff;
+}
+
+
+
+#attributeselect .select {
+
+ background-color: #999;
+}
+
+
+
+#attributeselect .list {
+border: 1px solid black;
+max-height: 200px;
+overflow: scroll;
+
+}
+
+
+.link h2 {
+font-size: 1em;
+padding-top: 1em;
+}
+
+#mainpanel {
+ padding: 20px;
+}
+
+#mainpanel dl {
+ padding-bottom:10px;
+}
+
+#mainpanel h2 {
+ font-size:14px;
+}
+
+#mainpanel dt {
+width: 20px;
+height: 20px;
+float: left;
+background-repeat: no-repeat;
+background-image: url('../images/sprite.png');
+}
+
+#legend dl {
+}
+
+#mainpanel h2 {
+ padding-bottom:10px;
+}
+
+#legend dd {
+margin-bottom: 8px;
+color: #000;
+}
+
+#mainpanel .infos dd {
+margin-bottom: 12px;
+}
+
+#mainpanel .node {
+background-position: -11px -119px;
+}
+
+#mainpanel .edge {
+background-position: -51px -122px;
+}
+
+#mainpanel .colours {
+
+background-image:url('../images/rainbow.png');
+
+}
+#legend .note {
+margin-bottom: 8px;
+
+}
+
+#mainpanel .regions {
+background-position: -171px -13px;
+}
+
+#mainpanel .download {
+background-position: -51px -13px;
+}
+
+#mainpanel .moreinformation {
+background: url('../images/info.png');
+background-repeat: no-repeat;
+margin-left: 5px;
+}
+
+
+#zoom {
+ z-index:999;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ position: relative;
+ left: 90%;
+ bottom: 5%;
+width: 60px;
+}
+.z {
+ width: 16px;
+ display: inline-block;
+ cursor:pointer;
+}
+.line {
+ font-size: 12px;
+ color: #000;
+ text-decoration: none;
+ font-weight: bold;
+ cursor: pointer;
+ cursor: hand;
+}
+
+#information {
+display: none;
+background: #fff;
+padding: 1px 10px 10px 10px;
+}
+
+#information h3 {
+margin: 14px 0 4px 0;
+}
+
+#information p {
+margin: 0 0 4px 0;
+}
+
+#information .button {
+width: 14px;
+height: 14px;
+background-image: url('../images/sprite.png');
+border: 1px solid #999;
+display: inline-block;
+*display: inline;
+*zoom: 1;
+}
+
+#information .button span {
+display: none;
+}
+
+#information .button.plus {
+background-position: -91px -122px;
+}
+
+#information .button.moins {
+background-position: -131px -122px;
+}
+
+#minify {
+background-color: #fff;
+padding: 4px 4px 4px 25px;
+cursor: pointer;
+background-image: url('../images/sprite.png');
+background-repeat: no-repeat;
+background-position: -167px -118px;
+position: absolute;
+top: 65px;
+left: 15px;
+display: none;
+}
+
+#minifier {
+position: absolute;
+width: 20px;
+height: 16px;
+background-image: url('../images/sprite.png');
+background-repeat: no-repeat;
+background-position: -45px -147px;
+cursor: pointer;
+display: none;
+}
+
+.input-icon {
+ position: absolute;
+ padding-top: 13px;
+ padding-left: 50px;
+}
+.box {
+ padding-bottom: 10%;
+
+}
+
+#websites {
+ list-style: none; /* Remove default bullets */
+}
+#websites li {
+ list-style: none;
+}
+#websites li::before {
+ content: "\2588 "; /* Add content: \2022 is the CSS Code/unicode for a square block */
+ font-weight: bold; /* If you want it to be bold */
+ display: inline-block; /* Needed to add space between the bullet and the text */
+ width: 1em; /* Also needed for space (tweak if needed) */
+ margin-left: -1em; /* Also needed for space (tweak if needed) */
+}
+.ui-all {
+ margin-left: 10px;
+}
+/* https://philipwalton.github.io/solved-by-flexbox/demos/holy-grail/ */
+.HolyGrail,
+.HolyGrail-body {
+ display: flex;
+ flex-direction: column;
+}
+
+.HolyGrail-nav {
+ order: -1;
+}
+
+@media (min-width: 768px) {
+ .HolyGrail-body {
+ flex-direction: row;
+ flex: 1 0 auto;
+ }
+ .HolyGrail-content {
+ flex: 1 0 auto;
+ }
+ .HolyGrail-nav, .HolyGrail-ads {
+ /* 12em is the width of the columns */
+ flex: 0 0 17em;
+ }
+}
diff --git a/html/observatory/css/tablet.css b/html/observatory/css/tablet.css
new file mode 100644
index 0000000..f89216d
--- /dev/null
+++ b/html/observatory/css/tablet.css
@@ -0,0 +1,3 @@
+#developercontainer {
+ display:none;
+}
\ No newline at end of file
diff --git a/html/observatory/data/.keep b/html/observatory/data/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/html/observatory/images/blank.gif b/html/observatory/images/blank.gif
new file mode 100644
index 0000000..35d42e8
Binary files /dev/null and b/html/observatory/images/blank.gif differ
diff --git a/html/observatory/images/fancybox_sprite.png b/html/observatory/images/fancybox_sprite.png
new file mode 100644
index 0000000..a1aae1a
Binary files /dev/null and b/html/observatory/images/fancybox_sprite.png differ
diff --git a/html/observatory/index.html b/html/observatory/index.html
new file mode 100644
index 0000000..5a40c5d
--- /dev/null
+++ b/html/observatory/index.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+This page has moved. Please click here if you are not automatically redirected to the new page.
+
+
diff --git a/html/observatory/js/designsystem.min.js b/html/observatory/js/designsystem.min.js
new file mode 100644
index 0000000..fccf6f9
--- /dev/null
+++ b/html/observatory/js/designsystem.min.js
@@ -0,0 +1 @@
+var AU=AU||{};!function(f){var e={};function u(e,t,n){if(e===t)return{stepSize:0,steps:0,intervalTime:0};var o=t-e,a=n/o,i=o<0?-1:1,l=Math.abs(o/i);return a=n/l,Math.abs(a)<1e3/60&&(a=1e3/60,i=o/(l=Math.ceil(Math.abs(n/a)))),{stepSize:i,steps:l-1,intervalTime:a}}"undefined"!=typeof module&&(e.CalculateAnimationSpecs=u),e.GetCSSPropertyBecauseIE=function(e,t){if("undefined"!=typeof getComputedStyle)return window.getComputedStyle(e)[t];var n=e.currentStyle[t];return"auto"===n&&(n=f.animate.CalculateAuto(e,t)),n},e.CalculateAuto=function(e,t){var n,o;return o="height"===t?(n=e.clientHeight,e.style[t]="auto",e.clientHeight):(n=e.clientWidth,e.style[t]="auto",e.clientWidth),e.style[t]=n+"px",parseInt(o)},e.Stop=function(e){clearInterval(e.AUanimation)},e.Run=function(i){var l=i.element,e=i.speed||250;l.length===undefined&&(l=[l]),"function"!=typeof i.callback&&(i.callback=function(){}),l[0].AUinteration=0,l[0].AUinterations=l.length;for(var t=0;t=l[0].AUinterations)return i.callback()}else n+=o.stepSize,e.style[i.property]=n+"px",o.steps--},Math.abs(o.intervalTime))}(n,o,c,r,a)}},e.Toggle=function(t){var n=t.element,e=t.property||"height",o=t.speed||250,a=t.closeSize===undefined?0:t.closeSize,i=t.openSize===undefined?"auto":t.openSize;n.length===undefined&&(n=[n]),"function"!=typeof t.prefunction&&(t.prefunction=function(){}),"function"!=typeof t.postfunction&&(t.postfunction=function(){}),"function"!=typeof t.callback&&(t.callback=function(){}),n[0].AUtoggleInteration=0,n[0].AUtoggleInterations=n.length;for(var l=0;lg;g++)for(var e=0;3>e;e++){for(var f=0,d=0;3>d;d++)f+=a[g][d]*b[d][e];c[g][e]=f}return c}function M(a,b){b.fillStyle=a.fillStyle;b.lineCap=a.lineCap;b.lineJoin=a.lineJoin;b.lineWidth=a.lineWidth;b.miterLimit=a.miterLimit;b.shadowBlur=a.shadowBlur;b.shadowColor=a.shadowColor;b.shadowOffsetX=
+a.shadowOffsetX;b.shadowOffsetY=a.shadowOffsetY;b.strokeStyle=a.strokeStyle;b.globalAlpha=a.globalAlpha;b.font=a.font;b.textAlign=a.textAlign;b.textBaseline=a.textBaseline;b.arcScaleX_=a.arcScaleX_;b.arcScaleY_=a.arcScaleY_;b.lineScale_=a.lineScale_}function N(a){var b=a.indexOf("(",3),c=a.indexOf(")",b+1),b=a.substring(b+1,c).split(",");if(4!=b.length||"a"!=a.charAt(3))b[3]=1;return b}function B(a,b,c){return Math.min(c,Math.max(b,a))}function C(a,b,c){0>c&&c++;16*c?a+6*(b-a)*c:
+1>2*c?b:2>3*c?a+6*(b-a)*(2/3-c):a}function D(a){if(a in E)return E[a];var b,c=1,a=""+a;if("#"==a.charAt(0))b=a;else if(/^rgb/.test(a)){c=N(a);b="#";for(var g,e=0;3>e;e++)g=-1!=c[e].indexOf("%")?Math.floor(255*(parseFloat(c[e])/100)):+c[e],b+=s[B(g,0,255)];c=+c[3]}else if(/^hsl/.test(a)){e=c=N(a);b=parseFloat(e[0])/360%360;0>b&&b++;g=B(parseFloat(e[1])/100,0,1);e=B(parseFloat(e[2])/100,0,1);if(0==g)g=e=b=e;else{var f=0.5>e?e*(1+g):e+g-e*g,d=2*e-f;g=C(d,f,b+1/3);e=C(d,f,b);b=C(d,f,b-1/3)}b="#"+s[Math.floor(255*
+g)]+s[Math.floor(255*e)]+s[Math.floor(255*b)];c=c[3]}else b=W[a]||a;return E[a]={color:b,alpha:c}}function z(a){this.m_=A();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.fillStyle=this.strokeStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=1*n;this.globalAlpha=1;this.font="10px sans-serif";this.textAlign="left";this.textBaseline="alphabetic";this.canvas=a;var b="width:"+a.clientWidth+"px;height:"+a.clientHeight+"px;overflow:hidden;position:absolute",
+c=a.ownerDocument.createElement("div");c.style.cssText=b;a.appendChild(c);b=c.cloneNode(!1);b.style.backgroundColor="red";b.style.filter="alpha(opacity=0)";a.appendChild(b);this.element_=c;this.lineScale_=this.arcScaleY_=this.arcScaleX_=1}function O(a,b,c,g){a.currentPath_.push({type:"bezierCurveTo",cp1x:b.x,cp1y:b.y,cp2x:c.x,cp2y:c.y,x:g.x,y:g.y});a.currentX_=g.x;a.currentY_=g.y}function P(a,b){var c=D(a.strokeStyle),g=c.color,c=c.alpha*a.globalAlpha,e=a.lineScale_*a.lineWidth;1>e&&(c*=e);b.push(" ')}function Q(a,b,c,g){var e=a.fillStyle,f=a.arcScaleX_,d=a.arcScaleY_,h=g.x-c.x,l=g.y-c.y;if(e instanceof t){var i=0,j=g=0,r=0,k=1;if("gradient"==e.type_){var i=e.x1_/f,c=e.y1_/d,m=p(a,e.x0_/f,e.y0_/d),i=p(a,i,c),i=180*Math.atan2(i.x-m.x,i.y-m.y)/Math.PI;0>i&&(i+=360);1.0E-6>i&&(i=0)}else m=p(a,e.x0_,e.y0_),g=(m.x-c.x)/h,j=(m.y-c.y)/l,h/=f*
+n,l/=d*n,k=u.max(h,l),r=2*e.r0_/k,k=2*e.r1_/k-r;f=e.colors_;f.sort(function(a,b){return a.offset-b.offset});for(var d=f.length,m=f[0].color,c=f[d-1].color,h=f[0].alpha*a.globalAlpha,a=f[d-1].alpha*a.globalAlpha,l=[],o=0;o ')}else e instanceof
+F?h&&l&&b.push(" '):(e=D(a.fillStyle),b.push(' '))}function p(a,b,c){a=a.m_;return{x:n*(b*a[0][0]+c*a[1][0]+a[2][0])-o,y:n*(b*a[0][1]+c*a[1][1]+a[2][1])-o}}function w(a,b,c){isFinite(b[0][0])&&isFinite(b[0][1])&&isFinite(b[1][0])&&isFinite(b[1][1])&&isFinite(b[2][0])&&isFinite(b[2][1])&&(a.m_=b,c&&(a.lineScale_=Y(Z(b[0][0]*b[1][1]-b[0][1]*
+b[1][0]))))}function t(a){this.type_=a;this.r1_=this.y1_=this.x1_=this.r0_=this.y0_=this.x0_=0;this.colors_=[]}function F(a,b){if(!a||1!=a.nodeType||"IMG"!=a.tagName)throw new x("TYPE_MISMATCH_ERR");if("complete"!=a.readyState)throw new x("INVALID_STATE_ERR");switch(b){case "repeat":case null:case "":this.repetition_="repeat";break;case "repeat-x":case "repeat-y":case "no-repeat":this.repetition_=b;break;default:throw new x("SYNTAX_ERR");}this.src_=a.src;this.width_=a.width;this.height_=a.height}
+function x(a){this.code=this[a];this.message=a+": DOM Exception "+this.code}var u=Math,h=u.round,G=u.sin,H=u.cos,Z=u.abs,Y=u.sqrt,n=10,o=n/2;navigator.userAgent.match(/MSIE ([\d.]+)?/);var J=Array.prototype.slice;L(document);var R={init:function(a){a=a||document;a.createElement("canvas");a.attachEvent("onreadystatechange",T(this.init_,this,a))},init_:function(a){for(var a=a.getElementsByTagName("canvas"),b=0;bd;d++)for(var y=0;16>y;y++)s[16*d+y]=d.toString(16)+y.toString(16);var W={aliceblue:"#F0F8FF",antiquewhite:"#FAEBD7",aquamarine:"#7FFFD4",azure:"#F0FFFF",beige:"#F5F5DC",
+bisque:"#FFE4C4",black:"#000000",blanchedalmond:"#FFEBCD",blueviolet:"#8A2BE2",brown:"#A52A2A",burlywood:"#DEB887",cadetblue:"#5F9EA0",chartreuse:"#7FFF00",chocolate:"#D2691E",coral:"#FF7F50",cornflowerblue:"#6495ED",cornsilk:"#FFF8DC",crimson:"#DC143C",cyan:"#00FFFF",darkblue:"#00008B",darkcyan:"#008B8B",darkgoldenrod:"#B8860B",darkgray:"#A9A9A9",darkgreen:"#006400",darkgrey:"#A9A9A9",darkkhaki:"#BDB76B",darkmagenta:"#8B008B",darkolivegreen:"#556B2F",darkorange:"#FF8C00",darkorchid:"#9932CC",darkred:"#8B0000",
+darksalmon:"#E9967A",darkseagreen:"#8FBC8F",darkslateblue:"#483D8B",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",darkturquoise:"#00CED1",darkviolet:"#9400D3",deeppink:"#FF1493",deepskyblue:"#00BFFF",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1E90FF",firebrick:"#B22222",floralwhite:"#FFFAF0",forestgreen:"#228B22",gainsboro:"#DCDCDC",ghostwhite:"#F8F8FF",gold:"#FFD700",goldenrod:"#DAA520",grey:"#808080",greenyellow:"#ADFF2F",honeydew:"#F0FFF0",hotpink:"#FF69B4",indianred:"#CD5C5C",indigo:"#4B0082",
+ivory:"#FFFFF0",khaki:"#F0E68C",lavender:"#E6E6FA",lavenderblush:"#FFF0F5",lawngreen:"#7CFC00",lemonchiffon:"#FFFACD",lightblue:"#ADD8E6",lightcoral:"#F08080",lightcyan:"#E0FFFF",lightgoldenrodyellow:"#FAFAD2",lightgreen:"#90EE90",lightgrey:"#D3D3D3",lightpink:"#FFB6C1",lightsalmon:"#FFA07A",lightseagreen:"#20B2AA",lightskyblue:"#87CEFA",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#B0C4DE",lightyellow:"#FFFFE0",limegreen:"#32CD32",linen:"#FAF0E6",magenta:"#FF00FF",mediumaquamarine:"#66CDAA",
+mediumblue:"#0000CD",mediumorchid:"#BA55D3",mediumpurple:"#9370DB",mediumseagreen:"#3CB371",mediumslateblue:"#7B68EE",mediumspringgreen:"#00FA9A",mediumturquoise:"#48D1CC",mediumvioletred:"#C71585",midnightblue:"#191970",mintcream:"#F5FFFA",mistyrose:"#FFE4E1",moccasin:"#FFE4B5",navajowhite:"#FFDEAD",oldlace:"#FDF5E6",olivedrab:"#6B8E23",orange:"#FFA500",orangered:"#FF4500",orchid:"#DA70D6",palegoldenrod:"#EEE8AA",palegreen:"#98FB98",paleturquoise:"#AFEEEE",palevioletred:"#DB7093",papayawhip:"#FFEFD5",
+peachpuff:"#FFDAB9",peru:"#CD853F",pink:"#FFC0CB",plum:"#DDA0DD",powderblue:"#B0E0E6",rosybrown:"#BC8F8F",royalblue:"#4169E1",saddlebrown:"#8B4513",salmon:"#FA8072",sandybrown:"#F4A460",seagreen:"#2E8B57",seashell:"#FFF5EE",sienna:"#A0522D",skyblue:"#87CEEB",slateblue:"#6A5ACD",slategray:"#708090",slategrey:"#708090",snow:"#FFFAFA",springgreen:"#00FF7F",steelblue:"#4682B4",tan:"#D2B48C",thistle:"#D8BFD8",tomato:"#FF6347",turquoise:"#40E0D0",violet:"#EE82EE",wheat:"#F5DEB3",whitesmoke:"#F5F5F5",yellowgreen:"#9ACD32"},
+E={},I={},X={butt:"flat",round:"round"},d=z.prototype;d.clearRect=function(){this.textMeasureEl_&&(this.textMeasureEl_.removeNode(!0),this.textMeasureEl_=null);this.element_.innerHTML=""};d.beginPath=function(){this.currentPath_=[]};d.moveTo=function(a,b){var c=p(this,a,b);this.currentPath_.push({type:"moveTo",x:c.x,y:c.y});this.currentX_=c.x;this.currentY_=c.y};d.lineTo=function(a,b){var c=p(this,a,b);this.currentPath_.push({type:"lineTo",x:c.x,y:c.y});this.currentX_=c.x;this.currentY_=c.y};d.bezierCurveTo=
+function(a,b,c,g,e,f){e=p(this,e,f);a=p(this,a,b);c=p(this,c,g);O(this,a,c,e)};d.quadraticCurveTo=function(a,b,c,g){a=p(this,a,b);c=p(this,c,g);g={x:this.currentX_+2/3*(a.x-this.currentX_),y:this.currentY_+2/3*(a.y-this.currentY_)};O(this,g,{x:g.x+(c.x-this.currentX_)/3,y:g.y+(c.y-this.currentY_)/3},c)};d.arc=function(a,b,c,g,e,f){var c=c*n,d=f?"at":"wa",h=a+H(g)*c-o,l=b+G(g)*c-o,g=a+H(e)*c-o,e=b+G(e)*c-o;h==g&&!f&&(h+=0.125);a=p(this,a,b);h=p(this,h,l);g=p(this,g,e);this.currentPath_.push({type:d,
+x:a.x,y:a.y,radius:c,xStart:h.x,yStart:h.y,xEnd:g.x,yEnd:g.y})};d.rect=function(a,b,c,g){this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+g);this.lineTo(a,b+g);this.closePath()};d.strokeRect=function(a,b,c,g){var e=this.currentPath_;this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+g);this.lineTo(a,b+g);this.closePath();this.stroke();this.currentPath_=e};d.fillRect=function(a,b,c,g){var e=this.currentPath_;this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+
+c,b+g);this.lineTo(a,b+g);this.closePath();this.fill();this.currentPath_=e};d.createLinearGradient=function(a,b,c,g){var e=new t("gradient");e.x0_=a;e.y0_=b;e.x1_=c;e.y1_=g;return e};d.createRadialGradient=function(a,b,c,g,e,f){var d=new t("gradientradial");d.x0_=a;d.y0_=b;d.r0_=c;d.x1_=g;d.y1_=e;d.r1_=f;return d};d.drawImage=function(a,b){var c,g,e,d,o,v,l,i;e=a.runtimeStyle.width;d=a.runtimeStyle.height;a.runtimeStyle.width="auto";a.runtimeStyle.height="auto";var j=a.width,r=a.height;a.runtimeStyle.width=
+e;a.runtimeStyle.height=d;if(3==arguments.length)c=arguments[1],g=arguments[2],o=v=0,l=e=j,i=d=r;else if(5==arguments.length)c=arguments[1],g=arguments[2],e=arguments[3],d=arguments[4],o=v=0,l=j,i=r;else if(9==arguments.length)o=arguments[1],v=arguments[2],l=arguments[3],i=arguments[4],c=arguments[5],g=arguments[6],e=arguments[7],d=arguments[8];else throw Error("Invalid number of arguments");var k=p(this,c,g),m=[];m.push(" ',' "," ");this.element_.insertAdjacentHTML("BeforeEnd",m.join(""))};d.stroke=function(a){var b=[];b.push("d.x)d.x=f.x;if(null==c.y||f.yd.y)d.y=f.y}}b.push(' ">');a?Q(this,b,c,d):P(this,b);b.push(" ");this.element_.insertAdjacentHTML("beforeEnd",b.join(""))};d.fill=function(){this.stroke(!0)};d.closePath=function(){this.currentPath_.push({type:"close"})};d.save=function(){var a=
+{};M(this,a);this.aStack_.push(a);this.mStack_.push(this.m_);this.m_=q(A(),this.m_)};d.restore=function(){this.aStack_.length&&(M(this.aStack_.pop(),this),this.m_=this.mStack_.pop())};d.translate=function(a,b){w(this,q([[1,0,0],[0,1,0],[a,b,1]],this.m_),!1)};d.rotate=function(a){var b=H(a),a=G(a);w(this,q([[b,a,0],[-a,b,0],[0,0,1]],this.m_),!1)};d.scale=function(a,b){this.arcScaleX_*=a;this.arcScaleY_*=b;w(this,q([[a,0,0],[0,b,0],[0,0,1]],this.m_),!0)};d.transform=function(a,b,c,d,e,f){w(this,q([[a,
+b,0],[c,d,0],[e,f,1]],this.m_),!0)};d.setTransform=function(a,b,c,d,e,f){w(this,[[a,b,0],[c,d,0],[e,f,1]],!0)};d.drawText_=function(a,b,c,d,e){var f=this.m_,d=0,o=1E3,q=0,l=[],i;i=this.font;if(I[i])i=I[i];else{var j=document.createElement("div").style;try{j.font=i}catch(r){}i=I[i]={style:j.fontStyle||"normal",variant:j.fontVariant||"normal",weight:j.fontWeight||"normal",size:j.fontSize||10,family:j.fontFamily||"sans-serif"}}var j=i,k=this.element_;i={};for(var m in j)i[m]=j[m];m=parseFloat(k.currentStyle.fontSize);
+k=parseFloat(j.size);i.size="number"==typeof j.size?j.size:-1!=j.size.indexOf("px")?k:-1!=j.size.indexOf("em")?m*k:-1!=j.size.indexOf("%")?m/100*k:-1!=j.size.indexOf("pt")?k/0.75:m;i.size*=0.981;m=i.style+" "+i.variant+" "+i.weight+" "+i.size+"px "+i.family;k=this.element_.currentStyle;j=this.textAlign.toLowerCase();switch(j){case "left":case "center":case "right":break;case "end":j="ltr"==k.direction?"right":"left";break;case "start":j="rtl"==k.direction?"right":"left";break;default:j="left"}switch(this.textBaseline){case "hanging":case "top":q=
+i.size/1.75;break;case "middle":break;default:case null:case "alphabetic":case "ideographic":case "bottom":q=-i.size/2.25}switch(j){case "right":d=1E3;o=0.05;break;case "center":d=o=500}b=p(this,b+0,c+q);l.push('');e?P(this,l):Q(this,l,{x:-d,y:0},{x:o,y:i.size});e=f[0][0].toFixed(3)+","+f[1][0].toFixed(3)+","+f[0][1].toFixed(3)+
+","+f[1][1].toFixed(3)+",0,0";b=h(b.x/n)+","+h(b.y/n);l.push(' ',' ',' ');this.element_.insertAdjacentHTML("beforeEnd",l.join(""))};d.fillText=function(a,b,c,d){this.drawText_(a,b,c,d,!1)};d.strokeText=function(a,b,c,d){this.drawText_(a,b,c,d,!0)};d.measureText=function(a){this.textMeasureEl_||(this.element_.insertAdjacentHTML("beforeEnd",
+' '),this.textMeasureEl_=this.element_.lastChild);var b=this.element_.ownerDocument;this.textMeasureEl_.innerHTML="";this.textMeasureEl_.style.font=this.font;this.textMeasureEl_.appendChild(b.createTextNode(a));return{width:this.textMeasureEl_.offsetWidth}};d.clip=function(){};d.arcTo=function(){};d.createPattern=function(a,b){return new F(a,b)};t.prototype.addColorStop=function(a,b){b=D(b);this.colors_.push({offset:a,
+color:b.color,alpha:b.alpha})};d=x.prototype=Error();d.INDEX_SIZE_ERR=1;d.DOMSTRING_SIZE_ERR=2;d.HIERARCHY_REQUEST_ERR=3;d.WRONG_DOCUMENT_ERR=4;d.INVALID_CHARACTER_ERR=5;d.NO_DATA_ALLOWED_ERR=6;d.NO_MODIFICATION_ALLOWED_ERR=7;d.NOT_FOUND_ERR=8;d.NOT_SUPPORTED_ERR=9;d.INUSE_ATTRIBUTE_ERR=10;d.INVALID_STATE_ERR=11;d.SYNTAX_ERR=12;d.INVALID_MODIFICATION_ERR=13;d.NAMESPACE_ERR=14;d.INVALID_ACCESS_ERR=15;d.VALIDATION_ERR=16;d.TYPE_MISMATCH_ERR=17;G_vmlCanvasManager=R;CanvasRenderingContext2D=z;CanvasGradient=
+t;CanvasPattern=F;DOMException=x}();
\ No newline at end of file
diff --git a/html/observatory/js/main.js b/html/observatory/js/main.js
new file mode 100644
index 0000000..93e0935
--- /dev/null
+++ b/html/observatory/js/main.js
@@ -0,0 +1,720 @@
+var sigInst, canvas, $GP;
+var colorBrewer2Set3 = [
+ "#8dd3c7",
+ "#ffffb3",
+ "#bebada",
+ "#fb8072",
+ "#80b1d3",
+ "#fdb462",
+ "#b3de69",
+ "#fccde5",
+ "#d9d9d9",
+ "#bc80bd",
+ "#ccebc5",
+ "#ffed6f"
+]; // http://colorbrewer2.org/#type=qualitative&scheme=Set3&n=12
+//Load configuration file
+var config = {};
+
+//For debug allow a config=file.json parameter to specify the config
+function GetQueryStringParams(sParam, defaultVal) {
+ var sPageURL = "" + window.location; //.search.substring(1);//This might be causing error in Safari?
+ if (sPageURL.indexOf("?") == -1) return defaultVal;
+ sPageURL = sPageURL.substr(sPageURL.indexOf("?") + 1);
+ var sURLVariables = sPageURL.split("&");
+ for (var i = 0; i < sURLVariables.length; i++) {
+ var sParameterName = sURLVariables[i].split("=");
+ if (sParameterName[0] == sParam) {
+ return sParameterName[1];
+ }
+ }
+ return defaultVal;
+}
+
+jQuery.getJSON(GetQueryStringParams("config", "config.json"), function(
+ data,
+ textStatus,
+ jqXHR
+) {
+ config = data;
+
+ if (config.type != "network") {
+ //bad config
+ alert("Invalid configuration settings.");
+ return;
+ }
+
+ //As soon as page is ready (and data ready) set up it
+ $(document).ready(setupGUI(config));
+}); //End JSON Config load
+
+// FUNCTION DECLARATIONS
+
+Object.size = function(obj) {
+ var size = 0,
+ key;
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) size++;
+ }
+ return size;
+};
+
+function initSigma(config) {
+ var data = config.data;
+
+ var drawProps, graphProps, mouseProps;
+ // https://github.com/jacomyal/sigma.js/wiki/Settings
+
+ if (config.sigma && config.sigma.drawingProperties)
+ drawProps = config.sigma.drawingProperties;
+ else
+ drawProps = {
+ defaultLabelColor: "#000",
+ defaultLabelSize: 10,
+ defaultLabelBGColor: "#ddd",
+ defaultHoverLabelBGColor: "#002147",
+ defaultLabelHoverColor: "#fff",
+ labelThreshold: 100,
+ defaultEdgeType: "curve",
+ edgeColor: "source",
+ hoverFontStyle: "bold",
+ fontStyle: "bold",
+ activeFontStyle: "bold",
+ borderSize: 2, //Something other than 0
+ nodeBorderColor: "default", //exactly like this
+ defaultNodeBorderColor: "#000", //Any color of your choice
+ defaultBorderView: "always" //apply the default color to all nodes always (normal+hover)
+ };
+
+ if (config.sigma && config.sigma.graphProperties)
+ graphProps = config.sigma.graphProperties;
+ else
+ graphProps = {
+ minNodeSize: 1,
+ maxNodeSize: 20,
+ minEdgeSize: 0.2,
+ maxEdgeSize: 0.5
+ };
+
+ if (config.sigma && config.sigma.mouseProperties)
+ mouseProps = config.sigma.mouseProperties;
+ else
+ mouseProps = {
+ minRatio: 0.75, // How far can we zoom out?
+ maxRatio: 20 // How far can we zoom in?
+ };
+
+ var a = sigma
+ .init(document.getElementById("sigma-canvas"))
+ .drawingProperties(drawProps)
+ .graphProperties(graphProps)
+ .mouseProperties(mouseProps);
+ sigInst = a;
+ a.active = false;
+ a.neighbors = {};
+ a.detail = false;
+
+ dataReady = function() {
+ //This is called as soon as data is loaded
+ a.clusters = {};
+ a.iterEdges(function(b) {
+ b.attr["true_color"] = b.color;
+ });
+ a.iterNodes(function(b) {
+ //This is where we populate the array used for the group select box
+
+ // note: index may not be consistent for all nodes. Should calculate each time.
+ // note: index may not be consistent for all nodes. Should calculate each time.
+ // alert(JSON.stringify(b.attr.attributes[5].val));
+ // alert(b.x);
+ b.attr["true_color"] = b.color;
+ // if (b.id.endsWith("()")) {
+ // b.attr['drawBorder'] = true;
+ // }
+ a.clusters[b.attr.attributes.domain] ||
+ (a.clusters[b.attr.attributes.domain] = []);
+ a.clusters[b.attr.attributes.domain].push(b.id); //SAH: push id not label
+ });
+
+ // a.bind("upnodes", function(a) {
+ // nodeActive(a.content[0]);
+ // });
+
+ a.draw();
+ configSigmaElements(config);
+ };
+
+ if (data.indexOf("gexf") > 0 || data.indexOf("xml") > 0)
+ a.parseGexf("data/" + data, dataReady);
+ else a.parseJson("data/" + data, dataReady);
+ gexf = sigmaInst = null;
+}
+
+function setupGUI(config) {
+ // Initialise main interface elements
+ $("#agencyName").html(config.agency.name);
+ // Node
+ if (config.legend.nodeLabel) {
+ $(".node")
+ .next()
+ .html(config.legend.nodeLabel);
+ } else {
+ //hide more information link
+ $(".node").hide();
+ }
+ // Edge
+ if (config.legend.edgeLabel) {
+ $(".edge")
+ .next()
+ .html(config.legend.edgeLabel);
+ } else {
+ //hide more information link
+ $(".edge").hide();
+ }
+ // Colours
+ if (config.legend.nodeLabel) {
+ $(".colours")
+ .next()
+ .html(config.legend.colorLabel);
+ } else {
+ //hide more information link
+ $(".colours").hide();
+ }
+ $.each(config.agency.websites, function(i) {
+ var li = $(" ")
+ .css("color", colorBrewer2Set3[i])
+ .addClass("ui-menu-item")
+ .attr("role", "menuitem")
+ .appendTo($("#websites"));
+
+ var aaa = $(" ")
+ .addClass("ui-all")
+ .text(config.agency.websites[i])
+ .attr("href", "#" + config.agency.websites[i])
+ .click(function() {
+ showCluster(config.agency.websites[i]);
+ })
+ .appendTo(li);
+ });
+ $GP = {
+ calculating: false,
+ showgroup: false
+ };
+ $GP.intro = $("#intro");
+ $GP.minifier = $GP.intro.find("#minifier");
+ $GP.mini = $("#minify");
+ $GP.info = $("#attributepane");
+ $GP.info_donnees = $GP.info.find(".nodeattributes");
+ $GP.info_name = $GP.info.find(".name");
+ $GP.info_link = $GP.info.find(".link");
+ $GP.info_data = $GP.info.find(".data");
+ $GP.info_close = $GP.info.find(".returntext");
+ $GP.info_close2 = $GP.info.find(".close");
+ $GP.info_p = $GP.info.find(".p");
+ $GP.info_close.click(nodeNormal);
+ $GP.info_close2.click(nodeNormal);
+ $GP.form = $("#mainpanel").find("form");
+ $GP.search = new Search($GP.form.find("#search"));
+ if (!config.features.search.enabled == true) {
+ $("#search").hide();
+ }
+ if (!config.features.groupSelector.enabled == true) {
+ $("#attributeselect").hide();
+ }
+ $GP.cluster = new Cluster($GP.form.find("#attributeselect"));
+ config.GP = $GP;
+ initSigma(config);
+}
+
+function configSigmaElements(config) {
+ $GP = config.GP;
+
+ $GP.bg = $(sigInst._core.domElements.bg);
+ $GP.bg2 = $(sigInst._core.domElements.bg2);
+ var clusterList = [],
+ clusterDomain;
+ for (clusterDomain in sigInst.clusters) {
+ clusterList.push(
+ '"
+ );
+ }
+ //a.sort();
+ $GP.cluster.content(clusterList.join(""));
+
+ $("#zoom")
+ .find(".z")
+ .each(function() {
+ var a = $(this),
+ b = a.attr("rel");
+ a.click(function() {
+ if (b == "center") {
+ sigInst.position(0, 0, 1).draw();
+ } else {
+ var a = sigInst._core;
+ sigInst.zoomTo(
+ a.domElements.nodes.width / 2,
+ a.domElements.nodes.height / 2,
+ a.mousecaptor.ratio * ("in" == b ? 1.5 : 0.5)
+ );
+ }
+ });
+ });
+ $GP.mini.click(function() {
+ $GP.mini.hide();
+ $GP.intro.show();
+ $GP.minifier.show();
+ });
+ $GP.minifier.click(function() {
+ $GP.intro.hide();
+ $GP.minifier.hide();
+ $GP.mini.show();
+ });
+ $GP.intro.find("#showGroups").click(function() {
+ true == $GP.showgroup ? showGroups(false) : showGroups(true);
+ });
+ clusterList = window.location.hash.substr(1);
+ if (0 < clusterList.length)
+ switch (clusterList) {
+ case "Groups":
+ showGroups(true);
+ break;
+ case "information":
+ $.fancybox.open($("#information"), clusterDomain);
+ break;
+ default:
+ ($GP.search.exactMatch = true), $GP.search.search(clusterList);
+ $GP.search.clean();
+ }
+}
+
+function Search(a) {
+ this.input = a.find("input[name=search]");
+ this.state = a.find(".state");
+ this.results = a.find(".results");
+ this.exactMatch = false;
+ this.lastSearch = "";
+ this.searching = false;
+ var b = this;
+ this.input.focus(function() {
+ var a = $(this);
+ a.data("focus") || (a.data("focus", true), a.removeClass("empty"));
+ b.clean();
+ });
+ this.input.keydown(function(a) {
+ if (13 == a.which)
+ return b.state.addClass("searching"), b.search(b.input.val()), false;
+ });
+ this.state.click(function() {
+ var a = b.input.val();
+ b.searching && a == b.lastSearch
+ ? b.close()
+ : (b.state.addClass("searching"), b.search(a));
+ });
+ this.dom = a;
+ this.close = function() {
+ this.state.removeClass("searching");
+ this.results.hide();
+ this.searching = false;
+ this.input.val(""); //SAH -- let's erase string when we close
+ nodeNormal();
+ };
+ this.clean = function() {
+ this.results.empty().hide();
+ this.state.removeClass("searching");
+ this.input.val("");
+ };
+ this.search = function(a) {
+ var b = false,
+ c = [],
+ b = this.exactMatch ? ("^" + a + "$").toLowerCase() : a.toLowerCase(),
+ g = RegExp(b);
+ this.exactMatch = false;
+ this.searching = true;
+ this.lastSearch = a;
+ this.results.empty();
+ if (2 >= a.length)
+ this.results.html(
+ "You must search for a name with a minimum of 3 letters. "
+ );
+ else {
+ sigInst.iterNodes(function(a) {
+ g.test(a.label.toLowerCase()) &&
+ c.push({
+ id: a.id,
+ name: a.label
+ });
+ });
+ c.length ? ((b = true), nodeActive(c[0].id)) : (b = showCluster(a));
+ a = ["Search Results: "];
+ if (1 < c.length)
+ for (var d = 0, h = c.length; d < h; d++)
+ a.push(
+ '" +
+ c[d].name +
+ " "
+ );
+ 0 == c.length && !b && a.push("No results found. ");
+ 1 < a.length && this.results.html(a.join(""));
+ }
+ if (c.length != 1) this.results.show();
+ if (c.length == 1) this.results.hide();
+ };
+}
+
+function Cluster(a) {
+ this.cluster = a;
+ this.display = false;
+ this.list = this.cluster.find(".list");
+ this.list.empty();
+
+ this.toggle = function() {
+ this.display ? this.hide() : this.show();
+ };
+ this.content = function(a) {
+ this.list.html(a);
+ this.list.find("a").click(function() {
+ var a = $(this)
+ .attr("href")
+ .substr(1);
+ showCluster(a);
+ });
+ };
+}
+function showGroups(a) {
+ a
+ ? ($GP.intro.find("#showGroups").text("Hide groups"),
+ $GP.bg.show(),
+ $GP.bg2.hide(),
+ ($GP.showgroup = true))
+ : ($GP.intro.find("#showGroups").text("View Groups"),
+ $GP.bg.hide(),
+ $GP.bg2.show(),
+ ($GP.showgroup = false));
+}
+
+function nodeNormal() {
+ if (true != $GP.calculating && false != sigInst.detail) {
+ sigInst.drawingProperties("edgeColor", "source");
+ showGroups(false);
+ $GP.calculating = true;
+ sigInst.detail = true;
+ $GP.info.hide();
+ sigInst.iterEdges(function(a) {
+ a.attr.color = false;
+ a.hidden = false;
+ a.color = a.attr["true_color"];
+ a.attr["grey"] = false;
+ });
+ sigInst.iterNodes(function(a) {
+ a.attr["drawBorder"] = false;
+ a.hidden = false;
+ a.attr.color = false;
+ a.attr.lineWidth = false;
+ a.attr.size = false;
+ a.color = a.attr["true_color"];
+ a.attr["grey"] = false;
+ });
+ sigInst.draw(2, 2, 2, 2);
+ sigInst.neighbors = {};
+ sigInst.active = false;
+ $GP.calculating = false;
+ window.location.hash = "";
+ }
+}
+
+function nodeActive(a) {
+ var groupByDirection = false;
+ if (
+ config.informationPanel.groupByEdgeDirection &&
+ config.informationPanel.groupByEdgeDirection == true
+ )
+ groupByDirection = true;
+
+ sigInst.neighbors = {};
+ sigInst.detail = !0;
+ var b = sigInst._core.graph.nodesIndex[a];
+ showGroups(!1);
+ var outgoing = {},
+ incoming = {},
+ mutual = {}; //SAH
+ sigInst.iterEdges(function(b) {
+ b.attr.lineWidth = !1;
+ b.hidden = !0;
+
+ n = {
+ name: b.label,
+ colour: b.color
+ };
+
+ if (a == b.source) outgoing[b.target] = n;
+ //SAH
+ else if (a == b.target) incoming[b.source] = n; //SAH
+ if (a == b.source || a == b.target)
+ sigInst.neighbors[a == b.target ? b.source : b.target] = n;
+ (b.hidden = false), (b.attr.color = "rgba(0, 0, 0, 1)");
+ });
+ var f = [];
+ sigInst.iterNodes(function(a) {
+ a.hidden = true;
+ a.attr.lineWidth = false;
+ a.attr.color = a.color;
+ });
+
+ if (groupByDirection) {
+ //SAH - Compute intersection for mutual and remove these from incoming/outgoing
+ for (e in outgoing) {
+ //name=outgoing[e];
+ if (e in incoming) {
+ mutual[e] = outgoing[e];
+ delete incoming[e];
+ delete outgoing[e];
+ }
+ }
+ }
+
+ var createList = function(c) {
+ var f = [];
+ var e = [],
+ //c = sigInst.neighbors,
+ g;
+ for (g in c) {
+ var d = sigInst._core.graph.nodesIndex[g];
+ d.hidden = !1;
+ d.attr.lineWidth = !1;
+ d.attr.color = c[g].colour;
+ a != g &&
+ e.push({
+ id: g,
+ name: d.label,
+ group: c[g].name ? c[g].name : "",
+ colour: c[g].colour
+ });
+ }
+ e.sort(function(a, b) {
+ var c = a.group.toLowerCase(),
+ d = b.group.toLowerCase(),
+ e = a.name.toLowerCase(),
+ f = b.name.toLowerCase();
+ return c != d ? (c < d ? -1 : c > d ? 1 : 0) : e < f ? -1 : e > f ? 1 : 0;
+ });
+ d = "";
+ for (g in e) {
+ c = e[g];
+ /*if (c.group != d) {
+ d = c.group;
+ f.push('
' + d + "
");
+ }*/
+ f.push(
+ '' +
+ c.name +
+ " "
+ );
+ }
+ return f;
+ };
+
+ /*console.log("mutual:");
+ console.log(mutual);
+ console.log("incoming:");
+ console.log(incoming);
+ console.log("outgoing:");
+ console.log(outgoing);*/
+
+ var f = [];
+
+ //console.log("neighbors:");
+ //console.log(sigInst.neighbors);
+
+ if (groupByDirection) {
+ size = Object.size(mutual);
+ f.push("Mututal (" + size + ") ");
+ size > 0
+ ? (f = f.concat(createList(mutual)))
+ : f.push("No mutual links ");
+ size = Object.size(incoming);
+ f.push("Incoming (" + size + ") ");
+ size > 0
+ ? (f = f.concat(createList(incoming)))
+ : f.push("No incoming links ");
+ size = Object.size(outgoing);
+ f.push("Outgoing (" + size + ") ");
+ size > 0
+ ? (f = f.concat(createList(outgoing)))
+ : f.push("No outgoing links ");
+ } else {
+ f = f.concat(createList(sigInst.neighbors));
+ }
+ //b is object of active node -- SAH
+ b.hidden = false;
+ b.attr.color = b.color;
+ b.attr.lineWidth = 6;
+ b.attr.strokeStyle = "#000000";
+ sigInst.draw(2, 2, 2, 2);
+
+ $GP.info_link.find("ul").html(f.join(""));
+ $GP.info_link.find("li").each(function() {
+ var a = $(this),
+ b = a.attr("rel");
+ });
+ f = b.attr;
+ if (f.attributes) {
+ var image_attribute = false;
+ if (config.informationPanel.imageAttribute) {
+ image_attribute = config.informationPanel.imageAttribute;
+ }
+ e = [];
+ temp_array = [];
+ g = 0;
+ for (var attr in f.attributes) {
+ var d = f.attributes[attr],
+ h = "";
+ if (attr != image_attribute) {
+ h = "" + attr + ": " + d + " ";
+ }
+ //temp_array.push(f.attributes[g].attr);
+ e.push(h);
+ }
+
+ if (image_attribute) {
+ //image_index = jQuery.inArray(image_attribute, temp_array);
+ $GP.info_name.html(
+ " ' +
+ b.label +
+ " "
+ );
+ } else {
+ $GP.info_name.html(
+ "' +
+ b.label +
+ "
"
+ );
+ }
+ // Image field for attribute pane
+ $GP.info_data.html(e.join(" "));
+ }
+ $GP.info_data.show();
+ $GP.info_p.html("Connections:");
+ $GP.info.show();
+ $GP.info_donnees.hide();
+ $GP.info_donnees.show();
+ sigInst.active = a;
+ window.location.hash = b.label;
+}
+
+function showCluster(a) {
+ var b = sigInst.clusters[a];
+ if (b && 0 < b.length) {
+ //showGroups(false);
+ sigInst.drawingProperties("edgeColor", "default");
+ sigInst.detail = true;
+ b.sort();
+ sigInst.iterEdges(function(a) {
+ a.hidden = false;
+ a.attr.lineWidth = false;
+ a.attr.color = false;
+ a.color = a.attr["true_color"];
+ a.attr["grey"] = 1;
+ });
+
+ sigInst.iterNodes(function(n) {
+ n.attr["grey"] = 1;
+ n.attr["drawBorder"] = true;
+ });
+ var clusterIds = [];
+ var toBeMoved = [];
+ for (var f = [], clusters = [], c = 0, g = b.length; c < g; c++) {
+ var d = sigInst._core.graph.nodesIndex[b[c]];
+ if (d.attr["grey"]) {
+ clusters.push(b[c]);
+
+ d.attr.lineWidth = true;
+ f.push(
+ '' +
+ d.label.replace(a, "").replace(/\/\//g, "/") +
+ " "
+ );
+
+ d.attr["drawBorder"] = false;
+ if (config.agency.websites.indexOf(a)> -1) {
+ d.color = colorBrewer2Set3[config.agency.websites.indexOf(a)];
+ } else {
+ d.color="red";
+
+ }
+ d.attr["grey"] = false;
+ toBeMoved.push(
+ sigInst._core.graph.nodes.findIndex(function(e) {
+ return e.id == d.id;
+ })
+ );
+ clusterIds.push(d.id);
+ }
+ }
+ sigInst.iterEdges(function(edge) {
+ if (
+ clusterIds.indexOf(edge.target) >= 0 ||
+ clusterIds.indexOf(edge.source) >= 0
+ ) {
+ if (config.agency.websites.indexOf(a)>-1) {
+ d.color = colorBrewer2Set3[config.agency.websites.indexOf(a)];
+ } else {
+ d.color="red";
+
+ }
+ edge.attr["grey"] = false;
+ }
+ });
+ toBeMoved.forEach(function(m) {
+ moved = sigInst._core.graph.nodes.splice(m, 1);
+ sigInst._core.graph.nodes.push(moved[0]);
+ //sigInst._core.graph.nodesIndex[moved[0].id] = sigInst._core.graph.nodes.length;
+ });
+
+ sigInst.clusters[a] = clusters;
+ sigInst.refresh();
+ sigInst.draw(2, 2, 2, 2);
+ $GP.info_name.html("" + a + " ");
+ $GP.info_data.hide();
+ $GP.info_p.html("Pages:");
+ $GP.info_link.find("ul").html(f.join(""));
+ $GP.info.show();
+ $GP.search.clean();
+ return true;
+ }
+ return false;
+}
diff --git a/html/observatory/js/sigma/sigma.min.js b/html/observatory/js/sigma/sigma.min.js
new file mode 100644
index 0000000..182f3e8
--- /dev/null
+++ b/html/observatory/js/sigma/sigma.min.js
@@ -0,0 +1,1800 @@
+/* sigmajs.org - an open-source light-weight JavaScript graph drawing library - Version: 0.1 - Author: Alexis Jacomy - License: MIT */
+var sigma = { tools: {}, classes: {}, instances: {} };
+(function() {
+ Array.prototype.some ||
+ (Array.prototype.some = function(g, i) {
+ var k = this.length;
+ if ("function" != typeof g) throw new TypeError();
+ for (var m = 0; m < k; m++)
+ if (m in this && g.call(i, this[m], m, this)) return !0;
+ return !1;
+ });
+ Array.prototype.forEach ||
+ (Array.prototype.forEach = function(g, i) {
+ var k = this.length;
+ if (typeof g != "function") throw new TypeError();
+ for (var m = 0; m < k; m++) m in this && g.call(i, this[m], m, this);
+ });
+ Array.prototype.map ||
+ (Array.prototype.map = function(g, i) {
+ var k = this.length;
+ if (typeof g != "function") throw new TypeError();
+ for (var m = Array(k), b = 0; b < k; b++)
+ b in this && (m[b] = g.call(i, this[b], b, this));
+ return m;
+ });
+ Array.prototype.filter ||
+ (Array.prototype.filter = function(g, i) {
+ var k = this.length;
+ if (typeof g != "function") throw new TypeError();
+ for (var m = [], b = 0; b < k; b++)
+ if (b in this) {
+ var j = this[b];
+ g.call(i, j, b, this) && m.push(j);
+ }
+ return m;
+ });
+ if (!Object.keys) {
+ var i = Object,
+ q = Object.prototype.hasOwnProperty,
+ g = !{ toString: null }.propertyIsEnumerable("toString"),
+ p = "toString toLocaleString valueOf hasOwnProperty isPrototypeOf propertyIsEnumerable constructor".split(
+ " "
+ ),
+ z = p.length;
+ i.keys = function(i) {
+ if ((typeof i !== "object" && typeof i !== "function") || i === null)
+ throw new TypeError("Object.keys called on non-object");
+ var x = [],
+ k;
+ for (k in i) q.call(i, k) && x.push(k);
+ if (g) for (k = 0; k < z; k++) q.call(i, p[k]) && x.push(p[k]);
+ return x;
+ };
+ }
+})();
+sigma.classes.Cascade = function() {
+ this.p = {};
+ this.config = function(i, q) {
+ if ("string" == typeof i && void 0 == q) return this.p[i];
+ var g = "object" == typeof i && void 0 == q ? i : {};
+ "string" == typeof i && (g[i] = q);
+ for (var p in g) void 0 != this.p[p] && (this.p[p] = g[p]);
+ return this;
+ };
+};
+sigma.classes.EventDispatcher = function() {
+ var i = {},
+ q = this;
+ this.one = function(g, p) {
+ if (!p || !g) return q;
+ ("string" == typeof g ? g.split(" ") : g).forEach(function(g) {
+ i[g] || (i[g] = []);
+ i[g].push({ h: p, one: !0 });
+ });
+ return q;
+ };
+ this.bind = function(g, p) {
+ if (!p || !g) return q;
+ ("string" == typeof g ? g.split(" ") : g).forEach(function(g) {
+ i[g] || (i[g] = []);
+ i[g].push({ h: p, one: !1 });
+ });
+ return q;
+ };
+ this.unbind = function(g, p) {
+ g || (i = {});
+ var z = "string" == typeof g ? g.split(" ") : g;
+ p
+ ? z.forEach(function(g) {
+ i[g] &&
+ (i[g] = i[g].filter(function(g) {
+ return g.h != p;
+ }));
+ i[g] && 0 == i[g].length && delete i[g];
+ })
+ : z.forEach(function(g) {
+ delete i[g];
+ });
+ return q;
+ };
+ this.dispatch = function(g, p) {
+ i[g] &&
+ (i[g].forEach(function(i) {
+ i.h({ type: g, content: p, target: q });
+ }),
+ (i[g] = i[g].filter(function(g) {
+ return !g.one;
+ })));
+ return q;
+ };
+};
+(function() {
+ function i() {
+ function b(a) {
+ return {
+ x: a.x,
+ y: a.y,
+ size: a.size,
+ degree: a.degree,
+ inDegree: a.inDegree,
+ outDegree: a.outDegree,
+ displayX: a.displayX,
+ displayY: a.displayY,
+ displaySize: a.displaySize,
+ label: a.label,
+ id: a.id,
+ color: a.color,
+ fixed: a.fixed,
+ active: a.active,
+ hidden: a.hidden,
+ forceLabel: a.forceLabel,
+ attr: a.attr
+ };
+ }
+ function j(a) {
+ return {
+ source: a.source.id,
+ target: a.target.id,
+ size: a.size,
+ type: a.type,
+ weight: a.weight,
+ displaySize: a.displaySize,
+ label: a.label,
+ hidden: a.hidden,
+ id: a.id,
+ attr: a.attr,
+ color: a.color
+ };
+ }
+ function f() {
+ c.nodes = [];
+ c.nodesIndex = {};
+ c.edges = [];
+ c.edgesIndex = {};
+ return c;
+ }
+ sigma.classes.Cascade.call(this);
+ sigma.classes.EventDispatcher.call(this);
+ var c = this;
+ this.p = {
+ minNodeSize: 0,
+ maxNodeSize: 0,
+ minEdgeSize: 0,
+ maxEdgeSize: 0,
+ scalingMode: "inside",
+ nodesPowRatio: 0.5,
+ edgesPowRatio: 0
+ };
+ this.borders = {};
+ f();
+ this.addNode = function(a, b) {
+ if (c.nodesIndex[a]) throw Error('Node "' + a + '" already exists.');
+ var b = b || {},
+ d = {
+ x: 0,
+ y: 0,
+ size: 1,
+ degree: 0,
+ inDegree: 0,
+ outDegree: 0,
+ fixed: !1,
+ active: !1,
+ hidden: !1,
+ forceLabel: !1,
+ label: a.toString(),
+ id: a.toString(),
+ attr: {}
+ },
+ f;
+ for (f in b)
+ switch (f) {
+ case "id":
+ break;
+ case "x":
+ case "y":
+ case "size":
+ d[f] = +b[f];
+ break;
+ case "fixed":
+ case "active":
+ case "hidden":
+ case "forceLabel":
+ d[f] = !!b[f];
+ break;
+ case "color":
+ case "label":
+ d[f] = b[f];
+ break;
+ default:
+ d.attr[f] = b[f];
+ }
+ c.nodes.push(d);
+ c.nodesIndex[a.toString()] = d;
+ return c;
+ };
+ this.addEdge = function(a, b, d, f) {
+ if (c.edgesIndex[a]) throw Error('Edge "' + a + '" already exists.');
+ if (!c.nodesIndex[b])
+ throw Error("Edge's source \"" + b + '" does not exist yet.');
+ if (!c.nodesIndex[d])
+ throw Error("Edge's target \"" + d + '" does not exist yet.');
+ f = f || {};
+ b = {
+ source: c.nodesIndex[b],
+ target: c.nodesIndex[d],
+ size: 1,
+ weight: 1,
+ displaySize: 0.5,
+ label: a.toString(),
+ id: a.toString(),
+ hidden: !1,
+ attr: {}
+ };
+ b.source.degree++;
+ b.source.outDegree++;
+ b.target.degree++;
+ b.target.inDegree++;
+ for (var o in f)
+ switch (o) {
+ case "id":
+ case "source":
+ case "target":
+ break;
+ case "hidden":
+ b[o] = !!f[o];
+ break;
+ case "size":
+ case "weight":
+ b[o] = +f[o];
+ break;
+ case "color":
+ b[o] = f[o].toString();
+ break;
+ case "type":
+ b[o] = f[o].toString();
+ break;
+ case "label":
+ b[o] = f[o];
+ break;
+ default:
+ b.attr[o] = f[o];
+ }
+ c.edges.push(b);
+ c.edgesIndex[a.toString()] = b;
+ return c;
+ };
+ this.dropNode = function(a) {
+ ((a instanceof Array ? a : [a]) || []).forEach(function(a) {
+ if (c.nodesIndex[a]) {
+ var b = null;
+ c.nodes.some(function(c, f) {
+ return c.id == a ? ((b = f), !0) : !1;
+ });
+ null != b && c.nodes.splice(b, 1);
+ delete c.nodesIndex[a];
+ c.edges = c.edges.filter(function(b) {
+ return b.source.id == a
+ ? (delete c.edgesIndex[b.id],
+ b.target.degree--,
+ b.target.inDegree--,
+ !1)
+ : b.target.id == a
+ ? (delete c.edgesIndex[b.id],
+ b.source.degree--,
+ b.source.outDegree--,
+ !1)
+ : !0;
+ });
+ } else sigma.log('Node "' + a + '" does not exist.');
+ });
+ return c;
+ };
+ this.dropEdge = function(a) {
+ ((a instanceof Array ? a : [a]) || []).forEach(function(a) {
+ if (c.edgesIndex[a]) {
+ c.edgesIndex[a].source.degree--;
+ c.edgesIndex[a].source.outDegree--;
+ c.edgesIndex[a].target.degree--;
+ c.edgesIndex[a].target.inDegree--;
+ var b = null;
+ c.edges.some(function(c, f) {
+ return c.id == a ? ((b = f), !0) : !1;
+ });
+ null != b && c.edges.splice(b, 1);
+ delete c.edgesIndex[a];
+ } else sigma.log('Edge "' + a + '" does not exist.');
+ });
+ return c;
+ };
+ this.iterEdges = function(a, b) {
+ var d = b
+ ? b.map(function(a) {
+ return c.edgesIndex[a];
+ })
+ : c.edges,
+ f = d.map(j);
+ f.forEach(a);
+ d.forEach(function(a, b) {
+ var d = f[b],
+ l;
+ for (l in d)
+ switch (l) {
+ case "id":
+ case "displaySize":
+ break;
+ case "weight":
+ case "size":
+ a[l] = +d[l];
+ break;
+ case "source":
+ case "target":
+ a[l] = c.nodesIndex[l] || a[l];
+ break;
+ case "hidden":
+ a[l] = !!d[l];
+ break;
+ case "color":
+ case "label":
+ case "type":
+ a[l] = (d[l] || "").toString();
+ break;
+ default:
+ a.attr[l] = d[l];
+ }
+ });
+ return c;
+ };
+ this.iterNodes = function(a, f) {
+ var d = f
+ ? f.map(function(a) {
+ return c.nodesIndex[a];
+ })
+ : c.nodes,
+ j = d.map(b);
+ j.forEach(a);
+ d.forEach(function(a, b) {
+ var d = j[b],
+ c;
+ for (c in d)
+ switch (c) {
+ case "id":
+ case "attr":
+ case "degree":
+ case "inDegree":
+ case "outDegree":
+ case "displayX":
+ case "displayY":
+ case "displaySize":
+ break;
+ case "x":
+ case "y":
+ case "size":
+ a[c] = +d[c];
+ break;
+ case "fixed":
+ case "active":
+ case "hidden":
+ case "forceLabel":
+ a[c] = !!d[c];
+ break;
+ case "color":
+ case "label":
+ a[c] = (d[c] || "").toString();
+ break;
+ default:
+ a.attr[c] = d[c];
+ }
+ });
+ return c;
+ };
+ this.getEdges = function(a) {
+ var b = ((a instanceof Array ? a : [a]) || []).map(function(a) {
+ return j(c.edgesIndex[a]);
+ });
+ return a instanceof Array ? b : b[0];
+ };
+ this.getNodes = function(a) {
+ var f = ((a instanceof Array ? a : [a]) || []).map(function(a) {
+ return b(c.nodesIndex[a]);
+ });
+ return a instanceof Array ? f : f[0];
+ };
+ this.empty = f;
+ this.rescale = function(a, b, d, f) {
+ var j = 0,
+ h = 0;
+ d &&
+ c.nodes.forEach(function(a) {
+ h = Math.max(a.size, h);
+ });
+ f &&
+ c.edges.forEach(function(a) {
+ j = Math.max(a.size, j);
+ });
+ var h = h || 1,
+ j = j || 1,
+ g,
+ l,
+ s,
+ t;
+ d &&
+ c.nodes.forEach(function(a) {
+ l = Math.max(a.x, l || a.x);
+ g = Math.min(a.x, g || a.x);
+ t = Math.max(a.y, t || a.y);
+ s = Math.min(a.y, s || a.y);
+ });
+ var A =
+ "outside" == c.p.scalingMode
+ ? Math.max(a / Math.max(l - g, 1), b / Math.max(t - s, 1))
+ : Math.min(a / Math.max(l - g, 1), b / Math.max(t - s, 1)),
+ i = (c.p.maxNodeSize || h) / A;
+ l += i;
+ g -= i;
+ t += i;
+ s -= i;
+ var A =
+ "outside" == c.p.scalingMode
+ ? Math.max(a / Math.max(l - g, 1), b / Math.max(t - s, 1))
+ : Math.min(a / Math.max(l - g, 1), b / Math.max(t - s, 1)),
+ u,
+ k;
+ !c.p.maxNodeSize && !c.p.minNodeSize
+ ? ((u = 1), (k = 0))
+ : c.p.maxNodeSize == c.p.minNodeSize
+ ? ((u = 0), (k = c.p.maxNodeSize))
+ : ((u = (c.p.maxNodeSize - c.p.minNodeSize) / h),
+ (k = c.p.minNodeSize));
+ var B, E;
+ !c.p.maxEdgeSize && !c.p.minEdgeSize
+ ? ((B = 1), (E = 0))
+ : ((B =
+ c.p.maxEdgeSize == c.p.minEdgeSize
+ ? 0
+ : (c.p.maxEdgeSize - c.p.minEdgeSize) / j),
+ (E = c.p.minEdgeSize));
+ d &&
+ c.nodes.forEach(function(c) {
+ c.displaySize = c.size * u + k;
+ if (!c.fixed) {
+ c.displayX = (c.x - (l + g) / 2) * A + a / 2;
+ c.displayY = (c.y - (t + s) / 2) * A + b / 2;
+ }
+ });
+ f &&
+ c.edges.forEach(function(a) {
+ a.displaySize = a.size * B + E;
+ });
+ return c;
+ };
+ this.translate = function(a, b, d, f, j) {
+ var h = Math.pow(d, c.p.nodesPowRatio);
+ f &&
+ c.nodes.forEach(function(c) {
+ c.fixed ||
+ ((c.displayX = c.displayX * d + a),
+ (c.displayY = c.displayY * d + b));
+ c.displaySize *= h;
+ });
+ h = Math.pow(d, c.p.edgesPowRatio);
+ j &&
+ c.edges.forEach(function(a) {
+ a.displaySize *= h;
+ });
+ return c;
+ };
+ this.setBorders = function() {
+ c.borders = {};
+ c.nodes.forEach(function(a) {
+ c.borders.minX = Math.min(
+ void 0 == c.borders.minX
+ ? a.displayX - a.displaySize
+ : c.borders.minX,
+ a.displayX - a.displaySize
+ );
+ c.borders.maxX = Math.max(
+ void 0 == c.borders.maxX
+ ? a.displayX + a.displaySize
+ : c.borders.maxX,
+ a.displayX + a.displaySize
+ );
+ c.borders.minY = Math.min(
+ void 0 == c.borders.minY
+ ? a.displayY - a.displaySize
+ : c.borders.minY,
+ a.displayY - a.displaySize
+ );
+ c.borders.maxY = Math.max(
+ void 0 == c.borders.maxY
+ ? a.displayY - a.displaySize
+ : c.borders.maxY,
+ a.displayY - a.displaySize
+ );
+ });
+ };
+ this.checkHover = function(a, b) {
+ var d,
+ f,
+ j,
+ h = [],
+ g = [];
+ c.nodes.forEach(function(c) {
+ if (c.hidden) c.hover = !1;
+ else {
+ d = Math.abs(c.displayX - a);
+ f = Math.abs(c.displayY - b);
+ j = c.displaySize;
+ var s = c.hover,
+ t = d < j && f < j && Math.sqrt(d * d + f * f) < j;
+ s && !t
+ ? ((c.hover = !1), g.push(c.id))
+ : t && !s && ((c.hover = !0), h.push(c.id));
+ }
+ });
+ h.length && c.dispatch("overnodes", h);
+ g.length && c.dispatch("outnodes", g);
+ return c;
+ };
+ }
+ function q(b, j) {
+ function f() {
+ var a;
+ a = "GLOBAL :
";
+ for (var b in c.p.globalProbes)
+ a += "" + b + " : " + c.p.globalProbes[b]() + "
";
+ a += "LOCAL :
";
+ for (b in c.p.localProbes)
+ a += "" + b + " : " + c.p.localProbes[b]() + "
";
+ c.p.dom.innerHTML = a;
+ return c;
+ }
+ sigma.classes.Cascade.call(this);
+ var c = this;
+ this.instance = b;
+ this.monitoring = !1;
+ this.p = {
+ fps: 40,
+ dom: j,
+ globalProbes: {
+ "Time (ms)": sigma.chronos.getExecutionTime,
+ Queue: sigma.chronos.getQueuedTasksCount,
+ Tasks: sigma.chronos.getTasksCount,
+ FPS: sigma.chronos.getFPS
+ },
+ localProbes: {
+ "Nodes count": function() {
+ return c.instance.graph.nodes.length;
+ },
+ "Edges count": function() {
+ return c.instance.graph.edges.length;
+ }
+ }
+ };
+ this.activate = function() {
+ c.monitoring || (c.monitoring = window.setInterval(f, 1e3 / c.p.fps));
+ return c;
+ };
+ this.desactivate = function() {
+ c.monitoring &&
+ (window.clearInterval(c.monitoring),
+ (c.monitoring = null),
+ (c.p.dom.innerHTML = ""));
+ return c;
+ };
+ }
+ function g(b) {
+ var j = b.changedTouches[0],
+ f = "";
+ switch (b.type) {
+ case "touchstart":
+ f = "mousedown";
+ break;
+ case "touchmove":
+ f = "mousemove";
+ break;
+ case "touchend":
+ f = "mouseup";
+ break;
+ default:
+ return;
+ }
+ var c = document.createEvent("MouseEvent");
+ c.initMouseEvent(
+ f,
+ !0,
+ !0,
+ window,
+ 1,
+ j.posX,
+ j.posY,
+ j.clientX,
+ j.clientY,
+ !1,
+ !1,
+ !1,
+ !1,
+ 0,
+ null
+ );
+ j.target.dispatchEvent(c);
+ b.preventDefault();
+ }
+ function p(b) {
+ function j(b) {
+ a.p.mouseEnabled &&
+ (f(
+ a.mouseX,
+ a.mouseY,
+ a.ratio *
+ (0 <
+ ((void 0 != b.wheelDelta && b.wheelDelta) ||
+ (void 0 != b.detail && -b.detail))
+ ? a.p.zoomMultiply
+ : 1 / a.p.zoomMultiply)
+ ),
+ a.p.blockScroll &&
+ (b.preventDefault ? b.preventDefault() : (b.returnValue = !1)));
+ }
+ function f(b, d, f) {
+ if (
+ !a.isMouseDown &&
+ (window.clearInterval(a.interpolationID),
+ (m = void 0 != f),
+ (w = a.stageX),
+ (n = b),
+ (o = a.stageY),
+ (l = d),
+ (h = f || a.ratio),
+ (h = Math.min(Math.max(h, a.p.minRatio), a.p.maxRatio)),
+ (u = a.p.directZooming ? 1 - (m ? a.p.zoomDelta : a.p.dragDelta) : 0),
+ a.ratio != h || a.stageX != n || a.stageY != l)
+ )
+ c(),
+ (a.interpolationID = window.setInterval(c, 50)),
+ a.dispatch("startinterpolate");
+ }
+ function c() {
+ u += m ? a.p.zoomDelta : a.p.dragDelta;
+ u = Math.min(u, 1);
+ var b = sigma.easing.quadratic.easeout(u),
+ c = a.ratio;
+ a.ratio = c * (1 - b) + h * b;
+ m
+ ? ((a.stageX = n + ((a.stageX - n) * a.ratio) / c),
+ (a.stageY = l + ((a.stageY - l) * a.ratio) / c))
+ : ((a.stageX = w * (1 - b) + n * b), (a.stageY = o * (1 - b) + l * b));
+ a.dispatch("interpolate");
+ 1 <= u &&
+ (window.clearInterval(a.interpolationID),
+ (b = a.ratio),
+ m
+ ? ((a.ratio = h),
+ (a.stageX = n + ((a.stageX - n) * a.ratio) / b),
+ (a.stageY = l + ((a.stageY - l) * a.ratio) / b))
+ : ((a.stageX = n), (a.stageY = l)),
+ a.dispatch("stopinterpolate"));
+ }
+ sigma.classes.Cascade.call(this);
+ sigma.classes.EventDispatcher.call(this);
+ var a = this;
+ this.p = {
+ minRatio: 1,
+ maxRatio: 32,
+ marginRatio: 1,
+ zoomDelta: 0.1,
+ dragDelta: 0.3,
+ zoomMultiply: 2,
+ directZooming: !1,
+ blockScroll: !0,
+ inertia: 1.1,
+ mouseEnabled: !0,
+ touchEnabled: !0
+ };
+ var i = 0,
+ d = 0,
+ w = 0,
+ o = 0,
+ h = 1,
+ n = 0,
+ l = 0,
+ s = 0,
+ t = 0,
+ A = 0,
+ k = 0,
+ u = 0,
+ m = !1;
+ this.stageY = this.stageX = 0;
+ this.ratio = 1;
+ this.mouseY = this.mouseX = 0;
+ this.isTouchDown = this.isMouseDown = !1;
+ b.addEventListener("DOMMouseScroll", j, !0);
+ b.addEventListener("mousewheel", j, !0);
+ b.addEventListener(
+ "mousemove",
+ function(b) {
+ a.mouseX =
+ (void 0 != b.offsetX && b.offsetX) ||
+ (void 0 != b.layerX && b.layerX) ||
+ (void 0 != b.clientX && b.clientX);
+ a.mouseY =
+ (void 0 != b.offsetY && b.offsetY) ||
+ (void 0 != b.layerY && b.layerY) ||
+ (void 0 != b.clientY && b.clientY);
+ if (a.isMouseDown) {
+ var c = a.mouseX - i + w,
+ h = a.mouseY - d + o;
+ if (c != a.stageX || h != a.stageY)
+ (t = s),
+ (k = A),
+ (s = c),
+ (A = h),
+ (a.stageX = c),
+ (a.stageY = h),
+ a.dispatch("drag");
+ }
+ a.dispatch("move");
+ b.preventDefault ? b.preventDefault() : (b.returnValue = !1);
+ },
+ !0
+ );
+ b.addEventListener(
+ "mousedown",
+ function(b) {
+ a.p.mouseEnabled &&
+ ((a.isMouseDown = !0),
+ a.dispatch("mousedown"),
+ (w = a.stageX),
+ (o = a.stageY),
+ (i = a.mouseX),
+ (d = a.mouseY),
+ (t = s = a.stageX),
+ (k = A = a.stageY),
+ a.dispatch("startdrag"),
+ b.preventDefault ? b.preventDefault() : (b.returnValue = !1));
+ },
+ !0
+ );
+ document.addEventListener(
+ "mouseup",
+ function(b) {
+ a.p.mouseEnabled &&
+ a.isMouseDown &&
+ ((a.isMouseDown = !1),
+ a.dispatch("mouseup"),
+ (w != a.stageX || o != a.stageY) &&
+ f(
+ a.stageX + a.p.inertia * (a.stageX - t),
+ a.stageY + a.p.inertia * (a.stageY - k)
+ ),
+ b.preventDefault ? b.preventDefault() : (b.returnValue = !1));
+ },
+ !0
+ );
+ b.addEventListener("touchstart", g, !0);
+ b.addEventListener("touchmove", g, !0);
+ document.addEventListener("touchend", g, !0);
+ b.addEventListener("touchcancel", g, !0);
+ this.checkBorders = function() {
+ return a;
+ };
+ this.interpolate = f;
+ }
+ function z(b, j, f, c, a, g, d) {
+ function i(a) {
+ var b = c,
+ d =
+ "fixed" == h.p.labelSize
+ ? h.p.defaultLabelSize
+ : h.p.labelSizeRatio * a.displaySize;
+ b.font =
+ (h.p.hoverFontStyle || h.p.fontStyle || "") +
+ " " +
+ d +
+ "px " +
+ (h.p.hoverFont || h.p.font || "");
+ b.fillStyle =
+ "node" == h.p.labelHoverBGColor
+ ? a.color || h.p.defaultNodeColor
+ : h.p.defaultHoverLabelBGColor;
+ b.beginPath();
+ h.p.labelHoverShadow &&
+ ((b.shadowOffsetX = 0),
+ (b.shadowOffsetY = 0),
+ (b.shadowBlur = 4),
+ (b.shadowColor = h.p.labelHoverShadowColor));
+ sigma.tools.drawRoundRect(
+ b,
+ Math.round(a.displayX - d / 2 - 2),
+ Math.round(a.displayY - d / 2 - 2),
+ Math.round(
+ b.measureText(a.label).width + 1.5 * a.displaySize + d / 2 + 4
+ ),
+ Math.round(d + 4),
+ Math.round(d / 2 + 2),
+ "left"
+ );
+ b.closePath();
+ b.fill();
+ b.shadowOffsetX = 0;
+ b.shadowOffsetY = 0;
+ b.shadowBlur = 0;
+ b.beginPath();
+ b.fillStyle =
+ "node" == h.p.nodeBorderColor
+ ? a.color || h.p.defaultNodeColor
+ : h.p.defaultNodeBorderColor;
+ b.arc(
+ Math.round(a.displayX),
+ Math.round(a.displayY),
+ a.displaySize + h.p.borderSize,
+ 0,
+ 2 * Math.PI,
+ !0
+ );
+ b.closePath();
+ b.fill();
+ b.beginPath();
+ b.fillStyle =
+ "node" == h.p.nodeHoverColor
+ ? a.color || h.p.defaultNodeColor
+ : h.p.defaultNodeHoverColor;
+ b.arc(
+ Math.round(a.displayX),
+ Math.round(a.displayY),
+ a.displaySize,
+ 0,
+ 2 * Math.PI,
+ !0
+ );
+ b.closePath();
+ b.fill();
+ b.fillStyle =
+ "node" == h.p.labelHoverColor
+ ? a.color || h.p.defaultNodeColor
+ : h.p.defaultLabelHoverColor;
+ b.fillText(
+ a.label,
+ Math.round(a.displayX + 1.5 * a.displaySize),
+ Math.round(a.displayY + d / 2 - 3)
+ );
+ return h;
+ }
+ function o(a) {
+ if (isNaN(a.x) || isNaN(a.y))
+ throw Error("A node's coordinate is not a number (id: " + a.id + ")");
+ return (
+ !a.hidden &&
+ a.displayX + a.displaySize > -n / 3 &&
+ a.displayX - a.displaySize < (4 * n) / 3 &&
+ a.displayY + a.displaySize > -l / 3 &&
+ a.displayY - a.displaySize < (4 * l) / 3
+ );
+ }
+ sigma.classes.Cascade.call(this);
+ var h = this;
+ this.p = {
+ labelColor: "default",
+ defaultLabelColor: "#000",
+ labelHoverBGColor: "default",
+ defaultHoverLabelBGColor: "#fff",
+ labelHoverShadow: !0,
+ labelHoverShadowColor: "#000",
+ labelHoverColor: "default",
+ defaultLabelHoverColor: "#000",
+ labelActiveBGColor: "default",
+ defaultActiveLabelBGColor: "#fff",
+ labelActiveShadow: !0,
+ labelActiveShadowColor: "#000",
+ labelActiveColor: "default",
+ defaultLabelActiveColor: "#000",
+ labelSize: "fixed",
+ defaultLabelSize: 12,
+ labelSizeRatio: 2,
+ labelThreshold: 6,
+ font: "Arial",
+ hoverFont: "",
+ activeFont: "",
+ fontStyle: "",
+ hoverFontStyle: "",
+ activeFontStyle: "",
+ edgeColor: "source",
+ defaultEdgeColor: "#aaa",
+ defaultEdgeType: "line",
+ defaultNodeColor: "#aaa",
+ nodeHoverColor: "node",
+ defaultNodeHoverColor: "#fff",
+ nodeActiveColor: "node",
+ defaultNodeActiveColor: "#fff",
+ borderSize: 0,
+ nodeBorderColor: "node",
+ defaultNodeBorderColor: "#fff",
+ edgesSpeed: 200,
+ nodesSpeed: 200,
+ labelsSpeed: 200
+ };
+ var n = g,
+ l = d;
+ this.currentLabelIndex = this.currentNodeIndex = this.currentEdgeIndex = 0;
+ this.task_drawLabel = function() {
+ for (
+ var b = a.nodes.length, c = 0;
+ c++ < h.p.labelsSpeed && h.currentLabelIndex < b;
+
+ )
+ if (h.isOnScreen(a.nodes[h.currentLabelIndex])) {
+ var d = a.nodes[h.currentLabelIndex++],
+ j = f;
+ if (d.displaySize >= h.p.labelThreshold || d.forceLabel) {
+ var g =
+ "fixed" == h.p.labelSize
+ ? h.p.defaultLabelSize
+ : h.p.labelSizeRatio * d.displaySize;
+ j.font = h.p.fontStyle + g + "px " + h.p.font;
+ j.fillStyle =
+ "node" == h.p.labelColor
+ ? d.color || h.p.defaultNodeColor
+ : h.p.defaultLabelColor;
+ j.fillText(
+ d.label,
+ Math.round(d.displayX + 1.5 * d.displaySize),
+ Math.round(d.displayY + g / 2 - 3)
+ );
+ }
+ } else h.currentLabelIndex++;
+ return h.currentLabelIndex < b;
+ };
+ this.task_drawEdge = function() {
+ for (
+ var b = a.edges.length, c, d, f = 0;
+ f++ < h.p.edgesSpeed && h.currentEdgeIndex < b;
+
+ )
+ if (
+ ((e = a.edges[h.currentEdgeIndex]),
+ (c = e.source),
+ (d = e.target),
+ e.hidden ||
+ c.hidden ||
+ d.hidden ||
+ (!h.isOnScreen(c) && !h.isOnScreen(d)))
+ )
+ h.currentEdgeIndex++;
+ else {
+ c = a.edges[h.currentEdgeIndex++];
+ d = c.source.displayX;
+ var g = c.source.displayY,
+ o = c.target.displayX,
+ i = c.target.displayY,
+ l = c.color;
+ if (!l)
+ switch (h.p.edgeColor) {
+ case "source":
+ l = c.source.color || h.p.defaultNodeColor;
+ break;
+ case "target":
+ l = c.target.color || h.p.defaultNodeColor;
+ break;
+ default:
+ l = h.p.defaultEdgeColor;
+ }
+ var n = j;
+ switch (c.type || h.p.defaultEdgeType) {
+ case "curve":
+ n.strokeStyle = l;
+ n.lineWidth = c.displaySize / 3;
+ n.beginPath();
+ n.moveTo(d, g);
+ n.quadraticCurveTo(
+ (d + o) / 2 + (i - g) / 4,
+ (g + i) / 2 + (d - o) / 4,
+ o,
+ i
+ );
+ n.stroke();
+ break;
+ default:
+ (n.strokeStyle = l),
+ (n.lineWidth = c.displaySize / 3),
+ n.beginPath(),
+ n.moveTo(d, g),
+ n.lineTo(o, i),
+ n.stroke();
+ }
+ }
+ return h.currentEdgeIndex < b;
+ };
+ this.task_drawNode = function() {
+ for (
+ var c = a.nodes.length, d = 0;
+ d++ < h.p.nodesSpeed && h.currentNodeIndex < c;
+
+ )
+ if (h.isOnScreen(a.nodes[h.currentNodeIndex])) {
+ var f = a.nodes[h.currentNodeIndex++],
+ j = Math.round(10 * f.displaySize) / 10,
+ g = b;
+ ctx = b;
+ node = f;
+
+ // AS 20190621 add node border
+ // if (h.p.defaultBorderView==="always" ||
+ // (h.p.defaultBorderView==="node" &&
+ if (node.attr['drawBorder']) {
+ ctx.beginPath();
+ if (node.attr['grey']) {
+ ctx.fillStyle = "rgba(0,0,0,0.1)" ;
+ }
+ //h.p.nodeBorderColor == 'node' ?
+ // (node['color'] || h.p.defaultNodeColor) :
+ // h.p.defaultNodeBorderColor;
+
+ g.arc(f.displayX, f.displayY, j+ h.p.borderSize, 0, 2 * Math.PI, !0);
+ ctx.closePath();
+ ctx.fill();
+
+
+ }
+ g.fillStyle = f.color;
+ if (node.attr['grey']) {
+ ctx.fillStyle = "rgba(244,244,244,0.1)" ;
+ }
+ g.beginPath();
+ g.arc(f.displayX, f.displayY, j, 0, 2 * Math.PI, !0);
+ g.closePath();
+ g.fill();
+ f.hover && i(f);
+ } else {
+ // not on screen, don't render
+ h.currentNodeIndex++;
+ }
+
+
+
+ return h.currentNodeIndex < c;
+ };
+ this.drawActiveNode = function(a) {
+ var b = c;
+ if (!o(a)) return h;
+ var d =
+ "fixed" == h.p.labelSize
+ ? h.p.defaultLabelSize
+ : h.p.labelSizeRatio * a.displaySize;
+ b.font =
+ (h.p.activeFontStyle || h.p.fontStyle || "") +
+ " " +
+ d +
+ "px " +
+ (h.p.activeFont || h.p.font || "");
+ b.fillStyle =
+ "node" == h.p.labelHoverBGColor
+ ? a.color || h.p.defaultNodeColor
+ : h.p.defaultActiveLabelBGColor;
+ b.beginPath();
+ h.p.labelActiveShadow &&
+ ((b.shadowOffsetX = 0),
+ (b.shadowOffsetY = 0),
+ (b.shadowBlur = 4),
+ (b.shadowColor = h.p.labelActiveShadowColor));
+ sigma.tools.drawRoundRect(
+ b,
+ Math.round(a.displayX - d / 2 - 2),
+ Math.round(a.displayY - d / 2 - 2),
+ Math.round(
+ b.measureText(a.label).width + 1.5 * a.displaySize + d / 2 + 4
+ ),
+ Math.round(d + 4),
+ Math.round(d / 2 + 2),
+ "left"
+ );
+ b.closePath();
+ b.fill();
+ b.shadowOffsetX = 0;
+ b.shadowOffsetY = 0;
+ b.shadowBlur = 0;
+ b.beginPath();
+ b.fillStyle =
+ "node" == h.p.nodeBorderColor
+ ? a.color || h.p.defaultNodeColor
+ : h.p.defaultNodeBorderColor;
+ b.arc(
+ Math.round(a.displayX),
+ Math.round(a.displayY),
+ a.displaySize + h.p.borderSize,
+ 0,
+ 2 * Math.PI,
+ !0
+ );
+ b.closePath();
+ b.fill();
+ b.beginPath();
+ b.fillStyle =
+ "node" == h.p.nodeActiveColor
+ ? a.color || h.p.defaultNodeColor
+ : h.p.defaultNodeActiveColor;
+ b.arc(
+ Math.round(a.displayX),
+ Math.round(a.displayY),
+ a.displaySize,
+ 0,
+ 2 * Math.PI,
+ !0
+ );
+ b.closePath();
+ b.fill();
+ b.fillStyle =
+ "node" == h.p.labelActiveColor
+ ? a.color || h.p.defaultNodeColor
+ : h.p.defaultLabelActiveColor;
+ b.fillText(
+ a.label,
+ Math.round(a.displayX + 1.5 * a.displaySize),
+ Math.round(a.displayY + d / 2 - 3)
+ );
+ return h;
+ };
+ this.drawHoverNode = i;
+ this.isOnScreen = o;
+ this.resize = function(a, b) {
+ n = a;
+ l = b;
+ return h;
+ };
+ }
+ function F(b, g) {
+ function f() {
+ sigma.chronos
+ .removeTask("node_" + d.id, 2)
+ .removeTask("edge_" + d.id, 2)
+ .removeTask("label_" + d.id, 2)
+ .stopTasks();
+ return d;
+ }
+ function c(a, b) {
+ d.domElements[a] = document.createElement(b);
+ d.domElements[a].style.position = "absolute";
+ d.domElements[a].setAttribute("id", "sigma_" + a + "_" + d.id);
+ d.domElements[a].setAttribute("class", "sigma_" + a + "_" + b);
+ d.domElements[a].setAttribute("width", d.width + "px");
+ d.domElements[a].setAttribute("height", d.height + "px");
+ d.domRoot.appendChild(d.domElements[a]);
+ return d;
+ }
+ function a() {
+ d.p.drawHoverNodes &&
+ (d.graph.checkHover(d.mousecaptor.mouseX, d.mousecaptor.mouseY),
+ d.graph.nodes.forEach(function(a) {
+ a.hover && !a.active && d.plotter.drawHoverNode(a);
+ }));
+ return d;
+ }
+ function D() {
+ d.p.drawActiveNodes &&
+ d.graph.nodes.forEach(function(a) {
+ a.active && d.plotter.drawActiveNode(a);
+ });
+ return d;
+ }
+ sigma.classes.Cascade.call(this);
+ sigma.classes.EventDispatcher.call(this);
+ var d = this;
+ this.id = g.toString();
+ this.p = {
+ auto: !0,
+ drawNodes: 2,
+ drawEdges: 1,
+ drawLabels: 2,
+ lastNodes: 2,
+ lastEdges: 0,
+ lastLabels: 2,
+ drawHoverNodes: !0,
+ drawActiveNodes: !0
+ };
+ this.domRoot = b;
+ this.width = this.domRoot.offsetWidth;
+ this.height = this.domRoot.offsetHeight;
+ this.graph = new i();
+ this.domElements = {};
+ c("edges", "canvas");
+ c("nodes", "canvas");
+ c("labels", "canvas");
+ c("hover", "canvas");
+ c("monitor", "div");
+ c("mouse", "canvas");
+ this.plotter = new z(
+ this.domElements.nodes.getContext("2d"),
+ this.domElements.edges.getContext("2d"),
+ this.domElements.labels.getContext("2d"),
+ this.domElements.hover.getContext("2d"),
+ this.graph,
+ this.width,
+ this.height
+ );
+ this.monitor = new q(this, this.domElements.monitor);
+ this.mousecaptor = new p(this.domElements.mouse, this.id);
+ this.mousecaptor
+ .bind("drag interpolate", function() {
+ d.draw(
+ d.p.auto ? 2 : d.p.drawNodes,
+ d.p.auto ? 0 : d.p.drawEdges,
+ d.p.auto ? 2 : d.p.drawLabels,
+ !0
+ );
+ })
+ .bind("stopdrag stopinterpolate", function() {
+ d.draw(
+ d.p.auto ? 2 : d.p.drawNodes,
+ d.p.auto ? 1 : d.p.drawEdges,
+ d.p.auto ? 2 : d.p.drawLabels,
+ !0
+ );
+ })
+ .bind("mousedown mouseup", function(a) {
+ var b = d.graph.nodes
+ .filter(function(a) {
+ return !!a.hover;
+ })
+ .map(function(a) {
+ return a.id;
+ });
+ d.dispatch("mousedown" == a.type ? "downgraph" : "upgraph");
+ b.length &&
+ d.dispatch("mousedown" == a.type ? "downnodes" : "upnodes", b);
+ })
+ .bind("move", function() {
+ d.domElements.hover
+ .getContext("2d")
+ .clearRect(
+ 0,
+ 0,
+ d.domElements.hover.width,
+ d.domElements.hover.height
+ );
+ a();
+ D();
+ });
+ sigma.chronos
+ .bind("startgenerators", function() {
+ sigma.chronos.getGeneratorsIDs().some(function(a) {
+ return !!a.match(RegExp("_ext_" + d.id + "$", ""));
+ }) &&
+ d.draw(
+ d.p.auto ? 2 : d.p.drawNodes,
+ d.p.auto ? 0 : d.p.drawEdges,
+ d.p.auto ? 2 : d.p.drawLabels
+ );
+ })
+ .bind("stopgenerators", function() {
+ d.draw();
+ });
+ for (var w = 0; w < m.plugins.length; w++) m.plugins[w](this);
+ this.draw = function(a, b, c, g) {
+ if (
+ g &&
+ sigma.chronos.getGeneratorsIDs().some(function(a) {
+ return !!a.match(RegExp("_ext_" + d.id + "$", ""));
+ })
+ )
+ return d;
+ a = void 0 == a ? d.p.drawNodes : a;
+ b = void 0 == b ? d.p.drawEdges : b;
+ c = void 0 == c ? d.p.drawLabels : c;
+ g = { nodes: a, edges: b, labels: c };
+ d.p.lastNodes = a;
+ d.p.lastEdges = b;
+ d.p.lastLabels = c;
+ f();
+ d.graph.rescale(d.width, d.height, 0 < a, 0 < b).setBorders();
+ d.mousecaptor.checkBorders(d.graph.borders, d.width, d.height);
+ d.graph.translate(
+ d.mousecaptor.stageX,
+ d.mousecaptor.stageY,
+ d.mousecaptor.ratio,
+ 0 < a,
+ 0 < b
+ );
+ d.dispatch("graphscaled");
+ for (var j in d.domElements)
+ "canvas" == d.domElements[j].nodeName.toLowerCase() &&
+ (void 0 == g[j] || 0 <= g[j]) &&
+ d.domElements[j]
+ .getContext("2d")
+ .clearRect(0, 0, d.domElements[j].width, d.domElements[j].height);
+ d.plotter.currentEdgeIndex = 0;
+ d.plotter.currentNodeIndex = 0;
+ d.plotter.currentLabelIndex = 0;
+ j = null;
+ g = !1;
+ if (a)
+ if (1 < a) for (; d.plotter.task_drawNode(); );
+ else
+ sigma.chronos.addTask(d.plotter.task_drawNode, "node_" + d.id, !1),
+ (g = !0),
+ (j = "node_" + d.id);
+ if (c)
+ if (1 < c) for (; d.plotter.task_drawLabel(); );
+ else
+ j
+ ? sigma.chronos.queueTask(
+ d.plotter.task_drawLabel,
+ "label_" + d.id,
+ j
+ )
+ : sigma.chronos.addTask(
+ d.plotter.task_drawLabel,
+ "label_" + d.id,
+ !1
+ ),
+ (g = !0),
+ (j = "label_" + d.id);
+ if (b)
+ if (1 < b) for (; d.plotter.task_drawEdge(); );
+ else
+ j
+ ? sigma.chronos.queueTask(
+ d.plotter.task_drawEdge,
+ "edge_" + d.id,
+ j
+ )
+ : sigma.chronos.addTask(
+ d.plotter.task_drawEdge,
+ "edge_" + d.id,
+ !1
+ ),
+ (g = !0),
+ (j = "edge_" + d.id);
+ d.dispatch("draw");
+ d.refresh();
+ g && sigma.chronos.runTasks();
+ return d;
+ };
+ this.resize = function(a, b) {
+ var c = d.width,
+ f = d.height;
+ void 0 != a && void 0 != b
+ ? ((d.width = a), (d.height = b))
+ : ((d.width = d.domRoot.offsetWidth),
+ (d.height = d.domRoot.offsetHeight));
+ if (c != d.width || f != d.height) {
+ for (var j in d.domElements)
+ d.domElements[j].setAttribute("width", d.width + "px"),
+ d.domElements[j].setAttribute("height", d.height + "px");
+ d.plotter.resize(d.width, d.height);
+ d.draw(d.p.lastNodes, d.p.lastEdges, d.p.lastLabels, !0);
+ }
+ return d;
+ };
+ this.refresh = function() {
+ d.domElements.hover
+ .getContext("2d")
+ .clearRect(0, 0, d.domElements.hover.width, d.domElements.hover.height);
+ a();
+ D();
+ return d;
+ };
+ this.drawHover = a;
+ this.drawActive = D;
+ this.clearSchedule = f;
+ window.addEventListener("resize", function() {
+ d.resize();
+ });
+ }
+ function x(b) {
+ var j = this;
+ sigma.classes.EventDispatcher.call(this);
+ this._core = b;
+ this.kill = function() {};
+ this.getID = function() {
+ return b.id;
+ };
+ this.configProperties = function(f, c) {
+ var a = b.config(f, c);
+ return a == b ? j : a;
+ };
+ this.drawingProperties = function(f, c) {
+ var a = b.plotter.config(f, c);
+ return a == b.plotter ? j : a;
+ };
+ this.mouseProperties = function(f, c) {
+ var a = b.mousecaptor.config(f, c);
+ return a == b.mousecaptor ? j : a;
+ };
+ this.graphProperties = function(f, c) {
+ var a = b.graph.config(f, c);
+ return a == b.graph ? j : a;
+ };
+ this.getMouse = function() {
+ return {
+ mouseX: b.mousecaptor.mouseX,
+ mouseY: b.mousecaptor.mouseY,
+ down: b.mousecaptor.isMouseDown
+ };
+ };
+ this.position = function(f, c, a) {
+ if (0 == arguments.length)
+ return {
+ stageX: b.mousecaptor.stageX,
+ stageY: b.mousecaptor.stageY,
+ ratio: b.mousecaptor.ratio
+ };
+ b.mousecaptor.stageX = void 0 != f ? f : b.mousecaptor.stageX;
+ b.mousecaptor.stageY = void 0 != c ? c : b.mousecaptor.stageY;
+ b.mousecaptor.ratio = void 0 != a ? a : b.mousecaptor.ratio;
+ return j;
+ };
+ this.goTo = function(f, c, a) {
+ b.mousecaptor.interpolate(f, c, a);
+ return j;
+ };
+ this.zoomTo = function(f, c, a) {
+ a = Math.min(
+ Math.max(b.mousecaptor.config("minRatio"), a),
+ b.mousecaptor.config("maxRatio")
+ );
+ a == b.mousecaptor.ratio
+ ? b.mousecaptor.interpolate(
+ f - b.width / 2 + b.mousecaptor.stageX,
+ c - b.height / 2 + b.mousecaptor.stageY
+ )
+ : b.mousecaptor.interpolate(
+ (a * f - (b.mousecaptor.ratio * b.width) / 2) /
+ (a - b.mousecaptor.ratio),
+ (a * c - (b.mousecaptor.ratio * b.height) / 2) /
+ (a - b.mousecaptor.ratio),
+ a
+ );
+ return j;
+ };
+ this.resize = function(f, c) {
+ b.resize(f, c);
+ return j;
+ };
+ this.draw = function(f, c, a, g) {
+ b.draw(f, c, a, g);
+ return j;
+ };
+ this.refresh = function() {
+ b.refresh();
+ return j;
+ };
+ this.addGenerator = function(f, c, a) {
+ sigma.chronos.addGenerator(f + "_ext_" + b.id, c, a);
+ return j;
+ };
+ this.removeGenerator = function(f) {
+ sigma.chronos.removeGenerator(f + "_ext_" + b.id);
+ return j;
+ };
+ this.addNode = function(f, c) {
+ b.graph.addNode(f, c);
+ return j;
+ };
+ this.addEdge = function(f, c, a, g) {
+ b.graph.addEdge(f, c, a, g);
+ return j;
+ };
+ this.dropNode = function(f) {
+ b.graph.dropNode(f);
+ return j;
+ };
+ this.dropEdge = function(f) {
+ b.graph.dropEdge(f);
+ return j;
+ };
+ this.pushGraph = function(f, c) {
+ f.nodes &&
+ f.nodes.forEach(function(a) {
+ a.id && (!c || !b.graph.nodesIndex[a.id]) && j.addNode(a.id, a);
+ });
+ f.edges &&
+ f.edges.forEach(function(a) {
+ (validID = a.source && a.target && a.id) &&
+ (!c || !b.graph.edgesIndex[a.id]) &&
+ j.addNode(a.id, a.source, a.target, a);
+ });
+ return j;
+ };
+ this.emptyGraph = function() {
+ b.graph.empty();
+ return j;
+ };
+ this.getNodesCount = function() {
+ return b.graph.nodes.length;
+ };
+ this.getEdgesCount = function() {
+ return b.graph.edges.length;
+ };
+ this.iterNodes = function(f, c) {
+ b.graph.iterNodes(f, c);
+ return j;
+ };
+ this.iterEdges = function(f, c) {
+ b.graph.iterEdges(f, c);
+ return j;
+ };
+ this.getNodes = function(f) {
+ return b.graph.getNodes(f);
+ };
+ this.getEdges = function(f) {
+ return b.graph.getEdges(f);
+ };
+ this.activateMonitoring = function() {
+ return b.monitor.activate();
+ };
+ this.desactivateMonitoring = function() {
+ return b.monitor.desactivate();
+ };
+ b.bind("downnodes upnodes downgraph upgraph", function(b) {
+ j.dispatch(b.type, b.content);
+ });
+ b.graph.bind("overnodes outnodes", function(b) {
+ j.dispatch(b.type, b.content);
+ });
+ }
+ var k = 0,
+ m = { plugins: [] };
+ sigma.init = function(b) {
+ b = new F(b, (++k).toString());
+ sigma.instances[k] = new x(b);
+ return sigma.instances[k];
+ };
+ sigma.addPlugin = function(b, g, f) {
+ x.prototype[b] = g;
+ m.plugins.push(f);
+ };
+ sigma.chronos = new (function() {
+ function b(a) {
+ window.setTimeout(a, 0);
+ return h;
+ }
+ function g() {
+ for (h.dispatch("frameinserted"); n && v.length && f(); );
+ !n || !v.length
+ ? a()
+ : ((B = new Date().getTime()),
+ m++,
+ (z = u - p),
+ (q = p - z),
+ h.dispatch("insertframe"),
+ b(g));
+ }
+ function f() {
+ C %= v.length;
+ if (!v[C].task()) {
+ var a = v[C].taskName;
+ y = y.filter(function(b) {
+ b.taskParent == a && v.push({ taskName: b.taskName, task: b.task });
+ return b.taskParent != a;
+ });
+ h.dispatch("killed", v.splice(C--, 1)[0]);
+ }
+ C++;
+ u = new Date().getTime() - B;
+ return u <= q;
+ }
+ function c() {
+ n = !0;
+ m = C = 0;
+ x = B = new Date().getTime();
+ h.dispatch("start");
+ h.dispatch("insertframe");
+ b(g);
+ return h;
+ }
+ function a() {
+ h.dispatch("stop");
+ n = !1;
+ return h;
+ }
+ function i(a, b, d) {
+ if ("function" != typeof a)
+ throw Error('Task "' + b + '" is not a function');
+ v.push({ taskName: b, task: a });
+ n = !(!n && !((d && c()) || 1));
+ return h;
+ }
+ function d(a) {
+ return a
+ ? Object.keys(r).filter(function(a) {
+ return !!r[a].on;
+ }).length
+ : Object.keys(r).length;
+ }
+ function w() {
+ Object.keys(r).length
+ ? (h.dispatch("startgenerators"),
+ h.unbind("killed", o),
+ b(function() {
+ for (var a in r) (r[a].on = !0), i(r[a].task, a, !1);
+ }),
+ h.bind("killed", o).runTasks())
+ : h.dispatch("stopgenerators");
+ return h;
+ }
+ function o(a) {
+ void 0 != r[a.content.taskName] &&
+ (r[a.content.taskName].del || !r[a.content.taskName].condition()
+ ? delete r[a.content.taskName]
+ : (r[a.content.taskName].on = !1),
+ 0 == d(!0) && w());
+ }
+ sigma.classes.EventDispatcher.call(this);
+ var h = this,
+ n = !1,
+ l = 80,
+ k = 0,
+ m = 0,
+ p = 1e3 / l,
+ q = p,
+ u = 0,
+ x = 0,
+ B = 0,
+ z = 0,
+ r = {},
+ v = [],
+ y = [],
+ C = 0;
+ this.frequency = function(a) {
+ return void 0 != a
+ ? ((l = Math.abs(1 * a)), (p = 1e3 / l), (m = 0), h)
+ : l;
+ };
+ this.runTasks = c;
+ this.stopTasks = a;
+ this.insertFrame = b;
+ this.addTask = i;
+ this.queueTask = function(a, b, c) {
+ if ("function" != typeof a)
+ throw Error('Task "' + b + '" is not a function');
+ if (
+ !v.concat(y).some(function(a) {
+ return a.taskName == c;
+ })
+ )
+ throw Error('Parent task "' + c + '" of "' + b + '" is not attached.');
+ y.push({ taskParent: c, taskName: b, task: a });
+ return h;
+ };
+ this.removeTask = function(b, c) {
+ if (void 0 == b)
+ (v = []), 1 == c ? (y = []) : 2 == c && ((v = y), (y = [])), a();
+ else {
+ var d = "string" == typeof b ? b : "";
+ v = v.filter(function(a) {
+ return ("string" == typeof b
+ ? a.taskName == b
+ : a.task == b)
+ ? ((d = a.taskName), !1)
+ : !0;
+ });
+ 0 < c &&
+ (y = y.filter(function(a) {
+ 1 == c && a.taskParent == d && v.push(a);
+ return a.taskParent != d;
+ }));
+ }
+ n = !(v.length && (!a() || 1));
+ return h;
+ };
+ this.addGenerator = function(a, b, c) {
+ if (void 0 != r[a]) return h;
+ r[a] = { task: b, condition: c };
+ 0 == d(!0) && w();
+ return h;
+ };
+ this.removeGenerator = function(a) {
+ r[a] && ((r[a].on = !1), (r[a].del = !0));
+ return h;
+ };
+ this.startGenerators = w;
+ this.getGeneratorsIDs = function() {
+ return Object.keys(r);
+ };
+ this.getFPS = function() {
+ n && (k = Math.round(1e4 * (m / (new Date().getTime() - x))) / 10);
+ return k;
+ };
+ this.getTasksCount = function() {
+ return v.length;
+ };
+ this.getQueuedTasksCount = function() {
+ return y.length;
+ };
+ this.getExecutionTime = function() {
+ return B - x;
+ };
+ return this;
+ })();
+ sigma.debugMode = 0;
+ sigma.log = function() {
+ if (1 == sigma.debugMode)
+ for (var b in arguments) console.log(arguments[b]);
+ else if (1 < sigma.debugMode)
+ for (b in arguments) throw Error(arguments[b]);
+ return sigma;
+ };
+ sigma.easing = { linear: {}, quadratic: {} };
+ sigma.easing.linear.easenone = function(b) {
+ return b;
+ };
+ sigma.easing.quadratic.easein = function(b) {
+ return b * b;
+ };
+ sigma.easing.quadratic.easeout = function(b) {
+ return -b * (b - 2);
+ };
+ sigma.easing.quadratic.easeinout = function(b) {
+ return 1 > (b *= 2) ? 0.5 * b * b : -0.5 * (--b * (b - 2) - 1);
+ };
+ sigma.tools.drawRoundRect = function(b, g, f, c, a, i, d) {
+ var i = i ? i : 0,
+ k = d ? d : [],
+ k = "string" == typeof k ? k.split(" ") : k,
+ d =
+ i &&
+ (0 <= k.indexOf("topleft") ||
+ 0 <= k.indexOf("top") ||
+ 0 <= k.indexOf("left")),
+ m =
+ i &&
+ (0 <= k.indexOf("topright") ||
+ 0 <= k.indexOf("top") ||
+ 0 <= k.indexOf("right")),
+ h =
+ i &&
+ (0 <= k.indexOf("bottomleft") ||
+ 0 <= k.indexOf("bottom") ||
+ 0 <= k.indexOf("left")),
+ k =
+ i &&
+ (0 <= k.indexOf("bottomright") ||
+ 0 <= k.indexOf("bottom") ||
+ 0 <= k.indexOf("right"));
+ b.moveTo(g, f + i);
+ d ? b.arcTo(g, f, g + i, f, i) : b.lineTo(g, f);
+ m
+ ? (b.lineTo(g + c - i, f), b.arcTo(g + c, f, g + c, f + i, i))
+ : b.lineTo(g + c, f);
+ k
+ ? (b.lineTo(g + c, f + a - i), b.arcTo(g + c, f + a, g + c - i, f + a, i))
+ : b.lineTo(g + c, f + a);
+ h
+ ? (b.lineTo(g + i, f + a), b.arcTo(g, f + a, g, f + a - i, i))
+ : b.lineTo(g, f + a);
+ b.lineTo(g, f + i);
+ };
+ sigma.tools.getRGB = function(b, g) {
+ var b = b.toString(),
+ f = { r: 0, g: 0, b: 0 };
+ if (3 <= b.length && "#" == b.charAt(0)) {
+ var c = b.length - 1;
+ 6 == c
+ ? (f = {
+ r: parseInt(b.charAt(1) + b.charAt(2), 16),
+ g: parseInt(b.charAt(3) + b.charAt(4), 16),
+ b: parseInt(b.charAt(5) + b.charAt(5), 16)
+ })
+ : 3 == c &&
+ (f = {
+ r: parseInt(b.charAt(1) + b.charAt(1), 16),
+ g: parseInt(b.charAt(2) + b.charAt(2), 16),
+ b: parseInt(b.charAt(3) + b.charAt(3), 16)
+ });
+ }
+ g && (f = [f.r, f.g, f.b]);
+ return f;
+ };
+ sigma.tools.rgbToHex = function(b, g, f) {
+ return sigma.tools.toHex(b) + sigma.tools.toHex(g) + sigma.tools.toHex(f);
+ };
+ sigma.tools.toHex = function(b) {
+ b = parseInt(b, 10);
+ if (isNaN(b)) return "00";
+ b = Math.max(0, Math.min(b, 255));
+ return (
+ "0123456789ABCDEF".charAt((b - (b % 16)) / 16) +
+ "0123456789ABCDEF".charAt(b % 16)
+ );
+ };
+ sigma.publicPrototype = x.prototype;
+})();
diff --git a/html/observatory/js/sigma/sigma.parseGexf.js b/html/observatory/js/sigma/sigma.parseGexf.js
new file mode 100644
index 0000000..1924c3e
--- /dev/null
+++ b/html/observatory/js/sigma/sigma.parseGexf.js
@@ -0,0 +1,166 @@
+// Mathieu Jacomy @ Sciences Po Mdialab & WebAtlas
+// (requires sigma.js to be loaded)
+sigma.publicPrototype.parseGexf = function(gexfPath,callback) {
+ // Load XML file:
+ var gexfhttp, gexf;
+ var sigmaInstance = this;
+ gexfhttp = window.XMLHttpRequest ?
+ new XMLHttpRequest() :
+ new ActiveXObject('Microsoft.XMLHTTP');
+
+ gexfhttp.overrideMimeType('text/xml');
+ gexfhttp.open('GET', gexfPath, false);
+ gexfhttp.send();
+ gexf = gexfhttp.responseXML;
+
+ var viz='http://www.gexf.net/1.2draft/viz'; // Vis namespace
+ var i, j, k;
+
+ // Parse Attributes
+ // This is confusing, so I'll comment heavily
+ var nodesAttributes = []; // The list of attributes of the nodes of the graph that we build in json
+ var nodesAttributesDict = {};
+ var edgesAttributes = []; // The list of attributes of the edges of the graph that we build in json
+ var edgesAttributesDict = {};
+ var attributesNodes = gexf.getElementsByTagName('attributes'); // In the gexf (that is an xml), the list of xml nodes 'attributes' (note the plural 's')
+
+ for(i = 0; i0){
+ sizeNode = sizeNodes[0];
+ size = parseFloat(sizeNode.getAttribute('value'));
+ }
+
+ var positionNodes = nodeNode.getElementsByTagName('position');
+ positionNodes = positionNodes.length ?
+ positionNodes :
+ nodeNode.getElementsByTagNameNS('*','position');
+ if(positionNodes.length>0){
+ var positionNode = positionNodes[0];
+ x = parseFloat(positionNode.getAttribute('x'));
+ y = parseFloat(positionNode.getAttribute('y'));
+ }
+
+ var colorNodes = nodeNode.getElementsByTagName('color');
+ colorNodes = colorNodes.length ?
+ colorNodes :
+ nodeNode.getElementsByTagNameNS('*','color');
+ if(colorNodes.length>0){
+ colorNode = colorNodes[0];
+ color = '#'+sigma.tools.rgbToHex(parseFloat(colorNode.getAttribute('r')),
+ parseFloat(colorNode.getAttribute('g')),
+ parseFloat(colorNode.getAttribute('b')));
+ }
+
+ // Create Node
+ var node = {label:label, size:size, x:x, y:y, attributes:{}, color:color}; // The graph node
+
+ // Attribute values
+ var attvalueNodes = nodeNode.getElementsByTagName('attvalue');
+ for(k=0; k
+
+
+ Observatory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Agency websites:
+
+
+
+
█ Entry point (search engine or social network)
+
+
+
+
+
+
+
+ User pathways across .gov.au
+ This diagram shows the pathways created by people as they move between .gov.au webpages. Each circle
+ represents a webpage and each line is a link between those pages
+ Select a website from the Agency websites list to better understand how people are coming to
+ those webpages, and where they are going to after they visit.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/html/observatory/observatory-html.code-workspace b/html/observatory/observatory-html.code-workspace
new file mode 100644
index 0000000..876a149
--- /dev/null
+++ b/html/observatory/observatory-html.code-workspace
@@ -0,0 +1,8 @@
+{
+ "folders": [
+ {
+ "path": "."
+ }
+ ],
+ "settings": {}
+}
\ No newline at end of file
diff --git a/html/observatory/run.py b/html/observatory/run.py
new file mode 100644
index 0000000..e24f57e
--- /dev/null
+++ b/html/observatory/run.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python3
+# https://stackoverflow.com/questions/14088294/multithreaded-web-server-in-python
+try:
+ # Python3
+ import http.server as SimpleHTTPServer
+ import http.server as BaseHTTPServer
+ import socketserver as SocketServer
+except ImportError:
+ # Python 2
+ import SimpleHTTPServer
+ import BaseHTTPServer
+ import SocketServer
+
+import sys
+import os
+
+# The absolute path of the directoy for this file:
+_ROOT = os.path.abspath(os.path.dirname(__file__))
+
+class ThreadingSimpleServer(SocketServer.ThreadingMixIn,BaseHTTPServer.HTTPServer):
+ pass
+
+if sys.argv[1:]:
+ port = int(sys.argv[1])
+else:
+ port = 8000
+
+server = ThreadingSimpleServer(('', port), SimpleHTTPServer.SimpleHTTPRequestHandler)
+print("Serving HTTP on 0.0.0.0 port",port,"...")
+
+try:
+ while 1:
+ sys.stdout.flush()
+ server.handle_request()
+except KeyboardInterrupt:
+ print("Finished")
\ No newline at end of file
diff --git a/html/observatory/run.sh b/html/observatory/run.sh
new file mode 100644
index 0000000..df87b1b
--- /dev/null
+++ b/html/observatory/run.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+brew install npm
+npm install -g browser-sync
+browser-sync -s -w .
\ No newline at end of file
diff --git a/html/observatory/server/gexf2Json.py b/html/observatory/server/gexf2Json.py
new file mode 100644
index 0000000..187816c
--- /dev/null
+++ b/html/observatory/server/gexf2Json.py
@@ -0,0 +1,165 @@
+import pprint
+import xml.dom.minidom
+from xml.dom.minidom import Node
+import sys
+from optparse import OptionParser
+import json
+import random
+
+usage="Run as python gexf2json.py input.gexf output.json [pretty]"
+
+"""parser = OptionParser()
+parser.add_option("-i", "--input", dest="input",
+ help="gexf file to read as input", metavar="INPUT")
+parser.add_option("-o", "--output", dest="output",
+ help="json file to write to as output", metavar="OUTPUT")
+parser.add_option("-q", "--quiet",
+ action="store_false", dest="verbose", default=True,
+ help="don't print status messages to stdout")
+
+(options, args) = parser.parse_args()
+"""
+
+if (len(sys.argv)<3):
+ print usage
+ exit()
+
+
+HEX = '0123456789abcdef'
+def rgb2hex(r,g,b):
+ return format((r<<16)|(g<<8)|b, '06x')
+
+
+gexf = xml.dom.minidom.parse(sys.argv[1])
+
+#Parse Attributes
+nodesAttributes = []#The list of attributes of the nodes of the graph that we build in json
+nodesAttributesDict={}
+edgesAttributes = []#The list of attributes of the edges of the graph that we build in json
+edgesAttributesDict={}
+
+#In the gexf (that is an xml), the list of xml nodes 'attributes' (note the plural 's')
+attributesNodes = gexf.getElementsByTagName("attributes")
+for attributesNode in attributesNodes:
+ if (attributesNode.getAttribute("class") == "node"):
+ attributeNodes = attributesNode.getElementsByTagName("attribute")#The list of xml nodes 'attribute' (no 's')
+ for attributeNodes in attributeNodes:
+ id = attributeNodes.getAttribute('id')
+ title = attributeNodes.getAttribute('title')
+ type = attributeNodes.getAttribute('type')
+ attribute = {"id":id, "title":title, "type":type}
+ nodesAttributes.append(attribute)
+ nodesAttributesDict[id]=title
+ elif (attributesNode.getAttribute("class")=="edge"):
+ attributeNodes = attributesNode.getElementsByTagName('attribute')#The list of xml nodes 'attribute' (no 's')
+ for attributeNode in attributeNodes:
+ #Each xml node 'attribute'
+ id = attributeNode.getAttribute('id')
+ title = attributeNode.getAttribute('title')
+ type = attributeNode.getAttribute('type')
+
+ attribute = {"id":id, "title":title, "type":type}
+ edgesAttributes.append(attribute)
+ edgesAttributesDict[id]=title
+
+jsonNodes = []#The nodes of the graph
+nodesNodes = gexf.getElementsByTagName("nodes")#The list of xml nodes 'nodes' (plural)
+
+for nodes in nodesNodes:
+ listNodes = nodes.getElementsByTagName("node")#The list of xml nodes 'node' (no 's')
+ for nodeEl in listNodes:
+ #Each xml node 'node' (no 's')
+ id = nodeEl.getAttribute('id')
+ title = nodeEl.getAttribute('title')
+ label = nodeEl.getAttribute('label') if nodeEl.hasAttribute("label") else id
+
+ #viz
+ size = 1
+ x = 100 - 200*random.random()
+ y = 100 - 200*random.random()
+ color=""
+
+ #SAH: Original JS code tested for size.length in ternary; is len(...)!=0 appropriate replacement?
+ sizeNodes = nodeEl.getElementsByTagName('size')
+ sizeNodes = sizeNodes if len(sizeNodes)!=0 else nodeEl.getElementsByTagNameNS('*','size')
+ if(len(sizeNodes)>0):
+ sizeNode = sizeNodes[0];
+ size = float(sizeNode.getAttribute('value'))
+
+ #SAH save as sizeNodes
+ positionNodes = nodeEl.getElementsByTagName('position')
+ positionNodes = positionNodes if len(positionNodes)!=0 else nodeEl.getElementsByTagNameNS('*','position')
+ if(len(positionNodes)>0):
+ positionNode = positionNodes[0]
+ x = float(positionNode.getAttribute('x'))
+ y = float(positionNode.getAttribute('y'))
+
+
+ #SAH: really couldn't this be a function by now; same as above
+ colorNodes = nodeEl.getElementsByTagName('color')
+ colorNodes = colorNodes if len(colorNodes)!=0 else nodeEl.getElementsByTagNameNS('*','color')
+ if(len(colorNodes)>0):
+ colorNode = colorNodes[0]
+ color = '#'+rgb2hex(int(colorNode.getAttribute('r')),
+ int(colorNode.getAttribute('g')),
+ int(colorNode.getAttribute('b')))
+
+ #Create Node
+ node = {"id":id,"label":label, "size":size, "x":x, "y":y, "attributes":{}, "color":color}; #The graph node
+
+ #Attribute values
+ attvalueNodes = nodeEl.getElementsByTagName("attvalue")
+ for attvalueNode in attvalueNodes:
+ attr = attvalueNode.getAttribute('for');
+ val = attvalueNode.getAttribute('value');
+ node["attributes"][nodesAttributesDict[attr]]=val
+
+ jsonNodes.append(node)
+
+jsonEdges = []
+edgeId = 0
+edgesNodes = gexf.getElementsByTagName('edges')
+for edgesNode in edgesNodes:
+ edgeNodes = edgesNode.getElementsByTagName('edge')
+ for edgeNode in edgeNodes:
+ source = edgeNode.getAttribute("source")
+ target = edgeNode.getAttribute("target")
+ label = edgeNode.getAttribute("label")
+ id = edgeNode.getAttribute("id") if edgeNode.hasAttribute("id") else edgeId
+ edgeId=edgeId+1
+
+ edge = {
+ "id": id,
+ "source": source,
+ "target": target,
+ "label": label,
+ "attributes": {}
+ }
+
+ #Anything besies source,target,label that is inside the actual edge tag
+ attrs = edgeNode.attributes #NamedNodeMap in python
+ for i in range(0,attrs.length):
+ item=attrs.item(i)#xml.dom.minidom.Attr
+ n=item.name
+ if(n == 'source' or n =='target' or n=='label'):
+ continue;
+ edge["attributes"][n]=item.value
+
+ #Redundant from block above
+ #if(edgeNode.hasAttribute("weight")):
+ # edge["weight"] = edgeNode.getAttribute('weight')
+
+ attvalueNodes = edgeNode.getElementsByTagName('attvalue')
+ for attvalueNode in attvalueNodes:
+ attr = attvalueNode.getAttribute('for')
+ val = attvalueNode.getAttribute('value')
+ edge["attributes"][edgesAttributesDict[attr]]=val
+
+ jsonEdges.append(edge)
+
+fhOutput = open(sys.argv[2],"w")
+j={"nodes":jsonNodes,"edges":jsonEdges}
+if len(sys.argv)>=4 and "pretty"==(sys.argv[3]).lower():
+ json.dump(j,fhOutput,indent=4)
+else:
+ json.dump(j,fhOutput)
diff --git a/html/observatory/web.config b/html/observatory/web.config
new file mode 100644
index 0000000..7345e31
--- /dev/null
+++ b/html/observatory/web.config
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shiny/observatory/.cfignore b/shiny/observatory/.cfignore
new file mode 100644
index 0000000..c5d9d94
--- /dev/null
+++ b/shiny/observatory/.cfignore
@@ -0,0 +1,3 @@
+.Rproj.user
+.Rhistory
+.Rdata
\ No newline at end of file
diff --git a/shiny/observatory/agencycomparison.R b/shiny/observatory/agencycomparison.R
new file mode 100644
index 0000000..f626671
--- /dev/null
+++ b/shiny/observatory/agencycomparison.R
@@ -0,0 +1,126 @@
+if (!exists("agency")){
+ agency <- read.csv("agency-1000plus.csv", stringsAsFactors = FALSE)[,-1]
+}
+
+if (!exists("all_agencies")){
+ all_agencies <- read_xlsx("hostnames.xlsx", sheet = 1, col_names = F, col_types = "text")
+ colnames(all_agencies) <- c("hostnames")
+}
+
+
+if (!exists("large_agencies")){
+ large_agencies <- read_xlsx("hostnames.xlsx", sheet = 2, col_names = F, col_types = "text")
+ colnames(large_agencies) <- c("hostnames")
+}
+
+if (!exists("med_agencies")){
+ med_agencies <- read_xlsx("hostnames.xlsx", sheet = 3, col_names = F, col_types = "text")
+ colnames(med_agencies) <- c("hostnames")
+}
+
+if (!exists("small_agencies")){
+ small_agencies <- read_xlsx("hostnames.xlsx", sheet = 4, col_names = F, col_types = "text")
+ colnames(small_agencies) <- c("hostnames")
+}
+
+
+agencyComparison <- tabPanel(
+ "Agency Comparison", # Sidebar with a slider input for number of bins
+ # Sidebar layout with input and output definitions ----
+ sidebarLayout(
+ # Sidebar panel for inputs ----
+ sidebarPanel(
+ # Input: Selector for choosing dataset ----
+ selectInput(
+ inputId = "agencies",
+ label = "Choose an agency:",
+ choices = c("dta.gov.au", "humanservices.gov.au", "casa.gov.au")
+ ),
+
+ selectInput(
+ inputId = "groups",
+ label = "Compare with:",
+ choices = c("small", "medium", "large", "all"),
+ ),
+ width = 3)
+ ,
+ # Main panel for displaying outputs ----
+ main = mainPanel(
+ # Output: Formatted text for caption ----
+ h3(textOutput("ac_caption", container = span)),
+ # Output: Verbatim text for data summary ----
+ verbatimTextOutput("ac_summary"),
+ # Output: HTML table with requested number of observations ----
+ fluidRow(
+ splitLayout(cellWidths = c("50%", "50%"), plotOutput("view1"), plotOutput("view2"))
+ )
+ )
+ )
+)
+
+
+agencycomparison_server <- function (input, output) {
+ # Return the requested dataset ----
+ # By declaring datasetInput as a reactive expression we ensure
+ # that:
+ #
+ # 1. It is only called when the inputs it depends on changes
+ # 2. The computation and result are shared by all the callers,
+ # i.e. it only executes a single time
+ group_filter <- reactive({
+ switch(input$groups,
+ "small" = small_agencies$hostnames,
+ "medium" = med_agencies$hostnames,
+ "large"= large_agencies$hostnames,
+ "all" = all_agencies$hostnames)})
+
+ datasetInput <- reactive({
+ agency1 <- filter(agency, hostname == input$agencies) %>%
+ group_by(sourceurl) %>%
+ arrange(desc(tot_source))
+ })
+
+ DatasetCompare <- reactive({
+ agency <- filter(agency, hostname %in% group_filter()) %>%
+ group_by(sourceurl) %>%
+ arrange(desc(tot_source))
+ })
+
+ output$ac_caption <- renderText({
+ paste("Comparing referral sources from",input$agencies, " with ", input$groups, "agencies")
+ })
+
+
+ output$view1 <- renderPlot({
+ datasetInput() %>%
+ top_n(5) %>%
+ ggplot(aes(x="", y=tot_source, fill=sourceurl)) +
+ geom_bar(width = 1, stat = "identity")+
+ coord_polar("y", start = 0) +
+ ylab(NULL)+
+ theme(axis.text = element_blank(),
+ axis.ticks = element_blank(),
+ panel.grid = element_blank()) +
+ ggtitle("Single Agency referal sources") +
+ theme(legend.position = "none")
+ })
+
+ output$view2 <- renderPlot({
+ DatasetCompare() %>%
+ group_by(sourceurl) %>%
+ top_n(5) %>%
+ ggplot(aes(x="", y=tot_source, fill = sourceurl)) +
+ geom_bar(width = 1, stat = "identity")+
+ coord_polar("y", start = 0)+
+ ylab(NULL)+
+ theme(axis.text = element_blank(),
+ axis.ticks = element_blank(),
+ panel.grid = element_blank()) +
+ ggtitle("Cohort Agencies referal sources") +
+ theme(legend.position = "none")
+ })
+
+
+}
+
+shinyApp(ui = agencyComparison, server = agencycomparison_server)
diff --git a/shiny/observatory/app.R b/shiny/observatory/app.R
index 30791f7..2bb8bed 100644
--- a/shiny/observatory/app.R
+++ b/shiny/observatory/app.R
@@ -1,10 +1,19 @@
library(shiny)
+library(dplyr)
+library(magrittr)
+library(ggplot2)
+library(lubridate)
+library(stringr)
+library(readxl)
+library(igraph)
+library(networkD3)
+library(lazyeval)
library(r2d3)
# Define UI ----
# User interface ----
-source("shinytester.R");
-source("painpoints.R");
+source("agencycomparison.R");
+source("siteuserjourneys.R");
source("userjourneys.R");
ui <- function() {
suppressDependencies("bootstrap");
@@ -15,15 +24,20 @@ ui <- function() {
subline = "To quantify interactions with every government service",
# https://support.dominodatalab.com/hc/en-us/articles/360015932932-Increasing-the-timeout-for-Shiny-Server
keepalive= textOutput("keepAlive"),
- main = navbarPage("", userJourneys, shinyTester, painPoints)
+ main = navbarPage("", siteUserJourneys, agencyComparison, userJourneys)
)
}
# Define server logic to summarize and view selected dataset ----
server <- function(input, output) {
- shinytester_server(input, output);
- painpoints_server(input, output);
+ agencycomparison_server(input, output);
userjourneys_server(input, output);
+ siteuserjourneys_server(input, output);
+
+ output$keepAlive <- renderText({
+ req(input$count)
+ paste("keep alive ", input$count)
+ })
}
shinyApp(ui = ui, server = server)
diff --git a/shiny/observatory/apt.yml b/shiny/observatory/apt.yml
index 1085f15..f003659 100644
--- a/shiny/observatory/apt.yml
+++ b/shiny/observatory/apt.yml
@@ -6,4 +6,11 @@ packages:
- r-base
- r-base-dev
- r-cran-littler
- - r-cran-dplyr
\ No newline at end of file
+ - r-cran-dplyr
+ - r-cran-magrittr
+ - r-cran-ggplot2
+ - r-cran-lubridate
+ - r-cran-stringr
+ - r-cran-readxl
+ - r-cran-igraph
+ - r-cran-lazyeval
diff --git a/shiny/observatory/hostnames.xlsx b/shiny/observatory/hostnames.xlsx
new file mode 100644
index 0000000..d74d051
Binary files /dev/null and b/shiny/observatory/hostnames.xlsx differ
diff --git a/shiny/observatory/manifest.yml b/shiny/observatory/manifest.yml
index f056dd8..571a306 100644
--- a/shiny/observatory/manifest.yml
+++ b/shiny/observatory/manifest.yml
@@ -1,6 +1,21 @@
+---
+defaults: &defaults
+ buildpacks:
+ - apt_buildpack
+ - r_buildpack
+ memory: 2G
+ health-check-type: http
+ health-check-http-endpoint: /shared/shiny.css
+ sidecars:
+ - name: nginx
+ process_types: [ 'web' ]
+ command: "/home/vcap/deps/0/apt/usr/sbin/nginx -p . -c nginx.conf"
applications:
- - name: observatory
- buildpacks:
- - apt_buildpack
- - r_buildpack
- memory: 2G
\ No newline at end of file
+ - name: observatory-green
+ routes:
+ - route: observatory-green.apps.y.cld.gov.au
+ <<: *defaults
+ - name: observatory-blue
+ routes:
+ - route: observatory-blue.apps.y.cld.gov.au
+ <<: *defaults
\ No newline at end of file
diff --git a/shiny/observatory/nginx.conf b/shiny/observatory/nginx.conf
index 3a1da7c..08994f3 100644
--- a/shiny/observatory/nginx.conf
+++ b/shiny/observatory/nginx.conf
@@ -20,7 +20,11 @@ scgi_temp_path /tmp/uwsgi_temp 1 2;
auth_basic "Administrator’s Area";
auth_basic_user_file htpasswd;
-
+ location = /shared/shiny.css {
+ auth_basic off;
+ allow all; # Allow all to see content
+ proxy_pass http://localhost:3838/shared/shiny.css;
+ }
access_log /dev/stdout cloudfoundry;
default_type application/octet-stream;
types {
diff --git a/shiny/observatory/observatory.Rproj b/shiny/observatory/observatory.Rproj
index 5c66677..228f973 100644
--- a/shiny/observatory/observatory.Rproj
+++ b/shiny/observatory/observatory.Rproj
@@ -11,8 +11,8 @@ Encoding: UTF-8
RnwWeave: Sweave
LaTeX: pdfLaTeX
-
AutoAppendNewline: Yes
StripTrailingWhitespace: Yes
QuitChildProcessesOnExit: Yes
+
diff --git a/shiny/observatory/painpoints.R b/shiny/observatory/painpoints.R
deleted file mode 100644
index 6a36b0b..0000000
--- a/shiny/observatory/painpoints.R
+++ /dev/null
@@ -1,16 +0,0 @@
-painPoints <- tabPanel(
- "Pain Points", # Sidebar with a slider input for number of bins
- # Sidebar layout with input and output definitions ----
- sidebarLayout(
- # Sidebar panel for inputs ----
- sidebarPanel(
- )
- ,
- # Main panel for displaying outputs ----
- main = mainPanel(
- )
- )
-)
-
-painpoints_server <- function (input, output) {
-}
\ No newline at end of file
diff --git a/shiny/observatory/r.yml b/shiny/observatory/r.yml
index 4d94800..98d31ce 100644
--- a/shiny/observatory/r.yml
+++ b/shiny/observatory/r.yml
@@ -2,5 +2,6 @@
packages:
- cran_mirror: https://cran.csiro.au
packages:
+ - name: networkD3
- name: shiny
- name: r2d3
\ No newline at end of file
diff --git a/shiny/observatory/run.sh b/shiny/observatory/run.sh
index 6f53bb4..eda4d99 100644
--- a/shiny/observatory/run.sh
+++ b/shiny/observatory/run.sh
@@ -1,13 +1,13 @@
#!/usr/bin/env bash
-if [ ! -f setup_complete ]; then
+if [[ ! -f setup_complete ]]; then
for dir in /home/vcap/deps/0/apt/usr/lib/R/site-library/*; do
if [[ ! "$dir" =~ (htmlwidgets|shiny|httpuv) ]]; then
- echo installing $dir;
- R CMD INSTALL $dir;
+ echo installing ${dir};
+ R CMD INSTALL ${dir} ;
fi
done
+ wait
/home/vcap/deps/0/apt/usr/sbin/nginx -V
touch setup_complete
fi
-/home/vcap/deps/0/apt/usr/sbin/nginx -p . -c nginx.conf &
R -e "options(shiny.port = 3838); shiny::runApp(getwd())"
diff --git a/shiny/observatory/shinytester.R b/shiny/observatory/shinytester.R
deleted file mode 100644
index 19a3116..0000000
--- a/shiny/observatory/shinytester.R
+++ /dev/null
@@ -1,95 +0,0 @@
-shinyTester <- tabPanel(
- "Shiny Tester", # Sidebar with a slider input for number of bins
- # Sidebar layout with input and output definitions ----
- sidebarLayout(
- # Sidebar panel for inputs ----
- sidebarPanel(
- # Input: Text for providing a caption ----
- # Note: Changes made to the caption in the textInput control
- # are updated in the output area immediately as you type
- textInput(
- inputId = "caption",
- label = "Caption:",
-
- value = "Data Summary"
- ),
- # Input: Selector for choosing dataset ----
- selectInput(
- inputId = "dataset",
- label = "Choose a dataset:",
- choices = c("rock", "pressure", "cars")
- ),
- # Input: Numeric entry for number of obs to view ----
- numericInput(
- inputId = "obs",
- label = "Number of observations to view:",
- value = 10
- )
- )
- ,
- # Main panel for displaying outputs ----
- main = mainPanel(
- # Output: Formatted text for caption ----
- h3(textOutput("caption", container = span)),
- # Output: Verbatim text for data summary ----
- verbatimTextOutput("summary"),
- # Output: HTML table with requested number of observations ----
- tableOutput("view")
-
- )
- )
-)
-
-shinytester_server <- function (input, output) {
- # Return the requested dataset ----
- # By declaring datasetInput as a reactive expression we ensure
- # that:
- #
- # 1. It is only called when the inputs it depends on changes
- # 2. The computation and result are shared by all the callers,
- # i.e. it only executes a single time
- datasetInput <- reactive({
- switch(
- input$dataset,
- "rock" = rock,
- "pressure" = pressure,
- "cars" = cars
- )
- })
-
- # Create caption ----
- # The output$caption is computed based on a reactive expression
- # that returns input$caption. When the user changes the
- # "caption" field:
- #
- # 1. This function is automatically called to recompute the output
- # 2. New caption is pushed back to the browser for re-display
- #
- # Note that because the data-oriented reactive expressions
- # below don't depend on input$caption, those expressions are
- # NOT called when input$caption changes
- output$caption <- renderText({
- input$caption
- })
-
- # Generate a summary of the dataset ----
- # The output$summary depends on the datasetInput reactive
- # expression, so will be re-executed whenever datasetInput is
- # invalidated, i.e. whenever the input$dataset changes
- output$summary <- renderPrint({
- dataset <- datasetInput()
- summary(dataset)
- })
-
- # Show the first "n" observations ----
- # The output$view depends on both the databaseInput reactive
- # expression and input$obs, so it will be re-executed whenever
- # input$dataset or input$obs is changed
- output$view <- renderTable({
- head(datasetInput(), n = input$obs)
- })
- output$keepAlive <- renderText({
- req(input$count)
- paste("keep alive ", input$count)
- })
-}
\ No newline at end of file
diff --git a/shiny/observatory/siteuserjourneys.R b/shiny/observatory/siteuserjourneys.R
new file mode 100644
index 0000000..9d0108b
--- /dev/null
+++ b/shiny/observatory/siteuserjourneys.R
@@ -0,0 +1,24 @@
+siteUserJourneys <- tabPanel(
+"User Journeys",
+d3Output("d3", width = "100%", height = 800)
+)
+
+siteuserjourneys_server <- function (input, output) {
+ output$d3 <- renderD3({
+ r2d3(
+ list(data.frame(title = c("DTA","About Us","Join Our Team","Recruiterbox"),
+ href=c("https://google.com","https://google.com","https://google.com","")),
+ data.frame(title = c("DTA","Blogs", "Help and Advice", "Guides and Tools", "Homepage - Digital Guides", "Topics", "Roles", "What each role does","Content guide","New to content design?"),
+ href=c("https://google.com","https://google.com","https://google.com"," "," "," "," "," "," "," ")),
+ data.frame(title = c("Domain Names","Guidelines", "Name Server Change"),
+ href=c("https://google.com","https://google.com","https://google.com")),
+ data.frame(title = c("Design System","Components", "Templates"),
+ href=c("https://google.com","https://google.com","https://google.com")),
+ data.frame(title = c("Design System","Get Started", "Download", "Community"),
+ href=c("https://google.com","https://google.com","https://google.com", ""))
+ ),
+ script = "siteuserjourneys.js"
+ )
+ })
+}
+shinyApp(ui = siteUserJourneys, server = siteuserjourneys_server)
diff --git a/shiny/observatory/siteuserjourneys.js b/shiny/observatory/siteuserjourneys.js
new file mode 100644
index 0000000..6b7eeee
--- /dev/null
+++ b/shiny/observatory/siteuserjourneys.js
@@ -0,0 +1,83 @@
+// !preview r2d3 data=list(data.frame(title = c("DTA","About Us","Join Our Team","Recruiterbox","5","6","7","8"),href=c("https://google.com","https://google.com","https://google.com","","","","","")), data.frame(title = c("DTA","Blogs", "Help and Advice"),href=c("https://google.com","https://google.com","https://google.com")), data.frame(title = c("Domain Names","Guidelines", "Name Server Change"),href=c("https://google.com","https://google.com","https://google.com")), data.frame(title = c("Design System","Components", "Templates"),href=c("https://google.com","https://google.com","https://google.com")), data.frame(title = c("Design System","Get Started", "Download", "Community"),href=c("https://google.com","https://google.com","https://google.com", ""))),height=800,width="100%"
+
+
+r2d3.svg.selectAll("svg > *").remove();
+var g = r2d3.svg
+ .selectAll()
+ .data(data)
+ .enter()
+ .append("g")
+ .attr("transform", function (d, i) {
+ return "translate(" + 15 + "," + (Math.abs(i) * 130) + ")";
+ });
+
+function dx(d, i) {
+ return i * 100 + 50;
+}
+
+function dy(d, i) {
+ return 50;
+}
+
+var lineFunction = d3
+ .line()
+ .x(function (d, i) {
+ return dx(d, i);
+ })
+ .y(function (d, i) {
+ return dy(d, i);
+ })
+ .curve(d3.curveLinear);
+var line = g
+ .append("path")
+ .attr("d", function (d) {
+ return lineFunction(d.title);
+ })
+ .attr("stroke", "grey")
+ .attr("stroke-width", 10)
+ .attr("fill", "white");
+
+var circles = g.selectAll().data(function (d) {
+ return HTMLWidgets.dataframeToD3(d);
+});
+circles
+ .enter()
+ .append("circle")
+ .attr("cy", function (d, i) {
+ return dy(d, i);
+ })
+ .attr("cx", function (d, i) {
+ return dx(d, i);
+ })
+ .attr("r", 20)
+ .attr("fill", "white")
+ .attr("stroke", "grey")
+ .attr("stroke-width", "10px");
+
+var texts = g
+ .selectAll()
+ .data(function (d) {
+ return HTMLWidgets.dataframeToD3(d);
+ })
+ .enter()
+ .append("foreignObject")
+ .attr("x", function (d, i) {
+ return dx(d, i)-10;
+ })
+ .attr("y", function (d, i) {
+ return dy(d, i);
+ })
+ .attr("width", function (d, i) {
+ return 115;
+ })
+ .attr("height", function (d, i) {
+ return 110;
+ })
+ .append("xhtml:p")
+ .style("text-align", "left")
+ .style("padding-left", "30px")
+ .style("transform-origin", "0 0")
+ .style("transform","rotate(25deg)")
+ .html(function (d) {
+ return d.title;
+ });
diff --git a/shiny/observatory/template.html b/shiny/observatory/template.html
index 204a454..85c0a44 100644
--- a/shiny/observatory/template.html
+++ b/shiny/observatory/template.html
@@ -4,89 +4,89 @@
{{ title }}
{{
- headContent()
+ headContent()
}}
-
-
+
-