From a908b6f1fe1369e98a7f5b602ed8e4d8c8cfea48 Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Sat, 11 Dec 2021 23:06:08 -0800 Subject: [PATCH 01/16] WIP: add create person mutation. --- .../schema/mutation/create_person_test.exs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 test/zero_phoenix_web/schema/mutation/create_person_test.exs diff --git a/test/zero_phoenix_web/schema/mutation/create_person_test.exs b/test/zero_phoenix_web/schema/mutation/create_person_test.exs new file mode 100644 index 0000000..d7e5091 --- /dev/null +++ b/test/zero_phoenix_web/schema/mutation/create_person_test.exs @@ -0,0 +1,51 @@ +defmodule ZeroPhoenixWeb.Schema.Query.CreatePersonTest do + use ZeroPhoenixWeb.ConnCase, async: true + + import Ecto.Query, only: [first: 1] + + alias ZeroPhoenix.Account.Person + alias ZeroPhoenix.Repo + + setup do + ZeroPhoenix.Seeds.run() + end + + test "create person" do + query = """ + mutation CreatePerson($person: Person!) { + createPerson(person: $person) { + firstName + lastName + email + userName + } + } + """ + + variables = %{ + "firstName" => "Jane", + "lastName" => "Doe", + "email" => "jane@example.com", + "username" => "janed" + } + + response = + post( + build_conn(), + "/graphql", + query: query, + variables: variables + ) + + assert json_response(response, 200) == %{ + "data" => %{ + "createPerson" => %{ + "firstName" => "Jane", + "lastName" => "Doe", + "email" => "jane@example.com", + "username" => "janed" + } + } + } + end +end From 989f9f3c15b6a79644f46904d481eee1054a3a5a Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Sat, 11 Dec 2021 23:09:53 -0800 Subject: [PATCH 02/16] Code cleanup. --- .iex.exs | 0 ACTIONS.md | 24 ++++ APOLLO.md | 3 + Dockerfile.sample | 131 ++++++++++++++++++ PRODUCTION-DEPLOYMENT.md | 7 + README-CURL-EXAMPLE.md | 6 + docker-compose.debug.yml | 10 ++ docker-compose.yml.sample | 60 ++++++++ schema.graphql | 29 ++++ .../schema/mutation/create_person_test.exs | 10 +- 10 files changed, 275 insertions(+), 5 deletions(-) create mode 100644 .iex.exs create mode 100644 ACTIONS.md create mode 100644 APOLLO.md create mode 100644 Dockerfile.sample create mode 100644 PRODUCTION-DEPLOYMENT.md create mode 100644 README-CURL-EXAMPLE.md create mode 100644 docker-compose.debug.yml create mode 100644 docker-compose.yml.sample create mode 100644 schema.graphql diff --git a/.iex.exs b/.iex.exs new file mode 100644 index 0000000..e69de29 diff --git a/ACTIONS.md b/ACTIONS.md new file mode 100644 index 0000000..6b902bd --- /dev/null +++ b/ACTIONS.md @@ -0,0 +1,24 @@ +# Let's set up GitHub Actions on our Phoenix app (with Jonathan Clem) + +https://changelog.com/podcast/331 +https://github.com/thechangelog/changelog.com + +## Actions + +https://docs.github.com/en/actions +https://github.com/actions/checkout +https://github.com/actions/cache +https://github.com/actions/github-script + +## Github Community + +https://github.community + +## Twitter Contact + +https://twitter.com/_clem +https://twitter.com/jerodsanto + +## References + +- https://www.youtube.com/watch?v=tiXMPCfZfag diff --git a/APOLLO.md b/APOLLO.md new file mode 100644 index 0000000..ddf6b80 --- /dev/null +++ b/APOLLO.md @@ -0,0 +1,3 @@ +APOLLO_KEY=service:Zero-Phoenix:RLA67gv0rVOE7cyq-H0zxA +APOLLO_GRAPH_VARIANT=current +APOLLO_SCHEMA_REPORTING=true diff --git a/Dockerfile.sample b/Dockerfile.sample new file mode 100644 index 0000000..495679b --- /dev/null +++ b/Dockerfile.sample @@ -0,0 +1,131 @@ +## +## Base +## + +FROM ruby:3.0.2-alpine3.14 as base + +# labels from https://github.com/opencontainers/image-spec/blob/master/annotations.md +LABEL org.opencontainers.image.authors=conradwt@gmail.com +LABEL org.opencontainers.image.created=$CREATED_DATE +LABEL org.opencontainers.image.revision=$SOURCE_COMMIT +LABEL org.opencontainers.image.title="Zero To GraphQL Using Rails" +LABEL org.opencontainers.image.url=https://hub.docker.com/u/conradwt/zero-rails +LABEL org.opencontainers.image.source=https://github.com/conradwt/zero-to-graphql-using-rails +LABEL org.opencontainers.image.licenses=MIT +LABEL com.conradtaylor.ruby_version=$RUBY_VERSION + +# set this with shell variables at build-time. +# If they aren't set, then not-set will be default. +ARG CREATED_DATE=not-set +ARG SOURCE_COMMIT=not-set + +# environment variables +ENV APP_PATH /app +ENV BUNDLE_PATH /usr/local/bundle/gems +ENV TMP_PATH /tmp/ +ENV RAILS_LOG_TO_STDOUT true +ENV RAILS_PORT 3000 + +# create application user. +RUN addgroup --gid 1000 darnoc \ + && adduser --uid 1000 --ingroup darnoc --shell /bin/bash --home darnoc + +# copy entrypoint scripts and grant execution permissions +# COPY ./dev-docker-entrypoint.sh /usr/local/bin/dev-entrypoint.sh +# COPY ./test-docker-entrypoint.sh /usr/local/bin/test-entrypoint.sh +# RUN chmod +x /usr/local/bin/dev-entrypoint.sh && chmod +x /usr/local/bin/test-entrypoint.sh + +# +# https://pkgs.alpinelinux.org/packages?name=&branch=v3.13 +# + +# install build and runtime dependencies +RUN apk -U add --no-cache \ + build-base=0.5-r2 \ + bzip2=1.0.8-r1 \ + ca-certificates=20191127-r5 \ + curl=7.78.0-r0 \ + fontconfig=2.13.1-r4 \ + postgresql-dev=13.4-r0 \ + tini=0.19.0-r0 \ + tzdata=2021a-r0 && \ + rm -rf /var/cache/apk/* && \ + mkdir -p $APP_PATH + +ENV RAILS_ENV=production + +EXPOSE ${RAILS_PORT} +ENV PORT ${RAILS_PORT} + +WORKDIR ${APP_PATH} + +COPY Gemfile* ./ + +RUN gem install bundler && \ + rm -rf ${GEM_HOME}/cache/* +RUN bundle config set without 'development test' +RUN bundle check || bundle install --jobs 20 --retry 5 + +ENTRYPOINT ["/sbin/tini", "--"] + +# Why should this go into `base` instead of `prod` stage? +# CMD ["rails", "server", "-b", "0.0.0.0", "-e", "production"] + +## +## Development +## + +FROM base as dev + +ENV RAILS_ENV=development + +# RUN bundle config list +RUN bundle config --delete without +RUN bundle config --delete with +RUN bundle check || bundle install --jobs 20 --retry 5 + +# uninstall our build dependencies +# RUN apk del build-dependencies + +# Add a script to be executed every time the container starts. +# COPY entrypoint.sh /usr/bin/ +# RUN chmod +x /usr/bin/entrypoint.sh +# ENTRYPOINT ["entrypoint.sh"] + +USER darnoc + +CMD ["rails", "server", "-b", "0.0.0.0"] + +## +## Test +## + +FROM dev as test + +COPY . . + +RUN bundle exec rspec + +## +## Pre-Production +## + +FROM test as pre-prod + +USER root + +RUN rm -rf ./spec + +## +## Production +## + +FROM base as prod + +COPY --from=pre-prod /app /app + +HEALTHCHECK CMD curl http://127.0.0.1/ || exit 1 + +USER darnoc + +CMD ["rails", "server", "-b", "0.0.0.0", "-e", "production"] diff --git a/PRODUCTION-DEPLOYMENT.md b/PRODUCTION-DEPLOYMENT.md new file mode 100644 index 0000000..c2bb641 --- /dev/null +++ b/PRODUCTION-DEPLOYMENT.md @@ -0,0 +1,7 @@ +# Production Deployment + +## References + +- https://hexdocs.pm/phoenix/releases.html#runtime-configuration + +- https://hexdocs.pm/phoenix/releases.html#containers diff --git a/README-CURL-EXAMPLE.md b/README-CURL-EXAMPLE.md new file mode 100644 index 0000000..674dfd7 --- /dev/null +++ b/README-CURL-EXAMPLE.md @@ -0,0 +1,6 @@ +curl \ + -i \ + --request POST \ + --url http://localhost:4000/graphql \ + -H "Content-Type: application/json" \ + --data '{"query":"query ExampleQuery($personId: ID!) {\n person(id: $personId) {\n email\n }\n}","variables":"{\n \"personId\": \"1\"\n}"}' diff --git a/docker-compose.debug.yml b/docker-compose.debug.yml new file mode 100644 index 0000000..b475b10 --- /dev/null +++ b/docker-compose.debug.yml @@ -0,0 +1,10 @@ +version: '2.1' + +services: + zero-to-graphql-using-phoenix: + image: zero-to-graphql-using-phoenix + build: + context: . + dockerfile: Dockerfile + ports: + - 4000:4000 \ No newline at end of file diff --git a/docker-compose.yml.sample b/docker-compose.yml.sample new file mode 100644 index 0000000..1ab7779 --- /dev/null +++ b/docker-compose.yml.sample @@ -0,0 +1,60 @@ +# https://docs.docker.com/compose/rails/ + +services: + app: + build: + context: . + dockerfile: Dockerfile + target: dev + + container_name: zero_rails + + command: ['rails', 'server', '-p', '3000', '-b', '0.0.0.0'] + + environment: + - RAILS_ENV=development + + ports: + - 3000:3000 + + stdin_open: true + + tty: true + + env_file: .env.development + + entrypoint: dev-entrypoint.sh + + volumes: + - .:/app + - shared_data:/var/shared + - gem_cache:/usr/local/bundle/gems + + depends_on: + db: + condition: service_healthy + + db: + image: postgres:13.2-alpine + + hostname: localhost + + volumes: + - db_data:/var/lib/postgresql/data + - shared_data:/var/shared + + environment: + - POSTGRES_HOST_AUTH_METHOD=trust + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=password + + ports: + - 5432:5432 + + healthcheck: + test: pg_isready -U postgres -h 127.0.0.1 + +volumes: + db_data: {} + gem_cache: {} + shared_data: {} diff --git a/schema.graphql b/schema.graphql new file mode 100644 index 0000000..9ee783e --- /dev/null +++ b/schema.graphql @@ -0,0 +1,29 @@ +"Represents a schema" +schema { + query: RootQueryType +} + +"a person" +type Person { + "unique identifier for the person" + id: String! + + "first name of a person" + firstName: String! + + "last name of a person" + lastName: String! + + "username of a person" + username: String! + + "email of a person" + email: String! + + "a list of friends for our person" + friends: [Person] +} + +type RootQueryType { + person(id: ID!): Person +} diff --git a/test/zero_phoenix_web/schema/mutation/create_person_test.exs b/test/zero_phoenix_web/schema/mutation/create_person_test.exs index d7e5091..86be3ea 100644 --- a/test/zero_phoenix_web/schema/mutation/create_person_test.exs +++ b/test/zero_phoenix_web/schema/mutation/create_person_test.exs @@ -23,11 +23,11 @@ defmodule ZeroPhoenixWeb.Schema.Query.CreatePersonTest do """ variables = %{ - "firstName" => "Jane", - "lastName" => "Doe", - "email" => "jane@example.com", - "username" => "janed" - } + "firstName" => "Jane", + "lastName" => "Doe", + "email" => "jane@example.com", + "username" => "janed" + } response = post( From 96a5827d81ecc3d859c032dce6bfa9ef7dc2358b Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Sun, 12 Dec 2021 19:24:05 -0800 Subject: [PATCH 03/16] Cleanup docs. (#50) --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e166866..b98a01d 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,11 @@ Note: This tutorial was updated on macOS 11.6.1. 1. create the project ```zsh - mix phx.new zero-to-graphql-using-elixir --app zero_phoenix --module ZeroPhoenix + mix phx.new zero-to-graphql-using-elixir \ + --app zero_phoenix \ + --module ZeroPhoenix \ + --no-html \ + --no-assets ``` Note: Just answer 'y' to all the prompts that appear. From da63e1d85e34ebd7e2cf57148bf0dba9b0ac71ce Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Mon, 13 Dec 2021 21:35:34 -0800 Subject: [PATCH 04/16] Remove esbuild. (#51) * remove esbuild. * Fix scope. --- .gitignore | 5 - README.md | 9 +- assets/css/app.css | 89 - assets/css/phoenix.css | 101 -- assets/js/app.js | 44 - assets/vendor/topbar.js | 157 -- config/config.exs | 14 +- config/dev.exs | 18 +- config/prod.exs | 4 +- config/runtime.exs | 21 +- config/test.exs | 2 +- lib/zero_phoenix/repo.ex | 14 +- lib/zero_phoenix_web/.DS_Store | Bin 6148 -> 6148 bytes lib/zero_phoenix_web/channels/user_socket.ex | 33 - .../controllers/fallback_controller.ex | 20 - .../controllers/page_controller.ex | 7 - lib/zero_phoenix_web/endpoint.ex | 4 +- lib/zero_phoenix_web/router.ex | 23 +- lib/zero_phoenix_web/telemetry.ex | 30 +- .../templates/layout/app.html.heex | 5 - .../templates/layout/live.html.heex | 11 - .../templates/layout/root.html.heex | 30 - .../templates/page/index.html.heex | 41 - lib/zero_phoenix_web/views/changeset_view.ex | 19 - lib/zero_phoenix_web/views/error_helpers.ex | 37 +- lib/zero_phoenix_web/views/error_view.ex | 8 +- lib/zero_phoenix_web/views/layout_view.ex | 7 - lib/zero_phoenix_web/views/page_view.ex | 3 - lib/zero_phoenix_web/views/person_view.ex | 20 - mix.exs | 12 +- mix.lock | 2 +- priv/static/css/app.css | 77 - priv/static/favicon.ico | Bin 1258 -> 0 bytes priv/static/images/phoenix.png | Bin 13900 -> 0 bytes priv/static/js/app.js | 3 - priv/static/js/phoenix.js | 1431 ----------------- priv/static/robots.txt | 5 - .../controllers/page_controller_test.exs | 8 - .../controllers/person_controller_test.exs | 43 - 39 files changed, 93 insertions(+), 2264 deletions(-) delete mode 100644 assets/css/app.css delete mode 100644 assets/css/phoenix.css delete mode 100644 assets/js/app.js delete mode 100644 assets/vendor/topbar.js delete mode 100644 lib/zero_phoenix_web/channels/user_socket.ex delete mode 100644 lib/zero_phoenix_web/controllers/fallback_controller.ex delete mode 100644 lib/zero_phoenix_web/controllers/page_controller.ex delete mode 100644 lib/zero_phoenix_web/templates/layout/app.html.heex delete mode 100644 lib/zero_phoenix_web/templates/layout/live.html.heex delete mode 100644 lib/zero_phoenix_web/templates/layout/root.html.heex delete mode 100644 lib/zero_phoenix_web/templates/page/index.html.heex delete mode 100644 lib/zero_phoenix_web/views/changeset_view.ex delete mode 100644 lib/zero_phoenix_web/views/layout_view.ex delete mode 100644 lib/zero_phoenix_web/views/page_view.ex delete mode 100644 lib/zero_phoenix_web/views/person_view.ex delete mode 100644 priv/static/css/app.css delete mode 100644 priv/static/favicon.ico delete mode 100644 priv/static/images/phoenix.png delete mode 100644 priv/static/js/app.js delete mode 100644 priv/static/js/phoenix.js delete mode 100644 priv/static/robots.txt delete mode 100644 test/zero_phoenix_web/controllers/page_controller_test.exs delete mode 100644 test/zero_phoenix_web/controllers/person_controller_test.exs diff --git a/.gitignore b/.gitignore index 0e23efd..3181cf1 100644 --- a/.gitignore +++ b/.gitignore @@ -22,11 +22,6 @@ erl_crash.dump # Ignore package tarball (built via "mix hex.build"). zero_phoenix-*.tar -# Since we are building assets from assets/, -# we ignore priv/static. You may want to comment -# this depending on your deployment strategy. -/priv/static/ - # Exclude VSCode artifacts .metals/ .vscode/ diff --git a/README.md b/README.md index b98a01d..ae63c89 100644 --- a/README.md +++ b/README.md @@ -380,16 +380,11 @@ Note: This tutorial was updated on macOS 11.6.1. ```elixir defp deps do [ - {:phoenix, "~> 1.6.2"}, + {:phoenix, "~> 1.6.4"}, {:phoenix_ecto, "~> 4.4"}, {:ecto_sql, "~> 3.7.1"}, {:postgrex, "~> 0.15.9"}, - {:phoenix_html, "~> 3.0"}, - {:phoenix_live_reload, "~> 1.3.3", only: :dev}, - {:phoenix_live_view, "~> 0.17.5"}, - {:floki, ">= 0.30.0", only: :test}, - {:phoenix_live_dashboard, "~> 0.5"}, - {:esbuild, "~> 0.2", runtime: Mix.env() == :dev}, + {:phoenix_live_dashboard, "~> 0.6"}, {:swoosh, "~> 1.3"}, {:telemetry_metrics, "~> 0.6.0"}, {:telemetry_poller, "~> 1.0"}, diff --git a/assets/css/app.css b/assets/css/app.css deleted file mode 100644 index 24920cf..0000000 --- a/assets/css/app.css +++ /dev/null @@ -1,89 +0,0 @@ -/* This file is for your main application CSS */ -@import "./phoenix.css"; - -/* Alerts and form errors used by phx.new */ -.alert { - padding: 15px; - margin-bottom: 20px; - border: 1px solid transparent; - border-radius: 4px; -} -.alert-info { - color: #31708f; - background-color: #d9edf7; - border-color: #bce8f1; -} -.alert-warning { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc; -} -.alert-danger { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1; -} -.alert p { - margin-bottom: 0; -} -.alert:empty { - display: none; -} -.invalid-feedback { - color: #a94442; - display: block; - margin: -1rem 0 2rem; -} - -/* LiveView specific classes for your customization */ -.phx-no-feedback.invalid-feedback, -.phx-no-feedback .invalid-feedback { - display: none; -} - -.phx-click-loading { - opacity: 0.5; - transition: opacity 1s ease-out; -} - -.phx-disconnected{ - cursor: wait; -} -.phx-disconnected *{ - pointer-events: none; -} - -.phx-modal { - opacity: 1!important; - position: fixed; - z-index: 1; - left: 0; - top: 0; - width: 100%; - height: 100%; - overflow: auto; - background-color: rgb(0,0,0); - background-color: rgba(0,0,0,0.4); -} - -.phx-modal-content { - background-color: #fefefe; - margin: 15vh auto; - padding: 20px; - border: 1px solid #888; - width: 80%; -} - -.phx-modal-close { - color: #aaa; - float: right; - font-size: 28px; - font-weight: bold; -} - -.phx-modal-close:hover, -.phx-modal-close:focus { - color: black; - text-decoration: none; - cursor: pointer; -} diff --git a/assets/css/phoenix.css b/assets/css/phoenix.css deleted file mode 100644 index 0d59050..0000000 --- a/assets/css/phoenix.css +++ /dev/null @@ -1,101 +0,0 @@ -/* Includes some default style for the starter application. - * This can be safely deleted to start fresh. - */ - -/* Milligram v1.4.1 https://milligram.github.io - * Copyright (c) 2020 CJ Patoilo Licensed under the MIT license - */ - -*,*:after,*:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#000000;font-family:'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;font-size:1.6em;font-weight:300;letter-spacing:.01em;line-height:1.6}blockquote{border-left:0.3rem solid #d1d1d1;margin-left:0;margin-right:0;padding:1rem 1.5rem}blockquote *:last-child{margin-bottom:0}.button,button,input[type='button'],input[type='reset'],input[type='submit']{background-color:#0069d9;border:0.1rem solid #0069d9;border-radius:.4rem;color:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-spacing:.1rem;line-height:3.8rem;padding:0 3.0rem;text-align:center;text-decoration:none;text-transform:uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type='button']:focus,input[type='button']:hover,input[type='reset']:focus,input[type='reset']:hover,input[type='submit']:focus,input[type='submit']:hover{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}.button[disabled],button[disabled],input[type='button'][disabled],input[type='reset'][disabled],input[type='submit'][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button[disabled]:focus,button[disabled]:hover,input[type='button'][disabled]:focus,input[type='button'][disabled]:hover,input[type='reset'][disabled]:focus,input[type='reset'][disabled]:hover,input[type='submit'][disabled]:focus,input[type='submit'][disabled]:hover{background-color:#0069d9;border-color:#0069d9}.button.button-outline,button.button-outline,input[type='button'].button-outline,input[type='reset'].button-outline,input[type='submit'].button-outline{background-color:transparent;color:#0069d9}.button.button-outline:focus,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type='button'].button-outline:focus,input[type='button'].button-outline:hover,input[type='reset'].button-outline:focus,input[type='reset'].button-outline:hover,input[type='submit'].button-outline:focus,input[type='submit'].button-outline:hover{background-color:transparent;border-color:#606c76;color:#606c76}.button.button-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,button.button-outline[disabled]:hover,input[type='button'].button-outline[disabled]:focus,input[type='button'].button-outline[disabled]:hover,input[type='reset'].button-outline[disabled]:focus,input[type='reset'].button-outline[disabled]:hover,input[type='submit'].button-outline[disabled]:focus,input[type='submit'].button-outline[disabled]:hover{border-color:inherit;color:#0069d9}.button.button-clear,button.button-clear,input[type='button'].button-clear,input[type='reset'].button-clear,input[type='submit'].button-clear{background-color:transparent;border-color:transparent;color:#0069d9}.button.button-clear:focus,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type='button'].button-clear:focus,input[type='button'].button-clear:hover,input[type='reset'].button-clear:focus,input[type='reset'].button-clear:hover,input[type='submit'].button-clear:focus,input[type='submit'].button-clear:hover{background-color:transparent;border-color:transparent;color:#606c76}.button.button-clear[disabled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-clear[disabled]:hover,input[type='button'].button-clear[disabled]:focus,input[type='button'].button-clear[disabled]:hover,input[type='reset'].button-clear[disabled]:focus,input[type='reset'].button-clear[disabled]:hover,input[type='submit'].button-clear[disabled]:focus,input[type='submit'].button-clear[disabled]:hover{color:#0069d9}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:.2rem .5rem;white-space:nowrap}pre{background:#f4f5f6;border-left:0.3rem solid #0069d9;overflow-y:hidden}pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:0.1rem solid #f4f5f6;margin:3.0rem 0}input[type='color'],input[type='date'],input[type='datetime'],input[type='datetime-local'],input[type='email'],input[type='month'],input[type='number'],input[type='password'],input[type='search'],input[type='tel'],input[type='text'],input[type='url'],input[type='week'],input:not([type]),textarea,select{-webkit-appearance:none;background-color:transparent;border:0.1rem solid #d1d1d1;border-radius:.4rem;box-shadow:none;box-sizing:inherit;height:3.8rem;padding:.6rem 1.0rem .7rem;width:100%}input[type='color']:focus,input[type='date']:focus,input[type='datetime']:focus,input[type='datetime-local']:focus,input[type='email']:focus,input[type='month']:focus,input[type='number']:focus,input[type='password']:focus,input[type='search']:focus,input[type='tel']:focus,input[type='text']:focus,input[type='url']:focus,input[type='week']:focus,input:not([type]):focus,textarea:focus,select:focus{border-color:#0069d9;outline:0}select{background:url('data:image/svg+xml;utf8,') center right no-repeat;padding-right:3.0rem}select:focus{background-image:url('data:image/svg+xml;utf8,')}select[multiple]{background:none;height:auto}textarea{min-height:6.5rem}label,legend{display:block;font-size:1.6rem;font-weight:700;margin-bottom:.5rem}fieldset{border-width:0;padding:0}input[type='checkbox'],input[type='radio']{display:inline}.label-inline{display:inline-block;font-weight:normal;margin-left:.5rem}.container{margin:0 auto;max-width:112.0rem;padding:0 2.0rem;position:relative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-items:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretch{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1 auto;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column.column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-40{margin-left:40%}.row .column.column-offset-50{margin-left:50%}.row .column.column-offset-60{margin-left:60%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column.column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{flex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,.row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-width:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-width:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .column.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .column .column-bottom{align-self:flex-end}.row .column .column-center{align-self:center}@media (min-width: 40rem){.row{flex-direction:row;margin-left:-1.0rem;width:calc(100% + 2.0rem)}.row .column{margin-bottom:inherit;padding:0 1.0rem}}a{color:#0069d9;text-decoration:none}a:focus,a:hover{color:#606c76}dl,ol,ul{list-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font-size:90%;margin:1.5rem 0 1.5rem 3.0rem}ol{list-style:decimal inside}ul{list-style:circle inside}.button,button,dd,dt,li{margin-bottom:1.0rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote,dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}table{border-spacing:0;display:block;overflow-x:auto;text-align:left;width:100%}td,th{border-bottom:0.1rem solid #e1e1e1;padding:1.2rem 1.5rem}td:first-child,th:first-child{padding-left:0}td:last-child,th:last-child{padding-right:0}@media (min-width: 40rem){table{display:table;overflow-x:initial}}b,strong{font-weight:bold}p{margin-top:0}h1,h2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2.0rem;margin-top:0}h1{font-size:4.6rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right} - -/* General style */ -h1{font-size: 3.6rem; line-height: 1.25} -h2{font-size: 2.8rem; line-height: 1.3} -h3{font-size: 2.2rem; letter-spacing: -.08rem; line-height: 1.35} -h4{font-size: 1.8rem; letter-spacing: -.05rem; line-height: 1.5} -h5{font-size: 1.6rem; letter-spacing: 0; line-height: 1.4} -h6{font-size: 1.4rem; letter-spacing: 0; line-height: 1.2} -pre{padding: 1em;} - -.container{ - margin: 0 auto; - max-width: 80.0rem; - padding: 0 2.0rem; - position: relative; - width: 100% -} -select { - width: auto; -} - -/* Phoenix promo and logo */ -.phx-hero { - text-align: center; - border-bottom: 1px solid #e3e3e3; - background: #eee; - border-radius: 6px; - padding: 3em 3em 1em; - margin-bottom: 3rem; - font-weight: 200; - font-size: 120%; -} -.phx-hero input { - background: #ffffff; -} -.phx-logo { - min-width: 300px; - margin: 1rem; - display: block; -} -.phx-logo img { - width: auto; - display: block; -} - -/* Headers */ -header { - width: 100%; - background: #fdfdfd; - border-bottom: 1px solid #eaeaea; - margin-bottom: 2rem; -} -header section { - align-items: center; - display: flex; - flex-direction: column; - justify-content: space-between; -} -header section :first-child { - order: 2; -} -header section :last-child { - order: 1; -} -header nav ul, -header nav li { - margin: 0; - padding: 0; - display: block; - text-align: right; - white-space: nowrap; -} -header nav ul { - margin: 1rem; - margin-top: 0; -} -header nav a { - display: block; -} - -@media (min-width: 40.0rem) { /* Small devices (landscape phones, 576px and up) */ - header section { - flex-direction: row; - } - header nav ul { - margin: 1rem; - } - .phx-logo { - flex-basis: 527px; - margin: 2rem 1rem; - } -} diff --git a/assets/js/app.js b/assets/js/app.js deleted file mode 100644 index 9eabcff..0000000 --- a/assets/js/app.js +++ /dev/null @@ -1,44 +0,0 @@ -// We import the CSS which is extracted to its own file by esbuild. -// Remove this line if you add a your own CSS build pipeline (e.g postcss). -import "../css/app.css" - -// If you want to use Phoenix channels, run `mix help phx.gen.channel` -// to get started and then uncomment the line below. -// import "./user_socket.js" - -// You can include dependencies in two ways. -// -// The simplest option is to put them in assets/vendor and -// import them using relative paths: -// -// import "./vendor/some-package.js" -// -// Alternatively, you can `npm install some-package` and import -// them using a path starting with the package name: -// -// import "some-package" -// - -// Include phoenix_html to handle method=PUT/DELETE in forms and buttons. -import "phoenix_html" -// Establish Phoenix Socket and LiveView configuration. -import {Socket} from "phoenix" -import {LiveSocket} from "phoenix_live_view" -import topbar from "../vendor/topbar" - -let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") -let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}}) - -// Show progress bar on live navigation and form submits -topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) -window.addEventListener("phx:page-loading-start", info => topbar.show()) -window.addEventListener("phx:page-loading-stop", info => topbar.hide()) - -// connect if there are any LiveViews on the page -liveSocket.connect() - -// expose liveSocket on window for web console debug logs and latency simulation: -// >> liveSocket.enableDebug() -// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session -// >> liveSocket.disableLatencySim() -window.liveSocket = liveSocket diff --git a/assets/vendor/topbar.js b/assets/vendor/topbar.js deleted file mode 100644 index ff7fbb6..0000000 --- a/assets/vendor/topbar.js +++ /dev/null @@ -1,157 +0,0 @@ -/** - * @license MIT - * topbar 1.0.0, 2021-01-06 - * http://buunguyen.github.io/topbar - * Copyright (c) 2021 Buu Nguyen - */ -(function (window, document) { - "use strict"; - - // https://gist.github.com/paulirish/1579671 - (function () { - var lastTime = 0; - var vendors = ["ms", "moz", "webkit", "o"]; - for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { - window.requestAnimationFrame = - window[vendors[x] + "RequestAnimationFrame"]; - window.cancelAnimationFrame = - window[vendors[x] + "CancelAnimationFrame"] || - window[vendors[x] + "CancelRequestAnimationFrame"]; - } - if (!window.requestAnimationFrame) - window.requestAnimationFrame = function (callback, element) { - var currTime = new Date().getTime(); - var timeToCall = Math.max(0, 16 - (currTime - lastTime)); - var id = window.setTimeout(function () { - callback(currTime + timeToCall); - }, timeToCall); - lastTime = currTime + timeToCall; - return id; - }; - if (!window.cancelAnimationFrame) - window.cancelAnimationFrame = function (id) { - clearTimeout(id); - }; - })(); - - var canvas, - progressTimerId, - fadeTimerId, - currentProgress, - showing, - addEvent = function (elem, type, handler) { - if (elem.addEventListener) elem.addEventListener(type, handler, false); - else if (elem.attachEvent) elem.attachEvent("on" + type, handler); - else elem["on" + type] = handler; - }, - options = { - autoRun: true, - barThickness: 3, - barColors: { - 0: "rgba(26, 188, 156, .9)", - ".25": "rgba(52, 152, 219, .9)", - ".50": "rgba(241, 196, 15, .9)", - ".75": "rgba(230, 126, 34, .9)", - "1.0": "rgba(211, 84, 0, .9)", - }, - shadowBlur: 10, - shadowColor: "rgba(0, 0, 0, .6)", - className: null, - }, - repaint = function () { - canvas.width = window.innerWidth; - canvas.height = options.barThickness * 5; // need space for shadow - - var ctx = canvas.getContext("2d"); - ctx.shadowBlur = options.shadowBlur; - ctx.shadowColor = options.shadowColor; - - var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0); - for (var stop in options.barColors) - lineGradient.addColorStop(stop, options.barColors[stop]); - ctx.lineWidth = options.barThickness; - ctx.beginPath(); - ctx.moveTo(0, options.barThickness / 2); - ctx.lineTo( - Math.ceil(currentProgress * canvas.width), - options.barThickness / 2 - ); - ctx.strokeStyle = lineGradient; - ctx.stroke(); - }, - createCanvas = function () { - canvas = document.createElement("canvas"); - var style = canvas.style; - style.position = "fixed"; - style.top = style.left = style.right = style.margin = style.padding = 0; - style.zIndex = 100001; - style.display = "none"; - if (options.className) canvas.classList.add(options.className); - document.body.appendChild(canvas); - addEvent(window, "resize", repaint); - }, - topbar = { - config: function (opts) { - for (var key in opts) - if (options.hasOwnProperty(key)) options[key] = opts[key]; - }, - show: function () { - if (showing) return; - showing = true; - if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId); - if (!canvas) createCanvas(); - canvas.style.opacity = 1; - canvas.style.display = "block"; - topbar.progress(0); - if (options.autoRun) { - (function loop() { - progressTimerId = window.requestAnimationFrame(loop); - topbar.progress( - "+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2) - ); - })(); - } - }, - progress: function (to) { - if (typeof to === "undefined") return currentProgress; - if (typeof to === "string") { - to = - (to.indexOf("+") >= 0 || to.indexOf("-") >= 0 - ? currentProgress - : 0) + parseFloat(to); - } - currentProgress = to > 1 ? 1 : to; - repaint(); - return currentProgress; - }, - hide: function () { - if (!showing) return; - showing = false; - if (progressTimerId != null) { - window.cancelAnimationFrame(progressTimerId); - progressTimerId = null; - } - (function loop() { - if (topbar.progress("+.1") >= 1) { - canvas.style.opacity -= 0.05; - if (canvas.style.opacity <= 0.05) { - canvas.style.display = "none"; - fadeTimerId = null; - return; - } - } - fadeTimerId = window.requestAnimationFrame(loop); - })(); - }, - }; - - if (typeof module === "object" && typeof module.exports === "object") { - module.exports = topbar; - } else if (typeof define === "function" && define.amd) { - define(function () { - return topbar; - }); - } else { - this.topbar = topbar; - } -}.call(this, window, document)); diff --git a/config/config.exs b/config/config.exs index 6a9838f..06ac63d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -13,9 +13,9 @@ config :zero_phoenix, # Configures the endpoint config :zero_phoenix, ZeroPhoenixWeb.Endpoint, url: [host: "localhost"], - render_errors: [view: ZeroPhoenixWeb.ErrorView, accepts: ~w(html json), layout: false], + render_errors: [view: ZeroPhoenixWeb.ErrorView, accepts: ~w(json), layout: false], pubsub_server: ZeroPhoenix.PubSub, - live_view: [signing_salt: "mBXKCKoH"] + live_view: [signing_salt: "o9i216Dv"] # Configures the mailer # @@ -29,16 +29,6 @@ config :zero_phoenix, ZeroPhoenix.Mailer, adapter: Swoosh.Adapters.Local # Swoosh API client is needed for adapters other than SMTP. config :swoosh, :api_client, false -# Configure esbuild (the version is required) -config :esbuild, - version: "0.12.18", - default: [ - args: - ~w(js/app.js --bundle --target=es2016 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*), - cd: Path.expand("../assets", __DIR__), - env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} - ] - # Configures Elixir's Logger config :logger, :console, format: "$time $metadata[$level] $message\n", diff --git a/config/dev.exs b/config/dev.exs index ecd4b44..7d4ff41 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -22,11 +22,8 @@ config :zero_phoenix, ZeroPhoenixWeb.Endpoint, check_origin: false, code_reloader: true, debug_errors: true, - secret_key_base: "gVs0DBoIXNmzV+8/InJrlCXp6mUqNtfcoxPlSuvFkZwHK+GGqpmFoMk/XyuSe+RV", - watchers: [ - # Start the esbuild watcher by calling Esbuild.install_and_run(:default, args) - esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]} - ] + secret_key_base: "QaZRP5dUmYwCW5wZnPwlIsO+nJe0ZnXAmJmaDcBM4sQ0OAhk2K6phBprknZQr61P", + watchers: [] # ## SSL Support # @@ -52,17 +49,6 @@ config :zero_phoenix, ZeroPhoenixWeb.Endpoint, # configured to run both http and https servers on # different ports. -# Watch static and templates for browser reloading. -config :zero_phoenix, ZeroPhoenixWeb.Endpoint, - live_reload: [ - patterns: [ - ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$", - ~r"priv/gettext/.*(po)$", - ~r"lib/zero_phoenix_web/(live|views)/.*(ex)$", - ~r"lib/zero_phoenix_web/templates/.*(eex)$" - ] - ] - # Do not include metadata nor timestamps in development logs config :logger, :console, format: "[$level] $message\n" diff --git a/config/prod.exs b/config/prod.exs index e3e70f3..afe5360 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -9,9 +9,7 @@ import Config # manifest is generated by the `mix phx.digest` task, # which you should run after static files are built and # before starting your production server. -config :zero_phoenix, ZeroPhoenixWeb.Endpoint, - url: [host: "example.com", port: 80], - cache_static_manifest: "priv/static/cache_manifest.json" +config :zero_phoenix, ZeroPhoenixWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json" # Do not print debug messages in production config :logger, level: :info diff --git a/config/runtime.exs b/config/runtime.exs index 7aa0ae5..f9c86f7 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -6,6 +6,12 @@ import Config # and secrets from environment variables or elsewhere. Do not define # any compile-time configuration in here, as it won't be applied. # The block below contains prod specific runtime configuration. + +# Start the phoenix server if environment is set and running in a release +if System.get_env("PHX_SERVER") && System.get_env("RELEASE_NAME") do + config :zero_phoenix, ZeroPhoenixWeb.Endpoint, server: true +end + if config_env() == :prod do database_url = System.get_env("DATABASE_URL") || @@ -14,11 +20,13 @@ if config_env() == :prod do For example: ecto://USER:PASS@HOST/DATABASE """ + maybe_ipv6 = if System.get_env("ECTO_IPV6"), do: [:inet6], else: [] + config :zero_phoenix, ZeroPhoenix.Repo, # ssl: true, - # socket_options: [:inet6], url: database_url, - pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10") + pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), + socket_options: maybe_ipv6 # The secret key base is used to sign/encrypt cookies and other secrets. # A default value is used in config/dev.exs and config/test.exs but you @@ -32,14 +40,18 @@ if config_env() == :prod do You can generate one by calling: mix phx.gen.secret """ + host = System.get_env("PHX_HOST") || "example.com" + port = String.to_integer(System.get_env("PORT") || "4000") + config :zero_phoenix, ZeroPhoenixWeb.Endpoint, + url: [host: host, port: 443], http: [ # Enable IPv6 and bind on all interfaces. # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access. # See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html # for details about using IPv6 vs IPv4 and loopback vs public addresses. ip: {0, 0, 0, 0, 0, 0, 0, 0}, - port: String.to_integer(System.get_env("PORT") || "4000") + port: port ], secret_key_base: secret_key_base @@ -48,8 +60,7 @@ if config_env() == :prod do # If you are doing OTP releases, you need to instruct Phoenix # to start each relevant endpoint: # - config :zero_phoenix, ZeroPhoenixWeb.Endpoint, server: true - + # config :zero_phoenix, ZeroPhoenixWeb.Endpoint, server: true # # Then you can assemble a release by calling `mix release`. # See `mix help release` for more information. diff --git a/config/test.exs b/config/test.exs index b6a35be..b36d49b 100644 --- a/config/test.exs +++ b/config/test.exs @@ -17,7 +17,7 @@ config :zero_phoenix, ZeroPhoenix.Repo, # you can enable the server option below. config :zero_phoenix, ZeroPhoenixWeb.Endpoint, http: [ip: {127, 0, 0, 1}, port: 4002], - secret_key_base: "OD4CXADDa3JXRJbltdliVJokWhGWmdhP8el84O9pTaqTZufuXgO3FkO7F25sRocG", + secret_key_base: "8ry+7zZ8q3QB18RmDZ5xP/oe8nprdfMp5ht1id/FocOspw/oi0EggAilESNuG5Y0", server: false # In test we don't send emails. diff --git a/lib/zero_phoenix/repo.ex b/lib/zero_phoenix/repo.ex index 4f0bfbc..68400be 100644 --- a/lib/zero_phoenix/repo.ex +++ b/lib/zero_phoenix/repo.ex @@ -3,11 +3,11 @@ defmodule ZeroPhoenix.Repo do otp_app: :zero_phoenix, adapter: Ecto.Adapters.Postgres - @doc """ - Dynamically loads the repository url from the - DATABASE_URL environment variable. - """ - def init(_, opts) do - {:ok, Keyword.put(opts, :url, System.get_env("DATABASE_URL"))} - end + # @doc """ + # Dynamically loads the repository url from the + # DATABASE_URL environment variable. + # """ + # def init(_, opts) do + # {:ok, Keyword.put(opts, :url, System.get_env("DATABASE_URL"))} + # end end diff --git a/lib/zero_phoenix_web/.DS_Store b/lib/zero_phoenix_web/.DS_Store index 0dccac6afe2445a27599fba4f08101835c0d7fb6..6d664cc3a5e9b11fd9275d56c06592163b310da2 100644 GIT binary patch delta 49 zcmZoMXfc@JFUrEez`)4BAi%&-#E{RB1B9szMVkdVmNPT5Y<6Tl#8c2$RA(E{hRJJLaU3;+NC diff --git a/lib/zero_phoenix_web/channels/user_socket.ex b/lib/zero_phoenix_web/channels/user_socket.ex deleted file mode 100644 index 2dd745f..0000000 --- a/lib/zero_phoenix_web/channels/user_socket.ex +++ /dev/null @@ -1,33 +0,0 @@ -defmodule ZeroPhoenixWeb.UserSocket do - use Phoenix.Socket - - ## Channels - # channel "room:*", ZeroPhoenixWeb.RoomChannel - - # Socket params are passed from the client and can - # be used to verify and authenticate a user. After - # verification, you can put default assigns into - # the socket that will be set for all channels, ie - # - # {:ok, assign(socket, :user_id, verified_user_id)} - # - # To deny connection, return `:error`. - # - # See `Phoenix.Token` documentation for examples in - # performing token verification on connect. - def connect(_params, socket, _connect_info) do - {:ok, socket} - end - - # Socket id's are topics that allow you to identify all sockets for a given user: - # - # def id(socket), do: "user_socket:#{socket.assigns.user_id}" - # - # Would allow you to broadcast a "disconnect" event and terminate - # all active sockets and channels for a given user: - # - # ZeroPhoenixWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{}) - # - # Returning `nil` makes this socket anonymous. - def id(_socket), do: nil -end diff --git a/lib/zero_phoenix_web/controllers/fallback_controller.ex b/lib/zero_phoenix_web/controllers/fallback_controller.ex deleted file mode 100644 index f8f4a06..0000000 --- a/lib/zero_phoenix_web/controllers/fallback_controller.ex +++ /dev/null @@ -1,20 +0,0 @@ -defmodule ZeroPhoenixWeb.FallbackController do - @moduledoc """ - Translates controller action results into valid `Plug.Conn` responses. - - See `Phoenix.Controller.action_fallback/1` for more details. - """ - use ZeroPhoenixWeb, :controller - - def call(conn, {:error, %Ecto.Changeset{} = changeset}) do - conn - |> put_status(:unprocessable_entity) - |> render(ZeroPhoenixWeb.ChangesetView, "error.json", changeset: changeset) - end - - def call(conn, {:error, :not_found}) do - conn - |> put_status(:not_found) - |> render(ZeroPhoenixWeb.ErrorView, :"404") - end -end diff --git a/lib/zero_phoenix_web/controllers/page_controller.ex b/lib/zero_phoenix_web/controllers/page_controller.ex deleted file mode 100644 index 9a861b5..0000000 --- a/lib/zero_phoenix_web/controllers/page_controller.ex +++ /dev/null @@ -1,7 +0,0 @@ -defmodule ZeroPhoenixWeb.PageController do - use ZeroPhoenixWeb, :controller - - def index(conn, _params) do - render conn, "index.html" - end -end diff --git a/lib/zero_phoenix_web/endpoint.ex b/lib/zero_phoenix_web/endpoint.ex index 38cfc05..5dcf303 100644 --- a/lib/zero_phoenix_web/endpoint.ex +++ b/lib/zero_phoenix_web/endpoint.ex @@ -7,7 +7,7 @@ defmodule ZeroPhoenixWeb.Endpoint do @session_options [ store: :cookie, key: "_zero_phoenix_key", - signing_salt: "pEK+TkWC" + signing_salt: "mxCsMSbf" ] socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]] @@ -25,8 +25,6 @@ defmodule ZeroPhoenixWeb.Endpoint do # Code reloading can be explicitly enabled under the # :code_reloader configuration of your endpoint. if code_reloading? do - socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket - plug Phoenix.LiveReloader plug Phoenix.CodeReloader plug Phoenix.Ecto.CheckRepoStatus, otp_app: :zero_phoenix end diff --git a/lib/zero_phoenix_web/router.ex b/lib/zero_phoenix_web/router.ex index a1a83d6..092ca19 100644 --- a/lib/zero_phoenix_web/router.ex +++ b/lib/zero_phoenix_web/router.ex @@ -1,14 +1,6 @@ defmodule ZeroPhoenixWeb.Router do use ZeroPhoenixWeb, :router - pipeline :browser do - plug :accepts, ["html"] - plug :fetch_session - plug :fetch_flash - plug :protect_from_forgery - plug :put_secure_browser_headers - end - pipeline :api do plug :accepts, ["json"] end @@ -38,8 +30,21 @@ defmodule ZeroPhoenixWeb.Router do import Phoenix.LiveDashboard.Router scope "/" do - pipe_through :browser + pipe_through [:fetch_session, :protect_from_forgery] + live_dashboard "/dashboard", metrics: ZeroPhoenixWeb.Telemetry end end + + # Enables the Swoosh mailbox preview in development. + # + # Note that preview only shows emails that were sent by the same + # node running the Phoenix server. + if Mix.env() == :dev do + scope "/dev" do + pipe_through [:fetch_session, :protect_from_forgery] + + forward "/mailbox", Plug.Swoosh.MailboxPreview + end + end end diff --git a/lib/zero_phoenix_web/telemetry.ex b/lib/zero_phoenix_web/telemetry.ex index 6e1f9d2..3365cc1 100644 --- a/lib/zero_phoenix_web/telemetry.ex +++ b/lib/zero_phoenix_web/telemetry.ex @@ -9,10 +9,12 @@ defmodule ZeroPhoenixWeb.Telemetry do @impl true def init(_arg) do children = [ + # Telemetry poller will execute the given period measurements + # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics {:telemetry_poller, measurements: periodic_measurements(), period: 10_000} # Add reporters as children of your supervision tree. # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()} - ] + ] Supervisor.init(children, strategy: :one_for_one) end @@ -29,11 +31,27 @@ defmodule ZeroPhoenixWeb.Telemetry do ), # Database Metrics - summary("zero_phoenix.repo.query.total_time", unit: {:native, :millisecond}), - summary("zero_phoenix.repo.query.decode_time", unit: {:native, :millisecond}), - summary("zero_phoenix.repo.query.query_time", unit: {:native, :millisecond}), - summary("zero_phoenix.repo.query.queue_time", unit: {:native, :millisecond}), - summary("zero_phoenix.repo.query.idle_time", unit: {:native, :millisecond}), + summary("zero_phoenix.repo.query.total_time", + unit: {:native, :millisecond}, + description: "The sum of the other measurements" + ), + summary("zero_phoenix.repo.query.decode_time", + unit: {:native, :millisecond}, + description: "The time spent decoding the data received from the database" + ), + summary("zero_phoenix.repo.query.query_time", + unit: {:native, :millisecond}, + description: "The time spent executing the query" + ), + summary("zero_phoenix.repo.query.queue_time", + unit: {:native, :millisecond}, + description: "The time spent waiting for a database connection" + ), + summary("zero_phoenix.repo.query.idle_time", + unit: {:native, :millisecond}, + description: + "The time the connection spent waiting before being checked out for the query" + ), # VM Metrics summary("vm.memory.total", unit: {:byte, :kilobyte}), diff --git a/lib/zero_phoenix_web/templates/layout/app.html.heex b/lib/zero_phoenix_web/templates/layout/app.html.heex deleted file mode 100644 index 169aed9..0000000 --- a/lib/zero_phoenix_web/templates/layout/app.html.heex +++ /dev/null @@ -1,5 +0,0 @@ -
- - - <%= @inner_content %> -
diff --git a/lib/zero_phoenix_web/templates/layout/live.html.heex b/lib/zero_phoenix_web/templates/layout/live.html.heex deleted file mode 100644 index a29d604..0000000 --- a/lib/zero_phoenix_web/templates/layout/live.html.heex +++ /dev/null @@ -1,11 +0,0 @@ -
- - - - - <%= @inner_content %> -
diff --git a/lib/zero_phoenix_web/templates/layout/root.html.heex b/lib/zero_phoenix_web/templates/layout/root.html.heex deleted file mode 100644 index e2baaf4..0000000 --- a/lib/zero_phoenix_web/templates/layout/root.html.heex +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - <%= csrf_meta_tag() %> - <%= live_title_tag assigns[:page_title] || "ZeroPhoenix", suffix: " · Phoenix Framework" %> - - - - -
-
- - -
-
- <%= @inner_content %> - - diff --git a/lib/zero_phoenix_web/templates/page/index.html.heex b/lib/zero_phoenix_web/templates/page/index.html.heex deleted file mode 100644 index f844bd8..0000000 --- a/lib/zero_phoenix_web/templates/page/index.html.heex +++ /dev/null @@ -1,41 +0,0 @@ -
-

