├── data
└── .gitkeep
├── src
├── django
│ ├── users
│ │ ├── __init__.py
│ │ ├── migrations
│ │ │ ├── __init__.py
│ │ │ ├── 0002_auto_20170221_1653.py
│ │ │ ├── 0003_auto_20170224_1639.py
│ │ │ └── 0004_auto_20170509_1559.py
│ │ ├── tests.py
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── utils.py
│ │ └── emails.py
│ ├── pfb_analysis
│ │ ├── __init__.py
│ │ ├── tests
│ │ │ ├── __init__.py
│ │ │ └── data
│ │ │ │ ├── birmingham
│ │ │ │ ├── birmingham.cpg
│ │ │ │ ├── birmingham.dbf
│ │ │ │ ├── birmingham.shp
│ │ │ │ ├── birmingham.shx
│ │ │ │ └── birmingham.prj
│ │ │ │ ├── ann-arbor-mi
│ │ │ │ ├── ann-arbor-mi.cpg
│ │ │ │ ├── ann-arbor-mi.dbf
│ │ │ │ ├── ann-arbor-mi.shp
│ │ │ │ ├── ann-arbor-mi.shx
│ │ │ │ └── ann-arbor-mi.prj
│ │ │ │ └── batch_create_shapefile
│ │ │ │ ├── PFB_BigJumpCities_1.prj
│ │ │ │ ├── PFB_BigJumpCities_1.dbf
│ │ │ │ ├── PFB_BigJumpCities_1.shp
│ │ │ │ ├── PFB_BigJumpCities_1.shx
│ │ │ │ ├── PFB_BigJumpCities_1.zip
│ │ │ │ └── PFB_BigJumpCities_1.qpj
│ │ ├── management
│ │ │ ├── __init__.py
│ │ │ └── commands
│ │ │ │ ├── __init__.py
│ │ │ │ ├── analysis_batch_cancel.py
│ │ │ │ ├── update_status.py
│ │ │ │ └── run_analysis_job.py
│ │ ├── migrations
│ │ │ ├── __init__.py
│ │ │ ├── 0008_merge_20170323_1200.py
│ │ │ ├── 0003_merge_20170307_1930.py
│ │ │ ├── 0006_merge_20170321_1656.py
│ │ │ ├── 0016_merge_20170412_1804.py
│ │ │ ├── 0006_merge_20170322_1647.py
│ │ │ ├── 0005_remove_analysisjob_status.py
│ │ │ ├── 0045_analysisjob_skip_import_jobs.py
│ │ │ ├── 0043_update_jsonfield_django_32.py
│ │ │ ├── 0046_analysisjob_jobs_url_field.py
│ │ │ ├── 0044_analysisjob_population_url.py
│ │ │ ├── 0042_analysisjob_max_trip_distance.py
│ │ │ ├── 0024_auto_20170509_2121.py
│ │ │ ├── 0047_neighborhood_speed_limit.py
│ │ │ ├── 0002_analysisjob_batch_job_id.py
│ │ │ ├── 0036_neighborhood_city_fips.py
│ │ │ ├── 0011_analysisjob_census_block_count.py
│ │ │ ├── 0021_neighborhood_visibility.py
│ │ │ ├── 0014_neighborhood_geom.py
│ │ │ ├── 0017_neighborhood_geom_pt.py
│ │ │ ├── 0010_analysisjob_overall_scores.py
│ │ │ ├── 0029_auto_20170802_1425.py
│ │ │ ├── 0039_alter_neighborhood_state_abbrev_field.py
│ │ │ ├── 0040_neighborhood_analysis_job_ondelete.py
│ │ │ ├── 0028_analysisscoremetadata_priority.py
│ │ │ ├── 0025_auto_20170511_1244.py
│ │ │ ├── 0018_add_neighborhood_geom_pt.py
│ │ │ ├── 0035_auto_20190124_1853.py
│ │ │ ├── 0049_neighborhood_geog.py
│ │ │ ├── 0032_neighborhood_country.py
│ │ │ ├── 0019_auto_20170421_1746.py
│ │ │ ├── 0041_auto_20201006_2320.py
│ │ │ ├── 0004_analysisjob_osm_extract_url.py
│ │ │ ├── 0026_auto_20170517_1531.py
│ │ │ ├── 0009_auto_20170323_1535.py
│ │ │ ├── 0007_auto_20170322_1309.py
│ │ │ ├── 0030_auto_20180419_1342.py
│ │ │ ├── 0027_remove_states_from_labels.py
│ │ │ ├── 0013_auto_20170407_0106.py
│ │ │ ├── 0048_crash.py
│ │ │ ├── 0012_analysisscoremetadata.py
│ │ │ ├── 0033_auto_20181205_1913.py
│ │ │ ├── 0020_neighborhood_geom_simple.py
│ │ │ └── 0014_auto_20170412_1611.py
│ │ ├── apps.py
│ │ └── functions.py
│ ├── pfb_network_connectivity
│ │ ├── migrations
│ │ │ ├── __init__.py
│ │ │ ├── 0002_delete_neighborhood.py
│ │ │ └── 0001_initial.py
│ │ ├── __init__.py
│ │ ├── tests.py
│ │ ├── admin.py
│ │ ├── views.py
│ │ ├── utils.py
│ │ ├── wsgi.py
│ │ ├── pagination.py
│ │ └── models.py
│ ├── setup.cfg
│ ├── gunicorn.conf.py
│ ├── manage.py
│ ├── Dockerfile
│ └── requirements.txt
├── nginx
│ ├── srv
│ │ ├── dist
│ │ │ └── .gitkeep
│ │ └── static
│ │ │ └── .gitkeep
│ ├── Dockerfile
│ └── etc
│ │ └── nginx
│ │ └── nginx.conf
├── analysis
│ ├── .gitignore
│ ├── stress
│ │ ├── stress_one_way_reset.sql
│ │ ├── stress_link_ints.sql
│ │ ├── stress_primary_ints.sql
│ │ ├── stress_secondary_ints.sql
│ │ ├── stress_motorway-trunk_ints.sql
│ │ ├── stress_path.sql
│ │ ├── stress_track.sql
│ │ ├── stress_motorway-trunk.sql
│ │ └── stress_living_street.sql
│ ├── import
│ │ ├── mapconfig_cycleway.xml
│ │ ├── clip_osm.sql
│ │ └── mapconfig_highway.xml
│ ├── connectivity
│ │ ├── reachable_roads_high_stress_cleanup.sql
│ │ ├── reachable_roads_high_stress_prep.sql
│ │ ├── reachable_roads_low_stress_prep.sql
│ │ ├── reachable_roads_low_stress_cleanup.sql
│ │ ├── reachable_roads_high_stress_calc.sql
│ │ └── reachable_roads_low_stress_calc.sql
│ ├── features
│ │ ├── legs.sql
│ │ ├── one_way.sql
│ │ ├── class_adjustments.sql
│ │ ├── island.sql
│ │ ├── rrfb.sql
│ │ ├── speed_limit.sql
│ │ ├── stops.sql
│ │ ├── streetlight
│ │ │ └── streetlight_destinations.sql
│ │ └── width_ft.sql
│ ├── LICENSE
│ ├── README.md
│ └── scripts
│ │ ├── import.sh
│ │ └── utils.sh
├── angularjs
│ ├── src
│ │ ├── assets
│ │ │ ├── images
│ │ │ │ ├── .gitkeep
│ │ │ │ ├── bna-icon.png
│ │ │ │ ├── bna-logo.png
│ │ │ │ ├── favicon.ico
│ │ │ │ ├── bna-icon-dark.png
│ │ │ │ ├── bna-logo-2021.png
│ │ │ │ ├── home-header-2.jpg
│ │ │ │ ├── home-header-3.jpg
│ │ │ │ ├── home-header.jpg
│ │ │ │ ├── fatality-bike-icon.png
│ │ │ │ ├── web-racing-stripe.png
│ │ │ │ ├── fatality-active-icon.png
│ │ │ │ ├── fatality-motor-icon.png
│ │ │ │ └── bna-logo-horizontal-2021.png
│ │ │ └── fonts
│ │ │ │ ├── fontello
│ │ │ │ ├── font
│ │ │ │ │ ├── fontello.eot
│ │ │ │ │ ├── fontello.ttf
│ │ │ │ │ ├── fontello.woff
│ │ │ │ │ └── fontello.woff2
│ │ │ │ └── LICENSE.txt
│ │ │ │ └── bootstrap
│ │ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ │ └── glyphicons-halflings-regular.woff2
│ │ ├── styles
│ │ │ ├── layout
│ │ │ │ ├── _header.scss
│ │ │ │ ├── _section.scss
│ │ │ │ ├── _container.scss
│ │ │ │ ├── _footer.scss
│ │ │ │ └── _navbar.scss
│ │ │ ├── components
│ │ │ │ ├── _image.scss
│ │ │ │ ├── _panel.scss
│ │ │ │ ├── _nav.scss
│ │ │ │ ├── _network-score.scss
│ │ │ │ ├── _metrics.scss
│ │ │ │ ├── _table.scss
│ │ │ │ └── _tooltip.scss
│ │ │ ├── base
│ │ │ │ ├── _list.scss
│ │ │ │ ├── _animation.scss
│ │ │ │ ├── _base.scss
│ │ │ │ └── _typography.scss
│ │ │ ├── pages
│ │ │ │ ├── _compare.scss
│ │ │ │ └── _location.scss
│ │ │ └── utils
│ │ │ │ ├── _mixins.scss
│ │ │ │ └── _variables.scss
│ │ └── app
│ │ │ ├── utils
│ │ │ └── module.js
│ │ │ ├── help
│ │ │ ├── module.js
│ │ │ └── help.html
│ │ │ ├── login
│ │ │ ├── module.js
│ │ │ └── user-login.controller.js
│ │ │ ├── home
│ │ │ ├── module.js
│ │ │ └── neighborhood-map.html
│ │ │ ├── places
│ │ │ ├── compare
│ │ │ │ └── module.js
│ │ │ ├── list
│ │ │ │ ├── module.js
│ │ │ │ └── places-list-map.html
│ │ │ ├── detail
│ │ │ │ ├── module.js
│ │ │ │ └── place-map.html
│ │ │ └── module.js
│ │ │ ├── users
│ │ │ ├── detail
│ │ │ │ └── module.js
│ │ │ ├── list
│ │ │ │ └── module.js
│ │ │ └── module.js
│ │ │ ├── components
│ │ │ ├── map
│ │ │ │ └── module.js
│ │ │ ├── auth
│ │ │ │ └── module.js
│ │ │ ├── filters
│ │ │ │ ├── module.js
│ │ │ │ └── user-filter.html
│ │ │ ├── analysis-jobs
│ │ │ │ ├── module.js
│ │ │ │ └── analysis-jobs-status.filter.js
│ │ │ ├── modals
│ │ │ │ ├── module.js
│ │ │ │ ├── confirmation-modal.html
│ │ │ │ ├── modal-instance-controller.js
│ │ │ │ └── confirmation-modal.js
│ │ │ ├── thumbnail-map
│ │ │ │ ├── module.js
│ │ │ │ └── thumbnail-map.html
│ │ │ ├── module.js
│ │ │ ├── countries.service.js
│ │ │ ├── pagination.service.js
│ │ │ ├── organizations.service.js
│ │ │ ├── footer
│ │ │ │ ├── footer.html
│ │ │ │ └── footer.directive.js
│ │ │ ├── neighborhoods.service.js
│ │ │ └── users.service.js
│ │ │ ├── analysis-jobs
│ │ │ ├── create
│ │ │ │ └── module.js
│ │ │ ├── detail
│ │ │ │ ├── module.js
│ │ │ │ └── analysis-jobs-detail.controller.js
│ │ │ ├── import
│ │ │ │ └── module.js
│ │ │ ├── list
│ │ │ │ └── module.js
│ │ │ └── module.js
│ │ │ ├── neighborhoods
│ │ │ ├── list
│ │ │ │ └── module.js
│ │ │ ├── detail
│ │ │ │ ├── module.js
│ │ │ │ └── neighborhood-detail-map.html
│ │ │ └── module.js
│ │ │ ├── organizations
│ │ │ ├── list
│ │ │ │ ├── module.js
│ │ │ │ ├── organizations-list.controller.js
│ │ │ │ └── organizations-list.html
│ │ │ ├── detail
│ │ │ │ └── module.js
│ │ │ └── module.js
│ │ │ ├── password-reset
│ │ │ ├── reset
│ │ │ │ ├── module.js
│ │ │ │ └── password-reset.controller.js
│ │ │ ├── request
│ │ │ │ ├── module.js
│ │ │ │ ├── password-reset-request.controller.js
│ │ │ │ └── password-reset-request.html
│ │ │ └── module.js
│ │ │ ├── index.constants.js
│ │ │ ├── index.module.js
│ │ │ └── index.run.js
│ ├── .gitignore
│ ├── gulp
│ │ ├── .eslintrc
│ │ ├── docs.js
│ │ ├── scripts.js
│ │ ├── watch.js
│ │ └── conf.js
│ ├── .bowerrc
│ ├── .editorconfig
│ ├── .eslintrc
│ ├── Dockerfile
│ ├── gulpfile.js
│ └── bower.json
├── verifier
│ ├── requirements.txt
│ ├── docker-compose.yml
│ ├── Dockerfile
│ └── compare_outputs.sh
└── tilegarden
│ ├── .gitignore
│ ├── .env.dev
│ ├── src
│ ├── util
│ │ ├── error-builder.js
│ │ ├── logger.js
│ │ └── xml-tools.js
│ └── config
│ │ └── mml
│ │ ├── census_blocks.mml
│ │ ├── ways.mml
│ │ ├── bike_infrastructure.mml
│ │ ├── census_blocks.mss
│ │ └── ways.mss
│ ├── tests
│ └── error-builder.test.js
│ ├── .eslintrc.json
│ ├── scripts
│ ├── build-xml.sh
│ ├── template-vars.js
│ ├── deploy
│ ├── deploy-new
│ └── build-all-xml.sh
│ ├── Dockerfile
│ └── .env.example
├── prototype
├── app
│ └── assets
│ │ ├── css
│ │ └── .gitkeep
│ │ ├── js
│ │ ├── .gitkeep
│ │ └── main.js
│ │ ├── images
│ │ ├── .gitkeep
│ │ ├── home-header.jpg
│ │ ├── footer-stripes.png
│ │ ├── home-header-2.jpg
│ │ ├── home-header-3.jpg
│ │ ├── placesforbikes-icon.png
│ │ ├── placesforbikes-logo.png
│ │ ├── placesforbikes-logo-white.png
│ │ └── placesforbikes-logo-vertical.png
│ │ ├── sass
│ │ ├── layout
│ │ │ ├── _header.scss
│ │ │ ├── _section.scss
│ │ │ ├── _container.scss
│ │ │ ├── _footer.scss
│ │ │ └── _navbar.scss
│ │ ├── base
│ │ │ ├── _animation.scss
│ │ │ ├── _list.scss
│ │ │ ├── _base.scss
│ │ │ └── _typography.scss
│ │ ├── components
│ │ │ ├── _map.scss
│ │ │ ├── _image.scss
│ │ │ ├── _nav.scss
│ │ │ ├── _network-score.scss
│ │ │ ├── _metrics.scss
│ │ │ └── _tooltip.scss
│ │ ├── pages
│ │ │ ├── _location.scss
│ │ │ └── _compare.scss
│ │ ├── utils
│ │ │ ├── _mixins.scss
│ │ │ └── _variables.scss
│ │ └── main.scss
│ │ └── fonts
│ │ ├── fontello
│ │ ├── font
│ │ │ ├── fontello.eot
│ │ │ ├── fontello.ttf
│ │ │ ├── fontello.woff
│ │ │ └── fontello.woff2
│ │ └── LICENSE.txt
│ │ └── fontello-old
│ │ └── font
│ │ ├── mantle.eot
│ │ ├── mantle.ttf
│ │ ├── mantle.woff
│ │ └── mantle.woff2
├── grunt
│ ├── aliases.yaml
│ ├── sass.js
│ ├── concurrent.js
│ ├── browserSync.js
│ ├── watch.js
│ └── postcss.js
├── Gruntfile.js
└── package.json
├── deployment
├── aws-batch
│ ├── requirements.txt
│ ├── docker-compose.yml
│ └── Dockerfile
└── terraform
│ ├── .gitconfig
│ ├── config.tf
│ ├── versions.tf
│ ├── docker-compose.yml
│ ├── network.tf
│ ├── task-definitions
│ └── nginx.json
│ └── alarms.tf
├── .gitattributes
├── scripts
├── setup
├── server
├── django-manage
├── test
├── console
└── clean-analysis-volumes
├── docker-compose.test.yml
├── LICENSE
├── .github
└── PULL_REQUEST_TEMPLATE.md
├── common.yml
└── docs
└── architecture
└── adr-0000-architecture-documentation.md
/data/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/django/users/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/nginx/srv/dist/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/prototype/app/assets/css/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/prototype/app/assets/js/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/nginx/srv/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/prototype/app/assets/images/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/analysis/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.log
3 |
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/django/users/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/verifier/requirements.txt:
--------------------------------------------------------------------------------
1 | csvdiff==0.3.1
2 |
--------------------------------------------------------------------------------
/deployment/aws-batch/requirements.txt:
--------------------------------------------------------------------------------
1 | boto3==1.26.132
2 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/django/pfb_network_connectivity/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/tilegarden/.gitignore:
--------------------------------------------------------------------------------
1 | # Claudia configs
2 | claudia/
3 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/birmingham/birmingham.cpg:
--------------------------------------------------------------------------------
1 | ISO-8859-1
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/ann-arbor-mi/ann-arbor-mi.cpg:
--------------------------------------------------------------------------------
1 | ISO-8859-1
--------------------------------------------------------------------------------
/src/django/users/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/src/django/users/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/prototype/grunt/aliases.yaml:
--------------------------------------------------------------------------------
1 | default:
2 | - 'sass'
3 | - 'postcss'
4 | - 'browserSync'
5 | - 'watch'
--------------------------------------------------------------------------------
/src/django/pfb_network_connectivity/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import, unicode_literals
2 |
--------------------------------------------------------------------------------
/src/django/pfb_network_connectivity/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/src/django/pfb_network_connectivity/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/src/django/pfb_network_connectivity/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 |
3 | # Create your views here.
4 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/layout/_header.scss:
--------------------------------------------------------------------------------
1 | header {
2 | padding: 5rem 0;
3 | position: relative;
4 | z-index: 1;
5 | }
--------------------------------------------------------------------------------
/src/angularjs/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | bower_components/
3 | coverage/
4 | .sass-cache/
5 | .idea/
6 | .tmp/
7 | dist/
8 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/layout/_header.scss:
--------------------------------------------------------------------------------
1 | header {
2 | padding: 5rem 0;
3 | position: relative;
4 | z-index: 1;
5 | }
--------------------------------------------------------------------------------
/src/angularjs/src/app/utils/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.utils', []);
5 | })();
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text eol=lf
2 | *.png binary
3 | *.jpg binary
4 | *.ttf binary
5 | *.shp binary
6 | *.shx binary
7 | *.zip binary
8 |
--------------------------------------------------------------------------------
/src/angularjs/gulp/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "node": true
4 | },
5 | "globals": {
6 | "require": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/help/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.help', ['hljs']);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/login/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.login', []);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/birmingham/birmingham.dbf:
--------------------------------------------------------------------------------
1 | u A FID N
0
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/ann-arbor-mi/ann-arbor-mi.dbf:
--------------------------------------------------------------------------------
1 | u A FID N
0
--------------------------------------------------------------------------------
/src/angularjs/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "bower_components",
3 | "registry": "https://registry.bower.io",
4 | "strict-ssl": false
5 | }
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/home/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.home', ['pfb.components']);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/places/compare/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 | angular.module('pfb.places.compare', []);
4 | })();
5 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/users/detail/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.users.detail', []);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/users/list/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.users.list', []);
5 | })();
6 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/base/_animation.scss:
--------------------------------------------------------------------------------
1 | .fade {
2 | opacity: 0;
3 | transition: .15s linear opacity;
4 | &.in {
5 | opacity: 1;
6 | }
7 | }
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/map/module.js:
--------------------------------------------------------------------------------
1 |
2 | (function() {
3 | 'use strict';
4 |
5 | angular.module('pfb.components.map', []);
6 | })();
7 |
--------------------------------------------------------------------------------
/prototype/app/assets/images/home-header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/images/home-header.jpg
--------------------------------------------------------------------------------
/src/angularjs/src/app/analysis-jobs/create/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 | angular.module('pfb.analysisJobs.create', []);
4 | })();
5 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/analysis-jobs/detail/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 | angular.module('pfb.analysisJobs.detail', []);
4 | })();
5 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/analysis-jobs/import/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 | angular.module('pfb.analysisJobs.import', []);
4 | })();
5 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/analysis-jobs/list/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.analysisJobs.list', []);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/auth/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.components.auth', []);
5 |
6 | })();
7 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/filters/module.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | angular.module('pfb.components.filters', []);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/neighborhoods/list/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.neighborhoods.list', []);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/organizations/list/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.organizations.list', []);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/password-reset/reset/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.passwordReset.reset', []);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/bna-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/bna-icon.png
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/bna-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/bna-logo.png
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/favicon.ico
--------------------------------------------------------------------------------
/prototype/app/assets/images/footer-stripes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/images/footer-stripes.png
--------------------------------------------------------------------------------
/prototype/app/assets/images/home-header-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/images/home-header-2.jpg
--------------------------------------------------------------------------------
/prototype/app/assets/images/home-header-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/images/home-header-3.jpg
--------------------------------------------------------------------------------
/src/angularjs/src/app/organizations/detail/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.organizations.detail', []);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/password-reset/request/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.passwordReset.request', []);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/places/list/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.places.list', ['pfb.components.map']);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/analysis-jobs/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.components.analysis-jobs', []);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/modals/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.components.modals', ['ui.bootstrap']);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/places/detail/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.places.detail', ['pfb.components.map']);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/users/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.users', ['pfb.users.list', 'pfb.users.detail']);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/bna-icon-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/bna-icon-dark.png
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/bna-logo-2021.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/bna-logo-2021.png
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/home-header-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/home-header-2.jpg
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/home-header-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/home-header-3.jpg
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/home-header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/home-header.jpg
--------------------------------------------------------------------------------
/prototype/app/assets/images/placesforbikes-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/images/placesforbikes-icon.png
--------------------------------------------------------------------------------
/prototype/app/assets/images/placesforbikes-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/images/placesforbikes-logo.png
--------------------------------------------------------------------------------
/prototype/app/assets/sass/components/_map.scss:
--------------------------------------------------------------------------------
1 | .map {
2 | position: absolute;
3 | top: 0;
4 | left: 0;
5 | right: 0;
6 | bottom: 0;
7 | background-color: #eee;
8 | }
--------------------------------------------------------------------------------
/src/angularjs/src/app/neighborhoods/detail/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 | angular.module('pfb.neighborhoods.detail', ['ngFileUpload']);
4 | })();
5 |
--------------------------------------------------------------------------------
/src/django/setup.cfg:
--------------------------------------------------------------------------------
1 | [flake8]
2 |
3 | ignore = D100,D101,D102,D103,D104
4 | max-line-length = 100
5 | exclude = migrations,*_migrations,manage.py
6 | max-complexity = 15
7 |
--------------------------------------------------------------------------------
/src/django/users/apps.py:
--------------------------------------------------------------------------------
1 | from __future__ import unicode_literals
2 |
3 | from django.apps import AppConfig
4 |
5 |
6 | class UsersConfig(AppConfig):
7 | name = 'users'
8 |
--------------------------------------------------------------------------------
/deployment/terraform/.gitconfig:
--------------------------------------------------------------------------------
1 | [safe]
2 | directory = /usr/local/src/.terraform/modules/database
3 | directory = /usr/local/src/.terraform/modules/vpc
4 |
5 |
6 |
--------------------------------------------------------------------------------
/prototype/app/assets/fonts/fontello/font/fontello.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/fonts/fontello/font/fontello.eot
--------------------------------------------------------------------------------
/prototype/app/assets/fonts/fontello/font/fontello.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/fonts/fontello/font/fontello.ttf
--------------------------------------------------------------------------------
/prototype/app/assets/fonts/fontello/font/fontello.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/fonts/fontello/font/fontello.woff
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/fatality-bike-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/fatality-bike-icon.png
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/web-racing-stripe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/web-racing-stripe.png
--------------------------------------------------------------------------------
/prototype/app/assets/fonts/fontello-old/font/mantle.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/fonts/fontello-old/font/mantle.eot
--------------------------------------------------------------------------------
/prototype/app/assets/fonts/fontello-old/font/mantle.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/fonts/fontello-old/font/mantle.ttf
--------------------------------------------------------------------------------
/prototype/app/assets/fonts/fontello-old/font/mantle.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/fonts/fontello-old/font/mantle.woff
--------------------------------------------------------------------------------
/prototype/app/assets/fonts/fontello/font/fontello.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/fonts/fontello/font/fontello.woff2
--------------------------------------------------------------------------------
/prototype/app/assets/sass/layout/_section.scss:
--------------------------------------------------------------------------------
1 | section {
2 | @extend %clearfix;
3 | display: block;
4 | position: relative;
5 | padding-top: 6rem;
6 | padding-bottom: 6rem;
7 | }
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/fatality-active-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/fatality-active-icon.png
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/fatality-motor-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/fatality-motor-icon.png
--------------------------------------------------------------------------------
/src/angularjs/src/styles/layout/_section.scss:
--------------------------------------------------------------------------------
1 | section {
2 | @extend %clearfix;
3 | display: block;
4 | position: relative;
5 | padding-top: 6rem;
6 | padding-bottom: 6rem;
7 | }
--------------------------------------------------------------------------------
/prototype/app/assets/fonts/fontello-old/font/mantle.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/fonts/fontello-old/font/mantle.woff2
--------------------------------------------------------------------------------
/prototype/app/assets/images/placesforbikes-logo-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/images/placesforbikes-logo-white.png
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/thumbnail-map/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.components.thumbnailMap', ['pfb.components.map']);
5 | })();
6 |
--------------------------------------------------------------------------------
/src/angularjs/src/assets/fonts/fontello/font/fontello.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/fonts/fontello/font/fontello.eot
--------------------------------------------------------------------------------
/src/angularjs/src/assets/fonts/fontello/font/fontello.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/fonts/fontello/font/fontello.ttf
--------------------------------------------------------------------------------
/src/angularjs/src/assets/fonts/fontello/font/fontello.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/fonts/fontello/font/fontello.woff
--------------------------------------------------------------------------------
/src/angularjs/src/assets/fonts/fontello/font/fontello.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/fonts/fontello/font/fontello.woff2
--------------------------------------------------------------------------------
/prototype/app/assets/images/placesforbikes-logo-vertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/prototype/app/assets/images/placesforbikes-logo-vertical.png
--------------------------------------------------------------------------------
/src/angularjs/src/assets/images/bna-logo-horizontal-2021.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/images/bna-logo-horizontal-2021.png
--------------------------------------------------------------------------------
/src/django/pfb_analysis/apps.py:
--------------------------------------------------------------------------------
1 | from __future__ import unicode_literals
2 |
3 | from django.apps import AppConfig
4 |
5 |
6 | class PfbAnalysisConfig(AppConfig):
7 | name = 'pfb_analysis'
8 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/birmingham/birmingham.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/django/pfb_analysis/tests/data/birmingham/birmingham.shp
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/birmingham/birmingham.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/django/pfb_analysis/tests/data/birmingham/birmingham.shx
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/ann-arbor-mi/ann-arbor-mi.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/django/pfb_analysis/tests/data/ann-arbor-mi/ann-arbor-mi.shp
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/ann-arbor-mi/ann-arbor-mi.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/django/pfb_analysis/tests/data/ann-arbor-mi/ann-arbor-mi.shx
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/birmingham/birmingham.prj:
--------------------------------------------------------------------------------
1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
--------------------------------------------------------------------------------
/prototype/app/assets/sass/components/_image.scss:
--------------------------------------------------------------------------------
1 | img {
2 | max-width: 100%;
3 | }
4 |
5 | .center-img {
6 | display: block;
7 | margin: auto;
8 | max-width: 100%;
9 | height: auto;
10 | }
--------------------------------------------------------------------------------
/src/angularjs/src/styles/components/_image.scss:
--------------------------------------------------------------------------------
1 | img {
2 | max-width: 100%;
3 | }
4 |
5 | .center-img {
6 | display: block;
7 | margin: auto;
8 | max-width: 100%;
9 | height: auto;
10 | }
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/ann-arbor-mi/ann-arbor-mi.prj:
--------------------------------------------------------------------------------
1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
--------------------------------------------------------------------------------
/deployment/terraform/config.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | region = var.aws_region
3 | }
4 |
5 | terraform {
6 | backend "s3" {
7 | region = "us-east-1"
8 | encrypt = "true"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/prototype/grunt/sass.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | sourceMap: true
4 | },
5 | dev: {
6 | files: {
7 | 'app/assets/css/main.css': 'app/assets/sass/main.scss'
8 | }
9 | }
10 | };
--------------------------------------------------------------------------------
/src/angularjs/src/app/index.constants.js:
--------------------------------------------------------------------------------
1 | /* global moment:false */
2 | (function() {
3 | 'use strict';
4 |
5 | angular
6 | .module('pfb')
7 | .constant('moment', moment);
8 |
9 | })();
10 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/places/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.places',
5 | ['pfb.places.list', 'pfb.places.detail', 'pfb.places.compare']);
6 | })();
7 |
--------------------------------------------------------------------------------
/src/angularjs/src/assets/fonts/bootstrap/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/fonts/bootstrap/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/src/angularjs/src/assets/fonts/bootstrap/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/fonts/bootstrap/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/src/angularjs/src/assets/fonts/bootstrap/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/fonts/bootstrap/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/src/angularjs/src/styles/components/_panel.scss:
--------------------------------------------------------------------------------
1 | .panel {
2 | background-color: #fff;
3 | position: relative;
4 | border: 1px solid #ddd;
5 | }
6 |
7 | .panel-body {
8 | padding: 1.5rem;
9 | }
10 |
--------------------------------------------------------------------------------
/prototype/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | // measures the time each task takes
4 | require('time-grunt')(grunt);
5 |
6 | // load grunt config
7 | require('load-grunt-config')(grunt);
8 |
9 | };
--------------------------------------------------------------------------------
/src/angularjs/src/app/neighborhoods/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.neighborhoods',
5 | ['pfb.neighborhoods.list', 'pfb.neighborhoods.detail']);
6 | })();
7 |
--------------------------------------------------------------------------------
/src/angularjs/src/assets/fonts/bootstrap/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/angularjs/src/assets/fonts/bootstrap/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/batch_create_shapefile/PFB_BigJumpCities_1.prj:
--------------------------------------------------------------------------------
1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
--------------------------------------------------------------------------------
/prototype/grunt/concurrent.js:
--------------------------------------------------------------------------------
1 | // This file goes with grunt-concurrent. Not in use
2 | module.exports = {
3 | first: [
4 | 'sass',
5 | 'postcss'
6 | ],
7 | second: [
8 | 'watch',
9 | 'browserSync'
10 | ]
11 | };
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/batch_create_shapefile/PFB_BigJumpCities_1.dbf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/django/pfb_analysis/tests/data/batch_create_shapefile/PFB_BigJumpCities_1.dbf
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/batch_create_shapefile/PFB_BigJumpCities_1.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/django/pfb_analysis/tests/data/batch_create_shapefile/PFB_BigJumpCities_1.shp
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/batch_create_shapefile/PFB_BigJumpCities_1.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/django/pfb_analysis/tests/data/batch_create_shapefile/PFB_BigJumpCities_1.shx
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/batch_create_shapefile/PFB_BigJumpCities_1.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PeopleForBikes/pfb-network-connectivity/HEAD/src/django/pfb_analysis/tests/data/batch_create_shapefile/PFB_BigJumpCities_1.zip
--------------------------------------------------------------------------------
/src/tilegarden/.env.dev:
--------------------------------------------------------------------------------
1 | AWS_PROFILE=pfb
2 | PFB_DB_HOST=database.service.pfb.internal
3 | PFB_DB_DATABASE=pfb
4 | PFB_DB_PASSWORD=pfb
5 | PFB_DB_PORT=5432
6 | PFB_DB_USER=pfb
7 | PFB_TILEGARDEN_CACHE_BUCKET=dev-pfb-tilecache-us-east-1
8 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/organizations/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.organizations',
5 | ['pfb.organizations.list',
6 | 'pfb.organizations.detail']);
7 | })();
8 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/password-reset/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.passwordReset',
5 | ['pfb.passwordReset.request',
6 | 'pfb.passwordReset.reset']);
7 | })();
8 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/components/_nav.scss:
--------------------------------------------------------------------------------
1 | nav {
2 |
3 | a {
4 | display: inline-block;
5 | padding: 10px;
6 | }
7 | }
8 |
9 | nav.social {
10 | font-size: 1.8rem;
11 |
12 | a:not(:hover) {
13 | color: #fff;
14 | }
15 | }
--------------------------------------------------------------------------------
/src/angularjs/src/styles/components/_nav.scss:
--------------------------------------------------------------------------------
1 | nav {
2 |
3 | a {
4 | display: inline-block;
5 | padding: 10px;
6 | }
7 | }
8 |
9 | nav.social {
10 | font-size: 1.8rem;
11 |
12 | a:not(:hover) {
13 | color: #fff;
14 | }
15 | }
--------------------------------------------------------------------------------
/src/analysis/stress/stress_one_way_reset.sql:
--------------------------------------------------------------------------------
1 | -- reset opposite stress for one-way
2 | UPDATE neighborhood_ways
3 | SET ft_seg_stress = NULL
4 | WHERE one_way = 'tf';
5 | UPDATE neighborhood_ways
6 | SET tf_seg_stress = NULL
7 | WHERE one_way = 'ft';
8 |
--------------------------------------------------------------------------------
/prototype/grunt/browserSync.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | dev: {
3 | bsFiles: {
4 | src : [
5 | 'app/**/*.css',
6 | 'app/**/*.html'
7 | ]
8 | },
9 | options: {
10 | watchTask: true,
11 | server: './app'
12 | }
13 | }
14 | };
--------------------------------------------------------------------------------
/src/analysis/stress/stress_link_ints.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | UPDATE neighborhood_ways SET ft_int_stress = 1, tf_int_stress = 1
6 | WHERE functional_class LIKE '%_link';
7 |
--------------------------------------------------------------------------------
/src/angularjs/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/prototype/grunt/watch.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | script: {
3 | files: ['app/**/*.js'],
4 | options: {
5 | spawn: false,
6 | }
7 | },
8 |
9 | css: {
10 | files: ['app/**/*.scss'],
11 | tasks: ['sass', 'postcss'],
12 | options: {
13 | spawn: false,
14 | }
15 | }
16 | };
--------------------------------------------------------------------------------
/src/verifier/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | verifier:
4 | image: pfb-verifier
5 | build:
6 | context: .
7 | dockerfile: Dockerfile
8 | volumes:
9 | - ../../data/output:/opt/verifier/output
10 | - ../../verified_output:/opt/verifier/verified_output
--------------------------------------------------------------------------------
/deployment/terraform/versions.tf:
--------------------------------------------------------------------------------
1 |
2 | terraform {
3 | required_version = ">= 0.13"
4 | required_providers {
5 | aws = {
6 | source = "hashicorp/aws"
7 | version = "~> 4.20.1"
8 | }
9 | template = {
10 | source = "hashicorp/template"
11 | version = "~> 2.1.0"
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/tests/data/batch_create_shapefile/PFB_BigJumpCities_1.qpj:
--------------------------------------------------------------------------------
1 | GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
2 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/pages/_location.scss:
--------------------------------------------------------------------------------
1 | .location-overview {
2 |
3 | .metric-details {
4 | padding: 1rem 2rem;
5 | background-color: $shade-light;
6 | border-bottom: 1px solid darken($shade-light, 5%);
7 | position: relative;
8 | z-index: 1;
9 |
10 | .column {
11 | padding: 0;
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/src/angularjs/src/styles/base/_list.scss:
--------------------------------------------------------------------------------
1 | dl {
2 | @extend %clearfix;
3 | }
4 |
5 | dl > dt {
6 | font-weight: 600;
7 | clear: both;
8 | margin: 5px 0;
9 | }
10 |
11 | dl > dd {
12 | margin-bottom: 10px;
13 | margin-left: 0;
14 | }
15 |
16 | ul {
17 | li {
18 | margin-top: 1rem;
19 | margin-bottom: 1rem;
20 | }
21 | }
--------------------------------------------------------------------------------
/prototype/app/assets/sass/base/_list.scss:
--------------------------------------------------------------------------------
1 | dl {
2 | @extend %clearfix;
3 | }
4 |
5 | dl > dt {
6 | font-weight: 600;
7 | clear: both;
8 | margin: 5px 0;
9 | }
10 |
11 | dl > dd {
12 | margin-bottom: 10px;
13 | margin-left: 0;
14 | }
15 |
16 | ul {
17 | li {
18 | margin-top: 1rem;
19 | margin-bottom: 1rem;
20 | }
21 | }
--------------------------------------------------------------------------------
/prototype/grunt/postcss.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | options: {
3 | map: false,
4 | processors: [
5 | require('autoprefixer')({browsers: ['last 2 versions']}),
6 | require('cssnano')({
7 | 'safe': true
8 | }) // minify the result
9 | ],
10 | },
11 | dist: {
12 | src: 'app/assets/css/*.css'
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/places/list/places-list-map.html:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/src/analysis/import/mapconfig_cycleway.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/analysis/stress/stress_primary_ints.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | -- assume low stress, since these juncions would always be controlled or free flowing
6 | UPDATE neighborhood_ways SET ft_int_stress = 1, tf_int_stress = 1
7 | WHERE functional_class = 'primary';
8 |
--------------------------------------------------------------------------------
/src/tilegarden/src/util/error-builder.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Builds an error object that stores an HTTP error code
3 | * @private
4 | * @param text - Error message.
5 | * @param status - HTTP status
6 | * @returns {Error}
7 | */
8 | module.exports = (text, status) => {
9 | const error = new Error(text)
10 | error.http_code = status
11 | return error
12 | }
13 |
--------------------------------------------------------------------------------
/deployment/aws-batch/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | update-job-defs:
3 | image: update-job-defs
4 | build:
5 | context: .
6 | dockerfile: Dockerfile
7 | environment:
8 | - AWS_PROFILE
9 | - AWS_DEFAULT_REGION
10 | - AWS_ACCESS_KEY_ID
11 | - AWS_SECRET_ACCESS_KEY
12 | volumes:
13 | - $HOME/.aws:/root/.aws:ro
14 |
--------------------------------------------------------------------------------
/src/analysis/stress/stress_secondary_ints.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | -- assume low stress, since these juncions would always be controlled or free flowing
6 | UPDATE neighborhood_ways SET ft_int_stress = 1, tf_int_stress = 1
7 | WHERE functional_class = 'secondary';
8 |
--------------------------------------------------------------------------------
/src/django/gunicorn.conf.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | bind = ":9202"
4 | accesslog = "-"
5 | errorlog = "-"
6 | workers = 3
7 | worker_class = 'gevent'
8 | loglevel = "Info"
9 |
10 | ENVIRONMENT = os.getenv("DJANGO_ENV", "dev")
11 |
12 | if ENVIRONMENT == "development":
13 | reload = True
14 | else:
15 | preload = True
16 |
17 | wsgi_app = "pfb_network_connectivity.wsgi"
18 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/components/_network-score.scss:
--------------------------------------------------------------------------------
1 | .network-score {
2 | margin-top: 1rem;
3 | margin-bottom: 1rem;
4 | font-size: 4rem;
5 | font-weight: bold;
6 |
7 | &.large {
8 | font-size: 7rem;
9 | margin-bottom: 0;
10 | }
11 |
12 | &.small {
13 | font-size: 2.5rem;
14 | margin: 0;
15 | }
16 |
17 | .h3, h3 {
18 | margin: 0;
19 | }
20 | }
--------------------------------------------------------------------------------
/src/analysis/stress/stress_motorway-trunk_ints.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | -- assume low stress, since these juncions would always be controlled or free flowing
6 | UPDATE neighborhood_ways SET ft_int_stress = 1, tf_int_stress = 1
7 | WHERE functional_class IN ('motorway','trunk');
8 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/components/_network-score.scss:
--------------------------------------------------------------------------------
1 | .network-score {
2 | margin-top: 1rem;
3 | margin-bottom: 1rem;
4 | font-size: 4rem;
5 | font-weight: bold;
6 |
7 | &.large {
8 | font-size: 7rem;
9 | margin-bottom: 0;
10 | }
11 |
12 | &.small {
13 | font-size: 2.5rem;
14 | margin: 0;
15 | }
16 |
17 | .h3, h3 {
18 | margin: 0;
19 | }
20 | }
--------------------------------------------------------------------------------
/prototype/app/assets/sass/layout/_container.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | width: 100%;
3 | max-width: 970px;
4 | margin: auto;
5 |
6 | @include respond-to('sm-down') {
7 | padding: 0 1rem;
8 | }
9 | }
10 |
11 | .container-small {
12 | width: 100%;
13 | max-width: 960px;
14 | margin: auto;
15 |
16 | @include respond-to('sm-down') {
17 | padding: 1rem;
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/layout/_container.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | width: 100%;
3 | max-width: 970px;
4 | margin: auto;
5 |
6 | @include respond-to('sm-down') {
7 | padding: 0 1rem;
8 | }
9 | }
10 |
11 | .container-small {
12 | width: 100%;
13 | max-width: 960px;
14 | margin: auto;
15 |
16 | @include respond-to('sm-down') {
17 | padding: 1rem;
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/analysis-jobs/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.analysisJobs',
5 | ['pfb.analysisJobs.constants',
6 | 'pfb.analysisJobs.list',
7 | 'pfb.analysisJobs.create',
8 | 'pfb.analysisJobs.detail',
9 | 'pfb.analysisJobs.import']);
10 | })();
11 |
--------------------------------------------------------------------------------
/src/analysis/connectivity/reachable_roads_high_stress_cleanup.sql:
--------------------------------------------------------------------------------
1 | CREATE UNIQUE INDEX IF NOT EXISTS idx_neighborhood_rchblrdshistrss_b ON generated.neighborhood_reachable_roads_high_stress (base_road, target_road);
2 | CREATE INDEX IF NOT EXISTS idx_neighborhood_rchblrdshistrss_t ON generated.neighborhood_reachable_roads_high_stress (target_road);
3 | VACUUM ANALYZE generated.neighborhood_reachable_roads_high_stress;
4 |
--------------------------------------------------------------------------------
/src/analysis/stress/stress_path.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | UPDATE neighborhood_ways SET ft_seg_stress = NULL, tf_seg_stress = NULL
6 | WHERE functional_class = 'path';
7 |
8 | UPDATE neighborhood_ways
9 | SET ft_seg_stress = 1,
10 | tf_seg_stress = 1
11 | WHERE functional_class = 'path';
12 |
--------------------------------------------------------------------------------
/src/nginx/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:1.10
2 |
3 | MAINTAINER Azavea
4 |
5 | RUN mkdir -p /srv/dist && \
6 | chown nginx:nginx -R /srv/dist/
7 |
8 | RUN mkdir -p /srv/static && \
9 | chown nginx:nginx -R /srv/static/
10 |
11 | COPY srv/dist /srv/dist/
12 | COPY srv/static /srv/static/
13 | COPY etc/nginx/nginx.conf /etc/nginx/nginx.conf
14 | COPY etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
15 |
--------------------------------------------------------------------------------
/src/analysis/stress/stress_track.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | UPDATE neighborhood_ways SET ft_seg_stress = NULL, tf_seg_stress = NULL
6 | WHERE functional_class = 'track';
7 |
8 | UPDATE neighborhood_ways
9 | SET ft_seg_stress = 1,
10 | tf_seg_stress = 1
11 | WHERE functional_class = 'track';
12 |
--------------------------------------------------------------------------------
/src/analysis/features/legs.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | UPDATE received.neighborhood_ways_intersections
6 | SET legs = (
7 | SELECT COUNT(road_id)
8 | FROM neighborhood_ways
9 | WHERE neighborhood_ways_intersections.int_id IN (intersection_from,intersection_to)
10 | );
11 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/pages/_compare.scss:
--------------------------------------------------------------------------------
1 | .comparisons {
2 | background-color: $shade-light;
3 |
4 | .card {
5 | margin-top: 2rem;
6 | }
7 |
8 | .compare-remove {
9 | position: absolute;
10 | right: 10px;
11 | top: 10px;
12 | font-size: 22px;
13 | color: #000;
14 | opacity: .5;
15 | transition: .2s ease-in-out opacity;
16 |
17 | &:hover {
18 | opacity: 1;
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/prototype/app/assets/sass/pages/_compare.scss:
--------------------------------------------------------------------------------
1 | .comparisons {
2 | background-color: $shade-light;
3 |
4 | .card {
5 | margin-top: 2rem;
6 | }
7 |
8 | .compare-remove {
9 | position: absolute;
10 | right: 10px;
11 | top: 10px;
12 | font-size: 22px;
13 | color: #000;
14 | opacity: .5;
15 | transition: .2s ease-in-out opacity;
16 |
17 | &:hover {
18 | opacity: 1;
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/module.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('pfb.components',
5 | ['pfb.components.analysis-jobs',
6 | 'pfb.components.auth',
7 | 'pfb.components.filters',
8 | 'pfb.components.map',
9 | 'pfb.components.modals',
10 | 'pfb.components.thumbnailMap']);
11 | })();
12 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/neighborhoods/detail/neighborhood-detail-map.html:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/thumbnail-map/thumbnail-map.html:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
--------------------------------------------------------------------------------
/src/analysis/connectivity/reachable_roads_high_stress_prep.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | DROP TABLE IF EXISTS generated.neighborhood_reachable_roads_high_stress;
6 |
7 | CREATE TABLE generated.neighborhood_reachable_roads_high_stress (
8 | id SERIAL PRIMARY KEY,
9 | base_road INT,
10 | target_road INT,
11 | total_cost FLOAT
12 | );
13 |
--------------------------------------------------------------------------------
/src/analysis/connectivity/reachable_roads_low_stress_prep.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | DROP TABLE IF EXISTS generated.neighborhood_reachable_roads_low_stress;
6 |
7 | CREATE TABLE generated.neighborhood_reachable_roads_low_stress (
8 | id SERIAL PRIMARY KEY,
9 | base_road INT,
10 | target_road INT,
11 | total_cost FLOAT
12 | );
13 |
--------------------------------------------------------------------------------
/src/angularjs/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint:recommended",
3 | "plugins": ["angular"],
4 | "env": {
5 | "browser": true,
6 | "jasmine": true
7 | },
8 | "globals": {
9 | "angular": true,
10 | "module": true,
11 | "URI": true,
12 | "_": true,
13 | "L": true,
14 | "inject": true,
15 | "gtag": true
16 | },
17 | "rules": {
18 | "angular/controller-as-vm": [2, "ctl"],
19 | "no-unreachable": 0
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/base/_animation.scss:
--------------------------------------------------------------------------------
1 | .fade {
2 | opacity: 0;
3 | transition: .15s linear opacity;
4 | &.in {
5 | opacity: 1;
6 | }
7 | }
8 |
9 | .animationIf.ng-enter,
10 | .animationIf.ng-leave {
11 | transition: opacity ease-in-out 0.5s;
12 | }
13 | .animationIf.ng-enter,
14 | .animationIf.ng-leave.ng-leave-active {
15 | opacity: 0;
16 | }
17 | .animationIf.ng-leave,
18 | .animationIf.ng-enter.ng-enter-active {
19 | opacity: 1;
20 | }
21 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0008_merge_20170323_1200.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-03-23 12:00
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0007_auto_20170322_1309'),
12 | ('pfb_analysis', '0006_merge_20170322_1647'),
13 | ]
14 |
15 | operations = [
16 | ]
17 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0003_merge_20170307_1930.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-03-07 19:30
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0002_auto_20170307_1640'),
12 | ('pfb_analysis', '0002_analysisjob_batch_job_id'),
13 | ]
14 |
15 | operations = [
16 | ]
17 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0006_merge_20170321_1656.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-03-21 16:56
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0004_auto_20170317_2018'),
12 | ('pfb_analysis', '0005_remove_analysisjob_status'),
13 | ]
14 |
15 | operations = [
16 | ]
17 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0016_merge_20170412_1804.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-04-12 18:04
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0014_auto_20170412_1611'),
12 | ('pfb_analysis', '0015_add_neighborhood_geoms'),
13 | ]
14 |
15 | operations = [
16 | ]
17 |
--------------------------------------------------------------------------------
/src/analysis/stress/stress_motorway-trunk.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | UPDATE neighborhood_ways SET ft_seg_stress = NULL, tf_seg_stress = NULL
6 | WHERE functional_class IN ('motorway','motorway_link','trunk','trunk_link');
7 |
8 | UPDATE neighborhood_ways SET ft_seg_stress = 3, tf_seg_stress = 3
9 | WHERE functional_class IN ('motorway','motorway_link','trunk','trunk_link');
10 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0006_merge_20170322_1647.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-03-22 16:47
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0004_analysisjob_osm_extract_url'),
12 | ('pfb_analysis', '0005_remove_analysisjob_status'),
13 | ]
14 |
15 | operations = [
16 | ]
17 |
--------------------------------------------------------------------------------
/src/verifier/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3-slim
2 |
3 | MAINTAINER Azavea
4 |
5 | RUN apt-get update && apt-get install -y --no-install-recommends \
6 | python3-pip \
7 | build-essential \
8 | && rm -rf /var/lib/apt/lists/*
9 |
10 | COPY requirements.txt /tmp/
11 | RUN pip3 install --upgrade pip && pip3 install --no-cache-dir -r /tmp/requirements.txt
12 |
13 | COPY ./ /opt/verifier
14 |
15 | WORKDIR /opt/verifier
16 |
17 | ENTRYPOINT ["./compare_outputs.sh"]
18 |
19 | CMD []
20 |
--------------------------------------------------------------------------------
/src/django/pfb_network_connectivity/utils.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import requests
4 |
5 |
6 | def download_file(url, local_filename=None):
7 | if not local_filename:
8 | local_filename = os.path.join('.', url.split('/')[-1])
9 | r = requests.get(url, stream=True)
10 | with open(local_filename, 'wb') as f:
11 | for chunk in r.iter_content(chunk_size=1024):
12 | if chunk: # filter out keep-alive new chunks
13 | f.write(chunk)
14 | return local_filename
15 |
--------------------------------------------------------------------------------
/deployment/aws-batch/Dockerfile:
--------------------------------------------------------------------------------
1 |
2 | FROM python:3.9-slim
3 |
4 | MAINTAINER Azavea
5 |
6 | RUN apt-get update && apt-get install -y --no-install-recommends \
7 | python3-pip \
8 | build-essential \
9 | && rm -rf /var/lib/apt/lists/*
10 |
11 | COPY requirements.txt /tmp/
12 | RUN pip3 install --upgrade pip && pip3 install --no-cache-dir -r /tmp/requirements.txt
13 |
14 | COPY ./ /opt/aws-batch
15 |
16 | WORKDIR /opt/aws-batch
17 |
18 | ENTRYPOINT ["python", "update_job_definition.py"]
19 |
20 | CMD ["--help"]
21 |
--------------------------------------------------------------------------------
/scripts/setup:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cd `dirname "${0}"`
6 |
7 | if [[ -n "${PFB_DEBUG}" ]]; then
8 | set -x
9 | fi
10 |
11 | function usage() {
12 | echo -n \
13 | "Usage: $(basename "$0")
14 |
15 | Sets up the development environment by building containers and loading example data.
16 |
17 | "
18 | }
19 |
20 | if [ "${BASH_SOURCE[0]}" = "${0}" ]
21 | then
22 | if [ "${1:-}" = "--help" ]
23 | then
24 | usage
25 | else
26 | ./update --load-data
27 | fi
28 | fi
29 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/pages/_location.scss:
--------------------------------------------------------------------------------
1 | .location-overview {
2 |
3 | .dropdown {
4 | display: inline;
5 | }
6 |
7 | .metric-details {
8 | padding: 0 2rem;
9 | background-color: $shade-light;
10 | border-bottom: 1px solid darken($shade-light, 5%);
11 | position: relative;
12 | z-index: 99;
13 |
14 | .row {
15 | margin: 0;
16 | }
17 |
18 | .network-score {
19 | margin: 0;
20 |
21 | .h3 {
22 | margin-left: 1rem;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/django/pfb_network_connectivity/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for pfb_network_connectivity project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pfb_network_connectivity.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/index.module.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | angular
5 | .module('pfb', [
6 | 'angular-loading-bar', 'pfb.login', 'pfb.analysisJobs', 'pfb.help', 'pfb.home',
7 | 'pfb.utils', 'pfb.places', 'pfb.passwordReset', 'pfb.users', 'pfb.organizations',
8 | 'pfb.neighborhoods',
9 | 'ngAnimate', 'ngCookies', 'ngSanitize', 'ngMessages', 'ngAria',
10 | 'ngResource', 'ui.router', 'toastr', 'ui.bootstrap', 'pfb.components']);
11 |
12 | })();
13 |
--------------------------------------------------------------------------------
/src/analysis/connectivity/reachable_roads_low_stress_cleanup.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | CREATE INDEX IF NOT EXISTS idx_neighborhood_rchblrdslowstrss_b ON generated.neighborhood_reachable_roads_low_stress (base_road);
6 | CREATE INDEX IF NOT EXISTS idx_neighborhood_rchblrdslowstrss_t ON generated.neighborhood_reachable_roads_low_stress (target_road);
7 | VACUUM ANALYZE generated.neighborhood_reachable_roads_low_stress (base_road,target_road);
8 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/places/detail/place-map.html:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
--------------------------------------------------------------------------------
/deployment/terraform/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | terraform:
3 | image: quay.io/azavea/terraform:1.1.9
4 | volumes:
5 | - ./:/usr/local/src
6 | - $HOME/.aws:/root/.aws:ro
7 | - ${PWD}/.gitconfig:/root/.gitconfig
8 | environment:
9 | - PFB_DEBUG=1
10 | - AWS_PROFILE
11 | - GIT_COMMIT
12 | - PFB_SETTINGS_BUCKET
13 | - BATCH_ANALYSIS_JOB_NAME_REVISION
14 | - AWS_ACCESS_KEY_ID
15 | - AWS_SECRET_ACCESS_KEY
16 | working_dir: /usr/local/src
17 | entrypoint: terraform
18 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/modals/confirmation-modal.html:
--------------------------------------------------------------------------------
1 |
4 |
7 |
12 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0005_remove_analysisjob_status.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-03-17 20:39
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0004_analysisjobstatusupdate'),
12 | ]
13 |
14 | operations = [
15 | migrations.RemoveField(
16 | model_name='analysisjob',
17 | name='status',
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0045_analysisjob_skip_import_jobs.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2022-07-01 20:04
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('pfb_analysis', '0044_analysisjob_population_url'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='analysisjob',
15 | name='skip_import_jobs',
16 | field=models.BooleanField(default=False),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/src/tilegarden/tests/error-builder.test.js:
--------------------------------------------------------------------------------
1 | const HTTPError = require('../src/util/error-builder')
2 |
3 | describe('Error builder', () => {
4 | test('Check that an HTTPError gets built properly', () => {
5 | const message = 'This function doesn\'t really need testing, but I want Jest to be happy.'
6 | const code = 401
7 |
8 | const error = HTTPError(message, code)
9 | expect(error).toBeInstanceOf(Error)
10 | expect(error.http_code).toBe(code)
11 | expect(error.message).toBe(message)
12 | })
13 | })
14 |
--------------------------------------------------------------------------------
/src/django/pfb_network_connectivity/migrations/0002_delete_neighborhood.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-02-24 16:39
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('users', '0003_auto_20170224_1639'),
12 | ('pfb_network_connectivity', '0001_initial'),
13 | ]
14 |
15 | operations = [
16 | migrations.DeleteModel(
17 | name='Neighborhood',
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/prototype/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mantle",
3 | "version": "0.1.0",
4 | "description": "Azavea's front end framework for GIS applications",
5 | "devDependencies": {
6 | "autoprefixer": "^6.3.6",
7 | "cssnano": "^3.5.2",
8 | "grunt": "^0.4.5",
9 | "grunt-browser-sync": "^2.2.0",
10 | "grunt-contrib-watch": "^1.0.0",
11 | "grunt-newer": "^1.2.0",
12 | "grunt-postcss": "^0.8.0",
13 | "grunt-sass": "^1.1.0",
14 | "load-grunt-config": "^0.19.1",
15 | "load-grunt-tasks": "^3.5.0",
16 | "time-grunt": "^1.3.0"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0043_update_jsonfield_django_32.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2022-06-09 17:21
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('pfb_analysis', '0042_analysisjob_max_trip_distance'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='analysisjob',
15 | name='overall_scores',
16 | field=models.JSONField(db_index=True, default=dict),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0046_analysisjob_jobs_url_field.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2022-07-01 20:53
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('pfb_analysis', '0045_analysisjob_skip_import_jobs'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='analysisjob',
15 | name='jobs_url',
16 | field=models.URLField(blank=True, max_length=2048, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0044_analysisjob_population_url.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2022-06-28 18:30
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('pfb_analysis', '0043_update_jsonfield_django_32'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='analysisjob',
15 | name='population_url',
16 | field=models.URLField(blank=True, max_length=2048, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/scripts/server:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cd `dirname "${0}"`
6 |
7 | if [[ -n "${PFB_DEBUG}" ]]; then
8 | set -x
9 | fi
10 |
11 | function usage() {
12 | echo -n \
13 | "Usage: $(basename "$0")
14 |
15 | Starts servers using docker-compose.
16 |
17 | "
18 | }
19 |
20 | if [ "${BASH_SOURCE[0]}" = "${0}" ]
21 | then
22 | if [ "${1:-}" = "--help" ]
23 | then
24 | usage
25 | else
26 | pushd ..
27 |
28 | docker compose up --build nginx django django-q angularjs tilegarden
29 |
30 | popd
31 | fi
32 | fi
33 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0042_analysisjob_max_trip_distance.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.16 on 2022-04-01 16:58
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('pfb_analysis', '0041_auto_20201006_2320'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='analysisjob',
15 | name='max_trip_distance',
16 | field=models.PositiveIntegerField(blank=True, default=2680, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/src/tilegarden/src/config/mml/census_blocks.mml:
--------------------------------------------------------------------------------
1 | name: Census blocks
2 | srs: +init=epsg:3857
3 | format: png
4 |
5 | Stylesheet:
6 | - census_blocks.mss
7 |
8 | Layer:
9 | - id: neighborhood_census_blocks
10 | name: neighborhood_census_blocks
11 | geometry: polygon
12 | srs: "+init=epsg:4326"
13 | Datasource:
14 | host: ${PFB_DB_HOST}
15 | dbname: ${PFB_DB_DATABASE}
16 | user: ${PFB_DB_USER}
17 | password: ${PFB_DB_PASSWORD}
18 | type: "postgis"
19 | table: "pfb_analysis_censusblocksresults"
20 | key_field: ""
21 | geometry_field: "geom"
22 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0024_auto_20170509_2121.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.7 on 2017-05-09 21:21
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0023_auto_20170509_2110'),
12 | ]
13 |
14 | operations = [
15 | migrations.RenameField(
16 | model_name='analysisjob',
17 | old_name='last_status',
18 | new_name='status',
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/docker-compose.test.yml:
--------------------------------------------------------------------------------
1 | services:
2 | nginx:
3 | image: pfb-nginx:${GIT_COMMIT}
4 | build:
5 | context: ./src/nginx
6 | dockerfile: Dockerfile
7 |
8 | django:
9 | image: pfb-app:${GIT_COMMIT}
10 | build:
11 | context: ./src/django
12 | dockerfile: Dockerfile
13 |
14 | analysis:
15 | image: pfb-analysis:${GIT_COMMIT}
16 | build:
17 | context: ./src
18 | dockerfile: analysis/Dockerfile
19 |
20 | tilegarden:
21 | env_file: ./src/tilegarden/.env
22 | volumes:
23 | - ./src/tilegarden/claudia:/opt/pfb/tilegarden/claudia
24 |
--------------------------------------------------------------------------------
/scripts/django-manage:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cd `dirname "${0}"`
6 |
7 | if [[ -n "${PFB_DEBUG}" ]]; then
8 | set -x
9 | fi
10 |
11 | function usage() {
12 | echo -n \
13 | "Usage: $(basename "$0")
14 |
15 | Run a Django management command in the running django container
16 |
17 | "
18 | }
19 |
20 | if [ "${BASH_SOURCE[0]}" = "${0}" ]
21 | then
22 | if [ "${1:-}" = "--help" ]
23 | then
24 | usage
25 | else
26 | pushd ..
27 |
28 | docker compose exec django python3 manage.py "${@}"
29 |
30 | popd
31 | fi
32 | fi
33 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/functions.py:
--------------------------------------------------------------------------------
1 | from django.db.models.expressions import Func
2 |
3 |
4 | class ObjectAtPath(Func):
5 | """ Database function to extract an object or value from a JSONField """
6 | function = '#>'
7 | template = "%(expressions)s%(function)s'{%(path)s}'"
8 | arity = 1
9 |
10 | def __init__(self, expression, path, **extra):
11 | # if path is a list, convert it to a comma separated string
12 | if isinstance(path, (list, tuple)):
13 | path = ','.join(path)
14 | super(ObjectAtPath, self).__init__(expression, path=path, **extra)
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2017 Azavea, Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/countries.service.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc service
3 | * @name pfb.components.stats:Country
4 | * @description
5 | * Resource for countries
6 | */
7 | (function() {
8 | 'use strict';
9 |
10 | /* @ngInject */
11 | function Country($resource) {
12 | return $resource('/api/countries/', {}, {
13 | cache: true,
14 | query: {
15 | method: 'GET',
16 | isArray: true
17 | }
18 | });
19 | }
20 |
21 | angular.module('pfb.components')
22 | .factory('Country', Country);
23 | })();
24 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0047_neighborhood_speed_limit.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2022-08-22 16:37
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('pfb_analysis', '0046_analysisjob_jobs_url_field'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='neighborhood',
15 | name='speed_limit',
16 | field=models.IntegerField(blank=True, help_text='The default residential speed limit, in MPH', null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/src/analysis/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2017 Azavea, Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0002_analysisjob_batch_job_id.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-03-03 16:19
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0001_initial'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='analysisjob',
17 | name='batch_job_id',
18 | field=models.CharField(blank=True, max_length=256, null=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/management/commands/analysis_batch_cancel.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from pfb_analysis.models import AnalysisBatch
4 |
5 |
6 | class Command(BaseCommand):
7 | help = """ Cancel all jobs in an AnalysisBatch """
8 |
9 | def add_arguments(self, parser):
10 | parser.add_argument('batch_uuid', type=str)
11 |
12 | def handle(self, *args, **options):
13 | batch_uuid = options['batch_uuid']
14 |
15 | batch = AnalysisBatch.objects.get(uuid=batch_uuid)
16 | self.stdout.write('Cancelling {}'.format(batch))
17 | batch.cancel()
18 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0036_neighborhood_city_fips.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.13 on 2019-01-31 19:59
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0035_auto_20190124_1853'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='neighborhood',
17 | name='city_fips',
18 | field=models.CharField(blank=True, default='', max_length=7),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/src/tilegarden/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "jest": true
4 | },
5 | "extends": "airbnb-base",
6 | "rules": {
7 | "camelcase": 2,
8 | "indent": ["error", 4],
9 | "import/no-extraneous-dependencies": ["error", {"optionalDependencies": true}],
10 | "no-console": 0,
11 | "no-unexpected-multiline": 2,
12 | "max-len": ["error", 100, { "ignoreComments": true}],
13 | "max-statements": ["error", 50],
14 | "object-curly-newline": ["error", { "consistent": true }],
15 | "quotes": ["error", "single"],
16 | "semi": [2, "never"],
17 | "strict": 2,
18 | "vars-on-top": 2
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/tilegarden/scripts/build-xml.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # This script is never meant to be called directly by the user.
4 | # It should only be called by other scripts that pass MML strings
5 | # in to it, so that different environments can have access to the
6 | # version of carto installed on the docker container.
7 |
8 | function main() {
9 | tempFile="${1%%.*}.temp.mml"
10 |
11 | # fill in environment variables
12 | node scripts/template-vars.js "${1}" > ${tempFile}
13 |
14 | # compile with carto
15 | carto ${tempFile}
16 |
17 | # clean up
18 | rm ${tempFile}
19 | }
20 |
21 | main "${1}" "${2}"
22 |
--------------------------------------------------------------------------------
/src/tilegarden/src/util/logger.js:
--------------------------------------------------------------------------------
1 | /* Creates and exports a logger that logs to console and prepends a timestamp.
2 | * Default log level is 'info', switching to 'debug' if DEBUG is true in the environment.
3 | */
4 |
5 | const { createLogger, format, transports } = require('winston')
6 |
7 | const logger = createLogger({
8 | level: process.env.DEBUG ? 'debug' : 'info',
9 | format: format.combine(
10 | format.timestamp(),
11 | format.printf(({ timestamp, level, message }) => `${level}:\t${timestamp} ${message}`),
12 | ),
13 | transports: [new transports.Console()],
14 | })
15 |
16 | module.exports = logger
17 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/index.run.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | angular
5 | .module('pfb')
6 | .run(runBlock);
7 |
8 | /** @ngInject */
9 | function runBlock($rootScope, $window) {
10 | // Ignore on-watch rule, since we're attaching to $rootScope
11 | /*eslint angular/on-watch: 0*/
12 | $rootScope.$on('$stateChangeSuccess', function ($event, toState) {
13 | var event = {
14 | 'app_name': 'PFB BNA Score',
15 | 'screen_name': toState.name,
16 | 'environment': $window.location.hostname
17 | }
18 | gtag('event', 'screen_view', event);
19 | });
20 | }
21 | })();
22 |
--------------------------------------------------------------------------------
/src/django/users/utils.py:
--------------------------------------------------------------------------------
1 | """Utility functions for User views/serializers"""
2 |
3 | from django.conf import settings
4 | from django.core.signing import TimestampSigner
5 |
6 |
7 | def get_password_reset_url(request, user):
8 | """Generates a password reset URL given a Request and user
9 |
10 | Args:
11 | request (rest_framework.request.Request)
12 | user (PBBUser): user to generate password reset url for
13 | """
14 | signer = TimestampSigner(salt=settings.RESET_SALT)
15 | token = signer.sign('{}'.format(user.uuid))
16 | return request.build_absolute_uri('/#/password-reset/?token={}'.format(token))
17 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0011_analysisjob_census_block_count.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-03-24 19:58
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0010_analysisjob_overall_scores'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='analysisjob',
17 | name='census_block_count',
18 | field=models.PositiveIntegerField(blank=True, null=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/src/analysis/features/one_way.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | UPDATE neighborhood_ways SET one_way_car = NULL;
6 |
7 | -- ft direction
8 | UPDATE neighborhood_ways
9 | SET one_way_car = 'ft'
10 | FROM neighborhood_osm_full_line osm
11 | WHERE neighborhood_ways.osm_id = osm.osm_id
12 | AND trim(osm.oneway) IN ('1','yes');
13 |
14 | -- tf direction
15 | UPDATE neighborhood_ways
16 | SET one_way_car = 'tf'
17 | FROM neighborhood_osm_full_line osm
18 | WHERE neighborhood_ways.osm_id = osm.osm_id
19 | AND trim(osm.oneway) = '-1';
20 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/components/_metrics.scss:
--------------------------------------------------------------------------------
1 | .metric-list {
2 | margin: 0;
3 | list-style-type: none;
4 | padding: 0;
5 | position: relative;
6 | z-index: 10;
7 |
8 | li {
9 | padding: 2rem;
10 | margin: 0;
11 | border-top: 1px solid #ddd;
12 | font-size: 1.8rem;
13 | }
14 |
15 | .network-score {
16 | float: right;
17 | margin-top: -5px !important;
18 | }
19 |
20 | .list-button {
21 | text-align: center;
22 | }
23 | }
24 |
25 | .metric-details {
26 | flex: 1;
27 | padding: 2rem;
28 |
29 | h1, h2, h3, h4 {
30 | margin: 0;
31 | }
32 |
33 | p:last-of-type {
34 | margin-bottom: 0;
35 | }
36 | }
--------------------------------------------------------------------------------
/src/tilegarden/scripts/template-vars.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Stub script that places variable templates with the proper env variable.
3 | * In all likelihood this could be done with one line of sed but I was having
4 | * trouble getting the string replacement part to work out.
5 | */
6 |
7 | const fs = require('fs')
8 |
9 | fs.readFile(process.argv[2], 'utf-8', function (err, out) {
10 | if (err) process.stderr.write(err)
11 | else {
12 | const templated = out.replace(
13 | /\$\{([a-z0-9_]+)\}/gi,
14 | (_, envName) => `"${process.env[envName]}"`
15 | )
16 |
17 | process.stdout.write(templated)
18 | }
19 | })
20 |
--------------------------------------------------------------------------------
/src/analysis/features/class_adjustments.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- Adjusts functional class on residential
3 | -- and unclassified with bike facilities
4 | -- or multiple travel lanes to be
5 | -- tertiary
6 | ----------------------------------------
7 | UPDATE received.neighborhood_ways
8 | SET functional_class = 'tertiary'
9 | WHERE functional_class IN ('residential','unclassified')
10 | AND (
11 | ft_bike_infra IN ('track','buffered_lane','lane')
12 | OR tf_bike_infra IN ('track','buffered_lane','lane')
13 | OR ft_lanes > 1
14 | OR tf_lanes > 1
15 | OR speed_limit >= 30
16 | );
17 |
--------------------------------------------------------------------------------
/src/django/users/emails.py:
--------------------------------------------------------------------------------
1 | """Python file holding emails to be sent"""
2 |
3 | password_reset_txt = """
4 | Hello {username},
5 |
6 | Someone has requested a password reset link.
7 |
8 | If this was you, please reset your password at
9 |
10 | {url}
11 |
12 | If not, please disregard this e-mail.
13 |
14 | Thank you!
15 | """
16 |
17 | user_registration_txt = """
18 | Hello {user_firstname},
19 |
20 | {created_by_name} from the {created_by_organization} organization has created a user ({username})
21 | for you in the {created_organization} organization.
22 |
23 | To complete registration please set your password at
24 |
25 | {url}
26 |
27 | Thank you!
28 | """
29 |
--------------------------------------------------------------------------------
/src/angularjs/gulp/docs.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var path = require('path');
4 | var gulp = require('gulp');
5 | var conf = require('./conf');
6 |
7 | var ngdocs = require('gulp-ngdocs');
8 |
9 |
10 | gulp.task('docs', function () {
11 | var options = {
12 | scripts: [
13 | 'bower/angular/angular.min.js',
14 | 'bower/angular-animate/angular-animate.min.js'
15 | ],
16 | title: 'PfB Network Connectivity Angular Docs',
17 | html5Mode: false
18 | };
19 |
20 | return gulp.src(path.join(conf.paths.src, 'app/**/*.js'))
21 | .pipe(ngdocs.process(options))
22 | .pipe(gulp.dest('./docs'));
23 | });
24 |
--------------------------------------------------------------------------------
/src/django/users/migrations/0002_auto_20170221_1653.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-02-21 16:53
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 | import django.db.models.deletion
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('users', '0001_initial'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterField(
17 | model_name='pfbuser',
18 | name='organization',
19 | field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='users.Organization'),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0021_neighborhood_visibility.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-05-09 14:52
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0020_neighborhood_geom_simple'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='neighborhood',
17 | name='visibility',
18 | field=models.CharField(choices=[('public', 'Public'), ('private', 'Private')], default='public', max_length=10),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/prototype/app/assets/fonts/fontello/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Font license info
2 |
3 |
4 | ## Font Awesome
5 |
6 | Copyright (C) 2016 by Dave Gandy
7 |
8 | Author: Dave Gandy
9 | License: SIL ()
10 | Homepage: http://fortawesome.github.com/Font-Awesome/
11 |
12 |
13 | ## Entypo
14 |
15 | Copyright (C) 2012 by Daniel Bruce
16 |
17 | Author: Daniel Bruce
18 | License: SIL (http://scripts.sil.org/OFL)
19 | Homepage: http://www.entypo.com
20 |
21 |
22 | ## Iconic
23 |
24 | Copyright (C) 2012 by P.J. Onori
25 |
26 | Author: P.J. Onori
27 | License: SIL (http://scripts.sil.org/OFL)
28 | Homepage: http://somerandomdude.com/work/iconic/
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0014_neighborhood_geom.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-04-11 15:15
3 | from __future__ import unicode_literals
4 |
5 | import django.contrib.gis.db.models.fields
6 | from django.db import migrations
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('pfb_analysis', '0013_auto_20170407_0106'),
13 | ]
14 |
15 | operations = [
16 | migrations.AddField(
17 | model_name='neighborhood',
18 | name='geom',
19 | field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0017_neighborhood_geom_pt.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-04-13 14:59
3 | from __future__ import unicode_literals
4 |
5 | import django.contrib.gis.db.models.fields
6 | from django.db import migrations
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('pfb_analysis', '0016_merge_20170412_1804'),
13 | ]
14 |
15 | operations = [
16 | migrations.AddField(
17 | model_name='neighborhood',
18 | name='geom_pt',
19 | field=django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/src/angularjs/src/assets/fonts/fontello/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Font license info
2 |
3 |
4 | ## Font Awesome
5 |
6 | Copyright (C) 2016 by Dave Gandy
7 |
8 | Author: Dave Gandy
9 | License: SIL ()
10 | Homepage: http://fortawesome.github.com/Font-Awesome/
11 |
12 |
13 | ## Entypo
14 |
15 | Copyright (C) 2012 by Daniel Bruce
16 |
17 | Author: Daniel Bruce
18 | License: SIL (http://scripts.sil.org/OFL)
19 | Homepage: http://www.entypo.com
20 |
21 |
22 | ## Iconic
23 |
24 | Copyright (C) 2012 by P.J. Onori
25 |
26 | Author: P.J. Onori
27 | License: SIL (http://scripts.sil.org/OFL)
28 | Homepage: http://somerandomdude.com/work/iconic/
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0010_analysisjob_overall_scores.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-03-24 13:35
3 | from __future__ import unicode_literals
4 |
5 | import django.contrib.postgres.fields.jsonb
6 | from django.db import migrations
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('pfb_analysis', '0009_auto_20170323_1535'),
13 | ]
14 |
15 | operations = [
16 | migrations.AddField(
17 | model_name='analysisjob',
18 | name='overall_scores',
19 | field=django.contrib.postgres.fields.jsonb.JSONField(db_index=True, default=dict),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/src/django/pfb_network_connectivity/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-02-21 16:50
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | ]
14 |
15 | operations = [
16 | migrations.CreateModel(
17 | name='Neighborhood',
18 | fields=[
19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
20 | ('name', models.TextField()),
21 | ],
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Overview
2 |
3 | Brief description of what this PR does, and why it is needed.
4 |
5 |
6 | ### Demo
7 |
8 | Optional. Screenshots, `curl` examples, etc.
9 |
10 |
11 | ### Notes
12 |
13 | Optional. Ancillary topics, caveats, alternative strategies that didn't work out, anything else.
14 |
15 |
16 | ## Testing Instructions
17 |
18 | * How to test this PR
19 | * Prefer bulleted description
20 | * Start after checking out this branch
21 | * Include any setup required, such as bundling scripts, restarting services, etc.
22 | * Include test case, and expected output
23 |
24 |
25 | ## Checklist
26 |
27 | - [ ] Add entry to CHANGELOG.md
28 |
29 | Resolves #XXX
30 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0029_auto_20170802_1425.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.7 on 2017-08-02 14:25
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0028_analysisscoremetadata_priority'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='neighborhood',
17 | name='visibility',
18 | field=models.CharField(choices=[('public', 'Public'), ('private', 'Private'), ('hidden', 'Hidden')], default='public', max_length=10),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0039_alter_neighborhood_state_abbrev_field.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.13 on 2019-04-06 02:46
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0038_move_territories_to_us'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='neighborhood',
17 | name='state_abbrev',
18 | field=models.CharField(blank=True, help_text='The state/province of the uploaded neighborhood', max_length=10, null=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/src/angularjs/gulp/scripts.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var path = require('path');
4 | var gulp = require('gulp');
5 | var conf = require('./conf');
6 |
7 | var browserSync = require('browser-sync');
8 |
9 | var $ = require('gulp-load-plugins')();
10 |
11 |
12 | gulp.task('scripts-reload', function() {
13 | return buildScripts()
14 | .pipe(browserSync.stream());
15 | });
16 |
17 | gulp.task('scripts', function() {
18 | return buildScripts();
19 | });
20 |
21 | function buildScripts() {
22 | return gulp.src(path.join(conf.paths.src, '/app/**/*.js'))
23 | .pipe($.eslint())
24 | .pipe($.eslint.format())
25 | .pipe($.eslint.failAfterError())
26 | .pipe($.size());
27 | };
28 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0040_neighborhood_analysis_job_ondelete.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.5 on 2019-11-11 16:12
2 |
3 | from django.db import migrations, models
4 | import django.db.models.deletion
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('pfb_analysis', '0039_alter_neighborhood_state_abbrev_field'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='neighborhood',
16 | name='last_job',
17 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='last_job_neighborhood', to='pfb_analysis.AnalysisJob'),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0028_analysisscoremetadata_priority.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.7 on 2017-05-22 13:20
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0027_remove_states_from_labels'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='analysisscoremetadata',
17 | name='priority',
18 | field=models.PositiveSmallIntegerField(blank=True, help_text='Determines sort order in response, lower numbers sort first', null=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/utils/_mixins.scss:
--------------------------------------------------------------------------------
1 | /* * * *
2 | * Responsive Breakpoint Manager
3 | * requires $breakpoints from _variables.scss > $breakpoints
4 | * Useage: @include respond-to('small') {...}
5 | * * * */
6 | @mixin respond-to($breakpoint) {
7 | // If the key exists in the map
8 | @if map-has-key($breakpoints, $breakpoint) {
9 | // Prints a media query based on the value
10 | @media #{inspect(map-get($breakpoints, $breakpoint))} {
11 | @content;
12 | }
13 | }
14 |
15 | // If the key doesn't exist in the map
16 | @else {
17 | @warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. "
18 | + "Available breakpoints are: #{map-keys($breakpoints)}.";
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/utils/_mixins.scss:
--------------------------------------------------------------------------------
1 | /* * * *
2 | * Responsive Breakpoint Manager
3 | * requires $breakpoints from _variables.scss > $breakpoints
4 | * Useage: @include respond-to('small') {...}
5 | * * * */
6 | @mixin respond-to($breakpoint) {
7 | // If the key exists in the map
8 | @if map-has-key($breakpoints, $breakpoint) {
9 | // Prints a media query based on the value
10 | @media #{inspect(map-get($breakpoints, $breakpoint))} {
11 | @content;
12 | }
13 | }
14 |
15 | // If the key doesn't exist in the map
16 | @else {
17 | @warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. "
18 | + "Available breakpoints are: #{map-keys($breakpoints)}.";
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/tilegarden/scripts/deploy:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | yarn claudia update --config claudia/claudia.json --no-optional-dependencies \
4 | --runtime "provided" \
5 | --layers "arn:aws:lambda:${LAMBDA_REGION}:553035198032:layer:nodejs12:36" \
6 | ${LAMBDA_TIMEOUT:+--timeout ${LAMBDA_TIMEOUT}} \
7 | ${LAMBDA_MEMORY:+--memory ${LAMBDA_MEMORY}} \
8 | ${LAMBDA_SECURITY_GROUPS:+--security-group-ids ${LAMBDA_SECURITY_GROUPS}} \
9 | ${LAMBDA_SUBNETS:+--subnet-ids ${LAMBDA_SUBNETS}} \
10 | --set-env PFB_DB_HOST=${PFB_DB_HOST},PFB_DB_DATABASE=${PFB_DB_DATABASE},PFB_DB_PASSWORD=${PFB_DB_PASSWORD},PFB_DB_PORT=${PFB_DB_PORT},PFB_DB_USER=${PFB_DB_USER},${PFB_TILEGARDEN_CACHE_BUCKET:+PFB_TILEGARDEN_CACHE_BUCKET=${PFB_TILEGARDEN_CACHE_BUCKET}}
11 |
--------------------------------------------------------------------------------
/src/analysis/features/island.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | -- vars:
5 | -- :sigctl_search_dist=25 Search distance for traffic signals at adjacent intersection
6 | ----------------------------------------
7 | UPDATE neighborhood_ways_intersections SET island = FALSE;
8 |
9 | UPDATE neighborhood_ways_intersections
10 | SET island = TRUE
11 | WHERE legs > 2
12 | AND EXISTS (
13 | SELECT 1
14 | FROM neighborhood_osm_full_point osm
15 | WHERE osm.highway = 'crossing'
16 | AND osm."crossing:island" = 'yes'
17 | AND ST_DWithin(neighborhood_ways_intersections.geom, osm.way, :sigctl_search_dist)
18 | );
19 |
--------------------------------------------------------------------------------
/src/analysis/stress/stress_living_street.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | UPDATE neighborhood_ways SET ft_seg_stress = NULL, tf_seg_stress = NULL
6 | WHERE functional_class = 'living_street';
7 |
8 | UPDATE neighborhood_ways
9 | SET ft_seg_stress = 3,
10 | tf_seg_stress = 3
11 | FROM neighborhood_osm_full_line osm
12 | WHERE functional_class = 'living_street'
13 | AND neighborhood_ways.osm_id = osm.osm_id
14 | AND osm.bicycle = 'no';
15 |
16 | UPDATE neighborhood_ways
17 | SET ft_seg_stress = COALESCE(ft_seg_stress,1),
18 | tf_seg_stress = COALESCE(tf_seg_stress,1)
19 | WHERE functional_class = 'living_street';
20 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0025_auto_20170511_1244.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-05-11 12:44
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 | import django.db.models.deletion
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('pfb_analysis', '0024_auto_20170509_2121'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterField(
17 | model_name='neighborhood',
18 | name='last_job',
19 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='last_job_neighborhood', to='pfb_analysis.AnalysisJob'),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/components/_metrics.scss:
--------------------------------------------------------------------------------
1 | .metric-list {
2 | margin: 0;
3 | list-style-type: none;
4 | padding: 0;
5 | position: relative;
6 | z-index: 10;
7 |
8 | li {
9 | padding: 2rem;
10 | margin: 0;
11 | border-top: 1px solid #ddd;
12 | font-size: 1.8rem;
13 |
14 | &.subscore {
15 | padding-left: 4rem;
16 | font-size: 1.4rem;
17 | }
18 | }
19 |
20 | .network-score {
21 | float: right;
22 | margin-top: -5px !important;
23 | }
24 |
25 | .list-button {
26 | text-align: center;
27 | }
28 | }
29 |
30 | .metric-details {
31 | flex: 1;
32 | padding: 2rem;
33 |
34 | h1, h2, h3, h4 {
35 | margin: 0;
36 | }
37 |
38 | p:last-of-type {
39 | margin-bottom: 0;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0018_add_neighborhood_geom_pt.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-04-13 14:59
3 | from __future__ import unicode_literals
4 |
5 | import django.contrib.gis.db.models.fields
6 | from django.db import migrations
7 |
8 |
9 | def set_neighborhood_geom_pt(apps, schema_editor):
10 | Neighborhood = apps.get_model("pfb_analysis", "Neighborhood")
11 | for n in Neighborhood.objects.all():
12 | n.geom_pt = n.geom.centroid
13 | n.save()
14 |
15 |
16 | class Migration(migrations.Migration):
17 |
18 | dependencies = [
19 | ('pfb_analysis', '0017_neighborhood_geom_pt'),
20 | ]
21 |
22 | operations = [
23 | migrations.RunPython(set_neighborhood_geom_pt)
24 | ]
25 |
--------------------------------------------------------------------------------
/deployment/terraform/network.tf:
--------------------------------------------------------------------------------
1 | # VPC module for setting up vpc
2 | module "vpc" {
3 | source = "github.com/azavea/terraform-aws-vpc?ref=6.0.1"
4 | name = "pfb${var.environment}"
5 | region = var.aws_region
6 | key_name = var.aws_key_name
7 | cidr_block = var.vpc_cidr_block
8 | private_subnet_cidr_blocks = var.vpc_private_subnet_cidr_blocks
9 | public_subnet_cidr_blocks = var.vpc_public_subnet_cidr_blocks
10 | availability_zones = var.vpc_availibility_zones
11 | bastion_ami = var.bastion_ami
12 | bastion_instance_type = var.vpc_bastion_instance_type
13 |
14 | project = var.project
15 | environment = var.environment
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/src/analysis/features/rrfb.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | -- vars:
5 | -- :sigctl_search_dist=25 Search distance for traffic signals at adjacent intersection
6 | ----------------------------------------
7 | UPDATE neighborhood_ways_intersections SET rrfb = FALSE;
8 |
9 | UPDATE neighborhood_ways_intersections
10 | SET rrfb = TRUE
11 | WHERE legs > 2
12 | AND EXISTS (
13 | SELECT 1
14 | FROM neighborhood_osm_full_point osm
15 | WHERE osm.highway = 'crossing'
16 | AND osm.flashing_lights IN ('yes','button','always','sensor')
17 | AND ST_DWithin(neighborhood_ways_intersections.geom, osm.way, :sigctl_search_dist)
18 | );
19 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0035_auto_20190124_1853.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.13 on 2019-01-24 18:53
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0034_add_analysislocaluploadtask_model'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='analysislocaluploadtask',
17 | name='status',
18 | field=models.CharField(choices=[('CREATED', 'Created'), ('QUEUED', 'Queued'), ('IMPORTING', 'Importing'), ('COMPLETE', 'Complete'), ('ERROR', 'Error')], default='CREATED', max_length=16),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0049_neighborhood_geog.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2022-12-05 20:50
2 |
3 | import django.contrib.gis.db.models.fields
4 | from django.db import migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('pfb_analysis', '0048_crash'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='neighborhood',
16 | name='geog',
17 | field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, geography=True, null=True, srid=4326),
18 | ),
19 | migrations.RunSQL(
20 | "UPDATE pfb_analysis_neighborhood SET geog = geom;",
21 | migrations.RunSQL.noop
22 | )
23 | ]
24 |
--------------------------------------------------------------------------------
/deployment/terraform/task-definitions/nginx.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "cpu": 10,
4 | "essential": true,
5 | "image": "${app_server_nginx_url}",
6 | "extraHosts": [
7 | {
8 | "hostname": "django",
9 | "ipAddress": "127.0.0.1"
10 | }
11 | ],
12 | "memory": 256,
13 | "name": "nginx",
14 | "portMappings": [
15 | {
16 | "containerPort": 80,
17 | "hostPort": 0
18 | }
19 | ],
20 | "logConfiguration": {
21 | "logDriver": "syslog",
22 | "options": {
23 | "syslog-address": "${pfb_app_papertrail_endpoint}",
24 | "syslog-tls-ca-cert": "/etc/papertrail-bundle.pem",
25 | "tag": "nginx-redirect"
26 | }
27 | }
28 | }
29 | ]
30 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0032_neighborhood_country.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.13 on 2018-12-05 16:30
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 | import django_countries.fields
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('pfb_analysis', '0031_censusblocksresults_neighborhoodwaysresults'),
13 | ]
14 |
15 | operations = [
16 | migrations.AddField(
17 | model_name='neighborhood',
18 | name='country',
19 | field=django_countries.fields.CountryField(default='US', help_text='The country of the uploaded neighborhood', max_length=2),
20 | preserve_default=False,
21 | ),
22 | ]
23 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0019_auto_20170421_1746.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-04-21 17:46
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 | import pfb_analysis.models
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('pfb_analysis', '0018_add_neighborhood_geom_pt'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterField(
17 | model_name='neighborhood',
18 | name='boundary_file',
19 | field=models.FileField(help_text='A zipped shapefile boundary to run the bike network analysis on', max_length=1024, upload_to=pfb_analysis.models.get_neighborhood_file_upload_path),
20 | ),
21 | ]
22 |
--------------------------------------------------------------------------------
/src/analysis/features/speed_limit.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | UPDATE neighborhood_ways SET speed_limit = NULL;
6 |
7 | -- convert kmph to mph and round to nearest 5
8 | UPDATE neighborhood_ways
9 | SET speed_limit = ROUND(substring(osm.maxspeed from '\d+')::INT / 1.609 / 5)*5
10 | FROM neighborhood_osm_full_line osm
11 | WHERE neighborhood_ways.osm_id = osm.osm_id
12 | AND (osm.maxspeed LIKE '% kmph' OR osm.maxspeed ~ '^\d+(\.\d+)?$');
13 |
14 | UPDATE neighborhood_ways
15 | SET speed_limit = substring(osm.maxspeed from '\d+')::INT
16 | FROM neighborhood_osm_full_line osm
17 | WHERE neighborhood_ways.osm_id = osm.osm_id
18 | AND osm.maxspeed LIKE '% mph';
19 |
--------------------------------------------------------------------------------
/prototype/app/assets/js/main.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function() {
2 |
3 | /* Scroll title fix in sidebar */
4 | var container = $('#scrollHeaders'),
5 | section = $('#scrollHeaders section');
6 |
7 | $(container).on('scroll', function() {
8 | containerTop = $(this).offset().top;
9 |
10 | $(section).each(function() {
11 | var topDistance = $(this).offset().top;
12 | var topDistance2 = $(this).scrollTop();
13 |
14 | if ( (topDistance) <= containerTop ) {
15 | $(this).addClass('active');
16 | $(this).children('.section-title').css('top', containerTop);
17 | } else {
18 | $(this).removeClass('active');
19 | $(this).children('.section-title').css('top', 'initial');
20 | }
21 | });
22 | });
23 | })
--------------------------------------------------------------------------------
/src/django/users/migrations/0003_auto_20170224_1639.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-02-24 16:39
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('users', '0002_auto_20170221_1653'),
12 | ]
13 |
14 | operations = [
15 | migrations.RemoveField(
16 | model_name='organization',
17 | name='neighborhood',
18 | ),
19 | migrations.AlterField(
20 | model_name='organization',
21 | name='org_type',
22 | field=models.CharField(choices=[('ADMIN', 'PFB Administrator Organization'), ('SUBSCRIBER', 'Subscriber')], max_length=10),
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/analysis-jobs/analysis-jobs-status.filter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc filter
3 | * @name pfb.analysis-jobs.status:displayStatus
4 | *
5 | * @description
6 | * Transforms analysis job status into user friendly long description string
7 | */
8 | (function () {
9 | 'use strict';
10 |
11 | /* ngInject */
12 | function displayStatus($log, JOB_STATUSES) {
13 |
14 | return function (input) {
15 | if (input in JOB_STATUSES) {
16 | return JOB_STATUSES[input].long;
17 | }
18 |
19 | $log.warn(input + ' is not a recognized job status');
20 | return input;
21 | };
22 | }
23 |
24 | angular.module('pfb.components.analysis-jobs')
25 | .filter('displayStatus', displayStatus);
26 | })();
27 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0041_auto_20201006_2320.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.2.10 on 2020-10-06 23:20
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('pfb_analysis', '0040_neighborhood_analysis_job_ondelete'),
10 | ]
11 |
12 | operations = [
13 | migrations.AddField(
14 | model_name='analysisjob',
15 | name='default_speed_limit',
16 | field=models.PositiveIntegerField(blank=True, null=True),
17 | ),
18 | migrations.AddField(
19 | model_name='analysisjob',
20 | name='speed_limit_src',
21 | field=models.CharField(blank=True, choices=[('State', 'State'), ('City', 'City')], max_length=20, null=True),
22 | ),
23 | ]
24 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/pagination.service.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc service
3 | * @name pfb.components.Pagination:Pagination
4 | *
5 | * @description
6 | * Handles parsing next/previous links for params to aid pagination
7 | */
8 | (function() {
9 | 'use strict';
10 |
11 | /* @ngInject */
12 | function Pagination() {
13 |
14 | var module = {
15 | getLinkParams: getLinkParams
16 | };
17 |
18 | return module;
19 |
20 | function getLinkParams(url) {
21 | if (!url) {
22 | return null;
23 | } else {
24 | var uri = URI(url);
25 | return uri.search(true);
26 | }
27 | }
28 | }
29 |
30 | angular.module('pfb.components')
31 | .factory('Pagination', Pagination);
32 | })();
33 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/organizations/list/organizations-list.controller.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc controller
3 | * @name pfb.organizations.list.organizations-list.controller:OrganizationListController
4 | *
5 | * @description
6 | * Controller for Organization list page
7 | *
8 | */
9 | (function() {
10 | 'use strict';
11 |
12 | /** @ngInject */
13 | function OrganizationListController(Organization) {
14 | var ctl = this;
15 | ctl.organizations = [];
16 | ctl.orgTypes = Organization.orgTypes;
17 |
18 | initialize();
19 |
20 | function initialize() {
21 | ctl.orgs = Organization.query();
22 | }
23 | }
24 |
25 | angular
26 | .module('pfb.organizations.list')
27 | .controller('OrganizationListController', OrganizationListController);
28 | })();
29 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/base/_base.scss:
--------------------------------------------------------------------------------
1 | *, *:after, *:before {
2 | box-sizing: border-box;
3 | }
4 |
5 | html {
6 | font-size: 62.5%;
7 | font-family: 'Cabin Condensed', sans-serif;
8 | height: 100%;
9 | }
10 |
11 | body {
12 | font-size: 14px;
13 | font-size: 1.4rem;
14 | color: $text-base;
15 | height: 100%;
16 | }
17 |
18 | a {
19 | text-decoration: none;
20 | font-weight: 600;
21 | color: $brand-primary;
22 |
23 | &:hover {
24 | color: darken($brand-primary, 10%);
25 | cursor: pointer;
26 | }
27 |
28 | &:disabled, &.disabled, &[disabled] {
29 | opacity: .5;
30 | cursor: not-allowed;
31 |
32 | &:hover {
33 | color: darken($brand-primary, 10%);
34 | }
35 | }
36 | }
37 |
38 | hr {
39 | margin-top: 1rem;
40 | margin-bottom: 1rem;
41 | border: 0;
42 | border-top: 1px solid #797979;
43 | clear: both;
44 | }
45 |
--------------------------------------------------------------------------------
/src/angularjs/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:6.17-stretch
2 |
3 | MAINTAINER Azavea
4 |
5 | ENV ANGULAR_DIR /opt/pfb/angularjs
6 | ENV NODE_OPTIONS --use-openssl-ca
7 |
8 | RUN echo "deb http://archive.debian.org/debian stretch main" > /etc/apt/sources.list
9 |
10 | RUN apt-get update && apt-get install -y --allow-unauthenticated rsync \
11 | && rm -rf /var/lib/apt/lists/*
12 |
13 | RUN npm install -g bower gulp@3.9.0
14 |
15 | WORKDIR /opt/pfb/angularjs
16 | COPY package.json ${ANGULAR_DIR}/package.json
17 | RUN npm install
18 |
19 | COPY bower.json ${ANGULAR_DIR}/bower.json
20 | COPY .bowerrc ${ANGULAR_DIR}/.bowerrc
21 | RUN bower install --allow-root --config.interactive=false
22 |
23 | COPY .eslintrc ${ANGULAR_DIR}/.eslintrc
24 | COPY gulp ${ANGULAR_DIR}/gulp
25 | COPY src ${ANGULAR_DIR}/src
26 |
27 | COPY gulpfile.js ${ANGULAR_DIR}/gulpfile.js
28 |
29 | RUN gulp build
30 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/base/_base.scss:
--------------------------------------------------------------------------------
1 | *, *:after, *:before {
2 | box-sizing: border-box;
3 | }
4 |
5 | html {
6 | font-size: 62.5%;
7 | font-family: 'Cabin Condensed', sans-serif;
8 | height: 100%;
9 | }
10 |
11 | body {
12 | font-size: 14px;
13 | font-size: 1.4rem;
14 | color: $text-base;
15 | height: 100%;
16 | }
17 |
18 | a {
19 | text-decoration: none;
20 | font-weight: 600;
21 | color: $brand-primary;
22 |
23 | &:hover {
24 | color: darken($brand-primary, 10%);
25 | cursor: pointer;
26 | }
27 |
28 | &:disabled, &.disabled, &[disabled] {
29 | opacity: .5;
30 | cursor: not-allowed;
31 |
32 | &:hover {
33 | color: darken($brand-primary, 10%);
34 | }
35 | }
36 | }
37 |
38 | hr {
39 | margin-top: 1rem;
40 | margin-bottom: 1rem;
41 | border: 0;
42 | border-top: 1px solid #797979;
43 | clear: both;
44 | }
45 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0004_analysisjob_osm_extract_url.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-03-21 14:04
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0003_merge_20170307_1930'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='analysisjob',
17 | name='osm_extract_url',
18 | field=models.URLField(blank=True, help_text='Load OSM data for this neighborhood from a URL rather than pulling from Overpass API. The url must have a .osm file extension and may optionally be compressed via zip/bzip/gz, e.g. http://a.com/foo.osm or http://a.com/foo.osm.bz2', max_length=2048, null=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/src/tilegarden/src/util/xml-tools.js:
--------------------------------------------------------------------------------
1 | /* Helper functions to encapsulate converting to and from XML.
2 | *
3 | * There's not much here, but it does get reused, and having it centralized should make it
4 | * easier to change libraries or settings if necessary.
5 | */
6 |
7 | const { promisify } = require('util')
8 | const xml2js = require('xml2js')
9 |
10 | const logger = require('./logger')
11 |
12 | // Make an async-friendly version of the parser
13 | const parsePromise = promisify(xml2js.parseString)
14 |
15 | async function parseXml(xmlString) {
16 | logger.debug('parseXml')
17 | return parsePromise(xmlString)
18 | }
19 |
20 | function buildXml(xmlJsObj) {
21 | logger.debug('buildXml')
22 | const builder = new xml2js.Builder()
23 | return builder.buildObject(xmlJsObj)
24 | }
25 |
26 | module.exports = {
27 | parseXml,
28 | buildXml,
29 | }
30 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0026_auto_20170517_1531.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.7 on 2017-05-17 15:31
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('users', '0004_auto_20170509_1559'),
12 | ('pfb_analysis', '0025_auto_20170511_1244'),
13 | ]
14 |
15 | operations = [
16 | migrations.AlterField(
17 | model_name='neighborhood',
18 | name='label',
19 | field=models.CharField(help_text='Human-readable label for neighborhood, should not include State', max_length=256),
20 | ),
21 | migrations.AlterUniqueTogether(
22 | name='neighborhood',
23 | unique_together=set([('name', 'state_abbrev', 'organization')]),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/src/tilegarden/scripts/deploy-new:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | yarn claudia create --config claudia/claudia.json --no-optional-dependencies \
4 | --runtime "provided" \
5 | --layers "arn:aws:lambda:${LAMBDA_REGION}:553035198032:layer:nodejs12:36" \
6 | --api-module dist/api \
7 | --name ${LAMBDA_FUNCTION_NAME} \
8 | --region ${LAMBDA_REGION} \
9 | --role "${LAMBDA_FUNCTION_NAME}Executor" \
10 | ${LAMBDA_TIMEOUT:+--timeout ${LAMBDA_TIMEOUT}} \
11 | ${LAMBDA_MEMORY:+--memory ${LAMBDA_MEMORY}} \
12 | ${LAMBDA_SECURITY_GROUPS:+--security-group-ids ${LAMBDA_SECURITY_GROUPS}} \
13 | ${LAMBDA_SUBNETS:+--subnet-ids ${LAMBDA_SUBNETS}} \
14 | --set-env PFB_DB_HOST=${PFB_DB_HOST},PFB_DB_DATABASE=${PFB_DB_DATABASE},PFB_DB_PASSWORD=${PFB_DB_PASSWORD},PFB_DB_PORT=${PFB_DB_PORT},PFB_DB_USER=${PFB_DB_USER},${PFB_TILEGARDEN_CACHE_BUCKET:+PFB_TILEGARDEN_CACHE_BUCKET=${PFB_TILEGARDEN_CACHE_BUCKET}}
15 |
--------------------------------------------------------------------------------
/src/tilegarden/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:12.19-buster-slim
2 |
3 | ENV BASE_DIR /opt/pfb/tilegarden
4 |
5 | # Quick fix for EOL Debian "Buster"
6 | # This command updates the sources.list to point to the archive before installing
7 | RUN sed -i 's/deb.debian.org/archive.debian.org/g' /etc/apt/sources.list && \
8 | sed -i 's|security.debian.org/debian-security|archive.debian.org/debian-security|g' /etc/apt/sources.list && \
9 | sed -i '/buster-updates/d' /etc/apt/sources.list && \
10 | apt-get update -y && apt-get install -y git jq python2 && apt-get clean
11 | RUN yarn global add carto
12 |
13 | # Copy files needed for installing packages first
14 | COPY package.json yarn.lock ${BASE_DIR}/
15 | WORKDIR ${BASE_DIR}/
16 |
17 | # install node modules
18 | RUN yarn install
19 |
20 | # Copy remaining files after package installation to benefit from layer caching
21 | COPY . ${BASE_DIR}/
22 |
23 | CMD ["yarn", "dev"]
24 |
--------------------------------------------------------------------------------
/scripts/test:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | DIR="$(dirname "$0")"
6 |
7 | function usage() {
8 | echo -n \
9 | "Usage: $(basename "$0")
10 | Run application tests
11 | "
12 | }
13 | if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
14 | if [ "${1:-}" = "--help" ]; then
15 | usage
16 | else
17 | echo "running python tests..."
18 | docker compose -f "${DIR}/../docker-compose.yml" run \
19 | --rm --entrypoint "python3 manage.py test --noinput" django
20 |
21 | echo "running Tilegarden tests..."
22 | docker compose run --rm --no-deps tilegarden yarn test
23 |
24 | echo "running angularjs linter..."
25 | docker compose run --rm --no-deps angularjs gulp lint
26 |
27 | echo "running angularjs build..."
28 | docker compose run --rm --no-deps angularjs gulp build
29 |
30 | echo "tests finished"
31 | fi
32 | fi
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/analysis/features/stops.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | -- vars:
5 | -- :sigctl_search_dist=25 Search distance for traffic signals at adjacent intersection
6 | ----------------------------------------
7 | UPDATE neighborhood_ways_intersections SET stops = 'f';
8 |
9 | UPDATE neighborhood_ways_intersections
10 | SET stops = 't'
11 | FROM neighborhood_osm_full_point osm
12 | WHERE neighborhood_ways_intersections.osm_id = osm.osm_id
13 | AND osm.highway = 'stop'
14 | AND osm.stop = 'all';
15 |
16 | UPDATE neighborhood_ways_intersections
17 | SET stops = 't'
18 | WHERE legs > 2
19 | AND EXISTS (
20 | SELECT 1
21 | FROM neighborhood_ways_intersections i
22 | WHERE i.stops
23 | AND ST_DWithin(neighborhood_ways_intersections.geom, i.geom, :sigctl_search_dist)
24 | );
25 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/home/neighborhood-map.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Is your place on the map?
4 |
5 |
24 |
--------------------------------------------------------------------------------
/src/django/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pfb_network_connectivity.settings")
7 | try:
8 | from django.core.management import execute_from_command_line
9 | except ImportError:
10 | # The above import may fail for some other reason. Ensure that the
11 | # issue is really that Django is missing to avoid masking other
12 | # exceptions on Python 2.
13 | try:
14 | import django
15 | except ImportError:
16 | raise ImportError(
17 | "Couldn't import Django. Are you sure it's installed and "
18 | "available on your PYTHONPATH environment variable? Did you "
19 | "forget to activate a virtual environment?"
20 | )
21 | raise
22 | execute_from_command_line(sys.argv)
23 |
--------------------------------------------------------------------------------
/src/django/Dockerfile:
--------------------------------------------------------------------------------
1 | # Note: the Django and psycopg2 versions are repeated in requirements.txt for the benefit
2 | # of the analysis container. The base container and requirements file versions should be kept
3 | # in sync.
4 | FROM python:3.10-slim-bullseye
5 |
6 | WORKDIR /usr/src
7 | COPY requirements.txt /tmp/
8 |
9 | RUN set -ex \
10 | && buildDeps=" \
11 | build-essential \
12 | libpq-dev \
13 | " \
14 | && deps=" \
15 | gdal-bin \
16 | libgdal-dev \
17 | gettext \
18 | postgresql-client-13 \
19 | " \
20 | && apt-get update && apt-get install -y $buildDeps $deps --no-install-recommends \
21 | && pip install --no-cache-dir -r /tmp/requirements.txt \
22 | && apt-get purge -y --auto-remove $buildDeps \
23 | && rm -rf /tmp/requirements.txt /var/lib/apt/lists/*
24 |
25 | COPY . /usr/src
26 |
27 | EXPOSE 9202
28 |
29 | ENTRYPOINT ["/usr/local/bin/gunicorn"]
30 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0009_auto_20170323_1535.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-03-23 15:35
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0008_merge_20170323_1200'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='analysisjobstatusupdate',
17 | name='status',
18 | field=models.CharField(choices=[('CREATED', 'Created'), ('QUEUED', 'Queued'), ('IMPORTING', 'Importing Data'), ('BUILDING', 'Building Network Graph'), ('CONNECTIVITY', 'Calculating Connectivity'), ('METRICS', 'Calculating Graph Metrics'), ('EXPORTING', 'Exporting Results'), ('CANCELLED', 'Cancelled'), ('COMPLETE', 'Complete'), ('ERROR', 'Error')], max_length=12),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0007_auto_20170322_1309.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-03-22 13:09
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0006_merge_20170321_1656'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='analysisjobstatusupdate',
17 | name='status',
18 | field=models.CharField(choices=[('CREATED', 'Created'), ('QUEUED', 'Queued'), ('IMPORTING', 'Importing Data'), ('BUILDING', 'Building Network Graph'), ('CONNECTIVITY', 'Calculating Connectivity'), ('METRICS', 'Calculating Graph Metrics'), ('EXPORTING', 'Exporting Results'), (('CANCELLED',), 'Cancelled'), ('COMPLETE', 'Complete'), ('ERROR', 'Error')], max_length=12),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0030_auto_20180419_1342.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.11 on 2018-04-19 13:42
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0029_auto_20170802_1425'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='analysisjob',
17 | name='osm_extract_url',
18 | field=models.URLField(blank=True, help_text='Load OSM data for this neighborhood from a URL rather than pulling from Goefabrik extracts. The url must be to an uncompressed OSM file (with .osm extension) or a compressed OSM file (with .osm.zip, .osm.gzip, .osm.bz2, or .osm.pbf extension). e.g. http://a.com/foo.osm or http://a.com/foo.osm.bz2', max_length=2048, null=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/src/tilegarden/src/config/mml/ways.mml:
--------------------------------------------------------------------------------
1 | name: Neighborhood ways
2 | srs: +init=epsg:3857
3 | format: png
4 |
5 | Stylesheet:
6 | - ways.mss
7 |
8 | Layer:
9 | - id: neighborhood_waysTF
10 | name: neighborhood_waysTF
11 | geometry: line
12 | srs: "+init=epsg:4326"
13 | Datasource:
14 | host: ${PFB_DB_HOST}
15 | dbname: ${PFB_DB_DATABASE}
16 | user: ${PFB_DB_USER}
17 | password: ${PFB_DB_PASSWORD}
18 | type: "postgis"
19 | table: "pfb_analysis_neighborhoodwaysresults"
20 | key_field: ""
21 | geometry_field: "geom"
22 | - id: neighborhood_waysFT
23 | name: neighborhood_waysFT
24 | geometry: line
25 | srs: "+init=epsg:4326"
26 | Datasource:
27 | host: ${PFB_DB_HOST}
28 | dbname: ${PFB_DB_DATABASE}
29 | user: ${PFB_DB_USER}
30 | password: ${PFB_DB_PASSWORD}
31 | type: "postgis"
32 | table: "pfb_analysis_neighborhoodwaysresults"
33 | key_field: ""
34 | geometry_field: "geom"
--------------------------------------------------------------------------------
/prototype/app/assets/sass/layout/_footer.scss:
--------------------------------------------------------------------------------
1 | footer {
2 | @extend %clearfix;
3 | display: block;
4 | background-color: #000;
5 | padding-top: 4rem;
6 | padding-bottom: 4rem;
7 | color: #fff;
8 | position: relative;
9 | border-top: 1px solid #333;
10 |
11 | .brand {
12 | max-width: 20rem;
13 | }
14 |
15 | .container {
16 | display: flex;
17 | align-items: baseline;
18 |
19 | @include respond-to(xs) {
20 | flex-direction: column;
21 | }
22 | }
23 | }
24 |
25 | .footer-left,
26 | .footer-right {
27 | flex: 1;
28 | }
29 |
30 | .footer-right {
31 | text-align: right;
32 |
33 | @include respond-to(xs) {
34 | text-align: left;
35 | }
36 | }
37 |
38 | .stripe {
39 | background-image: url(../images/footer-stripes.png);
40 | background-repeat: no-repeat;
41 | background-position: right;
42 | width: 100%;
43 | height: 10px;
44 | position: absolute;
45 | top: 1rem;
46 | right: 1rem;
47 | }
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/organizations.service.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc service
3 | * @name pfb.components.organization:Organization
4 | *
5 | * @description
6 | * Resource for Organization
7 | */
8 | (function() {
9 | 'use strict';
10 |
11 | /* @ngInject */
12 | function Organization($resource) {
13 | var module = $resource('/api/organizations/:uuid/', {uuid: '@uuid'}, {
14 | 'update': {
15 | method: 'PUT'
16 | },
17 | 'list': {
18 | method: 'GET',
19 | url: '/api/organizations/',
20 | isArray: true
21 | }
22 | });
23 |
24 | module.orgTypes = {
25 | ADMIN: 'Administrator Organization',
26 | SUBSCRIBER: 'Subscription'
27 | };
28 |
29 | return module;
30 | }
31 |
32 | angular.module('pfb')
33 | .factory('Organization', Organization);
34 | })();
35 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/main.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Utils
3 | **/
4 | @import
5 | "utils/mixins",
6 | "utils/variables";
7 |
8 | /**
9 | * Base
10 | **/
11 | @import
12 | "base/normalize",
13 | "base/animation",
14 | "base/base",
15 | "base/typography",
16 | "base/list",
17 | "base/grid",
18 | "base/helpers";
19 |
20 | /**
21 | * Layout
22 | **/
23 | @import
24 | "layout/container",
25 | "layout/header",
26 | "layout/footer",
27 | "layout/navbar",
28 | "layout/section";
29 |
30 | /**
31 | * Components
32 | **/
33 | @import
34 | "components/button",
35 | "components/card",
36 | "components/dropdown",
37 | "components/image",
38 | "components/form",
39 | "components/metrics",
40 | "components/nav",
41 | "components/network-score",
42 | "components/map",
43 | "components/tooltip";
44 |
45 | /**
46 | * Pages
47 | **/
48 | @import
49 | "pages/compare",
50 | "pages/location",
51 | "pages/home",
52 | "pages/mapping";
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/filters/user-filter.html:
--------------------------------------------------------------------------------
1 |
2 | Email
3 | Name
4 |
5 |
6 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/common.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | base:
4 | environment:
5 | - DJANGO_ENV=development
6 | - DJANGO_LOG_LEVEL=INFO
7 | - AWS_PROFILE=pfb
8 | - PFB_DB_HOST=database.service.pfb.internal
9 | - PFB_DB_DATABASE=pfb
10 | - PFB_DB_PASSWORD=pfb
11 | - PFB_DB_PORT=5432
12 | - PFB_DB_USER=pfb
13 | - PFB_SECRET_KEY=secret
14 | - PFB_AWS_BATCH_ANALYSIS_JOB_QUEUE_NAME=dummy-test-pfb-analysis-job-queue
15 | - PFB_AWS_BATCH_ANALYSIS_JOB_DEFINITION_NAME_REVISION="dummy-test-pfb-analysis-run-job:1"
16 | - PFB_AWS_BATCH_ANALYSIS_JOB_DEFINITION_NAME=dummy-test-pfb-analysis-run-job
17 | - PFB_TILEGARDEN_ROOT=http://localhost:9400
18 | - PFB_TILEGARDEN_CACHE_BUCKET=dev-pfb-tilecache-us-east-1
19 | volumes:
20 | - $HOME/.aws:/root/.aws:ro
21 |
22 | django-common:
23 | extends:
24 | service: base
25 | build:
26 | context: ./src/django
27 | dockerfile: Dockerfile
28 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/password-reset/request/password-reset-request.controller.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc controller
3 | * @name pfb.password-reset.controller:PasswordResetController
4 | *
5 | * @description
6 | * Controller for password reset request page
7 | *
8 | */
9 | (function() {
10 | 'use strict';
11 |
12 | /** @ngInject */
13 | function PasswordResetRequestController($log, PasswordResetService, toastr) {
14 | var ctl = this;
15 |
16 | initialize();
17 |
18 | function initialize() {
19 | ctl.requestReset = requestReset;
20 | }
21 |
22 | function requestReset() {
23 | PasswordResetService.requestPasswordReset(ctl.email);
24 | toastr.info('Password reset successfully requested');
25 | }
26 | }
27 |
28 | angular
29 | .module('pfb.passwordReset.request')
30 | .controller('PasswordResetRequestController', PasswordResetRequestController);
31 | })();
32 |
--------------------------------------------------------------------------------
/src/analysis/features/streetlight/streetlight_destinations.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | -- Prepares a table to be exported to StreetLightData
5 | ----------------------------------------
6 | DROP TABLE IF EXISTS neighborhood_streetlight_destinations;
7 | CREATE TABLE generated.neighborhood_streetlight_destinations (
8 | id SERIAL PRIMARY KEY,
9 | geom geometry(multipolygon,4326),
10 | name TEXT,
11 | blockid10 TEXT,
12 | is_pass INT
13 | );
14 |
15 | INSERT INTO neighborhood_streetlight_destinations (
16 | blockid10,
17 | name,
18 | geom,
19 | is_pass
20 | )
21 | SELECT blocks.blockid10,
22 | blocks.blockid10,
23 | -- Transform to 4326, this is what StreetLightData expects
24 | ST_Transform(blocks.geom,4326),
25 | 0
26 | FROM neighborhood_census_blocks blocks,
27 | neighborhood_boundary b
28 | WHERE ST_Intersects(blocks.geom,b.geom);
29 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0027_remove_states_from_labels.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.7 on 2017-05-18 13:19
3 | from __future__ import unicode_literals
4 | import re
5 | from django.utils.text import slugify
6 |
7 | from django.db import migrations
8 |
9 |
10 | def remove_states_from_labels(apps, schema_editor):
11 | Neighborhood = apps.get_model("pfb_analysis", "Neighborhood")
12 | for n in Neighborhood.objects.all():
13 | # Remove state abbreviation from label
14 | n.label = re.sub(r', *[A-Z]{2} *$', '', n.label)
15 | # Set name to new slugified label
16 | n.name = slugify(n.label)
17 | n.save()
18 |
19 |
20 | class Migration(migrations.Migration):
21 |
22 | dependencies = [
23 | ('pfb_analysis', '0026_auto_20170517_1531'),
24 | ]
25 |
26 | operations = [
27 | migrations.RunPython(remove_states_from_labels, reverse_code=migrations.RunPython.noop),
28 | ]
29 |
--------------------------------------------------------------------------------
/src/tilegarden/src/config/mml/bike_infrastructure.mml:
--------------------------------------------------------------------------------
1 | name: Bike infrastructure
2 | srs: +init=epsg:3857
3 | format: png
4 |
5 | Stylesheet:
6 | - bike_infrastructure.mss
7 |
8 | Layer:
9 | - id: neighborhood_waysTF
10 | name: neighborhood_waysTF
11 | geometry: line
12 | srs: "+init=epsg:4326"
13 | Datasource:
14 | host: ${PFB_DB_HOST}
15 | dbname: ${PFB_DB_DATABASE}
16 | user: ${PFB_DB_USER}
17 | password: ${PFB_DB_PASSWORD}
18 | type: "postgis"
19 | table: "pfb_analysis_neighborhoodwaysresults"
20 | key_field: ""
21 | geometry_field: "geom"
22 | - id: neighborhood_waysFT
23 | name: neighborhood_waysFT
24 | geometry: line
25 | srs: "+init=epsg:4326"
26 | Datasource:
27 | host: ${PFB_DB_HOST}
28 | dbname: ${PFB_DB_DATABASE}
29 | user: ${PFB_DB_USER}
30 | password: ${PFB_DB_PASSWORD}
31 | type: "postgis"
32 | table: "pfb_analysis_neighborhoodwaysresults"
33 | key_field: ""
34 | geometry_field: "geom"
35 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/organizations/list/organizations-list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
New Organization
7 |
Organization Management
8 |
9 |
10 |
11 | Name
12 | Type
13 |
14 |
15 |
16 |
17 |
18 | {{org.name}}
19 | {{orgList.orgTypes[org.orgType]}}
20 |
21 | Edit
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/analysis/README.md:
--------------------------------------------------------------------------------
1 | # pfb
2 |
3 | ## Docker
4 |
5 | To run the analysis in docker, first build the docker image.
6 |
7 | From the `src` folder, run
8 | ```bash
9 | docker build -t pfb -f analysis/Dockerfile .
10 | ```
11 |
12 | Then run the analysis as follows:
13 |
14 | ```bash
15 | docker run \
16 | -e PFB_SHPFILE=/data/neighborhood_boundary.shp \
17 | -e PFB_STATE=ma \
18 | -e PFB_STATE_FIPS=25 \
19 | -e NB_INPUT_SRID=2249 \
20 | -e NB_BOUNDARY_BUFFER=11000 \
21 | -v /vagrant/data/:/data/ \
22 | pfb
23 | ```
24 |
25 | The `-e` in this example sets environment variables, which will depend on the
26 | analysis you are running.
27 |
28 | The `-v` in this example mounts a local directory inside the docker container
29 | under `/data/`. The `PFB_SHPFILE` environment variable specifies the `.shp`
30 | file under this directory to use.
31 |
32 | This process of mounting a data directory with the input shapefile will be
33 | removed in favor of an import process.
34 |
--------------------------------------------------------------------------------
/scripts/console:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cd `dirname "${0}"`
6 |
7 | if [[ -n "${PFD_DEBUG}" ]]; then
8 | set -x
9 | fi
10 |
11 | usage() {
12 | echo -n "$(basename "${0}") [OPTION]
13 | Login to a running Docker container\'s shell.
14 | Options:
15 | database Database container
16 | django Django container
17 | django-q Django Q container
18 | angularjs AngularJS container
19 | nginx Nginx container
20 | tilegarden Tilegarden container
21 | help Display this help text
22 | "
23 | }
24 |
25 | case $1 in
26 | django|django-q|nginx|angularjs|tilegarden) NORMAL_CONTAINER=1 ;;
27 | database) DATABASE_CONTAINER=1 ;;
28 | help|*) usage; exit 1 ;;
29 | esac
30 |
31 | pushd ..
32 |
33 | if [ -n "$NORMAL_CONTAINER" ]; then
34 | docker compose exec "${1}" /bin/bash
35 | fi
36 |
37 | if [ -n "$DATABASE_CONTAINER" ]; then
38 | docker compose exec database gosu postgres psql -d pfb
39 | fi
40 |
41 | popd
42 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/management/commands/update_status.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from pfb_analysis.models import AnalysisJob
4 |
5 |
6 | class Command(BaseCommand):
7 | help = "Update status during an analysis job"
8 |
9 | def add_arguments(self, parser):
10 | # Positional arguments
11 | parser.add_argument('job_id')
12 | parser.add_argument('status')
13 | parser.add_argument('step')
14 | parser.add_argument('message', nargs='?', default='')
15 |
16 | def handle(self, *args, **options):
17 | try:
18 | job = AnalysisJob.objects.get(pk=options['job_id'])
19 | except (AnalysisJob.DoesNotExist, ValueError, KeyError):
20 | print('WARNING: Tried to update status for invalid job {job_id} '
21 | '(to {status} {step})'.format(**options))
22 | else:
23 | job.update_status(options['status'], step=options['step'], message=options['message'])
24 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0013_auto_20170407_0106.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-04-07 01:06
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0012_analysisscoremetadata'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='analysisjobstatusupdate',
17 | name='status',
18 | field=models.CharField(choices=[('CREATED', 'Created'), ('QUEUED', 'Queued'), ('IMPORTING', 'Importing Data'), ('BUILDING', 'Building Network Graph'), ('CONNECTIVITY', 'Calculating Connectivity'), ('METRICS', 'Calculating Graph Metrics'), ('EXPORTING', 'Exporting Results'), ('EXPORTED', 'Analysis Finished'), ('TILING', 'Generating Map Tiles'), ('COMPLETE', 'Complete'), ('CANCELLED', 'Cancelled'), ('ERROR', 'Error')], max_length=12),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/help/help.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Help
7 |
8 |
9 |
10 |
Authentication
11 |
The Account Settings page contains a field for an API token. If no API token exists, click the Refresh link to generate a new token. Once a token is created, authenticating API requests involves supplying the provided token via the Authorization HTTP header. Below is an example using curl:
12 |
13 |
14 | curl -H "Authorization: Token TOKEN" \
15 | -X GET "{{help.protocol}}://{{help.host}}/api/boundary-results/"
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/verifier/compare_outputs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DEFAULT_OUPUT='analysis_neighborhood_score_inputs.csv'
4 |
5 | USAGE="usage: $(basename {$0}) VERIFIED_FILE [FILE_TO_VERIFY]
6 |
7 | VERIFIED_FILE is name of a CSV in the verified_output directory
8 | FILE_TO_VERIFY is name of a CSV in the data/output directory; defaults to ${DEFAULT_OUPUT}
9 | "
10 |
11 | if [ $# -eq 0 ]; then
12 | echo "Missing argument for name of existing CSV file from verified_output to check against."
13 | exit 1
14 | fi
15 |
16 | if [[ "$1" == "-h" || "$1" == "--help" ]]; then
17 | echo $USAGE
18 | exit 0
19 | fi
20 |
21 | VERIFIED=verified_output/$1
22 | UNVERIFIED=output/${2:-$DEFAULT_OUPUT}
23 |
24 | echo "Comparing ${VERIFIED} to ${UNVERIFIED}"
25 |
26 | csvdiff -q id ${VERIFIED} ${UNVERIFIED}
27 |
28 | if [ $? -eq 0 ]; then
29 | echo "Output matches!"
30 | exit 0
31 | else
32 | echo "Output mismatch:"
33 | csvdiff id --style summary ${VERIFIED} ${UNVERIFIED}
34 | echo ""
35 | exit 1
36 | fi
37 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/layout/_footer.scss:
--------------------------------------------------------------------------------
1 | footer {
2 | @extend %clearfix;
3 | display: block;
4 | background-color: $brand-navy;
5 | padding-top: 4rem;
6 | padding-bottom: 4rem;
7 | color: #fff;
8 | position: relative;
9 | border-top: 1px solid lighten($brand-navy, 10%);
10 |
11 | .brand {
12 | max-width: 20rem;
13 | }
14 |
15 | .container {
16 | display: flex;
17 | align-items: baseline;
18 |
19 | @include respond-to(xs) {
20 | flex-direction: column;
21 | }
22 | }
23 | }
24 |
25 | .footer-left,
26 | .footer-right {
27 | flex: 1;
28 | }
29 |
30 | .footer-right {
31 | text-align: right;
32 |
33 | @include respond-to(xs) {
34 | text-align: left;
35 | }
36 | }
37 |
38 | .stripe {
39 | background-image: url(../assets/images/web-racing-stripe.png);
40 | background-repeat: no-repeat;
41 | background-size: 50%;
42 | background-position: right;
43 | width: 100%;
44 | height: 10px;
45 | position: absolute;
46 | top: 0;
47 | right: 0;
48 | }
49 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/layout/_navbar.scss:
--------------------------------------------------------------------------------
1 | .navbar {
2 | @extend %clearfix;
3 | position: relative;
4 | padding: 1rem;
5 | background-color: #000;
6 | z-index: 11;
7 |
8 | .container {
9 | max-width: 100%;
10 | display: flex;
11 |
12 | @include respond-to('sm-down') {
13 | flex-direction: column;
14 | text-align: center;
15 | }
16 | }
17 |
18 | nav {
19 | display: inline-block;
20 | vertical-align: middle;
21 |
22 | a {
23 | padding: 18px 20px;
24 | color: #fff;
25 | text-transform: uppercase;
26 |
27 | &:hover {
28 | color: $link-color;
29 | }
30 | }
31 | }
32 | }
33 |
34 | .navbar-left {
35 | flex: 1;
36 | }
37 |
38 | .navbar-right {
39 |
40 | @include respond-to('sm-down') {
41 | justify-content: flex-end;
42 | }
43 | }
44 |
45 | .brand {
46 | display: inline-block;
47 | vertical-align: middle;
48 |
49 | > img {
50 | max-height: 5rem;
51 | top: 4px;
52 | position: relative;
53 | }
54 | }
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0048_crash.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 3.2.13 on 2022-12-01 20:27
2 |
3 | import django.contrib.gis.db.models.fields
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('pfb_analysis', '0047_neighborhood_speed_limit'),
11 | ]
12 |
13 | operations = [
14 | migrations.CreateModel(
15 | name='Crash',
16 | fields=[
17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18 | ('fatality_count', models.IntegerField()),
19 | ('fatality_type', models.CharField(choices=[('ACTIVE', 'Other Active Transport'), ('BIKE', 'Bike'), ('MOTOR_VEHICLE', 'Motor Vehicle')], max_length=16)),
20 | ('geom_pt', django.contrib.gis.db.models.fields.PointField(srid=4326, geography=True)),
21 | ('year', models.IntegerField()),
22 | ],
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/src/tilegarden/scripts/build-all-xml.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | function usage() {
6 | echo -n "Usage: $(basename "${0}") [input directory] [output directory]
7 | Transpiles a directory's worth of MML+MSS files into Tilegarden-readable XML
8 | Options:
9 | --help Display this help text
10 | "
11 | }
12 |
13 | function main() {
14 | for file in $(echo "${1}/*")
15 | do
16 | ext="${file#*.}"
17 | if [ "$ext" == "mml" ]; then
18 | # get output path
19 | filename="${file##*/}"
20 | base="${filename%%.*}"
21 | outPath="${2}/${base}.xml"
22 |
23 | mkdir -p ${2}
24 |
25 | echo "Transpiling ${file} => ${outPath}"
26 | ./scripts/build-xml.sh "${file}" > ${outPath}
27 | fi
28 | done
29 | }
30 |
31 | if [ "${BASH_SOURCE[0]}" = "${0}" ]
32 | then
33 | if [ "${1:-}" = "--help" ]
34 | then
35 | usage
36 | else
37 | main "$1" "$2"
38 | fi
39 | exit
40 | fi
41 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/modals/modal-instance-controller.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | /**
5 | * A controller for a uibModal instance.
6 | * Use 'resolve' in your $uibModal.open() call to fill 'params' with whatever parameters
7 | * you want to use inside the modal.
8 | */
9 | /* ngInject */
10 | function ModalInstanceController($uibModalInstance, params) {
11 | var ctl = this;
12 | ctl.ok = ok;
13 | ctl.cancel = cancel;
14 |
15 | // params needs to be set on construction. If delayed until $onInit, the initial template
16 | // render doesn't have the values it needs
17 | ctl.params = params;
18 |
19 | function ok () {
20 | $uibModalInstance.close();
21 | }
22 |
23 | function cancel () {
24 | $uibModalInstance.dismiss('cancel');
25 | }
26 | }
27 |
28 | angular.module('pfb.components.modals')
29 | .controller('ModalInstanceController', ModalInstanceController);
30 |
31 | })();
32 |
--------------------------------------------------------------------------------
/src/django/users/migrations/0004_auto_20170509_1559.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.7 on 2017-05-09 15:59
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | def makeUsersViewers(apps, schema_editor):
9 | """Make all non-admin users viewers."""
10 | PFBUser = Neighborhood = apps.get_model("users", "PFBUser")
11 | for user in PFBUser.objects.filter(role__in=('EDITOR', 'UPLOADER')):
12 | user.role = 'VIEWER'
13 | user.save()
14 |
15 |
16 | class Migration(migrations.Migration):
17 |
18 | dependencies = [
19 | ('users', '0003_auto_20170224_1639'),
20 | ]
21 |
22 | operations = [
23 | migrations.RunPython(makeUsersViewers),
24 | migrations.AlterField(
25 | model_name='pfbuser',
26 | name='role',
27 | field=models.CharField(choices=[('ADMIN', 'Administrator'), ('ORGADMIN', 'Organization Administrator'), ('VIEWER', 'Viewer')], default='VIEWER', max_length=8),
28 | ),
29 | ]
30 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/modals/confirmation-modal.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | /* ngInject */
5 | function ConfirmationModal($uibModal) {
6 | var module = {
7 | open: open
8 | };
9 | return module;
10 |
11 | // Return uibModalInstance object
12 | function open(params) {
13 | var uibModalInstance = $uibModal.open({
14 | templateUrl: 'app/components/modals/confirmation-modal.html',
15 | controller: 'ModalInstanceController',
16 | controllerAs: 'modal',
17 | bindToController: true,
18 | size: 'md',
19 | resolve: {
20 | params: function () {
21 | return params;
22 | }
23 | }
24 | });
25 |
26 | return uibModalInstance;
27 | }
28 | }
29 |
30 | angular.module('pfb.components.modals')
31 | .service('ConfirmationModal', ConfirmationModal);
32 |
33 | })();
34 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/footer/footer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/angularjs/gulpfile.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to your gulpfile!
3 | * The gulp tasks are splitted in several files in the gulp directory
4 | * because putting all here was really too long
5 | */
6 |
7 | 'use strict';
8 |
9 | var gulp = require('gulp');
10 | var wrench = require('wrench');
11 | var Promise = require('es6-promise').Promise;
12 | var eslint = require('gulp-eslint');
13 |
14 | /**
15 | * This will load all js or coffee files in the gulp directory
16 | * in order to load all gulp tasks
17 | */
18 | wrench.readdirSyncRecursive('./gulp').filter(function(file) {
19 | return (/\.(js|coffee)$/i).test(file);
20 | }).map(function(file) {
21 | require('./gulp/' + file);
22 | });
23 |
24 |
25 | /**
26 | * Default task clean temporaries directories and launch the
27 | * main optimization build task
28 | */
29 | gulp.task('default', ['clean'], function () {
30 | gulp.start('build');
31 | });
32 |
33 | gulp.task('lint', [], function () {
34 | return gulp.src(['src/**/*.js'])
35 | .pipe(eslint())
36 | .pipe(eslint.format())
37 | .pipe(eslint.failAfterError());
38 | });
39 |
--------------------------------------------------------------------------------
/src/analysis/scripts/import.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cd `dirname "${0}"`
6 |
7 | if [[ -n "${PFB_DEBUG}" ]]; then
8 | set -x
9 | fi
10 |
11 | function usage() {
12 | echo -n \
13 | "
14 | Usage: $(basename "$0")
15 |
16 | Import all necessary files to run the analysis. See the scripts this calls for specific
17 | ENV configuration options.
18 |
19 | "
20 | }
21 |
22 | if [ "${BASH_SOURCE[0]}" = "${0}" ]
23 | then
24 | if [ "${1:-}" = "--help" ] || [ -z "${1:-}" ]
25 | then
26 | usage
27 | else
28 | PFB_SHPFILE="${1}"
29 | PFB_OSM_FILE="${2}"
30 | PFB_COUNTRY="${3}"
31 | PFB_STATE="${4}"
32 | PFB_STATE_FIPS="${5}"
33 |
34 | ../import/import_neighborhood.sh $PFB_SHPFILE $PFB_COUNTRY $PFB_STATE $PFB_STATE_FIPS
35 | if [ "$RUN_IMPORT_JOBS" == "1" ]; then
36 | ../import/import_jobs.sh $PFB_COUNTRY $PFB_STATE
37 | else
38 | echo "Skipping Importing Jobs"
39 | fi
40 | ../import/import_osm.sh $PFB_OSM_FILE
41 | fi
42 | fi
43 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/components/_table.scss:
--------------------------------------------------------------------------------
1 | .table {
2 | width: 100%;
3 | border-collapse: collapse;
4 | border: 1px solid #ddd;
5 | margin-bottom: 1rem;
6 |
7 | thead {
8 | text-align: left;
9 |
10 | th, td {
11 | font-weight: 600;
12 | }
13 | }
14 |
15 | tbody {
16 | text-align: left;
17 |
18 | > tr:hover {
19 | background-color: #f3f3f3;
20 | }
21 | }
22 |
23 | th,
24 | td {
25 | border-bottom: 1px solid #ddd;
26 | padding: 2rem 1.5rem;
27 | }
28 | }
29 |
30 | .table-responsive {
31 | overflow: auto;
32 | white-space: nowrap;
33 | }
34 |
35 | .table-mobile-stacked {
36 | @include respond-to(xs) {
37 |
38 | thead {
39 | display: none;
40 | }
41 |
42 | tr {
43 | border-bottom: 1px solid #ddd;
44 | }
45 |
46 | tbody [data-th] {
47 | display: block;
48 | text-align: right;
49 | border: none;
50 | padding: 1rem;
51 |
52 | &:before {
53 | content: attr(data-th);
54 | font-weight: 600;
55 | display: inline-block;
56 | margin-right: 1rem;
57 | float: left;
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/angularjs/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pfb",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "angular": "1.5.11",
6 | "angular-animate": "1.5.11",
7 | "angular-loading-bar": "0.9.0",
8 | "angular-aria": "1.5.11",
9 | "angular-cookies": "1.5.11",
10 | "highlightjs": "9.9.0",
11 | "angular-highlightjs": "0.7.0",
12 | "angular-messages": "1.5.11",
13 | "angular-sanitize": "1.5.11",
14 | "jquery": "2.2.4",
15 | "angular-resource": "1.5.11",
16 | "angular-ui-router": "0.4.2",
17 | "angular-toastr": "2.1.1",
18 | "leaflet": "1.0.3",
19 | "leaflet-groupedlayercontrol": "0.6.0",
20 | "leaflet.markercluster": "1.3.0",
21 | "moment": "2.17.1",
22 | "animate.css": "3.5.2",
23 | "angular-bootstrap": "1.3.3",
24 | "bootstrap-sass-official": "3.3.6",
25 | "urijs": "1.18.7",
26 | "lodash": "4.6.1",
27 | "ng-file-upload": "^12.2.13",
28 | "select2": "~3.4.5"
29 | },
30 | "devDependencies": {
31 | "angular-mocks": "1.5.11",
32 | "bootstrap": "^3.3.6"
33 | },
34 | "overrides": {},
35 | "resolutions": {
36 | "jquery": "2.2.4",
37 | "angular": "1.5.11"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0012_analysisscoremetadata.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-03-30 20:13
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('pfb_analysis', '0011_analysisjob_census_block_count'),
12 | ]
13 |
14 | operations = [
15 | migrations.CreateModel(
16 | name='AnalysisScoreMetadata',
17 | fields=[
18 | ('name', models.CharField(max_length=128, primary_key=True, serialize=False)),
19 | ('label', models.CharField(blank=True, help_text='Short descriptive name', max_length=256, null=True)),
20 | ('category', models.CharField(blank=True, help_text='Used to group scores with the same category together', max_length=128, null=True)),
21 | ('description', models.CharField(blank=True, help_text='Long description of the metric', max_length=1024, null=True)),
22 | ],
23 | options={
24 | 'ordering': ('name',),
25 | },
26 | ),
27 | ]
28 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/login/user-login.controller.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc controller
3 | * @name pfb.login.user-login.controller:LoginController
4 | *
5 | * @description
6 | * Controller handling logging a user in
7 | *
8 | */
9 | (function() {
10 | 'use strict';
11 |
12 | /** @ngInject */
13 | function LoginController($log, $state, toastr, AuthService) {
14 | var ctl = this;
15 |
16 | initialize();
17 |
18 | function initialize() {
19 | ctl.login = login;
20 | if (AuthService.getEmail()) {
21 | $state.go('admin.analysis-jobs.list');
22 | }
23 | }
24 |
25 | function login() {
26 | AuthService.user = AuthService.login(
27 | {'email': ctl.email, 'password': ctl.password}
28 | ).then(function() {
29 | $state.go('admin.analysis-jobs.list');
30 | }).catch(function() {
31 | toastr.error('Unable to login with credentials', 'Error');
32 | });
33 | }
34 | }
35 |
36 | angular
37 | .module('pfb.login')
38 | .controller('LoginController', LoginController);
39 |
40 | })();
41 |
--------------------------------------------------------------------------------
/scripts/clean-analysis-volumes:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | cd $(dirname "${0}")
6 |
7 | if [[ -n "${PFB_DEBUG}" ]]; then
8 | set -x
9 | fi
10 |
11 | function usage() {
12 | echo -n \
13 | "Usage: $(basename "$0")
14 |
15 | Removes all 'pfb-analysis' docker containers and their volumes to free up storage space,
16 | as well as any dangling docker volumes.
17 |
18 | "
19 | }
20 |
21 | if [ "${BASH_SOURCE[0]}" = "${0}" ]
22 | then
23 | if [ "${1:-}" = "--help" ]
24 | then
25 | usage
26 | else
27 | FILTERS='--filter "label=type=pfb-analysis" --filter "status=exited"'
28 |
29 | echo "The following containers and their volumes will be deleted:"
30 | eval docker ps -a $FILTERS
31 | echo "The following dangling docker volumes will be deleted:"
32 | docker volume ls -f 'dangling=true'
33 |
34 | read -r -p "Are you sure? [y/N] " response
35 | response=${response,,} # tolower
36 | if [[ "$response" =~ ^(yes|y)$ ]]
37 | then
38 | docker rm -v $(eval docker ps -aq $FILTERS)
39 | docker volume rm $(docker volume ls -f 'dangling=true' -q)
40 | fi
41 | fi
42 | fi
43 |
--------------------------------------------------------------------------------
/src/angularjs/gulp/watch.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var path = require('path');
4 | var gulp = require('gulp');
5 | var conf = require('./conf');
6 |
7 | var browserSync = require('browser-sync');
8 |
9 | function isOnlyChange(event) {
10 | return event.type === 'changed';
11 | }
12 |
13 | gulp.task('watch', ['inject'], function () {
14 |
15 | gulp.watch([path.join(conf.paths.src, '/*.html'), 'bower.json'], ['inject-reload']);
16 |
17 | gulp.watch([
18 | path.join(conf.paths.src, '/styles/**/*.css'),
19 | path.join(conf.paths.src, '/styles/**/*.scss')
20 | ], function(event) {
21 | if(isOnlyChange(event)) {
22 | gulp.start('styles-reload');
23 | } else {
24 | gulp.start('inject-reload');
25 | }
26 | });
27 |
28 | gulp.watch(path.join(conf.paths.src, '/app/**/*.js'), function(event) {
29 | if(isOnlyChange(event)) {
30 | gulp.start('scripts-reload');
31 | } else {
32 | gulp.start('inject-reload');
33 | }
34 | });
35 |
36 | gulp.watch(path.join(conf.paths.src, '/app/**/*.html'), function(event) {
37 | browserSync.reload(event.path);
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/footer/footer.directive.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc directive
3 | * @name pfb.footer.directive:pfbFooter
4 | * @restrict 'E'
5 | *
6 | * @description
7 | * Top level navigation bar for pfb application
8 | */
9 |
10 | (function() {
11 | 'use strict';
12 |
13 | /** @ngInject */
14 | function FooterController(AuthService) {
15 | var ctl = this;
16 |
17 | initialize();
18 |
19 | function initialize() {
20 | ctl.logout = AuthService.logout;
21 | // if user ID cookie is set, assume user is logged in
22 | ctl.loggedIn = !!AuthService.getUserId();
23 | }
24 | }
25 |
26 | function pfbFooter() {
27 | var directive = {
28 | restrict: 'E',
29 | templateUrl: 'app/components/footer/footer.html',
30 | controller: 'FooterController',
31 | controllerAs: 'footer',
32 | bindToController: true
33 | };
34 |
35 | return directive;
36 | }
37 |
38 |
39 | angular
40 | .module('pfb')
41 | .controller('FooterController', FooterController)
42 | .directive('pfbFooter', pfbFooter);
43 |
44 | })();
45 |
--------------------------------------------------------------------------------
/src/nginx/etc/nginx/nginx.conf:
--------------------------------------------------------------------------------
1 | user nginx;
2 | worker_processes 1;
3 |
4 | error_log /var/log/nginx/error.log warn;
5 | pid /var/run/nginx.pid;
6 |
7 | events {
8 | worker_connections 1024;
9 | }
10 |
11 | http {
12 | include /etc/nginx/mime.types;
13 | default_type application/octet-stream;
14 |
15 | log_format timed_combined '$remote_addr - $remote_user [$time_local] '
16 | '"$request" $status $body_bytes_sent $gzip_ratio '
17 | '"$http_referer" "$http_user_agent" '
18 | '$request_time $upstream_response_time';
19 |
20 | access_log /var/log/nginx/access.log timed_combined;
21 |
22 | sendfile on;
23 |
24 | keepalive_timeout 65;
25 |
26 | client_max_body_size 6m;
27 |
28 | server_tokens off;
29 |
30 | gzip on;
31 | gzip_types application/javascript text/css application/json;
32 | gzip_disable "msie6";
33 |
34 | set_real_ip_from 10.0.0.0/24;
35 | set_real_ip_from 10.0.2.0/24;
36 | set_real_ip_from 10.0.1.0/24;
37 | set_real_ip_from 10.0.3.0/24;
38 |
39 | real_ip_header X-Forwarded-For;
40 |
41 | include /etc/nginx/conf.d/*.conf;
42 | }
43 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/neighborhoods.service.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc service
3 | * @name pfb.components.stats:Neighborhood
4 | *
5 | * @description
6 | * Resource for neighborhoods
7 | */
8 | (function() {
9 | 'use strict';
10 |
11 | /* @ngInject */
12 | function Neighborhood($resource) {
13 | return $resource('/api/neighborhoods/:uuid/', {uuid: '@uuid'}, {
14 | 'query': {
15 | method: 'GET',
16 | isArray: false
17 | },
18 | 'all': {
19 | method: 'GET',
20 | isArray: false,
21 | params: {
22 | limit: 'all'
23 | }
24 | },
25 | 'geojson': {
26 | method: 'GET',
27 | isArray: false,
28 | url: '/api/neighborhoods_geojson/'
29 | },
30 | 'bounds': {
31 | method: 'GET',
32 | isArray: false,
33 | url: '/api/neighborhoods_bounds_geojson/:uuid/'
34 | }
35 | });
36 | }
37 |
38 | angular.module('pfb.components')
39 | .factory('Neighborhood', Neighborhood);
40 | })();
41 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/components/_tooltip.scss:
--------------------------------------------------------------------------------
1 | .tooltip {
2 | position: relative;
3 | z-index: 999;
4 | color: $brand-primary;
5 | white-space: nowrap;
6 | font-size: 1.4rem;
7 | height: 20px;
8 | display: inline-block;
9 |
10 | &:after {
11 | content: attr(title);
12 | position: absolute;
13 | top: 50%;
14 | left: 100%;
15 | transform: translate(0%, -50%);
16 | background: black;
17 | border-radius: 2px;
18 | color: white;
19 | font-style: normal;
20 | text-align: left;
21 | opacity: 0;
22 | pointer-events: none;
23 | font-size: 1.4rem;
24 | padding: 4px 10px;
25 | font-weight: 400;
26 | width: auto;
27 | min-width: 140px;
28 | max-width: 350px;
29 | white-space: normal;
30 | transition: opacity .2s ease-in-out;
31 | }
32 |
33 | &:before {
34 | content: '';
35 | display: block;
36 | position: absolute;
37 | opacity: 0;
38 | top: 50%;
39 | left: 100%;
40 | transform: translate(-100%,-50%);
41 | border: 7px solid transparent;
42 | border-right-color: black;
43 | transition: opacity .2s ease-in-out;
44 | }
45 |
46 | &:hover:after,
47 | &:hover:before {
48 | opacity: 1;
49 | }
50 | }
--------------------------------------------------------------------------------
/src/analysis/features/width_ft.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | ----------------------------------------
5 | UPDATE neighborhood_ways SET width_ft = NULL;
6 |
7 | -- feet
8 | UPDATE neighborhood_ways
9 | SET width_ft = substring(osm.width from '\d+\.?\d?\d?')::FLOAT
10 | FROM neighborhood_osm_full_line osm
11 | WHERE neighborhood_ways.osm_id = osm.osm_id
12 | AND osm.width IS NOT NULL
13 | AND osm.width LIKE '% ft';
14 |
15 | -- meters
16 | UPDATE neighborhood_ways
17 | SET width_ft = 3.28084 * substring(osm.width from '\d+\.?\d?\d?')::FLOAT
18 | FROM neighborhood_osm_full_line osm
19 | WHERE neighborhood_ways.osm_id = osm.osm_id
20 | AND osm.width IS NOT NULL
21 | AND osm.width LIKE '% m';
22 |
23 | -- no units (default=meters)
24 | -- N.B. we weed out anything more than 20, since that's likely either bogus
25 | -- or not in meters
26 | UPDATE neighborhood_ways
27 | SET width_ft = 3.28084 * substring(osm.width from '\d+\.?\d?\d?')::FLOAT
28 | FROM neighborhood_osm_full_line osm
29 | WHERE neighborhood_ways.osm_id = osm.osm_id
30 | AND osm.width IS NOT NULL
31 | AND substring(osm.width from '\d+\.?\d?\d?')::FLOAT < 20;
32 |
--------------------------------------------------------------------------------
/src/django/pfb_network_connectivity/pagination.py:
--------------------------------------------------------------------------------
1 | from rest_framework.pagination import LimitOffsetPagination
2 |
3 |
4 | class OptionalLimitOffsetPagination(LimitOffsetPagination):
5 | """
6 | Allow client to request all by setting limit parameter to 'all'
7 |
8 | Inspired by https://github.com/azavea/ashlar/blob/develop/ashlar/pagination.py
9 | """
10 | def paginate_queryset(self, queryset, request, view=None):
11 | self.limit = self.get_limit(request)
12 | # set the limit to one more than the queryset count
13 | if self.limit == 'all':
14 | self.limit = self.get_count(queryset) + 1
15 | return super(OptionalLimitOffsetPagination, self).paginate_queryset(queryset, request, view)
16 |
17 | def get_limit(self, request):
18 | # If the limit is already set as an integer (e.g. because we're in the
19 | # super.paginate_queryset call), just return it
20 | if type(getattr(self, 'limit', None)) == int:
21 | return self.limit
22 | if self.limit_query_param and request.query_params.get(self.limit_query_param) == 'all':
23 | return 'all'
24 | return super(OptionalLimitOffsetPagination, self).get_limit(request)
25 |
--------------------------------------------------------------------------------
/src/django/requirements.txt:
--------------------------------------------------------------------------------
1 | # Django and psycopg2 are included in the django base container, but the analysis
2 | # container also needs them, and uses this same requirements file.
3 | # Which means the versions here will be the ones that get installed, in both places.
4 | # Ideally these should be kept in sync with the versions in the base container
5 | # (https://github.com/azavea/docker-django/blob/master/3.2/requirements.txt) to avoid
6 | # downgrading when building the django container.
7 | Django==4.2.17
8 | psycopg2-binary==2.9.3
9 |
10 | boto3==1.23.10
11 | django-amazon-ses==4.0.0
12 | # Note: django-countries 7.3 changes how the field's filters work, so we want to stay on 7.2.1
13 | django-countries==7.2.1
14 | django-extensions==3.1.5
15 | django-filter==2.4.0
16 | django-q==1.3.9
17 | django-storages==1.12.3
18 | django-watchman==1.3.0
19 | djangorestframework==3.15.2
20 | fiona==1.8.21
21 | future==0.18.2
22 | gevent==24.11.1
23 | gunicorn==23.0.0
24 | pycountry==22.3.5
25 | pyuca==1.2
26 | requests==2.27.1
27 | us==2.0.2
28 |
29 | # This been removed from application code but was used in old migrations, so it can't be removed
30 | # unless those migrations are refactored to not import it.
31 | django-localflavor==4.0
32 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/components/_tooltip.scss:
--------------------------------------------------------------------------------
1 | .tooltip {
2 | position: relative;
3 | z-index: 999;
4 | color: $brand-primary;
5 | white-space: nowrap;
6 | font-size: 1.4rem;
7 | height: 20px;
8 | display: inline-block;
9 |
10 | &:after {
11 | content: attr(data-title);
12 | position: absolute;
13 | top: 50%;
14 | left: 100%;
15 | transform: translate(0%, -50%);
16 | background: black;
17 | border-radius: 2px;
18 | color: white;
19 | font-style: normal;
20 | text-align: left;
21 | opacity: 0;
22 | pointer-events: none;
23 | font-size: 1.4rem;
24 | padding: 10px 15px;
25 | font-weight: 400;
26 | width: auto;
27 | min-width: 140px;
28 | max-width: 350px;
29 | white-space: normal;
30 | transition: opacity .2s ease-in-out;
31 | }
32 |
33 | &:before {
34 | content: '';
35 | display: block;
36 | position: absolute;
37 | opacity: 0;
38 | top: 50%;
39 | left: 100%;
40 | transform: translate(-100%,-50%);
41 | border: 7px solid transparent;
42 | border-right-color: black;
43 | transition: opacity .2s ease-in-out;
44 | }
45 |
46 | &:hover:after,
47 | &:hover:before {
48 | opacity: 1;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/tilegarden/src/config/mml/census_blocks.mss:
--------------------------------------------------------------------------------
1 | #neighborhood_census_blocks[overall_score != null] {
2 | polygon-opacity: 0.65;
3 | }
4 |
5 | #neighborhood_census_blocks[overall_score >= 0][overall_score < 10] {
6 | polygon-fill: #FF3300;
7 | }
8 | #neighborhood_census_blocks[overall_score >= 10][overall_score < 20] {
9 | polygon-fill: #D04628;
10 | }
11 | #neighborhood_census_blocks[overall_score >= 20][overall_score < 30] {
12 | polygon-fill: #B9503C;
13 | }
14 | #neighborhood_census_blocks[overall_score >= 30][overall_score < 40] {
15 | polygon-fill: #A25A51;
16 | }
17 | #neighborhood_census_blocks[overall_score >= 40][overall_score < 50] {
18 | polygon-fill: #8B6465;
19 | }
20 | #neighborhood_census_blocks[overall_score >= 50][overall_score < 60] {
21 | polygon-fill: #736D79;
22 | }
23 | #neighborhood_census_blocks[overall_score >= 60][overall_score < 70] {
24 | polygon-fill: #5C778D;
25 | }
26 | #neighborhood_census_blocks[overall_score >= 70][overall_score < 80] {
27 | polygon-fill: #4581A2;
28 | }
29 | #neighborhood_census_blocks[overall_score >= 80][overall_score < 90] {
30 | polygon-fill: #2E8BB6;
31 | }
32 | #neighborhood_census_blocks[overall_score >= 90][overall_score <= 100] {
33 | polygon-fill: #009FDF;
34 | }
35 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/utils/_variables.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * LMC Variables
3 | * If overridng bootstrap please place inside _bs-variables.scss
4 | */
5 |
6 | // Brand Colors:
7 | $brand-primary: #00a1e1; // blue
8 | $brand-secondary: #e31d1a; // red
9 |
10 | // Base Colors:
11 | $text-base: #000000;
12 | $shade-light: #f3f3f3;
13 | $shade-normal: #bcbcbc;
14 | $shade-dark: #9da0a7;
15 | $link-color: $brand-primary;
16 | $white: #fff;
17 |
18 | // Action Colors:
19 | $warning: #E69348; // orange
20 | $danger: #F98094; // red
21 | $success: #21ce90; // red
22 |
23 | // Border Radius
24 | $border-radius-base: 2px;
25 |
26 |
27 | /* * * *
28 | * Screen Sizes
29 | * Used in _mixins.scss > @mixin respond-to($breakpoint)
30 | * * * */
31 | $breakpoints: (
32 |
33 | 'xxs': (max-width: 480px),
34 |
35 | 'xs': (max-width: 767px),
36 |
37 | 'sm': "(min-width: 768px) and (max-width: 991px)",
38 | 'sm-up': (min-width: 768px),
39 | 'sm-down': (max-width: 991px),
40 |
41 | 'md': "(min-width: 992px) and (max-width: 1180px)",
42 | 'md-up': (min-width: 992px),
43 | 'md-down': (max-width: 1180px),
44 |
45 | 'lg': (min-width: 1181px),
46 | );
47 |
48 |
49 | /* * * *
50 | * Columns
51 | * * * */
52 | $column-count: 12;
53 | $column-padding: 1rem;
54 |
--------------------------------------------------------------------------------
/docs/architecture/adr-0000-architecture-documentation.md:
--------------------------------------------------------------------------------
1 | # 0000 - Architecture Documentation
2 |
3 | ## Context
4 | We need a way to document major architecture decisions; in the past we have used the [Architecture Decision Record (ADR) format](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions). On past projects, we have found the ADR format to be a useful way to write and manage architecture decisions.
5 |
6 | We have written ADRs using both reStructuredText and Markdown formats on past projects. Certain documentation generators, such as Sphinx, can only use one of RST / Markdown. It is currently unknown which documentation generators we are likely to use for this project. The team is somewhat more comfortable writing in Markdown than RST.
7 |
8 | ## Decision
9 | We will continue to use the ADR format for writing architecture decisions for this project. We will use Markdown for formatting ADR documents.
10 |
11 | ## Consequences
12 | Major architectural decisions will need to be documented; changes to architectural decisions made via ADR will need to be documented in a superseding ADR.
13 |
14 | If we choose to use a documentation generator that does not support Markdown, we may need to convert existing ADRs to that tool's preferred format.
15 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0033_auto_20181205_1913.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.13 on 2018-12-05 19:13
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations
6 | import django_countries.fields
7 | import localflavor.us.models
8 |
9 |
10 | class Migration(migrations.Migration):
11 |
12 | dependencies = [
13 | ('users', '0004_auto_20170509_1559'),
14 | ('pfb_analysis', '0032_neighborhood_country'),
15 | ]
16 |
17 | operations = [
18 | migrations.AlterField(
19 | model_name='neighborhood',
20 | name='country',
21 | field=django_countries.fields.CountryField(default='US', help_text='The country of the uploaded neighborhood', max_length=2),
22 | ),
23 | migrations.AlterField(
24 | model_name='neighborhood',
25 | name='state_abbrev',
26 | field=localflavor.us.models.USStateField(blank=True, help_text='The state of the uploaded neighborhood, if in the US', max_length=2, null=True),
27 | ),
28 | migrations.AlterUniqueTogether(
29 | name='neighborhood',
30 | unique_together=set([('name', 'country', 'state_abbrev', 'organization')]),
31 | ),
32 | ]
33 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/utils/_variables.scss:
--------------------------------------------------------------------------------
1 | /*
2 | * LMC Variables
3 | * If overridng bootstrap please place inside _bs-variables.scss
4 | */
5 |
6 | // Brand Colors:
7 | $brand-primary: #00a1e1; // blue
8 | $brand-secondary: #e31d1a; // red
9 | $brand-navy: #002c40;
10 |
11 | // Base Colors:
12 | $text-base: #000000;
13 | $shade-light: #f3f3f3;
14 | $shade-normal: #bcbcbc;
15 | $shade-dark: #9da0a7;
16 | $link-color: $brand-primary;
17 | $white: #fff;
18 |
19 | // Action Colors:
20 | $warning: #E69348; // orange
21 | $danger: #F98094; // red
22 | $success: #21ce90; // red
23 |
24 | // Border Radius
25 | $border-radius-base: 2px;
26 |
27 |
28 | /* * * *
29 | * Screen Sizes
30 | * Used in _mixins.scss > @mixin respond-to($breakpoint)
31 | * * * */
32 | $breakpoints: (
33 |
34 | 'xxs': (max-width: 480px),
35 |
36 | 'xs': (max-width: 767px),
37 |
38 | 'sm': "(min-width: 768px) and (max-width: 991px)",
39 | 'sm-up': (min-width: 768px),
40 | 'sm-down': (max-width: 991px),
41 |
42 | 'md': "(min-width: 992px) and (max-width: 1180px)",
43 | 'md-up': (min-width: 992px),
44 | 'md-down': (max-width: 1180px),
45 |
46 | 'lg': (min-width: 1181px),
47 | );
48 |
49 |
50 | /* * * *
51 | * Columns
52 | * * * */
53 | $column-count: 12;
54 | $column-padding: 1rem;
55 |
--------------------------------------------------------------------------------
/src/angularjs/gulp/conf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This file contains the variables used in other gulp files
3 | * which defines tasks
4 | * By design, we only put there very generic config values
5 | * which are used in several places to keep good readability
6 | * of the tasks
7 | */
8 |
9 | var gutil = require('gulp-util');
10 |
11 | /**
12 | * The main paths of your project handle these with care
13 | */
14 | exports.paths = {
15 | src: 'src',
16 | bower: 'bower_components',
17 | dist: 'dist',
18 | tmp: '.tmp',
19 | e2e: 'e2e'
20 | };
21 |
22 | /**
23 | * Wiredep is the lib which inject bower dependencies in your project
24 | * Mainly used to inject script tags in the index.html but also used
25 | * to inject css preprocessor deps and js files in karma
26 | */
27 | exports.wiredep = {
28 | exclude: [/\/bootstrap\.js$/, /\/bootstrap-sass\/.*\.js/, /\/bootstrap\.css/],
29 | directory: 'bower_components'
30 | };
31 |
32 | /**
33 | * Common implementation for an error handler of a Gulp plugin
34 | */
35 | exports.errorHandler = function(title) {
36 | 'use strict';
37 |
38 | return function(err) {
39 | gutil.log(gutil.colors.red('[' + title + ']'), err.toString());
40 | this.emit('end');
41 | process.exit(1);
42 | };
43 | };
44 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0020_neighborhood_geom_simple.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-04-26 14:58
3 | from __future__ import unicode_literals
4 |
5 | import django.contrib.gis.db.models.fields
6 | from django.db import migrations
7 |
8 | from pfb_analysis.models import simplify_geom
9 |
10 |
11 | def add_neighborhood_simplified_geoms(apps, schema_editor):
12 | Neighborhood = apps.get_model("pfb_analysis", "Neighborhood")
13 | for n in Neighborhood.objects.all():
14 | n.geom_simple = simplify_geom(n.geom)
15 | n.save()
16 |
17 |
18 | class Migration(migrations.Migration):
19 |
20 | dependencies = [
21 | ('pfb_analysis', '0019_auto_20170421_1746'),
22 | ]
23 |
24 | operations = [
25 | migrations.AddField(
26 | model_name='neighborhood',
27 | name='geom_simple',
28 | field=django.contrib.gis.db.models.fields.MultiPolygonField(blank=True,
29 | null=True,
30 | srid=4326),
31 | ),
32 | migrations.RunPython(add_neighborhood_simplified_geoms,
33 | reverse_code=migrations.RunPython.noop)
34 | ]
35 |
--------------------------------------------------------------------------------
/src/tilegarden/src/config/mml/ways.mss:
--------------------------------------------------------------------------------
1 | @width-tight: 2;
2 | @width-med: 1.5;
3 | @width-wide: 1;
4 | @color-low-stress: #009fdf;
5 | @color-high-stress: #ff3300;
6 |
7 | #neighborhood_waysFT, #neighborhood_waysTF {
8 | [zoom > 13] {
9 | line-width: @width-tight;
10 | }
11 | [zoom <= 13][zoom >= 10] {
12 | line-width: @width-med;
13 | }
14 | [zoom < 10] {
15 | line-width: @width-wide;
16 | }
17 | }
18 |
19 | #neighborhood_waysTF {
20 | [zoom > 13] {
21 | line-offset: -@width-tight;
22 | }
23 | [zoom <= 13][zoom >= 10] {
24 | line-offset: -@width-med;
25 | }
26 | [zoom < 10] {
27 | line-offset: -@width-wide;
28 | }
29 | [tf_seg_str > 1] {
30 | line-color: @color-high-stress;
31 | }
32 | [tf_seg_str = 1] {
33 | line-color: @color-low-stress;
34 | }
35 | [tf_seg_str < 1] {
36 | line-opacity: 0;
37 | }
38 | }
39 |
40 | #neighborhood_waysFT {
41 | [zoom > 13] {
42 | line-offset: @width-tight;
43 | }
44 | [zoom <= 13][zoom >= 10] {
45 | line-offset: @width-med;
46 | }
47 | [zoom < 10] {
48 | line-offset: @width-wide;
49 | }
50 | [ft_seg_str > 1] {
51 | line-color: @color-high-stress;
52 | }
53 | [ft_seg_str = 1] {
54 | line-color: @color-low-stress;
55 | }
56 | [ft_seg_str < 1] {
57 | line-opacity: 0;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/tilegarden/.env.example:
--------------------------------------------------------------------------------
1 | # To import from the local environment rather than hard-coding, change to just 'AWS_PROFILE'
2 | AWS_PROFILE=pfb
3 |
4 | # Name of the lambda function. Should match the `tilegarden_function_name` Terraform variable.
5 | LAMBDA_FUNCTION_NAME=
6 |
7 | # Function config information
8 | ## REQUIRED ##
9 | LAMBDA_REGION=
10 |
11 | # Amount of time in seconds your lambdas will run before timing out.
12 | # Default is 3, so some override is necessary.
13 | LAMBDA_TIMEOUT=
14 |
15 | ## OPTIONAL ##
16 | # Memory in MB allocated to your lambda functions
17 | # More memory also brings more CPU and bandwidth. Default if not specified is 128.
18 | #LAMBDA_MEMORY=512
19 | # The following VPC (Virtual Private Cloud) settings should be used if you
20 | # need your lambdas to be able to connect to other AWS resources,
21 | # e.g. an RDS instance, and should match the subnets/security groups used
22 | # for those resources.
23 | # VPC Subnets that your lambdas should use (comma separated list)
24 | #LAMBDA_SUBNETS=subnet1,subnet2,subnet...N
25 | # VPC Security Groups that your lambdas should use (comma separated list)
26 | #LAMBDA_SECURITY_GROUPS=group1,group2,group...N
27 |
28 | # PFB-specific variables
29 | PFB_DB_DATABASE=
30 | PFB_DB_PASSWORD=
31 | PFB_DB_PORT=
32 | PFB_DB_USER=
33 | PFB_TILEGARDEN_CACHE_BUCKET=
34 |
--------------------------------------------------------------------------------
/src/analysis/connectivity/reachable_roads_high_stress_calc.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | -- :nb_max_trip_distance psql var must be set before running this script,
5 | -- e.g. psql -v nb_max_trip_distance=2680 -f reachable_roads_high_stress_calc.sql
6 | ----------------------------------------
7 | INSERT INTO generated.neighborhood_reachable_roads_high_stress (
8 | base_road,
9 | target_road,
10 | total_cost
11 | )
12 | SELECT r1.road_id,
13 | v2.road_id,
14 | sheds.agg_cost
15 | FROM neighborhood_ways r1,
16 | neighborhood_ways_net_vert v1,
17 | neighborhood_ways_net_vert v2,
18 | pgr_drivingDistance('
19 | SELECT link_id AS id,
20 | source_vert AS source,
21 | target_vert AS target,
22 | link_cost AS cost
23 | FROM neighborhood_ways_net_link',
24 | v1.vert_id,
25 | :nb_max_trip_distance,
26 | directed := true
27 | ) sheds
28 | WHERE r1.road_id % :thread_num = :thread_no
29 | AND
30 | EXISTS (
31 | SELECT 1
32 | FROM neighborhood_boundary AS b
33 | WHERE ST_Intersects(b.geom,r1.geom)
34 | )
35 | AND r1.road_id = v1.road_id
36 | AND v2.vert_id = sheds.node;
37 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/management/commands/run_analysis_job.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from pfb_analysis.models import AnalysisJob, Neighborhood
4 | from users.models import PFBUser
5 |
6 |
7 | class Command(BaseCommand):
8 | help = """ Create and run an AnalysisJob for the given neighborhood
9 |
10 | The neighborhood name must match an existing Neighborhood for the user's organization.
11 |
12 | """
13 |
14 | def add_arguments(self, parser):
15 | # Positional arguments
16 | parser.add_argument('neighborhood')
17 | parser.add_argument('--user', default=None, type=str)
18 |
19 | def handle(self, *args, **options):
20 | if options['user'] is not None:
21 | user = PFBUser.objects.get(email=options['user'])
22 | else:
23 | user = PFBUser.objects.get_root_user()
24 | neighborhood = Neighborhood.objects.get(name=options['neighborhood'],
25 | organization=user.organization)
26 | job = AnalysisJob.objects.create(neighborhood=neighborhood,
27 | created_by=user,
28 | modified_by=user)
29 | job.run()
30 | self.stdout.write('Started job {} for {}'.format(job.batch_job_id, neighborhood.name))
31 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/password-reset/request/password-reset-request.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
24 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/analysis/connectivity/reachable_roads_low_stress_calc.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | -- :nb_max_trip_distance psql var must be set before running this script,
5 | -- e.g. psql -v nb_max_trip_distance=2680 -f reachable_roads_low_stress_calc.sql
6 | ----------------------------------------
7 | INSERT INTO generated.neighborhood_reachable_roads_low_stress (
8 | base_road,
9 | target_road,
10 | total_cost
11 | )
12 | SELECT r1.road_id,
13 | v2.road_id,
14 | sheds.agg_cost
15 | FROM neighborhood_ways r1,
16 | neighborhood_ways_net_vert v1,
17 | neighborhood_ways_net_vert v2,
18 | pgr_drivingDistance('
19 | SELECT link_id AS id,
20 | source_vert AS source,
21 | target_vert AS target,
22 | link_cost AS cost
23 | FROM neighborhood_ways_net_link
24 | WHERE link_stress = 1',
25 | v1.vert_id,
26 | :nb_max_trip_distance,
27 | directed := true
28 | ) sheds
29 | WHERE r1.road_id % :thread_num = :thread_no
30 | AND
31 | EXISTS (
32 | SELECT 1
33 | FROM neighborhood_boundary AS b
34 | WHERE ST_Intersects(b.geom,r1.geom)
35 | )
36 | AND r1.road_id = v1.road_id
37 | AND v2.vert_id = sheds.node;
38 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/components/users.service.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | /**
5 | * @ngdoc service
6 | * @name pfb.components.User:User
7 | *
8 | * @description
9 | * Resource for user
10 | */
11 | /* @ngInject */
12 | function User($resource) {
13 |
14 | return $resource('/api/users/:uuid/', {
15 | uuid: '@uuid'
16 | }, {
17 | 'update': {
18 | method: 'PUT'
19 | },
20 | 'query': {
21 | method: 'GET',
22 | isArray: false
23 | }
24 | });
25 | }
26 |
27 | /**
28 | * @ngdoc service
29 | * @name pfb.components.UserRoles:UserRoles
30 | *
31 | * @description
32 | * Resource for user roles
33 | */
34 | function UserRoles() {
35 | var roles = ['Viewer', 'Administrator', 'Organization Administrator'];
36 | var roleFilters = {
37 | 'Viewer': 'VIEWER',
38 | 'Administrator': 'ADMIN',
39 | 'Organization Administrator': 'ORGADMIN'
40 | };
41 | var module = {
42 | roles: roles,
43 | roleFilters: roleFilters
44 | };
45 | return module;
46 | }
47 |
48 | angular.module('pfb.components')
49 | .factory('User', User)
50 | .factory('UserRoles', UserRoles);
51 | })();
52 |
--------------------------------------------------------------------------------
/src/django/pfb_analysis/migrations/0014_auto_20170412_1611.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.3 on 2017-04-12 16:11
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 | import pfb_analysis.models
7 |
8 |
9 | class Migration(migrations.Migration):
10 |
11 | dependencies = [
12 | ('pfb_analysis', '0013_auto_20170407_0106'),
13 | ]
14 |
15 | operations = [
16 | migrations.AddField(
17 | model_name='analysisjob',
18 | name='_analysis_job_name',
19 | field=models.CharField(default='', max_length=50),
20 | ),
21 | migrations.AddField(
22 | model_name='analysisjob',
23 | name='_tilemaker_job_name',
24 | field=models.CharField(default='', max_length=50),
25 | ),
26 | migrations.AddField(
27 | model_name='analysisjob',
28 | name='analysis_job_definition',
29 | field=models.CharField(default=pfb_analysis.models.generate_analysis_job_def, max_length=50),
30 | ),
31 | migrations.AddField(
32 | model_name='analysisjob',
33 | name='tilemaker_job_definition',
34 | # Formerly had 'default=pfb_analysis.models.generate_tilemaker_job_def', but that crashes
35 | field=models.CharField(default='', max_length=50),
36 | ),
37 | ]
38 |
--------------------------------------------------------------------------------
/prototype/app/assets/sass/base/_typography.scss:
--------------------------------------------------------------------------------
1 | @mixin heading-tags {
2 | h1, h2, h3, h4, h5, h6,
3 | .h1, .h2, .h3, .h4, .h5, .h6 {
4 | @content;
5 | }
6 | }
7 |
8 | @include heading-tags {
9 | margin-bottom: 1rem;
10 | line-height: 1.2;
11 | color: #000;
12 | font-weight: bold;
13 | letter-spacing: 1px;
14 | }
15 |
16 | h1, h2, h3,
17 | .h1, .h2, .h3 {
18 | margin-top: 2rem;
19 | margin-bottom: 3.5rem;
20 | }
21 |
22 | h4, h5, h6,
23 | .h4, .h5, .h6 {
24 | margin-top: 1.3rem;
25 | }
26 |
27 | h1, .h1 {
28 | font-size: 4rem;
29 | }
30 |
31 | h2, .h2 {
32 | font-size: 2.8rem;
33 | }
34 |
35 | h3, .h3 {
36 | font-size: 2.2rem;
37 | }
38 |
39 | h4, .h4 {
40 | font-size: 1.8rem;
41 | }
42 |
43 | h5, .h5 {
44 | font-size: 1.6rem;
45 | }
46 |
47 | h6, .h6 {
48 | font-size: 1.6rem;
49 | }
50 |
51 | p, .p {
52 | font-size: 1.6rem;
53 | font-weight: 400;
54 | line-height: 1.6;
55 | margin-top: 1rem;
56 | margin-bottom: 2.5rem;
57 | }
58 |
59 | .font-size-small {
60 | font-size: 1.4rem;
61 | }
62 |
63 | .text-uppercase {
64 | text-transform: uppercase;
65 | }
66 |
67 | .text-capitalize {
68 | text-transform: capitalize;
69 | }
70 |
71 | .text-lowercase {
72 | text-transform: lowercase;
73 | }
74 |
75 | .text-center {
76 | text-align: center;
77 | }
78 |
79 | .text-right {
80 | text-align: right;
81 | }
82 |
83 | .text-left {
84 | text-align: left;
85 | }
86 |
--------------------------------------------------------------------------------
/src/analysis/import/clip_osm.sql:
--------------------------------------------------------------------------------
1 | ----------------------------------------
2 | -- INPUTS
3 | -- location: neighborhood
4 | -- :nb_boundary_buffer psql var must be set before running this script,
5 | -- e.g. psql -v nb_boundary_buffer=1000 -f clip_osm.sql
6 | ----------------------------------------
7 |
8 |
9 | DELETE FROM neighborhood_ways AS ways
10 | USING neighborhood_boundary AS boundary
11 | WHERE NOT ST_DWithin(ways.geom, boundary.geom, :nb_boundary_buffer);
12 |
13 | DELETE FROM neighborhood_ways_intersections AS intersections
14 | USING neighborhood_boundary AS boundary
15 | WHERE NOT ST_DWithin(intersections.geom, boundary.geom, :nb_boundary_buffer);
16 |
17 | DELETE FROM neighborhood_osm_full_line AS lines
18 | USING neighborhood_boundary AS boundary
19 | WHERE NOT ST_DWithin(lines.way, boundary.geom, :nb_boundary_buffer);
20 |
21 | DELETE FROM neighborhood_osm_full_point AS points
22 | USING neighborhood_boundary AS boundary
23 | WHERE NOT ST_DWithin(points.way, boundary.geom, :nb_boundary_buffer);
24 |
25 | DELETE FROM neighborhood_osm_full_polygon AS polygons
26 | USING neighborhood_boundary AS boundary
27 | WHERE NOT ST_DWithin(polygons.way, boundary.geom, :nb_boundary_buffer);
28 |
29 | DELETE FROM neighborhood_osm_full_roads AS roads
30 | USING neighborhood_boundary AS boundary
31 | WHERE NOT ST_DWithin(roads.way, boundary.geom, :nb_boundary_buffer);
32 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/password-reset/reset/password-reset.controller.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc controller
3 | * @name pfb.password-reset.controller:PasswordResetController
4 | *
5 | * @description
6 | * Controller for password reset page
7 | *
8 | */
9 | (function() {
10 | 'use strict';
11 |
12 | /** @ngInject */
13 | function PasswordResetController($stateParams, $state, toastr, PasswordResetService) {
14 | var ctl = this;
15 |
16 | initialize();
17 |
18 | function initialize() {
19 | ctl.resetPassword = resetPassword;
20 | ctl.formSubmitted = false;
21 | }
22 |
23 | function resetPassword() {
24 | var reset = PasswordResetService.resetPassword(ctl.password, $stateParams.token);
25 | ctl.formSubmitted = true;
26 | reset.then(function() {
27 | toastr.info('Password reset succesfully, return to login to use new password');
28 | }).catch(function() {
29 | // TODO: Return more meaningful error messages based on response
30 | toastr.error('Unable to reset password with provided token and password.');
31 | $state.go('request-password-reset');
32 | });
33 | }
34 | }
35 |
36 | angular
37 | .module('pfb.passwordReset')
38 | .controller('PasswordResetController', PasswordResetController);
39 | })();
40 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/base/_typography.scss:
--------------------------------------------------------------------------------
1 | @mixin heading-tags {
2 | h1, h2, h3, h4, h5, h6,
3 | .h1, .h2, .h3, .h4, .h5, .h6 {
4 | @content;
5 | }
6 | }
7 |
8 | @include heading-tags {
9 | margin-bottom: 1rem;
10 | line-height: 1.2;
11 | color: #000;
12 | font-weight: bold;
13 | letter-spacing: 1px;
14 | }
15 |
16 | h1, h2, h3,
17 | .h1, .h2, .h3 {
18 | margin-top: 2rem;
19 | margin-bottom: 3.5rem;
20 | }
21 |
22 | h4, h5, h6,
23 | .h4, .h5, .h6 {
24 | margin-top: 1.3rem;
25 | }
26 |
27 | h1, .h1 {
28 | font-size: 4rem;
29 | }
30 |
31 | h2, .h2 {
32 | font-size: 2.8rem;
33 | }
34 |
35 | h3, .h3 {
36 | font-size: 2.2rem;
37 | }
38 |
39 | h4, .h4 {
40 | font-size: 1.8rem;
41 | }
42 |
43 | h5, .h5 {
44 | font-size: 1.6rem;
45 | }
46 |
47 | h6, .h6 {
48 | font-size: 1.6rem;
49 | }
50 |
51 | p, .p {
52 | font-size: 1.6rem;
53 | font-weight: 400;
54 | line-height: 1.6;
55 | margin-top: 1rem;
56 | margin-bottom: 2.5rem;
57 | }
58 |
59 | .font-size-small {
60 | font-size: 1.4rem;
61 | }
62 |
63 | .text-uppercase {
64 | text-transform: uppercase;
65 | }
66 |
67 | .text-capitalize {
68 | text-transform: capitalize;
69 | }
70 |
71 | .text-lowercase {
72 | text-transform: lowercase;
73 | }
74 |
75 | .text-center {
76 | text-align: center;
77 | }
78 |
79 | .text-right {
80 | text-align: right;
81 | }
82 |
83 | .text-left {
84 | text-align: left;
85 | }
86 |
--------------------------------------------------------------------------------
/src/analysis/import/mapconfig_highway.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/angularjs/src/styles/layout/_navbar.scss:
--------------------------------------------------------------------------------
1 | .navbar {
2 | @extend %clearfix;
3 | position: relative;
4 | padding: 0.5rem 1rem;
5 | background-color: $brand-navy;
6 | z-index: 11;
7 |
8 | .container {
9 | max-width: 100%;
10 | display: flex;
11 | flex-flow: row nowrap;
12 | justify-content: space-between;
13 | align-items: center;
14 |
15 | @include respond-to("sm-down") {
16 | flex-direction: column;
17 | }
18 | }
19 |
20 | nav {
21 | display: inline-block;
22 | vertical-align: middle;
23 |
24 | a {
25 | padding: 18px 20px;
26 | color: #fff;
27 | text-transform: uppercase;
28 |
29 | &:hover {
30 | color: $link-color;
31 | }
32 |
33 | &.active {
34 | color: $link-color;
35 | box-shadow: 0 2px 0 0 $link-color;
36 | }
37 | }
38 | }
39 | }
40 |
41 | .navbar-left {
42 | flex: none;
43 | }
44 |
45 | .navbar-right {
46 | flex: none;
47 | }
48 |
49 | .pfb-logo-small {
50 | width: auto;
51 | height: 4rem;
52 | }
53 |
54 | .brand {
55 | display: flex;
56 | flex-direction: row;
57 |
58 | @include respond-to("sm-down") {
59 | flex-direction: column;
60 | margin-top: 2.4rem;
61 | margin-bottom: 0.8rem;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/angularjs/src/app/analysis-jobs/detail/analysis-jobs-detail.controller.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ngdoc controller
3 | * @name pfb.analysis-jobs.detail.controller:AnalysisJobDetailController
4 | *
5 | * @description
6 | * Controller for showing details about an analysis job
7 | *
8 | */
9 | (function() {
10 | 'use strict';
11 |
12 | /** @ngInject */
13 | function AnalysisJobDetailController($stateParams, AnalysisJob) {
14 | var ctl = this;
15 |
16 | initialize();
17 |
18 | function initialize() {
19 | ctl.job = null;
20 | ctl.cancel = cancel;
21 | ctl.getAnalysisJob = getAnalysisJob;
22 |
23 | getAnalysisJob($stateParams.uuid);
24 | }
25 |
26 | function cancel(jobId) {
27 | AnalysisJob.cancel({uuid: jobId}).$promise.then(function() {
28 | getAnalysisJob(jobId);
29 | });
30 | }
31 |
32 | function getAnalysisJob(jobId) {
33 | AnalysisJob.get({uuid: jobId}).$promise.then(function(data) {
34 | ctl.job = data;
35 | });
36 | AnalysisJob.results({uuid: jobId}).$promise.then(function(data) {
37 | ctl.results = data;
38 | });
39 | }
40 | }
41 |
42 | angular
43 | .module('pfb.analysisJobs.detail')
44 | .controller('AnalysisJobDetailController', AnalysisJobDetailController);
45 | })();
46 |
--------------------------------------------------------------------------------
/src/analysis/scripts/utils.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function import_geometries_for_job() {
4 | if [ -n "${PFB_JOB_ID}" ];
5 | then
6 | /opt/pfb/django/manage.py import_results_shapefiles "${PFB_JOB_ID}"
7 | fi
8 | }
9 |
10 | function update_status() {
11 | # Usage:
12 | # update_status STATUS [step [message]]
13 | echo "Updating job status: $@"
14 | if [ -n "${PFB_JOB_ID}" ];
15 | then
16 | /opt/pfb/django/manage.py update_status "${PFB_JOB_ID}" "$@"
17 | fi
18 | }
19 |
20 | function update_overall_scores() {
21 | # Usage:
22 | # update_overall_scores OVERALL_SCORES_CSV
23 | if [ -n "${PFB_JOB_ID}" ];
24 | then
25 | /opt/pfb/django/manage.py load_overall_scores --skip-columns \
26 | human_explanation \
27 | "${PFB_JOB_ID}" "$@"
28 | fi
29 | }
30 |
31 | function update_residential_speed_limit() {
32 | # Usage:
33 | # update_residential_speed_limit RESIDENTIAL_SPEED_LIMIT_CSV
34 | if [ -n "${PFB_JOB_ID}" ];
35 | then
36 | /opt/pfb/django/manage.py load_residential_speed_limit "${PFB_JOB_ID}" "$@"
37 | fi
38 | }
39 |
40 | function set_job_attr() {
41 | # Usage:
42 | # update_job_attr ATTRIBUTE VALUE
43 | if [ -n "${PFB_JOB_ID}" ];
44 | then
45 | /opt/pfb/django/manage.py set_job_attr "${PFB_JOB_ID}" "$@"
46 | fi
47 | }
48 |
--------------------------------------------------------------------------------
/src/django/pfb_network_connectivity/models.py:
--------------------------------------------------------------------------------
1 | """
2 | Models related to analysis results.
3 | """
4 |
5 | from __future__ import unicode_literals
6 | import uuid
7 |
8 | from django.contrib.gis.db import models
9 |
10 |
11 | class PFBModel(models.Model):
12 | """Base class for most database models
13 | This base class includes attributes that will be common
14 | across multiple apps for this project.
15 | Attributes:
16 | uuid (str): unique identifier for object
17 | created_at (datetime.datetime): timestamp for object creation
18 | modified_at (datetime.datetime): timestamp for object edits
19 | created_by (users.PFBUser): user that created object
20 | modified_by (users.PFBUser): last user that modified object
21 | """
22 |
23 | uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
24 |
25 | created_at = models.DateTimeField(auto_now_add=True)
26 | modified_at = models.DateTimeField(auto_now=True)
27 |
28 | created_by = models.ForeignKey('users.PFBUser',
29 | related_name='%(app_label)s_%(class)s_related+',
30 | on_delete=models.PROTECT)
31 | modified_by = models.ForeignKey('users.PFBUser',
32 | related_name='%(app_label)s_%(class)s_related+',
33 | on_delete=models.PROTECT)
34 |
35 | class Meta:
36 | abstract = True
37 |
--------------------------------------------------------------------------------
/deployment/terraform/alarms.tf:
--------------------------------------------------------------------------------
1 | # set up SNS topic for monitoring
2 | resource "aws_sns_topic" "global" {
3 | name = "topic${var.environment}GlobalNotifications"
4 | }
5 |
6 | #
7 | # ECS Alarms
8 | #
9 |
10 | resource "aws_cloudwatch_metric_alarm" "ecs_cpu_util" {
11 | alarm_name = "alarm${var.environment}ECSCPUUtilization"
12 | alarm_description = "App Container service CPU utilization"
13 | comparison_operator = "GreaterThanThreshold"
14 | evaluation_periods = "2"
15 | metric_name = "CPUUtilization"
16 | namespace = "AWS/ECS"
17 | period = "60"
18 | statistic = "Average"
19 | threshold = "75"
20 |
21 | dimensions = {
22 | ClusterName = aws_ecs_cluster.app_container_instance.name
23 | }
24 |
25 | alarm_actions = [aws_sns_topic.global.arn]
26 | }
27 |
28 | resource "aws_cloudwatch_metric_alarm" "ecs_memory_util" {
29 | alarm_name = "alarm${var.environment}ECSMemoryUtilization"
30 | alarm_description = "App Container service memory utilization"
31 | comparison_operator = "GreaterThanThreshold"
32 | evaluation_periods = "2"
33 | metric_name = "MemoryUtilization"
34 | namespace = "AWS/ECS"
35 | period = "60"
36 | statistic = "Average"
37 | threshold = "80"
38 |
39 | dimensions = {
40 | ClusterName = aws_ecs_cluster.app_container_instance.name
41 | }
42 |
43 | alarm_actions = [aws_sns_topic.global.arn]
44 | }
45 |
46 |
--------------------------------------------------------------------------------