<%= gettext "Welcome to %{name}!", name: "Phoenix" %>

-

Peace of mind from prototype to production

-
- -
- - -
diff --git a/lib/zero_phoenix_web/views/changeset_view.ex b/lib/zero_phoenix_web/views/changeset_view.ex deleted file mode 100644 index 675a0d9..0000000 --- a/lib/zero_phoenix_web/views/changeset_view.ex +++ /dev/null @@ -1,19 +0,0 @@ -defmodule ZeroPhoenixWeb.ChangesetView do - use ZeroPhoenixWeb, :view - - @doc """ - Traverses and translates changeset errors. - - See `Ecto.Changeset.traverse_errors/2` and - `ZeroPhoenixWeb.ErrorHelpers.translate_error/1` for more details. - """ - def translate_errors(changeset) do - Ecto.Changeset.traverse_errors(changeset, &translate_error/1) - end - - def render("error.json", %{changeset: changeset}) do - # When encoded, the changeset returns its errors - # as a JSON object. So we just pass it forward. - %{errors: translate_errors(changeset)} - end -end diff --git a/lib/zero_phoenix_web/views/error_helpers.ex b/lib/zero_phoenix_web/views/error_helpers.ex index 1efabeb..fa0c273 100644 --- a/lib/zero_phoenix_web/views/error_helpers.ex +++ b/lib/zero_phoenix_web/views/error_helpers.ex @@ -3,34 +3,27 @@ defmodule ZeroPhoenixWeb.ErrorHelpers do Conveniences for translating and building error messages. """ - use Phoenix.HTML - - @doc """ - Generates tag for inlined form input errors. - """ - def error_tag(form, field) do - Enum.map(Keyword.get_values(form.errors, field), fn (error) -> - content_tag :span, translate_error(error), class: "help-block" - end) - end - @doc """ Translates an error message using gettext. """ def translate_error({msg, opts}) do - # Because error messages were defined within Ecto, we must - # call the Gettext module passing our Gettext backend. We - # also use the "errors" domain as translations are placed - # in the errors.po file. - # Ecto will pass the :count keyword if the error message is - # meant to be pluralized. - # On your own code and templates, depending on whether you - # need the message to be pluralized or not, this could be - # written simply as: + # When using gettext, we typically pass the strings we want + # to translate as a static argument: + # + # # Translate "is invalid" in the "errors" domain + # dgettext("errors", "is invalid") + # + # # Translate the number of files with plural rules + # dngettext("errors", "1 file", "%{count} files", count) # - # dngettext "errors", "1 file", "%{count} files", count - # dgettext "errors", "is invalid" + # Because the error messages we show in our forms and APIs + # are defined inside Ecto, we need to translate them dynamically. + # This requires us to call the Gettext module passing our gettext + # backend as first argument. # + # Note we use the "errors" domain, which means translations + # should be written to the errors.po file. The :count option is + # set by Ecto and indicates we should also apply plural rules. if count = opts[:count] do Gettext.dngettext(ZeroPhoenixWeb.Gettext, "errors", msg, msg, count, opts) else diff --git a/lib/zero_phoenix_web/views/error_view.ex b/lib/zero_phoenix_web/views/error_view.ex index 37a3b07..0e637a8 100644 --- a/lib/zero_phoenix_web/views/error_view.ex +++ b/lib/zero_phoenix_web/views/error_view.ex @@ -3,14 +3,14 @@ defmodule ZeroPhoenixWeb.ErrorView do # If you want to customize a particular status code # for a certain format, you may uncomment below. - # def render("500.html", _assigns) do - # "Internal Server Error" + # def render("500.json", _assigns) do + # %{errors: %{detail: "Internal Server Error"}} # end # By default, Phoenix returns the status message from - # the template name. For example, "404.html" becomes + # the template name. For example, "404.json" becomes # "Not Found". def template_not_found(template, _assigns) do - Phoenix.Controller.status_message_from_template(template) + %{errors: %{detail: Phoenix.Controller.status_message_from_template(template)}} end end diff --git a/lib/zero_phoenix_web/views/layout_view.ex b/lib/zero_phoenix_web/views/layout_view.ex deleted file mode 100644 index 4295168..0000000 --- a/lib/zero_phoenix_web/views/layout_view.ex +++ /dev/null @@ -1,7 +0,0 @@ -defmodule ZeroPhoenixWeb.LayoutView do - use ZeroPhoenixWeb, :view - - # Phoenix LiveDashboard is available only in development by default, - # so we instruct Elixir to not warn if the dashboard route is missing. - @compile {:no_warn_undefined, {Routes, :live_dashboard_path, 2}} -end diff --git a/lib/zero_phoenix_web/views/page_view.ex b/lib/zero_phoenix_web/views/page_view.ex deleted file mode 100644 index 9e70af6..0000000 --- a/lib/zero_phoenix_web/views/page_view.ex +++ /dev/null @@ -1,3 +0,0 @@ -defmodule ZeroPhoenixWeb.PageView do - use ZeroPhoenixWeb, :view -end diff --git a/lib/zero_phoenix_web/views/person_view.ex b/lib/zero_phoenix_web/views/person_view.ex deleted file mode 100644 index 1daaf97..0000000 --- a/lib/zero_phoenix_web/views/person_view.ex +++ /dev/null @@ -1,20 +0,0 @@ -defmodule ZeroPhoenixWeb.PersonView do - use ZeroPhoenixWeb, :view - alias ZeroPhoenixWeb.PersonView - - def render("index.json", %{people: people}) do - %{data: render_many(people, PersonView, "person.json")} - end - - def render("show.json", %{person: person}) do - %{data: render_one(person, PersonView, "person.json")} - end - - def render("person.json", %{person: person}) do - %{id: person.id, - first_name: person.first_name, - last_name: person.last_name, - username: person.username, - email: person.email} - end -end diff --git a/mix.exs b/mix.exs index 77b0f65..8eb1c38 100644 --- a/mix.exs +++ b/mix.exs @@ -34,16 +34,11 @@ defmodule ZeroPhoenix.Mixfile do # Type `mix help deps` for examples and options. defp deps do [ - {:phoenix, "~> 1.6.2"}, + {:phoenix, "~> 1.6.4"}, {:phoenix_ecto, "~> 4.4"}, {:ecto_sql, "~> 3.7.1"}, {:postgrex, "~> 0.15.9"}, - {:phoenix_html, "~> 3.0"}, - {:phoenix_live_reload, "~> 1.3.3", only: :dev}, - {:phoenix_live_view, "~> 0.17.5"}, - {:floki, ">= 0.30.0", only: :test}, - {:phoenix_live_dashboard, "~> 0.5"}, - {:esbuild, "~> 0.2", runtime: Mix.env() == :dev}, + {:phoenix_live_dashboard, "~> 0.6"}, {:swoosh, "~> 1.3"}, {:telemetry_metrics, "~> 0.6.0"}, {:telemetry_poller, "~> 1.0"}, @@ -66,8 +61,7 @@ defmodule ZeroPhoenix.Mixfile do setup: ["deps.get", "ecto.setup"], "ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], "ecto.reset": ["ecto.drop", "ecto.setup"], - test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"], - "assets.deploy": ["esbuild default --minify", "phx.digest"] + test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"] ] end end diff --git a/mix.lock b/mix.lock index 5275f86..a935bf6 100644 --- a/mix.lock +++ b/mix.lock @@ -19,7 +19,7 @@ "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, "nimble_parsec": {:hex, :nimble_parsec, "1.2.0", "b44d75e2a6542dcb6acf5d71c32c74ca88960421b6874777f79153bbbbd7dccc", [:mix], [], "hexpm", "52b2871a7515a5ac49b00f214e4165a40724cf99798d8e4a65e4fd64ebd002c1"}, - "phoenix": {:hex, :phoenix, "1.6.2", "6cbd5c8ed7a797f25a919a37fafbc2fb1634c9cdb12a4448d7a5d0b26926f005", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7bbee475acae0c3abc229b7f189e210ea788e63bd168e585f60c299a4b2f9133"}, + "phoenix": {:hex, :phoenix, "1.6.4", "bc9a757f0a4eac88e1e3501245a6259e74d30970df8c072836d755608dbc4c7d", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b6cb3f31e3ea1049049852703eca794f7afdb0c1dc111d8f166ba032c103a80"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_html": {:hex, :phoenix_html, "3.1.0", "0b499df05aad27160d697a9362f0e89fa0e24d3c7a9065c2bd9d38b4d1416c09", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0c0a98a2cefa63433657983a2a594c7dee5927e4391e0f1bfd3a151d1def33fc"}, "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.1", "fb94a33c077141f9ac7930b322a7a3b99f9b144bf3a08dd667b9f9aaf0319889", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.1", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "6faf1373e5846c8ab68c2cf55cfa5c196c1fbbe0c72d12a4cdfaaac6ef189948"}, diff --git a/priv/static/css/app.css b/priv/static/css/app.css deleted file mode 100644 index db4901e..0000000 --- a/priv/static/css/app.css +++ /dev/null @@ -1,77 +0,0 @@ -/* This file is for your main application css. *//* Includes Bootstrap as well as some default style for the starter - * application. This can be safely deleted to start fresh. - */ - -/*! - * Bootstrap v3.3.5 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} - -/* Space out content a bit */ -body, form, ul, table { - margin-top: 20px; - margin-bottom: 20px; -} - -/* Phoenix flash messages */ -.alert:empty { display: none; } - -/* Custom page header */ -.header { - border-bottom: 1px solid #e5e5e5; -} -.logo { - width: 519px; - height: 71px; - display: inline-block; - margin-bottom: 1em; - background-image: url("/images/phoenix.png"); - background-size: 519px 71px; -} - -/* Everything but the jumbotron gets side spacing for mobile first views */ -.header, -.marketing { - padding-right: 15px; - padding-left: 15px; -} - -/* Customize container */ -@media (min-width: 768px) { - .container { - max-width: 730px; - } -} -.container-narrow > hr { - margin: 30px 0; -} - -/* Main marketing message */ -.jumbotron { - text-align: center; - border-bottom: 1px solid #e5e5e5; -} - -/* Supporting marketing content */ -.marketing { - margin: 35px 0; -} - -/* Responsive: Portrait tablets and up */ -@media screen and (min-width: 768px) { - /* Remove the padding we set earlier */ - .header, - .marketing { - padding-right: 0; - padding-left: 0; - } - /* Space out the masthead */ - .header { - margin-bottom: 30px; - } - /* Remove the bottom border on the jumbotron for visual effect */ - .jumbotron { - border-bottom: 0; - } -} \ No newline at end of file diff --git a/priv/static/favicon.ico b/priv/static/favicon.ico deleted file mode 100644 index 73de524aaadcf60fbe9d32881db0aa86b58b5cb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1258 zcmbtUO>fgM7{=qN=;Mz_82;lvPEdVaxv-<-&=sZLwab?3I zBP>U*&(Hv<5n@9ZQ$vhg#|u$Zmtq8BV;+W*7(?jOx-{r?#TE&$Sdq77MbdJjD5`-q zMm_z(jLv3t>5NhzK{%aG(Yudfpjd3AFdKe2U7&zdepTe>^s(@!&0X8TJ`h+-I?84Ml# diff --git a/priv/static/images/phoenix.png b/priv/static/images/phoenix.png deleted file mode 100644 index 9c81075f63d2151e6f40e9aa66f665749a87cc6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13900 zcmaL8WmsF?7A@RTTCBLc6?b=ccXxso4H~R1?gT4RtT+@6?yiLril%4@T7niU{_*z6 z{eIkY^CMY%XUs9jnrrU0pClu(+L}t3=w#^6o;|}(O%cy#x4LjZZH1q*$X;nePbVE4Ruj~ha0EO zKNwDso99#XvuEN`AWs{Bi@gtxt-YhOy9C{FXD=O%vz-K;k$?ubhNqmple2Q5m%Uz~ zramCh1t4NaCnZTE4ibGLaI^QZp#izMx_gU)Bn$}9dm*VB;%os*A`rzjVfzrR1HKOd)umm?RCh=|BP9K5_7PY4e00Cyi75Qn=r z{eKwb?Y#kB&YnKb9_}>%FxuF9`1(lDJt_Uy6x=-jOY83a?=n3Vj0LBly^W8Dm%fLG z>wl`K?d0L(;qBz%Nh7BxK%-#;aCZOa_%B{VLsZ4x+sDQoV6P%CLHESK>FjJL%Eu=o zC@9Y_#G@c6$it(+FQO9uXOy|HR6B0DRr--F^NOYxjR*h5u*lKds>A z`IK4S-pkp~-cHfW!;R+eltrEYw-$l_$@lMAyZ^04@PEc~J&ED^XJP+;3;mx{Pu=s+ z@V{;QbnxHCw|9T)cCV+l_Rhg0diIRBPeoovAGCCkhmu7!e=!0j%CIc1U{;0rzhnzj zRH%Ot=y$J%$R~ap!UOQPkR*PGC6W<##xjgp8{rXFTPGUhD7@5RKexzmd%We{#b|6i z`?lh2^&{jx)SK#0PhPgi&eUZ0vBcGiH`@-FoRy{i3j{L(leZ-WVvvA2{XVGbnr9s* zG$JW*Sqd>q(BQkwNG{TIu68tN%oQnb6^FFNR~xPl$I zm|>W*j{xhT(g3sl-2z1KY@&qA0a~--8mlbo6MSY3Sy29DZRC=_#b9K&IcW(xbn3qD zali;DIL*NQ2a>E?#=CXQMk;2IJDpfLGR5_w?UEM;`!OQP>sJa904@JRBdgqw<{A-f zPODilVldJY3tG8mjj<9Cq%HNX;km>BP=EQ!_>VT)lC6`dm~$b&B*aCJ*_t6bQD*XIIA zrrq#>z~6ik=?Q&P-|3PvgPI@=_MRFRi5f&qlac?_B_cT$A11<`f;&+p^s(QUcKGMS zNYwS6+Y109HVx5PCw$%fR|2X^WJR_R&T>NOOaXhEOOBl@ACRbf{Q38g%!l_W!fCv{ zyn=GMr7&FEFtoISlT(_%iFGOyAW*%LTFx{?IMb~HaOTxco0(xXa`wb0B-{sjpkZ9F zbnZMIZIc!;=Qqv2^WY_d{p1IDf88Rxts3(SLO{5`#Xi5aUOr5);GFV06(V2G0%QE` zw{cbL@W!uuqA3n1q)>mMxU?wl*Pwndp(E*^iJ@$Hm4EfeJ`y=_@(E_@&+FH@D;5#% z%5izR;P_>FEfS3Nmq*3SI-GpsAP~&&m$citnCRwyK%Fs4!m6qG(fj((-y-2~&7)oQ z4#JKn4nA=SUWP)V&DUvjP#Hz?-yUdXY;@ zNlmhBn0p;i0j^5OqhqN%)6E;;VN5UVdzE$GmIS%ZKVBDViH>uKNOQ&Uq5yG0Dlp-V zTpnO8cV6#UAk z)?vp{kNcLNu9V6yaw#|j*h9p`zNZJMyYcx_9Zx@es61Md4Nc*y09>UV7@wE@EGya!%G<~=$Cg%(LWWrD<&NXYR$#UpU; zl-N8X3auH&u_czz`2@`)@9^Q(Z%i7Hf=u*EDPZM>R2Fk4J#Q=0-x+Y2G~abPx7&Ra z2NL1RzJ6GzOMmMRqU6 z$VT^YqYCg33>3Q}C1=wdL-qO~RY!>-RljOAeEMmD^wu(R)f~VT!$Ug{0mvR$s&%fPY=gWk9kNN8m)<5-VE?(DW&De z_K7#3AU;h7d9k4~t}aji!~JOUAShjMOMAIETdSX?IMsgoD0hRthVvFz_Pv zdB+jF*ZW#({d2~{sX9F*h~py)k>5uVOoN%aFYVn4R`h41lz|0c2VZIB=nppL5y=g> zu!5%WhCXBkP}Z@2N_Vz!AzjR@qHsS0JYuj-#`U;&ZpDXpK_mAhyos?3Q{PNOL0pmg zC+VYZt}AEuYBcotKWk`m>a(=zjXxDB3#5Um zVOPP7@tHWfoJhBge!5gA4xHSVT7cu2&GC^pQ`A)wCChhgTf&%uxo`T!dK!h-3`){W zpvJr6%XD*gpM-&tSGPXMc(X9$3n{M4OiY7A9Xmh?(uP=TgDFkP-egM4nbFfm?^>b$ zOW3Npm^VN^_io|YL=pYnX73Ft-K|c|A1*#YT?(+WskD4SwQN8cBq))xT(;M{@0~D8 zL`ANR>lb0mKLRtNENx&SAp>P7857a%ZP{0S3snYW+tbd!X-*{GL}**b@G};C z)Q3bSoD}bG=Jx$POx1UDzM= z`-IZDl+GJgv`ehIT0``{&WDsH3nEG03F1%AU(!=nGsjuyzcneB{{lp{>#5)ndCUO;OINf(7fpu|jyopb#q zlcAO8B?*00y0gq?{w~Rm#QuV^oj)tPcv!7-@bCr?Zk?hlTDK)}c8r_PG$e2Sxtqkw znT9qczCHX17&fsDl3Vm2V-Aarj3y0gN1oyt+l*_2>We#0j5b%9+SO=cHnf?jhBVL* zc#p)VMKXMa?+hxBt}v^^v`27e&jC%v7U zYKYuMhjG$Ix{NA9pgZ+vM>wy}WFw4vHwJAgeD0=m%D2|9gU5(o73(HHxx~ z$`tS4W>`?peBKOuh2OZWrn>N15K@lt?#^(;0WnTZ?_LtcuN$kZ4>wSZ(5iUWZ$`jTC z_ci7nCc@Rp`ZOBltEe^pK#3|uV{VnV_K305Q3%H-7{5pCjN#f=F$6GY0!$*`&2k!S zIddNLT9i~PSY$C(Vk}fNjSg5anR_qHRGpDH-%`M=-M#Uy)$8I8o`groI|!?V_x3%D z*jIq7JKZ%3t7W0A9=PatJ(#|9PuiW+t}h-&qnBZ5P*GhxNr~gqcYtmMghEcf1;N$b z?-KJjMQTx=;qx4;2QzXIHdtmV{?c(qZn=JMuV7*~^o}L0PZRG-cNY-v$m+tCNWA;qfeK|Ja$ z?dtZ+=kKMyDZQ?#yBJCu@vCPRGRG#W=#Uqy7gWdT#9=CV-aUP``ekX{im2fj$(ICH zrqyj>sx@=@VhTUP^u8#smC#HX@iA!B1&~*#t~u+7Nq74FS*V0Q0?u(R5}(HKHeXU| zaX6UE!_YCc0<@~U?km)OK|HeGDJuLE1en`EE(|f3b_8Kc>^KoR$h}C4y*efcDc79k z)u3b4(j8swz`YC~>rtU}6ui^r7(E_B<4DBV|5_E&6Rp|K-w*sw)y8zPZhwG05z^^w zLRAg*Our%j74=A`>3&;5GjxWvxa*y0L3)y#_vIKsT*HJxThAl=kcG%Qs?J-inZbh@ zq`FJ)@rN?G3!zzcyL6$GtD~<-+L`H#r!{AWlr~}E%2bRDzO|+VWq4@vyEP<&_QmKI7yfHm7c|~ zkdcGa5KJs;WE|^Wm#k^lqqyS>>?&VZTzP8uAppMl3)U|MmG^Sp-h8%HE>eK^IF3|u z6blQxe|+599-P{(w9u$@#Po)>v4I0!Sh_Zp$De)M6#l5 zMLd&@Q!>%r&X>3(dy1Sy?PO++U1`I)&{?M@Uo z%#2bAa3&rk<63k``;b?*UQ=TG&ME|}*pK;D6(8EIW`d64<`Ai~rNBrJ{k%38h0VrZ z)(*?!ceIz6p#l3bgLvo%tKy^07Gr2rg@|ENO0eGhf^tf4;XC)3w)a9%k-CFMjbN)`@oRUehd@f#YrH`!qtJ(}CQ8lR z+MUwQHG!ZjF=2+LRco1w;NA)|e&(F=;@5@~YvQ*}WwH|1 zW{l!fpO$_sGYm*FDc`WXx|&tI;x;P(o+0HlocYS>GuQ0YJ}uF5G$wr!TF%IET{Q4|>d}!k>Q%%+Z{vc^)k{}BmP<=f)KU-84}F(W3?QXO?M&M_+fH%H zP1RGVhy8_TH3xc5er1$IF9!{db){AF1?8D6r6x6UC#X=y=*ObiCe zZ|cKVcuN6?)kxDj?`&dz$0gLFecX{V&Au;2g)e>UH(kt49)MhGU9UX2($=TV6dnKe zCR!eldvubP@OGmDCuf$w`Jo*ml6I!*Z&(Oa{eaWP`8m*aE|7#?ovVrug{PNqINSdu z@u72)Vd`WJ6OYNAB#+hOE$k8B(PtN)wdfZ;ELi6(7IlI>Ir~TU<;xx4Tn0^Lm885k z!2|CbsSv##hl_!eoJ#>wpS`2KtE(5CZ!Hf~l*~7UMiIR+&UO9*juK5%YYJjtkERgP zggP=dxb4%E8W((`2g)%g?g>E+RZW)7*L)HMnl}Lnu;J?<6ODpm3RLPGq6Vl;z|aNp z5*5uzK$K)Bp{dY?A*8crtu--(0(l+bO&*>5!u!KQD+;nt(a~g^`=2T;v-g>ul$x_u zLcQ{AV+YeSFP`@OYqz>QCGH1>^M==xc=@-W?jSBT@vfSWgAluU7WT?eutjJ2$9ZSdl;^rlm2JPtQ%6@Y$l7(6B9 zlqVdq@F&qdugX5%1MkA<3y`rQM$#0zn1``Jaacc^tu(EL=wALU?vJ70Xwx&+^%@ab z;OsbwDLNe;#0Iv-_)%@b(BG3aEi4P?nhDFaEm@06YtqSK88&-%%KNKLjXM)jlt$0d z(q8vr_pCL!w|MrQ((|ceeWT@-V(H#9J;(%sS2B8f8}xNox|N@GD5loR?9+n2fWKZY zc(Y*>gX85*ALqgajeA^)lhbXRioH>St-U3|TRjZd87wh*%kX(J1H3jQhhtV+p3fcPQ>XQUKsF9mm zoH!0Sr&YY;%y1%&bJqhNV_vk;?sx~5__YLXe|G`Bd!GququTI(0J-~}A@a(HCwYmO zWj>cDZ4_FKb}1f&lN4TD2*1zVVhK*wFN*D6oRC-~%)GsE{(N>owOd z%1cRV&^^^z@YP_}sI0j+rz_3|Zk9B;z|^}WEhV^Bpm;=Uf9IpY5Fn6A|FO@j7Z8&B z96ZFHGbnNB^C(Vfa20auH(3;B>~V!Yon}t?kpi_J#_}@sKCrK4uY_Xf`p7hv`XQ=8 zWNp{9H3nF%DY43p1+@_OnTmXtj z%WgVqwJ!5UnSrBy?rhLiXKT?d}y73{iOJdN@mhf#J?H_awxEp#WUbKF{0}s=woC6Y47);j* z8rB1{w*AVT>0NSmFtEae;*67g8T_nxO0c+ov@>{eu5n{@#RGTr>^Bb8=wBEbB;0`7 zz|!xSHUh-AuPL^G!?~=j#GR%GzgKr%icju#i74clZV*{+CP!VXw1lVu78LdOSdw{V z{4*;Lt7ier$fJSEz6+QygOA+}x_4ilo(2pO&gO2#M3YigPU!~HbZzFpPP(m(7_Dq( z6E$iYyBlF8m8$F1Cuz4}csC&yn=cM8WVgfaL&h75{Shd3)~!cR zCrAVcxl!YrKl=V^piF14E39&aLJVb9-eT+g2xImTQ%l7;}SHq_(LSbo^EM-HXXtZ0O zdW3nm2Xc86CsIwEsbP>@Q~2ojkx)cvw^BKDjB5;4cJZr2KyPiMdSz9LK~+wi4%NKr zbN2DsiY=l;nH8!iP250F?V2V~z(9!|pVCyX9mL_@_ zlcc-NP!BZ_1zEf>pRi=1_Kqh(3X+M9b?No%R8SQvDbofi&Fz$Vs(U!_CusVn+==X` z4cUNCy9%^!gq7dHZ(d7yf82(&o(5y7mF`*OIvT28jRocQywzcRqsbN4HuB~hLSmiP z1-e(k^;S23LfRT&ykT>g@~+hOx!lg!Sf~$2v?1w2ja>QgaJtM|?p@SM9&ls$0J<8;>A`IHQY5INUj<+t`aZ}v)4 zTMv2I_QwzEM=Wg(QohmrlBbJ|jcKc6rM(eJ>_{Ce7!j7Wl-87@z;z5`*K8^*wY?^P zXZWbVI~{|7l7A`bsQ034<(8h(+iSK&8}ijuX4p=^0dk;0zaKuYr~S&idu-;u+p3y# zh&LfPIM%YArf&^E-XlY^y8hl$%bp>Gi+MuNLb0pOLODZ47f-(U&F8UH%lFk)H3Pg8 zGX$RR8odn{YWkC>IU_o}?Bgs(hY9Wy8?sIR0}Vgrg%#6#9%R$r^539t@SnujcyONj zpE?(`U`-_m!Nt>6WU8?;PR;ou0f`wuvuj1xX4j}4+M{ZmBHI>~O54)>S3Z}=gNpD= z-B$ESnoSp)Ib~)v6o{j~ZKMpo4IJYIwwCY%v9+$k%2a=ut+ETf&f;R4JYriH_yjfh zcF16FMV7{Bm~xVwCmSeQ>{H^VpmBwKi?xX5tMS?s%PV;WKlk>RF2_ zaQ#KT_9dmokkCTOdHzpHF5DT*Q$Z=`2&Z8*iEw|IL>%}ep?*ArUV@HuU70}fr}vsu z7ct2;mYIn^8+D@M!HHQVZamDm4kufo_&Lv2PQ+;2qON&of3i4Z`6^WdW!GxVHw*o( z9RCu?86CO{>RZqmkKJi#IZw5A|C&P3R7~+e1O|KX>AO!{L~~2Q^j{VcJ?fn1_JtHu zo#68?Z;9QhCQ%>Wl+v*xbCBkOYksQ3ErxKmI#@o+=yEv*{noTagX`J);d!Sqs6~1- z_t3kU4AG&!bh}$vq8bSpCgNXZ%R$m zvOkBz6;t?`*dmP4KpQa6S(Tb1v2UM_yTrv=nIeEr4bEdkEf&tcKxgqz=0#_b6#}=d z<1+YBT8K_dgbVSiDuNBJv!Zzw;~H`1CnOI;NRH;M5O3aN0V4|fV%s{@tfO&#!{~vE zXkC?8J?SKAwT&lDA&ld*Yz*V@55gw}#xX07=)to%1He+@{4HiU*{$`=4_`dDSl!dE zrb@kaTRT7dc#5TRzxH}})^%cZIN6|2;?tLujjh6Ku4c*Pw+2LJ{e43$piypJ3@{zz z{ZyQ_eCg6H#lsA4@F@ubKQ?$Sr!)(1u-g0Y@!Y3D0$d`L8{h{xE*7}P)$8&a||XD*TfFRvL{%LTfbnlB1i z`xZ=4^3YZ0(&j19vpsX0>pdpp@?^hP1Lua|`g^OU4F@JZvt-JBeIhxTzTB`_7Ha(C zXpMKEgjelG#+Z1pH3QN?T{LaXLXs&7drY%!CjC6=jey#;hs!{-|i#z2tEed4Ti=&S3x@^6XZrGR|k} znjEuABs|D(T|wc}%1sHwoY(yB{a6Ys6`5RKt#YYI&kJ0bNGe4P*Uq9}0YZR`s>=o) z$^kQp3e)J59I>B@@PGAi_X6G%Sved~($wM_il`m%ViYFIyuN(JJ|msKAXrNRV#341 z1|2JQNES0Z;*5kT&$YHc%^PE`bnRw~uILz)Jn z)rtYuuV1r^>4a@XS-a!^ETgu|Hbj0rKjU`uCKq2mWUW!kEocyb*qm8%j`6#5FX;H5 zH}?G7Z?<6e>UQ1ZW!lOfGLsiJ6Cmv5nnJCrOjaP?lKh2^41eXWTy*hxjZKwSr_VJ}-~$&#D3 zzhiEKdrOMKKU0O4xvH7-t>i*p@I!2=k5-G?6tO+uraKwk8#JkfX*#Z{*%i}i_x~lXo^+A!ibrcM>WX|z89iEn| zyC2#BpijrGcW&p}+^3j>Wt$A*=Jrvh8ETLM8aKVsi0&;hlS@-###$Xy))F)OMv57; zZdh4t?c_)zrcUIaOVOUk1$;wMCE>D~-O=N0NFI9^e^C}x37OgGLo)!Q zl=io=P5JDB<$lI%4Y+J3XEphD`qO&Kd_8!yc<*ECCAvC#XTpXe+6u_cmTjEJ| znoqk>=_ZZ4uO5-(m)F08ceF!p<}!?TgW`7279=mKmj~~5tj;zg?PgUz-)5VMM%0j%)T?pU<0Uk|D3p5{2e??#5jMB{Y!BJEFH zuWNq7jM!7<2zWCvPQRj%cXAC#;y_}2ul?h8L$gjQfeIy;;;WXDudit7Uv|Z2b;SrX zfetgr<80WRG+xgFc;C!8+A#ako200^e2Q~AmM2ENwvrd`El^q3CVWk8#pR}l6cCg~ zUYS?4ylI87x!WdHAgi(~ry661S05Qi1wbZZh3H*x{Rw|u!|$*brVLWole{Fe)at#5 z&|6f+nmc3oc&?6vkxR;joiAOb9VuypZ0J$RUBbNxlH~&My}W2{rLRnL z_-^!!5*@@mLvLnIN0QiIhGHHqzPd<3m6&`Vvw8X{6CQBzCaG00F|!`5<-vmAC>~F}0=9+5g-X4W2>mQBUE2eh0%g|SqINm6Te;DOFibuJZ*{m1m-=$li zA>OF0B&aPG^YmL#sfV^T*RCPN%5N9BL>0$sDyvtimKQ1W9gBJ=5(@^odQd1zJ)8Lo(zG zeg;Iwc}daKZlFmS1a-tPNNEfJ99rixy+0qS+Sm5iq zL+jh*2DCx)TBOktKeP!XXqS-sX*+N5l;5o1VpaD@M%Pak^Vqbsa_Eo0WNcXh8i zafO?AZFRj;yl(n{r6|&IBA_<(2I?rB(2@jt?Fv>m#>YoLznm1vhc1`weTd-;OKNlU z7eAu`QWzX1>w@I0VgfW#HL`x)yyghsLOaU(#V{i%@fmXs*QfgI)M>KgCz&&%`=PNZ zPu+yGi`h*t8-5KMsj5_yxl+d&O}k-3yJGaH4TJX)ynmlzXsKl%oOgmmFTRO-s`ckV z&u!9meAquxYhwk+gHo^`Q|*lIBH2K=|B*NDyfTf|*+wzNwSNZ2hkhakih?%7j(lPT zD;YT{1@b6F_gc~lu)m$%A9Eb*aK&Q@qrFOd-)-p{v7hkz2lg2jw=-pNt0yOAU(svi zLYL#99x*+EkqXq&U$tR)E{^73j>i*upyP+bN9CfUhi~MgD<%5{I+<#AWsg?a)U-af z&|(T&_pI1K{XL`TB94{Ou)PPi5Y+MbOb^}#nvWufpZWaDcRLGjsu}h_miC|C;Ors| z=3G3ILzSiI!nCg+;$03@KDrVVI`VxANUQz+09hW z{~WkYa@aKYcKD$MeY0x*7Sec0vr5BAj`1Ov&~s(J`O2>w{g%{Jq-lIT_L=68?J+E* zGGTu~fpOk97y&7_Diw3aL;G8#ku@_Hyb)LWa$+&s zEF~rPhKO&PraSlge{A(pz0+TTl9mN_uDi-)@vS9E8zK$1amRo!FM&6Ys)yQdvVSt? zd&vc0p2sNLeK7sJ7^QO9Xkp(Tm$9A!ml{~8K2#1711%(JGl8Eh9QYUDKEx@cv!JHg)>??HhpzbPA3DM&~U< ze~Rf!mHiBTPgT>F;L?v|Ymp&(l9!ZA&Mt9(uv}|zk8-{XfKyu7vYP#;ao1qBoecXG zs7P|7#x6hY;x|`wfR2^)K5ub~0ncUzK+Ybe)UnPC7iajN`lE-k73KK}UD zKzHTYGesC!j*8N598|aVJHKu;Qd&wK$pOh<2p%XS*W6`g#nH`{4mC<`Tm8tWUzn}AWi3+;%dy%2o{JaR5Qy)!>H z%gz0!Cx`4fqYzD`j6j=|L6X8+kHP1A*E0lNx2(ItObT73J3_eKE@=MB4=jMRRrw62 zG<8C+vWR^_5OLT~3Brb~kl1OQ5_pGlWb@Ulbtbkbg~d5y_X_mvTrZdJ`R2u?sF<7U zZv~d(&CJ-A72TvW_u`}1Z=|JAbP7kMUj`&-f$L>F7R;6ggDkC*jsf|P&oalP8U8fK zT_2wdY0JFNakO#`swMjx zM!cT4Z}M9M_60r_9>16xcaX^`A9gqPZ`l_3nb%}8T`Chs482ZkvJhPcGX?jMR}=ah zTZDVQSSASC6SiqO@{GT!Qk?JszB*o9FY#TP6Dko7-f4$6V16IQQ`bDNN^kJC2IR;t zY?SB&z67>8I0W=}iwTS;u3x6J_59+L8+<7^p24|fLiU+*HlGuF3@?Ppk+A-3MnmFl z)qZ;$wA_$w?+0srI|;Kh_%r5`bfl_d$kA>k$+avzku2rs<@<_TvP^;(tTuzj zhE_CzlafJ^=I2x-PY=Nl5R<=t%`qL1pvH4;}21B9;( zkl_bYZ2+YII)|5v`(DLhC^8SK&@Rg;W2>Er#Wa&~W~5#GeHRr{N`OC4&x8mdeH^(Z zSo~{uE-6NJ{V*qLT*hB@@O-Qm!r>wH*J1pN8Ht>Ri`CHLtL;2>NxDqFb41bk*1z+J zhV>B-vfA2MMCt)_#) z3G~quaUUm>*(ov1gX?+|@8-u$!zgCPz9kxLJH$2OO{(l${;)=ie$@*MH+Dtp83U5!%o~k zPQ8KRJ141&WM*HM=`hd+PDS93YX&}Sllg@j-BHpM?!v8!WeV^^4DX@GQ`sea*>H?=b|NHgB}D2V9jt) zJ=prm-}$6M+ZsPel4vwOBmuhqij3Ujz<~(=Z+%`0#*Vm+M8&7Up%ajiBU{{m!_%D9 z1zJjlE#0`HNju{ds8|+m7h{Hj5#iNXfrHNd}8lmEE zQSW{7z*8sq+W$*S6LniEU?Z!#B?GdWkjUeg4$&N$;$N7gqx*-E<^6-zhv(0nSsJz2 UWxWXg`G1#+f~I_}taaG`2PLnS&Hw-a diff --git a/priv/static/js/app.js b/priv/static/js/app.js deleted file mode 100644 index 57999a4..0000000 --- a/priv/static/js/app.js +++ /dev/null @@ -1,3 +0,0 @@ -// for phoenix_html support, including form and button helpers -// copy the following scripts into your javascript bundle: -// * https://raw.githubusercontent.com/phoenixframework/phoenix_html/v2.10.0/priv/static/phoenix_html.js \ No newline at end of file diff --git a/priv/static/js/phoenix.js b/priv/static/js/phoenix.js deleted file mode 100644 index c56e0dd..0000000 --- a/priv/static/js/phoenix.js +++ /dev/null @@ -1,1431 +0,0 @@ -(function (global, factory) { -typeof exports === 'object' ? factory(exports) : -typeof define === 'function' && define.amd ? define(['exports'], factory) : -factory(global.Phoenix = global.Phoenix || {}); -}(this, (function (exports) { -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -/** - * Phoenix Channels JavaScript client - * - * ## Socket Connection - * - * A single connection is established to the server and - * channels are multiplexed over the connection. - * Connect to the server using the `Socket` class: - * - * ```javascript - * let socket = new Socket("/socket", {params: {userToken: "123"}}) - * socket.connect() - * ``` - * - * The `Socket` constructor takes the mount point of the socket, - * the authentication params, as well as options that can be found in - * the Socket docs, such as configuring the `LongPoll` transport, and - * heartbeat. - * - * ## Channels - * - * Channels are isolated, concurrent processes on the server that - * subscribe to topics and broker events between the client and server. - * To join a channel, you must provide the topic, and channel params for - * authorization. Here's an example chat room example where `"new_msg"` - * events are listened for, messages are pushed to the server, and - * the channel is joined with ok/error/timeout matches: - * - * ```javascript - * let channel = socket.channel("room:123", {token: roomToken}) - * channel.on("new_msg", msg => console.log("Got message", msg) ) - * $input.onEnter( e => { - * channel.push("new_msg", {body: e.target.val}, 10000) - * .receive("ok", (msg) => console.log("created message", msg) ) - * .receive("error", (reasons) => console.log("create failed", reasons) ) - * .receive("timeout", () => console.log("Networking issue...") ) - * }) - * channel.join() - * .receive("ok", ({messages}) => console.log("catching up", messages) ) - * .receive("error", ({reason}) => console.log("failed join", reason) ) - * .receive("timeout", () => console.log("Networking issue. Still waiting...") ) - *``` - * - * ## Joining - * - * Creating a channel with `socket.channel(topic, params)`, binds the params to - * `channel.params`, which are sent up on `channel.join()`. - * Subsequent rejoins will send up the modified params for - * updating authorization params, or passing up last_message_id information. - * Successful joins receive an "ok" status, while unsuccessful joins - * receive "error". - * - * ## Duplicate Join Subscriptions - * - * While the client may join any number of topics on any number of channels, - * the client may only hold a single subscription for each unique topic at any - * given time. When attempting to create a duplicate subscription, - * the server will close the existing channel, log a warning, and - * spawn a new channel for the topic. The client will have their - * `channel.onClose` callbacks fired for the existing channel, and the new - * channel join will have its receive hooks processed as normal. - * - * ## Pushing Messages - * - * From the previous example, we can see that pushing messages to the server - * can be done with `channel.push(eventName, payload)` and we can optionally - * receive responses from the push. Additionally, we can use - * `receive("timeout", callback)` to abort waiting for our other `receive` hooks - * and take action after some period of waiting. The default timeout is 5000ms. - * - * - * ## Socket Hooks - * - * Lifecycle events of the multiplexed connection can be hooked into via - * `socket.onError()` and `socket.onClose()` events, ie: - * - * ```javascript - * socket.onError( () => console.log("there was an error with the connection!") ) - * socket.onClose( () => console.log("the connection dropped") ) - * ``` - * - * - * ## Channel Hooks - * - * For each joined channel, you can bind to `onError` and `onClose` events - * to monitor the channel lifecycle, ie: - * - * ```javascript - * channel.onError( () => console.log("there was an error!") ) - * channel.onClose( () => console.log("the channel has gone away gracefully") ) - * ``` - * - * ### onError hooks - * - * `onError` hooks are invoked if the socket connection drops, or the channel - * crashes on the server. In either case, a channel rejoin is attempted - * automatically in an exponential backoff manner. - * - * ### onClose hooks - * - * `onClose` hooks are invoked only in two cases. 1) the channel explicitly - * closed on the server, or 2). The client explicitly closed, by calling - * `channel.leave()` - * - * - * ## Presence - * - * The `Presence` object provides features for syncing presence information - * from the server with the client and handling presences joining and leaving. - * - * ### Syncing initial state from the server - * - * `Presence.syncState` is used to sync the list of presences on the server - * with the client's state. An optional `onJoin` and `onLeave` callback can - * be provided to react to changes in the client's local presences across - * disconnects and reconnects with the server. - * - * `Presence.syncDiff` is used to sync a diff of presence join and leave - * events from the server, as they happen. Like `syncState`, `syncDiff` - * accepts optional `onJoin` and `onLeave` callbacks to react to a user - * joining or leaving from a device. - * - * ### Listing Presences - * - * `Presence.list` is used to return a list of presence information - * based on the local state of metadata. By default, all presence - * metadata is returned, but a `listBy` function can be supplied to - * allow the client to select which metadata to use for a given presence. - * For example, you may have a user online from different devices with - * a metadata status of "online", but they have set themselves to "away" - * on another device. In this case, the app may choose to use the "away" - * status for what appears on the UI. The example below defines a `listBy` - * function which prioritizes the first metadata which was registered for - * each user. This could be the first tab they opened, or the first device - * they came online from: - * - * ```javascript - * let state = {} - * state = Presence.syncState(state, stateFromServer) - * let listBy = (id, {metas: [first, ...rest]}) => { - * first.count = rest.length + 1 // count of this user's presences - * first.id = id - * return first - * } - * let onlineUsers = Presence.list(state, listBy) - * ``` - * - * - * ### Example Usage - *```javascript - * // detect if user has joined for the 1st time or from another tab/device - * let onJoin = (id, current, newPres) => { - * if(!current){ - * console.log("user has entered for the first time", newPres) - * } else { - * console.log("user additional presence", newPres) - * } - * } - * // detect if user has left from all tabs/devices, or is still present - * let onLeave = (id, current, leftPres) => { - * if(current.metas.length === 0){ - * console.log("user has left from all devices", leftPres) - * } else { - * console.log("user left from a device", leftPres) - * } - * } - * let presences = {} // client's initial empty presence state - * // receive initial presence data from server, sent after join - * myChannel.on("presence_state", state => { - * presences = Presence.syncState(presences, state, onJoin, onLeave) - * displayUsers(Presence.list(presences)) - * }) - * // receive "presence_diff" from server, containing join/leave events - * myChannel.on("presence_diff", diff => { - * presences = Presence.syncDiff(presences, diff, onJoin, onLeave) - * this.setState({users: Presence.list(room.presences, listBy)}) - * }) - * ``` - * @module phoenix - */ - -var VSN = "2.0.0"; -var SOCKET_STATES = { connecting: 0, open: 1, closing: 2, closed: 3 }; -var DEFAULT_TIMEOUT = 10000; -var WS_CLOSE_NORMAL = 1000; -var CHANNEL_STATES = { - closed: "closed", - errored: "errored", - joined: "joined", - joining: "joining", - leaving: "leaving" -}; -var CHANNEL_EVENTS = { - close: "phx_close", - error: "phx_error", - join: "phx_join", - reply: "phx_reply", - leave: "phx_leave" -}; -var CHANNEL_LIFECYCLE_EVENTS = [CHANNEL_EVENTS.close, CHANNEL_EVENTS.error, CHANNEL_EVENTS.join, CHANNEL_EVENTS.reply, CHANNEL_EVENTS.leave]; -var TRANSPORTS = { - longpoll: "longpoll", - websocket: "websocket" -}; - -/** - * Initializes the Push - * @param {Channel} channel - The Channel - * @param {string} event - The event, for example `"phx_join"` - * @param {Object} payload - The payload, for example `{user_id: 123}` - * @param {number} timeout - The push timeout in milliseconds - */ - -var Push = function () { - function Push(channel, event, payload, timeout) { - _classCallCheck(this, Push); - - this.channel = channel; - this.event = event; - this.payload = payload || {}; - this.receivedResp = null; - this.timeout = timeout; - this.timeoutTimer = null; - this.recHooks = []; - this.sent = false; - } - - /** - * - * @param {number} timeout - */ - - - _createClass(Push, [{ - key: "resend", - value: function resend(timeout) { - this.timeout = timeout; - this.reset(); - this.send(); - } - - /** - * - */ - - }, { - key: "send", - value: function send() { - if (this.hasReceived("timeout")) { - return; - } - this.startTimeout(); - this.sent = true; - this.channel.socket.push({ - topic: this.channel.topic, - event: this.event, - payload: this.payload, - ref: this.ref, - join_ref: this.channel.joinRef() - }); - } - - /** - * - * @param {*} status - * @param {*} callback - */ - - }, { - key: "receive", - value: function receive(status, callback) { - if (this.hasReceived(status)) { - callback(this.receivedResp.response); - } - - this.recHooks.push({ status: status, callback: callback }); - return this; - } - - // private - - }, { - key: "reset", - value: function reset() { - this.cancelRefEvent(); - this.ref = null; - this.refEvent = null; - this.receivedResp = null; - this.sent = false; - } - }, { - key: "matchReceive", - value: function matchReceive(_ref) { - var status = _ref.status, - response = _ref.response, - ref = _ref.ref; - - this.recHooks.filter(function (h) { - return h.status === status; - }).forEach(function (h) { - return h.callback(response); - }); - } - }, { - key: "cancelRefEvent", - value: function cancelRefEvent() { - if (!this.refEvent) { - return; - } - this.channel.off(this.refEvent); - } - }, { - key: "cancelTimeout", - value: function cancelTimeout() { - clearTimeout(this.timeoutTimer); - this.timeoutTimer = null; - } - }, { - key: "startTimeout", - value: function startTimeout() { - var _this = this; - - if (this.timeoutTimer) { - this.cancelTimeout(); - } - this.ref = this.channel.socket.makeRef(); - this.refEvent = this.channel.replyEventName(this.ref); - - this.channel.on(this.refEvent, function (payload) { - _this.cancelRefEvent(); - _this.cancelTimeout(); - _this.receivedResp = payload; - _this.matchReceive(payload); - }); - - this.timeoutTimer = setTimeout(function () { - _this.trigger("timeout", {}); - }, this.timeout); - } - }, { - key: "hasReceived", - value: function hasReceived(status) { - return this.receivedResp && this.receivedResp.status === status; - } - }, { - key: "trigger", - value: function trigger(status, response) { - this.channel.trigger(this.refEvent, { status: status, response: response }); - } - }]); - - return Push; -}(); - -/** - * - * @param {string} topic - * @param {Object} params - * @param {Socket} socket - */ - - -var Channel = exports.Channel = function () { - function Channel(topic, params, socket) { - var _this2 = this; - - _classCallCheck(this, Channel); - - this.state = CHANNEL_STATES.closed; - this.topic = topic; - this.params = params || {}; - this.socket = socket; - this.bindings = []; - this.timeout = this.socket.timeout; - this.joinedOnce = false; - this.joinPush = new Push(this, CHANNEL_EVENTS.join, this.params, this.timeout); - this.pushBuffer = []; - this.rejoinTimer = new Timer(function () { - return _this2.rejoinUntilConnected(); - }, this.socket.reconnectAfterMs); - this.joinPush.receive("ok", function () { - _this2.state = CHANNEL_STATES.joined; - _this2.rejoinTimer.reset(); - _this2.pushBuffer.forEach(function (pushEvent) { - return pushEvent.send(); - }); - _this2.pushBuffer = []; - }); - this.onClose(function () { - _this2.rejoinTimer.reset(); - _this2.socket.log("channel", "close " + _this2.topic + " " + _this2.joinRef()); - _this2.state = CHANNEL_STATES.closed; - _this2.socket.remove(_this2); - }); - this.onError(function (reason) { - if (_this2.isLeaving() || _this2.isClosed()) { - return; - } - _this2.socket.log("channel", "error " + _this2.topic, reason); - _this2.state = CHANNEL_STATES.errored; - _this2.rejoinTimer.scheduleTimeout(); - }); - this.joinPush.receive("timeout", function () { - if (!_this2.isJoining()) { - return; - } - _this2.socket.log("channel", "timeout " + _this2.topic + " (" + _this2.joinRef() + ")", _this2.joinPush.timeout); - var leavePush = new Push(_this2, CHANNEL_EVENTS.leave, {}, _this2.timeout); - leavePush.send(); - _this2.state = CHANNEL_STATES.errored; - _this2.joinPush.reset(); - _this2.rejoinTimer.scheduleTimeout(); - }); - this.on(CHANNEL_EVENTS.reply, function (payload, ref) { - _this2.trigger(_this2.replyEventName(ref), payload); - }); - } - - _createClass(Channel, [{ - key: "rejoinUntilConnected", - value: function rejoinUntilConnected() { - this.rejoinTimer.scheduleTimeout(); - if (this.socket.isConnected()) { - this.rejoin(); - } - } - }, { - key: "join", - value: function join() { - var timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.timeout; - - if (this.joinedOnce) { - throw "tried to join multiple times. 'join' can only be called a single time per channel instance"; - } else { - this.joinedOnce = true; - this.rejoin(timeout); - return this.joinPush; - } - } - }, { - key: "onClose", - value: function onClose(callback) { - this.on(CHANNEL_EVENTS.close, callback); - } - }, { - key: "onError", - value: function onError(callback) { - this.on(CHANNEL_EVENTS.error, function (reason) { - return callback(reason); - }); - } - }, { - key: "on", - value: function on(event, callback) { - this.bindings.push({ event: event, callback: callback }); - } - }, { - key: "off", - value: function off(event) { - this.bindings = this.bindings.filter(function (bind) { - return bind.event !== event; - }); - } - }, { - key: "canPush", - value: function canPush() { - return this.socket.isConnected() && this.isJoined(); - } - }, { - key: "push", - value: function push(event, payload) { - var timeout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.timeout; - - if (!this.joinedOnce) { - throw "tried to push '" + event + "' to '" + this.topic + "' before joining. Use channel.join() before pushing events"; - } - var pushEvent = new Push(this, event, payload, timeout); - if (this.canPush()) { - pushEvent.send(); - } else { - pushEvent.startTimeout(); - this.pushBuffer.push(pushEvent); - } - - return pushEvent; - } - - /** Leaves the channel - * - * Unsubscribes from server events, and - * instructs channel to terminate on server - * - * Triggers onClose() hooks - * - * To receive leave acknowledgements, use the a `receive` - * hook to bind to the server ack, ie: - * - * ```javascript - * channel.leave().receive("ok", () => alert("left!") ) - * ``` - */ - - }, { - key: "leave", - value: function leave() { - var _this3 = this; - - var timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.timeout; - - this.state = CHANNEL_STATES.leaving; - var onClose = function onClose() { - _this3.socket.log("channel", "leave " + _this3.topic); - _this3.trigger(CHANNEL_EVENTS.close, "leave"); - }; - var leavePush = new Push(this, CHANNEL_EVENTS.leave, {}, timeout); - leavePush.receive("ok", function () { - return onClose(); - }).receive("timeout", function () { - return onClose(); - }); - leavePush.send(); - if (!this.canPush()) { - leavePush.trigger("ok", {}); - } - - return leavePush; - } - - /** - * Overridable message hook - * - * Receives all events for specialized message handling - * before dispatching to the channel callbacks. - * - * Must return the payload, modified or unmodified - */ - - }, { - key: "onMessage", - value: function onMessage(event, payload, ref) { - return payload; - } - - // private - - }, { - key: "isMember", - value: function isMember(topic, event, payload, joinRef) { - if (this.topic !== topic) { - return false; - } - var isLifecycleEvent = CHANNEL_LIFECYCLE_EVENTS.indexOf(event) >= 0; - - if (joinRef && isLifecycleEvent && joinRef !== this.joinRef()) { - this.socket.log("channel", "dropping outdated message", { topic: topic, event: event, payload: payload, joinRef: joinRef }); - return false; - } else { - return true; - } - } - }, { - key: "joinRef", - value: function joinRef() { - return this.joinPush.ref; - } - }, { - key: "sendJoin", - value: function sendJoin(timeout) { - this.state = CHANNEL_STATES.joining; - this.joinPush.resend(timeout); - } - }, { - key: "rejoin", - value: function rejoin() { - var timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.timeout; - if (this.isLeaving()) { - return; - } - this.sendJoin(timeout); - } - }, { - key: "trigger", - value: function trigger(event, payload, ref, joinRef) { - var _this4 = this; - - var handledPayload = this.onMessage(event, payload, ref, joinRef); - if (payload && !handledPayload) { - throw "channel onMessage callbacks must return the payload, modified or unmodified"; - } - - this.bindings.filter(function (bind) { - return bind.event === event; - }).map(function (bind) { - return bind.callback(handledPayload, ref, joinRef || _this4.joinRef()); - }); - } - }, { - key: "replyEventName", - value: function replyEventName(ref) { - return "chan_reply_" + ref; - } - }, { - key: "isClosed", - value: function isClosed() { - return this.state === CHANNEL_STATES.closed; - } - }, { - key: "isErrored", - value: function isErrored() { - return this.state === CHANNEL_STATES.errored; - } - }, { - key: "isJoined", - value: function isJoined() { - return this.state === CHANNEL_STATES.joined; - } - }, { - key: "isJoining", - value: function isJoining() { - return this.state === CHANNEL_STATES.joining; - } - }, { - key: "isLeaving", - value: function isLeaving() { - return this.state === CHANNEL_STATES.leaving; - } - }]); - - return Channel; -}(); - -var Serializer = { - encode: function encode(msg, callback) { - var payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload]; - return callback(JSON.stringify(payload)); - }, - decode: function decode(rawPayload, callback) { - var _JSON$parse = JSON.parse(rawPayload), - _JSON$parse2 = _slicedToArray(_JSON$parse, 5), - join_ref = _JSON$parse2[0], - ref = _JSON$parse2[1], - topic = _JSON$parse2[2], - event = _JSON$parse2[3], - payload = _JSON$parse2[4]; - - return callback({ join_ref: join_ref, ref: ref, topic: topic, event: event, payload: payload }); - } -}; - -/** Initializes the Socket - * - * - * For IE8 support use an ES5-shim (https://github.com/es-shims/es5-shim) - * - * @param {string} endPoint - The string WebSocket endpoint, ie, `"ws://example.com/socket"`, - * `"wss://example.com"` - * `"/socket"` (inherited host & protocol) - * @param {Object} opts - Optional configuration - * @param {string} opts.transport - The Websocket Transport, for example WebSocket or Phoenix.LongPoll. - * - * Defaults to WebSocket with automatic LongPoll fallback. - * @param {Function} opts.encode - The function to encode outgoing messages. - * - * Defaults to JSON: - * - * ```javascript - * (payload, callback) => callback(JSON.stringify(payload)) - * ``` - * - * @param {Function} opts.decode - The function to decode incoming messages. - * - * Defaults to JSON: - * - * ```javascript - * (payload, callback) => callback(JSON.parse(payload)) - * ``` - * - * @param {number} opts.timeout - The default timeout in milliseconds to trigger push timeouts. - * - * Defaults `DEFAULT_TIMEOUT` - * @param {number} opts.heartbeatIntervalMs - The millisec interval to send a heartbeat message - * @param {number} opts.reconnectAfterMs - The optional function that returns the millsec reconnect interval. - * - * Defaults to stepped backoff of: - * - * ```javascript - * function(tries){ - * return [1000, 5000, 10000][tries - 1] || 10000 - * } - * ``` - * @param {Function} opts.logger - The optional function for specialized logging, ie: - * ```javascript - * logger: (kind, msg, data) => { console.log(`${kind}: ${msg}`, data) } - * ``` - * - * @param {number} opts.longpollerTimeout - The maximum timeout of a long poll AJAX request. - * - * Defaults to 20s (double the server long poll timer). - * - * @param {Object} opts.params - The optional params to pass when connecting - * - * -*/ - -var Socket = exports.Socket = function () { - function Socket(endPoint) { - var _this5 = this; - - var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - - _classCallCheck(this, Socket); - - this.stateChangeCallbacks = { open: [], close: [], error: [], message: [] }; - this.channels = []; - this.sendBuffer = []; - this.ref = 0; - this.timeout = opts.timeout || DEFAULT_TIMEOUT; - this.transport = opts.transport || window.WebSocket || LongPoll; - this.defaultEncoder = Serializer.encode; - this.defaultDecoder = Serializer.decode; - if (this.transport !== LongPoll) { - this.encode = opts.encode || this.defaultEncoder; - this.decode = opts.decode || this.defaultDecoder; - } else { - this.encode = this.defaultEncoder; - this.decode = this.defaultDecoder; - } - this.heartbeatIntervalMs = opts.heartbeatIntervalMs || 30000; - this.reconnectAfterMs = opts.reconnectAfterMs || function (tries) { - return [1000, 2000, 5000, 10000][tries - 1] || 10000; - }; - this.logger = opts.logger || function () {}; // noop - this.longpollerTimeout = opts.longpollerTimeout || 20000; - this.params = opts.params || {}; - this.endPoint = endPoint + "/" + TRANSPORTS.websocket; - this.heartbeatTimer = null; - this.pendingHeartbeatRef = null; - this.reconnectTimer = new Timer(function () { - _this5.disconnect(function () { - return _this5.connect(); - }); - }, this.reconnectAfterMs); - } - - _createClass(Socket, [{ - key: "protocol", - value: function protocol() { - return location.protocol.match(/^https/) ? "wss" : "ws"; - } - }, { - key: "endPointURL", - value: function endPointURL() { - var uri = Ajax.appendParams(Ajax.appendParams(this.endPoint, this.params), { vsn: VSN }); - if (uri.charAt(0) !== "/") { - return uri; - } - if (uri.charAt(1) === "/") { - return this.protocol() + ":" + uri; - } - - return this.protocol() + "://" + location.host + uri; - } - }, { - key: "disconnect", - value: function disconnect(callback, code, reason) { - if (this.conn) { - this.conn.onclose = function () {}; // noop - if (code) { - this.conn.close(code, reason || ""); - } else { - this.conn.close(); - } - this.conn = null; - } - callback && callback(); - } - - /** - * - * @param {Object} params - The params to send when connecting, for example `{user_id: userToken}` - */ - - }, { - key: "connect", - value: function connect(params) { - var _this6 = this; - - if (params) { - console && console.log("passing params to connect is deprecated. Instead pass :params to the Socket constructor"); - this.params = params; - } - if (this.conn) { - return; - } - - this.conn = new this.transport(this.endPointURL()); - this.conn.timeout = this.longpollerTimeout; - this.conn.onopen = function () { - return _this6.onConnOpen(); - }; - this.conn.onerror = function (error) { - return _this6.onConnError(error); - }; - this.conn.onmessage = function (event) { - return _this6.onConnMessage(event); - }; - this.conn.onclose = function (event) { - return _this6.onConnClose(event); - }; - } - - /** - * Logs the message. Override `this.logger` for specialized logging. noops by default - * @param {string} kind - * @param {string} msg - * @param {Object} data - */ - - }, { - key: "log", - value: function log(kind, msg, data) { - this.logger(kind, msg, data); - } - - // Registers callbacks for connection state change events - // - // Examples - // - // socket.onError(function(error){ alert("An error occurred") }) - // - - }, { - key: "onOpen", - value: function onOpen(callback) { - this.stateChangeCallbacks.open.push(callback); - } - }, { - key: "onClose", - value: function onClose(callback) { - this.stateChangeCallbacks.close.push(callback); - } - }, { - key: "onError", - value: function onError(callback) { - this.stateChangeCallbacks.error.push(callback); - } - }, { - key: "onMessage", - value: function onMessage(callback) { - this.stateChangeCallbacks.message.push(callback); - } - }, { - key: "onConnOpen", - value: function onConnOpen() { - var _this7 = this; - - this.log("transport", "connected to " + this.endPointURL()); - this.flushSendBuffer(); - this.reconnectTimer.reset(); - if (!this.conn.skipHeartbeat) { - clearInterval(this.heartbeatTimer); - this.heartbeatTimer = setInterval(function () { - return _this7.sendHeartbeat(); - }, this.heartbeatIntervalMs); - } - this.stateChangeCallbacks.open.forEach(function (callback) { - return callback(); - }); - } - }, { - key: "onConnClose", - value: function onConnClose(event) { - this.log("transport", "close", event); - this.triggerChanError(); - clearInterval(this.heartbeatTimer); - this.reconnectTimer.scheduleTimeout(); - this.stateChangeCallbacks.close.forEach(function (callback) { - return callback(event); - }); - } - }, { - key: "onConnError", - value: function onConnError(error) { - this.log("transport", error); - this.triggerChanError(); - this.stateChangeCallbacks.error.forEach(function (callback) { - return callback(error); - }); - } - }, { - key: "triggerChanError", - value: function triggerChanError() { - this.channels.forEach(function (channel) { - return channel.trigger(CHANNEL_EVENTS.error); - }); - } - }, { - key: "connectionState", - value: function connectionState() { - switch (this.conn && this.conn.readyState) { - case SOCKET_STATES.connecting: - return "connecting"; - case SOCKET_STATES.open: - return "open"; - case SOCKET_STATES.closing: - return "closing"; - default: - return "closed"; - } - } - }, { - key: "isConnected", - value: function isConnected() { - return this.connectionState() === "open"; - } - }, { - key: "remove", - value: function remove(channel) { - this.channels = this.channels.filter(function (c) { - return c.joinRef() !== channel.joinRef(); - }); - } - }, { - key: "channel", - value: function channel(topic) { - var chanParams = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - - var chan = new Channel(topic, chanParams, this); - this.channels.push(chan); - return chan; - } - }, { - key: "push", - value: function push(data) { - var _this8 = this; - - var topic = data.topic, - event = data.event, - payload = data.payload, - ref = data.ref, - join_ref = data.join_ref; - - var callback = function callback() { - _this8.encode(data, function (result) { - _this8.conn.send(result); - }); - }; - this.log("push", topic + " " + event + " (" + join_ref + ", " + ref + ")", payload); - if (this.isConnected()) { - callback(); - } else { - this.sendBuffer.push(callback); - } - } - - /** - * Return the next message ref, accounting for overflows - */ - - }, { - key: "makeRef", - value: function makeRef() { - var newRef = this.ref + 1; - if (newRef === this.ref) { - this.ref = 0; - } else { - this.ref = newRef; - } - - return this.ref.toString(); - } - }, { - key: "sendHeartbeat", - value: function sendHeartbeat() { - if (!this.isConnected()) { - return; - } - if (this.pendingHeartbeatRef) { - this.pendingHeartbeatRef = null; - this.log("transport", "heartbeat timeout. Attempting to re-establish connection"); - this.conn.close(WS_CLOSE_NORMAL, "hearbeat timeout"); - return; - } - this.pendingHeartbeatRef = this.makeRef(); - this.push({ topic: "phoenix", event: "heartbeat", payload: {}, ref: this.pendingHeartbeatRef }); - } - }, { - key: "flushSendBuffer", - value: function flushSendBuffer() { - if (this.isConnected() && this.sendBuffer.length > 0) { - this.sendBuffer.forEach(function (callback) { - return callback(); - }); - this.sendBuffer = []; - } - } - }, { - key: "onConnMessage", - value: function onConnMessage(rawMessage) { - var _this9 = this; - - this.decode(rawMessage.data, function (msg) { - var topic = msg.topic, - event = msg.event, - payload = msg.payload, - ref = msg.ref, - join_ref = msg.join_ref; - - if (ref && ref === _this9.pendingHeartbeatRef) { - _this9.pendingHeartbeatRef = null; - } - - _this9.log("receive", (payload.status || "") + " " + topic + " " + event + " " + (ref && "(" + ref + ")" || ""), payload); - _this9.channels.filter(function (channel) { - return channel.isMember(topic, event, payload, join_ref); - }).forEach(function (channel) { - return channel.trigger(event, payload, ref, join_ref); - }); - _this9.stateChangeCallbacks.message.forEach(function (callback) { - return callback(msg); - }); - }); - } - }]); - - return Socket; -}(); - -var LongPoll = exports.LongPoll = function () { - function LongPoll(endPoint) { - _classCallCheck(this, LongPoll); - - this.endPoint = null; - this.token = null; - this.skipHeartbeat = true; - this.onopen = function () {}; // noop - this.onerror = function () {}; // noop - this.onmessage = function () {}; // noop - this.onclose = function () {}; // noop - this.pollEndpoint = this.normalizeEndpoint(endPoint); - this.readyState = SOCKET_STATES.connecting; - - this.poll(); - } - - _createClass(LongPoll, [{ - key: "normalizeEndpoint", - value: function normalizeEndpoint(endPoint) { - return endPoint.replace("ws://", "http://").replace("wss://", "https://").replace(new RegExp("(.*)\/" + TRANSPORTS.websocket), "$1/" + TRANSPORTS.longpoll); - } - }, { - key: "endpointURL", - value: function endpointURL() { - return Ajax.appendParams(this.pollEndpoint, { token: this.token }); - } - }, { - key: "closeAndRetry", - value: function closeAndRetry() { - this.close(); - this.readyState = SOCKET_STATES.connecting; - } - }, { - key: "ontimeout", - value: function ontimeout() { - this.onerror("timeout"); - this.closeAndRetry(); - } - }, { - key: "poll", - value: function poll() { - var _this10 = this; - - if (!(this.readyState === SOCKET_STATES.open || this.readyState === SOCKET_STATES.connecting)) { - return; - } - - Ajax.request("GET", this.endpointURL(), "application/json", null, this.timeout, this.ontimeout.bind(this), function (resp) { - if (resp) { - var status = resp.status, - token = resp.token, - messages = resp.messages; - - _this10.token = token; - } else { - var status = 0; - } - - switch (status) { - case 200: - messages.forEach(function (msg) { - return _this10.onmessage({ data: msg }); - }); - _this10.poll(); - break; - case 204: - _this10.poll(); - break; - case 410: - _this10.readyState = SOCKET_STATES.open; - _this10.onopen(); - _this10.poll(); - break; - case 0: - case 500: - _this10.onerror(); - _this10.closeAndRetry(); - break; - default: - throw "unhandled poll status " + status; - } - }); - } - }, { - key: "send", - value: function send(body) { - var _this11 = this; - - Ajax.request("POST", this.endpointURL(), "application/json", body, this.timeout, this.onerror.bind(this, "timeout"), function (resp) { - if (!resp || resp.status !== 200) { - _this11.onerror(resp && resp.status); - _this11.closeAndRetry(); - } - }); - } - }, { - key: "close", - value: function close(code, reason) { - this.readyState = SOCKET_STATES.closed; - this.onclose(); - } - }]); - - return LongPoll; -}(); - -var Ajax = exports.Ajax = function () { - function Ajax() { - _classCallCheck(this, Ajax); - } - - _createClass(Ajax, null, [{ - key: "request", - value: function request(method, endPoint, accept, body, timeout, ontimeout, callback) { - if (window.XDomainRequest) { - var req = new XDomainRequest(); // IE8, IE9 - this.xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback); - } else { - var _req = window.XMLHttpRequest ? new window.XMLHttpRequest() : // IE7+, Firefox, Chrome, Opera, Safari - new ActiveXObject("Microsoft.XMLHTTP"); // IE6, IE5 - this.xhrRequest(_req, method, endPoint, accept, body, timeout, ontimeout, callback); - } - } - }, { - key: "xdomainRequest", - value: function xdomainRequest(req, method, endPoint, body, timeout, ontimeout, callback) { - var _this12 = this; - - req.timeout = timeout; - req.open(method, endPoint); - req.onload = function () { - var response = _this12.parseJSON(req.responseText); - callback && callback(response); - }; - if (ontimeout) { - req.ontimeout = ontimeout; - } - - // Work around bug in IE9 that requires an attached onprogress handler - req.onprogress = function () {}; - - req.send(body); - } - }, { - key: "xhrRequest", - value: function xhrRequest(req, method, endPoint, accept, body, timeout, ontimeout, callback) { - var _this13 = this; - - req.open(method, endPoint, true); - req.timeout = timeout; - req.setRequestHeader("Content-Type", accept); - req.onerror = function () { - callback && callback(null); - }; - req.onreadystatechange = function () { - if (req.readyState === _this13.states.complete && callback) { - var response = _this13.parseJSON(req.responseText); - callback(response); - } - }; - if (ontimeout) { - req.ontimeout = ontimeout; - } - - req.send(body); - } - }, { - key: "parseJSON", - value: function parseJSON(resp) { - if (!resp || resp === "") { - return null; - } - - try { - return JSON.parse(resp); - } catch (e) { - console && console.log("failed to parse JSON response", resp); - return null; - } - } - }, { - key: "serialize", - value: function serialize(obj, parentKey) { - var queryStr = []; - for (var key in obj) { - if (!obj.hasOwnProperty(key)) { - continue; - } - var paramKey = parentKey ? parentKey + "[" + key + "]" : key; - var paramVal = obj[key]; - if ((typeof paramVal === "undefined" ? "undefined" : _typeof(paramVal)) === "object") { - queryStr.push(this.serialize(paramVal, paramKey)); - } else { - queryStr.push(encodeURIComponent(paramKey) + "=" + encodeURIComponent(paramVal)); - } - } - return queryStr.join("&"); - } - }, { - key: "appendParams", - value: function appendParams(url, params) { - if (Object.keys(params).length === 0) { - return url; - } - - var prefix = url.match(/\?/) ? "&" : "?"; - return "" + url + prefix + this.serialize(params); - } - }]); - - return Ajax; -}(); - -Ajax.states = { complete: 4 }; - -var Presence = exports.Presence = { - syncState: function syncState(currentState, newState, onJoin, onLeave) { - var _this14 = this; - - var state = this.clone(currentState); - var joins = {}; - var leaves = {}; - - this.map(state, function (key, presence) { - if (!newState[key]) { - leaves[key] = presence; - } - }); - this.map(newState, function (key, newPresence) { - var currentPresence = state[key]; - if (currentPresence) { - var newRefs = newPresence.metas.map(function (m) { - return m.phx_ref; - }); - var curRefs = currentPresence.metas.map(function (m) { - return m.phx_ref; - }); - var joinedMetas = newPresence.metas.filter(function (m) { - return curRefs.indexOf(m.phx_ref) < 0; - }); - var leftMetas = currentPresence.metas.filter(function (m) { - return newRefs.indexOf(m.phx_ref) < 0; - }); - if (joinedMetas.length > 0) { - joins[key] = newPresence; - joins[key].metas = joinedMetas; - } - if (leftMetas.length > 0) { - leaves[key] = _this14.clone(currentPresence); - leaves[key].metas = leftMetas; - } - } else { - joins[key] = newPresence; - } - }); - return this.syncDiff(state, { joins: joins, leaves: leaves }, onJoin, onLeave); - }, - syncDiff: function syncDiff(currentState, _ref2, onJoin, onLeave) { - var joins = _ref2.joins, - leaves = _ref2.leaves; - - var state = this.clone(currentState); - if (!onJoin) { - onJoin = function onJoin() {}; - } - if (!onLeave) { - onLeave = function onLeave() {}; - } - - this.map(joins, function (key, newPresence) { - var currentPresence = state[key]; - state[key] = newPresence; - if (currentPresence) { - var _state$key$metas; - - (_state$key$metas = state[key].metas).unshift.apply(_state$key$metas, _toConsumableArray(currentPresence.metas)); - } - onJoin(key, currentPresence, newPresence); - }); - this.map(leaves, function (key, leftPresence) { - var currentPresence = state[key]; - if (!currentPresence) { - return; - } - var refsToRemove = leftPresence.metas.map(function (m) { - return m.phx_ref; - }); - currentPresence.metas = currentPresence.metas.filter(function (p) { - return refsToRemove.indexOf(p.phx_ref) < 0; - }); - onLeave(key, currentPresence, leftPresence); - if (currentPresence.metas.length === 0) { - delete state[key]; - } - }); - return state; - }, - list: function list(presences, chooser) { - if (!chooser) { - chooser = function chooser(key, pres) { - return pres; - }; - } - - return this.map(presences, function (key, presence) { - return chooser(key, presence); - }); - }, - - - // private - - map: function map(obj, func) { - return Object.getOwnPropertyNames(obj).map(function (key) { - return func(key, obj[key]); - }); - }, - clone: function clone(obj) { - return JSON.parse(JSON.stringify(obj)); - } -}; - -/** - * - * Creates a timer that accepts a `timerCalc` function to perform - * calculated timeout retries, such as exponential backoff. - * - * ## Examples - * - * ```javascript - * let reconnectTimer = new Timer(() => this.connect(), function(tries){ - * return [1000, 5000, 10000][tries - 1] || 10000 - * }) - * reconnectTimer.scheduleTimeout() // fires after 1000 - * reconnectTimer.scheduleTimeout() // fires after 5000 - * reconnectTimer.reset() - * reconnectTimer.scheduleTimeout() // fires after 1000 - * ``` - * @param {Function} callback - * @param {Function} timerCalc - */ - -var Timer = function () { - function Timer(callback, timerCalc) { - _classCallCheck(this, Timer); - - this.callback = callback; - this.timerCalc = timerCalc; - this.timer = null; - this.tries = 0; - } - - _createClass(Timer, [{ - key: "reset", - value: function reset() { - this.tries = 0; - clearTimeout(this.timer); - } - - /** - * Cancels any previous scheduleTimeout and schedules callback - */ - - }, { - key: "scheduleTimeout", - value: function scheduleTimeout() { - var _this15 = this; - - clearTimeout(this.timer); - - this.timer = setTimeout(function () { - _this15.tries = _this15.tries + 1; - _this15.callback(); - }, this.timerCalc(this.tries + 1)); - } - }]); - - return Timer; -}(); - -}))); diff --git a/priv/static/robots.txt b/priv/static/robots.txt deleted file mode 100644 index 3c9c7c0..0000000 --- a/priv/static/robots.txt +++ /dev/null @@ -1,5 +0,0 @@ -# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file -# -# To ban all spiders from the entire site uncomment the next two lines: -# User-agent: * -# Disallow: / diff --git a/test/zero_phoenix_web/controllers/page_controller_test.exs b/test/zero_phoenix_web/controllers/page_controller_test.exs deleted file mode 100644 index 9f9163f..0000000 --- a/test/zero_phoenix_web/controllers/page_controller_test.exs +++ /dev/null @@ -1,8 +0,0 @@ -defmodule ZeroPhoenixWeb.PageControllerTest do - use ZeroPhoenixWeb.ConnCase - - test "GET /", %{conn: conn} do - conn = get conn, "/" - assert html_response(conn, 200) =~ "Welcome to Phoenix!" - end -end diff --git a/test/zero_phoenix_web/controllers/person_controller_test.exs b/test/zero_phoenix_web/controllers/person_controller_test.exs deleted file mode 100644 index bd250fa..0000000 --- a/test/zero_phoenix_web/controllers/person_controller_test.exs +++ /dev/null @@ -1,43 +0,0 @@ -defmodule ZeroPhoenixWeb.PersonController do - use ZeroPhoenixWeb, :controller - - alias ZeroPhoenix.Account - alias ZeroPhoenix.Account.Person - - action_fallback ZeroPhoenixWeb.FallbackController - - def index(conn, _params) do - people = Account.list_people() - render(conn, "index.json", people: people) - end - - def create(conn, %{"person" => person_params}) do - with {:ok, %Person{} = person} <- Account.create_person(person_params) do - conn - |> put_status(:created) - |> put_resp_header("location", Routes.person_path(conn, :show, person)) - |> render("show.json", person: person) - end - end - - def show(conn, %{"id" => id}) do - person = Account.get_person!(id) - render(conn, "show.json", person: person) - end - - def update(conn, %{"id" => id, "person" => person_params}) do - person = Account.get_person!(id) - - with {:ok, %Person{} = person} <- Account.update_person(person, person_params) do - render(conn, "show.json", person: person) - end - end - - def delete(conn, %{"id" => id}) do - person = Account.get_person!(id) - - with {:ok, %Person{}} <- Account.delete_person(person) do - send_resp(conn, :no_content, "") - end - end -end From 119582f95916edcfdaceb44a9937e27ed50cf5ed Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Tue, 14 Dec 2021 19:11:18 -0800 Subject: [PATCH 05/16] Upgrade to Elixir 1.13.1 and update docs. (#52) --- README.md | 4 ++-- dev/support/seeds.ex | 4 ++-- mix.exs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ae63c89..34da69a 100644 --- a/README.md +++ b/README.md @@ -272,7 +272,7 @@ Note: This tutorial was updated on macOS 11.6.1. reset() # - # people + # create people # me = @@ -308,7 +308,7 @@ Note: This tutorial was updated on macOS 11.6.1. }) # - # friendships + # create friendships # me diff --git a/dev/support/seeds.ex b/dev/support/seeds.ex index 549caee..eb3d36c 100644 --- a/dev/support/seeds.ex +++ b/dev/support/seeds.ex @@ -10,7 +10,7 @@ defmodule ZeroPhoenix.Seeds do reset() # - # people + # create people # me = @@ -46,7 +46,7 @@ defmodule ZeroPhoenix.Seeds do }) # - # friendships + # create friendships # me diff --git a/mix.exs b/mix.exs index 8eb1c38..98921e4 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule ZeroPhoenix.Mixfile do [ app: :zero_phoenix, version: "2.7.2", - elixir: "~> 1.13.0", + elixir: "~> 1.13.1", elixirc_paths: elixirc_paths(Mix.env()), compilers: [:gettext] ++ Mix.compilers(), start_permanent: Mix.env() == :prod, From 00712a70a0a4ce6a55df9174953bfdefbd8ff45e Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Wed, 15 Dec 2021 14:31:05 -0800 Subject: [PATCH 06/16] Update to Erlang 24.2. (#53) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 34da69a..15c107c 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ The purpose of this example is to provide details as to how one would go about u - Elixir 1.13.0 or newer -- Erlang 24.1.7 or newer +- Erlang 24.2 or newer - Phoenix 1.6.2 or newer - PostgreSQL 14.0 or newer -Note: This tutorial was updated on macOS 11.6.1. +Note: This tutorial was updated on macOS 11.6.2. ## Communication From a987296f8dd0b37b4a0f22dd83d4076f625dbdea Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Wed, 15 Dec 2021 14:34:29 -0800 Subject: [PATCH 07/16] Upgrade docs to use Phoenix 1.6.4. (#54) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 15c107c..665428a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The purpose of this example is to provide details as to how one would go about u - Erlang 24.2 or newer -- Phoenix 1.6.2 or newer +- Phoenix 1.6.4 or newer - PostgreSQL 14.0 or newer From a0ffd1bdb31f19cfa55633082cab71399da7245b Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Fri, 17 Dec 2021 16:12:38 -0800 Subject: [PATCH 08/16] Fix routing and associated docs. (#55) --- README.md | 30 +++++++++++++++++++++++------- lib/zero_phoenix_web/router.ex | 18 ++++++++++-------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 665428a..7d34421 100644 --- a/README.md +++ b/README.md @@ -482,19 +482,35 @@ Note: This tutorial was updated on macOS 11.6.2. end ``` -22. add route for mounting the GraphiQL browser endpoint: +22. add routes for our GraphQL API and GraphiQL browser endpoints: `lib/zero_phoenix_web/router.ex`: + replace + ```elixir - scope "/graphiql" do + scope "/api", ZeroPhoenixWeb do pipe_through :api + end + ``` + + with + + ``` + scope "/" do + pipe_through :api + + if Mix.env() in [:dev, :test] do + forward "/graphiql", + Absinthe.Plug.GraphiQL, + schema: ZeroPhoenixWeb.Graphql.Schema, + json_codec: Jason, + interface: :playground + end - forward "/", - Absinthe.Plug.GraphiQL, - schema: ZeroPhoenixWeb.Graphql.Schema, - json_codec: Jason, - interface: :playground + forward "/graphql", + Absinthe.Plug, + schema: ZeroPhoenixWeb.Graphql.Schema end ``` diff --git a/lib/zero_phoenix_web/router.ex b/lib/zero_phoenix_web/router.ex index 092ca19..c37be6b 100644 --- a/lib/zero_phoenix_web/router.ex +++ b/lib/zero_phoenix_web/router.ex @@ -8,15 +8,17 @@ defmodule ZeroPhoenixWeb.Router do scope "/" do pipe_through :api + if Mix.env() in [:dev, :test] do + forward "/graphiql", + Absinthe.Plug.GraphiQL, + schema: ZeroPhoenixWeb.Graphql.Schema, + json_codec: Jason, + interface: :playground + end + forward "/graphql", - Absinthe.Plug, - schema: ZeroPhoenixWeb.Graphql.Schema - - forward "/graphiql", - Absinthe.Plug.GraphiQL, - schema: ZeroPhoenixWeb.Graphql.Schema, - json_codec: Jason, - interface: :playground + Absinthe.Plug, + schema: ZeroPhoenixWeb.Graphql.Schema end # Enables LiveDashboard only for development From 62ad49aae92595a890dfcba53c43081674dab9f2 Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Sat, 18 Dec 2021 22:19:18 -0800 Subject: [PATCH 09/16] Upgrade docs to use Elixir 1.13.1. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d34421..bcff29c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The purpose of this example is to provide details as to how one would go about u ## Software requirements -- Elixir 1.13.0 or newer +- Elixir 1.13.1 or newer - Erlang 24.2 or newer From 760928a4b0a5c2bfdb1a4f94706ffccc3316926e Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Mon, 20 Dec 2021 23:10:05 -0800 Subject: [PATCH 10/16] Bump to app 3.3.4. (#56) --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 98921e4..e3405ce 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule ZeroPhoenix.Mixfile do def project do [ app: :zero_phoenix, - version: "2.7.2", + version: "3.3.4", elixir: "~> 1.13.1", elixirc_paths: elixirc_paths(Mix.env()), compilers: [:gettext] ++ Mix.compilers(), From 28af508c969f497ed079911282f453408e3026a8 Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Tue, 21 Dec 2021 20:53:14 -0800 Subject: [PATCH 11/16] Upgrade docs and associated implementation code. (#57) --- README.md | 22 +++++++++++++--------- lib/zero_phoenix_web/graphql/schema.ex | 10 ++++++---- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index bcff29c..fe1b99c 100644 --- a/README.md +++ b/README.md @@ -425,21 +425,25 @@ Note: This tutorial was updated on macOS 11.6.2. defmodule ZeroPhoenixWeb.Graphql.Schema do use Absinthe.Schema - import_types ZeroPhoenix.Graphql.Types.Person + import_types(ZeroPhoenixWeb.Graphql.Types.Person) - alias ZeroPhoenix.Repo + alias ZeroPhoenix.Account.Person + alias ZeroPhoenix.Account query do field :person, type: :person do - arg :id, non_null(:id) - resolve fn %{id: id}, _info -> - case ZeroPhoenix.Person|> Repo.get(id) do - nil -> {:error, "Person id #{id} not found"} - person -> {:ok, person} + arg(:id, non_null(:id)) + + resolve(fn %{id: id}, _info -> + case Account.get_person(id) do + %Person{} = person -> + {:ok, person} + + _error -> + {:error, "Person id #{id} not found"} end - end + end) end - end end ``` diff --git a/lib/zero_phoenix_web/graphql/schema.ex b/lib/zero_phoenix_web/graphql/schema.ex index b131096..7d9d318 100644 --- a/lib/zero_phoenix_web/graphql/schema.ex +++ b/lib/zero_phoenix_web/graphql/schema.ex @@ -3,7 +3,6 @@ defmodule ZeroPhoenixWeb.Graphql.Schema do import_types(ZeroPhoenixWeb.Graphql.Types.Person) - alias ZeroPhoenix.Repo alias ZeroPhoenix.Account.Person alias ZeroPhoenix.Account @@ -12,9 +11,12 @@ defmodule ZeroPhoenixWeb.Graphql.Schema do arg(:id, non_null(:id)) resolve(fn %{id: id}, _info -> - case Person |> Repo.get(id) do - nil -> {:error, "Person id #{id} not found"} - person -> {:ok, person} + case Account.get_person(id) do + %Person{} = person -> + {:ok, person} + + _error -> + {:error, "Person id #{id} not found"} end end) end From f98c377f5128fed59f5ce6851796ce222db71406 Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Fri, 24 Dec 2021 20:46:23 -0800 Subject: [PATCH 12/16] Update to PostgreSQL 14.1. (#58) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fe1b99c..70fe1d5 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ The purpose of this example is to provide details as to how one would go about u - Phoenix 1.6.4 or newer -- PostgreSQL 14.0 or newer +- PostgreSQL 14.1 or newer Note: This tutorial was updated on macOS 11.6.2. From 8ef31f08c8548f1dc2b04a36698b63d698c013fb Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Sun, 9 Jan 2022 14:26:27 -0800 Subject: [PATCH 13/16] Upgrade license information. (#59) --- LICENSE.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index e949107..d8dcf79 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright © 2018 - 2021 Conrad Taylor. All Rights Reserved. +Copyright © 2018 - 2022 Conrad Taylor. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 70fe1d5..5c48508 100644 --- a/README.md +++ b/README.md @@ -587,4 +587,4 @@ Zero to GraphQL Using Elixir is released under the [MIT license](./LICENSE.md). ## Copyright -copyright:: (c) Copyright 2018 - 2021 Conrad Taylor. All Rights Reserved. +copyright:: (c) Copyright 2018 - 2022 Conrad Taylor. All Rights Reserved. From 621cce7ba9976149884d43c010a9b8f436f871d4 Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Fri, 14 Jan 2022 01:20:07 -0800 Subject: [PATCH 14/16] Upgrade-to-elixir-1.13.2-otp-24 (#60) --- README.md | 2 +- mix.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5c48508..e5d2a27 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The purpose of this example is to provide details as to how one would go about u ## Software requirements -- Elixir 1.13.1 or newer +- Elixir 1.13.2 or newer - Erlang 24.2 or newer diff --git a/mix.exs b/mix.exs index e3405ce..e01f5ff 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule ZeroPhoenix.Mixfile do [ app: :zero_phoenix, version: "3.3.4", - elixir: "~> 1.13.1", + elixir: "~> 1.13.2", elixirc_paths: elixirc_paths(Mix.env()), compilers: [:gettext] ++ Mix.compilers(), start_permanent: Mix.env() == :prod, From 2c219ec6ec705a3ba5d09264ed44eb55ed5b85d4 Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Mon, 24 Jan 2022 20:56:49 -0800 Subject: [PATCH 15/16] Upgrade to Absinthe 1.7.0. --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index a935bf6..bca1b87 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "absinthe": {:hex, :absinthe, "1.6.6", "d4b3d87c868264edf47fbf9c152155f31e8d26c370607f5fe92f6e106d190b74", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a03e18478b19bdf81ed1eef9b0853edf4496a080c2048ed17993dc945a90bedc"}, + "absinthe": {:hex, :absinthe, "1.7.0", "36819e7b1fd5046c9c734f27fe7e564aed3bda59f0354c37cd2df88fd32dd014", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "566a5b5519afc9b29c4d367f0c6768162de3ec03e9bf9916f9dc2bcbe7c09643"}, "absinthe_plug": {:hex, :absinthe_plug, "1.5.8", "38d230641ba9dca8f72f1fed2dfc8abd53b3907d1996363da32434ab6ee5d6ab", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bbb04176647b735828861e7b2705465e53e2cf54ccf5a73ddd1ebd855f996e5a"}, "castore": {:hex, :castore, "0.1.13", "ccf3ab251ffaebc4319f41d788ce59a6ab3f42b6c27e598ad838ffecee0b04f9", [:mix], [], "hexpm", "a14a7eecfec7e20385493dbb92b0d12c5d77ecfd6307de10102d58c94e8c49c0"}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, From 331f2a5d7efa3062d5fbcee4416ae451678f10c7 Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Tue, 25 Jan 2022 21:30:36 -0800 Subject: [PATCH 16/16] Upgrade software requirements. --- README.md | 2 +- mix.exs | 2 +- mix.lock | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e5d2a27..1808e03 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The purpose of this example is to provide details as to how one would go about u - Elixir 1.13.2 or newer -- Erlang 24.2 or newer +- Erlang 24.2.1 or newer - Phoenix 1.6.4 or newer diff --git a/mix.exs b/mix.exs index e01f5ff..a47258f 100644 --- a/mix.exs +++ b/mix.exs @@ -34,7 +34,7 @@ defmodule ZeroPhoenix.Mixfile do # Type `mix help deps` for examples and options. defp deps do [ - {:phoenix, "~> 1.6.4"}, + {:phoenix, "~> 1.6.6"}, {:phoenix_ecto, "~> 4.4"}, {:ecto_sql, "~> 3.7.1"}, {:postgrex, "~> 0.15.9"}, diff --git a/mix.lock b/mix.lock index bca1b87..a1261f5 100644 --- a/mix.lock +++ b/mix.lock @@ -19,14 +19,14 @@ "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, "nimble_parsec": {:hex, :nimble_parsec, "1.2.0", "b44d75e2a6542dcb6acf5d71c32c74ca88960421b6874777f79153bbbbd7dccc", [:mix], [], "hexpm", "52b2871a7515a5ac49b00f214e4165a40724cf99798d8e4a65e4fd64ebd002c1"}, - "phoenix": {:hex, :phoenix, "1.6.4", "bc9a757f0a4eac88e1e3501245a6259e74d30970df8c072836d755608dbc4c7d", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b6cb3f31e3ea1049049852703eca794f7afdb0c1dc111d8f166ba032c103a80"}, + "phoenix": {:hex, :phoenix, "1.6.6", "281c8ce8dccc9f60607346b72cdfc597c3dde134dd9df28dff08282f0b751754", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "807bd646e64cd9dc83db016199715faba72758e6db1de0707eef0a2da4924364"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, - "phoenix_html": {:hex, :phoenix_html, "3.1.0", "0b499df05aad27160d697a9362f0e89fa0e24d3c7a9065c2bd9d38b4d1416c09", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0c0a98a2cefa63433657983a2a594c7dee5927e4391e0f1bfd3a151d1def33fc"}, + "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"}, "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.1", "fb94a33c077141f9ac7930b322a7a3b99f9b144bf3a08dd667b9f9aaf0319889", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.1", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "6faf1373e5846c8ab68c2cf55cfa5c196c1fbbe0c72d12a4cdfaaac6ef189948"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"}, "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.5", "63f52a6f9f6983f04e424586ff897c016ecc5e4f8d1e2c22c2887af1c57215d8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.5.9 or ~> 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c5586e6a3d4df71b8214c769d4f5eb8ece2b4001711a7ca0f97323c36958b0e3"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"}, - "phoenix_view": {:hex, :phoenix_view, "1.0.0", "fea71ecaaed71178b26dd65c401607de5ec22e2e9ef141389c721b3f3d4d8011", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "82be3e2516f5633220246e2e58181282c71640dab7afc04f70ad94253025db0c"}, + "phoenix_view": {:hex, :phoenix_view, "1.1.0", "149f053830ec3c19a2a8a67c208885a26e4c2b92cc4a9d54e03b633d68ef9add", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "dd219f768b3d97a224ed11e8a83f4fd0f3bd490434d3950d7c51a2e597a762f1"}, "plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"}, "plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"}, "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"},