[
  {
    "path": ".gitattributes",
    "content": "api-doc/* -diff linguist-vendored\n"
  },
  {
    "path": ".github/scripts/build.sh",
    "content": "#!/bin/bash\n\n\n# This script is run by GitHub Actions to build the cross-platform uberjar.\n\n# If this is a full release, tweak the project to generate the correct API doc source links.\nif [[ $release_snapshot == \"false\" ]]\nthen\n    # Update codox source link\n    prefix=\"\\/github.com\\/Deep-Symmetry\\/afterglow\\/blob\\/\"\n    sourceswap=\"s/${prefix}main/${prefix}${git_version}/g\"\n    mv project.clj project.clj.old\n    sed \"${sourceswap}\" project.clj.old > project.clj\n    rm -f project.clj.old\nfi\n\n# Make sure Antora is installed\nnpm install\n\n# Now that the project has been tweaked if needed, do the actual build\nlein uberjar\n\n# Rename the output jar to where we want it.\nmv target/afterglow.jar \"./$uberjar_name\"\n"
  },
  {
    "path": ".github/scripts/build_guide.sh",
    "content": "#!/usr/bin/env bash\n\n# This script is run by GitHub Actions to build the\n# Antora site hosting the developer guide.\n\nset -e  # Exit if any command fails.\n\n# There is no point in doing this if we lack the SSH key to publish the guide.\nif [ \"$GUIDE_SSH_KEY\" != \"\" ]; then\n\n    # Set up node dependencies; probably redundant thanks to main workflow, but just in case...\n    npm install\n\n    # Build the cloud version of the documentation site. Note that the API docs are already\n    # built in, from the stage of building the uberjar.\n    npm run hosted-docs\n\n    # Make sure there are no broken links in the versions we care about.\n    curl https://htmltest.wjdp.uk | bash\n    bin/htmltest\n\n    # Publish the user guide to the right place on the Deep Symmetry web server.\n    rsync -avz doc/build/site/ guides@deepsymmetry.org:/var/www/guides/afterglow/\n\nelse\n    echo \"No SSH key present, not building user guide.\"\nfi\n"
  },
  {
    "path": ".github/workflows/uberjar.yml",
    "content": "name: Create überjar\n\non:\n  push:\n    branches:\n      - main\n\nenv:\n  initial_description: |\n    :construction: This is pre-release code for people who want to help test [what is going into the next release](https://github.com/Deep-Symmetry/afterglow/blob/master/CHANGELOG.md).\n\n    > Don’t download this if you aren’t comfortable testing code while it is under active development! Instead, look at the [latest release](https:///github.com/Deep-Symmetry/afterglow/releases/latest).\n\n    :calendar: **Ignore the “release date” above!** Because this is a snapshot release, the executables below (you may need to click to expand the Assets) will change frequently—whenever new code is pushed to the project—so you will want to _download the latest version every time you work with one_. The date you see _on each asset row_ shows you when it was last updated. Source code archive assets are not useful for snapshot releases, they will always reflect the state of the project when the snapshots began.\n\njobs:\n  build_uberjar:\n    name: Build cross-platform überjar\n    runs-on: ubuntu-latest\n    if: \"!contains(github.event.head_commit.message, '[skip ci]')\"\n\n    steps:\n    - name: Check out main branch\n      uses: actions/checkout@v3\n\n    - name: Install SSH Key\n      uses: shimataro/ssh-key-action@v2\n      with:\n        key: ${{ secrets.GUIDE_SSH_KEY }}\n        known_hosts: 'deepsymmetry.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINfnL8k99MCOHLciHb7czxFCCvF3lbmY2ase2VhdvCTN'\n\n    - name: Prepare Java\n      uses: actions/setup-java@v3\n      with:\n        java-version: '17'\n        distribution: 'corretto'\n\n    - name: Install clojure tools\n      uses: DeLaGuardo/setup-clojure@13.0\n      with:\n        lein: 2.11.2\n\n    - name: Determine version being built\n      uses: Deep-Symmetry/github-version-action@v1\n      with:\n        tag-var-name: release_tag\n\n    - name: Determine überjar name from git version, and snapshot status\n      run: |\n        echo \"uberjar_name=afterglow-$git_version.jar\" >> $GITHUB_ENV\n        if [[ $release_tag =~ .*-SNAPSHOT ]]\n        then\n          echo \"release_snapshot=true\" >> $GITHUB_ENV\n        else\n          echo \"release_snapshot=false\" >> $GITHUB_ENV\n        fi\n\n    - name: Cache Leiningen dependencies\n      uses: actions/cache@v3\n      with:\n        path: ~/.m2/repository\n        key: ${{ runner.os }}-lein-${{ hashFiles('**/project.clj') }}\n        restore-keys: |\n          ${{ runner.os }}-lein-\n\n    - name: Install dependencies, forcing updates of snapshots\n      run: lein -U deps\n\n    - name: Install antora for building user guide\n      run: npm install\n\n    - name: Build überjar\n      run: bash .github/scripts/build.sh\n\n    - name: Upload überjar\n      if: success()\n      uses: Xotl/cool-github-releases@v1\n      with:\n        mode: update\n        tag_name: ${{ env.release_tag }}\n        isPrerelease: ${{ env.release_snapshot }}\n        replace_assets: ${{ env.release_snapshot }}\n        assets: ${{ env.uberjar_name }}\n        github_token: ${{ github.token }}\n        initial_mrkdwn: ${{ env.initial_description }}\n\n    - name: Cache htmltest results\n      uses: actions/cache@v3\n      with:\n        path: tmp/.htmltest\n        key: ${{ runner.os }}-htmltest\n\n    - name: Build and publish user guide\n      env:\n        GUIDE_SSH_KEY: ${{ secrets.GUIDE_SSH_KEY }}\n      run: bash .github/scripts/build_guide.sh\n"
  },
  {
    "path": ".gitignore",
    "content": "*.class\n*.jar\n.hg/\n.hgignore\n/.cider_history\n/.dir-locals.el\n/.env\n/.lein-*\n/.nrepl-port\n/checkouts\n/classes\n/doc/build\n/gh-pages\n/node_modules\n/pom.xml\n/pom.xml.asc\n/research\n/target\n/resources/afterglow/version.edn\nlogs/*.log*\n.idea/\n*.iml\n*.ipr\n*.iws\n\n# Local Netlify folder\n.netlify\n"
  },
  {
    "path": ".htmltest.yml",
    "content": "DirectoryPath: \"doc/build/site\"\nIgnoreURLs:\n- \"github.com/Deep-Symmetry/afterglow/blob/\"\n- \"support.native-instruments.com/hc/\"\n- \"help.ableton.com/hc/\"\n- \"^http://localhost:9090\"\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nThis change log follows the conventions of\n[keepachangelog.com](http://keepachangelog.com/).\n\n## [Unreleased][unreleased]\n\n### Fixed\n\n- Afterglow would crash when told to convert a QLC+ fixture definition\n  in the current working directory (with no path component),\n  [#72](https://github.com/Deep-Symmetry/afterglow/issues/72).\n- External links were not being checked in the developer guide, but\n  even so the link checker plugin ended up failing. Switched to\n  htmltest, which is used on other Deep Symmetry projects, enabled\n  external link checking (although not yet for GitHub source links\n  because they are hitting rate limits, there are so many of them),\n  and fixed a great many broken/stale links.\n\n### Added\n\n- A new effect builder, `wrap-fade-in-out`, to make it easy to build\n  effects that fade in when you start them, and out when you tell them\n  to end.\n- When resolving dynamic parameters, resolution will be repeated if\n  the result was still a dynamic parameter. This allows, for example,\n  oscillated parameters to be stored in show variable parameters and\n  swapped out during the lifetime of a cue. Resolving the variable\n  parameter will first obtain the oscillated parameter, which will be\n  resolved again for the appropriate number based on the show\n  metronome snapshot.\n- The `variable-effect` function now takes optional keyword arguments\n  which allow a more meaningful effect name to be specified, and can\n  suppress the resolution of dynamic parameters, allowing the raw\n  parameter itself to be set into a show variable while the effect is\n  active, so that it can be used by other effects.\n\n\n## [0.2.5] - 2022-01-12\n\n### Fixed\n\n- The built-in converter for QLC+ fixture definitions (`.qxf` files)\n  now supports the new XML schema used by QLC+.\n- There were some off-by-one errors in the metronome, which canceled\n  each other out in the places they were used, but would have caused\n  problems in new situations. They were discovered while porting the\n  logic to Java for the\n  [electro](https://github.com/Deep-Symmetry/electro) library.\n- Abrupt tempo changes could cause the metronome to jump to the wrong\n  place, even the wrong beat. This is now prevented, leaving you at\n  the exact same place in the beat grid before and after any tempo\n  change.\n- The metronome better handles negative time, and has some improved\n  documentation.\n\n### Added\n\n- The detailed documentation has been reorganized as a Developer Guide\n  and is now built by [Antora](http://antora.org) to provide easier\n  navigation and a more readable presentation.\n- The Developer Guide is now available through the built-in web server\n  even if you do not have a connection to the internet.\n\n### Changed\n\n- Upgraded to version 2.0 of the Eclipse Publice License.\n\n## [0.2.4] - 2017-04-18\n\n### Fixed\n\n- The pixels of the Blizzard Pixellicious were flipped over the X\n  axis.\n- The web interface needed to have the Beat Link `DeviceFinder`\n  started before trying to render the UI, or it would only partially\n  render because of an exception when trying to use it.\n- Calling `show/patch-fixture!` returned a huge recursive data\n  structure which would cause the REPL to choke trying to print it,\n  especially in an editor. Now it just returns the key identifying the\n  fixture that was patched.\n\n### Added\n\n- A new command-line argument, `-n`, tells afterglow not to try to\n  launch a web browser when it is invoked from the command-line. This\n  is to enable headless operation on small servers which lack a\n  windowing environment.\n\n## [0.2.3] - 2016-06-09\n\n### Fixed\n\n- Rich controller bindings (Ableton Push and Novation Launchpad\n  families) were not being successfully auto-bound under Windows\n  because of significant differences in the way their port names were\n  assigned on that platform. Fixing that was surprisingly tricky, but\n  it has been done. I look forward to someone being able to help test\n  this under Linux now.\n- The graphical display on the Ableton Push 2 could not be connected\n  under Windows due to an issue in the Wayang library. That library\n  has been fixed, and the new version is embedded in this release.\n\n## [0.2.2] - 2016-05-30\n\n### Added\n\n- The CoreMIDI4J library is now embedded within Afterglow, so it does\n  not need to be separately installed by the user for MIDI to work\n  properly on Mac OS X. If you have a separate installation of\n  CoreMIDI4J in `/Library/Java/Extensions`, you should remove it to\n  avoid version conflicts with newer versions shipped with Afterglow.\n- Afterglow now uses the new beat-link library to synchronize with\n  Pioneer DJ Link equipment, which enables several new features such\n  as tracking the master player, synching to bars as well as beats,\n  and having the metronome reflect the current track position.\n- Holding down Shift while pressing a scroll arrow on the Launchpad\n  family of controllers now moves you as far as possible in that\n  direction, as it did on the Push 2.\n- Head information is now available to channel effects (which include\n  dimmer effects), so they can use dynamic parameters with spatial\n  components, just like all the other kinds of effects can.\n\n### Fixed\n\n- When updating large sections of the cue grid colors, we no longer\n  send all of them at once, because this was overflowing buffers on\n  the Push 2 and losing some updates. Instead we send them in batches,\n  ending each batch with a query, and wait for the response so we know\n  the controller has caught up.\n- Updated to the latest release of the Wayang library for drawing on\n  the Push 2 display, which solves an issue that prevented the display\n  from working under Window.\n\n### Changed\n\n- The hue and saturation gauges on the Push 2 are now drawn using a\n  masking image so they can be anti-aliased to the same outline shape\n  as the other gauges, and look much cleaner.\n- Boolean gauges on the Push 2 are drawn in red or green for No and\n  Yes values, and the transition between values is animated, to make\n  it easier to see what is happening, and to relate it to the encoder\n  rotation.\n- Assigner target IDs can now have arbitrary structure appropriate to\n  the needs of the assigner implementation, rather than being forced\n  into keywords as they used to be. For the most part, they are\n  integers (head IDs), some are tuples (universe ID and channel pairs\n  for channel assigners, head ID and function keywords for head\n  function assigners, other things for extensions like Beyond laser\n  show assigners).\n\n\n## [0.2.1] - 2016-04-03\n\n### Added\n\n- The web and Push interfaces now offer a way to save adjusted cue\n  variable values, so the next time the cue is launched the saved\n  values are used.\n- Show operators can also create \"Macros\" by selecting a group of\n  running cues and choosing an unused cue grid cell. This will create\n  a new compound cue in the cell which will re-run all of the cues\n  they specified, with the same parameters they had when the macro was\n  created, whenever it is run. The compound cue will end all of its\n  component cues when you end it, and will end itself if they end\n  independently.\n- You can now right-click on cues in the web interface to bring up a\n  menu of actions. The menu so far offers just the ability to delete\n  the cue if there is one there (this can clean up macros you no\n  longer want, for example).\n- The Ableton Push 2 is now supported as a rich grid control\n  interface, taking full advantage of its color graphic display.\n- Support for other members of the Novation Launchpad family of grid\n  controllers has been implemented:\n  - Launchpad Mini\n  - Launchpad S (untested, but the Mini, which works, is based on the S)\n  - Launchpad Mk2\n- The identity of grid controllers is verified before binding to them,\n  by sending a MIDI Device Inquiry message and inspecting the\n  response.\n- The auto-bind mechanism has been improved so much that the sample\n  show can now simply turn it on to fully automate the process of\n  detecting and binding to any compatible grid controllers that appear\n  in the MIDI environment, with no user or configuration effort.\n- Direction and aim parameters can now be transformed by a dynamic\n  Java3D `Transform3D` parameter to create kaleidoscopic looks with\n  groups of lights.\n- A new `confetti` effect which assigns random colors (and optionally\n  aim points) to groups of lights at intervals.\n- A new `pinstripes` effect which can alternate stripes of color\n  across fixtures.\n- Incoming MIDI System Exclusive messages can now be received and\n  delivered to handlers.\n- Cue variables can now be Booleans, to support cues which want to be\n  able to adjust the direction of a sawtooth oscillator while running.\n- The dimmer oscillator cues created in the sample show now include\n  Min and Max variables so the range over which the dimmer oscillates\n  can be adjusted.\n- The Ableton Push mapping now lets you scroll through all variables\n  assigned to a cue so you can see and adjust more than the first two.\n- You can now use the touch strip on the Ableton Push to immediately\n  jump to any part of the legal value range when adjusting a numeric,\n  boolean, or color cue variable, BPM, or the Dimmer Grand Master. The\n  LEDs on the touch strip also reflect the current value of the\n  variable being adjusted.\n- You can use the keyboard arrow keys to navigate around the cue grid\n  when using the web UI, as long as no input element is focused.\n- You can use the space bar to tap tempo when using the web UI, as\n  long as no input element is focused.\n- Cues can have visualizer creation functions assigned to them, so\n  they can provide animated visualizer displays on the Push 2.\n\n### Fixed\n\n- Fixtures which had no channels assigned to the fixture itself, but\n  only to heads (like Blizzard's Pixellicious pixel grids) could not\n  be patched properly to shows, because the code checking for address\n  conflicts was not able to figure out the universe assigned to them.\n- Chases containing only scenes would end instantly rather than\n  running, because of some assumptions they were making about how the\n  effect protocol was implemented, which scenes violated. Chases are\n  now more robust.\n- The low-level tempo tap handler was already more useful than I was\n  giving it credit for, suitable for both aligning to the current beat\n  as well as adjusting the tempo if you hit it three or more times, so\n  the shift key can be used to adjust the down beat even on\n  unsynchronized shows. This makes it much easier to keep the lights\n  in sync manually!\n- The color wheel is only applied when a color has sufficient\n  saturation for it to make sense. The threshold can be adjusted by\n  setting the show variable `:color-wheel-min-saturation`.\n- Floating-point cue variables now stay rounded to the specified\n  resolution when adjusting them on the Push.\n- Effects with Unicode characters in them were crashing the Ableton\n  Push display code, since it only handles single byte ASCII plus a\n  handful of special symbols used for drawing interface elements. Now\n  unprintable characters are substituted with an ellipsis symbol\n  rather than crashing.\n- The entire Push display was being redrawn on each frame of\n  user-interface updates, and all text-labeled button states were\n  being set, even if they had not changed from the previous frame.\n  These redundant messages are no longer sent, and MIDI messages are\n  sent to the Push only when text and button states actually need to\n  change.\n- The slider tooltips for cue variables in the web UI were getting in\n  the way of adjusting the sliders because they would appear when the\n  mouse was over the tooltip, not just the slider track. They could\n  also not be seen on mobile devices. So they have been turned off\n  entirely in favor of always-visible value labels.\n- The documentation link in the web interface now takes you to the\n  proper version-specific tag of the documentation if it is a release\n  build. Snapshot builds take you to `master`.\n- The nav bar in the show control web page is now compressed to better\n  fit mobile devices, since it can be used on the iPad Pro.\n- Extraneous errors were being logged in the browser console because\n  we were sometimes returning spurious error responses for cue\n  variable updates, saves, and clears.\n- The end effect buttons and cue variable scroll buttons under\n  the text area on the Ableton Push were not affecting the proper\n  effects when the effect view was scrolled back from the most recent.\n- The effect overflow indicators in the Push text area were not\n  properly disappearing when enough effects ended to render them no\n  longer needed until the user pressed Shift to try to scroll.\n- Under some circumstances the Push mapping could crash when there was\n  no cue associated with an effect.\n- All MIDI event handler functions are now called in a context which\n  properly recovers from exceptions at the level of that individual\n  handler, so other handlers will not be affected.\n- Everywhere that Afterglow was checking whether an argument was\n  callable as a function has been fixed to use the `ifn?` predicate\n  rather than `fn?` since the latter is too restrictive, and only\n  returns `true` for functions explicitly created using `(fn ...)`.\n  That precluded, for example, the idiomatic Clojure approach of using\n  `:x` as a function to extract the _x_ coordinate of a head when\n  defining a spatial parameter.\n\n### Changed\n\n- You no longer need to specify what kind of grid controller you are\n  trying to bind to in advance; the controller manager in\n  `afterglow.controllers` can recognize the supported controllers from\n  their responses to the MIDI Device Inquiry message, and instantiate\n  the appropriate binding. New controller implementations can register\n  themselves when their namespaces are loaded so the controller\n  manager will dispatch to them as needed.\n- The code to gracefully shut down active controller bindings, which\n  was becoming duplicated with every new controller mapping created,\n  has been pulled up into the shared controllers namespace.\n- The code to watch for and automatically bind to a controller when it\n  appears in the MIDI environment has similarly been generalized and\n  pulled into the shared controllers namespace.\n- The ability to register an interest in all events from a specific\n  MIDI device was added, and the controller mapping implementations\n  were updated to take advantage of this, so they no longer need to\n  receive and filter out all the events from other devices.\n- The sample show is becoming a much more practical example of how to\n  layer flexible color and dimmer cues, with good cue variables to add\n  even more dimensions.\n- A lot of repetitive code in the examples namespace was consolidated\n  using helper functions.\n- The `controllers/IOverlay` protocol was expanded to include the\n  ability for an overlay to handle and absorb pitch-bend messages, in\n  preparation for supporting the touch strip on the Ableton Push.\n- The floating-point format for cue variables was changed from `float`\n  to `double` since that is what Clojure actually natively uses.\n- All other `float` values which were created throughout Afterglow\n  were changed to `double` values, since that is what Clojure actually\n  natively uses, and they were getting promoted when used anyway.\n\n## [0.2.0] - 2016-02-02\n\n### Added\n\n- Running effects are now listed on the Show Control page of the Web\n  UI, in descending priority order, with buttons to end them, and\n  controls to adjust cue parameters, including colors.\n- The show's dimmer grand master is now visible and controllable\n  below the cue grid in the web UI.\n- A rich grid controller mapping for the\n  [Novation Launchpad Pro](https://us.novationmusic.com/launch/launchpad-pro#).\n- A rich color picker interface on the Ableton Push for cues with\n  color variables.\n- You can now map sliders and encoders on any MIDI controller to\n  adjust components of a color stored in a show variable (that is,\n  adjust its red, green, and blue values, or its hue, saturation, and\n  lightness).\n- The example global color and strobe cues have been upgraded to take\n  advantage of the new color cue parameters, so their colors can be\n  adjusted on the fly using the web or Push interfaces.\n- The Shift button can be used with Tap Tempo buttons on controllers\n  and the web UI to set the start of a beat, bar, or phrase, depending\n  on the synchronization level of the metronome.\n- Buttons or pads on any MIDI controller can now easily be mapped to\n  act like the smart Tap Tempo and Shift buttons on the Ableton Push\n  and Novation Launchpad.\n- Cues can have animated colors on grid controllers including the web\n  interface, to help remind operators about the effects they launch,\n  or reflect the current value of a color variable on which they are\n  based.\n- When binding a generic MIDI controller to launch a cue, if that\n  controller does not have velocity-sensitive pads, you can assign an\n  explicit velocity to use in the binding, for the purpose of setting\n  any velocity-sensitive cue variables.\n- An explanation of how to bind a MIDI controller to a dimmer master\n  has been added to the mapping documentation.\n- Animated GIFs in the documentation illustrate how the cue user\n  interface works.\n\n### Fixed\n\n- Using dynamic color variables to as inputs for other dynamic color\n  parameters could cause crashes when trying to adjust the incoming\n  color values due to a longstanding subtle bug, which has been fixed.\n- Ordinary MIDI control surfaces were sometimes being mistakenly\n  identified as candidate sources of Tratktor beat phase information,\n  leading to exceptions in the log file. Now only devices sending\n  clock pulses are considered beat phase candidates.\n- Cue colors were improved in the web interface and on the Push to\n  make it easier to see which cues are active, as well as to make the\n  colors more faithful to the cue's intent.\n- The text labels on cues in the web interface are now more legible\n  because they use a contrasting color based on the cell's perceived\n  brightness.\n- Incompatible cues are now identified not just from matching effect\n  keys, but also from their `:end-keys` lists, so the web and\n  controller interfaces provide even more guidance.\n- Launching cues from the web interface was not setting any value for\n  cue variables configured to be velocity sensitive, which was\n  sometimes causing issues. Now the assignment of velocity-adjustable\n  variables happens in the process of launching any cue from the grid,\n  and a default velocity of 127 is assumed if none is specified.\n- The entire frame of a user interface being rendered on a grid\n  controller or the web interface now uses the same metronome\n  snapshot, to represent a consistent point in time.\n- Some testing in a Windows virtual machine revealed issues when\n  working with standard Java Midi implementations (as opposed to\n  CoreMidi4J on the Mac). These were addressed.\n\n### Changed\n\n- Updated to newly-released Clojure 1.8 for improved performance.\n- Deprecated functions were removed:\n  - `afterglow.effects.color/find-rgb-heads` (instead use `afterglow.channels/find-rgb-heads`)\n  - `afterglow.effects.color/has-rgb-heads?` (instead use `afterglow.channels/has-rgb-heads`)\n  - `afterglow.effects.oscillators/sawtooth-beat` (instead use `sawtooth`)\n  - `afterglow.effects.oscillators/sawtooth-bar` (instead use `sawtooth` with `:interval :bar`)\n  - `afterglow.effects.oscillators/sawtooth-phrase` (instead use `sawtooth` with `:interval :phrase`)\n  - `afterglow.effects.oscillators/triangle-beat` (instead use `triangle`)\n  - `afterglow.effects.oscillators/triangle-bar` (instead use `triangle` with `:interval :bar`)\n  - `afterglow.effects.oscillators/triangle-phrase` (instead use `triangle` with `:interval :phrase`)\n  - `afterglow.effects.oscillators/square-beat` (instead use `square`)\n  - `afterglow.effects.oscillators/square-bar` (instead use `square` with `:interval :bar`)\n  - `afterglow.effects.oscillators/square-phrase` (instead use `square` with `:interval :phrase`)\n  - `afterglow.effects.oscillators/sine-beat` (instead use `sine`)\n  - `afterglow.effects.oscillators/sine-bar` (instead use `sine` with `:interval :bar`)\n  - `afterglow.effects.oscillators/sine-phrase` (instead use `sine` with `:interval :phrase`)\n  - `afterglow.effects.params/build-oscillated-param` (instead use\n  `afterglow.effects.oscillators/build-oscillated-param`)\n  - `afterglow.show/add-midi-control-to-cue-mapping` (instead use\n    `afterglow.effects.cues/add-midi-to-cue-mapping`)\n  - `afterglow.show/remove-midi-control-to-cue-mapping` (instead use\n    `afterglow.effects.cues/remove-midi-to-cue-mapping`)\n- The detailed documentation was updated to use attributes to link to the API\n  documentation so it could be linked to its release-specific version.\n- The API documentation was moved into a github-pages branch so\n  versioned snapshots can be kept around.\n- A few functions were newly deprecated to improve the consistency of the API:\n  - `afterglow.effects.cues/add-midi-control-to-cue-mapping` (instead\n    use the more accurately named `add-midi-to-cue-mapping`)\n  - `afterglow.effects.cues/remove-midi-control-to-cue-mapping`\n    (instead use the more accurately named `remove-midi-to-cue-mapping`)\n  - `afterglow.show/remove-midi-control-to-var-mapping`,\n    `afterglow.show/remove-midi-control-to-master-mapping`, and\n    `afterglow.show/remove-midi-control-metronome-mapping` (they are\n    no longer needed, the general-purpose function\n    `afterglow.midi/remove-control-mapping` works instead of each)\n\n## [0.1.6] - 2016-01-11\n\n### Added\n\n- Support for [CoreMIDI4J](https://github.com/DerekCook/CoreMidi4J),\n  to preferentially use MIDI devices returned by this new lightweight\n  open-source Java MIDI service provider implementation for Mac OS X.\n  CoreMIDI4J is compatible with current Java and OS versions, and\n  addresses long-standing defects in the standard Java MIDI\n  implementation, such as support for System Exclusive messages, and\n  reconfiguration of the MIDI environment as devices are connected and\n  disconnected. Afterglow's MIDI implementation now gracefully handles\n  changes in the MIDI environment, cleaning up bindings, synced\n  metronomes, grid controllers, and cue feedback functions associated\n  with devices which no longer exist, and making new devices available\n  for use.\n- MIDI device watchers, which can set up bindings whenever a specified\n  device is connected. These also allow effortless recovery from a\n  temporary disconnection from a device during a show.\n- Code cues, making it easy to trigger arbitrary activity from a cue\n  grid, [issue 34](https://github.com/Deep-Symmetry/afterglow/issues/34).\n- Links to graphs and expanded discussion in the oscillator API docs.\n- Dimmer effects can now work with dimmer function ranges on\n  multipurpose channels as well as full dedicated dimmer channels.\n- Dimmer effects can now also create virtual dimmers for RGB-mixing\n  fixtures that don't have any actual dimmer channels, allowing them\n  to participate as if they did, by modifying the color effects being\n  sent to them.\n- Step parameters can now have interval ratios, like oscillators.\n- When building step parameters, you can now use dynamic parameters as\n  inputs.\n- When mapping a MIDI control to a show variable, you can now supply a\n  custom function to transform the incoming value into whatever you\n  need it to be,\n  [issue 32](https://github.com/Deep-Symmetry/afterglow/issues/32).\n- When mapping a midi control to launch a cue, if your controller\n  supports velocity (and perhaps also aftertouch, or polyphonic key\n  pressure), you can have those values affect cue variables which have\n  been defined as velocity sensitive, in the same way that Ableton\n  Push pads do.\n- A variation of the sparkle effect which uses dimmer channels,\n  [issue 35](https://github.com/Deep-Symmetry/afterglow/issues/35).\n- Some more examples of how to get started working with Afterglow.\n- A variety of other documentation improvements.\n\n### Changed\n\n- Oscillators have been completely redesigned in order to be more\n  flexible and easy to create and work with, and to support dynamic\n  parameters so their configuration can vary over time or location,\n  [issue 9](https://github.com/Deep-Symmetry/afterglow/issues/9). The old\n  oscillator and oscillated parameter functions have been deprecated,\n  and are now stubs wich delegate to the new implementation. They will\n  be removed in an upcoming release.\n- The functions `add-midi-control-to-cue-mapping` and\n  `remove-midi-control-to-cue-mapping` have been moved from the\n  `afterglow.show` namespace to `afterglow.effects.cues`, to solve a\n  circular dependency conflict which arose in implementing velocity\n  and aftertouch support. There are stubs in the old location which\n  delegate to the new ones, but they are less efficient than calling\n  them in the new location directly, and are deprecated. The stubs\n  will be removed in an upcoming release.\n- The former `IHeadParam` interface has been eliminated, folding its\n  semantics into the `IParam` interface, and simplifying the\n  implementation of dynamic parameters,\n  [issue 20](https://github.com/Deep-Symmetry/afterglow/issues/20).\n- The `:adjust-fn` parameter to `build-variable-param` has been\n  renamed `:transform-fn` to be consistent with the equivalent\n  mechanism added for MIDI control mappings in\n  [issue 32](https://github.com/Deep-Symmetry/afterglow/issues/32). The\n  documentation has been improved a bit as well.\n- The maps which track MIDI bindings now use the underlying Java\n  `MidiDevice` object for their keys, which allows for more efficent\n  lookup than the `overtone.midi` `:midi-device` map which was\n  previously used.\n- The functions which add and remove bindings to MIDI control, note,\n  and aftertouch messages have been simplified so they no longer\n  require you to come up with a unique keyword to use when later\n  removing the binding. Instead, you simply pass the same function\n  that was used when establishing the binding to remove it.\n- All functions which allow you to select a MIDI device have been made\n  consistent, and now allow you to filter devices by a variety of\n  criteria, not just the name and description.\n- Various maps used to manage Afterglow state, such as shows, cue\n  grids, Push controllers and auto-binding watchers, are now tagged\n  with type metadata to make it easier to recognize them.\n\n### Fixed\n\n- Clicking on the BPM slider in the web interface now updates the BPM\n  (previously you had to actually drag it),\n  [issue 18](https://github.com/Deep-Symmetry/afterglow/issues/18).\n- Launching `:held` cues from generic MIDI controllers, the Ableton\n  Push, and the web interface, would not succeed if the previous\n  effect created by the cue was still in the process of ending,\n  [issue 33](https://github.com/Deep-Symmetry/afterglow/issues/33).\n- Make sure MIDI inputs are connected when `sync-to-midi-clock` is\n  called,\n  [issue 10](https://github.com/Deep-Symmetry/afterglow/issues/10).\n- Also make sure the MIDI inputs are opened when rendering the web UI,\n  so that the sync button will be able to list available sources of\n  MIDI clock messages.\n- Clarified that syncing to Traktor beat phase still requires Traktor\n  to be configured to send MIDI clock,\n  [issue 37](https://github.com/Deep-Symmetry/afterglow/issues/37).\n- Added more detail about how to safely import and configure the\n  Afterglow Traktor device mapping.\n- A variety of issues ranging from questionable style through misplaced\n  documentation, unused or inaccessible code, preconditions that would\n  not take effect, and actual problems, were identified by Kibit and\n  Eastwood (after discovering how to work around a crash in Eastwood\n  caused by the protocol definitions in `rhythm.clj`), were cleaned\n  up.\n\n## [0.1.5] - 2015-11-25\n\n### Added\n\n- Chases, which support sequences of effects with a variety of timing,\n  fade, and looping options.\n- Step parameters, which provide flexible control of chases.\n- Pan/Tilt effects, which work at a lower level than direction\n  effects, but since they are closer to the physical capabilities of\n  the lights, can be helpful in creating natural and intuitive\n  movements. They also help avoid issues with geometric singularities\n  when fading between different directions.\n- Graphs to visually illustrate the available oscillators and the\n  parameters that tune their behavior.\n\n### Changed\n\n- Fades now delegate their notion of ending to the underlying effects\n  which are being faded between, and pass end requests along to them.\n- Stopped embedding `cider-nrepl` because it added too much bloat and\n  complexity for an unlikely use case. If you want to work with CIDER\n  for live-coding with Afterglow, launch it from a project, rather\n  than as an überjar.\n\n### Fixed\n\n- Some MIDI controllers (perhaps those which sent messages on channels\n  other than 0?) were causing Overtone's\n  [midi-clj](https://github.com/overtone/midi-clj) library to create\n  message maps with `nil` values for the `:status` key when sending\n  control-change or note messages, which was preventing them from\n  being detected or processed correctly. Afterglow now always looks\n  for command-like messages via the `:command` key instead,\n  [issue 8](https://github.com/Deep-Symmetry/afterglow/issues/8).\n- Fading colors in and out from nothing, as represented by a `nil`\n  assignment value, was fading to a desaturated version of black,\n  which does not lead to the kind of results people generally expect\n  and want. In this situation, the color is now faded to or from a\n  darkened version of itself.\n- The phases of the square-bar and square-phrase oscillators were\n  flipped from what they should be according to the documentation, and\n  compared with square-beat. This was discovered and corrected when\n  graphing them.\n- Calculation of white LED channel for colors with lightness less than\n  50 was wrong, leading to slight unintentional desaturation of\n  colors.\n- It was a little too hard to see the difference between the \"ready\"\n  and \"active\" states for some colors on the Ableton Push after\n  introducing full RGB button color support; they are once again more\n  visually distinct.\n- Preconditions in channel-creation functions for fixture definitions\n  were mal-formed, and so were not actually validating the function\n  arguments.\n- Parts of the introductory walk-through in `README.md` had become\n  stale and needed to be updated.\n- The API documentation for `patch-fixture!` was fleshed out.\n\n## [0.1.4] - 2015-09-27\n### Added\n- Support for inverted dimmers (where lower DMX values are brighter).\n- Scenes, which allow multiple effects to be grouped into one.\n- A framework for fading between effect elements, with sensible\n  semantics for colors, aim, directions, and functions, and defaults\n  when fading in or out of nothing.\n- Fading between entire effects, including complex effects and scenes,\n  which do not necessarily affect all the same fixtures and channels.\n- A new mechanism for extending the rendering loop to support effects\n  which do not result in DMX values to send to the show universes.\n- Support for (and examples of) integration with laser shows being run\n  by Pangolin Beyond software, using the extension mechanism.\n- New conditional effects and variable-setting effects, using the\n  extension mechanism.\n- A composable effect which can transform the colors being created by\n  other effects to build layered looks. The default transformation\n  causes the colors to range from fully saturated at the start of each\n  beat to pure gray by the end of the beat, but it is very easy to\n  swap in other transformations using oscillated parameters.\n- Holding down the Shift key while turning the encoder allows the BPM\n  to be changed more rapidly (in whole beat increments, rather than\n  tenths) on the Ableton Push.\n- Fixture definitions for Chauvet LED Techno Strobe, LED Techno Strobe\n  RGB, ColorStrip, Spot LED 150, Kinta X, Scorpion Storm FX RGB,\n  Scorpion Storm RGX, Q-Spot 160, Intimidator Scan LED 300, Geyser RGB\n  fogger, and Hurricane 1800 Flex fogger.\n- Example effect which desaturates a rainbow over the course of a\n  beat.\n\n### Changed\n- Improved readability and parallelism of core rendering loop.\n- The default frame rate was raised from 30Hz to 40Hz.\n- Ableton Push now uses SysEx message to specify the exact RGB color\n  to light up a pad, rather than choosing from the limited set\n  available through MIDI velocity.\n- Ableton Push now makes sure the pads are put in poly-pressure mode,\n  and sets the sensitivity level to reduce the chance of stuck pads.\n- The stability of MIDI clock sync was greatly improved, in order to\n  facilitate the Beyond integration.\n- The refresh rates of the Push and web interfaces were reduced to put\n  less load on the CPU.\n- The tempo buttons on the Push and web interfaces are now always\n  flashed at least once per beat, even if the reduced refresh rate\n  causes the normal \"on\" window to be missed.\n- Improved content and format of command-line usage help.\n\n### Fixed\n- The Ableton Push binding now ends cues when it receives an afertouch\n  value of 0, since the hardware is not reliably sending a note-end\n  message, especially when multiple pads are being pressed at once.\n- Fail gracefully when trying to bind to an Ableton Push when none can\n  be found.\n- Some small errors in the documentation were corrected.\n\n## [0.1.3] - 2015-08-16\n\n### Added\n- Ability to\n  [translate](https://github.com/Deep-Symmetry/afterglow/blob/master/doc/fixture_definitions.adoc#translating-qlc-fixture-definitions)\n  fixture definitions from the format used by\n  [QLC+](http://www.qlcplus.org/) to help people get started on\n  defining fixtures.\n\n### Changed\n- Separated OLA communication into its own project,\n  [ola-clojure](https://github.com/Deep-Symmetry/ola-clojure#ola-clojure).\n\n## [0.1.2] - 2015-08-09\n### Added\n- Allow configuration of an alternate host for the OLA daemon\n  (primarily for Windows users, since there is not yet a Windows port\n  of OLA).\n- Flesh out the command-line arguments when running as an executable\n  jar.\n- Allow a list of files to be loaded at startup when running as an\n  executable jar, in order to configure fixtures, shows, effects, and\n  cues.\n- Support syncing to Traktor’s beat grid with the help of a new custom\n  controller mapping.\n\n### Changed\n- MIDI sync sources are now always watched for, and can be offered to\n  the user without pausing first.\n\n## [0.1.1] - 2015-08-02\n### Added\n- Ability to register for notification about changes in status of cues\n  and values of show variables.\n- Creating a show can optionally register it with the web interface by\n  passing a description with `:description`.\n- Now cleans up thread-local bindings stored by the web REPL when\n  sessions time out.\n\n### Changed\n- Forked Protobuf related libraries to make them build Java 6\n  compatible clases, so\n  [afterglow-max](https://github.com/Deep-Symmetry/afterglow-max) can run\n  inside the Java environment provided by\n  [Cycling ‘74’s Max](https://cycling74.com/).\n- Made the meaning of the `:start` attribute of cue variables simpler\n  and more consistent.\n- Cue variables which respond to aftertouch now also respond to\n  initial velocity, and the related configuration attributes have been\n  renamed to `:velocity` to reflect this increased generality.\n- Improved the detection of project name and version number so they\n  work for afterglow-max builds too.\n\n### Fixed\n- Eliminated crashes in the Ableton Push interface when trying to\n  adjust the value of a cue variable which had not yet been set to\n  anything.\n\n## 0.1.0 - 2015-07-19\n### Added\n- Initial Public Release\n\n\n[unreleased]: https://github.com/Deep-Symmetry/afterglow/compare/v0.2.5...HEAD\n[0.2.5]: https://github.com/Deep-Symmetry/afterglow/compare/v0.2.4...v0.2.5\n[0.2.4]: https://github.com/Deep-Symmetry/afterglow/compare/v0.2.3...v0.2.4\n[0.2.3]: https://github.com/Deep-Symmetry/afterglow/compare/v0.2.2...v0.2.3\n[0.2.2]: https://github.com/Deep-Symmetry/afterglow/compare/v0.2.1...v0.2.2\n[0.2.1]: https://github.com/Deep-Symmetry/afterglow/compare/v0.2.0...v0.2.1\n[0.2.0]: https://github.com/Deep-Symmetry/afterglow/compare/v0.1.6...v0.2.0\n[0.1.6]: https://github.com/Deep-Symmetry/afterglow/compare/v0.1.5...v0.1.6\n[0.1.5]: https://github.com/Deep-Symmetry/afterglow/compare/v0.1.4...v0.1.5\n[0.1.4]: https://github.com/Deep-Symmetry/afterglow/compare/v0.1.3...v0.1.4\n[0.1.3]: https://github.com/Deep-Symmetry/afterglow/compare/v0.1.2...v0.1.3\n[0.1.2]: https://github.com/Deep-Symmetry/afterglow/compare/v0.1.1...v0.1.2\n[0.1.1]: https://github.com/Deep-Symmetry/afterglow/compare/v0.1.0...v0.1.1\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at james@deepsymmetry.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nHi there! We're delighted that you'd like to contribute to this\nproject. It has been generous collaboration from people all over the\nworld that has made it possible so far, and your help is key to\nkeeping it great.\n\nContributions to this project are [released][contributions-released]\nto the public under the [project's open source license](LICENSE).\n\nThis project adheres to the\n[Contributor Covenant Code of Conduct][covenant].\nBy participating, you are expected to uphold this code.\n\n## Getting started\n\nBefore you can start contributing to Afterglow, you'll need to\nset up your environment. Fork and clone the repo and install\n[Clojure][clojure] (for compiling and running the code) and\n[Leiningen](https://leiningen.org) (to manage the project dependencies\nand builds). Both of these rely on having a working Java runtime; if\nthe mechanism you used to install them did not automatically include\none, I recommend installing a current version of the\n[OpenJDK](http://openjdk.java.net).\n\n> Starting with version 0.2.5, you also need to have\n> [Antora](https://antora.org) installed because it is used to build\n> the embedded copy of the User Guide when building and running from\n> source. Assuming you have a current version of `node` installed,\n> simply running `npm i` inside the top level directory of the\n> afterglow project will install Antora for you. If you don't have a\n> node environment and are impatient to get started without getting\n> one, you can temporarily comment out the section of `project.clj`\n> that builds the user guide. Add `#_` to the `:prep-tasks`\n> line so that it looks like this:\n>\n>  `  :prep-tasks [#_[\"shell\" \"npx\" \"antora\" \"--fetch\" \"doc/embedded.yml\"`\n>\n> But keep in mind that if you do this, the built-in user guide will\n> not work, and you will not be able to create a release-worthy build\n> until you install Antora and restore the line to its un-commented\n> state.\n\nOnce you have those in place, you can run Afterglow from source by\nopening a terminal window inside your clone of the project, and typing\n`lein repl`. You will see a bunch of output as the embedded copy of\nthe User Guide is generated by Antora and the images are copied in,\nand then Clojure will start, with output similar to this:\n\n    REPL-y 0.5.1, nREPL 0.8.3\n    Clojure 1.10.3\n    OpenJDK 64-Bit Server VM 11.0.10+9-LTS\n    afterglow loaded.\n    afterglow.examples=>\n\nAt that point you can follow along with the example flow on the main\nproject page, and start diving into exploring and changing the source\ncode.\n\n> :wrench: If you are just building Afterglow to work around the\n> current [issue](https://github.com/clojars/clojars-web/issues/195)\n> preventing current versions from being available through Clojars, at\n> this point you can run `lein install`, which will build and install\n> the library in your local Maven repository, so other projects can\n> depend on the version that you just built without needing to find it\n> on Clojars.\n\nOf course to do any serious work, you will want some sort of editor\nwith embedded REPL support, and ideally structural editing support for\nLisp s-expressions. We find [GNU Emacs][emacs] with [CIDER][cider] to\nbe an incredibly productive environment for Clojure work, but some of\nour colleagues swear by [IntelliJ IDEA][idea] (even the free Community\nEdition) with [Cursive][cursive], so use whatever IDE or editor works\nbest for you.\n\nFor testing you are going to want to install OLA (as described on the\nmain project page) and have some lighting (and possibly MIDI) hardware\nto attach.\n\n## Giving back\n\nOnce you have something working you’d like to share, you can open a\n[pull request][pulls].\n\nOr if you simply have an idea, or something that you wish worked\ndifferently, feel free to open an [issue][issues] if it seems like\nnobody already has.\n\n## Maintainers\n\nAfterglow is primarily maintained by [@brunchboy][brunchboy].\n\n## License\n\n<a href=\"http://deepsymmetry.org\"><img align=\"right\" alt=\"Deep Symmetry\"\n src=\"doc/modules/ROOT/assets/images/DS-logo-github.png\" width=\"250\" height=\"150\"></a>\n\nCopyright © 2016&ndash;2022 [Deep Symmetry, LLC](http://deepsymmetry.org)\n\nDistributed under the\n[Eclipse Public License 2.0](https://opensource.org/licenses/EPL-2.0)\nBy using this software in any fashion, you are agreeing to be bound by\nthe terms of this license. You must not remove this notice, or any\nother, from this software.\n\n\n[contributions-released]: https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license\n[covenant]: http://contributor-covenant.org/\n[clojure]: https://clojure.org\n[leiningen]: https://leiningen.org\n[emacs]: https://www.gnu.org/software/emacs/\n[cider]: http://www.cider.mx/en/latest/\n[idea]: https://www.jetbrains.com/idea/\n[cursive]: https://cursive-ide.com\n[pulls]: https://github.com/Deep-Symmetry/afterglow/pulls\n[issues]: https://github.com/Deep-Symmetry/afterglow/issues\n[brunchboy]: https://github.com/brunchboy\n"
  },
  {
    "path": "LICENSE",
    "content": "Eclipse Public License - v 2.0\n\n    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n    PUBLIC LICENSE (\"AGREEMENT\"). ANY USE, REPRODUCTION OR DISTRIBUTION\n    OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.\n\n1. DEFINITIONS\n\n\"Contribution\" means:\n\n  a) in the case of the initial Contributor, the initial content\n     Distributed under this Agreement, and\n\n  b) in the case of each subsequent Contributor:\n     i) changes to the Program, and\n     ii) additions to the Program;\n  where such changes and/or additions to the Program originate from\n  and are Distributed by that particular Contributor. A Contribution\n  \"originates\" from a Contributor if it was added to the Program by\n  such Contributor itself or anyone acting on such Contributor's behalf.\n  Contributions do not include changes or additions to the Program that\n  are not Modified Works.\n\n\"Contributor\" means any person or entity that Distributes the Program.\n\n\"Licensed Patents\" mean patent claims licensable by a Contributor which\nare necessarily infringed by the use or sale of its Contribution alone\nor when combined with the Program.\n\n\"Program\" means the Contributions Distributed in accordance with this\nAgreement.\n\n\"Recipient\" means anyone who receives the Program under this Agreement\nor any Secondary License (as applicable), including Contributors.\n\n\"Derivative Works\" shall mean any work, whether in Source Code or other\nform, that is based on (or derived from) the Program and for which the\neditorial revisions, annotations, elaborations, or other modifications\nrepresent, as a whole, an original work of authorship.\n\n\"Modified Works\" shall mean any work in Source Code or other form that\nresults from an addition to, deletion from, or modification of the\ncontents of the Program, including, for purposes of clarity any new file\nin Source Code form that contains any contents of the Program. Modified\nWorks shall not include works that contain only declarations,\ninterfaces, types, classes, structures, or files of the Program solely\nin each case in order to link to, bind by name, or subclass the Program\nor Modified Works thereof.\n\n\"Distribute\" means the acts of a) distributing or b) making available\nin any manner that enables the transfer of a copy.\n\n\"Source Code\" means the form of a Program preferred for making\nmodifications, including but not limited to software source code,\ndocumentation source, and configuration files.\n\n\"Secondary License\" means either the GNU General Public License,\nVersion 2.0, or any later versions of that license, including any\nexceptions or additional permissions as identified by the initial\nContributor.\n\n2. GRANT OF RIGHTS\n\n  a) Subject to the terms of this Agreement, each Contributor hereby\n  grants Recipient a non-exclusive, worldwide, royalty-free copyright\n  license to reproduce, prepare Derivative Works of, publicly display,\n  publicly perform, Distribute and sublicense the Contribution of such\n  Contributor, if any, and such Derivative Works.\n\n  b) Subject to the terms of this Agreement, each Contributor hereby\n  grants Recipient a non-exclusive, worldwide, royalty-free patent\n  license under Licensed Patents to make, use, sell, offer to sell,\n  import and otherwise transfer the Contribution of such Contributor,\n  if any, in Source Code or other form. This patent license shall\n  apply to the combination of the Contribution and the Program if, at\n  the time the Contribution is added by the Contributor, such addition\n  of the Contribution causes such combination to be covered by the\n  Licensed Patents. The patent license shall not apply to any other\n  combinations which include the Contribution. No hardware per se is\n  licensed hereunder.\n\n  c) Recipient understands that although each Contributor grants the\n  licenses to its Contributions set forth herein, no assurances are\n  provided by any Contributor that the Program does not infringe the\n  patent or other intellectual property rights of any other entity.\n  Each Contributor disclaims any liability to Recipient for claims\n  brought by any other entity based on infringement of intellectual\n  property rights or otherwise. As a condition to exercising the\n  rights and licenses granted hereunder, each Recipient hereby\n  assumes sole responsibility to secure any other intellectual\n  property rights needed, if any. For example, if a third party\n  patent license is required to allow Recipient to Distribute the\n  Program, it is Recipient's responsibility to acquire that license\n  before distributing the Program.\n\n  d) Each Contributor represents that to its knowledge it has\n  sufficient copyright rights in its Contribution, if any, to grant\n  the copyright license set forth in this Agreement.\n\n  e) Notwithstanding the terms of any Secondary License, no\n  Contributor makes additional grants to any Recipient (other than\n  those set forth in this Agreement) as a result of such Recipient's\n  receipt of the Program under the terms of a Secondary License\n  (if permitted under the terms of Section 3).\n\n3. REQUIREMENTS\n\n3.1 If a Contributor Distributes the Program in any form, then:\n\n  a) the Program must also be made available as Source Code, in\n  accordance with section 3.2, and the Contributor must accompany\n  the Program with a statement that the Source Code for the Program\n  is available under this Agreement, and informs Recipients how to\n  obtain it in a reasonable manner on or through a medium customarily\n  used for software exchange; and\n\n  b) the Contributor may Distribute the Program under a license\n  different than this Agreement, provided that such license:\n     i) effectively disclaims on behalf of all other Contributors all\n     warranties and conditions, express and implied, including\n     warranties or conditions of title and non-infringement, and\n     implied warranties or conditions of merchantability and fitness\n     for a particular purpose;\n\n     ii) effectively excludes on behalf of all other Contributors all\n     liability for damages, including direct, indirect, special,\n     incidental and consequential damages, such as lost profits;\n\n     iii) does not attempt to limit or alter the recipients' rights\n     in the Source Code under section 3.2; and\n\n     iv) requires any subsequent distribution of the Program by any\n     party to be under a license that satisfies the requirements\n     of this section 3.\n\n3.2 When the Program is Distributed as Source Code:\n\n  a) it must be made available under this Agreement, or if the\n  Program (i) is combined with other material in a separate file or\n  files made available under a Secondary License, and (ii) the initial\n  Contributor attached to the Source Code the notice described in\n  Exhibit A of this Agreement, then the Program may be made available\n  under the terms of such Secondary Licenses, and\n\n  b) a copy of this Agreement must be included with each copy of\n  the Program.\n\n3.3 Contributors may not remove or alter any copyright, patent,\ntrademark, attribution notices, disclaimers of warranty, or limitations\nof liability (\"notices\") contained within the Program from any copy of\nthe Program which they Distribute, provided that Contributors may add\ntheir own appropriate notices.\n\n4. COMMERCIAL DISTRIBUTION\n\nCommercial distributors of software may accept certain responsibilities\nwith respect to end users, business partners and the like. While this\nlicense is intended to facilitate the commercial use of the Program,\nthe Contributor who includes the Program in a commercial product\noffering should do so in a manner which does not create potential\nliability for other Contributors. Therefore, if a Contributor includes\nthe Program in a commercial product offering, such Contributor\n(\"Commercial Contributor\") hereby agrees to defend and indemnify every\nother Contributor (\"Indemnified Contributor\") against any losses,\ndamages and costs (collectively \"Losses\") arising from claims, lawsuits\nand other legal actions brought by a third party against the Indemnified\nContributor to the extent caused by the acts or omissions of such\nCommercial Contributor in connection with its distribution of the Program\nin a commercial product offering. The obligations in this section do not\napply to any claims or Losses relating to any actual or alleged\nintellectual property infringement. In order to qualify, an Indemnified\nContributor must: a) promptly notify the Commercial Contributor in\nwriting of such claim, and b) allow the Commercial Contributor to control,\nand cooperate with the Commercial Contributor in, the defense and any\nrelated settlement negotiations. The Indemnified Contributor may\nparticipate in any such claim at its own expense.\n\nFor example, a Contributor might include the Program in a commercial\nproduct offering, Product X. That Contributor is then a Commercial\nContributor. If that Commercial Contributor then makes performance\nclaims, or offers warranties related to Product X, those performance\nclaims and warranties are such Commercial Contributor's responsibility\nalone. Under this section, the Commercial Contributor would have to\ndefend claims against the other Contributors related to those performance\nclaims and warranties, and if a court requires any other Contributor to\npay any damages as a result, the Commercial Contributor must pay\nthose damages.\n\n5. NO WARRANTY\n\nEXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT\nPERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN \"AS IS\"\nBASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR\nIMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF\nTITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR\nPURPOSE. Each Recipient is solely responsible for determining the\nappropriateness of using and distributing the Program and assumes all\nrisks associated with its exercise of rights under this Agreement,\nincluding but not limited to the risks and costs of program errors,\ncompliance with applicable laws, damage to or loss of data, programs\nor equipment, and unavailability or interruption of operations.\n\n6. DISCLAIMER OF LIABILITY\n\nEXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT\nPERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS\nSHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST\nPROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE\nEXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n7. GENERAL\n\nIf any provision of this Agreement is invalid or unenforceable under\napplicable law, it shall not affect the validity or enforceability of\nthe remainder of the terms of this Agreement, and without further\naction by the parties hereto, such provision shall be reformed to the\nminimum extent necessary to make such provision valid and enforceable.\n\nIf Recipient institutes patent litigation against any entity\n(including a cross-claim or counterclaim in a lawsuit) alleging that the\nProgram itself (excluding combinations of the Program with other software\nor hardware) infringes such Recipient's patent(s), then such Recipient's\nrights granted under Section 2(b) shall terminate as of the date such\nlitigation is filed.\n\nAll Recipient's rights under this Agreement shall terminate if it\nfails to comply with any of the material terms or conditions of this\nAgreement and does not cure such failure in a reasonable period of\ntime after becoming aware of such noncompliance. If all Recipient's\nrights under this Agreement terminate, Recipient agrees to cease use\nand distribution of the Program as soon as reasonably practicable.\nHowever, Recipient's obligations under this Agreement and any licenses\ngranted by Recipient relating to the Program shall continue and survive.\n\nEveryone is permitted to copy and distribute copies of this Agreement,\nbut in order to avoid inconsistency the Agreement is copyrighted and\nmay only be modified in the following manner. The Agreement Steward\nreserves the right to publish new versions (including revisions) of\nthis Agreement from time to time. No one other than the Agreement\nSteward has the right to modify this Agreement. The Eclipse Foundation\nis the initial Agreement Steward. The Eclipse Foundation may assign the\nresponsibility to serve as the Agreement Steward to a suitable separate\nentity. Each new version of the Agreement will be given a distinguishing\nversion number. The Program (including Contributions) may always be\nDistributed subject to the version of the Agreement under which it was\nreceived. In addition, after a new version of the Agreement is published,\nContributor may elect to Distribute the Program (including its\nContributions) under the new version.\n\nExcept as expressly stated in Sections 2(a) and 2(b) above, Recipient\nreceives no rights or licenses to the intellectual property of any\nContributor under this Agreement, whether expressly, by implication,\nestoppel or otherwise. All rights in the Program not expressly granted\nunder this Agreement are reserved. Nothing in this Agreement is intended\nto be enforceable by any entity that is not a Contributor or Recipient.\nNo third-party beneficiary rights are created under this Agreement.\n\nExhibit A - Form of Secondary Licenses Notice\n\n\"This Source Code may also be made available under the following \nSecondary Licenses when the conditions for such availability set forth \nin the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\nversion(s), and exceptions or additional permissions here}.\"\n\n  Simply including a copy of this Agreement, including this Exhibit A\n  is not sufficient to license the Source Code under Secondary Licenses.\n\n  If it is not possible or desirable to put the notice in a particular\n  file, then You may include the notice in a location (such as a LICENSE\n  file in a relevant directory) where a recipient would be likely to\n  look for such a notice.\n\n  You may add additional accurate notices of copyright ownership."
  },
  {
    "path": "README.md",
    "content": "# Afterglow\n\n[![project chat](https://img.shields.io/badge/chat-on%20zulip-brightgreen)](https://deep-symmetry.zulipchat.com/#narrow/stream/318697-afterglow)\n <image align=\"right\" width=\"275\" height=\"255\"\n src=\"doc/modules/ROOT/assets/images/Afterglow-logo-padded-left.png\"> <br/><br/> An\n environment supporting\n [live coding](https://en.wikipedia.org/wiki/Live_coding) for the\n creation of algorithmic light shows in [Clojure](http://clojure.org),\n leveraging the\n [Open Lighting Architecture](https://www.openlighting.org/ola/) with\n the help of\n [ola-clojure](https://github.com/Deep-Symmetry/ola-clojure#ola-clojure),\n [wayang](https://github.com/Deep-Symmetry/wayang#wayang),\n [beat-link](https://github.com/Deep-Symmetry/beat-link), and pieces of\n the [Overtone](http://overtone.github.io) toolkit. Beyond building on\n pieces of Overtone, the entire Afterglow project was\n [inspired](https://vimeo.com/22798433) by it.\n\n[![License](https://img.shields.io/badge/License-Eclipse%20Public%20License%202.0-blue.svg)](#license)\n\n### Documentation Overview\n\nThis page provides an introduction in how to install and use\nAfterglow. The [Developer\nGuide](https://afterglow-guide.deepsymmetry.org) goes much deeper,\nand there is also [API\ndocumentation](http://afterglow-guide.deepsymmetry.org/api/). For more\ninteractive help, the [Afterglow stream on\nZulip](https://deep-symmetry.zulipchat.com/#narrow/stream/318697-afterglow) is the place to start,\nand if you want to see (or contribute to) more structured and lasting\ncommunity-driven documentation, there is also a project\n[wiki](https://github.com/Deep-Symmetry/afterglow/wiki).\n\n## Why Explore Afterglow?\n\n> tl;dr&mdash;show me? Check out the\n> [Show Control pics](https://afterglow-guide.deepsymmetry.org/afterglow/README.html#show-control)\n> and [performance video](https://afterglow-guide.deepsymmetry.org/afterglow/videos.html).\n\nAs suggested by the live-coding orientation mentioned above, which is\ndesigned to let you inject your own code right into the frame\nrendering process, Afterglow takes a very different approach to\ncontrolling light shows than other software. It won&rsquo;t be right\nfor everyone, but will be extremely compelling to a particular niche.\nThe early stages of its [rendering\nloop](https://afterglow-guide.deepsymmetry.org/afterglow/rendering_loop.html#the-rendering-loop)\ncan offer higher levels of abstraction than the usual DMX [channel\nvalue](https://afterglow-guide.deepsymmetry.org/afterglow/effects.html#channel-effects)\nor [fixture\nfunction](https://afterglow-guide.deepsymmetry.org/afterglow/effects.html#function-effects)\n(although those are fully supported too):\n\n* You can express your desired results in terms of an abstract\n  [color](https://afterglow-guide.deepsymmetry.org/afterglow/effects.html#color-effects),\n  including support for the hue-saturation-lightness model, which is\n  great for algorithmic looks, and have it translated to whatever\n  color channels (or color wheel) your fixture supports.\n\n* Groups of moving heads can be told to face particular\n  [directions](https://afterglow-guide.deepsymmetry.org/afterglow/effects.html#direction-effects)\n  by specifying parameterized vectors, or to\n  [aim](https://afterglow-guide.deepsymmetry.org/afterglow/effects.html#aim-effects)\n  at a particular point in space, and Afterglow figures out how to\n  translate that into DMX control values given its understanding of\n  the\n  [fixture](https://afterglow-guide.deepsymmetry.org/afterglow/fixture_definitions.html)\n  and\n  [where](https://afterglow-guide.deepsymmetry.org/afterglow/show_space.html),\n  and at what angle, you hung it.\n\n* There are a variety of\n  [oscillators](https://afterglow-guide.deepsymmetry.org/afterglow/oscillators.html)\n  which can efficiently drive effect parameters.\n\n* You can also create\n  [complex effects](https://afterglow-guide.deepsymmetry.org/afterglow/effects.html#complex-effects),\n  with\n  [adjustable parameters](https://afterglow-guide.deepsymmetry.org/afterglow/parameters.html)\n  that can be controlled through a rich binding to an\n  [Ableton Push](https://afterglow-guide.deepsymmetry.org/afterglow/push2.html) or\n  [Novation Launchpad family](https://afterglow-guide.deepsymmetry.org/afterglow/launchpad.html)\n  controller, or via\n  [Open Sound Control](https://afterglow-guide.deepsymmetry.org/afterglow/mapping_sync.html#open-sound-control)\n  (OSC)&mdash;even wirelessly from a tablet or smartphone.\n\n* The timing of effects is pervasively influenced by a deep notion of\n  [musical time](https://afterglow-guide.deepsymmetry.org/afterglow/metronomes.html),\n  with support for synchronization via\n  [MIDI clock](https://afterglow-guide.deepsymmetry.org/afterglow/mapping_sync.html#syncing-to-midi-clock),\n  [Traktor Beat Phase](https://afterglow-guide.deepsymmetry.org/afterglow/mapping_sync.html#syncing-to-traktor-beat-phase),\n  or Pioneer\n  [Pro DJ Link](https://afterglow-guide.deepsymmetry.org/afterglow/mapping_sync.html#syncing-to-pro-dj-link)\n  beat grids.\n\n* You can even host Afterglow within\n  [Cycling ‘74’s Max](https://cycling74.com/) visual interactive\n  environment.\n\nIf any of this sounds interesting to you, read on to see how to get\nstarted!\n\n## Table of Contents\n\n  * [Why Explore Afterglow?](#why-explore-afterglow)\n  * [Installation](#installation)\n  * [Status](#status)\n  * [Getting Help](#getting-help)\n  * [Usage](#usage)\n  * [Troubleshooting](#troubleshooting)\n  * [Bugs](#bugs)\n  * [What Next?](#what-next)\n  * [Release Checklist](#release-checklist)\n  * [Tasks](#tasks)\n  * [License](#license)\n\n## Installation\n\n1. [Install OLA](https://www.openlighting.org/ola/getting-started/downloads/).\n   (On the Mac I recommend using [Homebrew](http://brew.sh) which lets you simply\n   `brew install ola`). Once you launch the `olad` server you can\n   interact with its embedded\n   [web server](http://localhost:9090/ola.html), which is very helpful\n   in seeing whether anything is working; you can even watch live DMX\n   values changing.\n\n   > :wrench: If you are installing Afterglow on Windows, see the\n   > [Wiki discussion](https://github.com/Deep-Symmetry/afterglow/wiki/Questions#ola-and-windows)\n   > about OLA options.\n\n2. For now set up a Clojure project using [Leiningen](http://leiningen.org).\n\n3. Add this project as a dependency:\n   [![Clojars Project](https://img.shields.io/clojars/v/afterglow.svg)](http://clojars.org/afterglow)\n\n> :wrench: If you were using older releases of Afterglow and installed\n> [CoreMIDI4J](https://github.com/DerekCook/CoreMidi4J) in\n> `/Library/Java/Extensions`, you need to remove it, because Afterglow\n> now embeds an improved version and uses it when necessary.\n\nIf you want to run Afterglow as a standalone executable, you can\ndownload the executable &uuml;berjar from the\n[releases](https://github.com/Deep-Symmetry/afterglow/releases) page.\n[![&uuml;berjar](https://img.shields.io/github/downloads/Deep-Symmetry/afterglow/total.svg)](https://github.com/Deep-Symmetry/afterglow/releases)\n\nFor an example of a project which uses Afterglow as a dependency, as\ndescribed above, see\n[afterglow-max](https://github.com/Deep-Symmetry/afterglow-max#afterglow-max),\nwhich hosts Afterglow inside [Cycling ‘74’s Max](https://cycling74.com/).\n\n## Status\n\nAlthough Afterglow is far from finished, it&rsquo;s ready for the world to\nstart exploring, and helping decide directions in which to grow next\n(as well as identifying areas where the documentation needs\nclarification or reinforcement).\n\nMost of the crazy ideas have panned out and been implemented, and I am\nfleshing out the basic details needed for everyday use. The examples\nare starting to be intriguing and informative, and the [Developer\nGuide](https://afterglow-guide.deepsymmetry.org) is getting\nsubstantial. The modeling of fixtures, channels, etc. is coming\ntogether nicely, though there may be a few more changes.\n\nThere is now an embedded web application, which is growing into a show\ncontrol interface for people who are not Clojure hackers, and a useful\nadjunct to the Ableton Push and Launchpad family control surface\ninterfaces. Each is explained in the documentation link above.\nAfterglow also includes the beginnings of a show visualizer for\ndesigning and working on effects without having to physically hook up\nlights (a proof of concept, really, at this point). This is\nimplemented in WebGL using a volumetric ray tracer and looks quite\npromising, at least for a small number of fixtures; it will probably\noverwhelm the graphics processor on most systems once you add too many\nlights. However, the framework can be used by someone who actually\nknows OpenGL programming to build a more scalable preview (albeit one\nthat probably doesn’t look quite so photo-realistic with beams\nimpacting drifting fog). This is an area where I would love some help\nif it sounds interesting!\n\n## Getting Help\n\n<a href=\"http://zulip.com\"><img align=\"right\" alt=\"Zulip logo\"\n src=\"doc/modules/ROOT/assets/images/zulip-icon-circle.svg\"\n width=\"128\" height=\"128\"></a>\n\nDeep Symmetry&rsquo;s projects are generously sponsored with hosting by <a\nhref=\"https://zulip.com\">Zulip</a>, an open-source modern team chat\napp designed to keep both live and asynchronous conversations\norganized. Thanks to them, you can <a\nhref=\"https://deep-symmetry.zulipchat.com/#narrow/stream/318697-afterglow\">chat\nwith our community</a>, ask questions, get inspiration, and share your\nown ideas.\n\n## Usage\n\n> The rest of this document primarily provides an introduction to the\n> configuration of Afterglow from the command line and text files. The\n> show control interface is explained in the\n> [web](https://afterglow-guide.deepsymmetry.org/afterglow/README.html#web-ui)\n> and\n> [Push](https://afterglow-guide.deepsymmetry.org/afterglow/push2.html)\n> sections.\n\nAlthough you will often want to use Afterglow from a Clojure repl, you\ncan also bring it up as an executable jar, and run it using `java\n-jar` with command-line arguments:\n\n```\n> java -jar afterglow.jar --help\n\nafterglow 0.2.4, a live-coding environment for light shows.\nUsage: afterglow [options] [init-file ...]\n  Any init-files specified as arguments will be loaded at startup,\n  in the order they are given, before creating any embedded servers.\n\nOptions:\n  -w, --web-port PORT     16000               Port number for web UI\n  -n, --no-browser                            Don't launch web browser\n  -o, --osc-port PORT     16001               Port number for OSC server\n  -r, --repl-port PORT                        Port number for REPL, if desired\n  -l, --log-file PATH     logs/afterglow.log  File into which log is written\n  -H, --olad-host HOST    localhost           Host name or address of OLA daemon\n  -P, --olad-port PORT    9010                Port number OLA daemon listens on\n  -q, --convert-qxf PATH                      Convert QLC+ fixture file and exit\n  -h, --help                                  Display help information and exit\n\nIf you translate a QLC+ fixture definition file, Afterglow will try to write\nits version in the same directory, but won't overwrite an existing file.\n\nIf you do not explicitly specify a log file, and Afterglow cannot write to\nthe default log file path, logging will be silently suppressed.\n\nPlease see https://github.com/Deep-Symmetry/afterglow for more information.\n```\n\nAs noted, you can pass a list of init-files when you run Afterglow\nthis way, which gives you the opportunity to set up the actual\nuniverses, fixtures, effects, and cues that you want to use in your\nshow. As a starting point, you could put something like the following\nin a file `my-show.clj` and then invoke Afterglow as `java -jar afterglow.jar my-show.clj`:\n\n```clojure\n(ns my-show\n  \"Set up the fixtures, effects, and cues I actually want to use.\"\n  ;; TODO: Your list of required namespaces will differ from this, depending on\n  ;;       what fixtures you actually use, and what effects and cues you create.\n  (:require [afterglow.core :as core]\n            [afterglow.transform :as tf]\n            [afterglow.effects.color :refer [color-effect]]\n            [afterglow.effects.cues :as cues]\n            [afterglow.effects.dimmer :refer [dimmer-effect]]\n            [afterglow.effects.fun :as fun]\n            [afterglow.effects.movement :as move]\n            [afterglow.effects.oscillators :as oscillators]\n            [afterglow.effects.params :as params]\n            [afterglow.fixtures.blizzard :as blizzard]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer :all]\n            [com.evocomputing.colors :refer [create-color hue adjust-hue]]\n            [taoensso.timbre :as timbre]))\n\n(defonce ^{:doc \"Holds my show if it has been created,\n  so it can be unregistered if it is being re-created.\"}\n  my-show\n  (atom nil))\n\n(defn use-my-show\n  \"Set up the show on the OLA universes it actually needs.\"\n  []\n\n  ;; Create, or re-create the show. Make it the default show so we don't\n  ;; need to wrap everything below in a (with-show sample-show ...) binding.\n  (set-default-show!\n   (swap! my-show (fn [s]\n                    (when s\n                      (show/unregister-show s)\n                      (with-show s (show/stop!)))\n                    ;; TODO: Edit this to list the actual OLA universe(s) that\n                    ;;       your show needs to use if they are different than\n                    ;;       just universe 1, as below, and change the description\n                    ;;       to something descriptive and in your own style:\n                    (show/show :universes [1] :description \"My Show\"))))\n\n  ;; TODO: Replace this to patch in an actual fixture in your show, at its actual\n  ;;       universe, DMX address, physical location and orientation, then add all\n  ;;       your other fixtures one by one.\n  (show/patch-fixture! :torrent-1 (blizzard/torrent-f3) 1 1\n                       :x (tf/inches 44) :y (tf/inches 51.75) :z (tf/inches -4.75)\n                       :y-rotation (tf/degrees 0))\n\n  ;; Return the show's symbol, rather than the actual map, which gets huge with\n  ;; all the expanded, patched fixtures in it.\n  '*show*)\n\n(core/init-logging)  ; Log at :info level to rotating files in logs/ subdirectory.\n(use-my-show)  ; Set up my show as the default show, using the function above.\n\n;; TODO: Add your custom effects, then assign them to cues with sensible colors\n;;       See afterglow.examples for examples.\n```\n\nAs noted, you will want to look at the\n[afterglow.examples](src/afterglow/examples.clj)\nnamespace for some examples of how to populate this file; the rest of\nthis section gives an overview and walk-through of how pieces of that\nnamespace work. The `:require` section at the top of `my-show.clj` is\nset up to make it easy to cut and paste from these examples, although\nit is not complete, and you will eventually need to learn how to\nadjust and optimize it yourself.\n\n> The example code above configures Afterglow to log to a set of\n> rotating log files in a `logs/` subdirectory of your project.\n> Afterglow will attempt to create that directory if it does not\n> exist. If you want to see any logging information, which can be\n> quite useful when troubleshooting, you will need to ensure that the\n> path to the logs directory is writeable (or that the logs directory\n> exists and is writable), otherwise the logging mechanism will\n> silently do nothing. The logs will stay out of your way until you\n> are interested in them, and take up a limited amount of space, but\n> whenever you do want to watch what Afterglow is doing, you can look\n> at them, or `tail -f logs/afterglow.log` to watch it live.\n\nAs your show gets more complex, you may want to split this into\nmultiple files, which you can either load by listing them all on the\ncommand line, or by using Clojure&rsquo;s `load-file` function from within\nthe first file. Or, once you are comfortable with idomatic Clojure\ndevelopment, by organizing them into a hierarchy of namespaces, and\nusing the normal `:require` mechanism that is used to pull in\nAfterglow&rsquo;s own namespaces.\n\n> :heavy_exclamation_mark: At this early stage of development, using\n> Afterglow as an executable jar is less-tested territory, and you may\n> find surprising bugs... though this is becoming less of an issue\n> since the advent of\n> [afterglow-max](https://github.com/Deep-Symmetry/afterglow-max#afterglow-max),\n> which is putting Afterglow through its paces as an embedded jar. In\n> any case, although the project will gradually evolve into a system\n> that non-Clojure hackers can use, for now you are probably best off\n> playing with it inside a Clojure development environment, or within\n> Max, likely with a Clojure environment connected via nREPL.\n\nAssuming you are using it from within a REPL, there is a namespace\n`afterglow.examples` which is intended to help you get started quickly\nin exploring the environment, as well as serving as an example of how\nto configure your own shows, fixtures, effects, and cues.\n\n> The next two lines are not needed if you are using a checkout of the\n> Afterglow source code rather than the library version described\n> above, since the project is configured to start you in this\n> namespace for convenience.\n\n```clojure\n(require 'afterglow.examples)\n(in-ns 'afterglow.examples)\n```\n\nWhen you run Afterglow as an executable jar, it will automatically\nopen a web browser window on its embedded web interface. If you are\nusing it in another way, you can bring up the web interface, and open\na browser window on it, with a one-liner like this (the first argument\nspecifies the port on which to run the web interface, and the second\ncontrols whether a browser window should be automatically opened):\n\n```clojure\n(core/start-web-server 16000 true)\n```\n\n<img alt=\"Web Interface\"\nsrc=\"doc/modules/ROOT/assets/images/WebHome.png\" width=\"537\"\nheight=\"427\">\n\nAs noted at the bottom, the web interface provides a minimal console\nas well, so if you are running Afterglow from a jar and just want to\ntweak something quickly, you can use that:\n\n<img alt=\"Web Console\"\nsrc=\"doc/modules/ROOT/assets/images/Console.png\" width=\"850\"\nheight=\"690\">\n\n> However, this does not offer the valuable support you would have\n> from a dedicated REPL like\n> [Cider](https://github.com/clojure-emacs/cider) (in Emacs) or\n> [Cursive](https://cursiveclojure.com) (in IntelliJ): things like\n> symbol completion, popup documentation, and command-line recall,\n> which make for a vastly more productive exploration session. So even\n> when you are running from a jar rather than launching from a REPL,\n> you will often want to access a real REPL. You can accomplish that\n> with command-line arguments or by using the web console to invoke\n> [core/start-nrepl](http://deepsymmetry.org/afterglow/api-doc/afterglow.core.html#var-start-nrepl)\n> and then connecting your favorite REPL environment to the network\n> REPL port you created.\n\nThe web interface does provide a nice show control page, though, with\naccess to a scrollable grid of cues, and the ability to track the cues\ndisplayed on a physical cue grid control surface like the Ableton Push\nor a current member of the Novation Launchpad family, so you can\ncontrol them from either place, and see the names that go with the\ncolored buttons on the control surface. This animated GIF shows how\ncues respond to clicks, lightening while they run, and darkening any\ncues which cannot run at the same time. It also shows how you can\nscroll around a larger grid than fits on the screen at one time\n(although it has reduced colors, frame rate, and quality when compared\nto the actual web interface):\n\n<img alt=\"Show Control\"\nsrc=\"doc/modules/ROOT/assets/images/ShowGrid.gif\" width=\"998\"\nheight=\"912\">\n\nHere is the Ableton Push interface tied to the same cue grid. This\nphysical control surface lets you trigger more than one cue at the\nsame time, and also gives you niceties unavailable with a mouse, like\npressure sensitivity so your effect intensity, speed, color, or other\nparameters can be varied as you alter the pressure which you are\napplying to the pads:\n\n<img alt=\"Push Interface\"\nsrc=\"doc/modules/ROOT/assets/images/GrandMaster2.jpg\" width=\"1200\"\nheight=\"978\">\n\nYou can adjust running effects, scroll around the cue grid, and adjust\nor sync the show metronome from either interface. Other MIDI\ncontrollers can be mapped to provide similar functionality, and\nhopefully such mappings will make their way into Afterglow soon\n(indeed, the current Novation Launchpad family is now supported too).\nThe Afterglow mappings are done entirely on the User layer as well, so\nthey coexist gracefully with Ableton Live, and you can switch back and\nforth by pressing the User button if you want to perform with both.\n\nBut, getting back to our REPL-based example: We next start the sample\nshow, which runs on DMX universe 1. You will want to have OLA\nconfigured to at least have an dummy universe with that ID so you can\nwatch the DMX values using its web interface. It would be even better\nif you had an actual DMX interface hooked up, and changed the show to\ninclude some real lights you have connected. Either way, here is how\nyou start the show sending control signals to lights:\n\n```clojure\n(use-sample-show) ; Create the sample show that uses universe 1.\n(show/start!)     ; Start sending its DMX frames.\n```\n\nThe `afterglow.examples` namespace includes a helper function,\n`fiat-lux`, to assign a nice cool blue color to all lights in the\nsample show, set their dimmers to full, and open the shutters of the\nTorrent moving-head spots, which can be called like this:\n\n```clojure\n(fiat-lux)\n```\n\nSo if you happened to have the same fixtures hooked up, assigned the\nsame DMX addresses as I did when I wrote this, you would see a bunch\nof blue light. More realistically, you can navigate to the `olad`\nembedded [web server](http://localhost:9090/new/) and see the\nnon-zero DMX values in the blue and dimmer channels, assuming you have\nset up a Universe with ID 1.\n\n> In an environment where you are running multiple shows, the more\n> general way of working with one would look like:\n\n```clojure\n(def another-show (some-function-that-creates-a-show))\n(with-show another-show\n  (show/start!)\n  (fiat-lux))\n```\n\n> However, the `examples` namespace assumes you are just using one,\n> and has set it up as the default show, like this:\n\n```clojure\n(set-default-show! sample-show)\n```\n\n> That saves us the trouble of wrapping all our show manipulation\n> functions inside of `(with-show ...)` to establish a context. You\n> will likely want to do something similar in setting up your own\n> shows, since a single show is the most common scenario. See the\n> `afterglow.show-context`\n> [API documentation](http://deepsymmetry.org/afterglow/api-doc/afterglow.show-context.html)\n> for more details. The `show-context` namespace also defines the\n> dynamic variable `*show*` which you can use to refer to the current\n> default show when you need to mention it explicitly, as you will see\n> in some of the examples below.\n\nThe actual content of `fiat-lux` is quite simple, creating\nthree effects to achieve the goals mentioned above:\n\n```clojure\n(defn fiat-lux\n  \"Start simple with a cool blue color from all the lights.\"\n  []\n  (show/add-effect! :color (global-color-effect \"slateblue\"\n                    :include-color-wheels? true))\n  (show/add-effect! :dimmers (global-dimmer-effect 255))\n  (show/add-effect! :torrent-shutter\n                    (afterglow.effects.channel/function-effect\n                    \"Torrents Open\" :shutter-open 50\n                    (show/fixtures-named \"torrent\"))))\n```\n\nWe can make the lights a little dimmer...\n\n```clojure\n(show/add-effect! :dimmers (global-dimmer-effect 200))\n```\n\n> Adding a function with the same keyword as an existing function\n> replaces the old one. The dimmer channels drop from 255 to 200.\n\nBut for dimmer channels, there is an even better way of doing that:\n\n```clojure\n(master-set-level (:grand-master *show*) 80)\n```\n\nAll cues which set dimmer levels are tied to a dimmer master chain.\nIf none is specified when creating the cue, they are tied directly\nto the show’s dimmer grand master. Setting this to a value less than\n100 scales the dimmer values sent to the lights down by that amount.\nSo the above command dims the lights to 80% of their possible\nbrightness, no matter what else the cues are trying to do. See the\n[dimmer effects API documentation](http://deepsymmetry.org/afterglow/api-doc/afterglow.effects.dimmer.html)\nfor more details. Here is an example of what I call right away when\ntesting effects in my office with the little Korg nanoKONTROL 2\nplugged in:\n\n```clojure\n(show/add-midi-control-to-master-mapping \"slider\" 0 7)\n```\n\nAnd then the last fader acts as my grand master dimmer, and I can\nquickly get relief from overly bright lights. (In a real performance\ncontext, you would want to use [this alternate\napproach](https://afterglow-guide.deepsymmetry.org/afterglow/mapping_sync.html#automatic-bindings)\nto automatically set up your bindings whenever the controller is\nconnected. That way, if someone trips over the controller cable, as\nsoon as you plug it back in, you are good to go again.)\n\n> If you have an Ableton Push, it is even easier to have [intutive\n> control](https://afterglow-guide.deepsymmetry.org/afterglow/push2.html#show-control)\n> over your show’s grand master dimmer. As soon as you bind the Push\n> to your show, the Push Master encoder is automatically tied to the\n> show master dimmer, with nice graphical feedback in the text area.\n> Plus you get deep control over the show metronome as well, as shown\n> in the photo above. If you called `(use-sample-show)` as discussed\n> above, as soon as you connect and power on your Push, Afterglow will\n> activate its show control interface.\n\nMoving on, though... we can change the global color to orange:\n\n```clojure\n(show/add-effect! :color (global-color-effect :orange))\n```\n\n> The color channel values change.\n\nLet’s get a little fancy and ramp the dimmers up on a sawtooth curve each beat:\n\n```clojure\n(show/add-effect! :dimmers\n                  (global-dimmer-effect (oscillators/build-oscillated-param\n                                        (oscillators/sawtooth))))\n```\n\nSlow that down a little:\n\n```clojure\n(afterglow.rhythm/metro-bpm (:metronome *show*) 70)\n```\n\n> If you have a web browser open on\n> [your OLA daemon](http://localhost:9090/ola.html)’s DMX monitor for\n> Universe 1, you will see the values for channels changing, then\n> ramping up quickly, then a little more slowly after you change the\n> BPM. OLA 0.9.5 introduced a new, beta web UI based on AngularJS\n> which you can access through a small\n> [New UI (Beta)](http://localhost:9090/new/) link at the bottom of\n> the page. In my experience, it has been completely stable, looks a\n> lot better, and is *far* more dynamic and responsive at monitoring\n> changing DMX values, and presenting them in an intuitive at-a-glance\n> way.\n\nIf you can, alter the example to use a universe and channels that you\nwill actually be able to see with a connected fixture, and watch\nClojure seize control of your lights!\n\n### Further Experiments\n\nIf you have DJ software or a mixer sending you MIDI clock data, you\ncan sync the show’s BPM to it (see the [Developer\nGuide](https://afterglow-guide.deepsymmetry.org/afterglow/mapping_sync.html#syncing-to-midi-clock)\nfor details, and for a Traktor controller mapping file that lets you\nsync to its beat phase information as well):\n\n```clojure\n(show/sync-to-external-clock (afterglow.midi/sync-to-midi-clock \"traktor\"))\n```\n\nHow about a nice cycling rainbow color fade?\n\n```clojure\n(def hue-param (oscillators/build-oscillated-param (oscillators/sawtooth :interval :bar)\n                                                   :max 360))\n(show/add-effect! :color (global-color-effect\n  (params/build-color-param :s 100 :l 50 :h hue-param)))\n```\n\nOr, if you need to be woken up a bit,\n\n```clojure\n(show/add-effect! :strobe (afterglow.effects.channel/function-cue\n  \"Fast blast!\" :strobe 100 (show/all-fixtures)))\n```\n\n> The [Developer Guide](https://afterglow-guide.deepsymmetry.org) has\n> more examples of [building\n> effects](https://afterglow-guide.deepsymmetry.org/afterglow/effects.html#effect-examples),\n> and [mapping\n> parameters](https://afterglow-guide.deepsymmetry.org/afterglow/mapping_sync.html)\n> to MIDI controllers. There is also low-level [API\n> documentation](http://deepsymmetry.org/afterglow/api-doc), but the\n> project documentation is the best starting point for a conceptual\n> overview and introduction.\n\nWhen you are all done, you can terminate the effect handler thread...\n\n```clojure\n(show/stop!)\n```\n\nAnd darken the universe you were playing with.\n\n```clojure\n(show/blackout-show)\n```\n\n> An alternate way of accomplishing those last two steps would have\n> been to call `(show/clear-effects!)` before `(show/stop!)` because\n> once there were were no active effects, all the DMX values would\n> settle back at zero and stay there until you stopped the show.\n\n## Troubleshooting\n\nWhen afterglow has important events to report, or encounters problems,\nit writes log entries. In its default configuration, it tries to write\nto a `logs` directory located in the current working directory from\nwhich it was run. If that directory does not exist, and you have not\nexplicitly configured a path to a log file, it assumes you are not\ninterested in the logs, and silently suppresses them. So if things are\nnot going right, the first step is to enable logging. You can either\ndo this by creating a `logs` folder for Afterglow to use, or by\nrunning it with the `-l` command-line argument to set an explicit log\nfile path, as described in the [Usage](#usage) section above. If you\ndo that, afterglow will create any missing directories in the log file\npath, and fail with a clear error message if it is unable to log to\nthe place you asked it to.\n\nThe Open Lighting Architecture&rsquo;s\n[web interface](http://localhost:9090/new/#/), which you can find on\nport 9090 of the machine running afterglow if you installed it in the\nnormal way, can be useful in troubleshooting as well. You can see if\nthe universes that afterglow is expecting to interact with actually\nexist, are configured to talk to the lighting interfaces you expect,\nand are sending DMX channel values that seem reasonable.\n\n## Bugs\n\nAlthough there are none known as of the time of this release, I am\nsure some will be found, especially if you are tracking the master\nbranch to keep up with the current rapid pace of development. Please\nfeel free to log\n[issues](https://github.com/Deep-Symmetry/afterglow/issues) as you\nencounter them!\n\n## What Next?\n\nEverything beyond this point in this document is written for people\nwho are working on enhancing Afterglow itself.\n\nIf you are trying to learn how to use it, jump to the main [Developer\nGuide](https://afterglow-guide.deepsymmetry.org) page now!\n\n## Release Checklist\n\nHere is the set of tasks needed to cut a new release:\n\n### Prerelease Steps\n\n- [ ] Check over the documentation. If any moving screen captures are\n  needed, see this [gist](https://gist.github.com/dergachev/4627207).\n  The command I have used so far is: `ffmpeg -i ~/Desktop/Cues.mov\n  -pix_fmt rgb24 -r 10 -f gif - | gifsicle --optimize=3 --delay=10 >\n  ~/Desktop/Cues.gif`\n- [ ] Update [`CHANGELOG.md`](CHANGELOG.md) to reflect the release:\n  make sure nothing is missing, and rename the sections to reflect the\n  fact that the unreleased code is now released, and there is nothing\n  unreleased.\n- [ ] Tag the repository with a non -SNAPSHOT version.\n\n### Release Steps\n\n- [ ] Commit everything including the rebuilt API docs, tag the commit\n  with the tag name used above, and push including the tag. `git\n  commit -a`, `git tag -a v0.2.0 -m \"Release 0.2.0\"`, `git push --tags`.\n- [ ] Deploy the release to Clojars: `lein deploy clojars`.\n\n### Postrelease Steps\n\n- [ ] Update [`CHANGELOG.md`](CHANGELOG.md) to include a new\n  unreleased section.\n- [ ] Tag the repository with a new -SNAPSHOT version.\n- [ ] Commit and push.\n\n## Tasks\n\nTo a large extent, this is now historical, and issue and enhancement\ntracking has moved to the\n[issues](https://github.com/Deep-Symmetry/afterglow/issues) system. There\nare still some interesting ideas here for longer-term consideration,\nthough.\n\n- [x] Sync metronomes to MIDI\n- [x] Add metronome chase for clear sync testing\n- [x] Allow parameterized effects functions\n- [x] Start wiki\n- [x] Allow metronomes to be show variables\n- [x] Improve Oscillators\n  - [x] Use keyword parameters\n  - [x] Add phrase oscillators\n  - [x] Finish wiki page\n- [x] Migrate wiki documentation into project documentation.\n- [x] Have metronome cue take metronome parameter and support dynamic\n  parameters.\n- [x] Consider having patched fixture hold a reference to the show.\n  That way we could stop having to pass it so many places, though it\n  would make printing fixtures less useful. (Not needed; dynamic\n  binding works better.)\n- [x] Add support for named fixture functions which exist as a value\n  range subset of a channel, and effects which set them to particular\n  values.\n- [x] Allow scaling of named fixture functions, for example to allow a\n  strobe effect to be set to a rough Hz value despite differences in\n  fixture implementation.\n- [x] Add color wheel support.\n- [x] Review existing fixture definitions for consistency of function\n  names, start a style guide in the docs for others creating fixture\n  definitions.\n- [x] Add configuration support for running OLA on a different machine.\n- [ ] Make pass over all source, flesh out API doc and preconditions.\n- [ ] Sparkle effect, essentially a particle generator with\n  configurable maximum brightness, fade time, distribution.\n  - [x] Get basic effect working until spatial features are available.\n  - [ ] Work both with arbitrary head list, and with spatially mapped origin/density.\n  - [ ] Work as single intensity, or spatially mapped hue/saturation patterns.\n- [x] Implement a grand master dimmer in the show which imposes a\n    ceiling on all dimmer cues.\n  - [x] Also allow custom sub-master dimmer variables, chained off\n    each other and ultimately the grand master, assigned to cues. Each\n    step can scale the output.\n  - [x] All dimmer cues are assigned a master chain, defaulting to the\n    grand master if none supplied.\n- [x] Consider implementing virtual dimmer effects to allow fixtures\n  which lack actual dimmer channels to simulate them and participate\n  in the dimmer master chain, as proposed\n  [here](https://github.com/Deep-Symmetry/afterglow/issues/43).\n- [x] Get geometry engine and head-movement cues working.\n- [x] Named cues: Define cues with a unique name so they can have\n  parameters saved for them, to be reloaded on future runs, once we\n  have a database. Also useful for compound cues, see below.\n  - [x] This requires cues to have a mechanism for reporting their\n    current variable values for saving, and to look them up when\n    saved.\n- [ ] Compound cues:\n  - [x] Unflattened compound cues trigger multiple cues&rsquo; effects:\n    - [x] Each effect gets its own priority, parameters.\n    - [x] The compound finishes when all triggered effects do.\n    - [x] Implement by having the outer cue&rsquo;s effect call\n      `show/add-effect-from-cue-grid!` to launch all the nested\n      effects, recording their IDs. The effect will never return any\n      assigners, but will report that it has ended when all of the\n      nested effects have ended. Telling this effect to end will, in\n      turn, call `show/end-effect!` on all nested cues (passing their\n      recorded id values as `:when-id`, to avoid inadvertently killing\n      later effects run under the same key).\n    - [x] Add a `:variable-overrides` parameter to\n      `show/add-effect-from-cue-grid!` so compound cues can use it to\n      customize the values of parameters introduced by nested cues.\n  - [ ] Flattened compound cues flatten their nested cues&rsquo; effects\n    into a single new effect:\n    - [ ] This effect gets assigned a new priority.\n    - [ ] The compound cue aggregates nested cue variables into one\n      big list, and passes them down to the nested effects. (Renaming\n      with numeric suffixes as needed to avoid name clashes? No, they\n      might be shared.)\n  - [ ] Compound cues created from solely named cues can be saved and\n    restored, so they can be built using the web (and rich controller)\n    interface out of existing cues, and current parameter values for\n    running cues.\n    - [ ] When creating a compound cue this way, will need to check\n      for and prevent circular definitions, as well as reporting\n      sensible errors when constituent cues can no longer be found.\n- [x] Compound effects:\n  - [x] Simplest compound effect just delegates to nested effects,\n    returning concatenated assigners. But implement as a fade with\n    time zero?\n  - [x] Fade compound effect: fade in at start, out at end.\n  - [x] Cue list compound effect: Move through list of embedded\n    effects, with optional fades. Loops, driven by metronome, or a\n    variable parameter (knob controls where in the list we are). Maybe\n    different implementations?\n  - [x] Have effects pass a context map to children with show,\n    snapshot, own stuff? For example, so the children can be aware of\n    build, duration, a shared palette, other things? Or better, since\n    snapshot is already passed, just add a usually-nil section which\n    contains information about context, with at least information\n    about when overall effect started; current fade level of this\n    effect, fading in or out, when effect will end. Even better: This\n    can be assoc-ed on to the snapshot, without changing the\n    definition in rhythm.clj, since Clojure records are also maps!\n    _This seems to be unnecessary given how fades and chases ended up\n    being actually implemented._\n  - [x] Effects which can do their own blending implement an\n    additional interface. Otherwise the fade and chase effects (if\n    they are different), handle it. To fade between direction effects,\n    convert them to pan/tilt numbers, scale between those, then\n    convert back to a direction. _This was implemented as a\n    multimethod for each of the effect assigner types._\n- [ ] Provide a mechanism for creating and controlling/monitoring\n  effects via OSC messages. Probably essentially a special-purpose OSC\n  REPL.\n- [x] Add web page for viewing/adjusting cue variables; associate\n  metadata with the variables so the page can provide appropriate\n  editing tools and validation. Values live-update when controllers\n  change them.\n- [ ] When it comes time to save data and settings, the luminus\n  approach looks good, including\n  [yesql](https://yobriefca.se/blog/2014/11/25/yesql-sql-in-sql-in-clojure/)\n  and h2 as the database. Need to figure out where it would be stored,\n  though.\n- [x] See if I can get Traktor to just send beat notes for master\n  track; if so, add mode for MIDI sync to ride them like DJ link.\n  - [x] See example on page 166 of Traktor Bible; it is close, but I\n    want to add a condition that makes sure these pulses are sent only\n    for the deck which is currently the tempo master. Write to the\n    author for advice? Alternately, send separate messages when each\n    deck is set as the tempo master, and use those to keep track of\n    which beat pulses to pay attention to?\n- [ ] See if I can detect which Pro DJ Link device is the current\n  master, and if so, add an option for down beat tracking using that.\n- [x] Add tap tempo support for really low-end sync.\n- [x] Add machine-readable metronome sync status flag, so Push can\n  color code it; detect stalled clocks even without stop signals.\n- [x] See how Afterglow works as a hosted Max package, with an Inlet\n  to send Clojure code to be evaluated, and an outlet for the results.\n  This could be a quick way to add beat detection, sound spectrum\n  analysis, etc.\n  https://pcm.peabody.jhu.edu/~gwright/stdmp/docs/writingmaxexternalsinjava.pdf\n  https://docs.cycling74.com/max7/tutorials/jitterchapter51\n  https://docs.cycling74.com/max7/vignettes/packages\n- [ ] Consider creating a\n  [Processing Library](https://github.com/processing/processing/wiki/Library-Overview)\n  for Afterglow. They are far more invested in the Java ecosystem than\n  Max is, anyway.\n- [x] Provide a way to import QLC+ fixture definitions to help people\n  get started.\n- [ ] Consider importing [Avolites](http://personalities.avolites.com)\n  personalities/fixture definitions (D4 files); they seem fairly\n  straightforward too.\n- [x] Separate, or at least document clearly, how to use the low-level\n  OLA communication tools, for the benefit of people interested in\n  their own implementations.\n- [x] Support Push version 2 if possible. As of March, 2016 this is\n  looking possible! Ableton has published\n  [detailed documentation](https://github.com/Ableton/push-interface)\n  of the MIDI and USB interfaces of the Push 2 and display.\n  - [x] For the display, I will need [Libusb](http://libusb.info/),\n    and there is a promising-looking Java wrapper,\n    [usb4Java](http://usb4java.org). Although there is a start at\n    [Clojure bindings](https://github.com/aamedina/tools.usb), it does\n    not seem to have gotten far.\n  - [x] Embed some [fonts](https://www.google.com/fonts#ReviewPlace:refine/Collection:Roboto|Open+Sans+Condensed:300|Source+Sans+Pro:400,200italic).\n- [x] Support the Novation Launchpad series. The Pro has pressure\n  sensitivity, so start there. They also provide excellent programmer\n  documentation, so it will even be straightforward. For example,\n  [Launchpad Pro Programmers Reference Guide](http://global.novationmusic.com/sites/default/files/novation/downloads/10598/launchpad-pro-programmers-reference-guide_0.pdf),\n  found on their\n  [Downloads Page](http://global.novationmusic.com/support/product-downloads?product=Launchpad+Pro).\n  Having someone loan me one would speed this up!\n  - [x] Novation is loaning me a Launchpad Mini! It\n    [seems](http://www.soundonsound.com/sos/jan14/articles/novation-launchpad.htm)\n    to use the same control messages as the Launchpad S, so refer to\n    that guide in trying to set it up. Has only red/green 2 bit LEDs, so\n    don&rsquo;t try to replicate colors from the cue grid.\n  - [x] Novation Launchpad Mk2 support added with the testing help of\n    [Benjamin Gudehus](https://github.com/hastebrot).\n\n### Ideas\n\n- [x] Model moving head location and position, so they can be panned and aimed in a coordinated way.\n  - [x] [Wikipedia](http://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions)\n    has the most promising overview of what I need to do.\n  - [ ] Use iOS device to help determine orientation of fixture: Hold\n    phone upright facing stage from audience perspective to set\n    reference attitude; move to match a landmark on the fixture\n    (documented in the fixture definition), and have phone use\n    [CoreMotion](https://developer.apple.com/library/ios/documentation/CoreMotion/Reference/CMAttitude_Class/index.html#//apple_ref/occ/instm/CMAttitude/multiplyByInverseOfAttitude:)\n    `CMAttitude` `multiplyByInverseOfAttitude` to determine the\n    difference.\n  - [x] The more I investigate, the more it looks like\n    [Java3D’s](http://docs.oracle.com/cd/E17802_01/j2se/javase/technologies/desktop/java3d/forDevelopers/J3D_1_3_API/j3dapi/)\n    [Transform3D](http://docs.oracle.com/cd/E17802_01/j2se/javase/technologies/desktop/java3d/forDevelopers/J3D_1_3_API/j3dapi/javax/media/j3d/Transform3D.html)\n    object is going to handle it for me, which is very convenient, as\n    it is already available in Clojure. To combine transformations,\n    just multiply them together (with the `mul` method).\n  - [x] Use `setEuler` to set a `Transform3D` to a specific set of\n    rotation angles.\n  - [x] If this leads to accuracy issues or loss of a degree of\n    freedom, consider Quaternions, as recommended in\n  this [article](http://java.sys-con.com/node/99792).\n  - [x] Wow, this may be exactly what I need: Java code for converting\n    Quaternions to Euler Angles:\n  http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/\n  The site is in general an amazing reference for the kind of geometry I need to learn.\n  - [x] This seems to be the formula I need to figure out the angles\n    to send a light to make it face a particular direction (the\n    selected, top answer):\n    http://stackoverflow.com/questions/1251828/calculate-rotations-to-look-at-a-3d-point\n    and transform.clj has an implementation in invert-direction. Now I\n    just need to test it with an actual light!\n  - [x] Remember that Vector3d has nice methods like angle (calculate\n    angle to another Vector3d), length, cross, dot...\n- [ ] Render preview animations of a light show using WebGL.\n  - [x] This [shader](https://www.shadertoy.com/view/Mlj3W1) looks\n    nearly perfect, if I can figure out how to adopt it.\n  - [x] Looks like a nice intro to 3D, linear algebra, shaders:\n    [Making WebGL Dance](http://acko.net/files/fullfrontal/fullfrontal/webglmath/online.html).\n    Has interesting references too, such as\n    [Interactive 3D Graphics Course](https://www.udacity.com/course/interactive-3d-graphics--cs291),\n    Eric Haines, Udacity.com. And the\n    [Aerotwist tutorials](https://aerotwist.com/tutorials/), in\n    particular Three.js and shaders.\n  - [x] Fix the transform of lights into the WebGL shader space;\n    currently inconsistent.\n  - [ ] See if someone can come up with a more bare bones but scalable preview, probably building a geometry of the light cones instead of ray marching through them.\n- [ ] Add a Focus effect type, which is resolved after direction and aim\n  effects are; this will allow, for example, fixtures to be annotated\n  with functions that map from focal distance to DMX value (the\n  Torrents would have two such functions, one for each gobo wheel),\n  and those functions could be used by an auto-focus effect which\n  would be given geometry information about the planes in the room\n  (floor, ceiling, walls, screens), could figure out the distance to\n  the nearest one the fixture is pointing at, and automatically\n  generate a focus channel value to focus at that distance. A fade\n  could be used with an oscillator to bounce back and forth between\n  focus on each gobo wheel.\n- [x] Use [claypoole](https://clojars.org/com.climate/claypoole) for\n  parallelism.\n- [ ] Change to core.async for all parallelism, since we are already using it anyway.\n- [ ] Add OSC support (probably using\n  [Overtone&rsquo;s implementation](https://github.com/rosejn/osc-clj))\n  for controller support, and MIDI as well.\n- [x] Serious references for color manipulation, but in [Julia](https://github.com/timholy/Color.jl).\n- [ ] Absolutely amazing reference on\n  [color vision](http://handprint.com/LS/CVS/color.html)! Send him a\n  note asking if he knows where I can find an algorithm for using\n  arbitrary LEDs to make an HSL color!\n  - [ ] Consider an alternate HSI color implementation. It could yield more\n  pure/accurate results, but perhaps with less intuitive semantics,\n  and definitely lower peak output. Most likely a configurable option?\n  See the discussion and code on the\n  [SaikoLED blog](http://blog.saikoled.com/post/44677718712/how-to-convert-from-hsi-to-rgb-white).\n  And [related discussion](http://blog.saikoled.com/post/43693602826/why-every-led-light-should-be-using-hsi),\n  with links to color correction.\n- [ ] When it is time to optimize performance, study the\n  [type hints](http://clojure.org/java_interop#Java%20Interop-Type%20Hints)\n  interop information looks very informative and helpful.\n  - [ ] satisfies? seems to take twice as long as instance? so change the preconditions to use instance? where possible\n  - [ ] Do a pass through all files with *warn-on-reflection* set to\n    true, see what hinting can help. `(set! *warn-on-reflection*\n    true)` at top of file.\n- [ ] Eventually create a leiningen task that can build a standalone\n  jar with Afterglow and a custom show definition file and its\n  supporting resources, so developers can easily deploy and share\n  shows with non-Clojurists.\n- [ ] Consider adding support for metronome synchronization with\n  [EspGrid](https://github.com/d0kt0r0/EspGrid).\n- [ ] Investigate whether\n  [Vamp](https://code.soundsoftware.ac.uk/projects/vamp) (and jVamp)\n  would be worthwhile for audio analysis. But adding native components\n  is likely to be a hassle.\n- [ ] See if [thi-ng/color](https://github.com/thi-ng/color) is a\n  better fit.\n- [x] Once I release the first version, answer this StackOverflow\n  [question](http://stackoverflow.com/questions/9582192/dmx-software-to-control-lights-with-programmable-interface).\n  - [x] Also submit a link to\n    [TOPLAP](http://toplap.org/contact-page/).\n  - [ ] Also post a followup to this\n    [article](http://radar.oreilly.com/2015/05/creative-computing-with-clojure.html)\n    and reach out to some of the artists themselves. (Sadly too late\n    to post a comment on the thread, but I should try contacting the\n    artists!)\n\n### References\n\n* Clojure implementation of Protocol Buffers via\n  [lein-protobuf](https://github.com/flatland/lein-protobuf) and\n  [clojure-protobuf](https://github.com/flatland/clojure-protobuf).\n* The incomplete\n  [Java OLA client](https://github.com/OpenLightingProject/ola/tree/master/java).\n* Making [Animated GIF Screencasts](https://gist.github.com/dergachev/4627207).\n\n### Related Work\n\n- [x] Rich controller support for\n  [Ableton Push](https://forum.ableton.com/viewtopic.php?f=55&t=193744)!\n  - [x] [Color chart](https://forum.ableton.com/viewtopic.php?f=55&t=192920),\n    post a followup if my hue theory pans out.\n  - [x] Nice\n    [breakdown](http://tai-studio.org/index.php/projects/sound-programming/accessing-abletons-push-device/)\n    of button sections.\n  - [x] It looks like I can actually specify an RGB color for the buttons using another SysEx:\n    [PushPix](https://cycling74.com/wiki/index.php?title=Push_Programming_Oct13_03)\n- [ ] Could add basic grid control using the\n  [Livid Ohm RGB](http://wiki.lividinstruments.com/wiki/OhmRGB),\n  alhough it supports only 7 colors, no pressure sensitivity, and has\n  been discontinued, so this is a low priority even though we own one,\n  unless/until someone requests it.\n- [x] Add a user interface using [Luminus](http://www.luminusweb.net/docs).\n- [x] Separate [ola-clojure](https://github.com/Deep-Symmetry/ola-clojure#ola-clojure) into its own project.\n\n## License\n\n<a href=\"http://deepsymmetry.org\"><img align=\"right\" alt=\"Deep Symmetry\"\n src=\"doc/modules/ROOT/assets/images/DS-logo-github.png\" width=\"250\" height=\"150\"></a>\n\nCopyright © 2015-2023 [Deep Symmetry, LLC](http://deepsymmetry.org)\n\nDistributed under the [Eclipse Public License\n2.0](https://opensource.org/licenses/EPL-2.0). By using this software\nin any fashion, you are agreeing to be bound by the terms of this\nlicense. You must not remove this notice, or any other, from this\nsoftware. A copy of the license can be found in\n[LICENSE](https://github.com/Deep-Symmetry/afterglow/blob/master/LICENSE)\nwithin this project.\n\n<a href=\"https://www.netlify.com\">\n  <img align=\"right\" src=\"https://www.netlify.com/img/global/badges/netlify-color-accent.svg\"/>\n</a>\n\n### [Antora](https://antora.org)\n\nAntora is used to build the [Developer\nGuide](https://afterglow-guide.deepsymmetry.org), for embedding inside\nthe application, and hosting on [Netlify](https://www.netlify.com).\nAntora is licensed under the [Mozilla Public License Version\n2.0](https://www.mozilla.org/en-US/MPL/2.0/) (MPL-2.0).\n"
  },
  {
    "path": "doc/README.md",
    "content": "# Developer Guide Module\n\n> :mag_right: If you are looking for the online documentation, it has\n> [moved](https://afterglow-guide.deepsymmetry.org/) off of\n> GitHub to become easier to read and navigate.\n\nAfterglow now uses [Antora](https://antora.org) to build its Developer\nGuide. this folder hosts the documentation module and playbooks used\nto build it. `embedded.yml` is used to create the self-hosted version\nwhich is served out of Afterglow itself, so it can be used even\nwithout an Internet connection, and `github-actions.yml` is used to build the\n[online version](https://afterglow-guide.deepsymmetry.org/) that is\nbuilt by GitHub Actions.\n\nThe Leiningen project in the root of this repository automatically\ninvokes Antora to build the embedded version as an early build step.\nThe online version, which will grow to support multiple released\nversions of Afterglow, is built automatically whenever changes are\npushed to the relevant branches on GitHub.\n"
  },
  {
    "path": "doc/antora.yml",
    "content": "name: afterglow\ntitle: Afterglow\nversion: ~\ndisplay_version: 'main'\nprerelease: true\nstart_page: ROOT:README.adoc\nasciidoc:\n  attributes:\n    icons: font\n    experimental: ''\n    page-copyright: 2015–2022\n    page-pagination: ''\nnav:\n- modules/ROOT/nav.adoc\n"
  },
  {
    "path": "doc/ds.yml",
    "content": "site:\n  title: Afterglow Developer Guide\n  url: https://deepsymmetry.org/afterglow/guide\n  start_page: afterglow::README.adoc\ncontent:\n  sources:\n  - url: https://github.com/Deep-Symmetry/afterglow.git\n    branches: [main, guide*]\n    tags: va*\n    start_path: doc\nantora:\n  extensions:\n  - require: '@antora/lunr-extension'\n    index_latest_only: true\nasciidoc:\n  attributes:\n    api-doc: http://deepsymmetry.org/afterglow/api-doc/\n    icons: font\n    experimental: ''\nui:\n  bundle:\n    url: https://deepsymmetry.org/media/antora/ui-bundle-3.zip\n    snapshot: true\n"
  },
  {
    "path": "doc/embedded.yml",
    "content": "site:\n  title: Afterglow Developer Guide\n  url: http:/guide\n  start_page: afterglow::README.adoc\ncontent:\n  edit_url: false\n  sources:\n  - url: ./..\n    branches: HEAD\n    start_path: doc\nantora:\n  extensions:\n  - '@antora/lunr-extension'\nasciidoc:\n  attributes:\n    api-doc: link:../../api-doc/\n    icons: font\n    experimental: ''\nui:\n  bundle:\n    url: https://deepsymmetry.org/media/antora/ui-bundle-3-self.zip\n    snapshot: true\noutput:\n  dir: ./../target/classes/developer_guide\n"
  },
  {
    "path": "doc/github-actions.yml",
    "content": "site:\n  title: Afterglow Developer Guide\n  url: https://afterglow-guide.deepsymmetry.org/\n  start_page: afterglow::README.adoc\n  robots: allow\n  keys:\n    google_analytics: G-ZNLRY347Y7\nurls:\n  redirect_facility: httpd\ncontent:\n  sources:\n  - url: https://github.com/Deep-Symmetry/afterglow.git\n    branches: [main, guide*]\n    start_path: doc\nantora:\n  extensions:\n  - require: '@antora/lunr-extension'\n    index_latest_only: true\nasciidoc:\n  attributes:\n    api-doc: https://afterglow-guide.deepsymmetry.org/api/\n    icons: font\n    experimental: ''\nui:\n  bundle:\n    url: https://deepsymmetry.org/media/antora/ui-bundle-3-self.zip\n    snapshot: true\n"
  },
  {
    "path": "doc/modules/ROOT/assets/source/Afterglow logo.ai",
    "content": "%PDF-1.5\r%\r\n1 0 obj\r<</Metadata 2 0 R/OCProperties<</D<</ON[5 0 R 31 0 R 81 0 R 131 0 R]/Order 132 0 R/RBGroups[]>>/OCGs[5 0 R 31 0 R 81 0 R 131 0 R]>>/Pages 3 0 R/Type/Catalog>>\rendobj\r2 0 obj\r<</Length 50109/Subtype/XML/Type/Metadata>>stream\r\n<?xpacket begin=\"﻿\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"Adobe XMP Core 5.6-c067 79.157747, 2015/03/30-23:40:42        \">\n   <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n      <rdf:Description rdf:about=\"\"\n            xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n            xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\"\n            xmlns:xmpGImg=\"http://ns.adobe.com/xap/1.0/g/img/\"\n            xmlns:xmpMM=\"http://ns.adobe.com/xap/1.0/mm/\"\n            xmlns:stRef=\"http://ns.adobe.com/xap/1.0/sType/ResourceRef#\"\n            xmlns:stEvt=\"http://ns.adobe.com/xap/1.0/sType/ResourceEvent#\"\n            xmlns:stMfs=\"http://ns.adobe.com/xap/1.0/sType/ManifestItem#\"\n            xmlns:illustrator=\"http://ns.adobe.com/illustrator/1.0/\"\n            xmlns:xmpTPg=\"http://ns.adobe.com/xap/1.0/t/pg/\"\n            xmlns:stDim=\"http://ns.adobe.com/xap/1.0/sType/Dimensions#\"\n            xmlns:xmpG=\"http://ns.adobe.com/xap/1.0/g/\"\n            xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n         <dc:format>application/pdf</dc:format>\n         <dc:title>\n            <rdf:Alt>\n               <rdf:li xml:lang=\"x-default\">OLA Logo RGB CS6</rdf:li>\n            </rdf:Alt>\n         </dc:title>\n         <xmp:MetadataDate>2015-07-20T14:20:46-05:00</xmp:MetadataDate>\n         <xmp:ModifyDate>2015-07-20T14:20:46-05:00</xmp:ModifyDate>\n         <xmp:CreateDate>2015-07-20T12:06:36-05:00</xmp:CreateDate>\n         <xmp:CreatorTool>Adobe Illustrator CC 2015 (Macintosh)</xmp:CreatorTool>\n         <xmp:Thumbnails>\n            <rdf:Alt>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <xmpGImg:width>256</xmpGImg:width>\n                  <xmpGImg:height>136</xmpGImg:height>\n                  <xmpGImg:format>JPEG</xmpGImg:format>\n                  <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAiAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FVk88EELzT&#xA;yLFDGC0krkKqqOpLHYDFXknnL/nKf8pfLbvBBfSa9eJUGLS1EsYPvOzJCR/qM3yxV5Fr3/ObvmKV&#xA;2XQPLdpaJ0V76WS5Y+5WL6uB8qnFWHXn/OXP5zzvyivbO0H8kNpGR/yV9U/jiqEj/wCcrPzwVnLa&#xA;5E4Y1VWsrOi+w4xA/fXFU203/nMb83LVl+sppmoKKBhPbMhNOprBJFucVZ/5b/5zesndI/MvlqSF&#xA;f27rTphL/wAkJhH/AMncVe1eR/zq/LXzqUi0TWoTfv0025/0e6r4LHJTn/sOQxVnGKuxV2KuxV2K&#xA;uxVLPM3/ABwb3/jGf1jJQ5uVov76PveUXH90cyC9ZDmxfVP2sw8rtcDFb3+9HzzUah2+LkmOnds1&#xA;OVxszKtN7ZrcrqszKdN7ZrsrqszIF/uRmH1dXlSvUv7psysPN1uo5PPte/azpNG8lrmIf7ub551O&#xA;jecyJhbds6zROJNf+1mVld92ejYvsDMGXN6vF9L6cznnJdirsVeV/nB/zkL5R/LuN7Ef7lvMrLWP&#xA;SoWAEdRUNcyb+mKbgULHwpvir41/MT84vPvn65Ztd1FhYcuUOlW5MVpHQ1H7oE8yP5nJb3xVhOKt&#xA;gEmg3JxVMbby35hugGttMupVPRkhkK7+4FMujp8kuUT8mByRHMhE/wCCvN3/AFZ7v/kU39Ml+Uy/&#xA;zT8mPjQ7wgLvRtYsxW8sbi2A7zROnv8AtAZXLFOPMEfBmJxPIoPK2TYJBBBoRuCOtcVe1flb/wA5&#xA;TeefKLw2OuO/mLQVopiuHJu4l6fubhqk0/lkqOwK4q+xvIn5heVPPWirq/ly8W5g2W4gb4Z4HIrw&#xA;mj6q34HsSMVZHirsVdirsVSzzN/xwb3/AIxn9YyUOblaL++j73lFx/dHMgvWQ5sX1T9rMPK7XAxW&#xA;9/vR881Godvi5Jjp3bNTlcbMyrTe2a3K6rMynTe2a7K6rMyBf7kZh9XV5Ur1L+6bMrDzdbqOTz7X&#xA;v2s6TRvJa5iH+7m+edTo3nMiYW3bOs0TiTX/ALWZWV33Z6Ni+wMwZc3q8X0vpzOecl2Kvnn/AJyK&#xA;/wCckF8rev5T8oTq/mMjjf6ivF0sgesaVqGn8aiif63RV8a3FxcXM8lxcyvNcTMXlmkYu7uxqzMx&#xA;qSSepOKq+maTqOqXa2mn273Nw37CCtB4seij3OWY8UpmoiyxlMRFl6f5d/JeFQs+vXBkfr9UtzRR&#xA;7PIRU/7Gnzzc4OyRzyH4Bwcmt/ms/wBL8uaDpShdPsIbcj/diqC/0uaufpObTHp4Q+kAOHLJKXMp&#xA;llzB2KuxVItY8j+VtWVvrWnxrK3+74R6UlfHklK/7KuYuXR4p8w2wzzjyLzXzP8Ak/qdir3OjSG/&#xA;t13NuwAuAPanwv8ARQ+2ajUdlSjvD1D7XOxawHaWzz10dHZHUq6khlIoQR1BGakhzE98keevMvkr&#xA;Xodb8v3ZtruP4ZENTFNHUFopkqOaNTp9IoaHFX3t+T35w+X/AMyvL4vLMi11i1CrqulM1Xhc/tp/&#xA;NE37LfQd8VZ/irsVdiqWeZv+ODe/8Yz+sZKHNytF/fR97yi4/ujmQXrIc2L6p+1mHldrgYre/wB6&#xA;Pnmo1Dt8XJMdO7ZqcrjZmVab2zW5XVZmU6b2zXZXVZmQL/cjMPq6vKlepf3TZlYebrdRyefa9+1n&#xA;SaN5LXMQ/wB3N886nRvOZEwtu2dZonEmv/azKyu+7PRsX2BmDLm9Xi+l9OZzzkvFv+clPzt/wFoK&#xA;6LosoHmrVo29BxQm0tz8LXBH85NRH71PahVfC0kkksjSSMXkclndiSxYmpJJ6k4qn3k/ydqHmXUP&#xA;RhrFaREG6uyKqgPYeLHsMytLpZZpUOXUtObMIDze8aB5d0nQrIWmnQiNf92SHeSRv5nbvnT4MEMU&#xA;aiHU5MhmbKZ5cwdiq2SSONGkkYJGgLO7GgAHUknATSpXZebPLV7dfVLTU7ea4JosayCrHwX+b6Mp&#xA;hqccjQkLbJYpAWQm2XtbsVdirEPPH5eaf5hha5twttqyj4JwKLJQbLLT/iXUZgazQxyixtL8c3Iw&#xA;agw2PJ4Xf2F5YXktneRNDcwtxkjbqD/TwOczOBiaOxDtoyBFhN/IvnfXvJXmW08waJN6d3bGjxtX&#xA;05oiRzhlUEckem/3jcA5FL9Evy9896L568qWfmPSG/cXK8Z7diC8E6/3kL0/aU/eKHocVZHirsVS&#xA;zzN/xwb3/jGf1jJQ5uVov76PveUXH90cyC9ZDmxfVP2sw8rtcDFb3+9HzzUah2+LkmOnds1OVxsz&#xA;KtN7ZrcrqszKdN7ZrsrqszIF/uRmH1dXlSvUv7psysPN1uo5PPte/azpNG8lrmIf7ub551OjecyJ&#xA;hbds6zROJNf+1mVld92ejYvsDMGXN6vF9L6I80+ZNM8s+XdR1/VH4WOmwPPMRTkeI2Ra0qztRVHi&#xA;c55yX5t+d/N+recPNOo+Y9Vfld6hKZOANVjjG0cSf5MaAKPliqt5A8kax5382WHlzSl/0i8f95OR&#xA;VIYV3kmf/JRd/c7dTir9CPJH5ZeTfJmj2mm6Np8QNqATeSqHuJJKAPK0hFQzkVPGg8ABlniy4eG/&#xA;T3MeAXdbsqytkgNT0HRdUUjULGG5JUoHkRS4B68X+0v0HLceacPpJDCWOMuYYTc/kpokmo+tDezw&#xA;WBqXtAFZwSTskrdFG32lY++bGPa8xGiAZd/7HFOijfPZ41/zlt5bsfLHk/QoNHt5I4b66kj1C8aR&#xA;2Z/SjDRxuK8PiJZtlH2cxM2ty5BRO3c349PCO4G75WVmVgykqymqsNiCO4zEbn3v5J/LXR/MX5de&#xA;XNUufWsdWvdLtp7mVGLK80kKt6jxycvtE8qKVzZYu1MsefqcWejgeWzHvNP5ba/oKvcBRfaetSbq&#xA;EGqqKmske5TYbndR45t9N2hjy7cpdzhZdNKG/MMTzOcd2KsN/MfyTHr+nG7tEA1a0UmIjrKg3MR/&#xA;419/nmv1+j8WNj6h+KcnTZ+A0eTwcgqSCKEbEHrXOYds9q/5xZ/NKTyj56j0O+l46D5idLaYMfhi&#xA;ujtbzb9KsfTb2NT9nFX3TirsVSzzN/xwb3/jGf1jJQ5uVov76PveUXH90cyC9ZDmxfVP2sw8rtcD&#xA;Fb3+9HzzUah2+LkmOnds1OVxszKtN7ZrcrqszKdN7ZrsrqszIF/uRmH1dXlSvUv7psysPN1uo5PP&#xA;te/azpNG8lrmIf7ub551OjecyJhbds6zROJNf+1mVld92ejYvsDMGXN6vF9K7/nNTzy9ro+keS7W&#xA;Ti+osdQ1JR19CFuECn/JeXk3zQZzzkvkXFX2V/ziv5O0jyb5Ak8764y29/5h2tnkHxrZRn92iKKs&#xA;TKymQ06rx8Mry5YwFyNBjOYiLLN9Y/OG8eTjpFosUQr+9ufidgV/kUgLQ/5RzT5e1j/APm4E9af4&#xA;Q8e/ND/nIjzx5ceGy0++DaldJ6rM8acIoqlQQqqKsxBpv2y7QzzZblKXp9w/U2aeU57k7IH8qv8A&#xA;nLnzenmO003zs0GoaRezJC9+sSQTWxc8RIfTCo8ak/ECvKm4PY7XkHMfWGk+YNO1QutsxWSPcxSA&#xA;KxX+YUJqMxNLrsea+HmOha8eaM+TBvzf8gaV5h02QajCbixueKzgV5xSKKRyxtvxPb+vLOh0U45I&#xA;+FL4OPqImJ4w8M0r/nHDyfaaitzdXd1f28bcltJCiK1DsJGQAsPlTMiHZkAbJJa5auRD2PTtV1DT&#xA;gq2U7QRrssS/3fSn2DVfwzMyYIT+oNEcko8inesfm/pPl/ytqOta1EVbT4TIscX2Z3JCxxKTXgzu&#xA;wXfb9WabV6E4xxA3Fz8Oo4tjzfGes/nn5kv9bmv7awsbC0lcsunQo5jVSenItWv+rQeAHTHH2nli&#xA;ALv3rLSQL03yv5htvMGjQalAvp+pVZYSalJF2Za7V8R7Z0GmzjLASDrcuMwlSbZe1vD/AM2/LS6Z&#xA;ro1G3Tja6lV2AGyzj+8H+yqG+/Ob7T0/BPiHKX3u00mTijR6MFBIIINCNwR1rmsct+jX5J+dz50/&#xA;LPRdbmfnf+l9W1Enr9Ztz6cjH/jJxEnybFWc4qlnmb/jg3v/ABjP6xkoc3K0X99H3vKLj+6OZBes&#xA;hzYvqn7WYeV2uBit7/ej55qNQ7fFyTHTu2anK42ZlWm9s1uV1WZlOm9s12V1WZkC/wByMw+rq8qV&#xA;6l/dNmVh5ut1HJ59r37WdJo3ktcxD/dzfPOp0bzmRMLbtnWaJxJr/wBrMrK77s9GxfYGYMub1eL6&#xA;Xi3/ADkp5jfXfzl19w/KDTpF023WteItVCSKP+e3qH6c55yXnmj6e2patZaepKm7njg5AVI9Rwta&#xA;e1a5GcxGJkeQRKVC315qeqy3wtoQogsbCGO10+zQnhDBEoRFWvU0UVPf5UGcrqdTLLKz8A6bLlMz&#xA;ZQWY7Uwf82vyU85a5pdn500Gxl1KMq1rc2NuvqTiOJjwnSNSzuC7OjKBUcQehrnRdlxIxb9S7TRg&#xA;8DzjyF+VPm3XPMFqlxp1xY6dDKj3l3cxvCoRSGZU5gcnI2AH07ZLV6/HjgaIMugDZlzxiOe767tr&#xA;me2nSeBzHNGao47HOSx5JQkJRNEOrjIg2HpVjcWuvaJWVQVnUxzoKfC460+1Sh+Jfozt9BrOOMck&#xA;ef6fx9jtoSGSDzG5t5La5lt5KepC7I9OlVNDTOyhISAI6uqkKNKeTYsa/MbyvN5o8m6jo1u4S6mV&#xA;XtmY0X1InEihj4Nx4/TmPqcXiQMQ24p8MgXytH+XvnqTVf0TFoF/LqJbiLeO3kcnenIFQV4/5Vae&#xA;+c3PHKP1CnaxmDyL3ry/+XWueQtFtNJ1tUTULlBeyxowcIZtvTLLUFk4cWptXpUb50XZVeFt3us1&#xA;l8aYZsnFYp+Z+kjUfJ94QtZbOl1GfD0/t/8AJMtmD2ji48J8t3I00+GY83z/AJyzt31j/wA4Q+ZG&#xA;ey8y+WpG+GGSHUbZP+MqmGc/8k4sVfUeKpZ5m/44N7/xjP6xkoc3K0X99H3vKLj+6OZBeshzYvqn&#xA;7WYeV2uBit7/AHo+eajUO3xckx07tmpyuNmZVpvbNbldVmZTpvbNdldVmZAv9yMw+rq8qV6l/dNm&#xA;Vh5ut1HJ59r37WdJo3ktcxD/AHc3zzqdG85kTC27Z1micSa/9rMrK77s9GxfYGYMub1eL6Xyz5k1&#xA;JtU8xapqTNya+u57ktWtTNKz1rQfzeGc85Kf/lLZi5896eWFVgEsxHusbBf+GIzB7RlWE+bj6o1j&#xA;L6KzmXUOxV7/AHqjQ/KpggYn6pbpbxyCitWgjD7d6nlnTaqXg6c10Ffot3GT0Y9ugeb5xrqnYqyj&#xA;yJqJivpLFz8FwOUY32dBU07brWvyGbrsXUcMzA8pfeP2fc5mknR4e9D+erIwawLgA8LpA3I9OafC&#xA;QPoCn6c9E7NyXjr+ax1calfexzNi4rsVTTyxevaa5aupPGVxC4rQFZPh3+RofozF1mPixHy3+Tdg&#xA;lUwivzs09JNGsL/f1Le4MNB04TIWJP0xCnzzB7InUzHvH3f2uTrY+kF47nQOtUb22S6s57Z/sTxv&#xA;E3ydSp/XkZx4gR3pBo2+W2UqxVhQg0IPiM4p3z3X/nDbUHtvzamthXhfaXcRMO1UkilB/wCSdPpx&#xA;V9vYqlnmb/jg3v8AxjP6xkoc3K0X99H3vKLj+6OZBeshzYvqn7WYeV2uBit7/ej55qNQ7fFyTHTu&#xA;2anK42ZlWm9s1uV1WZlOm9s12V1WZkC/3IzD6urypXqX902ZWHm63Ucnn2vftZ0mjeS1zEP93N88&#xA;6nRvOZEwtu2dZonEmv8A2sysrvuz0bF9gZgy5vV4vpfI+c85L0D8kQD5zckVpaSkf8EgzW9qf3Xx&#xA;cTWfR8Xvec66tJfNfnW08n2EWrT24vJRMi29mTxWVweXFjvRaLvtmXosByZB5bt+nxmUmLP/AM5f&#xA;efr+4WLWNP0+XS2kDS29rHLFKFB/YkeSQbf5Q3zf6zTeNj4bp2mXHxxp7jpmo2mp6dbajZv6lrdx&#xA;JPA/SqSKGXbtsc4ucDGRieYdQRRoonIoZX5H01ec2qz0WKAFImOwrT426/srt9Ptm77IwAXmlyj+&#xA;Cfk52jxWb+SO86Qw32hW+pW5DpGVkSTpWKYAVA9zxztey8w466SDPUgSgJBgeb91zsVYr+Yn5hWn&#xA;kfRU1J4/rF7LJ6djbA8eUgHLkzb0Ve/3Zi6rOMcbO9t2HGZl5hff85bedNbgm0/XtL099MuHRj9U&#xA;SaOaLgwNUZ5ZFbYbhhv4jNFpc/hZBJ2ObHxxIZjbXENzbRXMDc4Z0WSJx0KuOSn6Qc62MgRY5F0x&#xA;FGlTJIfLd7x+u3HGpX1H4k9acjnFT5l30eT1n/nE/wD8nbo//GC8/wCoaTIpfemKpZ5m/wCODe/8&#xA;Yz+sZKHNytF/fR97yi4/ujmQXrIc2L6p+1mHldrgYre/3o+eajUO3xckx07tmpyuNmZVpvbNbldV&#xA;mZTpvbNdldVmZAv9yMw+rq8qV6l/dNmVh5ut1HJ59r37WdJo3ktcxD/dzfPOp0bzmRMLbtnWaJxJ&#xA;r/2sysrvuz0bF9gZgy5vV4vpfKOqWTWOp3di1eVrNJC1etY3K9vlnPOSyz8nboQ+erRCafWIpout&#xA;P91l/wDjTMDtKN4T5U42rFwL6FzmnUsH/NvyvqOu+X4m05DNdWMvq/Vx9qRGXiwXxYbGn8c2HZ2o&#xA;jjn6uRcnS5BGW/V41o3kTzlrWoDT9N0a8nuurqIXAjWleUjEBUWndjTOilMCPF05u1JFW+vvKWhn&#xA;QvLOmaOz+o9jbxwySCtGcD4yK9uVaZw+oy+JkMu8unnLikSndrbS3VxHbwjlLKwVR7nx9shjxmch&#xA;EcyxjEk0GWea76PRtP0nQbUkSX0oUncH0YSHmao7s7KCO4Y50HapGDSGEe6v1/N67sfRg8U/4ccf&#xA;tPL9J96K8oXC6t5bubCdizWs1xYStQCig8ouP+rFIg+jNl2VnPg45jmAPsdHiPEJRP8ADKUf1fYQ&#xA;wW5t5Le4lt5RSSJijgeKmhzuISEgCOrrpCjSnkmLzP8APTyJr3mrQrOXQ7Z7290ySSVrKIcpHidB&#xA;zKKN2ZeAPEdRXvmt7Tx3AS7nL0kqlXe+b7Tyzr93erZQ6fP9ZZuPBo2TiQaHkWA4gd65pseKUzUR&#xA;bnzmIiy+i9F079G6RZafy5m1gjhL+JRQCfpzr8OPggI9wdJOXFIlE3M6W9tLcP8AYhRpG+Sip/Vk&#xA;pSoWgCzT5ad2d2djVmJJPuc4ol3z3H/nDmwe5/N15wPhsdMuZmNP5njhH/J3FX3DiqWeZv8Ajg3v&#xA;/GM/rGShzcrRf30fe8ouP7o5kF6yHNi+qftZh5Xa4GK3v96Pnmo1Dt8XJMdO7ZqcrjZmVab2zW5X&#xA;VZmU6b2zXZXVZmQL/cjMPq6vKlepf3TZlYebrdRyefa9+1nSaN5LXMQ/3c3zzqdG85kTC27Z1mic&#xA;Sa/9rMrK77s9GxfYGYMub1eL6Xgn58aA+hfm95psmXikt895FQUHp3tLlQPYCWn0ZzzksV8tap+i&#xA;tf0/UT9m2nR5PdA3xj6VrlWfHxwMe8MMkeKJD6nVlZQykFSKgjcEHOQdG3ir2H8qvMK3ujHS5nrd&#xA;af8A3YJ+JoGPwnc1PA/DsKAcc6HszPxQ4Tzj9ztNJkuNdQlfmTRm0vUGRR/o01XtzvSld137rmg7&#xA;Q0ng5KH0nl+r4OJnxcEvJOPIemB5ZdRkFRH+6h/1iKsfoUgfTmw7F09k5D02H6W/SY/4mI6tqp1j&#xA;8z7llNbfTONlDsR8UZJlr7+ozCvgBmL7Q5rFdz6FpsHg6Ad8/V8+X2Jp5F1UWPn/AFXSJDSPU41n&#xA;gqT/AH0INQB0+KMkk/5ObP2fnxaav5r5wMnh62cD/GL+I/Z9yb+fNHZZl1SJSUkolzTsw2Vj8xt9&#xA;HvnZdm57HAfg26vHvxBiObZwmdeRNIaG3k1GZSsk44QA7fu9iW6/tHxHb3zSdpZ7IgOnP3uw0mOh&#xA;xF5d+ZvmRNa8yOtu/OxsR9XtypqrMDWSQbkfE21R1AGbTs7T+Hj3+qW7ianJxS25BiWZ7jpJ+YDz&#xA;2fkDV9S+xAVWyR2NOctyePpp4t6fN/kp9s1/aOoEMZH8UnJ02IylfQPm/OYds+rP+cIPLzBPM/mO&#xA;RfhJg062encVmmFfpixV9UYqlnmb/jg3v/GM/rGShzcrRf30fe8ouP7o5kF6yHNi+qftZh5Xa4GK&#xA;3v8Aej55qNQ7fFyTHTu2anK42ZlWm9s1uV1WZlOm9s12V1WZkC/3IzD6urypXqX902ZWHm63Ucnn&#xA;2vftZ0mjeS1zEP8AdzfPOp0bzmRMLbtnWaJxJr/2sysrvuz0bF9gZgy5vV4vpST/AJzX8mPDq+i+&#xA;cYI/3N3EdNvmA2EsRMkJb3dGcf7DOecl8xYq+h/yo8yrrPlWGCR63umgW04PUoo/dP8ASu3zBzme&#xA;0MHBkJ6S3dTqsfDLyLNMwXGR2i6zfaNqMV/ZPxmjO6ndXU/aRh3B/tG+W4c0schIM8czE2Htmm6r&#xA;oPm/SGCHlTj68J2lhkIqCKj50YbHf3GdFeLVY6P7QXaiUMsU00rT007T4bNG5iIGrkUqWJYmnzOX&#xA;abAMWMQG9NmOHDGnhnkH1ri+e8nJae4kaaVj1LO3In7znEdr5OIl9F7VqMOEcgKW+c7q50rzTZar&#xA;anjPA6uh3pVTWhpSoNKEZuvZTKPpPIvjftDxY8wyR5h7PoWuaR5p0T6xEA8MoMdzbMatG/dWp94P&#xA;051eSEsM/MO402ohqMYkOR6JfbeQbKK99WWdprZTVYCtCfAMwO4+QGZk+05GNAUe9EdIAbvZW86j&#xA;zO+kNY+XLXlPMOElwHjj9OPoRHyZfiPSvbtv0o0nh8fFkOzZm4+Goh5bZ/lF5znaksUFoP5ppVI/&#xA;5Jeqc3U+1MI5En4frpwRpJlP9E/JOUSh9bvkMan+4tKksKd5JFXjv24n55i5u1xXoHzbYaL+cXgX&#xA;/OW3nLTZdd07yFoYSPSvLqmW8ji+yb2YfZY1PJo4urHfkzV3zTZMkpm5Gy50YiIoPn7IMn6If84/&#xA;+Sm8oflXo2nTxmO/uozqGoK2zCa6o/Fh4pHwQ/6uKvRMVSzzN/xwb3/jGf1jJQ5uVov76PveUXH9&#xA;0cyC9ZDmxfVP2sw8rtcDFb3+9HzzUah2+LkmOnds1OVxszKtN7ZrcrqszKdN7ZrsrqszIF/uRmH1&#xA;dXlSvUv7psysPN1uo5PPte/azpNG8lrmIf7ub551OjecyJhbds6zROJNf+1mVld92ejYvsDMGXN6&#xA;vF9L3D80/Ilp568i6p5cn4rNcx87GZv91XUfxQvXrTkKNT9kkZzzkvzg1LTr3TdQudOvomgvbOV4&#xA;LmB9mSSNirKfkRiqceRvNk/lnXY71avaSfur2EftRE9R/lL1GY2r04ywrr0as2LjjT6Us7y2vbSK&#xA;7tZBLbzoJIpF6MrCoOcrKJiaPN0xBBoq2BCvZ6peaXOt9Zztbzw7rIhodt6EHYg+B2OW4JTExwGi&#xA;3aeM5TEYfUWf+XPz002dkttftmtJyafW7cGSE9TVk3kTsNuX0Z0p1UY/U9x/IGWceLHv5HY/q+5m&#xA;1pP5N1Qi6tmtJZZ/jMi8UmY+LfZkr88xcsdHm2lwG/gf0F1+SOpxemXEAPl+pR1byr5IkK3eqwQc&#xA;YviEk8zKgp4hnC/fl2m0Wnwb4xXxP6S6jVYsWTfLW3el9556/LXyxau1vcWqK45+jpsayeoVFACY&#xA;Rw5f67DNt4WWY4jZHeWjFqtNA8EDH3R/Yl9n+dOhXBaRrG5W1YK1vIpjd2B680LKEI9mbNLPtOMJ&#xA;mMgdmf5yINEFPI/zL8luqk35RmAJRoZqgnsaIR+OWjtHCf4vsLYNVj717fmN5MUVOpL9EUx/UmE6&#xA;/CP4vvSdTj72D/mp/wA5D+V/KPlu4n00te6zOrR6XEUKxmYj7b8+LcI61NBv02rXJ4tXDIajuyhm&#xA;jI0HwdfXt3f3s97eStPd3UjTXE7mrPJISzMx8STXMltel/8AOOn5Zt56/MS1S6h9TQtHK32rFhVG&#xA;VD+6gPj6rihH8obwxV+gWKuxVLPM3/HBvf8AjGf1jJQ5uVov76PveUXH90cyC9ZDmxfVP2sw8rtc&#xA;DFb3+9HzzUah2+LkmOnds1OVxszKtN7ZrcrqszKdN7ZrsrqszIF/uRmH1dXlSvUv7psysPN1uo5P&#xA;Pte/azpNG8lrmIf7ub551OjecyJhbds6zROJNf8AtZlZXfdno2L7AzBlzerxfS+nM55yXy7/AM5a&#xA;/kpLciT8xNAgLyxoq+YbWMVLIgCpdqo/kUcZPajdmOKvk3FWdflx+ZE3lub6hfcptGlapA3eFj1d&#xA;PFT+0v0jfrr9bohlFj6vvcXUafj3HN71Y31nfWkV3ZzLPbTDlHKhqpGc7OBiaOxdWYkGihtTuKAR&#xA;A+7/AMBmfoMW5kXouwNJxSOQ+4fp/HvSyxT1b1fAZZrJ7PqeCHBies+UI+PD6M5HWl53tA3aj5/g&#xA;9S0O3jmV2ROpvn/bsLg8w4etZPGeq7j6M9c7Nnx4uF4LFPgyAr/Ld2aSWTndPjj+RPxD785DtzS8&#xA;E+Mddj+j8eT1hPEBJPM0LBI/NnnDR/LNgbm+flM4P1a0Qj1JWHgOw8W7ZkafTSymh823FiMzQfOv&#xA;mXzJqXmLVZNRv2q7fDFEv2I4x0RR4DOmwYI4o8MXbY8YgKCF0rS9R1bUrbTNNt3ur+8kWG2t4xVn&#xA;kc0VRlzY/Qz8lvytsvy58l2+kLxl1W4pcaxdrv6lwwAKqaA+nGPhT7+pOKs9xV2KoHXLae60i6t4&#xA;F5zSJxRagVNfE0GGJ3b9LMRyAnkHn03kzzK0ZAs6n/jJF/zXlxmHoo9o4Afq+w/qSG//AC585y19&#xA;PT+Vf+LoB+t8x8gvk5+LtjTDnL7JfqY/dflJ+YLyArpVRX/lotv+qua3Np5nkHYw7f0YH1/7GX6k&#xA;bZflb57jpz0yn/Pe3P6pM1+TQZjyj9o/W05O3dIeU/8AYy/Un9l5B82xU52FP+esJ/U+YOTsrUHl&#xA;H7R+t1+TtbTnlL7D+pP7Hyrr0VOdrT/npGf1NmFk7F1R/g+2P63X5NfhPKX2H9ScDRNT9Lj6O/8A&#xA;rJ/XMb+QdZf0f7KP63AyamB6oC+8ta1LGQltUn/LjH62zIxdiaoHeH2x/W4WaYkNmHav+XfnG4r6&#xA;On8q/wDF0A/W+bvTaDNHnH7R+t53V6PLPkPuY5/yqX8wfULforYn/lotv+qub/TRMebpZ9kak/w/&#xA;bH9aMg/Kzz4tOWmU/wCe9v8A9VM6HTazFHmfvceXYuq/mfbH9a//AJVd575V/Rn/ACXt/wDqpmRk&#xA;1+E8pfYf1O20fZ2aH1R+0frRMf5aedgoB03f/jNB/wBVMwzqsff970GOBAe65p29bJHHLG0cih43&#xA;BV0YAqykUIIPUHFXxj/zkV/zjld+WLm682eU7b1fLEh9S9sIgS9izH4iq94K9KfY6HbfFXz3iqfe&#xA;VvOuveWpy+nzVt3NZrSSrRP78aih9xvmPqNLDKPVz72rLhjPm9P0n80NB1gAXT/o+8f7Ucx/d1/y&#xA;ZNh/wVMpGnOONDo9L2PnwwEYE8Nd7NPL6LJKJFIZW3BG4IzSayT3WYgQFPWPK6U4Zy+rLy2tLvOE&#xA;XOzb6cu7OlU3jO1o3B5PF+7uZEPSp/HPVOxM3J841EaKTajeQaPeC8mlSGONqlnYKCOhFT4jbMnt&#xA;bSicSD1ei7MyeJj4Ug81fnbYwK9t5di+tTEU+uzArEp/yUNGY/Og+echp+yid57eTtsWjJ3k8g1P&#xA;VNQ1S8kvdQuHubqT7crmp9gOwA7AbZuoY4wFRFBz4xERQWWVjeX95DZWUElzeXLrFb28Sl5HdjRV&#xA;VVqSScmyfbn/ADjp/wA4/ReRLRfMXmBEm823cdEi2ZbGJxvGjb1lYGkjD/VG1Syr3HFXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FWmVWUqwDKwoyncEHscVfNH5z/wDOJNrqUlxrv5fL&#xA;HZ3rVkn0BiI7eRjuTbOfhiY/yH4PAqNsVfKOtaHrOh6jLpmsWU2n38BpLbXCNG48DRgNj2I2OKoH&#xA;FUy0nzJr+juG0y/ntaGvCNyEJ90Pwn6RlWXBCf1AFyMOqy4/okQzzRv+civzM0wAfWLW7p0NxbrX&#xA;/kl6WavN2Dpp9CPcf123S7Ryy5m0w1L/AJye8/38LRSWOlx8v244bio/4Kdh+GV4fZ7BjNgz+Y/U&#xA;4Wc+IKLDL/8AM/zjdyM/1tbfn1EEaL9xIZvxzd4I+F9LrP5J092Y37yxy91C+vpjNe3ElzKf92Su&#xA;zt97E5ZKcpGybc7HijAVEADyQ+RbGX/l7+VPnfz9f/VfL2ntLAjBbnUZax2sNf8AfkpFK9+K1Y9h&#xA;ir7S/Jz/AJx+8qflzAt6aap5mkSk+qyqAI6j4ktkNfTXxP2m7mmwVep4q7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FUg83+QfJ3nGx+p+ZNKg1GIAiOSRaSx16mKZeMkf+xYY&#xA;q+fvOf8AzhPYzO9x5O11rWtSthqamRKnsLiIB1X5xsffFXkOv/8AOMH5z6OzEaH+koF6T2E0UwPy&#xA;jLJN/wAJirDL78tvzDsCwvfLGrW/Hq0ljcKtK0ryKUIr3xVA/wCE/NP/AFZr7/pGm/5pxVNtO/Kj&#xA;8zdSYLZ+VNWlBoBJ9TnVN6dXZVQdfHFWf+W/+cR/ze1Z0N/bWuh253Ml5Ojvx9o7f1jX2bjir27y&#xA;L/zh55B0Vo7rzJcTeY7xaEwsDb2gb/jGjF3of5nof5cVe6afp2n6bZxWOnW0VnZQLxhtoEWONF8F&#xA;RQFGKojFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX//2Q==</xmpGImg:image>\n               </rdf:li>\n            </rdf:Alt>\n         </xmp:Thumbnails>\n         <xmpMM:InstanceID>uuid:179f7641-5b82-f94b-aee1-41c2d263a77c</xmpMM:InstanceID>\n         <xmpMM:DocumentID>xmp.did:3f5bc854-b7f3-4530-a63b-4e8e84ed7795</xmpMM:DocumentID>\n         <xmpMM:OriginalDocumentID>uuid:5D20892493BFDB11914A8590D31508C8</xmpMM:OriginalDocumentID>\n         <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>\n         <xmpMM:DerivedFrom rdf:parseType=\"Resource\">\n            <stRef:instanceID>uuid:4b8d80fb-79e0-e648-b7e5-561a697a3c5f</stRef:instanceID>\n            <stRef:documentID>xmp.did:78407A0809206811822AB037A4F90ED9</stRef:documentID>\n            <stRef:originalDocumentID>uuid:5D20892493BFDB11914A8590D31508C8</stRef:originalDocumentID>\n            <stRef:renditionClass>proof:pdf</stRef:renditionClass>\n         </xmpMM:DerivedFrom>\n         <xmpMM:History>\n            <rdf:Seq>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <stEvt:action>saved</stEvt:action>\n                  <stEvt:instanceID>xmp.iid:0180117407206811822AB037A4F90ED9</stEvt:instanceID>\n                  <stEvt:when>2012-08-26T15:46:21+10:00</stEvt:when>\n                  <stEvt:softwareAgent>Adobe Illustrator CS6 (Macintosh)</stEvt:softwareAgent>\n                  <stEvt:changed>/</stEvt:changed>\n               </rdf:li>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <stEvt:action>saved</stEvt:action>\n                  <stEvt:instanceID>xmp.iid:3f5bc854-b7f3-4530-a63b-4e8e84ed7795</stEvt:instanceID>\n                  <stEvt:when>2015-07-20T12:06:36-05:00</stEvt:when>\n                  <stEvt:softwareAgent>Adobe Illustrator CC 2015 (Macintosh)</stEvt:softwareAgent>\n                  <stEvt:changed>/</stEvt:changed>\n               </rdf:li>\n            </rdf:Seq>\n         </xmpMM:History>\n         <xmpMM:Manifest>\n            <rdf:Seq>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <stMfs:linkForm>EmbedByReference</stMfs:linkForm>\n                  <stMfs:reference rdf:parseType=\"Resource\">\n                     <stRef:filePath>/Users/jim/Desktop/Beam.png</stRef:filePath>\n                     <stRef:documentID>0</stRef:documentID>\n                     <stRef:instanceID>0</stRef:instanceID>\n                  </stMfs:reference>\n               </rdf:li>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <stMfs:linkForm>EmbedByReference</stMfs:linkForm>\n                  <stMfs:reference rdf:parseType=\"Resource\">\n                     <stRef:filePath>/Users/jim/Desktop/Clojure Beam.png</stRef:filePath>\n                     <stRef:documentID>0</stRef:documentID>\n                     <stRef:instanceID>0</stRef:instanceID>\n                  </stMfs:reference>\n               </rdf:li>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <stMfs:linkForm>EmbedByReference</stMfs:linkForm>\n                  <stMfs:reference rdf:parseType=\"Resource\">\n                     <stRef:filePath>/Users/jim/Desktop/Clojure-Logo.png</stRef:filePath>\n                     <stRef:documentID>0</stRef:documentID>\n                     <stRef:instanceID>0</stRef:instanceID>\n                  </stMfs:reference>\n               </rdf:li>\n            </rdf:Seq>\n         </xmpMM:Manifest>\n         <xmpMM:Ingredients>\n            <rdf:Bag>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <stRef:filePath>/Users/jim/Desktop/Beam.png</stRef:filePath>\n                  <stRef:documentID>0</stRef:documentID>\n                  <stRef:instanceID>0</stRef:instanceID>\n               </rdf:li>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <stRef:filePath>/Users/jim/Desktop/Clojure Beam.png</stRef:filePath>\n                  <stRef:documentID>0</stRef:documentID>\n                  <stRef:instanceID>0</stRef:instanceID>\n               </rdf:li>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <stRef:filePath>/Users/jim/Desktop/Clojure-Logo.png</stRef:filePath>\n                  <stRef:documentID>0</stRef:documentID>\n                  <stRef:instanceID>0</stRef:instanceID>\n               </rdf:li>\n            </rdf:Bag>\n         </xmpMM:Ingredients>\n         <illustrator:Type>Document</illustrator:Type>\n         <illustrator:StartupProfile>Print</illustrator:StartupProfile>\n         <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>\n         <xmpTPg:HasVisibleTransparency>True</xmpTPg:HasVisibleTransparency>\n         <xmpTPg:NPages>1</xmpTPg:NPages>\n         <xmpTPg:MaxPageSize rdf:parseType=\"Resource\">\n            <stDim:w>296.999935</stDim:w>\n            <stDim:h>210.001661</stDim:h>\n            <stDim:unit>Millimeters</stDim:unit>\n         </xmpTPg:MaxPageSize>\n         <xmpTPg:PlateNames>\n            <rdf:Seq>\n               <rdf:li>Cyan</rdf:li>\n               <rdf:li>Magenta</rdf:li>\n               <rdf:li>Yellow</rdf:li>\n               <rdf:li>Black</rdf:li>\n            </rdf:Seq>\n         </xmpTPg:PlateNames>\n         <xmpTPg:SwatchGroups>\n            <rdf:Seq>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <xmpG:groupName>Default Swatch Group</xmpG:groupName>\n                  <xmpG:groupType>0</xmpG:groupType>\n                  <xmpG:Colorants>\n                     <rdf:Seq>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>White</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>255</xmpG:red>\n                           <xmpG:green>255</xmpG:green>\n                           <xmpG:blue>255</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>Black</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>29</xmpG:red>\n                           <xmpG:green>29</xmpG:green>\n                           <xmpG:blue>27</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>CMYK Red</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>226</xmpG:red>\n                           <xmpG:green>6</xmpG:green>\n                           <xmpG:blue>19</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>CMYK Yellow</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>255</xmpG:red>\n                           <xmpG:green>236</xmpG:green>\n                           <xmpG:blue>0</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>CMYK Green</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>0</xmpG:red>\n                           <xmpG:green>149</xmpG:green>\n                           <xmpG:blue>64</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>CMYK Cyan</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>0</xmpG:red>\n                           <xmpG:green>158</xmpG:green>\n                           <xmpG:blue>226</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>CMYK Blue</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>49</xmpG:red>\n                           <xmpG:green>39</xmpG:green>\n                           <xmpG:blue>130</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>CMYK Magenta</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>229</xmpG:red>\n                           <xmpG:green>0</xmpG:green>\n                           <xmpG:blue>126</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=15 M=100 Y=90 K=10</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>189</xmpG:red>\n                           <xmpG:green>22</xmpG:green>\n                           <xmpG:blue>34</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=90 Y=85 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>229</xmpG:red>\n                           <xmpG:green>51</xmpG:green>\n                           <xmpG:blue>42</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=80 Y=95 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>232</xmpG:red>\n                           <xmpG:green>78</xmpG:green>\n                           <xmpG:blue>27</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=50 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>242</xmpG:red>\n                           <xmpG:green>145</xmpG:green>\n                           <xmpG:blue>0</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=35 Y=85 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>248</xmpG:red>\n                           <xmpG:green>177</xmpG:green>\n                           <xmpG:blue>51</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=5 M=0 Y=90 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>252</xmpG:red>\n                           <xmpG:green>234</xmpG:green>\n                           <xmpG:blue>13</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=20 M=0 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>221</xmpG:red>\n                           <xmpG:green>219</xmpG:green>\n                           <xmpG:blue>0</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=50 M=0 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>147</xmpG:red>\n                           <xmpG:green>192</xmpG:green>\n                           <xmpG:blue>31</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=75 M=0 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>57</xmpG:red>\n                           <xmpG:green>169</xmpG:green>\n                           <xmpG:blue>53</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=85 M=10 Y=100 K=10</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>0</xmpG:red>\n                           <xmpG:green>141</xmpG:green>\n                           <xmpG:blue>54</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=90 M=30 Y=95 K=30</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>0</xmpG:red>\n                           <xmpG:green>102</xmpG:green>\n                           <xmpG:blue>51</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=75 M=0 Y=75 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>45</xmpG:red>\n                           <xmpG:green>171</xmpG:green>\n                           <xmpG:blue>102</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=80 M=10 Y=45 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>0</xmpG:red>\n                           <xmpG:green>160</xmpG:green>\n                           <xmpG:blue>153</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=70 M=15 Y=0 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>53</xmpG:red>\n                           <xmpG:green>168</xmpG:green>\n                           <xmpG:blue>224</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=85 M=50 Y=0 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>29</xmpG:red>\n                           <xmpG:green>112</xmpG:green>\n                           <xmpG:blue>183</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=100 M=95 Y=5 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>45</xmpG:red>\n                           <xmpG:green>46</xmpG:green>\n                           <xmpG:blue>130</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=100 M=100 Y=25 K=25</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>41</xmpG:red>\n                           <xmpG:green>35</xmpG:green>\n                           <xmpG:blue>92</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=75 M=100 Y=0 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>102</xmpG:red>\n                           <xmpG:green>36</xmpG:green>\n                           <xmpG:blue>130</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=50 M=100 Y=0 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>148</xmpG:red>\n                           <xmpG:green>27</xmpG:green>\n                           <xmpG:blue>128</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=35 M=100 Y=35 K=10</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>162</xmpG:red>\n                           <xmpG:green>25</xmpG:green>\n                           <xmpG:blue>91</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=10 M=100 Y=50 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>214</xmpG:red>\n                           <xmpG:green>11</xmpG:green>\n                           <xmpG:blue>81</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=95 Y=20 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>230</xmpG:red>\n                           <xmpG:green>27</xmpG:green>\n                           <xmpG:blue>114</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=25 M=25 Y=40 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>202</xmpG:red>\n                           <xmpG:green>186</xmpG:green>\n                           <xmpG:blue>159</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=40 M=45 Y=50 K=5</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>163</xmpG:red>\n                           <xmpG:green>137</xmpG:green>\n                           <xmpG:blue>122</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=50 M=50 Y=60 K=25</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>122</xmpG:red>\n                           <xmpG:green>106</xmpG:green>\n                           <xmpG:blue>88</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=55 M=60 Y=65 K=40</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>99</xmpG:red>\n                           <xmpG:green>78</xmpG:green>\n                           <xmpG:blue>66</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=25 M=40 Y=65 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>201</xmpG:red>\n                           <xmpG:green>157</xmpG:green>\n                           <xmpG:blue>102</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=30 M=50 Y=75 K=10</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>177</xmpG:red>\n                           <xmpG:green>127</xmpG:green>\n                           <xmpG:blue>73</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=35 M=60 Y=80 K=25</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>146</xmpG:red>\n                           <xmpG:green>95</xmpG:green>\n                           <xmpG:blue>54</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=40 M=65 Y=90 K=35</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>126</xmpG:red>\n                           <xmpG:green>78</xmpG:green>\n                           <xmpG:blue>36</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=40 M=70 Y=100 K=50</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>104</xmpG:red>\n                           <xmpG:green>59</xmpG:green>\n                           <xmpG:blue>17</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=50 M=70 Y=80 K=70</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>66</xmpG:red>\n                           <xmpG:green>41</xmpG:green>\n                           <xmpG:blue>24</xmpG:blue>\n                        </rdf:li>\n                     </rdf:Seq>\n                  </xmpG:Colorants>\n               </rdf:li>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <xmpG:groupName>Grays</xmpG:groupName>\n                  <xmpG:groupType>1</xmpG:groupType>\n                  <xmpG:Colorants>\n                     <rdf:Seq>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=100</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>29</xmpG:red>\n                           <xmpG:green>29</xmpG:green>\n                           <xmpG:blue>27</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=90</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>60</xmpG:red>\n                           <xmpG:green>60</xmpG:green>\n                           <xmpG:blue>59</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=80</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>87</xmpG:red>\n                           <xmpG:green>87</xmpG:green>\n                           <xmpG:blue>86</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=70</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>111</xmpG:red>\n                           <xmpG:green>111</xmpG:green>\n                           <xmpG:blue>110</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=60</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>134</xmpG:red>\n                           <xmpG:green>134</xmpG:green>\n                           <xmpG:blue>134</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=50</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>156</xmpG:red>\n                           <xmpG:green>155</xmpG:green>\n                           <xmpG:blue>155</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=40</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>177</xmpG:red>\n                           <xmpG:green>177</xmpG:green>\n                           <xmpG:blue>177</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=30</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>198</xmpG:red>\n                           <xmpG:green>198</xmpG:green>\n                           <xmpG:blue>197</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=20</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>217</xmpG:red>\n                           <xmpG:green>217</xmpG:green>\n                           <xmpG:blue>217</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=10</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>236</xmpG:red>\n                           <xmpG:green>236</xmpG:green>\n                           <xmpG:blue>236</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=5</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>245</xmpG:red>\n                           <xmpG:green>245</xmpG:green>\n                           <xmpG:blue>245</xmpG:blue>\n                        </rdf:li>\n                     </rdf:Seq>\n                  </xmpG:Colorants>\n               </rdf:li>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <xmpG:groupName>Brights</xmpG:groupName>\n                  <xmpG:groupType>1</xmpG:groupType>\n                  <xmpG:Colorants>\n                     <rdf:Seq>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=100 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>226</xmpG:red>\n                           <xmpG:green>6</xmpG:green>\n                           <xmpG:blue>19</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=75 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>233</xmpG:red>\n                           <xmpG:green>90</xmpG:green>\n                           <xmpG:blue>12</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=10 Y=95 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>255</xmpG:red>\n                           <xmpG:green>221</xmpG:green>\n                           <xmpG:blue>0</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=85 M=10 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>0</xmpG:red>\n                           <xmpG:green>151</xmpG:green>\n                           <xmpG:blue>58</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=100 M=90 Y=0 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>40</xmpG:red>\n                           <xmpG:green>52</xmpG:green>\n                           <xmpG:blue>138</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=60 M=90 Y=0 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>129</xmpG:red>\n                           <xmpG:green>53</xmpG:green>\n                           <xmpG:blue>138</xmpG:blue>\n                        </rdf:li>\n                     </rdf:Seq>\n                  </xmpG:Colorants>\n               </rdf:li>\n            </rdf:Seq>\n         </xmpTPg:SwatchGroups>\n         <pdf:Producer>Adobe PDF library 10.01</pdf:Producer>\n      </rdf:Description>\n   </rdf:RDF>\n</x:xmpmeta>\n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                           \n<?xpacket end=\"w\"?>\rendstream\rendobj\r3 0 obj\r<</Count 1/Kids[7 0 R]/Type/Pages>>\rendobj\r7 0 obj\r<</ArtBox[78.7725 155.908 623.663 444.145]/BleedBox[0.0 0.0 841.89 595.28]/Contents 133 0 R/CropBox[0.0 0.0 841.89 595.28]/Group 134 0 R/LastModified(D:20150720142046-05'00')/MediaBox[0.0 0.0 841.89 595.28]/Parent 3 0 R/PieceInfo<</Illustrator 135 0 R>>/Resources<</ColorSpace<</CS0 136 0 R>>/ExtGState<</GS0 137 0 R/GS1 138 0 R>>/ProcSet[/PDF/ImageC]/Properties<</MC0 131 0 R>>/Shading<</Sh0 139 0 R>>/XObject<</Im0 140 0 R/Im1 141 0 R>>>>/Thumb 142 0 R/TrimBox[0.0 0.0 841.89 595.28]/Type/Page>>\rendobj\r133 0 obj\r<</Filter/FlateDecode/Length 957>>stream\r\nH|VɎ\u00141\fW\u0007*\u001d;+\u0003B\u001c\u0010\u001aq{2a_9K\"C~:}zǇHo>)ʉ\u0010.5ҟo\u00173#xnUF_J\u000bP\u0003լĵ\u001bhOSGm\u0010YmւTnĒ%\u001eH 89X}\u0013\u0001n/v$z9:<?\u0013E&\u0018ZMRᠵVw[O\u0012\u001d\u0019PZ&my\tqp4THFq7$Ki͵0<N\u0011y_+\"j\u000e~O4T\u001ce\u0002oS\u001cX\u001d4+b\u0017\u0010'f\u0017kru_y\u0001#mN\u0019йM\u00018b\u000b{>Pέ'%ugJ@r@/3\bZ\u0010\u000fME/))\u00075WySoTx_\rFME\u0001]\u001f0~U4l\u0005}\u0007\u000b9&\u0017\u000fG\u0000-HH\u001c\ba>`b*hah\u0015<ZP\u000b\rc\u0003\u001a+\u0016LuI\u001e*\u0007ɲ\u00168Y1.K?\u0016&ܩvNF\u0001x\n@I\u0011WMa)\u0016E.\u001a8V\u0005\u001b{{3/\f1b\u0013藂)e`ANPĒ=|:\u0003$Hٕ6A8S\u0016\u001d\u0007\"#Pݵ\u0011\u0012\u001b\u0000|5\u0014Գ\u0004\\{\u0010\u0007S. F9:Hn>z\bs\u0013N5CC\u0016wdM.2kN\u0014Uwiݫ)!b\u0012\u0016~\u0018)>E\u0012z6f\u0003^T\u001f7NH4m\b;\r7QI#X\u000e(\u001bp\u0015W\u0002e:DÖ\u00162&\f\u001e}T\u001f$ [q[|Qdk02\b\nZEQEDkz\"ϱ'p%F=1<\u0017!Ī.3<dϤjj\u001e\u0016in\r;`$\u0011G\rn\u000b\u0019\nhCD-j׊S\u0013s؜\u001b\tp\u0015\u0004V(h\u0002j \u001b_UrO\bQ;\u0005xaB\u0012:\u001cs\u001fJد\u00175{8!Ǹ_=oH/?Wz}W\u0001\u0000\u0012j\rendstream\rendobj\r134 0 obj\r<</CS 143 0 R/I false/K false/S/Transparency>>\rendobj\r142 0 obj\r<</BitsPerComponent 8/ColorSpace 144 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 74/Length 868/Width 105>>stream\r\n8;Z]!9krEJ'Z]AHr]#]?fMWl8:D(FY#cU>X/k[,i#/&&Mfsk0%$7bELP`;2e69sDW\noNeBdV:!?r'ROA(@@f31,;[+4o\\Nq2!3TS;EokH/X+-f!=?X>[(KjmAeY,1ha!@3/\n`np??:[ZM8%dA9EH=EDbkDYP3eZQ(@4NEAB2t<g,DKR\\1LW,6Z\\C'.e\\fEH%TDV\\s\nKfL;JUHLE5PgT5`N-[0`PVd\\;MK8Steb-254^(U/Irtt:=Smj.O<0SMd6f@0PlJl>\nHoi7=C\"+[Q\"sHk4;c7C1^@E=NA7W1eY:f),S\".'1bDc50'1T&nrY\\1G`IJ)\"kM79j\nOX%En%fi@#dreP2q]'a*+[;o#)4(QKdE*B/:PP'AA<S82?fMF8,q2/rq@gdUP!G5t\nF!R'gJqHl,&5kh^.fS-IW\\q*(OT`W_i]iV9^m\\04Q6;HjY0j(+P![BKrKa5k]6>E(\ne$-qoUL]o?Yn6NC.;Y/A\\k/9OHi`_!Bom1ljIM2_#%0W/U:WhSjCs]mNjKBbap=s0\n&t9,t-.Bpb7u`Xu\\S/m?etPh&l.7euaH9RQ_Qa(q-R_9(8W6qo@UtTGe4^kfnYt8k\nk&X&hNGNYMM&aVI*Tj@pD2u1s2E;CG\"p!MRU5ENK!-F7rfBi7,Af>,R!ltk.cUfZV\nH;=SZ@R!c>+IrMT>s=PjR*Vd\\Zk'PdM(WdGH-@)RmPX$-B>5OF/n*O^$!JRcEui\\(\npK:Yt#+0YP0?,>PJ9)aZ:1(<.Wq3b[R0c*11X*C)OlH8AftKN0l$,3eq\\*_*>=4qH\noDp]t[d:H\\`Pe7:E/(BIKIUjrqPZUh%JorFs15!VE;ED__7W-@&*(ft.p&lY\\b^g@\ncN*$l'-.~>\rendstream\rendobj\r144 0 obj\r[/Indexed/DeviceRGB 255 145 0 R]\rendobj\r145 0 obj\r<</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream\r\n8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@\"pJ+EP(%0\nb]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\\Ulg9dhD*\"iC[;*=3`oP1[!S^)?1)IZ4dup`\nE1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\\.?d>Mn\n6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1\nVNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<\nPO7r\\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(\nl[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\\~>\rendstream\rendobj\r140 0 obj\r<</BitsPerComponent 8/ColorSpace 136 0 R/DecodeParms<</BitsPerComponent 4/Colors 3/Columns 500>>/Filter/FlateDecode/Height 500/Intent/RelativeColorimetric/Length 23780/Name/X/SMask 146 0 R/Subtype/Image/Type/XObject/Width 500>>stream\r\nHST\u001dgv\u00055ZŴMLk\u0004X\u0010\u0004\u0012D3\tZQ3^(H\u0005\u0012\u000be\u0017n\u000fS#sO\u000e~\b\u0000*\u0000\u0019\u0010B@/\b!\u0004\fz\t!,Z]A\b!\u001b\u0004=V\u0002}+B\bY\u0016@\u0007%\t!N\u0007\u0007}aBS@sA_\u0010b7ЫF\u0016N\u0004! \u0007\u000e:#\u0010k*q!T\u001dY\"\u0004&B\b\u0018\b\u0011sA\u0010\"\u0015\u0010٠\u0013G\b1\u0011\u0010<\f\u0012B*\tzQHu#!@O\bv\t%\u000ff\u0010+N+!d\u0015#A\r:ŠW\u0007t\t!\u000b\u0016t\tq\"\u0013N:!N\u0001uDЩ'ΠM\u000e\u0001\rt\u0005!\u0005Md犓?\u001bR{S$N\u000e]|~&٩v\u001cr[7/o[=wt\r\u000e\u0018ȑ#\u0012\u000e\u0006Fg\u0019WCBj8u}[W@\u001d@\u0018\u0010\"W\u0010ImtL{>s;ti\u000f5ʢl[a\u0004zcw_\u0004թ\u0019n\u0006!V\u0005]\u0019\u0018hx0\u001f\\?\u0017lKX?\u0017<ßҾHN\u000e{tK\b\u0012辚HA\u0013d̉c.&w\u0007Gg)M+yэ!Aw\u00144=\u0010\u000e\u001a·67)\u0005S>8\"8/p!\u001aAb\u00185Gf[6;zWfϡk'?ϦEaG7j\u0001\n`LS458\u0001W\u0003~6-禆\u0002)aѭ\"\u0004\f\u001bG\b15S!m{Sɴf<[`@7o\u00144LQ[/OԸ\u0015\u0006Zrsoї \u0011\"\u000ft6TF3^<ϝcQ*>m<s\u000edؐd7\u0003_6?k\u001a##cќ6\u001e]>BL\u0001]b,F ^mnR;FWƭ\u001c\u0006V\u001ayt\u000b\t$>d'Z[LɛQ,aG7\ndk\u000f&5s-&to<ЙZ\u001dt/\t8BI/?\u001a\u001fHֵ\u000e\u000bjǣ;JȺAf%Bհ\u000b?T͗BX\u000eU@5.ʲ\u001444\u0007\u001f\u001c*-o\u0007s\u0005\u001deA@cYbۗaP&|yt\u001e\u0005`B\u0000]%\u0010_1\u0006\u0014ZUֵ{\u0007Fg@\u0007t)=&\r6,AI\u0017m-\u001eЪuKxR+ú\u0014N\u0013RuÞgo]\r頖Јʩ\u0019Nb&\u0006\u001dȨ#\u00163HJC-&N\u0004\u0014\u0006@mh\u000e@w8\bt0\t\u0007̏:&yt߀n<?茿!5S?\u0017\u0000\u001aL\u0015I\u0003ĶZt_\u0017:Ľ]DZC5\r 6\u0004\u001d\u00058u\u0004^v@\u0006?\u0015\rX\u0000\u0004V\\.򽤫\u0001qd[.ry\u001d݆\u0005Г@,\u000f:eQ.{u+^Sjh<0?\u0014\u0002]\f;y\u0007-+\u0013u^x)]g/~pF6;\n+L\n~OLkئwX\tlVK8'\u0001-kp^\u0013֠7X\u0000lDT[=R.k\u001ao\u0006S}G/\u0007jT?#\u0000/)\u001bw|\u0006,\u0011z?H\n~<B\u0017Ҋx72qbPQ\f'\u001f\u001cHi\u0005rNT\u0011\u000471x\r)5+!$ *s\u001d\u000f*xDn\u0001/}&e?YTB`@&D$I\n5\u0003\u001e1\u0004\u0000$ida\u0001\u001fkJxUHKC\"?`sIx(\u0005zzD\u0001\u000fx\u0010IȏVv\u0018YK5\u001dD\u000e1\u001d\u001fljwFJ\b\u000fx\u0010\u0013.\u0017&=\nx.K$z)HNQ2l\u001bDiZV~d%\u0017\u0013CHݡ\u000b]\u001cJ-ɛQ!5\"\u0015CfltQv_R\u000bɉ&uћD*db\u0001\u000f)Zm̶\u00132oܦF|G(}O2;[[\u0013\tؗR\u001bz%$W\u001bi(_\u00046~xħui\u0015Fo\u0015Y\u0007Rwy]fֺ\u0015$'\"kBZ\u001e9#\u0016PjW\u001f=H3z*HK3Sj{/%\u001a^dYe\u0004<:BҪ0\u0004rN/h0\u0001O;\u0013%]8z[9:9ԁֵ{՜.=#s\\A|p\u0007O8us\u0012Kir^5\"i3jq~\u000f<۔:\\W\u0011*ms4rN\u001c׺\u0015x)\u001ceVN\u000bP\u001c\u0013w5L)=KY\u00009\u0011\tg\u001d.t)Kz_)\t#PEA\u0007Fg饔\u0012\u0000v\u000eB5R_܊K\u0018\u00049\u0002\tw4<5y#*a\u0016gs$\\ixV)˰\u0010\u0003zl[\u0018v)mWC\u0012&\u00026D8Zڎ@o0^wdRJѮޘ[B[a\u0006~gRZ\u0011O\u0018E\tfiħH)7Sf\u0006z\u0017-\u0007Er.t\u000e)\u0015i\u0003D\n\u001a!謩\u0003Ro\u0014S23Wu+QJsث:#荴$^$-\u001ex(\u0019NM\u001d\u0013RZ\fSoQŮ6/<uR\tֺYhꤠ2z\u0005!ǝfǩK\u001bKwOGf}X4g\u0018\u0013ӚajJ\u0019+T\u0007#\u001f^>xd䉞Xgw\u001c$J/,\u000eO/kSF*KTj,\u001b\\m\bJ\n8\u0004\u0001\u0007\u0004\u0007\ba\u0016\u0004Q\t\u0019\u001cۇeU\"Bs\u0003\u0002{;\u001cE\u0013O\u0012P`[S\u001aqEFV|Jw|XcpQ\u001eQ\u001e\r\u0013K\u0017#ڧ:\u0003\u001dK\u000e\u000bKNttۘ֔\u0000pŧlw\u001cV>vyH,\u0001;\u000flK'FG\u000b\u0005p9YX6\t@w\";3\u001a\u000fb=\u000fm\u0018s\u001d'7%-baɜ;\u001c[\u000f۠\u000b\\-ΨloB^ܝq\u001f{6P~|%<\u000b\u001ftaK4\u00136\u0017RRfl \u0014I=U!F\u001e\nj\u00051js\u0004na{4+u'T:e6\n\u0013\u0004y2\u0001;bsZn\u0015o\u0005MAV1\u001d\u000bjCs:Nm\u000em\u0011=C\u0000|\u0019?sG\u0005&O\u0006\r-̅\rSzmX$bU0/lf\u0010pEGnܺѲgo\u0006f\u0018`3\u0013?2Jݶѱ*\u001dUv\u0007=\u0016֨pyz\ns{{U>\u001f,4hxL\u0001\u000f^:2U;\u0006\u0000R\u0016k\u0007J}N4hVL:v鵎,~jswVx/є]{I\u0011w\u0010\\[\u000bjI\u001f\u00147\u0017Z\u00135zv슮oovx]Ň\u0002r cSt\u000bV`\u0015\u0019\u0006ϩ>\u0006Ӕ:$)s\u001bZ\u001cZ;+;K~\u001an;^\u000bx\u0002\tu\u0003\u0017g4~ii\u001f|Ƈ^^\u0006lb\u0002TR'\rM\u000010ڣ-6\u0007ѯΫ\u001fZ\u0005%>\u001cprt~3ъo#K\n\u0002`\u0015\rzRJ۾&ʬKh#lϛ:1\t\u00139wm\u000b6أC\u0006tlj\u001d\u001bmY\u001c?е\u0015\rŀ\u001e?>1S\f@5v\u00036we}\u001a|\u0006O:-t\u0003TF_0~,OC@%g\u0019_\\w*\u0005ussnHO\u00153<:^G7\u001b\u000b\u001aP]VjHrrҗdN!\u0012t\u00156 &R0dO\tZ\u0005\u0003Wjn󒲤'C\u0011\u001eM\u001f@\u0005|l+\u001c\u001cX\u0018\u001f0:\r\u001a5MJ/hR%\u0018Nvy\u000bj\r\u0010bI%?V\bH-t\u0000T:+E>)fdM\u0007Ms\u00016j%|ٺ\bu9\u0018:\u0000\u0015ۻ\u0000Ս\u0005\u0017e$\u0010V\u0003jtZ,n'}a\u0001*\u001ap\u0011+O~\u0016xC\u0017N\nMl\u0002\u0002Q.\u0006#I$r%f4B\u0019\u000e\u0006\u0001V\fF\u0010Oq\nftdb)\bGl\u0013\u000fP\u0018\" 5SqQ\u001e&\u0016\u0019\u00121\u00189K$Ʒ\u000e\u000f\u001d)\u0003\u000fb\u0002T\"\u0006#%Zl2l\u0007fq\u0006\u0010h@\u0014`Gm\u000e5+VE\u0004kV\u0016\u00070\u0018\u000fP\f\u0006Vhe}9So\u0004\u001a\nPY\u0018\f\u0006\b!ÖaeV\u0017\u0017\u0004DA\u0018\f\u0016,\u001aj>̦|UN&\tD\r{ `0& \u000f{]y*t+fM.5[!:m]\u0002Q\n\u0006c\u0003I^\b\u0005WPۄi0LsD1IZW4Kr{='MyzޑQ\u0015}\"\\/$ cZZ1:u\u0006t+fM\bD=\u001b q`t\nSzڸul]W\u0014r\u001fK?ytϐ\ts #$wWeV̎\\K\u0000N|lO\u0018KI̵vaxi7z@4zOmOE\ra&et\\~\u0016ݍY{=N\u0006azg@T#BQ&\r}2:{H[2\u0013l^\u0007D$\u0018NȂFހB\u0011^`z\u0007vF\u0013\u000b*%HE:Ȃy(\r)霽mh\rS\u0005b팬d-,\u00181RX?DF+]Y#_֡\u001bR1:?\u0012D-%8@^']Y%wW\r)|wIG}6fFb\t5\u0012AV'p1r\u001f\b\u000fz]2lIJ7ó~ћmm\u0010}YF,\u0019qr\u0016˚[Xp:X_\u000e\u001a[\u0007J݃Ac˫\u0017;^Sg\u00112Ea짆e\"7=R\u0010$1\u0004o\u0017/\u001d(U{RDw\u0004[!jI(\u0016f~mP7ܛ+\u001a?~f@vC|Sʿ\r\u001f{SغX3jn7 *Ecd\u0019_L}\u001f\b8v\u0005hWjU);\u001d\u0003ߟEJ\b\u0017g=[V=ɞ;͉?\u001cy4_9a5\u0013/+7͹I牟C'W\u0001]RL\u0013vǶ戾L&\f/8Z^\u001c懎?GۨOdcf7\u0013\u0001|ߦ?W\u0014D1I\u001c>c{ftUJ.D\u00057A5f D &r\u000f\u001e]柦tk.]]Z\u0013j:e\u0013dՏV$Onm)Xq{򍈾!'ޭ4\u0014\u0018[رX2]=$;\u00167mo\u000bp~2Fr z\u0017]\u0011.\u0013\t?~\u001f:@1yA5\u0013)|抂\"9zdV\u000e\u0007*lK\u001e4<Yg_Ѝb.\u0012`M\u001c\t\u000f_$$q\\+dEΔJWEo\u0001ν\u0013֞W]r:\u001f:I;NU;mjtL@\u0005Ɖ6ȤF\u0012\u0007dE%RD\u0002\u001ae)k,\u0017v\u0017\u0005]=oݔfX.y9gs\u001e\u001a\u0003+_i+\u000f<\"\u00136(= Uc\u0000\u0003~)\u0013{%Ǜ3EVj\fװc\u0001U~!.#\u0018\u0007}iDצ*8\\`\u0001\u001f\u0003~)%,V.ֿnup\u0010?Vm\u0017TPKzD\u0010\u0015\u0013}0\u0010xi/Bh_+z}ܝ\u001aB*\u0015\u001aT݊NGO}5^N\u001d:\n\u001f[\u001c?^S*uLd~#N98I\bMmķ\u0007ۜ\u0005xuO}\tj&W\r]\u001b\u0019\u001e|+#JrE'K9V;Y*7\u0001\u000f9'\u0014xiP\u00190xe;7Hpbb7zYP8\u0015\u0010\\|qB-K928%\u0013^o]nty\u0016=-7>s %\u0014hL$%M$W;G\u000f$\"*/\u0019H^\u001f\t\u0000gsS.O9\u0006=W&.ƪ'jsH\"@i|W֖\u00158\u000b\u000bG\u0016-Ķ $\"_3Oqy_aiD.t'p7ΐMLb뮗Şм\\\u0005~.+g\ndȬ b\t\u001b3䙳iDw'άلd\u0010rZ<:֥\u0011K?Ǿ\u0002{}\n!B8\u0017r/\u00153\u0004y\u0005'G\u00172\u0014YG\u001d\u001dKKHzǩՈ=Iu@3S4.LStrNy\u0007+\u0013Ba\u0011iZw붠\u000b\u0019\u0010ui!]e?z(\u0004㭤]/OB\u001c^\u0018\nǷ(fD\u0016&=&KU\ff8$/\u00193ݜٻ\u000e'nhX0=J\"q\t_SH\u000eF(4\f\u0000Snw\u0004Zw\u0018\u0016z\u0010bڛ5u=\tipƦs%S29UAX΂\u001c_U-'9g\"De;iA2H\r]Ű\u001cjx`1\u0018lbywbO\nu3=m2(<7Zֳ}c+Vt\u0013C\u00107-抬*%fB+&M bOBd陓ͦW5Цc؇gM\"\u0010\u0007[#vQ\u0012=̂\nV7.0g\u0000d뙞F\"\u000e|g1BX\n{܏.R>\u0004ت\u0004h\u0011t\tt>AJnS;`wd\u001c}m4\u0010Qb8\u0005trȿ=\t\u0003\u0012fAn[\u0019v-\u0014\f{ﱻB2UT\u0017a{$&\u001d.7}i<.l\u0013\u00195=r\u0015\u0010{r{7\b91fre-A>Nyc\u001c9UNB70#4U7P*w\n-~vס·h1%tƧצaKNI؏7g~FՙT=Iu;>F/^C$+\u0012,Ny#\u0018\u0000KN=Ky+̚M\\\u0003\t\u000f\u0016YUXIn\u001eJ\u0001F\"D.W\u001aybf4\u0013ٱ\u001cƈS|-9\u001e{>o#Q:rQu^cف\"$SFcO8j(5=:gM/q{\\ڏ_v\u001cmm0cQ]PX1>ؓZ\u0016{R\u00145\u0012PD4QB?\u001b\u0001l85.HK}9eʀIu$Va;.v\n}8x\u00126\u0016wͦWurxCLb]=mD7*?\rWۉLJ˔\u0018W8n\u0015*\"\u0011XS\u0010e(tO\u00141\u0019\\B7*?9e\u0019zbt2%<zݥ>.u\u001673KR\fB:g%q\u0005]0n|#Z\u0003̚MeJ6Vt\u0004b\u0006|I\u0001\u0013 Q!\r^oEw/SZw\u0000^;>\u001d\bi\r^\ndb,\n;T9a)(B>v_I˚1G'xu\u0002U0\u00025/\u001bR\\k&0\\Ftr¨)\u0004ح.\u0011|o\u0016xYs7E{\u0002t{\u001e=_b\u001bR!\u0012^c\u001aR/Jg`Ui?+D\u0017/kj7F\u000etu?\u0003;i!o>\u0003܃\u00111\u0014W9A UG\u001d\u001d5˚|2\\lݍUb\b7@wΒGzT5\u0005Z2\f>\u0019iЃ.UNx\u000f\u0002\u0016\u0016{#F\u0017/kr|17luD\u000f\u001b{L9!E`K7Ql%\u0004\\D\u001c){\u0007\u0005,V\u0015b'2ԗ.^\u00051\\\u0007oo\u001dJr\u0019x\u000f\\ףi\u001c!|G*'\"d\u0012ݺ\npWD\u0000:ob\u001e׊Ʋ# `\u001bwc\n`u\u0002υ\u0014Yѽ\u0003Y\u0017+n\u000b붠W\u0001\u001e\u001a#採z}4;C!Ϻdt1\u0000<&q\u0001x4\u0013\u0001t\u0002`<]\"}UC\ro\u0013~j\u0015\u000121#l!ȥmnL\u0001t\u0004|4/FW+:\u001f3\u0016˧iUj\u0006,󆠏\u000eNh\u0006L\u001d\u0002-\u0000\u001c_\bQħ]!{NVt*Gm8^Ot9oP7l-L\u0014H;cǯZՊN\u0013/`\u001cbo6u\u0015fCZ\u0006-Ƞ\u0006\u0007bL\rFa'#ՊΧ k:t*Cvݖ`\u000bXD\nAt-C\u000f\u0002Cѭ\u001a\u00147h\u001cr4H/튎\b\"J\u0011SSg\u0002?Ngӝθ^:U\u0015XٖeRU.\u0016EZ(\"@\u0005\u0004#\u00044\b\u001a\u0012Hȅ\u001b\tIN٠;t<y\u0019NW>y\u0013;-]]1UN`\u001b\r7A\u0006\u0015p|èf𯪆%:,\u0004pRU~w\u0012\\a9BSV3ъt[\u0013eO\b_EmT,/EW\u0013KH[rָ\u0000T={c}M\u0015S\u0000^R\u0005bx7\u001fHr\u001a+UL\rFӽu+私{Ctr5\u0000N\u0017N-ޡSFBMf~W\u0002B 4\u001fXnD\u0006J`\u000fѽ\u0015ogd\t^\u0012\u001d<Uiߞ&$j~yFl1teE>ۻNt֛ioF\u001f/>}aNrGrִ\u0000ܓn36\u0016I\u0006uJ*NϜ=|\u00125S\u0001tOK\u0019:>8\u0003ܓk{]+2\u0011zb\u001f/t\u0002G3l<ݑ}QnrKIK\u001bފ왧\u000bWFW@\u000bd\u0005\u000f>a;{ȧ۟M\u0000=3G@VXZΤPEr\u0016:b\fݲc>Z\u0017\u0006^rA\u0007XCo\u00008&vȪG/\u0000{\u0012+;΃6ZLȧ{e:\nځcRl\u0015dV\"\u0005ͨ$9U1>\\Mc\u001b#+m#q(\u0015iǙi\u0002~SRl7-tӱ\u00151MD:\n(p[$j\t\\n,1(Zb]toE8U\u0001\\u6\u0007\u000eԀ|\u000fwmrZB]=\u001c\u0003Kp\b6\u001dx؂tl\u00057\u001fF]b3˩w\u0019/=X.(4XVe\u001eؔm:THVd\u001d[/\u0016әtn\\\nf{Ȩɞ\u000b5N\u000e\\\u0002\u0014i{ P\u000b\"m.F۶Йe5\u0018A-h\nFQ<\u000fэ%&˰/J\u001dDVp!zca\u001d\u001dXbIr\u001a+1X\u001301ii+\u0019ԒlOJ\u0007[ޤc+O[\u0012jzw!\u001dXn\u0013\u000eȒٗQE;C-\u0013TӍe56\u001bC(~g\u000b\u001d[]v\u001c^,TjLו[s?jQ\u001aG]RӍeU(\u0000\u000e\u0005tl\u00057nGgZӪ<1Ȟs>\u001c=ܧ\u001cqN@ͨ\b\u001byȲ2j\u0003tWՐ{\u0001Q=RW\fH\u0019:v`F|q\u0004~oG\u0017L9騪r;q)\u0004YPce\r:7YV)\t\u000b(߶gd-:\u001eż0g(xzʮ\u0001YQ\u0018j\u0011\u0018JzSn,+o 1߶\u0017\rti݁\u001au.za@V\u0000JY\u000bC-U. $XV\u0006s\u00043bm8]Zy)\\ZG\u0017UUͮ\f@m0=X\u0010f־\u000bgRm\u00113bmOJOIVp'\u0006D{閪cmM\n\u001dCe@nf\u0014qљt\t\u001by\u0007~l\fҊf\b5`tKVus4}`tvp\u00069{yy\u001a\r\u0001:>dCm2aw6۷-Ua\u001aȾUzZYN 7LRvj\n'ؾҊ\u0013\f[\u0015Ug?8vgr_Xo{,ܯe\u0007gRJJ?y}NgV|\u001f3\u0001C+ڜ\u0017]T\u0018j1K+\u001dtf)\u0005\"iԆy_ҥ\u0015߹\u000fQ\u0003z\tUmm_pZRZ\u001ej>ךtf)MQ\u001bvY\u001ch\u0015]ZՌ\u00166\u0013ڮ~̬>r*iSWn0Hg޴Y0?V:\u001c!\u0003FKt?U9ܜs\nC5Z΄},*\"fp:YJ\u0014dh/\u001dOW:\u0006,_ډ%:qÎY0?\u0018\u000fҙ\u0015ަפ\f\u0017it<R\u0012WP{\u001e\fʹ_˳\u001b+]Z\u0015\u0014[Q\u0003*cK+\u0006:LSe\u0001sZo{*`I\u0012j@߶\u0003?p7ҊR\u0001~T\u0015sȹP]T\u001ejD\nWjљ\u001f˲LgR\u0005Ȁz\u001a3vZRZ\u001ej)\u0012@i\u001b\\3Ki5R%9EgR\u001a2#nzs\"\u001b|\u000fd\f[btf)W2\u0005Ѷǒ!:\u0017z \u0003>\u000fݧ^*\u001d\u00029\u000enU\u001ejQ̳Oҙ\r \u0003*hۗn:\u0011+dn\u0019uBb2\rۑ=؞Ltf)Y\tȀ\n\u0014Yy))B\u0006w\u0017\\/s\ryE\u0007DTم={>JV|QԀX}tiwX\u0016jJv%g|\u0004nOf*i\fZ\u000ek\u001b\fbCjK+[!$\u001dRs3T$j\u0018^.׹Ҋv\u000f3\u001fv&]Z\u0015\u001bA\u000b<t3K(d&6lGcu.\u001b<ж6_K+C<q\"'Q3\u001dKӥ\u0015\u001f1m4K+\"zc:\"\u001e㓨\u0006,K\u0019tiw,f>eҊq\u0002HΦw\u0001Yc*t\u00125S\u0012r)\u0006s.>-UE\u0002랫\u001fIS\u001fٓL+|\u0015Q\tc-FV|{/@Sжy.z:!u˩݅~j\r|\u0015Q\u0000YO.>`m/x.}\u0003\u0016NTy\u00192O4_EmTӇ}q9EV|lW^ZCV|0dz\u0017t<\\\u001e\u0017e\u0014ՕRc||\u0019FcIJ\"q\\TL=1* (ʦ\bC\nE\u0005\u0014\u0010EYzivri\u0010F6o=_9RO+*.\u000fηѴ\u001fॅ@boa\b۾]xic\u000eثu|\u0001吏qFGH<rdE=݌\u000f2\flv^}3r*/\u000bs\u001e>ˀM4m\n<\u0010\u0014\u001aO\u001dq\u0004$*>'TҾ0*<\u00033i3\u000bAHZs\t'W_\u0018~B@Uu叜inkzxE\tKTvø\f4\txi#=vF\t?\"\u0010>\u001dǇq\u0019i;\u000b\t)v\u0010I\u0004IeJI.e<\u0001\u0015\u001ee@8NOf43̐;o]\u0007\u000f޸2ҧ\u0003t'sogAi쩤m{xi#D\\$J9\rW@vsˀoc#\u0013]<љ\u0005]mK˟^T.\u001e\u0012o53>\u0015tj\u0017fھ8Z?Ib&xNDl̨ATdq\u0011%</4i%dxf!(dilZWK˟)8Z\u0017ƙ\u001a\u001cʊTj\ts,\u001e\u00172}9BӦp,v!l7?\u0013\u0010:.xQuB1K48\bv%|Ĳ\bO\u00172}I~_\u001cHg69ص\u001e^Z\u0018<$£\u0013ZG9qHy;SށdRA&|\u0002Y\b$\u00169g`^8<z ߴҗpj\u0010h<\\8H,\u0019G2Mi\u0015g?9\u0007ION\u0013=O2\u001e\fU=6{B\u001bo\u0017\u000fqFGXv!\u0004Ux$ӔA\u000f'$='{K˟$\n^@tkK8Y\u0011J\u0019Qمd:9B\u0001xi#LbOn{QWf\u0007\u0012{\u0013nxZtzNk>{s[\u0018o\\ݵp|\u000b/-v\u0017[iQQxiSr\u000f=Gd\u0018V,MCA]D'e%/:ÙkadS9\u0007/-TiQq\u001c^ZNbϗp9mz+_>m4pq#5wL;nFϦ\r/-iQ\u0004/-\u000euDb/.u\u0005Rd^\u00135x\u0013x×\u000fl9¸\u0007qk+&\t/-J~\u001anK˟-\u0012XlY\u000bo,\u001e\\GW\u001ex,&F|-ӋȢ[f?n\u000b4\b\u0018g\u00118ZNxc!15&\u00075\u0018ST_;\u001550na\u0010_4\\(|q60K˟~*mzॅ\nZI\u0004͞g\u0016=o6cPk\u0015.0nVL#zi.JJ~|i3b\bT\u001e\u0015CB\u0018q\b\u001c3˟bڸ_/_src\u0007FdE-n73]hDv\\\u001cY\bvODJvIN3\u000bRG\"\u001c?>ܱןg̊J\u001fݣf\u000bCfF1\u0004,\u0004_P1HvEUP7G\"ЗpK˙\u0012:QxWi9ǂ?2.\u0013PL\u0017Mۀ\u000fY\b\u0004͇J֯?g\u0007&'+R=xoy2*$\t\u0005Uo<=^.u㳙\u0016#첟LU,<\u0010dӷ}g\u001fϷT\u0002c\u000e-7m\u001bdEGhPG\u0014[d\\\u0003Kf$\u000b\u001a\u0007<YpJS\t~'\nIب\u0017S\bO.7\f6m$E<g\u0012\u001a\u0018\u0012xꜫwھ=\u0004/-v䙩\u0004)h{\u0003B'I\u0004\u001a\u0002F7@\u001f+Tz?>:o]ltf!\u001cd1\\\tag\u0016BD/W\u000fm͖ۖj\u0016*<:6ˮL#Bhq\u0018LM=B\u001bͣrXlY\u000b\u000fooU^]Q[>.+$1.EQԒv|?L4ٴ\r:1\u000b\u0019xf!Jk/\u001aq>nOUuw2suU*:4R<%\r3Bxl\tS9LEb\fY\bZ\u001cVۛRj\u001d;5\tIBi>޵}/׀>{lBpyT\u000eSvEQE1\u001f8tE\r\u0014gf9=B'\u0016HJ}5\u0003\u0013\u0015uÑ\txfoL~\u001fSh\u0003<\u0010\u0006$\u0002\u0015U>k\u0000^\u0014qu\u001bf$E,\\[x}56\n\u000e9ՠ(<\u0010:c1tRn\n,GǨ\u001c6\u001cG85dc\u0013\u0006Z5?SH\u001f-\u001bU.MwBjry\u001a>\n,\u0003]9T\u000eG\u00037\u0011N\t\r\u0003,Z[4?ܶd5\u0003Ed\u0013Y\b\u0006[ʡw[3\u000baƥ(Ð8SLKBܦى+j`|\u0001ob}5߈ϩp\n^ͦFxfѡqQ\"}KCu;\f,\nJ㥩M\u001aEH!\u0017\u0018LꇢfE&ʒۛg\u0016¿k\u001c4\u0006N\u001eN\u0004EQ?~J\u001d\u0014^cBM+\u0013Ӛm$!y\u0002;\\M\u001a\u001f\u001a\u0006.]\u000fB\u0018r튢|v\u001dxf!\u001cK\u001d\u0007ٓ,6z\u000bP`z/!GHs\u0013\u001fU0\u0017)g?!Lb*۞mk{cED\fQi`\u0014d\u0012\nL\u0002[\u0007YJ y\u0013c\u000ej\u001eX2W'\u00146+\"Q`?{l4\u0006|h\u001f<(:4\t\u0017Y&S\u001czVq$D\u0005V8C\n䘧Bhr0/0}&xcQT<8Hћói8\u001e)|2vGic5\\5\u0007,\u001f\u0005E2O'mwmƢJ*ɩoǙ,\u0006'ߴ}\u001caB\u0006|]iQ$_OMg\u001cjvJwΎ;\u001dV\u001dM\u0010/k\u0004\u0011T.\nR.\u0011DX\u0010V\u000e\\ȍ\\='99ۣ\u0019\u0018\fFs'[\u0003{&<|ScF7-{J`\r+\u000ev^L;\u0016\u0011[H\u000f䨿\t]r(7n~9\raGT\u0000}\u001c\u0004_L\u0012&\\R`M˞\u0000T(v)\u0007Ew,\u0016z\u001aV\fyO(^\t;Ry\u0017ǡV/E\u0017,\"v\u001fTtx6Y>%^>/g\u0006;\u0016O\u0001lw@Wd &n>Vb0w\u001cauc\u0000߱(\\\u001f\u0000;ڥ޶=\u0015-\u000e\u000eSa\ntbW\u001dI\u000b7n1T'swF|`\u000f9[zO-@UH㼸\u000eݴZ8\u0012zxF\u001dH|-T:^tQ)\u0015\u000f\u0013bD\u00112lVb\u0006Ao#\u0012ZՋoZƔ#\u0000U!\u001d\rk=GM`\rc|\u0004]\u0014jRx\u000eߔǾ2~kPn\u00044R&Lo`@'?vtӲg\u000fa*k\u001dR\u000e\u0016ݱ#V&bܸ\u0005]׹sQB$,|܄%ǡ\u0005[-K!(\u0017\u0017whM˘=gu\bVr]ECW\rXf<sg$s߅SE'l\u001f\u0005.<\u0019!eu\u001bÕ0s\u000b]|`+`~V߄.\\v^ܷQRd\u0010H\u0012\u000bߺl0{j{3\rVt2b'C\u000ew?F\u0017,.z$TRѽ\u000bO?4\f\u0005J,\u0006.[\u00017\u0007! \u000e]hq\u0000v\u001efn'k݀.XDjO@)ś0]oDWT\u0018?LQJ\u000e\fFmw@~p:ݫ4\u0006'`gv\u0017ݴVY& K\\k\u000ev)'\u0007v\u000b\u0016\u001d\b`\"t{͈^ּ\u0017\rb\f,w\u001a߽r\u001fh'~vހ.[Ɯo\u0003v\u001enE\u0017,.}&>]q]>\u001fŰ\u001dm\u0014 % GK;\r\u001c\u001aP-\"e\"խN\u001eң\u0015\u001d}JiY\u0012\u0018Z`\u0007f\u0003;N\u001f'\r\u0010\b<le̥\u000e\u0006_N.n\u0007ԻHvEg\fOt/ӽܸK\u0006dn't3G\u000f\u0004<ab-lY\u0013!KLKb=ݏ/@+.Uc_\u0003)E7W3୔6سnc{\u00024\u000e˖1`;L\u000ftWˁcnJÂ}ts^$$_2\u001fNO0JU6ᇬ(!sesј\bYAq;jC+:3?\u0000V*ex\u000ey/\u0015MT͌'/o~ço\u0006ƀt\u0001\u001f'~t2g\u000faFrw;\t%A+.w!.D*\u0015JOQf(\b\t\u0000\u000fQ\u0013Vç'\u001a\u0017\f\u0006\tq\u0010B2˖%+M\"cfP._\u0015\u0006J\u0004[=E<F7,Fv\u0018d\fk\u0019\u0004i\u0011fFfCe\"q1\u0006aFHnrVt7$\t*-\u0017bW\u00196\u0007E,%x[l\f\t.+'KfIu/\u0005bWUft߲^\r];nOqt\u0003C6Vx\u0013&\u0000\u0012]F\u0011\u00187l'z.g4k˖%J\rq^\u0004.qUz?ބVt\u000f{KyTvW\\\u000bHy\u001f\u00167\u0001\"=BVyt\u0011NNԾEG\"͜\u0003pupޢ@Wk>0p\u0007U)Iיb)~\u0014d\u000bO\u000f% Gk\u0015$\u0000ncR\u001fA-K\u001az=:\u000evWԊ|@\u0010ybc\u0017\u001bQ|h0T\u0011_=.\u0019i\u001c\u0017:\u0000 \u0001uu\u0001ݷ8^i\u0012\u000fAw;u\u0003Z\u0007FbSy.e/zKዟ,@jͻ^c\u0005Nz_<\u0002SM\u0018ݷ{v\u0003>e}n{#^\u0007toE./r{\u0018p:\t23E\u0017{\n+7\tQF'u;\u0015j\u0012\u00017@\b=VaBW.\u001b\u0017i&#\rfɺ\u000evo\u001aݫy=}\u001d`2C\u00013\r^6m\u0015\b?Ԡ\n)Ԯs \u001be$\u0012\u0017K;G\u000e\u0006\u001ë́Еˌ\u000ex\u001b̒<q;!baۯѽ\u000f|P|\tTFM48\n5vy\u001fS\u001b$D\u000ej\u001a(sw\u000b\u0005\u0003r-\u001b|#z|z\u001cݫyBD\u0011`!w\u0017*\u0002ЕL\u000bd\u0018W=$B\u0012~~/rp\u0018\rfO.<u%\u00016hw\u0002ls|\u000b56i\rj8\u0003B\u0007$ ޠ\u000eݺ\fnޱo0{d\u001d턒m{5On\u0010ە,D7)*@+7\u000e5m03$Pe,ó1mVdeU\"u\u0019n\u0019W+K\u001a\n]\u0013}zS\u00197)zKipɠC\u0014d\u0005ZՋL|Ќ̙me0X8%\n\\;\u000ewKPnᘺ .D\u0001]IB\u001b7C\r,F7jʍE~F\u0017E7y\u0006HRT$x\t]Jvb>\u0002_\u0002\"vX\u0013J\u000e.a;zW\"Wf(m!;%&%S6\u001dW{\u0002+\\!ф\"kv\fū4ۋ4ó!E{]RjƿE7jPغm8j\u0006+.)\u0001eVt\u0003pkf&.Ъ^|Ku\u0011g@\u001d]>~)\u001d{\u0015E؇7\ra\u00186\u001b5(\u00006\u0012GlN\u0001gƠf$\f\u000e_\u0003+7\t=\u0014]\u0012s6E#[ݫ(O&\u0011E!buCcܟ:8Glwӝ;[n\u000bn\u000bvSi\u0017o (\u0001\u0014/ *\u0010D\u0010!2\u0010PĠ\u0002\u0002!'9!BH!䞜=n;\nb.ϛl>}O޴nTYP\rsL\u0001\u0015\u001aDw禷go\\\u0018\u0002_!\u001f&]qdMFh\u0001ݽTSxhi՗\u0000rv{\nNemuYؒ3k+cݠ\"4\u000b||.f\u0007\u0015\u0004\"6]7\u0001\u0019\n?a#~eI\u001d^\u001dVx\u0004]rˁ\u0002\u0001K~!>}\u0001i\u0002_9=Jye1$ G.q_z]z|qz%\u0002a.Qڿ\u001d]rˍ\nؒ_Sg\u00017\fO4\u001f}S/2'eT!B];_z9u\u0011\tK\u0018}\u001bGwRɛ\u0004\u000bۮ)B\u0013V\u001e/4;<^\u0006zYb8@ⴾ\u001avOt)t\u0003\f\u001d^Z%\t\r]=|~\u001dt-9\u0018[\u0004E!5A\u001e}u\fۉDͮ\t!I&~\u001eQ\u0013{'{\u0016t\t'iꯁ\u0004$vXKt\u0018/TQK`{~\u0011I)xɾ\u0017v\u001b;н`\\#K\u0005}bO.Q9.a\u001a)\b\u0005%R\u001e\u0007E*ܛ\u0005[ː6k\u0003\\'rӟХ`\rq\u0012\u0005\u001cY$hi؟0\u0002l\tq`lbk)Az?Ի\u0005]2̎o\u0016\u0019ت_+\u0013\u000fkE\u0018tc'\u000b̀㿎PT\u0007^̓y_o?Ơ\u00186\r6i.\u0004U\u001dA\u0017<SA(m\u0015tD`\u0002v]&CuRl_R/t\u001ew*\u0006LqIoK\u0019n;!\u000f\"gT_\u0012\u0000\u0014FbVl!\u001evQ=׈d#\u0019\u0011:\u0018Ko/nE1T67\\vG+K\u0003e]⾭\u001dݢfR\rRL{WК7f]Q;Bwu25\"d:\u0017ś\u000fӲzY\u001byRߧvx\u0001] )iŨW\u0006\u0019\u0010;ۉ(lk}\u000bݢL&o\u000f[R\\\u0011C5aY]\u0014|&G\tSH,x\u0015+0`x\u0014^NLԷE\u0017]\u0019\u0019Wdzo1T[Tu3>#lKY.Z.\u0015])EN!\u0015q\u000fx\u001b+`\u0017k\u001389\u001b\u0005'\u0018t-olzY\u0010dLn\tU\u0016mtYza;_JT\b:EhL\u0000[].*\u0005ocebqq(u\u001fHLƂnSFA)82vpWK\u0015*\u001c\u001c3j$\u000f\u0006\u0015\u0017I?D\u0004?\u0012ϟ;cЅh\\\u001c\u0016$v(\u0005;\u0011xކ\u000b\u001d.|zM((O|+Lq5ARY?\u001f\u001e}~N+gv\u00121\u0013,n?I~yɄ-C\u001bmEWt\n٫h\u0017o\u001c\u0019\t\f\u001d\u0012tS4r\u0018e=uZ's1\u001b̓VZ1 M~r.ehf<L]\u001cd :dz/)f`k\u001d\u0002K\u0007#<.4sQ9}#\u0002lW'3-1s\u0010\u0006Ens=ty<-g\f{x\f]͹\u000fȌ777K{|Ynn㖐|?\u0007z7s$[[a\u0018\u0010Ab`w!0\u0001يU{\u0010gD{Bָ]\u0003ty?E.3\u0000\u001b\u001cD2H\u0010aIqKp)tb}:#$KA\u0014;\r[}\u0006ts*\"Z\u001aՁO\u001b&ЏeǮ.S3\u001fB\u0016\f0l\r~_n%sຝ޿ӮE7\"#.}үEw2`|\u001d؍½\u0010Beʰw`~<o8<.J7X<\u0007\u0000\u001fʾhBצR\"\u000e-\u0011#^aZZK\b/\u0010\u001f\"#`߈}o-vme\u0019XeZj媿{R-R~<?-zfg]\\sK=3\n?`{Wg#6\"M޽[G@)/asѺ5N\"ؽ*?Gs\u0005ѝ\u0014jzk@\u000368ncq\u001d5GVm\u0000nftg*(-n3u\u0000NV]\u0010W]m,\u0001\u0002>'D\u0017ru\u0004!\u0002Y\u0000b\u000b{N'Zvsd\u0003._\u0006\u0019KRq\u001c&G\u0002و\u0001[´RaZ\fO`\u0017C`[|y\f-m\u001cd1\u0005?\u000e\u0010\u001d]fI\u0003bwC`[Ozc\u001c]J̞5~\u000bqO\u001bjZ\u0010s`לC`{%\u0015U\u0014;~\u0000~\"i\"\u0010\u001e]Sk`7Cy`\r;Т{R)\u001b/\u0010\u001fJ:lB/԰\u0005is(\tls\u0019\u001aSZIrH<H\\RC qKAi_%L/jv;j.;b6wBO=F7#\u0005?4I\twJ:t\u0015\u0003]+}r1\u0001]L\bcwC\u0019`;;Qh^v\u0018ݐήw\u001e:h\u001cM\u00108\u0003.,cBTLyf&\u0002v9\u0014\u0006\u0000|H<XC7s\b\u001f\u0002?\u001d@B<g\f+.Zu֢\u0006O_n.RurhՠFwc\u0016C{J\t>6ྷN-6T\u001b{\u0007ϳPl\u0000IC\u0003U\u001fݘ\u0005[S\b\u0011(\u0011Eq%84]+f]Gjv};cC\\tbw#t*71k\u001fKό\u001dgj=Sq;S-\u0010\\\u0010\u0001\u0007GqTl\f0ւV]\u0004\bK\u0002\u0002\u0010V\u0014%a\tl>=̱SE}s?\u001c\u0013{7L!$\fͮv{qݫ4^y\u0003q?f瘷\u0018P\u001bJR[\u000fe\u0017i\u0017==ű?\u001f|{z@\";VT;>.͓\u0003\u001e\r_\u0007;\"\u000b\u0007b\u001a\u0012v\u0015~ފJo_\u000f_B, 9nE\u00011f>Tϳ}\u0017b_\u0004A?\u001c\u0002 Cm\u001cz\u001f*T1\u0003ľ\b\u0019\u001c\u0002 <*r2TY1\u0000\bx\rv+\fᘆJkP4td|3\u0010#\b\u0007C\tЈV~^\n6AY%_b\u0001\u0011Dd!\u0006bD>gf)z\u0007*T\u0006Ӑ1\tb\u0004\u0011i`7q\u0001\u001aTh\rzE+67Zu,ȀH\u0010\u0011\u0002v\u0013\u00004,S\"zEiV\u0003푘솔Q\u0019\u0010\u000b\u0007\u0001\u0018W@\n)^{[E\u0001\u000fMM$\u0016\u001b9#Pw2E?Bδg?\r\u0016\u0001\u0001بÂx7e_\\s@;p<\u0001VJ9V\\cV~r׸u0/T[Gk-\u0005\u0007hn\u000fG\btw'w;NO\u001ar?ޣt[QGk\bI߶w\u001b\u000bsL\tUoNB~\u0014wE\u00004:AzLQg⛬\u0015\u0001\u000f_#1el\u001e^ԋ\u0005ߏ>ra@ßHs)'gl?3/5\u001e8[%\u0005%ݻ\u0000ެϱȻ \u0017iRƜ\u0003@+V$\u0013!\\\u0006b#ſL7nW[:Y\u000b\u000e\u001cuZ\u001aK\r)\u0007\u001bQ\u000b\u0005Kl1ݸB\u0001aUo$?tClg\u0007Z\u0002\u000f!mf4OV\u000f\u0014t]ǿ\u0019zR\u0015_\u000eߌڗWs\u001cںp\u0002&|\u000f\u001dbwhȹt\u0010ת4\u001b\u00064n\u0003nw\u001a\u00074%i/Y;\u001d:Ɲ\u0012\u000b`-8S鮖ey[gH)[\u001bo]po\u001bk\u0011\u0000%O&'CJ<˔d\u001c,\u001eָ|3BUQs\u001bYzP1>{^\r/&3}\u000e4蔜^{ɪ\\\u001c\u001d߸XZ\u0002ݲh\u0000w%\\)x5/.Ou0\n\u0013\u0007,nPɢ#5G+:mܝ|??<;-~yF\u0001~#ڒ\u000fK{펌O]hHɬyfۑ,Ĩ=@\u0001WLF\u0019w_\u00019{_nJ5\fhF\u0016$g5\\e~xav\u0015ɹmV%\u0001_\u001bli54dd\\kk\u000fH~T@6}m\u001c{@\u000e}<t\b.\u0015\u001a\u00167v'z~\u000fuG\u00135ۮ\u001eS\t|a%cU[c5KчF~*6 \u0003J\bv\u000b@HLJ,Y\"r/9\u000f:ƍ\u000e_M\u0018&\\Ýu\u0015}wn:m\u0018u\u0014L\u0018_\u0007\u0019!N\r#Mh\u0012ft}e_~Эt͋\u0015wJO\u000f_ܣ.;G0\u0001\u000f\u000b3W㮡\u0011{Ѫ\u0005^uFS\u001bT\u001f\fy=\u00069m\u001avֆ\u001e'\u0012Qşd#D\"6fk\u001b\u001e\rS\u0006ｅ($},\u000bg\u0000tW[sE$?\u0018T%ݠa\rfE$*61&\u000bvw\u0000ͦ7g$I&*|p݂ݚ\u0000n\u001c/^4$\u0017~\u0007h`l\u0000݂kSi$I\u0001F\u0017,\u0019\u0003\u0014쾔\u0019\u0018\u001bGO\u001dIvׁ\tvS\u0012Ѝ֠$IPk\u000755ݑr\u0005t)\u001a#$\tdI5\u000eH\u0019\u0003<\u0004$\u0019roC\u0007v;\u001e\u0005we$\u0010ݰ\u000f7{Q!@f{:z\u001aI\fg{\u001b\u0003\u0011\u0015\u0005r[3I\"0Ʊ \u000b:T\u0014✯߇L$\u0017'1Tr\u0004zeƝ$Ir\u0001F._\u0017ǳQKN2\nR\u001c1ƲѳJ<=d;c\u0012t3`7_D\u0000DNN\u0011Ē$^3q\u0015\u0004*97۾G-IsxִW@\u0007\u0005\"`\u0007~DO/IobC\u001enCZ/a$敖41\rs\u0011֘\u001f'$ɟTw]\u0012s\r\u0017шYqUg$\u00016BP[]KуM\u0011kt\u0013\rb\u001dՈ\"fv-x%zI2\u0002UiYg\\:v\u0011{s(hW9617d[\u0010z\u0016N\u001av\u0010\u000f7$0❈\t\u0000c,%\r=$x\u0018\u00195v{\u0011AL\f8e=y'I\u0005{#S9c\u00161/D}:\n\u0004HRaF\u001a:a\u001cn\u000f\"a\u0012J>G\u0005TWNp]n\b\u000b\u0002'k_\u0004I**6$\rR\u0010\u0014~\u0017$)kt\u0005ȳn)b\f\t֦Ҭ@?\u0010\u0005KE\u000f\u0016\"2->GJo/$eޒ^GDi])\fcRV}\u0012,̨X@\u0006ؕ<\u0019PG\u000f$Y]mC\u0004\bSRע\u000fI\tU!'@\u0004 ĂF\t;\"ɰ)!\u0002\u0011{\bp\u0004'cz\u0013\"Itc\u001fTA!\u0004!>Z\u0001;eA,D4bӬ)\u0010qf:(Q\"eNɲ8\u001f\u0006c*\u0016p\u00187]\u001c1sq!$s\u0011\t\u0014ʠ /AA\u000bn\u0015\u0011K2\u0004@mϽ\u000b\t?9VU$+01NjJeY}KC\u0000?3Ō,>\u00055Yr붻\u00137` 4\f\u0017x\u0000)pI\u000e\u0001^C\u001cvÃ\\'z0Qm~w\u0002u=Ά$x\r\u0019F(IkQ!\u000e;͇CQ\u0012۳}d\u0018UriWtڄ^\u0011(A*OmU\u001bdiJ3\u0004,\u0011z?HӀ)O2L\u0004)~\u001aD`}A:\u0000OGp\u0007^UYa-;'֠7\u0004{)as2\fD2MIV\u0005۔\u0010X9$79~KX\u000b0?\u000bJAlG\u000bA:=](KO0u[WtaBgR3\u0006wG\u000et\u001bfW\u0007g9\\,)3\u0006as.t\u0003f\u0010_?\r^v 9PȲ>Y\r>9K'5oËqL\u001bZ\u001eBX\u0010\u000f}szZ\u000f#Y>6o\u001eC%􁿄n<\u0019\bȲlȮ\f\u001f\u0004&\u000erzǕY\u0010b\u000e}!o-n;|\u001c\u0018H[\u0011rH[\u0007r2./4\u001e8ݼ\u001f>\u0014S\u0013+r\u0017B7Hs\bS=\u0006mMsz\u0006׺\bt۰\bQW]Q\u0004\u0010FSIXs34B\u00171\"еX\u001c:\u001enO\n\u0003!srˣ\u001bA9š\u001bL\u0014t?^\u0005i\u0015\taboڳ\u001b|-tkV\u0004]H3ڐgI\r\u0013dWo\f\\\u0007}[\nDA7f\u0019+_\u0012èԊK]9#\u0001-\u0003Q\b<YNi\u000f#F\u00144(З<t;V\u000bݡ\u0015\u0011%hcQ>:1\u0011$\u0006G?Eъ\u001bI&tVJ]u{,c[\u0006xE7j.\"Э\n\u0010w\f?kx\u000f`̂ץX\u001cfg\u001b\t\u000fDхnX؄obь7fؤV$kMv\u0007|\b\u001bsDn[$dY~|~9>\u0005u\u0006A+g\\\u001cD?H{F\u0004ݪ\u0004%{kGu\u0001(ߏ;\u000eZ\u0016_~Ϋn\u0018\u0011\u0012*\b.eJOdWo\u000fNnJ<ߞ2t\u001bW\u001f\u001fj[E\u0015.F){\u0017-)x,>W9jM\"\"t/U&ҸqBǑ[[\nOfՆmYF\u0003$!:tGEzownqQӾtS\"|l<ˎ-C71\u0017\u0002~\u0013\u0016tc\u0004X\u0007|#C?NiP\u0019I\u0005pFuތC2\u0003:tK\nXSP|NҞƽYU\u001b*U\u000b\u001aw}y\u001diaJO. \u0007\u001e)\u001fEq&\u000fOv)Zc|\u001d-j nگ$ݔ\u0018[C-',;\u000b~ɚ[vXbuZSq#\u0012%\u0011^ŗn\u0003QAwZg\u001d/RP\u0012(_\u0007\u0001\u0010Q$K/~\u0007\u0006\u0001D\fo2\"\u0013\u0019\u0005d\u0014K'2\"t)8&9\u0013<I }C/\u0011-\u0005\u0010?%0\u0007\u000e}D\u00149~\u0016T\u0013C \u0011E\u0011z`(\u0017GD1\u001c.}\u0011\u0011\u0018zHMk\"\"A\u0012E\u000e};D\u0003衢B_\n\u0011\u0015zh!E\u0010Q\\AOѡ?\u0011?\u0019\u00059\u0013'0\u001f&\u0011\"Ө?'FD\u00146pj\u0011\u0010\u0011\u000f`\u0003\u000eHD\u001b^\by\u0010\u0011\u0019\u0011皈ҿ\u0002\f\u0000x\rendstream\rendobj\r141 0 obj\r<</BitsPerComponent 8/ColorSpace 136 0 R/DecodeParms<</BitsPerComponent 4/Colors 3/Columns 500>>/Filter/FlateDecode/Height 500/Intent/RelativeColorimetric/Length 62605/Name/X/SMask 147 0 R/Subtype/Image/Type/XObject/Width 500>>stream\r\nHST\u001dgv\u00055ZŴMLk\u0004X\u0010\u0004\u0012D3\tZQ3^(H\u0005\u0012\u000be\u0017n\u000fS#sO\u000e~\b\u0000*\u0000\u0019\u0010B@/\b!\u0004\fz\t!,Z]A\b!\u001b\u0004=V\u0002}+B\bY\u0016@\u0007%\t!N\u0007\u0007}aBS@sA_\u0010b7ЫF\u0016N\u0004! \u0007\u000e:#\u0010k*q!T\u001dY\"\u0004&B\b\u0018\b\u0011sA\u0010\"\u0015\u0010٠\u0013G\b1\u0011\u0010<\f\u0012B*\tzQHu#!@O\bv\t%\u000ff\u0010+N+!d\u0015#A\r:ŠW\u0007t\t!\u000b\u0016t\tq\"\u0013N:!N\u0001uDЩ'ΠM\u000e\u0001\rt\u0005!\u0005Md犓?\u001bR{S$N\u000e]|~&٩v\u001cr[7/o[=wt\r\u000e\u0018ȑ#\u0012\u000e\u0006Fg\u0019WCBj8u}[W@\u001d@\u0018\u0010\"W\u0010ImtL{>s;ti\u000f5ʢl[a\u0004zcw_\u0004թ\u0019n\u0006!V\u0005]\u0019\u0018hx0\u001f\\?\u0017lKX?\u0017<ßҾHN\u000e{tK\b\u0012辚HA\u0013d̉c.&w\u0007Gg)M+yэ!Aw\u00144=\u0010\u000e\u001a·67)\u0005S>8\"8/p!\u001aAb\u00185Gf[6;zWfϡk'?ϦEaG7j\u0001\n`LS458\u0001W\u0003~6-禆\u0002)aѭ\"\u0004\f\u001bG\b15S!m{Sɴf<[`@7o\u00144LQ[/OԸ\u0015\u0006Zrsoї \u0011\"\u000ft6TF3^<ϝcQ*>m<s\u000edؐd7\u0003_6?k\u001a##cќ6\u001e]>BL\u0001]b,F ^mnR;FWƭ\u001c\u0006V\u001ayt\u000b\t$>d'Z[LɛQ,aG7\ndk\u000f&5s-&to<ЙZ\u001dt/\t8BI/?\u001a\u001fHֵ\u000e\u000bjǣ;JȺAf%Bհ\u000b?T͗BX\u000eU@5.ʲ\u001444\u0007\u001f\u001c*-o\u0007s\u0005\u001deA@cYbۗaP&|yt\u001e\u0005`B\u0000]%\u0010_1\u0006\u0014ZUֵ{\u0007Fg@\u0007t)=&\r6,AI\u0017m-\u001eЪuKxR+ú\u0014N\u0013RuÞgo]\r頖Јʩ\u0019Nb&\u0006\u001dȨ#\u00163HJC-&N\u0004\u0014\u0006@mh\u000e@w8\bt0\t\u0007̏:&yt߀n<?茿!5S?\u0017\u0000\u001aL\u0015I\u0003ĶZt_\u0017:Ľ]DZC5\r 6\u0004\u001d\u00058u\u0004^v@\u0006?\u0015\rX\u0000\u0004V\\.򽤫\u0001qd[.ry\u001d݆\u0005Г@,\u000f:eQ.{u+^Sjh<0?\u0014\u0002]\f;y\u0007-+\u0013u^x)]g/~pF6;\n+L\n~OLkئwX\tlVK8'\u0001-kp^\u0013֠7X\u0000lDT[=R.k\u001ao\u0006S}G/\u0007jT?#\u0000/)\u001bw|\u0006,\u0011z?H\n~<B\u0017Ҋx72qbPQ\f'\u001f\u001cHi\u0005rNT\u0011\u000471x\r)5+!$ *s\u001d\u000f*xDn\u0001/}&e?YTB`@&D$I\n5\u0003\u001e1\u0004\u0000$ida\u0001\u001fkJxUHKC\"?`sIx(\u0005zzD\u0001\u000fx\u0010IȏVv\u0018YK5\u001dD\u000e1\u001d\u001fljwFJ\b\u000fx\u0010\u0013.\u0017&=\nx.K$z)HNQ2l\u001bDiZV~d%\u0017\u0013CHݡ\u000b]\u001cJ-ɛQ!5\"\u0015CfltQv_R\u000bɉ&uћD*db\u0001\u000f)Zm̶\u00132oܦF|G(}O2;[[\u0013\tؗR\u001bz%$W\u001bi(_\u00046~xħui\u0015Fo\u0015Y\u0007Rwy]fֺ\u0015$'\"kBZ\u001e9#\u0016PjW\u001f=H3z*HK3Sj{/%\u001a^dYe\u0004<:BҪ0\u0004rN/h0\u0001O;\u0013%]8z[9:9ԁֵ{՜.=#s\\A|p\u0007O8us\u0012Kir^5\"i3jq~\u000f<۔:\\W\u0011*ms4rN\u001c׺\u0015x)\u001ceVN\u000bP\u001c\u0013w5L)=KY\u00009\u0011\tg\u001d.t)Kz_)\t#PEA\u0007Fg饔\u0012\u0000v\u000eB5R_܊K\u0018\u00049\u0002\tw4<5y#*a\u0016gs$\\ixV)˰\u0010\u0003zl[\u0018v)mWC\u0012&\u00026D8Zڎ@o0^wdRJѮޘ[B[a\u0006~gRZ\u0011O\u0018E\tfiħH)7Sf\u0006z\u0017-\u0007Er.t\u000e)\u0015i\u0003D\n\u001a!謩\u0003Ro\u0014S23Wu+QJsث:#荴$^$-\u001ex(\u0019NM\u001d\u0013RZ\fSoQŮ6/<uR\tֺYhꤠ2z\u0005!ǝfǩK\u001bKwOGf}X4g\u0018\u0013ӚajJ\u0019+T\u0007#\u001f^>xd䉞Xgw\u001c$J/(4\f-cbtbdc\f䌉\b\u0002\u0002\r\u000b\u000b\u0002*Ko{ݚqF#!@}uu? t_Uu2M@łmMi\u0000:vLqN{pEmĸ8\u000fqn\r\u000b[W3f==\u001d\u0016\u001c\u000f=s\u001dĶ\u0004+\u0010=9U}ji,D\n<U<18^@/\b\u0015'ٞes\u001dJvgN\u0003J0/\u0006]KJI~c&F\u00027uMXXr'~\u00076h\u0002׹\u0015M(*W^g\u001a\u0003I\u0006g2ϳ(Ɨ\u0003+\u000e[\b\\\\?Z|*U:H,\r\f\u0011\u00045x]ҨC__,,Qcp\u000b\rۣ9\u0007\\i\u0014ת37\u0015ʆnۢ2L\u0011ϓ\u000b<W3sr\f\u001d&'.K\u001a\u0017jZ}c9ZpU\u0013Yr*sTg\u0019q/I\u0013\\ͮ8\u0012ͺ<!zl6]z`.?Yk\"\u0014+Q\u001en}a4+ܰe\u0017\u0014\u0017\u001aW\u0002\u0004s\u0013w 5Nܾ:uZ;\u000e+mp'y\u000b~`wM\u0011o,4W<rvj\u0000!\u001e=^;z\u0012p\u001f@\u0012[ʦ!~R>h\u0016\u001e;\u0014ҶKutg\u0019[\u000eP_gb{\t%vjN\u0000W>wc-i\r/\fK\u0011zsmС7mK\u0001+\u0013.˟Z\u000b\u001cz\u0019;K'=o}po\u0005Y+6̥qQio3.\"2GЊWl{uL\bz)\u0016\u0007.ί#csr\u0011\u000f\f~\u0004R'ŵ\u001dCȢ\u000010]6\u000f^RU?\u000b7'>;zTη%GBFz]\u0005z\u0001\u0006P\u0007?ì2\u001f\u0010+^\";\"VXVG6\u0007ݓ[ztșz-\u001bmY\u001c\u001c[\u000e|ZYIb@7K_\u0019^_;\t'5I>Bp\u0013\u0016m\u0001\u001fN}<a4T\u0011Ro;r}]\u0005wH\u0014+9>SC7\u001b\u000bf\bhخ*@\u001d<F}zxџfN!\u001f\u000eʕ.\u0010Yü\u0015NY\u0019Aks\rݶ\u0017w%;9Rx)c\u001b7{\u0000\u0015X*sp`\u0003b|yiVw\f$G*hWҨ\u0010\u0017K&^K$\u0006@\t-\u0006\u0019ތ{\u0001VZ\u001dBi^\u001e)w]\u0001OƊ]pzc`-\t\u0004/6<VB]⁺{b\u0017\u0016\u0018/ŵ\u001at\u0015NN\\V;)4\u000b\bD]\fFޓJEט᳔\u001dfQb;\u0018\u0004\u0018\u0002!&}j᳑0\u001cM,>@E1\u0018\u0005E\"EzNV)<\u0004M,2\u0010\u00151\u0018\u0005K,wOzU\u001d)i\u0001\u000fb\u0002T\u0011QxC.\fہy\u0000},\u001a\u00100\u0018sr#\u00062Ex@L\r\u0000\f\u0004jT\u0006]\u0006a\u0000`0v\u001e\f[Um\u0004b^n>\u0014\u00100\u0018=4p4}ORN\u0013aa\u001b@`0&\"GEJt+MuZ!&m\u0003\u0002Q\u00054/\u0004'l²NQ5ҷHi>FF2DlG>׻ccj;n\u00072$oY\u0004[G\u0004\u001e䘖U\fxi\u001e݊y\u0013#\u00061&lO\u001f\u0004\u001e\u0018\u0005\u000e\u0017\u0017\f.aI'P\u001bwmF\u001f+~菥?sY!\u000bjAA$G2Mqʰ\u001fg\u0000؞7W(H5vajk\u0007A4y豟ڞn+f\u0017&cִ\\q\u0006ݍy\u0007.\u0001az@4(\u0010\u0011a ^&m2;\u0006I{\u0015l>\u00078щH8ĂFހ\"1^`z\u001f쌼'\u0014VaxK Gפl/\u001a9{\n%!%\u000bw\u0010vv@<;#/\tE\u0015=G,V\u001eNY\u0005q\u0007\r5u-!%\u001dC\u001b\u0019!S3XR3bJ\rc\u0017%!.]q߄nHkZBğ\u000b_~a\u0000_й?Ak\u0005.]h-Öt3\u001a\u0010}(\n?oH\\\u0012\u001b\u001bU;Є{XhXh5mzEe6B.;\"x:aٲ\bNH\"1\u0005S\u0001\f\u001dT{RBO\u0004{!JH\"H߯j{VU7VM\u001do~Wڽ0kף0Sƌ\u0002_L(YP\u000b$v`ǋk5誔b\u0003\u000e!!\u0010I%,F_(f3?<Y]\u000ezv\u000e\u000eūwrn\u000eu\u0012\u0006Sn֣R\tsݳi\u00111sx:޺ye{?Cw%\u0018v7\u0007!\u00126G\u0016ÏY~4_z`FW\u001fQY`+d\u0017D\u001c\b\u0018P([.M}TN}%C=\u001d\u0010wHh\u0018-V^.\u0010g\u00004Onm)X<IgmCO}pδcw\u0015n̝Ncm\u001d\u000fF\u0001ݱyOx\t\u000f-_\u001bO\u0001[$_ \u0002<לӭK`\u0011\u0017{\u0010vg\"п/X#\u0000W-Li\u0010@ψhg\u001buإ+D صC<%\u000b\u0016=\r\u0003dVA\u0018{\fߙRəz#6\u0010\u0005`\tF\u000bE\u0013vs\"c\u000bvͅ\fu@oO\u00050g\u001c%*\b\u000f}~?7u]q\u000bL&Ӥ\u0014NS\tI$db\u0002dXHX\u0018ppqlV\u0007\u0002\u0006\u0018oXZ,ɖdK,Kzڥ}}T\u0001lΕG;{GF3Z\"\u0003eP2jSȽ\u000f̓, h}\u0004c؞,\u000b\u000e\u001cSE2J,uE?L^7A3\u0013%MO9Vɜ+\u000e?^,~Rrk\u0007\nqTUK+{')\fЅvu\u0007_G\b鵦3&\u00190\"3b)<aYQS螌6gY\u0001|u'4\f\"\u001a$-&Z\u0006@fb\tm>HGR\u000eV\u001dDhܜs<xT\u0001_\u0004/\f]j*\n0\u0013G5\u0013=>xGQ1\u0017_?.\u0010yizk\u000f˓$l$]\u00015\u001evz`\u001fIK9;_\u001a4&lAg+%=I\u001a|>\u0017)\u0019fQ`lk\u0015ryr\u0011\u0002x{\u0006|\u0005dt\\ %iPZ89.u~r\u001f\u001a\fR2r1EJ'sjq\u00102S\\\"'\u0004/=\u0003;?F,ׂ\u0017ܭAiX󏯊=޾}dA\u000bG!W(lܮAW\u00173\u001aj\u0019a#ʙ[?hY\bv\u001c!\u0013viLaC{n-}\u001azy)w\u00159ƙΚ \u001e`'W(S2lZ\u0006vr,Ezײ\rLzKʩG=Gsh\u0007TO@P)?9\t\tpFPnk]-\\3\r.Mz&F[\u001dviq18?',x1˓v2_\u0018,㻪-'j3`\u000b63C%-&j'jӀf1}\u0014?Oۮ-.B9n/}B\u0013'Qj?mC?ArrK(\nm\u0003;3H|\u0005mv8I1ڛ3>rŞCiQ\\ؼBnβ@gdNܳP\u001c7y-'\u001f1VfWwiA2ޚ$\u000f\u0016joXE%=c>>:m.>7g0`}%g\u0017\"哧\u0018lt\u001bW&Ʉ\u000bY]o\u000e\"\u001c6\u0017D9\u0017ru/n\u0013]+\u000fNE!\u001elը\u001dHX?]/U>ףV7\u0015iٷ\u0001l\u0011\u001eNFf^zg\u0011ӌa\n~`F \u0017)D\"lx΁dn\u0013M\tso(g\u001b\u000b5!XzW8eW\u0017F$d\u0013n񒋔C\u0019O;s\u0016DV8=\u000foMڬ\u0016\u001b^\u0014oL୐K\u00000\u000b\u0004=\u000f\u001c.=Ya;Gr\u000e%$Z=\u001eҎ_\u0019:U\u001a=w{\u0015\u0016Qc\\\u000bc\u001aMbu'ZESޘa{\u000e%\n`I\fcG3\trr[zvG|\u0004o\u001d5,;MzӳJR\u0002l\u0018恝lmg\u0004l>U=G`f\u0001i\u0017Ky+Wbһ$ou\u001b\fX2v\u0000g+.*R\\y`\u0014XmŞk_J\"ŘKr\u001dL\u0014ZfI+NI\u0000dXVh7݈M\u001eCΗ2\u001b\u001c;HĞ8jj,˕{X\u000e\u001aNb)\u001bK\tV>\u0015:ٿ\u0017v\u001d\u0012D0W\u0017'\u0014{\u000e`NսޓHu\u001bQ\u000eEWW\u0016ȍ\u0015fW\u0012a@\u0000NUhD9{~ .\u001cfӆR\u001dK7]E}8n\u001d՘\\{\\d8ʡ8'F凓7\u0003;Ua\n8\n\u000501Ry\u000f}ȭND=EIQ\u001dE2E}QEi\f\u001b\u001fv\u001d\u0019z\u00038RAoZ۬&1\u001b\n֑%W06U3ld`\f9IgO\u000erÌ\u0003\u0004\"\u001fy\nʨ\rd~aQ9Enױ͛7V.K|\u0019a\u001c2a\u001b\u001fa-?\u0019GTGEꂙEc\u0007_O{WV1MoEgd\u0001cQN5zȥ\t[$\tT\u00003tϴ\u000f:\u001b w&V\u0013\u0010\u0014rC5;?\u0017O ܫ0e\u0003v[\u0000'2\f}T؜\u0001\u0002:r{oN$\b!˚LW6?T9_uݖ Iz(\u001c`\u0005\u001a%Ww>5jlսT-r%'*'H2d(\br<2\u0005r'ש\u0002N\f8%vXb\rwz,ktF\u0006~2JX\\\u001c\u0003,\u0014\u000b\u0001ƄR~ wH:\b[\u001dS䛞Οڅd$l\tjFz,wut\u0016\\$}w{\u0007\u0002,h\u0005\u00010\u001f>\bOnr\u0005mr]\u0017Z=x\u000fѤ7idGL *'H\u0012dY\bp7汣\tV&V\u0017.U;!wu\u0018\u001c;b\u0000\n5\u000fݸ\u0005pEIU\u001e _Y\bpͳ\u0014ܷ@,\u001d!\u0017uqt@\u0002\n\u0018\u0000?>a\u0019\u0011hf^\u0001}/`ŉ\bpM\"3D\u001eXrDVmY\u0017rE6\n[\bcJ]7\u001b\u0000&\u0006~4_,\u000fN`-B_$\u0006\fr\u0016\u0001qsI\u000eNԌ*Ww\u0000tF\u001c\u0002>_*W\u0017D␏BE\u0004M\u0012{0,g\u0019K/o\\:\u0001Zz܍[^&^KNr4\fj\"\u0002Fa\n;7t\u0000â\u001cE\\qr-p\u0011S@\r(FŸ5Z=\u0019g*BVr\fYk.\u0002F\u0019r?İ(eLjt'2\u0014h\u0017`9jK\n\u0015\u00065\u001d,<\u001aQb\u0007J\u0004\"_D\u001f(I1'Rrm[fB\u0006kk\u0005OVR.Ӌqkm\u0002~U\u0007J͓\u00024\u0017\u0001~tܞRX\u0000K˱\u000b\u000b\u0019Y\r\"5[qk7`\u0014h)6r\u001f\u0000әvnawǺlGתe]bu\u0011d,\"ł\\\u0003\u0011\u0002\n\u0012@B.BBn$$9\u00063uXQ93<?3|/7ZVJw\"K_;O̞m%\"*zܴ\u001d4В3ҫ(\f&ս^W.\u001f]\u0003y/}ʆ寥zۈ\u000b.ZOOq>\u0018\u000f=\u0000ʬ_Ea|+[\t$\u0007K,!|E׽i3To\u0015\thw\u001e<Qc۟V@W\u00033$\nC ~2\\ƭ1ϝ\bST\\|T?k\u0002\u000b=\u0015^ڳ`JOHQ\u0007\"r`\u0005s'9\u0002n\rΩ\u0016I\u0006z|eZ!Ϝ[}$\nC\u0011yuOKǥ\u000b\u0012\u0002Nr\u0004|+滥Z8^$\u0014Ҟe&\rfZ(\\ݑ|Qow咒`˝\u0014\t{ܒj=@{\u0006_\u0005=\u001ap{HQaBۑ\u001bD^]$\\l\u0004s\u0004|+\u0015Yhi9\u0017M+\u001fë\r\u0011-I\u0014\t_\u0018x8Z;=D\u0003@o\u0011E|MQu:E'Zzr53\u001dI(t\u001eX\"m@o/\u0012E[ʩ޽DU'\u0006'P$%U!=Z\u001c\u001fE[\u0015ڎUQF֥\u0003ge,K\"󳍮jST@{ӑ.zl5\u001f@\u001f(\u0012ȫ:\u0007D\u0014ۣz+;Xd-U@{\rcjΞ@Ҏ\u001288H\\P\u0012pޱ\u0010=D\u001e`*ߜw+\u001a4kU=l9<٘egC\nʡ/{(\u00183Nᨱt\u001c,*0H]À:RjU\\\n44{(\u0012O\u0014dvAo,W,@\u001a\u0014\u0002\u0015-ݙ(Eې\u000fe1\u001cG|4`\u0004Q%(\u000f团z8yYˮa3\u0011p;=DIJ\u001ab\u0019P1\u0014iX1i\u0019~cYe7E\tKJ\u001bZFU'\u0015\t%UL\u000f,H\u0017dfTHd|U6zcYL.P\u001a\u0014%_nѦeTg'Qbr\u001ez];|v=\u0014\f\u001fu8jOo,G\u0001\u001d+y\\}]\u001bvu썮5Ӫ\u0007܉I%J`t.8,NoGiT5i'jӼEk(w\u001cG]\u0003힋\u0010^kP$w*2\u0005zf)\u001c0bۣ\u0004|xvʵO+w'\r\u001f\u0005S\u000ezTuB\u0014Xm\u001bP02PgEJ\u0002%ԓ\u0015IWg03\u001b\tޥGU?dl@λUz\f\u0005s\u001c\u0016%hX\u0016@\u0012q{POnk>=uu\u00046:Ӌ\u001fn\u000e**!ZHTu*\n.X\u0016Ɖ\bFb^i/\\ې_Ћ+\u0016ׇ nM\u001e\n'\u00049͏wQ\u0002=\u0014~b$I)}W;ջ\u0017%p>Oo޸>\u0001q;c(\u0018ylY\n\u001c0?;\r;;X%\\\u0012RQn\u0013Msw\u001b\u0016\u000e~.ٵ\u0018\u0003Re+ʡ϶W>g\u0005AG+ȟRmOo\u000e\u0019\u000eC\u001a=\u0014V%:\u001cg¾ӳ\u0018/K1V]sG\u0016!\u0002}\u001b\u0016zE2\u001f\r\u001b&=\u0014ywǲTZ9xn^Z\nI\tgkPlɪ+w\"C\u0004Cnqs7U1\u0014IXN陥\u0010Q\u000ev\t̾{%ĝ\u001f\u0003JCyzBuK\r%C\u001f\u0003\u000f=\u0014([ӄzʬrWo.A9\u001d'T\\:).H*)Э}8H,\u0005\u001a`~\n[Xun~\u001f\"0^SL[s<{(\u0018܏esӶuzf)Զ{1\u0006Uʝ=4\u000b\u0011\u0010S489\u0018-\u001d|ǲh\\g?o0\u00062gr'ɘ_VZ\u0003\"Ӱdw[\u000bSTjA\tT\u001d\u0013#\u00068\u001f˩2_U\u001b&=\u0014\u001eX/ࠗ\u0002J\u001fQ?_ST-^VrU=\u0014D\n_3KAalPOS\u0014X\u0017!\u0002#i\u001f=\u0005K̘V{(\u0012U1F,N.))ncYA\u0004-]xCxlnl>F,1n{,\u0019&>f\u0016*I\u001c.\u001eD\u0019stR\u0004R\u0010*q\u0017\"\u0016^\u0005LBۑ4>=V虥0H@\u0004/ge-)m@\u00046-s\r⼪Da=OK=3QlPO\rr\u001b\u001aJ`m?\u0005G|\u001c}Da(kU$\u0019r,\u001a;1\u001cC}m,ezB쥕$=&!3v$Z\fs.W\u001a]jϝn\u001fF\u001f[RVj\u0004b/rӛ[p\u0010E\u0013#1RK/T61m3qZYή\u0014C\u0013Sf\nn(\f\u0013v̡4՞3^Cf+nf)7@Yb\u0015\u0000/N(\fCCi7\u0005՞W\u00171m0ZYZf C-l&\u0017\u0010[g$\nCC\t9\u0014D^ZKN^b,fޥF-z9\u000fҞY2(\u0006m1ziK\u000b\u0010{*g\u001f\u001dfnn߷r&W1D5\u0018U\u0014!L\u0017\tzi\u0017!Tt۹em7\u0004`\u0014=:Ǖ޾9~\u0015Š~\u0000vZ^Z9|\u001evEz\u00077\u001f\u0018kr}Aߥ=3g@WQ\f1m\u000fKRBs5hkt\u001eSϸ\u0012\u0010ϯWa\u0014k혶o\u0016ھQ\u001c\u0005z\u0011z?uKs>/4\u000f\u0000\\}i{23KA{6g\u0002W\t=%F\u0017Uz\u0018\u0000u\"\u0016ھQ\u0002\u0015_1Qy\u001c7&llI3}4[\u0001JFֵ5c=Z[QD\u0011\"(2(r\r00\u00073\u00000=\te]}?ߌ7ϋ|O0;\u0006KvB\u0014w\u0012_Z\t7}3Y\u001e\u001e/^\u000f\u001bP\u000b\u001c{ѥn8C\u0018Aֻ*AW\u000fϣeza|\u0003\u001a;hƘA\u000b\u001dw*љXt\u0018߀Z0~6h;QBe6\u0004ME\u001c:# ۾z*m\f\u0006$u{`c\u0013GoӂwK\u0005R.\u0001S-1\u0001zxb3d{/\u00192+@K\u001f؉n_5\u0018Ȱ!\u0003nc\u0017\u0016\u0006m0*\u0014d9\u001aq]\\8Un!9DJ9>+049\u0018\u000f:(\u001e4\u0003\u001eԏZ8tÆN(u~4\u0010.|!\u0003J`l:&$h;Yz@|.4oީ䰡Vc\u0003$\u001aXt!\u0003/!\u00192F\u001b٠9]\u0019\u001bZHtM k'-\u0019>a@x^\u0013^%QyPAr\n|$\u0003+`lҍ3̢\u0014d\t}\u000b6\bi\u001e\u0014W6\u001d:Ф5\u0006Fa@QnꝵϹF[v#\u0019ͮ]u3\u0001Y\u0001\u00108\u0013jw2*CjCE#\t\u001chĦ9&\r\u0017E^&̢#\u0019\u0015oE<'\u0005YB̢&zs]EHkzk\u0002 -E\u001c^d\u00079ҫ\fVv^iBKB~ .(8\u000f^YN+z+u\\~hRW<H\"k\u0017|\u0010%Tu/t\u0006gq\u0018H\u0002f>h32@Si([a:kg#O꘰]*\u000bOjX$ourO)9ƭA۹cd\u001fS9.-6]\u00053\u001f4Ldr~/z\u0006F+nGop%\u001ezQ pu\n,t<f(\r\u0015G\t/\u0004ʀlpu_Rѥ忉90A^*e\u0016%g[Asz,\",\u001e簛zr\u0014\t\\]\u0002)3-+^8\";?\u001c\rV\u0011O#\u0012]\u0013.X\u001a0Y\tX8,j\u0015\u000ffM\u001c%\u0002dv\";D+~\u0019 9a\n\f:]$Jtio^\u001ef>hզ>\\c8A\u0006V\u001f@7\u0016d\u001f:<f\u000e1\u0013\u0016(\u0013\u0005V-T\tXuZ\u0010^D؂e\u0000FpJCִ\u0019\u0006|I\u0013:TbѢ5+@\u0006\u0014$3ƱLn\ro>MnSN3a2L9P9\u000f\u0013'lE\u00073S\u0007c=/-@\u0006dm,bc\u0016d\u0016C6:7Y'ʹGilv2J2D͒y}{P-%&\u0019(-o]3Dg\u0016*\u0013d@\u0016v5\u0016+\u001c\u0001eztiozLi?([&\u0012{\u00056-Vu:[8`Ռ;1'G\u0011w\u0019(}&#\u001cۗ}\u0016tfQj0`\u0016zqJNW\"Ȁ\u0006F.-MQĹ\\*LxBAڒ@ٳ(XNخQ5κPƢ͈\u0015'<Ģ\u0019(U\u0010틨ـ,J\u001d\f?>,\u001f|r0z\u001eR$|Xm+Sivt&RlY}P\u0019\\:jӢ޺g\u0012I_\u0019b|6\u0003F\u001bҾdFЙE\u000709Q\u0019\u000b5=^toykrP\u0013HS|^\u000f(}?>\u0010\u001fҲphEhvTH_U=Gi\u0007K`.K,|\u000fuj&u\u0010EŨRw\u0005\\*1d.3liIzR\u0013ځP,\u000b>^>_n8>QlN6\u0010\u001fO?\u00060&K%954A}S\"Fe\f(1O\u001fr@\u001d!6g(\rʑ'`j}\u000f\rv\"ZUlY\u0019wb\n%\t\u001fO?o}/\u00139=̢\f\u0015̂S`\u000fB+nUE \u0003\u001a\u0018\rRm\"gx42l|+m:@[)-O\u0001S'p\u000b/lW\"\u001eZtMwңPM\"\rxy#\u001bҫ3%0\u000bN=\u0016,]qӕ\ba|\u0013:ݻ=,GoƢ m9G(P4\bܲ\tۇUyj\u0014~CR];2\u0019M)ӟkg\b7El@g\u0016ec0\u000bNz\u0010I\u0003a8]8\u001aͦ\u0018ڸ6\u001d-)\u001dQ(`\u001a}B𒎹W{]ȭ\u0015\u0017 \r>koWpiRC̢Snp*MPt\u001cX\u0007jƱNk\u00078c|_\u001ejD\u001bw棔\u0002eK\u001cf{<qלu}\\~DNR?|'KZAx\u0017M\u0014+-m\u0005x\u0012YjǜP\u001bNK^\u0017Vu \u001bj\u0012t~\u001a{;e5\u0003;\u001f\u001ah\u0004eMlD4\tr*K>\u0015Xp͌;1!is\u0012\u00144+ꟕםn\u0017Y\u001bn\u001bqKPϾUi֔\fe=e\u001b\u0005>\u001a\u001beG\u0017Ƿ/h)zߣ\u001c\u0002gN\u0015*SvϺ޼hV&=:$uǞL(u,~؋B\u0015)\u0017u\u001a\u0014ŕ\u0001S{|j6_vkwR[85!\u0002\u0002Q.+FW\u001a%k0n\u0014l\u0003\u0013<df8(*\b\bȍ\\0\u00033\"s\f0;\u001cn\u0019<*yswQ?<2bg\u0016K\u0006,8g]B;1tś\u00136,~|\u0014;³\u0011Sݳ\f}YTF@&\u0004O\u0005K17Nn}@̭q5\u000f)\ncv8_)<$\u000e:~4[-ufW#p\u0016+3OPmh}mǰЊ=+סڰS{\u00037³Ra71?pQ\u0004P\u000ft\"П\u0007\\qMӶˇH佧/z_/\u0011Մ`P:>5l2WY,Qmh5۫yXhu0F$\u001b\u0016튋b=\u0017`$vo2zB>T\u0004P\u0005j@80|\rW\u0000S17sFSCإ[NjUŁ0w/Q`\u0007\u001fSLӉM,]c\u0019EyP=O>N.\u0001Ռ\u0017\u0006ck#^\\0\u0014HM*C\u0003\nC:\t\u0018x\u0007glNzH@+dD\u0011H\t?Ԓ1D,(ؙғ\u0017h\u0016.zެc\u001fU'IQ7fQkgCGv)̣ XD*àz\u0003l}\u0002\u0018ans,-Ӷ+pPXh%>yofE\u0012+*Eu\n\u001b]8+[5ؙҊf5\ri8:INlF5㈩\u0017;\b[K`j$1)WRO\"z\u0013N\u0006t`*0UK.q\u0012\u0016O-70\u000f\u0011\u0004\u0003B\u0010=Ёt2nGIkI\u001f,]s[C\"\u001bq6m_\u0018,4\u00193$1MFҳ˴\u0011w0UR\u001cw<RT\u000f\u001fAm\u001c\u001d\u00063\tLN\u0018(pH-r-<]pۭk.\"\u0004nBr4-\u0003?_'R2nAĒT\u001fvi~>ߒy\u0010>\\|}T$M\u0015f2VPg\u001dAv\u0000\u0005roR\u0019\u0002UXQ?\u0007\fYTa9ˠt\u000f4,Y\u001f&\fzRد\u0004Q\u001e\u0015J\u001c?\u001aŚZV-i\u001ew|̩\u001e\u00193%6\u000b]BbEu\u001cA5<e{\u0005m=\u0002S$HRK*CU4l=N\u0004T`\u0006&!3\u001e\u0011V\u000b]鿲8{y(\u0011P*Br:Ui^f&ZYPJgA6d^\u0012%,TA5-C`Vɿrd\u0001u~\u001e5דr#\u00152\u00027@??>\u000ei\u0003L9f߳Wĭ5|^巶$7\"\t\u0006\"}w\u0002$GBblZ\u0018-'/.-MD+6J1EJ.Rm\u001f%\u001bUqv)pè?\u0016IL4\u0005䞤b\tz\u000f7BͿn/O\u0002y`\bL\u001csͤ\u0013dP6i{MGFo,]\u0017\b\u0010ג2))l\u000f,Ɩ#\u0016av.-hVp*/CW\u000e)D5B\u000fNݭ\u001c|}j\u0002\n}He0T\u0018\u0001u\u0007\u0000}\n\u0018\u0001KT2G\u0012\"n]{vwB☛K\u0002\nC\t>!F\u001f\u0011J\u0007ΐ܊\u001dX)8\u0007Z̲\u000fkdPB;1lrTIZpɢ؉H֑o%%Ps(\u0017RK*A\u001a\u0018jwA!@\u0001\f\u0002c.0r̵\u001cKl\u001b6_j:VhKׂv1ׂ(1`[\u0019ӹPX,ͪBvie\u0019vioZ0\r2\u0010+MN-^jAC\u0013vk\"Ñ\u000f7׵J)ܝT0-P\u001b\u000fuG\u0000\f\f|`\u0002L78:j탤^^Iun\u0005\u0010\u0006\u0015s2lo\"w{\u0015Cu:]&F5d\u001ep\u0017gЀlħy\u0005J^M5\u0006\u0013\u0000ՒVx$\u0006;?i1ڑV\u0017R,ܓT,!UP\u0001jBnH\u001f\u00053 \u0000ƫtsÃdЭ+\u001d\u0015Q׃./mV$_G\b~yL(\u001bBr6coKrSJ\u0016$M\u0016;wW\u0000\u0005+PB\nfQghTKҬn=e#l.zQ R\u00127B6\f҉@\u000e\u001821\u000f06N<]$\u0015?{oA|WCw!!\u0004ۉ#Neൻj\u001fG-.ɰK~\u001aU\b7ʫQbE?<\fm1RDع=?\u0019s&SLGTBjOn/\u0001}\n0d\u0002S>)9Nд\u0007\u00011ϵ3aJ@?儿[I\b\u0010\u0003yNv\u0006~o٬\\j<4.\u0007,wӱ^#3lħyH\b_t^\u001c;:gɗmT:۾\u0014p{\n?R\u0002Bf\tu\u0001}\u0002Ӏ!\u000b\n8Ls\u000fb1ߵc}U}xci@a_\u000b\u001fe\u0016\u0014evSL**sa.\\$UQi6e]\u0001A\u0016QQct4\u000e#h\u001c0.\b\u0013;ʨ\u0002;\" \u000eݍ{ߐ\t2`tS\u001e%w!\u00038\\KiԶ1[%&ɣC9㦵}K\u0007\bv_m$nu\u0017Ƣ\u0013]ז\u0010,6$vc\\<\rCZK5z\u001f=0r\u0010Ϣ$\u00014\u0012+<\u001a)!\u001e:\f)P\u0001uYk,7EXzcoϺ\u00199Sf\rp\u0001t>\":\u001aD\u0011ֵM\u001ecR`F7㦵qVk2\u0003\u0012_R\"5\f@\u0013N\u0003Re)\u0017\u001eOY\u0016n*R,LQb\u000fJ\u0012Hыl5oDH\u0019\u0007UG\ffB]>K_1nt\u0015.\u001e\t5>\u000b\u001d>I[\u00008+\u0000w\u000b/ .#T42o]\u001b$.\u000fEǸlmӗ\u0012p4?k$R&\r9%U\u0019^t3qu;CjK456Fc;orċC\u0012$[1H\u0003)\u0018Ԝ,_g\u0019g.VceKzZkA\u0017Bw>\u0012.\u0005܍{j>RԚ\nw#'U\u000b*ŌY\u001e'֓,\u00151\u0012qUωfPE+O\u0018sKfᎆچis\fO\f\u001d.ėG2$[䛐b'R}\u0007ՉPs\u000ejd\u0019\u0006[ǺMX~W\u0015~K\u0002~\bcFGŀ\u0001\tG:\b变wU^Ih7\u001aM1\u00049KьGG\u0004\u0015vpΉN(`t\u0013t?%\\\u001bRZӔ\u001fۻaDgQ\u0000J\u001a($_[\"\u0016Cu\u0012p6\u0007\nYWnyn\u000bk[s\u001b܎ޚ_TqŐ?gE|]\b8\u0001v?5\u0002\rl\u0012R}q8Qq\u0003V9M6w{\\IO3b\u0019wR#Ip;C]cW2lgb\u0007JAI\u0002)z\u0001W\"H5R\u0003P\f5\\̓a\u0015#num?>pKQ黪dnyӳçn+~\rxSsO\u0014>%.#\\}\u0014^Hl7\u001da\\6Ω$0N#\u001a7d|nUsN\nfR}^\u001d\u0013t?)<Y@<\u000bCgDI(i0\u0017#j$\u0002)!\u001e:\b'7bƛ.diw-glڲ9AܰO\u0016\u0000N\u0014~\tx{@Z\"_J]F?ӽh}m֖Y\u0015߆e\u0006%b:bdʹ\bi!MTS,_I|\u001c1b])/%\rEH\u00067\"v\u000bU\u0014ԤA\u0005+aYmC})Ѭo\u001a0J0;o S\u0006X?*\u001eMI\u0003\u001e&\u001a'ɔW)f\\6\u000e\u0019\u000eG3~\u001d\u0011\u001c~j֜4\u0001*\u0007q qN L\\b^n\blgaD(?%\rC2$[_\"\u000e\u0007UG:\u0005jҡ7\u001dr{}Sa3w=}#\n\\/!##\"Y\u0007\u0000d.'.#զBmL6Oi\r\u0007;\u0018-\u001dj\u0010\u0012_g.\"8t@c=gN\u0016r\u001a\u0012M\tqN\u0005>aR򂒁i\u000b\\\u0003%$s)i$l=oFH\u0000UG{9?Rn1]~T8s#' \u001fB\u00191w!\u0001ܭ\u0000NlGSȼ\t>᣽\u000e͸lmh\u001dtDjd0'\u0017A5J\u00184gD\u0018WHN\bB\u0015\u0004~tl\u0003'N؉xQ`D/DUH\u0001)BX\u000eC\u0019ɀ,][)b7v:5{Rῴ8b_çn_\u0005\u0000o\u000fHK\fȶG֙w2(4$1\u001aM[ّ֖\"\u001a\"q,\"sm0'\u0011e\fi\u00173n\u000f\u001c|\u001dC]\u001fwAJI|)i\b\u0017#j$FH-TD9\u000bPw7f\u0002\u0011IX^~~+J\u0002\u0003.ϛ\u0013۴\u0005 u9~\u0001xW\nz-_a4-kH̋mVq2Qq>-\u000e.\"8a\rkr1d|NUi(g3bO\u0012\f}#\u001e\u0016LLQb7JOI\u0010\u0014 F؆\u0000T'A9͂ne\r6vq7kv{\u0017YX~o*V\r\u000fræG%\u0001v\u0000\u0001}R\u0003W\u0018`:U¼-Lj0H\u0018ӷ\u001e3[[&Ow\"\"8Z?*'\u001d5O\tjF\u0017%\tBu{a\u0018D>\u00191\u0019)'%KI#\u0010\u001c\"y\fRlG=Pu\u0010&\u0015j.V\u000b-B\u0016\u0006ĺ;|ז\t\u00127\u0019,\u0002\u0000w\u001b%dYo1;&laD$R3.[[fS@g\u0018\"\\O?\\\u000f_AMy\u0018;ۙ3\u001fawv#\"yU\u0004R\u001aA\u0005\u0005EZZ/X^.bUG\"X\u000b(\u0002xA\u0001\u0011r\u000f\u0001QFHd\u0001et\u001d3</}t\u001f䮜K{_a\u0010IIGɛ2wBKȃ\b\"\\Tkz\u000b\"\u001e;\f?C\u0003\u0017fB\u0015F_ۛqvY<\u0006^I\u000fq笻17,?3'sq#\u0000g%\u0000^<\u0010$!c!1[\u0016qj5wA⹿=\rO%\u0006\u001b8D/5$cdVE\u000eO5t=k;+HP\u0010D:H$\"dE(Br1R@/:\u0006iv\"Pw\u0004OB\u0003o\u0012\u001ex\u0003]#n\u001b\\6_:mֆb fM\u000f}9n\u00028?\u0002\u0004g\u000f=rh\u001a&{r\u0011ü\u0016\u001dgo~y\u0013\u0013\u0011\u0002=N\u0007L\u0018\u001d.%\u0016TQ/^\u0015-u\b g\f\u000f d^ܟP\"e$RD\rH\u0015B}Pw\u0014ꓡ\u000f{vӯn'ڇ~RשJM%W\u0003Yl̰?\t\u0016ԥ\u001eb\u0001 \u0010x\u0015ewcE\u001dE=:00\u000eL;[bS~/>3>\u000ba,@Y(31\u000e\u0012q]\u0011=/k+\nt:t'|HN\u00122&!G(\u0013Z\u001bkPw\fSA0\u0002F_)ta\u001f\u000716\u0007yuTÊ)*\f{9\u0003wR#\u0001'\u001ap\u0003> 8\u0001iyϺm?Ǌn{tϾ_J\rZ}k9ܣ\b7\u0016\u0016\u0011\u000e??\u0006 '7\u0001̯\u0001\u0003OnS\u0017`)H\u001dH9\u0017\\dܗ\u0007\u0011H)RF/\u001b\ru\u0007.\u0001OA\u0010fCUFM\rn1v6&\u0002lNρ\u001fo+[^\u0014\u0010\u00175/\u000b,\u0006Հ\u0015\u0003A\u0002\u0010rcʰ\\dEQ\r~$_\u0017(ˎd1ʵO440/8\u0006X\bc6E\u001d&5Nz\n[\u0018}I)5nb?%4S\u0018~L\u0015\u0015k\u000e\u0001/I\"BIY\"\u0004)#r\u0019REH\u0003iP\u001c\u001aNCC\u001a\u0019v{و[.\u0019v{U[ȓWs2ϯ\u0005\u0004g\\{\b\fp\u0000^\u001c\u001f\u00063\u001fwl?\n]D!~˴>HCr햜[\u0016\u000baAQ\u00038\u0005\u0018\u0018}I^.;B$&g3$Ýt&d^ܟP\"\u0012Zz\u000b\"m<\u001dDh8\u000b\r\"4\u0016WFQ[Q,A{es\\\u0017\u001f4;iAG\u0001F\t\u0007 \u0019\b3\u0012,wYQj]oZ\n&3%v'G?ÿh!MR*cq\nكq\u0011A쉭l\u0007KcyV!t#IJ\u00112&!G(\u0016 忐j%RG\u0018ى{'O\u001ar{9he\u0018\u0018}\u0018\u0007nW<C#nv~V#\u001f}wkκ\u001bs\u0017\u0015\u00041/\u001d·Q\b.\u0005/\u0000w\u0007\u0003$ \u0014]r\u0015\u0003%\u0016oR~ghW}-Mo\u001ch!M$'X85P5`%~i҉v{ދ\u001fp\u0015\u0016o:\u0004\u001fNI, 侄<P#RZ\u001bf\u001bBڽPw\u0018O@C[ݹͥŭGFwb\u0005s9\u001b\\\rb岝2>\u0010.|'u\t\u0001m\u0017\u000fǀ.\u0019Fӭ$/X@I+7n];dO/}\u0017\u001c\u001b\u0015\fel3e8T\u001eqW+L;\rT5U. g%g~D2<Hy\u0012r\u0016\bFEH\u0019TK\u001aiC}Pw\u0014OB\u0003\u0017f@%\u001a65wNC2vQk\u0013\u000b5^'\u001e0YJ?)\f{9\u0004]X紅r\u0016\u0003瀻\u0015\u00000\u0010\u0006\u000b{EX{;|I&[\u000eY}8!\u000b\nlu핦\f\u000f%U\u000b\u0013'vAGЯ4\u000e4ER`яt!;Bȼ\t\u001f`#b\\Tkz\u0013lG8\u000fua\f\u0011F(][]˞zd?J~{YQ``^kύ\u0000\u0015\t\u0005\u0003@p\u0012\bgw)\u001chl9[L_ύZ<_\u0015O%O鶮\u001d2ba\u0001\u001b,\nاC݈Ҕhc\u0015E=\u0007'l\\%%\u000e#t\"\u000bFȘ|\u001eH\u0002z3@\u0000\u001d\u0014hLh\u001bv{9T9VkwJ[.OZ]\u001b<rkNU2am+Z\u0000JпgOG(Y\u000f\u0006}@\b<v)\u0013׍VXh7U2R\u0003/\u001d,)b;YY\u0007.`DY(\\\u0006u0\n3e܌]I~5\n$ 1K:y\"侄<P:\u000f<\u0000LGL;L}\u001f-r)Ƅx\u001a\u000fh\u001a5\u001e\u0018<G\u0015\u0001\u0001!HC\u0004\bH\u0015\u0010Q@X\u0011\u0014o\u0005Aq,uyf3\b.@\u0018^ԱH\u0013BA;\u000e Ƭ\u000fvh\u000f\u001c[:ZvOP=mU%å!9äX\u0014\rR\u0017\u0000J\n\b\u00001 J\u00053+=,5Ǧ=>)W\u0001*kJk6,ZsWC|/!ۊ-bG+^h\u0007qʃEdm/||T=Suc](\u0004`{/u\f#(|\u0019E0BBZkf\u0013lCڽPw\bꓠ\u001c41\u001bv϶}5.Mn:5>q\u0015KG\u0015\u0004{q2#>\u0011G:\u0017\u0001F \u0005G(\u0019/\u0000IGIjӗ?8r[dʎO\u0003m6X^UMd9o\u0011\u0010lի X=CÃ\u0004/<?\u0019[,/m?4ԓŢ>`\u0018:cGF(\u0019e\u0018bg#v1R-CH\u0019i#>;\f'!\u0005\u001aVۥ܁+V^T{ϥMPX㳽oՕ9y?I~˛\rx1\u001e\bv\u0000a\u0002\u0010\u0006b\to%t\u0011nn*ۙGFE\u000fmn/⻶F\u0011\u0007ɿw셟羮:I\u0016J\u0004v^W\u001f.tb0r0r/F\u0011(g\"v.b r_!7H\u001f@Ih8\u000f\r\u0012hhkzf{\u0007wն߸Rxgu?)\r_\u0018\u0014x)!{_\"?[l_\u0002k\u0000?\u000e\b\u0004\u00108\u000f9\u0005\u001e:Zk*m\f{}Z7ln/YqH|\bY|v+H'[=O\u0007d<MjqY/V)&UT{o\u0014\u0004ޘ\u0011#we\u0014>b\u0006\fG<\fW\"zي;6\u001e\u00124h́\u0005o7\\L4x$zw]Y⢠PYKH8\u001b.\u0002U\u0005\b\u0002Q :\u000fY@RJj߱\u00196\\\u0019Z~)vpvKo\u001d߃\u0007(]o!\u000fn\u0003MW~>l\u001e\"xѹfrYS\u000f>\u0003\r}v=0t\u000e܍Q2`F\u0019\u0005H\u0015ԫz\u0003|\u0000\u001bOCC\\e\\S5T\u001dl~\u000f:\u001du8յ9u͸q^{Ɩ\u0007,)\u000e\n!djdD|,\u0006\u0001o\u0005o\u0002]@x\u0004\u0002q:Hbic1)\u0001E\r`$B7qg\u001fՃ7l#Uii9EȣS)?K`x`)}v30g\u001aw\t;1r\u000fF(C\u0011\u001bEH\u0014 FCP\u0000uG?t܁vǆvf[oxT\u001fsyF4='B'\u0002\u0017\u0001\bv\u0000a\u0002\u0010\u0006b\u0011䁴Ԏn[Mgq;\r\u001ae*KoNinܡ!\u000fن]l3\u0013=m\u0006w\u001e\u0015som{*`-\u0000<\u001bOAȽ\u0018E 9]TːKل4ېv\u000f\u001dP\u0006\u001aИ\u0001\u0017v\u0018\u001b۝˚d7uwUe%#޹a\u0011D?\u001b>\u0007@/ \u0007$ \u0001EvٻLڣ%w3س̓\u001a\u0007b\u000e\\`\u001a{EJZ{P`CRɉ\u001eIC/|dxOHnw\u001cl.a䮌Q`ም%H\u001c\"fَ{~\u0016\u001a\u0004xW\u001aeUlop-s<%Mτiq\u0015+J\u0002\u0014\u0004兢?E}()\u0006@\u0017\b\u00029 \u0004\u0002v-򶦜ˍ\u0002\u001a\u001aCmɝ6GƬ=*k2:\u001b\u001e;d{\u0016\u000bUINΣcIڞ۳`\u0007SMI30\u0017ۻc\u001d\u0018\u001be\u00142\u00023Zf\u000b@}Pw\u0018ꓠ>\u0019\u001aV܁v\u0007wdN-SRyg[ߪ+\n\u0002/:fkzG u!\u0004@\u001b\b\u000f\u0003\u0019 N\u0003|V_V)\u0011\\lGrӅ-\u0011]94^q0!۳PONͣ\u0002~1Ҿod{ZJ\u0015@n\u00189bgF(\u0019e\bRF!v\u0001R *^4[v'#P\u0002\u001aA\b\u001a3a\u0017moyvlӡZ˔n:\u001a\u001d~_\u0006,,\n\n\u000fu8\u0019\u0017E:\u000f\u0001~,\u0010|\u0003\t@t\n\u0005@\u000bҮڬ$2\u0016x3т=.2\"[#L|V\u001cjx\nUvV2jۉn_*>=Nؓd!!\u0005\u00130'\u0000O\\W\u0018\u000b#b\u0014\u00012\fш]TKz5R\"H\u000bj.\u0011OBC,헹\u0003\\u(;\u000edvNȴ3ʹ35</\u0012\u000eKH4\u001aX\u0006\u000fJh$(Q\u0017\u0011w\u0001Q!\u001cr* BP\u000e\u0011\u0014ͻrv]K\u0004\u0006\u001d_}6\u0003/ϩ۵ÝҴ:\r\u0002CݯsNQ\u0000k3c\u0019p\n,灠\f\r5O4\u0004\u00171Z[C\u001e|a_<蓽6:g\\\u0016\\mN9d-]xF;\"OR/*\f%{ߡDz/mI#\u0017$)\u000f%]F0\u001a3\u001b|\u001bVĊ}Xy\u0000\u0012(RBsH|4tb;>n\u000ewni#u{\u0003><8J\u0004oW\u0001#`\u0004~$\u00027\u0005x\u0019\u0006A1\bo%o!;1.%\t{qea\u001f0\u001c\u001c9\u0004ϞԾ\u001e˾ws\u0015!`0X\u0002i>@pi\rL6ٛ\u000eDӋ|h;\u000f\u001a9юĝR@J\u00123k1l'X\u0019Xu\u0004!u\nҜ7.ll{L?\u001el\u001fpwjq)ލ;7K Pܕo\u000b#1!\u00068$\u0000\u0004Ҁ\u0007A\u0001\b@$j*ylƌd`4^mQ\u001a:\u001b\u0011Uq\u000bO6X\u001cKytkOOYl=\"{kwvn4v)'%dX\u0016|\u0013o7\u001e\u0007H M\u001af!\u0010^F\"u/]2e{vqKn;ny'5oX\u0016U\u0012W\u0010pi\u001f\u0011殂u\u000e}9\u0004d\u0003>\u001bW@X\u000eF\u0010s\u001fdwxY&ER=6`UrLO>s3f#\u0001lgq:\u0017h:5\u001d|zz2\u0006\b;gp\u001b{\u001b[\u001f{\u0007v^+)+%\u0001,\u00143QY囱b\u0007VOsJDH4\"-kb{̶}{s<n{\u001fmkJ~\u0017\u0017Nvěײ\u0002k+w\u0003'\u001e8IK\u0005^&sAP\u0002:\u0010*\u001dV]c4<'z\u000e+5=xQ\u0017]<s?40^![՚/\f)\u001e\u001d|zvL>KFch;\u000f\u001a\u000ečPel\u0005fVaf=oŊh؃CX%R@Hs\u0001ihTFL^o?v~m\u001ft\u001bpwjr6f>\u0017}}!W);Y\tػ}\u00008=\u0005t\u000bAP\bj\u0010\u0002QW'dט=Rcfσ=0XB=+,_{\u0003\u001aE\"ԆlI5/(2O~R]8\u0013{Մ55v4r\u001d)\u0007%l%f`f\u0003oÊX\u0017+cajtl4z\u0015Jק>o\u0015lo\\ٹ8GF׉>\u0007kvU\u0006/\u000b\f.\nv\u0012oW\u0001k#\u001d\u0007\u0004\u0000^\u001ay\n\n\u0010\u0004Q;wʆTd\u0007?s\u001b\u000fi^\tzjtc.>s>\u0013\"\u0017+kCVTI?aO9\u001b\u0002v\u001fIĴ7m\u000e3%~4cf-f6m߅\u0015\u0000V}TIH5Ҝf{3ڎM\u000f\r:?|n\u0007՝Wzdxs/*``vo\u000b\"Y\u0005YW`\u0002\u0010pw\u0016x,灠\fu \u0003\u000f[:\u000eJ\u001b;\u0006`0LLZɤx\"{>l;~SlDLcemȖW\u0019+_p9#4X5\u001am\u0019\u0003Lg\u000f&~qUq\tmIۻИR\u0012oJ\u001a@B,\u00123\u001f`&,ߎ\u0015`e,VcU\u0002R\u001fEHs\u0016i3Fs.^W1>_۵/l\u001fOlw5݃u撄:U\u0001ʗ\u0017\u0007䇢K+/\rd\u0007\u0018{\u0013\u000f$\u0002\"s@P\u0004\u001a\u00105\u0017G\n⳼bhgK\r]V*YDħ?j~qXi&>5\u001fX\u0016?8gj\\ri8^Il\u001emA#gځQR\u001fJL\u0014faf؁\u00151X\u0019\u0007\bR\u001fCSHs\u000ei/\"-\u000fm/W\\ZiJmZr7kȒ \u0010Ǽ?\"F\u0016X[\u001d\u0003\u0003I\u0004)]\u0000\u0000\u0004\u0005 \u0004a\u0013:@\u0017Q!\u0018T\u0012_gQ\u001b[\r\u0006v\u0007kɯ\\uv00@M!\b}6yk<,q/\u0014΍Ǝ\u0013%񠤾t9%\u000bj|[\"\u001a+vcX9V%\"u2R yDZ)\u001bf}\u001a\u001et\u00180TZm<#5\u001fW,[]\u001a/v=(\u000ePuL8S'3Lt:-\\D\u001eC\u0011!\u0014Q>\"Q(\u0011EP\u0004h`ݗ \r\u0002\ndaY@\u0014\u0005hr#Ʀ\u000b%~\u000e\u001c\u000bgezE;oZ\f@l\u0002b'#\u0013\u0007d2p\u0002^>+A\fB\u0019Nhk^Hi\te\u0018\u001efzkwL93a\u00061J3htZp\u0015.\u0015θb\u0001A\u0000\nDH\ti!.݇tQ>\u0016'`ӣg`C͇\u001fP7vswtl鴬\u0012[_={dct].nKs\u0016\\y~SE\n\u0004\u0006 B\u001d\u0001#@&\u0001\u0002n\u0006r_\u0006F\u0010'\u000fȺz.\u00065V\u001ejg\u001cW.+gC\f:C ]\fbBUлq~~\u0019f%q\r.w\u0015\u0003)}j)Rlߌ4!H\u001bt\u0011؈G1W\f6\r\u0017l*{([b\u0016[M\u001b1UNe.\u001bܖ]s{x~؋ m9\u0003\u001d_\u0000;\u001a8\t@\u0003\u0000x9/\u0006A\u001d\bZ@ ڶ\u0017Nk\u000b}\u00057T}GLiLb\u00104ipC}G0K\u0005.\u0015sp<\\TH\tRFH\u0005iw m8}1}\u001cfHlga\u0003|\u001cR?6eZ\r#N{ʜ7\u0017\u0006{]pi\u0007\u001cK\u0016@\u0003 p\u0001\u0002\\._\u0000*\u0010\u0002a\u0019!,ezc^[!(qß?\u0012I\u0017)'\u0013Ř\u0015qz5NdB\u001eTҾ^L\fY,q\u001dp\u0015q\u0017R-BH\u001d4H\u0007c\u0018L\u001fOٞ\r\u0010\u0017(\u000b\u001fQ7v-eQ%]3Zֶ[ئ7۝mpv[YW==\f?\n|s'\u0005\u0000+\b@\u0002v$pL\u0006.\u0001L\u0001\u0002\u0004 \u0014O\"%SRZ>L-/V31\u0019=0=TWBF_V]1<az+\u0017{D\u0012g2D\u000fM\u0010.\u0019W,H\u0015T+z\r\u0013i\"푔0IpvA\u0001e\u0017lx\u0016^nu&ݹ\u00069_V8o+v\r*B̏,A\u0016\u0003k\u00156\u0002\u0011\n\b\u001c\u00012\t4\u0003\nK@P\u000fV\u0010H'MKj\u000eR^&U11I~=Q:Όo>yMB^Ӫ5\u001f7?\u001dӴDP}Z)3RinV\u0019mp#pŕ\u001eHTK*\u0010\"Fن;\u000b;\u000fc#\u000f\u0006ؔY)k}?eaUjs]j9+憔~z}\u0005n\u0017Z]P>o\n\bX+\u0015\fD\b\u0002;\u00068\t@\u0003.\u001fx_\b\u001a\u0010@iF&މo8YZ1Ay7J]!P!*\u0017ˌƟ\u0017M'LDxɺg~PLoog\u001e9@1*Nxtv?YmvQ u\r\u001a/TǴ+Ϣ}\u0015LdJͥ\nƨ{Q!\u0016W\u0015n\u0013)j)Rl߄4ۑv\u0017C\b?\u0019NQsA!6x\u0011\u001bJ^>j{\u000be\u001fٮ\u001c\u0011\u001b;۬/X\u000e\t\u001f\u001d\u001bZ%y9\u000bmv<iE\fX\n>\bc@\u0001.\t,\u0003\u0002\u0004M lLIiyD{15y\u0007LM\u0013*EwpLLoa,\rv\tWǕ^HTːz5RC-H\u0013aH\u00170},e{2656@b{˲cVIuȎXQTܝ.n\\sG~p/\u0005\u001a \u0000\u0011\u0006H\u0001y\n,f\u0000*KAp\u0003\u0004NNmnlkR%ӫ}ĉiN~\u0014\u001d*_L&V~'I-^_.\u0015.w\u0015θ\u001dWz#bZAH\u001d<bv\u0007҆S\u001fG1}\u0002f8\r>}(|(9ۛ~olMɬ6ˢٜ&Us\\6\u0016-u'w:RZ\u0000V\u0003\tρ\u001d\u0001#@&\u0002\n\\!r_\u0004Z\u0010@iF\u0016X\u00002\ro!!h\u001fPngz&+SO\u001erG\\+=\u0007\u0002j\u0005RA\rH\u0019҆\"nۏ1}\u001cjv.6\u0015kGm`{߈XXH)ۛ%ʿι=ip2EW==-2?7X\u0012X\u001b\u0001\u0001N\u0002g\u0003^6\u000b_\t&\u0010EJ\u0019\u0011e!Y\u0012\u0005\u000b~Ǵ\"/\u001962=|#ѓ!\u001e:jL8Uvԩ㴝i;vΜ} ʦ[\u001c\u000bR\u0005Ե,7a/B\u0002\u0001\u0012\u0003EV\"VʌcK5k|9給2W\u0013}b6R,B\u001dˑr%REH\u0015v\u0001Ls\u0014ӞĴg1]T\u001fh]Y}l|\u001bZ̫,ujkNMDݡ\u0002\u001d\"5B\u0019S}NIq?f\u0018\u0005\u0007\u0000c\u001d\u0010ہ\u000bp`E\u0000\u0000v<pҀ\u0003\u0004@6\u000fX;t%^\u001eMx<76eQ3n5՛\u0003e.adIt\u0003]6.\u0014~H1\u0017u,}\u0015RC-H\u0003C~\nӞt8`>Ŵ\u0017c۫Z[Xq6$vG\n\u001cBDN.2^򴌟h1\u0019ÈG\u0003|90\u0000#\bP`\u001e\u0001ַ\u001d\u0003\u0014 @\u0016\u0001\u001axW\u00071FT\u0017.\u0019lg\u001awS\u001axf\u0006_P{MZt\u0013]FOG\n:/r5RGH\u00130AL\u0013iOcHLt$\u0019/鴮lZ߶'7okyl\u0005\u0013j6\u0012N\u001br\\\u000bJswKNWGL\u0001Q\u0001_\nU\f.`\u001e\u0002I`]\u00006\u00178I@\n\u0007n\u0005\u001a\u0006\u001aDּ{|?\u0012iKև_\u0014H\u001aQҦ/xV\u0006\u001f!՛{%\u0006kj˜2w\u001b)f\"|Ա\u0014u@/r\u0003R\u0005!U\bR407g=*F:BP\u001c\u00009in\u001e\u001e6\t^\u0018ￒ#~\u0003f\u0001\u0004\u0004D\b\u0010\u0007y\u001cXf\u0003;\u00118@+\u0001n\u001d̓/\u000e;-\u001d~fۅ\u001fO8\u0012)՛x7rQ\rs2V!՛&?=\u0006?+ו/et'\",X:!ecU\u001bj\u001bRb11L-;\bucd>%|9\u001b[_i6/jyeb\\夋eǊ&]vܒ\u001c:/+cr\u0017=S(;L\u0017\u0002\u0002\u0018\b\u0006b/0Áu\u0006\f`\u0002\u000fd\u000ep[\rA\u0011UKF+0\u000b\u001dI*\u00122wS/\u001cT<orgJqWzNĶ+3b\u000eR,B\u001dˑr%RAMH\u001dwa}09i<GKe[7]뵽ټaB֕\t2ۓœ;\u00069v]pk|<_3\u0010?D\u0007\u000b`\u00056 y\u0004X\u0015\u0005h$\u0003\u0005d\u0001pk\u001cl\u001c\u0012Y\u0011G\u0016ޚڴ\u0003.dq&SolT;B\u0019|u\u0006՛\u0010;k\u0006]*\u0017fܹ5r-RmF`ލc#D\u00170\u001d\u0013a\tOlc{\u0013~]q\u001bu\r\u0013k'&VM\"mO\u0015wܞ:eQ\u000f)\"nߣ}pf\f#\u001e>\u0017ρ\u001a\u0018[\u0005C:\u0001&\u001d@[\u0006: \u0007_i\u000f!,,8\u001b2\u001cĆdnQ̦#xcuT2$YqT]{/ei j\u0007Rb\u0003Olt\u00171\u001d\u000b=WaW7.i L,9]bw0!8ieITT)<'OgχL\u0001Q\u0001_\nJ`l\u0002\"\u0004\u0003<\u0006sf\u0001;\u001e8i@\u0002\u0004k\u001eĨ\u001f\u001aQ5x3!ؓ]\"jj/jQ)mx\f]_K!BW@g\u0018u\"m\u0019nڻ\u0017\\5G1IL{\u0016E==\u0011{mϥu翨ż\"R5Lݡ\u0002\"uB3LswKNw_HߑL,\u0017\u0003\u001e\b\r@\u0004\u0003\u0017Gu\u0006\f`\u0000'\u0005H!,Er\u0005*L\u0019eTr\u000b$7DR=-J\u001cȀ=*z\"\u0013\u0007MMyb֕k{i\u001fo>^h[k\\mͩ9[jw+ӆ\u001c)<=l\u0012XOX~3\u0001_\u0000x\u00000\u0001c\u001b\u0010a<\f8\"e\u001e\u0017XV[T)j\u000f^~x\u001e7=6==\u000fF҃ۢ\"m\u000b!\u000eA2[V-\u001cg׷W4Y,\ns\u0012Ŏ\u001bs\u0003\u0004S榻yxLN\u001a\u0017=k\u001b/\u001f^`ǌ#M\u001fy~0D\u0004RCYoO/5Vzy=\u001dy$\u000f'\u0015m[emKw\u001c\u0014w\u0016ۨghB\\gZcœڜ؆\u0017ڇ\u001d7:\u0007f.'#P\u0018\u0010 ޲(Ns.V%V/󠦲433euL(@\b \u0002=mq[iwm\r\u0005\u0017ĭ\u0005\u0015e\u0011nf\\PQT\u0010\\\u0010ŞVMPP6Y[\u0004d^B\u0004\u0013HXmYvC;%Jջ|;9!C!\u001d\u0003\t\u000e+\u00023=I+PGT͉\u0017͉MIMMI\r7טkU\u0015'Ȋ\u0012ErQM#\\\u0003W芐\u0007\u001bj,}/ѩ\bǰ888:\u00108\f)eD<:R+q̋㷐x-Ö\u0003+IOʓZ\u0010qpp\t]\u00028lQ_؅nr\t\u000fҋ5pi\u0014iY\u0006\u001bOӾ\".98\u000eE&,w$Lx3_]liK3L\u0013肐^t-âfU#iYzocgT\u0019\u00158& \u0007Q9I\t\u001fd\u001f2\n<\u001e\u000bTb#\u0007G\u0017c\u0001W\u000fH+\u0007\t=/2Dmh}S\"Lh<|4\u001bH߅!\u0018aW,nx;V\b&_`uǞ\u0013Uy8\u0006\u001a~Myo\u000e;!Dym楆\u0005\u0017D|\u0012\u0001&Ǫ\u001bI+m\toJ\u0017y cw\u0000@\nfA\u0018,\u001enL4֦֮̋'8,tiL}u\u00156ƥ%wʮ\u0006fz4:\tӳ0/1y0v#*\u001dv\u001fD<o\u0002`\u0006\u0004+A\fb\u0001\u001c@<`\u0012&21\rd\u0014RySuģ\u0010wqwM-Etv @\u0007nox,m\u000bjiY;5h4*d;[w!#oێ F0aK*0[\u0001Bg0_\b \u000b`9\r&\fۣv2.\u00111ϲ\u0007\\\u000f\u001cO¼{U`\u001b)KI#Os\u0002Ys\u0001:NR\u000e\u001f8S]\u0001{ͪ\u0006tKnd\u0013\u0019}\u001boF|70]\u000b\u0002W0cKbp\u0002#\r\u0019`9\u0015&2\u00191͈B\u0019\u0010\u00144e=#'ٍ4g76_\u001fx=\u0011<ek3iQkՍҘ\u0005\u0001Gݨ&J\u001dh'\u0007\u0019Xt\u000f\u0019}\u00072Vڿ\u0006j\u0010p)/\u0002\u0005 r\u0000,\u0010O^Sj\u0002{,c=\u001d\u000eb$+/޴>21\u0016Ӭu|Vy߽-n^pM?Xj\u001f\u0016i}q4fQLo;\u000bϓ˘nu~0\u0012AZ~A=|\u0017y cw\u0000Jr\u0010.\u0001 \u000f \tj2Xgl\u001f\u000ee\fd$24-eCi\u0003tnJBeRffS\u0007\u0004L='\u000fG\u001c\u001b-?pw(r>܇JUCRQ^[YB{\u000e&jˁCɫ][[!y!Lg谴 'ⱥ}\u0013׃\u001a\u0010\u00042\u0010.\u0006\u000b'\u00109B \u0001Sj\"ceXalF0C>\u0003\u0018\u001fӗ\reCi(Z>HU8\r*ݿ.&DB>Xq%bi-+\u0015W\u000e\u0017{\u0011l;\f5ħC|.|6$g/\u001biU\u001f2%\rZF5*5\u001623q?\u0017\u001fh1C\u000bwZ02\u001d`\r\u000b\u0019y#vd\u00057\t[W\u0005K|\u0011X,\u0000\u0003gx:\u0002V\u0013\u0018ьpv0#c(G\u0006Ҳa|4-k&Q5),J@!~%~ӪT\u000f[r6U6^+ۑg\u001f\u001agr I[G\t\\X\u0012s^3/L>+\u0019wcv\u0003~\u0001>S\u0004fzJ\u000fOEg'*Exu\u0012#^}\u0018U|εcay\u0007|\u001fJ^'iw\\Zj_0\u0003\u0004E\u0011\u0007,uuv/NdĖm\u0019t-\b\\l9\b9[h\u000eg%j<c=\u001e\u000ecl\u00071d{Z6chtd\u000bJ1ṚjZg΅[MU\f+;,oy\u0014R9\u001fQDT\u0017O\u000bKP's}?>{='66YpuWWs¬345:tdJ\u000f\u0011\u0006QHAi7dK\u000ed\u0007\u001a\u0010\u00042\u0010+\u00109B \u0001Sj\"X}Xذ>314-eChHZ>kP53(\u001cJ1]Ԗ+5T\u001bUN{P\r\u0012A}U7[Kt&#*.\u0016oHM, <]\f|?}D_?~=\u0018n寻erb՞\u0017\f\u0014D=oQ;;\u001dzɌ\u001d^\f:\u0005=NJG/2B<\u000fd\u001bd\u001d\bV\n\u0010:B\u0010-\u0000\u0003g-lO`zcG36۲ݎ2}i\u0000Z6h\u0004f*R5ۗRuT_};#i-i+i<$y/9ٷ*ltթMjiY\f݉(ϊ(\r+ڑ\u00119)x݂\u001b\u00045\bd\u0010\u0006{DT\u001c?\u0005\u0017w\u000b[OQei\u0018_,1\n\"h\u0003HsH\u0004\u0015\u0010P\u0010\u0010A\u0014\u0004\n80a\u0004꘳\"t\u000e`\u00046&\u0006f\u0006\u0017\u0006\u0016\u00163=\u00034AL̶/~h\u000fs{}Kz(EaYb9,cr#d!B?\u00139zkɬWDٮbr%z:.\u001b\\ģGmq*m6э\u00152b'!>\f#h$VZg{\u0010\t`l}\u00191(Εtc\u0011+]r\u0014V*?!H\u00134Ӑ&\u00165B\rPBd];lE5Z\u000eS-ǩLUHJW9T9\u0012S_[v\u001e/zQR{IU;.'(\u0001KA\u0002T\u0010p?\u0007b9H΁*Ho\u0014d\u0015 \u0005x=W}}Οo)6Zws\u0002Ӥ+\u0016/pfZM\u001e\u001e&C>'\u001dF\u001dK<.׉#7i0tNOÞ1уVӦ%{b\u001eO,t$b\t'XN!VaZ7\u0003?c؎f<\u0018\u000bC92\u00183NXU^XUX\u001dԡH\u00134Q!\u000e5FQq1.G\u0014Դ\u00015mӨ\u001f:l?/_ɨWg>ޖm}྾}S}S}[m;Vz?yY\u0017E\u001f,SrFf7jZojU(ZZ\u0014M-\nmHTDko֩Ԑw\nfk\u000fRf܌S'^\u0017<t\u0010٤\u0001=5\u0015x3\u0000\n\u0004\u001b@\u0006= :\u0002L\u0010K@\u0007|*@Z\f{ \u0006=2{\u001dfwY%\u000366^ucВ\t:k9=p鈉\u0002\u0014:5ݿP41tN\u0017:QѾ6]I&\u0013h_@,搡3\b'p\u0011\bb\u001b:31\b/Νd\u0003cXU\u0007\u0002z\"R!\u0014fm\u001aYۗ \n]ja~\bk{\u0016*m[})szznK%\u0002_ 9_fIÃ'\u000exC\u001fk\u000b]U=Ny-\u0019ؔ[ދ\u0014s\n]\r\bɟs>5oaIⰯ\u0005ݲ\"\u0017\u0007yO\u0002\n\u0010\u0007V\u0010\u0000C \u0000\b9 \u0004\u0002\u0001/ \u0002nG=2kz\u001e^\u001dߦ5ZSd|}\u0016sbXEmCE܀,}H_ t1tN\u001a\u001dcu|th+=p\u0013m\u001e,'!>\f#h$VZg{\u0010k/c;d\u0018ʙA\u0003V`\u0007V*_\u001aH3\u001d5dmO`m_+Y7RM[ty7|d\u000e/\u0017q_u\u000e\u000f8>q|jreJ\u0017]s{I\u0002\u0001.\u0004\u0005\u0010K$\u0013I7)\u0001\\/\u0004~2\bւ`\u000b\bw\u0000N\u000f 9\u000fk \u0005RU\u0016<^@y?Zl\u0015\fYpq<˨l\u0012@>\u001awȃ]55̟]\"z9|\u0019>\u001diZz*vh_H\\b1\f%(b9X\u0011\u0010b\u0013Hl\u0019[\u0019;\u000fΕ\u0018\u0019GtJO\u001aU~X=\u0001Cf2LE\u00181\u00115&!2]kQ&\u001d\u001d\u001femQb\\\u0002k{l߶W=r*uQrMVQ6@WZu\u0016/\u001c\u0017s- \u001eyAg塦E@V4f\u0003?\u0011@\u0002T\u0010p\u001f\u0007b\u0019ς\nH\u0015 \u0011d\u0003Y\r\u001fw\u0017QpEe\ftxbkfC眳ɱن\b)L<愓.zE:uzy\u001aѾ6֍\rnM\u0011E<\fO,f3\bg:L#V\u0011J7ڃz3#t3ܑ\f`8a\u001bVya7Vcu R\"M\u0004LCX0\u000b5cm_ɬX۷Q;=T\u000ffP|^a{m~vΊ\u0017\u0015\u001e:Wz\rw|\u000b^\u000b\b<~\tg\u001c\u0004dI&CV\u0014f\u0002/\u001e\u001a\u0004\u001bA\u0006= :\u0002S 8\u0017$ -\u0004]\n\u000f\u001fȬy{}vm]7M\u000b\u0006']\u0013k5U><Ll7|2\u001c<:;wMwd\"x1t5t9C泣=6uh_B̓y\u0002G,faq\u0013M,#U8\u001eڮ\u001bc\u0011\fr`\u0019+ݱj4V`U\u0000V\u0007!$4Qd>>8Qc\b\"  H=?J&e\u001d\u0015Ŋ( X\u0010\u0010Eņ\u001ab]\u0004\u0004Tb\t\nR\u0014,r-\u000b,&^[f;GƬ;\u000f37B+|5!y\"KB})/\u0015Q\u0012ϼm{\u0001^egۛ߶O]\u001fnG/\u001b;-+X\u0015Ͻ.Dz.IUܖVxzYNE>\u0016ƹ\u0001E\u0005c\u0006m\u0000R`\u0006N\u0002p6\u00037\u0015;\f\u0013?\u000f\u0002\u001e\b@x\u0015D\u0015 \u0001q\u0003\u001fBN\u0007F;d=:1qz)ɷ4\u0013˦-P?20Dd˥/,lN\fۮ\u001fog\u001b\u001aS+?>+=D6fDs\u0013JqX;\u0006º%Xo!\u000f\u0006Ax?6F\u001evE36\ffRkZjG˜h\u001b-}Qw\u0010}\u0011}% y<'o%&g\u0010O\u0010/P+!:~mi\u000fgbss\u001fزO6:d;uNr嶼#ӷ|겯in8P]\u00104\u001b2\";\u001cK\u001d\rx$\u0001w;p\u0000/\u0003ǀ\u0016\u0004\u001c\u0010\\\u0002a\u0011\b@T\t n\u0001\u00139'\u001f?4iݯwժX\u0015Wޒ|\u001c\u0000\u0017\u001bc\u000f1{~¢̔\u000b?u>\u0015CѾW2eD#U2uDs3\u0001k%`X<}5YubH\u0000\u001bb@l臍X,wؕ1QnǘY3\u0016Ԇ:2gZNwP?\tF=\u0011'\u0012.#%o@}Q6\rտ\u001aO\r\u001c\u00062'Yԫv\u0011^Fl&7\u0010mKb{\u000f]Blle̲U#\u0016S\u000eGKR\u001am\r2O\u0012\u0015o\u0002_<) \ta\u0004J\u0002g#p\u00027\rx\u0007\t\u0006\b\u0004\u0005 ,\u0001-\u0010\u0001q\u0013!\b/>\u0019sm|fă\r}GmGF\r̈́R3\u0015/d\u0014,4P/v<ci=~RIQ}ClJ\u001fT}ߧއ}d\"ڷKnh&ihkN4QD{\u0014[ñA0\u0019\r}\u00173k>c̘82\u001504-si#-se\u001et7=ؾؾ\nc|\u001d=ؾ~@鶿 ?!\u0010/?؟p=wV$v[u}ag@Uo\u0002\u001f: '@S\u0018%/sv(d/\u0002r`\u0005z\u0000w'p\u0003(O\u0001\u0002\b\u0004 \u0007a1n\u0006\r ~\b9 \u001a\u0018>x넌IVrk2b\u0015Efyf\u001eݩa=\u001bSꏴV}\u000f\u0007\u0006]D\"ړ%\u001bV\"\u0018\u0012*l_\u0016b0l\u0010gc#ol\u00181N=c:1dlf6-l\u001e-s%\u0000\u0013z\u0016%w9&'o\u000bNlKl?B\r|G<E<Kl\u0011\u001fo\u001c,jZ=)xhkjr:m.+ݢoG{\u0006xy^+gx)@K\u0014\u0015?x4'\u0004\u0017\u0000{\u0019c\bd\u00027\u001dx\u001c@\u0005A.\b\u001cDU \u0007V\u0010?Q\u001fqM_uZJM\u0015D_ыl\u00103+H` \u001dXZ\u001d\u001fW52)H'~7I\u0014ѾSC25Dzخ\u0015XW\u0011X/\u0002\u001bb@l臍X;c\u0018cL\u0018S\u001b`\u0010ִ̡Ԏ927ZEw \u0013z\u0016(Ի\u0002W#y\u001c}\u0013}\u0007El?Hl?Fl?Gʦ^A,2\u001b^c&]-,tX?)lڝkrȼ縯y{ˆJ{\u0006_r,1u)@[\u00148\u001fŠ\u0011\u0002v4p\u0001'\t;\u0007x\fYg \u0007\u0004 \u000e \u0003q3\u001fA\u0011.>\u0019sm\\fC\r_SQ5eM̈́kX^(0Ddǣ/Ng-\u001c#WlCT}\u0010P'*}v\u001247\u0012m$7ihkvEGh\u000f\u0006!xf\u00006F^̬\u000bcȘ2f\fe4cAKmh\u0003-sen\u0016#EH\u001eHP_\n=O\u0006\u000eQ\u0003G߶=^_/A]E]Uc6[a&9sNqXrR/V1˩In8PM\u0010<\u001b2\";\f؋\n8q\u0004mM\u0003\u0001e\u00024A \u0004e\u0010\u0016&jA\b6\u0004QHv['dܟ^?ygS7k~85\u001ac1A\u0010!\u0014\u0005s&H\u0007\b\u0016\u0014\u0004DADP\u0014wQE\u0014\u0014\u0002\"\n\b*, `APU3ٙ\u0002ز=ɝM&ƒ\u000e?k޵\t猣+L\"\u0010\u000f\u0007x|${r5pO\u000ft>Q{#dZdۙhϖǺX/Dl\u0010\rcQ4c;\u001dxF\u0010fa7.#c5fӶ˭I\u001dp\"\u0015nT!e\u0010R!U\u0014R-F\u0003+\u0019\u0018۳\u0016%忲y1.j;ն'T\u000fmU=SUn\u0019ݓ\u001b=b_?Vg{&<X\u001a-\f\u000fC۾\u00188qM\u0006n:p\rx\u0007\u0002\u0010\u0014P\u0000 \u0006q=[@|\r$Ar\u001fG?/7\u001b\u0013sMѦYg]ô\u0017\f\u0012c*/,cL)ҹj\u0011܎w״\u001b}'2M?7wO\u001etoM͔fiiX?\u0005'1Ѿ\f\u001bѾ\u0018\u001bGa\u0013\u0010<3\u0010|1ˋbSlǵ2C\u0011\u0016\u0005)!T\n/R鏔H\u0015T\u000b*=\u0001\r&1lxBv.\\l'm\u000f~U\u0003{=v%7\u001d^wmeU\u001e꽢.x\u0007WU\u0013KCB'p\"t\u0011pb\u0012k\u0001x[\u0007 \u0007I\u0010rAX\u0006s \bf\u0010&H(1%}_\u0014?|\u0003'E{CIN>=#B\u000e{\"\u000e^k\boޑ5\u0016cO*sO\u0016eSh\"ӡ}Lw-[Wa\u0015 \u0001\u001bbLGb0l\u0012g\u0006`\u000f5k\u001evLh\b+\n%)%sI\u000b \u0015ޤ2\u0000)C*\u0002\u0016\"\u00124\f\r,Ghp5c\u00064}\u0017t\u001fca^F8^m{޷ێ_g{C\u000e>ۚ^7\u001d\n:\u001d\u000fhulqOio\\p;׳Ͼt\fi8t l,7\u001cJ\u0017\u0000'\u00068M\u0005n\u00066\u0003o\u0017\u000f\u0000\b\b\nA\u0001\u0004 \u0005q#@\u0005\u001eh΃E_ߞގo_դ^oU*%gLBf~\\4SH:^R\\\f4Xu\u001f+?\u0016;ed:eShOz~2.\u0011\u001bc\u0018l\u0014NG{(\u0011YMخ#c\rE̦H\"sH#p%\u0015H\u000f\fDPTR4\u0010\u0006\u0012*4֢L4\t=؞C<el/ \u0015\u0011O1ԶWTdVm\u0001m#kM}6{ʻ97\u001du:v8lsjqOmHh\\t;ǻ@VY8d l\u001c7|Ti$p\u0002g9pS\u000ex\u001b\u00139?\f (\u0001\b\u0015 \u0001q=:HAr\u001fG?/7Wy7&\\ˎ6Mu2\u001atS/|(rb@>U\\OXڏ{`[\b\u001f4d\u000ew\u001a+?\u00049tolftit``96X\rh_\tm{\b\u0019YEihw(sk\nYP\u0016ܚۑ\n'RF*<I/R\u0006!U\u0018RE2Ǡx4}\r\u001aZ};d7c!\u0011%slmzusMmn{-]:wf5{,o\u0017};ǧ鬿UE <@\u0012%\f\u001bϣm\u000fh\u00037\u0019\u00026\u0003!\u0010\u0014\u0018|\u0010\nD@\f\u000e\u0002=>\u001a%x8Gn}}sv--S2\u001b]O>o\u00188$R\u000e\u0011rGcMﲜָ\u0011?i近h+ڥlzZD\nl\rb\u0012&#I\u00186\t3\u00030ˇI(S\u001c\u0010I&6ܞT8\nwRE*2\u0018*\n\u0016Xh0=\u0003\re͌{ն\u001f#P.&^\u0013/*ն7^o\u001f~eg>s*n9\u0014u9u8[zǊ[r;Ƿ圿\u0000`#I0t\u0002?3N\u0004.\u0002N\u001cp\u0006Lm\u0005\u001e \u001f\u0004'@\u0005\u0014gAT\u0007&\u0010\u0006Hz@\u000fǣ9\u000f\u0016~{Bn7{;&oonYW?- 8r2V4Gx.EVv\u0005#\u0012\b\u001f4|/_<ڙ1W~13ѾCMG&T:348l\u0018\u0019h\u000f30˟vWԉ2m)햤ܖ%\u0015.Txm@\u0005H\u0015؞\u0006\u0018\u0018۳\u0016d<~e;WטtևSg\u001e1X.\u0006E\u0004GGAT\u0002b\u0003l\u0005\u0015a;\u000eE\u0001\u0001\u0000\u0002`\u0001D\u0005DI.7w}~.M4ɜw?6\u001c=9a\u001f|5oe}~/eleo?0+lȾkɫ:YkRc}5ueQW\u0017^v\r.ti:-,\f\u0018\u000b\u001c\u000e\u0010`\u0003{9pV\u0003'\u000e\t\u0005\u0003K\u0005~:3@ \u0002A6\b/\u0004D@|\u0013\r y\u0000'ù\u000f?;4*)u*J%|R\\ښQ\"r2ug~|{\u0006r8ed}|(߾\u0017/e\u0018+?}GwN`_{V)=QMJGFz\u0006k`\u0015X=\u0002O[\u00191\u0017жc]\u001f])&m\u001de`C\u0019̤X\u00142H2!,6\u001bRfOʜI;)F\u0000\bF\u0010X#PR\u0011:VX\u0019k{vԕDt%\u000f\u0014ѓmb\\\u000f>ۛ\u001e\u001b׶^{`Vhsג_ou&ۯ9/w\u0014~uNOc\u000b^(WG7E\u0014G~H\u000em<`/\u0002R\u0002\u0006n\u0001n\u0012𒁗\u00024\u0001\u0000\u0004 \bb\u0010\u0006 n\u0002aG#6~otj\u0003z{+cգ\u000b41\u0016d̕L\u000f\u0010\u0018xr\b3\t\u0013C&P\u001fc?%=ѽ\u0003}o{D{t\u000eeoRF{,V_X3\u0012ki\u000b>\u0007\u0004b\u001d?筌v\u0017H1gQ\u0006֔\u0005Eж\u001bRd)fIlI\u0003)s!\u001eHg{(j_\u0017eJWus#BNDw\n\u001b>31,??;Ozm|`Vh{RptvT:ĕ;\\qZ\\:ͷ墧\u0005/,\u001fs~\u001a\"\tQa\u0019s\u0000K\u0013\u0003u\fD\u0003a\u001f\u0003)\u0010pAp\u001e ,\u0004U\u0010]\u0007q-upv\u0013_\u001cm\u0018s5\u0013vVl)S]_Psi\u0017C\u0005<k\u0006?il6dkwf\u0000!\u0007p\u0003\rq҉tonF\u0014:Wb(<Xk\u0011fǌyX\u0000;SL\u0007j-e`I)B$eDmVl\u0016)s$e\u0013}\"\u0010)\"E\u0018j_#Qr\u0011g{<܊v\u0010]}lO'zN\u0013=Wl/R^Vۥ\u001fȿl{\u0013V\u0016&sv\u001d3GoK/w\\y)%ͯ5:8g9\"\u0015Ah.m{0À\u001d\t(\u0005N<p\u0003w\u000f\u000e\u0001\bO\r\u00021\br@X\u0000R\u0010U\u0016\u0005Os\u001f~viT/SURJBR5E\u001aї\"s\u0019tH|\u0003\u000f6r:mhnj>\u0013\u0007Ɓ><k#`\u001f{W\u001a\tɛjqRuX=\u0006kK&\u001d\u000b1#\u00143b\u001dv=+tv\f\u001bf\u0014akqv̉r/$C>Õ@\u001d+Q\u001aԹDk7ѝLt\u001f\"L<=Y\\K^Kl\r~׷\\o1+i2ϻg)n:[Gnsng\nW\u0015\u0005|1+${y?-DA\u0018^pl\b\u0005v\u0004W\u0000g\rp※\rw\u0000xO\u0007~\u0006\b \u0002a>.\u0002D7@\\\u000ff<\u0003ш͟\u001bZ?{qm⦫.\u0014h.c,\u000e9\u001f$%\\Βv'-$\r\u0000}'ys\u0007\u000f[mONܩtoSbUX#\u001aO]5#\u0016m\u0002\bsN z޽ѮB1\u001d),2IL)dD$eBYm6̞92wRH1\u001b)!|\u001e=JiZԹ\u0001unB\t~xz9Cp\u001e\u0001L\u0015{m7z@&fJ\u001a2꬏ݲ9T3+~sګNJ\u0017\u0005}aempޗ!W\u0015\u0006\u0005`\u0007AF\bÁ\f8\u0001[\u0004d\u0000?\rg@\u0007A&\b@X\u00042\u0010U\u000eA:Lx8e/69\\;n_̈́*[T7.\"ZDvXn7pg#S6MͿ\u0019]l990\u000f70O\\+}=}tRTuTRx\n\u001d+F\u0014\\5\u0017cE\u0011\u00196\u001d\u0001X\u0017y>ݙb:P3hۭ(\u0003\u000bm7\f6Sْ͒2\u0007RB=\u0007\u0003\"\u0018)Bb%#Zi{,Sھ\ru$\u0010Dwm/`=/fTgw;L[L4ߟy]gvpͬU[*\u001cb˜:/,v\r.tiq_։S\u0014g\u001a\u0018ј\u0018\u0003* 0B-}˭\u001c\"\u0005\u001a<PD\u0011xF61'# x(\b\"\b\"\u0001E7Vjޞat2Yw\u0013\u0017ڝZ\u0007Ou\u0012yQBP=\u001axqK\u0000j\u0019P)_\u000f-\u0000~\u0010f\u0004(\u0010\u0002Q!/\f$7@z\u001b k\u0006!Y\u000f\u001d\u001fq5W_M-\u001b\u000bFgF,\"\u0010;Iz\u001cuÀ̪tN3^ۇ\u000eLC?holg}f6]/\u0019'Ѿ\u0004\u001bcC&q\f6Ʀl:6\u000f\u00014ǗxѓiKgʁ&lhD֤TJ\u000fRC*ɶ`\u0016T\\B\u0018\u001e\u0017\u0004\u0015jCOY۳\u001e>#&\"&^\u001fc[vM\u000eE\u000fr;S\\q;pcG׆JW}\u0012˦+*\u000e^\u0014s6ة \u000b5;\u0015/\u0018-\u000e\"\u0007D\u0001/\u0016x@-\u0005*\u00194o\u0002\u000e\u0010\u0003!\u0010\u001e\u0003!\u000fD\u0012\u0010\u0015\b$ \u0004I5H@\u0004\u000f?nhCFَ_lM+\u001fR2~E&/0ɝ\u0014)\n\u0002r\tk#v{O{\u0003e\u001d/۴}h?\u000f\fr]&7~%[gU`\u0005kbl/'ƳI\u00146b0<=69>4vW҉bݚ&IږT8\nWRI*}Ie\u0000\u0016*\u0012j\u000ej\u0017Ũc\u0019HBQg*\num\"\u0011];=D\u0001\u000bf;ϬOh\u0003{\u001d徳+;2\u0005%\u0001\u0017\u0005\u0014XO8\u00156A\u0012#\u000e3\u0004\u001c-\u0004^\"P+J\u0005~:`\u000f\b\u0005\u0011\u0010fH\u0004<\u0010\u0003e\\\u0005M\u0005\u0003=\u001a$n\u001dk\u001ez#~Q\u001b:\u001b*ƬAbB|(E2BSOGm\u001d3g|C\u0007/G>?-}\u001b\u001b\u001bVc`\u00196\u0012\u001b&`\u0005؈9x\u00166a=\u0002I!<JsY]hKG`lBO!\u0015vTJ/R9T\u0006mP[8R@YH\u0015糶/A\u001dնC\u001bX۷\u0013\u0019\u0007cm?]25ok{\u001f}ʯ7V]m_,rj*M׽T,+]X7R@؅@n!69aFp]Q'\u0019\u0013\u0003[\u0002T\u0012Pk\u0001@\u000b\u0004\u0007Ax\u0018Y \u0012(\u0017g@\\\fr\u0000\u001d6\u0019O\u0006[d=\u001cv~#Ԍ^~Mw]ٸ.\u0018&5;m2yx4>៍۸\u001c~wl\u001b\u0003ixm;\u000f]E\u0006=\u0019'Ѿ\u0004\u001bcx\"c{\f6Ʀ،`l\u001e@[\u001c/z;mL[9Є-HښTؓ\ngRN*I\u001f\u0016l@sQ\u0002D3Emf{ն\u001fam!z\u0004\u0002V/JԶWem;նŮɾѱYxDۡj]U{V,/]T\u0017s) b` 3!vY\u0019Ǌ#>\u0015p\"!g\u0016\u0001/\u0001@\u0000=\u0000?\u0003\u0004A\t\u0013 @$\u0003Q!/\u0014$ \u0001i\u001dH@M\u001f\u001dm\u0018~?yk:믎M)[Q<a\u000b\nM͔rt!߬)nG\u001ct˫\u0017y>t`of~ޜmھן;:c\u0018chOL/\u0006x\u0002\u0013\u000b<<1\u0016\u001b&QؔM$ lOs\u0018=n4ag\rp \u0015.҃TJPնǫm_:נ4Թ\u0011um!&w\u0011oXۏ}\u001dm>mn]Rca%\u001a7=\\Zw'7/r\u0000b` 3!\u000eY冚\u0011ܡ\u0014c{4\u0017\u000fRJ\u0003&\u0000>\u0010\u001e\u00021\u0010@$\u0006Q>σ\u0004$\u0015 \u0005һ m\u0004A\u001b?μ?@?zCgcŘWV^2XZd\u0014xni̜+\u001cB\u0011~٤q\u001b+ݿJ3Z۷\u000ei7`V*\\?D\u000eV=/Vc}eKlؾ\u0000\u001b1>\u0007\u001b&LG`P<)\u0004\u0007\u0016~4ǇxЖ\u0013meG#k$i[RH*\\I'em\u000f]E(Aq}!jO@\u001dKQ\nԑ:ײ>{\u001e\u001e#$KY\u000b_\r?y[۟0V;*Y48\\NֺfָW5U律L{9`Fq`pQ`i(/L\u0016/\u0018-\u000e\"\u0007D\u0001/\u0016x\b*R\u000fv+|\u000f\u00070\fsMGڵkߵJ)\u0014\u0011ɾe˾ط\u0012ٗЂJJ(BwΙ{s逸\rsqFs1Gs=O\u001f||^\u0000\u000bO\u0002\u0019\u0010\b@p\u0016\u0017Ax\u0005D *\u0007q\u0015@\bA뇞7P{o+\u0017(\u0018\u001bw\u0015\u0019\u001d\u001b,\u0019y!S&vIG\"g<8w]W{h*zwӫhW}T5˰b\u0010h̊X+\u0014ж\u0007\tt{c=\u000fj\"\u001d펔\u0001m\re8\"hۍ)cRfNʬH\u001dH\u001e\u00115\u0012F\u0018\u0016ږؾ}+ѱCtgl?;2\u0018u]6*'=W=6/}h]|&xݾ\ne;-/qYpuV{eO\\/lo,\u001f)z\u001a\u0000%A7\u0010H\u0000l`/\u0000\u0012\u0006\u0006n\u0003^\"\u000e\u0002\u0004O\u000bt\u0010\u0007%\u0010\u0015\u0014ķA\\\u000b y:Ԇ\u000f;rw\u000fwF\u0018Ti}ʪB%h9=#SgdbЛC!\u001dNY\u001d+^\n{>hwda}tfF:jh_5b8:Xs\u0006֚CN\u0010Ǻ^XϝҧmL\u0019Q֔%EQLH\u0005)&\u0019\u0018}QK\u0000OE0$Z\u0018翳}\u0005j_ףMDzl?~xqx!^\bRW7ϺmvNCL\u001f=(Xg-I=QiaG\u001bN+Jc\\\nܧ]r1ɜ\u0012\u0007(\u000b\u0002G\u0007BZ8\u001d\u0003Y\t\u0002\u000fcO\u0001\u0001\u001b\u0004b\u0010d0\u0017D\u0005 \u000e[ \u0001\u0003<\u0019 |:hHʃaj\u001f\u001axoʔ\u0012YS,_}a\u001ekEYt\u0006SF锉m\u0017g\n{nx{JpO['7HU2Ѿ\u001c/v5\u0017ftG`0MG{ u}'5эwh\f(#\u000b0ݔY2\u001bفlv\u000bLA-H\u001eӑ|&jؾ\u0000-BmKQJ\u001ec6D\u0001l\u0010/3\u000b\u001fGm7+{dQXo]g^kîMcwag\u001bN+K\u0017\u0016.p\u000fmw,sA8@E\u00188\u00174\u0013\fia\u0004<\u0001g\u0005p\u0002w\u0013pw\u0002o\u001f\u0000?\u0019i \u0010 \u0013 \u0007Q\tA\\\u0005:4i\u0010qI9TQ;n~b\u0005c\u0017_b֌:\u001dqvBXߟoF&\u001dRmT<.=~?Qysd٫hW%\u0013*tch_m\u0018̊㣰L\u0015B\u000em{\u0000@G7&RN\u0001m\re8\")dB$eF&2[y2c;Z<\bɧ!yxsQ[l\u00187Dvs{ \u0010/RcQWQ\u0015\u000fmwӆ&Ӛf,[ܷʨ&߱;Xᰫq\rUל\\\u000b¯x\u0004yzx;\\1?k-\tP\u0013\u0006\u0007\r=\u00143=\u00178\u000b\f8M\u0000v\u0005a'\u0001\f\b \u0000\u0005\u0010^\u0006Q\u0011@\\\tZ\u0010?\u0004I@R\u001bN?\u0011U1zk҆kcV\u0015-\u0011;>LP^K\"\u0014S\u0013dg7o(mz/GGBOSKw\u0014ݶ+o5WKV`u8\u0000a\u001c<>\u0012kZӱv\b\t:X\u000bS.#e`O\u0019ZSF\u0014aF!cʘ2+RfG6;.d\u0007Z<\u0018CmoZym!c2}#c\u000fDAl\u0012/\u000fl7|#m=?1ȼ2[cRewrͥNk9/*v[\u0016\u0011t+9_⬟_]\u00148\u001f4\u0013< m\u001a#=\u0007رY\n\bmK\u0004A\u001f\u0007)\u0010p@ \u0001y\u0010恨\u0010D7@t\u000b5 \u0007ɓ\u0001§؏<\u0018vv{n\\)r||<VLVdvxT\u001fȓO\u0019%[~i^<\u0005?l_o?(Z^Pj]R1[h_/Uca_}>f,:ga\b\u0015h\u000f\u0013/&QΔ>\u001dv\u0016\u0014aJ!2!e\u0016̚lglw%=\u0016_\u0012S\u0019#Pk$jFm1QrԾ=w\u0010D\u001eۓ>޳a]\u0006Vy56o'OR\u0018yI˼B\u0019\u001eS/yzz9]!k\u0002\u0004Aù\u0003!\u0016\u000ea^j\u0000?0\fƜR*H{U;t\u0015!B.\u0012$&w$\u0014EITNI%b9e߻wΰLλ_g:gY3:\u0016?xz\"\u0012qN\u00006$\u0003'\u0015G\u0006Lీ/\u0004\u0005\u0010\u0014\u0014\u0015 \u0001Q#\rDOFd\u001fq\u0007龎Z\rkkKtV\u0015M,\u000f3'\u001e7a3\u0011\u00166SO\f*ol\u001b{$$\u001aIItc-*`\u0018CE{\u0014BپX\u0011z\u0001e{ 6݇ݍ4vm#MgfL\u0012\u0004AZ\u0010ҙԖ9\u00102\u0017BNtx9#=\fQg\u0004mJԵ\u001auš퉨{\u0007I\u001e`\u00010>Kf?\u0017+m4{Y߶?x_۟wX>bV<j}ن;iu\u000f(lZkuť%^~]\u000b}l}ϙC(p\"?h,7d8k.,\u0000R`\u0000\u001a`o\u0004N\"pv\u0001g\u001fp\u000f\u0003\u0004N\u0003/\u001b|\u0012\b\u0006\bAT\u000ff\u0010=\u0004/x~{Ӛ\u001en\u0018Z]rZRj^]~Io\u0005\u001fB\u0004&sf9}\u0006sfg`њ__C\fy\u001f{D{Dmd\"\u0015;hJG\u0006<9\u000ekګ.e{$\u0014O\rWخ\u001f\rA\u0000F<HcW؉4vSkA>AԚ\u00112Gv\u000f\u0007uӶ\"\u0002$_:#iW5J7mg'm>F\u0001F\u0011\u0017\u0019}Y\u0003l\u001d`{\u0000k_̢\u0014Z7l؝}qOSb\nUݖy+/v/8?87`(P]\u0010\r7x\u0004;\u0004r\u0004Xˁ\u001d\u000b\r\u0002\u001dI\u0001A\u001e\u0007)e\u0001\u000b\\\u0017\u0018Ax\u0013Du j\u0002}\u0010?\u0019&h\u001fz42ut1G;Pmm\u001dU\u0013kl,ZsE7pjD<Pq\u0000ԛ\u0011\u000eg,g}~Xŏ7\u001eA\u0019\u0015_QˎA]=l-wH4hLGz<y-֎:+rKE\u0012\ba}*ڃ?槈v#wvG^aLaI\"]$\b=!s\"d̓U.\u000fFyHPir\u0015C۾\u000euǣ-omga|\u0017JY>|υJۯ\u0000}-umJ\u0016\u001bA;vk\u001dRU9op)w(_\u0019PQc_ky47@O\u001c8I\u00104\u0017<\u001d2,g\u001e\u0016\u0003+\nX1^\u0007MI\u0002\u001e\u0007Q\u0003,\u0017\u0001?\u001f\u0004AX\u0006J\u0010ւ\u0011D@\u0006m#h\u000e֏W3a-\nkq%1D][|`(X`axd#Ls\f'?U\u001f{\u0019Q-\u001fE;ړ%To}Ds#\u000ek1Xex\nebE\u0006ؐv_Hcg؁4#MgfV$Ba9!\"6l6m\u001b!\":PG\u0000 |KP2Թ\u0002uҶG\tQ.\u0007\u0007~w-C\u001b^5)mn{\u0007؎_mL~ݲYj\u0016\u001bamv#\u000e{tp-w]vcUb/\"\u001fV\u0017r\r\u0001Z x8Z\u0004H`\u0002v\u001c\u0013\r8I\u0005\u0011\u0001\fX\u0017\u0000<\b\nAP\n\n\u0010V\u0001D ~\u0004_p\u001fF5=Mj_Ւ*7OZ_:9Xw%\u000bs\u0015\u001asMX5kӖ'?t?Quk\u0015?^zh\u0006}T|Q$xhWK念}d\u0016f\u0002ڀ')]vH<p \u0018\u001b\u0004i>ȓNE\u0013iBnKZfL\u0012\u0004AZ\u0012ҙԖ9\u00102gBNtx#H>\u0017Ð|\u0011\\:Pg4mZԵ}\u0014Fo*mQF\t\u0018}lyJۯnwmGom;lhhc|hUj}Ft6TZo;P鲺5«AW.Z<Cq0p\u0002?x\f'\u000bV(,\u0004V\u0004\u0016I\u0004.\u0003a\u0000^\u0006\u0003~.\b.\n\bAx\u000bDu j\u0002}\u0010\u000f\u0013\u000fg=\u001a::c\u000e}r{Ϊ[ohėi-YY45@?<`xz\u0010ԇp&\u001c3-lO1X7=P\u000f~쥇FEz\u000fپ_a\"wI4$\u0012%%Xmbh\u001buhl_°>\u0015A\u001fO\u001d\u001byƔ펤=ijC$\u00193\u0019IH\t\u001d!s$d.̃}\u000e\bBPp\u0019k%Z}\u0013m{\u0012K~{\u0000J\u000b,`?m̢1C3)wmYv\u0019\rhwrTka>0lQc[#\bR\u0015/pߗ.\bHｈ \r{F,,\u001a\u0014\t^H\u0011\u0014\u0002R\\DV Jfg\\.آfVGƙ-$qf/8g|#/y^)vcSkZ\u0018`\u00178\u000eR\u0017\u0005O\u0014ARE\u0003/\u001e@m\u0002*\u0005{\u0000\u0004GAp\u0012_0\u001bD|\u0010<+\u0006:Ѝ \rv\u0007g\u0014uLvǸ̻N:vk>Syuj\rUZ:q\u0017\u0017\u0019,3\f\u0015s\u0005&9S3ֿt]\u001bÏO>SA\u001f\u0018/\u000f!\u000f+]8SѮF;kZ\u0006G{,҉FQh\u000bG\u0006AJ\r}Yۙy\fǅnmb\fA2fv\u001b\u001eJ=>_/P`ۗ\u0012(?\u0006۾\u0006۞D<Jƶ \u001e\u0019=O3Yg9K\u0007m/7޵ۮ`m۲[\u000eһ6ymT?ٟlr8ri_k.IQ<*ʽ]K}l}\n9:ɂ1T(.\u0006r\u0001\bF\u00017SA\u0006/Ax\u001a@D\u0006Q\u0011@|\t@\u0004I\u000bH\u000b=#\u0005ݣs:Ǟi\u001fqg≖iMSS\\SV3s%͵\u0015ګJuW\u0014/+H\t\u0012\u001a{S\\oȅgmO.lyՇtT\u000f=yO>hO}\u001b3D\u00164k#\\}5ҎC1HeJ\u0017!\u0010d\u0010#C\u001fdcݙ1bm_\u00180&l)m7'{^[R@ʝH\u001b)¶\u0007b\tE\u0004ѿ\u001c\u001eG\f$\u0010\u0003눁\rmģ\u001f>9m>=m\u000f^\u001flo2yml7添-껬tX[Zӛ\u001cn:~^reC+n/yWzWx؝5/7\u000fԓ\u0006\u0014\u0007O\u0011BG\u0003/\u0012xK\u0000*\t-\t?\u0002\u0013 \u0000Y\u0010H\f\u0002\u0010_\u0000q%е@ׁ\u0019$w@\t҇#D\u000fG>ɺ7tۄnO:\rPOZ#rvBNl^dbaȏ!ϙgZZg|+#|7U{x*J\u001b[/3\u000f!ڏ\u000e\u000eF.\u001c[e\u001ah\u0016\u001bV\u0002\niD+.k{\u0004[h\u000fFsXhG\u001e\f݉1rPF|nʐ$cm_@\u0017rgRNy\u0013}~D_\u0010\b#\u0014\t2l{,\u001f37\u0013+m\u0010\u0017zv[۟(m|o=xc{]V5\u001d6\u0005m\u0005ZE:\u001dם7]u]s-Jπ\no2\u001fE~\u0001ҠYtTa8>k\"-\u0003^\fV\u0003\u001e\u0001}?\u0004 H\u0007a&\b\u0001\u0010D .\u0001q\u0005@\u0000\t$ \u0007n{FQdwͼizc\u001cnlڮkӷ^XX\u001dA/X?\"n\u0018\tdӝGe\u000eg-l>tuk\u0015a戮W\u000f]\u0015\u0007\u001edjl)\u001dG&\"5H;\u001ei\"h\u001bvpd\u001e\u0004<wp\u001c\u0019#{&\fBi)kI'{H#)w!\u001ev/\u0018۾\u0004\u001eM$W\u0011\u0003ģ-]T\u0013\u000eڞ&/j7߃\rcmeYi]nSg[a\u0016fc\rN;\t5n1=Ty\u0006Vxy8Z\u0017q\u000b\u0002\ft4Q\u0004~H^\u0018F\u0000o\u0005Z\u0007T2P)\u000b\u0003 8\n \u001a @$\u0005Q1ˁ\f5\u001b@\u0002 \u0002iHAαggܙperZz=շH<kEե1#\u000b\f¥Eƾ\u0014=p2˴\u0018]L+\u000fc^`j9\u0016deh-CMY\u0019V\"\u001ai)]eJ\u0017!\u0010dF?2A<7p\u00162v\rcbp\u0019d^+׆ǶrOχ\u000b/¶G\u0012+\u000f}=1\t۞m}|\u0000~\u0014۞}zZillƶ\u0017aMW\u001blöm=\";v7.<PsU\u001aj*N%Ȃy uQDAhK\u0017\r8\u0012\b6\u0001~*\b@%\bO0\u000b<\u0010 *\u0004q)\u0005\u001e$@\u0006N>\u001c!z8Iֽq&|u{)\u0007\u001bvjJr%zQE\u0006K\fCŜ\u0000W.mpb\u0007|Ua؇T\u000e_Ezc\u0010\u000f9\u0004\u000f\u000ehߋ=vF2܀!\u00044Hg\u0005em@z>\u001bh\u000ek\u001f2F\u001e\fǕ81F\u000e\u0002x>cb\u0010f\fI2d5kK\u001dH\u0013)w#^d/\u0017H(B\bE8XJ(\u0018ljb`-1mߊm'Ucq60̌Db&K~Q\"\"KK!\fƵD+J$J%rsά9i2\u0019\u0016<Ya0\u0017~k~^=HPc2}Glۻl;\u0003/moE_oU2)jhN^H<Tc&+\u001db;Fs\u000e-v\r<q>,,_\u000eJ\u000f\u0017\u0005\f\"\u0002!3\u0004\u0004 \u0004A4\u0010KX\u0005x\u0010&0\u0019DA\u001fĩ \u0004\u00042\u0007$'Ar\u0006 \b+@\u0003\f; ;h\u001dt/\u000fU3b[7*UW-V)D\u0015hDj\u0004Q\\?\u0007ma>\"ݷT=|ܫɮٷ?֔ ٵ\u001byw>r;\u001d\u0014>yK\u0014>n\u0001amCOEk)]3fmu|艞\u001b3ə:0\\[Fϊ7gM\u0019Cv#<s\nimp=.wF{!\u0003\u0010{\u0006v&}.ֳ\u0000Yw9}-ֻ\u0001پ\u0015پMWl/3xT&~^dmok&su:5V{mUmhayǹÊ]\u0016yvw,04>A\u0010\u0005\f&\u0002e\u0006 \f\u0004s@\u0000%@\u0004Z\u0010n\u0002a\u0012vh\u001fS@\u000e\b, @R\b\u0012\u001a:@v\u001bdw\f̸58\u0007\u000f];|Ǖ6Wl\u0018\u0015Ǧ{\u000bNi\f;\u001d\"\ry\t\r\\21FV|S{?+>\u001d\u0007\u0012_gOōr\u001dG{<Uh\u001f<\u0017h\\\u0013AO`=TaV\u0010\u001d@kMzк$'kpm\u0018}K\u0006&!p\b#-q-.w.x;uaS9yXO4})}5ֻ\u000eٞlߎlߋl?lO7\u0017+\u0017*l;l[m6ޕV~-SN6S\r\u0016u)*M\u001d\\pw)5ͻݹ2ϓw[?WK7V8`=\b2g \u0002\u0004Q@,\u0002b9\u0010q \b­ \t@|\u0018G$<\u0001S )\u0006i\u0019H/\u0001U\u0003T\u0003P- kG\u000f\u0010,yȡ{Y3\"ȄJueWS[zvӜyNhMϞ8U\u0015\u000b0t\b[lؼ\u001f\u0012G]\u001cSdQO\u001b}Cu\u001dc֠h_F(}h5i\u0019f\bF?EӺ.\fב1z\u0016\u0019cg\f\u0015O;MN3\nl|.;\b랆lݏD/|i\nw\u0007\u001b\r\u0015'!ۿU\u0000=5s\r*@\u0017bed{{d\u0017OnqS\u001bj+Ea{~BPgzjour-k\n\u0017\u001c:,v\t.r)tw9a?e-U$\u0003\n\u0003\u000bBt\u0010\u0002< bX\u0006\u001a\u0010n\u0000f\u0010m\u0007\u001e\u0010\u001f\u0004q\u001a\u0005@J\u0001I>H@z\u001e@]\u0005\u001ef\u0001\u0001Dc7\u00074}~خk#N|c\u00159É*И\u0015\u001d,Oy\u0012.\u0019lOJ\u001ePk>rj[W==\u0019E{b*\u001b;ƬP[ݡ\u001e\u001bK/F>氶Ϧ'̢5P\u0007ڬ~\u000f=ѓuc&9#m\u0019=kEOa\f\f6q\u00184;q5.N\u0015T\u001dlua#\u0014D!\u0017c=XJd{<}3}\u0007;d{\n=\u0003N\"s^5ۛ?V\u0016fS\u0006\u000b5}WW&TU8Ė9.(u(q\t)r-ts=a{\u0017㣓;NB\u0006\f\u0013\u0005\u000eT>\r\u00043A0\u0017@,\u0005b\u0015\bA\bd\u0010\u0006~\u00108\u0003H1 9\tB\u0003i\u0005H\u0003\u0006nnѝ\u0019\u0006{jՖ\u001b+F]\u0018DmIѸ\u0013\"Oj\u001fמ\u001b(\f\u00041:gӽR`or_쳟U;$\u0011;\u0014ѮC5cF\u0014qlw-GѾ\u001e\u0017M94f(9\n\u0003hm_ZǛ@;1\\\u0007Fv\u0003SƐ`F\u0011)x\u0005.\u0019]^X/=\u0018랁ucg#c=1e8d&d6dndAdQd\u0015>\u000b_loiv޵;\u0016\u0005Mf\rz˴ZWw\\M[[a1\u0012g]θr42P~pQ \"\u00102C@\u0010\u000eH\u0010D\u0003\u0004 \\\u000bM L\u0002.\u0010\u0003q\n\u0001)\u0004R\u0006d.HN\u0004e \u0002\u001aP@\u001f>@p!\u001arg͈$Tė*U=3/_#\"W+4G'=\bCt.me\n\u0013;u'O(|m}\u001e??SUw\u001a'5uE\u0011΅sw]tP\u0011\u000b*\b\u0005\u0014\u001b*.\u0015co\bߋ(ҔtQ BPC\\|ϽlvfFތfnt\u000f|y;m\u0016{qb]e'9\u001bj\"RK@jq8ڗ#Mň\u0010\"6\u001dAH#}\u001fI\u0019B\u0019ѶSl\u001bؒ21\b]fm'Nܕ߇`l\u000f$\u0006B\bhl\nb(\u0018ZC\f%b7aw`m?m?m?mQ؞e*l{\u0003\u001fn֊m*dl\u0017ܳpPӞ\u0006m.\u001boW-Xx+۷ǥ׶ϴ0%\rT\u0016\u0007M\u0013\u0004O|\u0013\u000eE]\u0006X\u0005^\u0012\u0000'Ap\u0010\u0004_\u0014\b/\u0007\"\t\n@|\rAR\u0003z\u001d]\u0018$x\u000f?p\u0017'\u001f;5yzZRj̔j\u0015s֔\u0016k-*Љ\u000f\u0016\u001br\b\u000bs\u001dΚ[ض\u001fih\u0018c\u001b\u0013\u001ey1\\ھwھ/};M}*Ih\u000e\u001dkZ<RE\u001a+2\u0004iE!\u0002\u001dth\u0003n\u0000c]߃2mw\u001c)\u001dŶ-(ݔY2[Rmw#d/O\u0007\u0011\u0003EuFlVb8q7c2So.ƶ\u0017`ۋ_mv\u0013m?ִ[\u0007\u001e˪.N\u000eV-\u000e\u001b׹$tMv\u0015ZWv׮Ϭ(\rT\u0011\u0007M\u0017\u0006OӶAB.\u0005*%\u0000o\u0003R\n= \u000fL\u0010\u0004y\u0010H\u0004|\u0010_\u0005q\u0019H@R\u0007 mS\u0018r\u001fS\u0013uN<դ)\u0007Z8cW\u001aJr\u0012\u0015E\u000bB%\u001c!ۇk~t:ofwc{ju'\u0010>wml}#tc%c~\u001c{p)o뛝D\n\u001dpF꫐F\fҠ=\u001a\u0016!V$\u000eC:Ht/c;eJ\u0019:QF\u000e\u0014ۖb[Q&s)I\u0015cܑ;rwRE\u0011\u00010b \u0018\"\u0006`W\u0012C\nۓ6Clw\u0016]m\u0015owm{ȼǲ۪ӦVm?uH󼽍Ωu.ɷ\\TX|+ۿ㚯\u0015?\u0000\\$h(x\u0012?d\u001c7\u0014r\u0016\u0000w\tpW\u0002/\u001ex끷\u0019ہ\u0006\f\u0010\u001c\u0001q\u0010\u0005a6 \u0004+ .\u0005I\u0005Hn\t \u0000א'oq{>?/;&}6i{V֬MUPM(XuMkivTNxAȏoM~꣤~\u0002f\u001f6\u001b\u001eA\u001f-̢E{:\u0013h7{kf\u001c*v8\u0012i,Ѿ\u0018\u0016\"V\u0004Ҧ=\br\u001em\u000f\fhw\fQl{vcKĜ}.ݚّy܅{rol;\u0018\bƶ//%\u0006cU\ncS\u0014acۏ*l?mb%l\u0007M{\u0015w۪Mab\u001bc{f};]6rMq[Y\u001e}3+ǳ&\u0001\u001c5I(x d<c{$p\u001b\u0003[\u0007do\u0003n\u0005!\u0010\u001c\u0003i\u0010f\u0007\").\u00187@R\u0003\u0006\u001d]\u0018$x\u000f?p\u0017'\u001f;5=\rJ3S*T֖\u0015k\\e-.Љ\u0017\"1\f\u0010{\u00169wCՋ\u0017/F}\u001eOK۟=(x#ڕhݧ\u0013G\u0016:T69talWE\u001a+2\u0019\u0010k\u0001\u000eG:H7\u0000ю=)CvgȑbQl\u001b؂21\b2%e\u0016̆ٓr'RCǶ\u0010\u0003Bb`11\f\u001eK\f%\u0010Ck\rp2};N\u0013\nOfPaejo{dcQmYJ.4=yWKJ\u001a*%\u0015\u0011^Rob_~֗\u0001z8y!\u0013\u0001(.\u0007n\u001c\u0012\u0004\tt\u0010\u001c\u0000Q\u0010\u0002\u0005\u0010rA$\u0006Q>@\\\u000ejԁ6H\u0013r\u001fS\u0013uN<դ)\u0007Z7Urrʺ\u001a+XK\n\u0017I\r\u0002l_G6|ԞN\u0013\u001fE##\nG`\u001fh83Z~M)ehO뛵vўl@H-\u0001Ft H+\u001a\u0016!V$\u000eC:Hthm\f<(CWЉ2r`mMXP)E\u0019)$e\u0001F=D 1\u0010J\fD0\u000fF+lö'*lߢ}\u000f+:k)l/y~\u000f~?{ݴ\u0019ov[Ӷ߷ٟp1iwZ7ܗVxF^\n,.q.)[op)\r/\u0014Eq5.&D\u0011\u00182t#9Ga`\u0010P\u0001\u0005\u0003*\u0010ń\u0001\u0015\u0014azR\b\bHPH\u0010%\u0018\u0011pe\fNνY=K=ryWC\u0014aa#\"\u001b\u00058\u0003\u0012um\u00026\u0004~:\u000f\b\bA\u0007B!\bAT\u0002\nk\u0000\u0007\nA\t{ y8B={̉_\u001ek\u00132w7OL49~jJ+i/+Ս+fD\u0017GJ8\" O\u001ecei+̇\u0019Z5^M><J?=ܔdʫhd\u001ae'hJ\u001eZTS/\"t\u0016\u00121\u0004c>=0`\u0013~\u000fi<4q'M\\Hv3\u001beI\"r-Qv3*smA{`7}.\u0017E۾\b_\f@\u0006Vm\u001f\\\fnmOEe\rd\rmzz8\u0013{lmoH{c{\u001bݖʹ핷mK:%\u001d\u000ekYW\u000e8ӶonpO\\Q;{QJ\u001f9_r?E\u0001\nL\fI(\u001b\u0001g,/l$7\u001c\u00037\u0016K\u0001K\u0004l-`)K\u0005^\u001a\u0000\u001f\b\u000e8\bN\u000f ,\u0002Q9\u0000\u0003\tm \u0000\u001dt\u00033\n\"ZV7uz75M0eEjV,)a,87/p\u000en\u00160t?#e?]>e/[\u001f?\u0016{ɴhפ}\rxB{<uh&\u0018\b\b\u0010 0\f0&M<I\u00137v5ɲ \u00114GV\u0016:2\u0017Tf2_7@n{\u001f\u0007\u000bmF\u0017Ҷ/UؾFaf\u001d\n*lϤm?z;l?\nҶWҶ_|nyc],Xtt[tYӶmǮ;hw:\u0015״&-\r<\u0012j=\u0017xEU\r(,w(\n(\fb$!I\u00028^(\u001cț\u0007܅]\u0002X\u0002`k\u0000[\u000f-\u0001\u0000!\u0010\u001c\u0003A\u000e\b1\u0010 ,\u0004Q)*\u0001\u0005\u0012- \u000e[ \u0002qHѹwղo\u0018w}V]W&hn\u000bk+g$ThǗ\u0016E\u0015GH9B@w.q)6M/Z5^Mٷz/n_~oFT%f&\u0012\tL*\u0017\u0013:.e{\u0014K\u0013\u001cBM\u0018P\u001e@N\u001a{Ѷ$ӁdڒfV$kYv\u00112\u000fTE\u001ei#yH_\f\u001f/F㑁\u0004`\n2\u0005\u00196l=\n\u000fѶgaPa{\u0011m{m\u0018V\rov[vY5ܳm?aϣm?qugF:Z%5^U>s\u0006y;\u0015\u0007X\t4\u000f֗Bx~hn\u0018E\u00027\u0006\u001cՀ%\u0003o3\u0003o\u0017\u0000Ap\u0014\u0004'@\u0005\b\u0005 *\u00019k\u0000o\u0000\u0019 \u0004}<\u001c!\u001eŽ?/\t\u0019m껛'5MNVc]Uf./YT̈)ԟ{0\f7\t3l*ݳ-\u001ct/mW=e}j>e?{>n$B+Цl#t\u0016\u00121hgD\u001eJ\u0018\tCvȇ4M&.\u0013ɴ'6$ˊDf(JZRkTjJh=Q7m\u000fAHo>m{e\u001b\u0015v)l?@~Ta{\u001e\u0019Oa{\u0001m{\u001fm~.{wlJ;;\u001dN;e:kv达ce\u001a*\u0015~e.%\u00016g\u0002Y\u00053)Я1X؈\bF\u00037\u000e\u0000[\u0005:6\u0001o\u001bv\u0002?\u001dAp\u0004\u0004 \u0005\u0000 ,\u0006Q9Հ\u0001~\u0019m \u0000]t{Fa]_Q\u001c{_iI\u001bl\\R+\\{YB*\r!Bf\u0000EOr:nthe葲\u000f\u001dSO)\u001bދ_6?\bOGv,CE{v\b\u0010 0\f0&=mg:m7&Y$bN%*A\u000e\u0019ѶHo\u0010\u001b͡mB\u0017(l_\f$Ҷ'!i۷\"CYöfж\u001f\u001eY\u001bK޶|?e#·r/ݳcSvˮ=1iݶ5{\u0019a*>\n_2ג\u0000ۢ@ 4[[\u001c!\nUs䶇C^\u0014pc\u001b\u000fX\"`I\u0000/\u0015x\u0001o\u000f0\b\u0014\by \f@T\u0005E/\u0015A|\u001b$] \u00190:Z\u001d\u000e\\U+\u0013w\\n\u000bӒf$Vh/+Ս+fD\u0017GJ8\" o\u001e♃d[\u001f}1\u0007RccT{ǔ\u0016؋V_IH#t)\u0013^8!ل\u0001\u0015\u0001\u0017iBF:L\u0007iGY,\u000b\u0012A)ۥVԖ?WTw\u001aǒ\u0018DkE^zGz\u0019@\u0015\u000b\u0016, v,{C\u0006\u0004\u0004{̝{\u0007)w\u0014E5gx3\f 5gXY]jsf|^YIm1\u0003&uP\u0007gR$[}\u0003\t@7\u0018l߇\u000e*l?{y2J\u0014*ll/lT)]n{~\u0001\u0006lo4^84L~s6m\u000f,R<+%os4M/iV,k{g$;\u0014\u001f\u000fp7\u0001\u0011\u0004N \u0001y\b\u0013@\u0003A\u0018\b0\u0012@\u0011@@%..\u0000\f\u0001\fv\u0010?\u001dB=\u0019\u001eEdӗG=\u001c{\u0015\u001aGK'\u001e(7o\u0019\u0019ޘ6{m\tZB\u001dׁ6ѳ24}{h\\E_ZZ~Tm'U/X~ϕp֟{ڽyv\u001fݵKә]jٱZ֬i1ay,ғۮI0)&֘\u000e:rnO$Qؾ\u001asozg{\u001e%ۏs_|kpޫH%\u0005\tIﳽmv\u0018Vml1Mn2\u001aoYD>6m\u000f*\u000f,pX2;˅j⦟X;sk\u001a=A3\u001d/\u0005<\u0000@ v\u0000\u0011\u0002d(ǀ<\u0003 \n\u001b \u0001!\u000e\u0014\u0005T\"@\tt\u001e%@W\u0002S\u0003L\u00130m ~2Dt\u0018[FD7\fo\u0018}v\u0007NWN8^\u0011Z49$ΜA37ߝ.eΪ;s\u0017PBxd\u0017k\u0015m`u_\\:u9U\u000fW{S:]<wi4\u0005\u0003O-ձ۾И]0V\u001f\u0018c\u00123LbnIn>zk/-CH\u0006C=\u001bQf\u001bپSa{(;~ZkJsӃmzlO+^nTfbd&j0zhyUnrRA\u000e\u001b\u001dr}\\2\\S\f\u0016$z\u0015{N5(\u0002//\u0007|\r\u001b\u0000\nv \u0002q\u0010ȣ@\u0006\u0005\u0010\\\u0001a8\bA\u0018\u0007\u0000\u0004R@\u0001\\\u0000\u001az`ZA\u0001ӡd\u00117[FF4Zեg>Qqd)s\u0005gؒ>kC5IsW$<\u0004:|p\u001bѷܴ'&OI{URb~7o꺣NRVӑ\u001a݆\u001eݜ1e\u0017\u001a<\u0003\u0018knI0vWԽ\u0018u{!\u0012$[d~]o/ۏ\u000e\txWlQ.\u001cl{%\n۫?\u001fa{'g{;g{]EmFY&fty|Et\u0007V\u0017OmSl\u0017Th1qul\u0017\f=WT7dw\u001dyb\u0019D{swH2W\u0001\u001e@\u0004\u0003\u001b\u0003@\u001e\u0001\u0014Ap\u0019߂0\n\"bJ\u0002=\u0010\u0000]\bt\u0019\u000f\u0003\u0019 ~:z2\u001co<Ȧ/׏\u000e\u0019sS\u0015\u001aGK'\u001e,7o?\u0005f\f;?e_⼥\u0002/Jۍ^\u0013u\r/mxެV]?:UO\u0003)y^Þzi1a\u0017\u001a<}\u0016a\u001e&1$&0-&uX\u001b@\nW\n۷mw;g{\b;d\u0019^y%#x8x?\u0011J'\u0005\u001fg\u000f|\u001dJW\u001b\u000e؞jl4u\u00167k,?Xe}Pbm\u0001K]<2N鮋܌\u001d\u000f\u0004ϙ$X\bK!\u000fuo\u0002\"\b]@\u00030'<\u00070\u0010\\\u0003a$\bcA\u0003%\u0002\u000e@\u0005t>%@W\u0001S\u000bL\u00130m \u001c\"\u001cF<֣\u0011#\u001bF]\u001dszܙ\t4\u000e\u0015O\nɟ+g̙Z:g\u001dM?zWĽ\u001fZ_>שNM\u001bpoJ\u0013m\t3d\u001eq\u001ba\u0012SLbI1\u001d&uĤ.HdKl\r'\u0000nl߁zw1˓J뿮=v퉃mSjm폞s\u0017\u0019p\u001b͉zZo\u001fXUY9\\f\u001bRb\u0017\\h)qMӲlgL\u0017tW47\u0014w$\u0005\t\u0018)\"qBP|\u0003\u001e\u0000x \u0010;\b\u00012\u0014@\u0001E\u0010\\\u0005a\u0004\bc@\u0018\u000f\u0014\u0005T\"P \u0000:\u000fb+y\bL\u00030 \u0000Pcx\\ۈ-##\u001aG]ñg>Yqd){mϚ57,ETA[ézzO\u001f՛~/\ftY\u0003LbI0v'ݕl_dQ?g&\u001bz\u0015C}\u0007Qa%/\u0014ཊVf\u0006۞d{\u001d}\n6%4\u0016VTL8\u0018nVd'1glI\u0017(U\u0019\fe\u0006Bb-\"\u0016Y\u0001E\r6[Ν\u000e]Бޤ7CSP\u00028ZPw3\u0007\\L%q'X<lU$\u0015\u000b\u0013lU T)ma*!-\u0000GV\u0000\u0006o\u0007|\u000f.@\u0001q\f@z\u0002.\u000f(\u0012()P \u0004q,I@\u0003\r\u0002\n\u0013w~S{i\u001eyOehGn3\\x\u0017&פU<Ȭ|y\u001e:uo>W5\u0014޸ ƚ,VΈh\u0000U\bQ\"T\u0004U,GWkhaw*\u001fF:\"'m@\"]UlGz1G؞:M\r\u001bTl*ΪIЍ\u001b=X,4\u0018bg\u0013,tS\u0014$ΆDU\u00161V(.;\u001fj\u0015lu \u000b3ca\u001a)\t1`\u0000s\u0002l\u0003[\u0001\r> \u000e\u0001q\u0014S@z\u0000\rK \u0005\n\u0007\u0006*\u0018 \u0001:\u0011T@\u000f\u0012Tnn\"^=ɷ|[](\u0007\u001cu:yukru+ӟeczwcza/U\u0015H\u001cZ,jC6{T\u0000U,\u001e}\u001dO*C#DG~\u0005\u001dc{(\u001bbi\u0007_l{lWV;Z'R7|n-Ƕ\u001b~;dLt}ɜMf-Z:XYGq9\u0011<CvFݗRLZ0N:Lƅ\u0013\u0017\u0001\u0014U\u0007|\u000b;\u0001w\u0006 \u0010G8\t\u0019 ρ\u0007D@\u0001%\u0006*\ba \u0006:\u001ed3A\u000b\"\u0006$\u00105^7.,קN\\}{|1ޜ:u^۸ː&Ǵ];޸7dBT*+Fl߀vlA;\u001d;Q\u0011]#HQw_@}.E\u001e\u0006\u001eћ0<+Jjsu*uF\u0005\n\rmʚjvTdfS8\u00051V6Q\\\bZ7\u0006\tk\u0000s\u0013}aʐ\u000b\t`+\u0001[\u0007fw\u0000-\u00108\fq ݁<\u000b \u0002\"D@\u0005\u0000\u0015\n(\u0010\u0001\u0004t:Hr@R\bRV͔\u0015.O&j\u0015QJczg1\u0010ӳ{h;\rE;6ؾ\u000bU~*\u0003m't\u001bc;G\u001el}/iT؞[^P>7T/D*2+05:;dɑtTrΚ\u0004eq\u000boXFs-\"yìh\u0006=gOb\u000fD\u000e\u0011wAۿ\u0001l\u0005`k\u0001\u0004v\u0000\u0002\u001b\u0010ǀ<\r'΃2\"\u0000\u0015\u0002\b\u0010\u0000Z\u000etdNB։f雿bL/L:&\u001b@ՃbzR7x-ױ\u0015>N7;8ujW\u001e?\u0007\u001bm\f\u0018m{ګ|\u001b~N;oѥz!%\"\u0005e\u001bi]:@d\u00169gm8E7,<0kP\bϒ\n>\u0015(rJ\b'b\u000b\u00119\u0001\u0011m\u0006|\u001f\u0010@\u001c\u0005\u0014\u001e@z\u0007D@@@\u0005M\u0006D/\u001b˚[kԩ{+{\u0019ޗObz@|8'\tOno9Vʃ#Ot_D/F\u001e\u0006 \u000f؞4d{Ym{Ӱ퍃~bakt2t\u0015CE\u0006X<#lc&G3X\u0007L9\u0012WY\fΏysm\n!\u0015|FL9L#p!/\u0006l\u0019`\u0001[\u000f\u0016w\u0001\fA \u0000q\u00123@\u00033\u0002.\u0005\u0016\u000644ɚ2}7\u0010cRmi\u0010__\u001bWԟ\u0016q\u00032y_^\"\u001e:]3Hhۯ#=8#z\r\u001bi{ǳmb{iv~N1ed%\u0006x<gn\u001c`\u001dJ3ݛޖYh21R\u0010cōy\u0006Z_\u0007\"Ϥ\u00053(d\\8\u0011`K\u0001[\u0005:7\u0003\u0003@\u001cFj{9e\u0004{W6˚~`Vo,Nە폟O\u0007I\u0003UG epV\u0015kϵ=NmW9ök==BFټ[A\u000b\r\u001b]1ir\"fޑ٘h*XK\u0018+^\u0014\u00133Yh\u0004}\u0019\u0016|BٿO:L\u0019}!/\u0001l\f\u0006pi~^I!e\nczCԽu\u0002\u0006?\tڣG\u001e\\W܋^c2Pa\b\u001b\u001b\u001br׿g/i\u0015h߬Q(4ot13kL[Td&SŒXKaM\u0014<g,\rA\u0016%\u0011 fn[\n8֋P\f\u001f\u0015\u0015cH\"!I%ݨY7 A`9A;qkޢnJtî6lnss)2)ssv~\u001f7pr\nr[Ov\u0018+\u0006\u001b-@dC_&B/\u0010J{9<$\u001b\b\tKi8ZCc|\u001foΈ#>\u001ak]\f\u0011Cۭ#;_\fz>mvmϯ,woiwμ\u000b},O\u001f(l;x)skeC5M\u0013}m~-&\u000ezukͰ/\u001dC|%<omVIX<\b:o\u001dUtizmw\u000fO_v\u0004k}kStH_m45<e\u001b`N-vv0]Qpɣg;֯m{\u0006D/V{Cv1R\u0018nrOa+ia>^nՉ\u0006Ѡr惖H@994ۺx\u0002fg\u001a{_M^QNwG9/f.U:&\u000eר\u0017zc4 ְo\u0012[P!RDuvuPu\\\u0004#u!ҌڍJSnR+bkvѝm\f<fKO)\u0014Zy@/\n\u001eaן\u001bzxB3\u0011\u0003\u00046\u0012jЅ A,\u0011\u0003:\u0018v\t%C\b=D\u00147\u0010\u001ez\u0006h\u0013\u0003C8\"J(trhs狈\u0011xBO\u0013\u0011\u000e:Kq!\"\r@b\u0014\"*th9D\u0010QRA'MOD\u000f9@3\u0011\u001a:I\u0005DD+@Q{/FDnp\u0011M\u000f]DC7\u0011\u0011\f:E\"\"@\u0007{9}\u0010\u0011\u0011sMDDDI\u0000\u0003\u0000\u0007Y\rendstream\rendobj\r136 0 obj\r[/ICCBased 148 0 R]\rendobj\r147 0 obj\r<</BitsPerComponent 8/ColorSpace/DeviceGray/DecodeParms<</BitsPerComponent 4/Colors 1/Columns 500>>/Filter/FlateDecode/Height 500/Intent/RelativeColorimetric/Length 13535/Name/X/Subtype/Image/Type/XObject/Width 500>>stream\r\nHytTW\u001d3\u0010HBYb\u0014K)Bs\f\b\u0002Z\u0016!R\u0011E\u0015J=\u00068\b\u00148X\u00168\u0001KV*m9\u0014PAFTT2k&m\f,,,L&<\u000446y}7}~g\u0011S|o\u001dh-r\u001b\bw5_û^ɲ'GAʡa9m{s\u0000oMGn_X9\u0004L}R\u0019 Q\u000f5,v\u001f4\u001c4>lR!\\h\u000b3BOsPei7[%@ȹG#i\u001f8\u0004t\rb\fKݭRA=<Y\u0007;\u0012z%~ɾln\\@O\u001fy\fN\u000b{\u000b~+\u000e:\bbs?YD\u0002\u0003f\u0017@MžЙ5SP\u000f-/m'\rN&L[z\u0015Z\u00183\u000e'N=\u001e\u0014pq<gB\u0014Fhf\u001f\u000e-/m\u001b\bUx0v\u0015hԦO+\u0019z\u000b푌\u001f@\u0016$mwB+C\u001bS\u000bQ\u0006.9'\u0017A8B]h>4\u0019:b\u0010{\u0005\u001a CA+,кXao\u0018<Ѹ=\u0001:`g䫍ЖXӹ~Tq\u0007H=p0ˤ\u00197Z[[;JI-b9;'A'\u001b$sͺne]'x;+.{\u0000:`$a\u000f\u001fY]˙zݶN\u0012tƈژD+5f1;\bV2䳺\u000fN9\u0018fL}eFs.1\u001aJ|z}\u0014tBܦ\u00064s2:襠p\u0015dR?}:wC\u001d\fh˱\u0010he\u0011(ӛ)m}y\u0010t̲$ؕcP=nv\u0017Ag\u000e˸\u0014\u001cЄ/\u001f_&C\u000eG/e? sM7(Rg\r]=oCg\u000f3N\u0019MT++|\u00166\u001fG3f\u0001Ûkjw\u0006fလ\\Ƭ \u0012_zrL^\u0013O%B[Pr$,\u001e#U\u001e#񄌀nʸJ5ZWe\\\t.TMx\u0014/u*Qlt\u0013_4\u0010Z\n<p8k\u0006ci7\u0011_3\u0015ڈ\f@\u0005O3J.+|V\u0014%J\u0018H\npW=\u0006E94i\u000f&'d\u00101]#3\u001aڍB$'Ka\t]\u0010<\b96\u000b,\u0013(\"w-\u001bajFGc\u0015\u001fľEr\u0012\u0013J\t#\u000eBD\u0005hGI\u0013L/d;THN'-D`\u001c\u0007i53I` hS\u0018} \u0012`\n+C-AhWz\u0015\u000e\u001bqAOi6ږTh[Lxу=qmfȾ!a/\rZ\u0003-?bۢ\u0013h(\u00100⿨vFx}ͧo\u0015gЅ.OFż\u0006Am_R\u0019holcNY)3ȐV@4;\f;9b\u00110bԏ'B\nɌ0\u0004i_'Gjk5\n\u0013\fEuxC\u001b$&\u0013o4\u0013)/\\0}ɽ\u001d\u00123[}.MzJ\u0011l\u0006Z#\u0001xC\u0007\u0017xt^u\u001f@&4D7ir\u000bm˰\u0012]b2*\u0013k\u001eK\u000bMhGTw<\bm\u0013IWpe\u0016YU?\u0013'\u0006)X\u0014aɅ3-X_ιF%ތ1\u0012ޱ>10\u0016\u0017C;6)ji\n\u0017*\u001d\u0018z~\u0000m\u0015|/nv\u0007mT\u0017(_\t\u0015w<\u0018S\u000e\u0011C\u000e(A\u0015eW\"\u000bg\u001aa\u000b[\u0011Vc\u001cC\n7\\\u0018^/k1l#?'M\rྫྷne'<)j^\u001fp\u001fVKʝ\f\tSnbv9VHoڶF\u0006ل-^:-l،qh;ZhϽ/\\\u001aG:n\u0015ЦKY7?aP,¿\u001c&jS\u0011PJ\u0015=OA۾KJTUN6?͒оoPT\u00166D\u0002ݒ\u000fALhQ+̕|s>CKhx\bX,\u0016үqHJ\u0018\r\\\u0017\tl ĂXH{(\u0015ڇ\u001a8i3J!0Km{/hM`\u0015Ba:\u0004\u0001)O@%\\bAđF@'Uے~SЅ\u0000(\u001f^nJ0\u000b \u0012)tI+לAĕӒ'L\u001c\u0012\u001dg\u001a=rJ\u001c\u0005\u0012Kf\u0000]^U\u001b\r\u001e\u0018\u0005d=ME19^^9\u0018#s~\u0014݊+gĆyaZn$_!@.|\u0006iy;Ñ#\u001ew^a*GW#lb92\u0000Yn\n5\u001f#{hd90֭v'\\\u0018\u000e\\vr s\u001eT\\T\u000f鴜]Paq2Xl\u0001U\u001bL8A(HvK\u001cG>hi\n*\u001fs\u0013u:\u0018~\u001baŔk#o`;&7MumR\"219.#\u001fo(<ٍ+áƈ*\n\u0014Q>0\u001bu\"/\t9}@nΡJ8߈e}#8}qo)|B\u0017bq\u0005Q\ffcT7:q%Ϗ(ڙW\"{\u0011\u0018\u000f\u001fAU\u0013\u00107of<\u001aG\u0004?\u0019If$B֣qĨ@\u0014\u0003X*\nUsq\u0010Qu\f\u000fVk$\u0014(\u001dI\u001fQm\"\u0014\u001d5yfʧ\u0007T#I1m)#\u001ajp0@UİqBi88V&ʇ8U[>\r\u0003\u001fe<ɥ(\u001cL|tz'\u001bK)n*%7\t\u0007\u001bR&[18\u0004k!tW6\u0005\b\u001bbN|HzSp0\\hoVo\u0006\u000e\u0019⵷)\u000fkPo\u0006\u000e!\u001fzx_Qo\u0002\u000e)]l#ZT\u001bCN17Q*\u000e!$^:&SyBzsdP%ZO7*ϑN'Yǈ\u0018՞:/}ۦu+~z\u000boqVUᇧJ\u0014H|\"mjvtbgy/\u001fq2ͺA\u0013p8g;\\<\u000e6ъ0!iOm[0\tL\u001b\bS\u0003\u0013+\u001fb֗Vx\u00065\u0010ΘE+B2i;\u0018=kos)F\u001d7>1ć6hH_%<*,\u001a\u0000do`Ѝ2GE2h \"\u000e\u0012E\u001emE{zMlQ\u000b\u001cNSr>//+'#Z\u0015I\u0016./ت2\nkV0\u000b\u0018\bA5\u0001q\"\u0002lP\tl\u000b\u0012DlH%\r\fDd!\u0003$HXS6OT.\u0002\u00036\n:\u0018\foJRP~r[zϽs{PvϟcFRR\u000709\u000fNOU2nQ2\u0007\u001a\u0018M~E-\u0003hݐ[dS@\u00054nJ-<T^}aK7\u0019\u001a7\u0007\u0018cO=ѲiIg\u0015v9r\u000b%\u001d\u0016KE%mܘ\u0016\u000e4\u0017}cKv\u0005\u0011+\u00070)Or]a\u001cŭ\u0003\u000eU;Ҷ\u001csŝ\u000e~op)G\u0013ސ~a܌$J\u0007[G`%ɏMt;*͢;%:l8Jp3Zbܘ:\u0007s(9&Fb{l&(\u0001g\u0013L;DLgQr\u00031>ѷ9Fd;\u0007(t\u000fIh®Lӊ\u001cxvdῚ.\u001b:0)7˓nVd=hm*򧉡sٌn?\u000e˸N\fu(\u0017xހQRYy\u001f\u0005[\\\u000ee3*8\n+PP\rw=/#J}\u000b(ǟut6d\u0014\u0005ޮ\u001d J}Qp\u0013:1\u001e|;\u0013O](i4rRp\u000b\u001c\u0019O\fFUWi`\u001f\nn>h?<F妘\u0012\u0018\n&Uq*M\\elBA]\u001e/d2*\"mܧl\u0002yYF2*7*a`M,\u000f+R.U\t\u0003k3Êk8{6T\u0012#\u0014\bh{)ԑS\u0018b4R\u000eub\r\u001cMTn9*lAX\u0003/_n)Tib'\nc\u0015\u001bw4V\u001bX*\\\u00036\u0006\u001e\u0019o1zU(4R~\n&]k\u0005r7\u0002F+x)RŪ1b-\u0010\n(8+4Vf=oQ\u0013`~6\u0007=#y\u0001Si\u0014\u0005}\u000eYF:_Si\u0006~Lr^[Sr-\b\u0012^\u0018\"\u001cJ3{A\u0015U*7%=f\u000fzH\u0007\u0003\u0017t^O\u0010sK%P\u001d)᧮k,^&K%\nFJw]YCRqp\u0004߉\n4,J\u0004[jf\t\u0019un+pbJ$+0Y 8\u0018\u0005\u0011O쟹-@K*\u000e΃f\u000b\u001b\u0016eVB%\u0015'kmK.\u0003HT\u001cyuJ7\\ncVn\u0016KT\u001cB,\fpzr;'J\u0014\u0015(^).wV(WT\u0004_6iX\u0011tT\u0006כ4\u0005[ĭܔtTl\u0006=M\u001a\u000e{s+K\u0012\u0015(ymjXC[Vv>S(\u0015\u000fߺ[YO\u0006\u001fO\bkȆwHn$RQ0<Yxc\tr3H\u0012v0_\u001d\u0016\f\u001cJ4`M>|LC%m`~$(]\u0007`~mC:tLvC\u001a*ќA폵\u001e(؝O)R\u0003B\u001eF\nؕe2X\u000eԐ']vS\"TPa'?\u001f0\u000f0\u000e$TPa3\u000bX\r7ؕ+?C\"\u0006yΟ*İ\u0003Dk\u0017K\u0015Tb\u000f\u0017B\"΋\n*1\\@A\u0006\u0011\u0011;'zk`՘L\u0010\u0011$TOp\u001a̿bL/\u0010\u0015;\u001f$UOp\u0000\u001a\r\u0010<[ba7O\"\u0016;ϕX\u000es#nJS,l\u0006\u0017\u0003\u0019΋)\u00166Jc@49\tSl\u001fY\u0001ٕP;601 \u001a<Kb\f̷\u001bW\u0010=T;>0k[ |T;Q0/7f+:;\u001f#Nq\u0002\u0018\u0007Daw>Yb\n͍9`O=\u001cz(0\u001e\u0010rT;F-\n3\u0011 \u0005vJBd<j\n>:_o~л@Rv\r\u001c\u0004\u0002WIS\u0006su\u0004|T9J9yT9A0HSg\u000bv~\u001e\b8_.NW\u0003\u0001K)6Y_/\u0016kظ\b\u000bb\u0014\u001by9n\u000f=b\u0014\u001b`fW\\\u001a\u001crJB\u0018\u0007$ΟYAKl\u0003QGv)6Ny1o\u001baB\u0014+ܘ P9~0gL!;*N^5f\u0015Ƴ;O'v20Ә ܐP;v0/2\u0019\u0010;/X@\u001fd\u000eyΗKS,\u00036f\"\u0016;G\u0014E`1\u0004*~瓥)\u0016\u0007i<\u0002\u0002~#)\u0016\u000e\u0004c@D\u001fX\u0004AƤܴG\u0002#~J,u`޽i{Dҋ\n*T A@֋\u0012~J,\u0007rHě \u001c|TA%G!\u0011@\u0014s}q\u001d`vH 3\t\u0015\u0003z$\r_\u000b\n\u001b\u0012*İ\u000b\u0017<|\u000b\u0002J5t].s\u001e\u001c\u000b$<G+ʮ!\u000f \f~Z _EA\"NLCW߅=:\u0017Qpm\u0011[Am~P\u001bt~\u0013O=\u0006\u001f\t8/\u0011s-p\u001e\u0016\n8\u001fk\\V\u001f\u001e~\bbL`+~ت\u001b0\u0010\u0012\u001fk׆\r\\oa\r\u0019 \u0002s\u00172z\t&\u001a=\u001c\u0005w\u0004\u000f ?\u001b_\u001f-fF\u000f\u0000\u0017\n87gņIK\u0015\u0012Ηy}m;4pAl_;^9_~\u0005M\u001a\u000b(Cy:ٱJ\u001dLj\u0000_\u0018(ܬ\nRs玆\u0003$Obu\r\u001fwk\\M\rpo$o\u0015T=f\rs%pnVVIRsf\u000b%Ex*VV藚\u00165%O\rV\b#4\u001c\u0003̓pn|jXu\\\u001cHP\f.*\u0010qޟ|iXut/\u001b3EZ\r.4-9\n|ixltH\tCUDOaű:_6g\u001c)!\u0006*Gy\u001aP)Rsa\f\\FĹYCꗚ\nWe$/7<u\u0002zz\u0005?;%dh\u0005\u000e֟s\u0007s\u000e<^\b.xP~9\u0019\u0018%a\u001f@ƹs{[TF9X\r.N2'/+oLkIMljH\u001aSMQ8f:Uj\u001d8ј\u0010ƤD C\u0005v\u000f~\u0006\u0007>\u0005\u0016v\u0007,owwA\u0016cw\\\\w\u0016-vp5`%\u00158$\u0005*\u0015M͚\u0015ғH\u00054*\u0003f\u0002\u0017W<%<)E\u001cE\u0016ݛ5,\b'<\n}=V\u0006\u0002kܛ56^ߑ\u001csQ*^}2{Sf}\u0007Bx\u0016k[\u0013\u0004\u000525W&۰ ,\u0018t1Z}uEպ\u000e.I-\u00076^R@ܟs+\u000er`\u001a8,EHi\u000b*ݛ5l:PBx\u001a&by>\u001dpS\u0015UkpB*ߵ>\u001fcy.\n)TЉ\u0013Uɰm\u0002\th{\u0001F}\n\u001e#\u000bֶ\u0001#\u001b\tσ1\rPܽY*\u0000\u001esQ\"B\u001a];B\\\u0017&\n҉D<g\u0003%M\u000f Io\u001b \neM\u000fs:H\u0000\u001eSTk[Y\u0007umrtFh\u00110.PV^8ocH\u0007hz8t%zsn\u00143H\"z)aZ_CqƽY&?qr\u0007\u0005*\u0014M͚4G7}K`X`ua<קk\"Uxҹ$LE\t\f+R75+t\u000e|\n0+ƽY.G-.LEU\u0015uM͊V\u0001\u000f!\u0004OTÀQ\u001a{SF:o\u0012Z9OƽY\u0001$\u001dŝD\u0013Mu6\u000f\u000f\u0006Q1+Iga1\u000bI*fEҏ'\u001d\\\t\u0018TW\r<!wy\u000eI\u0017Ȧ\u0002\n\u0015Z>ܳQ~*~dEGhP685ּUv)E:\u000e=L]bKW\u001ej+G٥\u0000D$|kl\u0018xo%^@B\u0013~\u0014\u0000<q-\u0017f\u0003\u001auw;5N\u000f\u0011C\u001aα\f\u0015ĳ;\f)/ث5\rn3Wfw{P2}ݺ#5n[X\u000b|48M&\u0017avC\f\".\u0007\u001eUZ4|C0|jÊHA\u0013<{\u001b8_e+MA5TL82sJ\f6\u001c0k*o\u0017\u0003;\u001753jb\u001cH\u00008[&5\u001a]#0OO\u001c\u0012=\u0018H:\u0012g+ցun\\s\u0018\u0012;\u0017\u00118nƿ^%l\u001fg\u0011P(&e\u0019\bN\u001fZ5e2ݠgIG%H0n°?s%\u0002cW\u00165\u0015qX\u0004b,X\u0004m-\u0016PtŹ59%S:ѾbM\u00147-ZEy~B58\u0019\u0017\u001df0>\u0010N^7U>}]\u001clޓ_h\u0012\u0002\u0004\u0013\u0017^UuY`dg\\\"ƃ%\u00149\\s/xpJb0srJ(fk,\rD\u0001ꦭQ)+z|ڥAH΄N}\u0018\u0011>c+a T\u0016^wAgU{\u0018S:\u0003\u000fe\u0015*Fr~\u000e'G\u0001\u0004Beas\u0001yDKv\u000e\u0010N0ק\u001d\u001eR3.|%I$Qz\u0018\u0017\u0002Xi\u001f^\u0007A8\\);92Lf䦽,wq#CG~<CA0\\\u00188:c_8\b t.\u000bErpX\u00066:Ȗ|sM=x<\u001c~/\u000f\u001denש0P\u00009<,a\u0010!\u0005\u0005\u0006<tN\u0014\u000bՓ\u0013\"\u00035#=P8\u0011]7\u001c@II\u0006a<0|`*\u0016GN\u0001+䰓\rf\u0003w\u001fȪ\u0010NHסn\f#\u0017PH&0Jb\u0017;͖o\u000b\t?\u0018u~`R\u00036y/\u0007G̤PD120\u001fZ^\u001d\u001b x\\\u0012L^QuF,\f\u0001\u001063DF٣e\u000fg\u001a562K3 f˿ܹ'\"hbZƙy*-k]\u0007\u0002J\u0013@\u00107M$ZAy\u001dbDLw=t$>Yr|f֝bu\u0013kui\"\u0013\u00015)@œL^RRdR2%D#{c)p7=*i[\u0018LFͫ6\u001c\u0003$kb(\u0016b*r`,A\u0004\u0017{<-ks<-V;ݏ'###\u0017|׫w$s\u001e$\u0017z[B5i[8mt/j\t.Yz|;\u000f+kԍ-؞Tf'G\u001b>\u0011\u0012\u000b@\u001c\u0016\u0017F\u0016#M2u:\u001b,Xm\u0003\t.5%\u00174z殮τ()\\cҜUփ#i\u0000hƓJ9]\u0003vZ[Aɗ<]_\u001d\u0004\u0017v\u001cs]5.\u0013Nz湌c1\u0017\u000f\u000e\\\u0001|oq[\u0003VKh=}H(%\u001f!$fN`\u0004\u0017Mpb\u000b\\k3\u0006aȋr)iR}\u00191aڬy\u0016.oϜx\u001d?@j3\u001aŔ\u0001#eo_\tXSkjjZuS+c2\u0007YϦ\u001c6cj?\u0002WPrPr05\u000fm%'ͭJշ3FUuy7?v<9etG\r)%MBjfwϢfb\u000bWL^g\u001byѡ(*ܺz4\u0013M9j\u0019H'p]Z#Xi9~\u0016=r\u0013\fKk/)075Ss/-xx7N%\u001e5{.ڗ\b5+~&J^\bBkl1=ZX\u0004o̭\u001dwSkm){&7%Ǚ׵)\u000b\\c.bu4y`\rZ7uOp\u0013\u001chjE*m3fl\u00078˺l\u0012h\fFMM\rnYL\u0013\\Rډ^0njhg:^Vu\u0014'I5k1aUjTݳ_BM>\\S\u0013Lp\u0004'2lk5Mhg^Q{\tum?N\u0004Ʀn荜T}Ǣ$=\u0005\u001b'g.^an혛\u001a?2Mq\u0017=\u001eohϰX\r>݄Qb\nD\u001cNH8{ڹM\rsnnUeݼMqum'F\u0004\u000eQ/9\u000b^cc:8\u001eC\u001a$MЃM\u001b\u0014\u0015j\u0005\b5V#(\u0012J\u000fZ(Ui`c6\u0004L.\u001a{\u000f|6g`\u00023N\u001b|S1\u001d>vL\u00042r\n\u0004԰8!\u0017f\u0016~\n?:BR{\u0003uV^Uj\u0001\u00040/\u0014\"NG\u001b,iy\b-\u0010cWLjH<\u001bJ\u000b\u000bF\u0003JMդ*\u0015+z{5? 8\u0015\u0010kS9\u0017\\SQ\\\u0010׌Ӎ\u0001vkFb\u0017`\u000bj\u000b\bAP\u0018tpqz3pB6w\u0006F/_bRÂp\u001fs..wqlӍ6\u0001\u00125i\u0002j~b\u001f`\u0003j5\u000f\nE\u000e.\u0001\bwhL夆\r07\u0003\u0018/hMZ4lb'mɂ\u001atpI&\u0001mξ\t՟s\f\n\tGFZ\u0015;-M^l`WjG#NG'S97!԰\u0010\u0013㚉O\u000bfžmT\u0003v(O*JGŠ\u001d\\jho䒚91\brLI|\\16.\u000fhQ}*ןSW2Ul\u00199\"ǯsp\u001fj.Nk*K\fm9ԭ\u001e+Sn\u0002:\u001f\u0010\u001c\\,F{I\r{[Cu)rqb\\;?ήgM9Vz~@%R\u0016U\u0013לwp)6{\f5xyt4T\u0014eIq\u0017I_]bqwZ}C)=K\u0017<spz39ǡw\u0018&]{\f\u0018ע1ٵ8QVZI\t+f\u001e\u001b\u0002D\u0007wsp̳\u0018#Z$57.\u000et5V\u0017L5cEg0Yd<\u000fժLЇR^B\u0014\u0004\u0007_3MRC\\[q>?n5q-u\u0016s|PK\b`\nV.\to\u0005ʂ\u001arpf;4IRCBp\u001fsW.Nkl\u00069C%8$-$?\u000b7w{pD\nj$\u0019rkԐx7֔s.Nk\t?`4J\u001b\tT,V*\u0016W\u0010yr\f\u001ah\u001f\u0018(!!\u000ft6UNwqf)&B3]ϱ/:\u0007=E϶C\u001d\\hoh*!pok.+.NkM+\u0015KQ+\b\u001d\u0002OA)!\u0007\u0017bg\u0015b\rkԐ8ڛjK\u001a\u0013E\u000fe9MwlV&08wI\u0011\u0003\u0001\u001d\\<tp\u0019\u0002]\u0003#`R\u0011Ǉz;[/`\u0017gJ\u0012a)qn\u0007FneZ3$t\tytCbP\u000b\u000eC\u000e.hIs\u0016@7@\u000f^|V9u\u001eEŉqM%a\u0001>z<9v_B\u0007\u0017\u0007\u001d=GoxVI\r\t⠫\u001ctq)I1<n\u0001\u001evż6G?5CW\u001cܑc_\u0013\f\u00109\u0018#\u0013%5,\u000e]-U%qM\u0011A\u0000.>gV[8{ʹ/q̓B±3Z2s\u000bJ\u0010;{\u0006QR6(81f\u0001l*1^ȬoAxٖWġwxLä בj\u0012n'\u0019f\"pI!V7_mN\u0007~,\u0010\u0019,\u000e\u000e\b(iOqp\u001fj\u0015]\\L,&OhSS~,\nS(9ea9\u0014=QԴ|aHp\u001fpop.\u000eqv) 6`}\u0019:A\u0019yҚ\u0007s\u000e.\fҳ1\u001b!ڇMjH\u0010W ;\u0005\u0017gI\u0016=\u001a\u0001\u001e\ns$\u0006aKeA\r:3ah\u001f\u001eIM|{\r½sqB\\nv/\u000bx\u0002;╋\u000ed\u001d%ۚ\u001d\u0000{-z1齚ܻVrq#pZ_[\u0007!4\u0007=~T\u0016x\u0007g\u0006\u0019\u0018m\b(i|2A\u0017gŵ^ퟀ\\;{\u0005}D\u0005\u0010<\u001dҚC\u0007wtd\\R5͑{G{\u001fNj>Pwx7.$-z3[\u0012\tȕ#\u001e2.NdH:eÐכmJ\u00195MjH\u001c]\u001du\u0017ǵ\u001eNW\u0016\u001e\u001e~O@\u0000ᐭ\u0016\u001eq\n\"wPt6PoW+lR\\<ǀg'\u0000\u0012W)\u001d1_GCgho\u00151'FM5u\u000f(@.zW6ޤ\u0018\u001eةp~)\u0016lhopvK㤆$½wqB\\\u001d~GקRF\u001d\u0014\u0002N=\u0019A-26hIu\u0017a 9>\u0001\u0017g\u001c4/\u0014Pw~䢙]7o\n\u0016԰3\"QR}Rpno,]\u0010tT)T/i\nNx\rֲJ\u0001A}dZP\u001c\u0019><眇`OgK}UYQ\u001evq⢧8\u0019}\u0001hu:ѷm4?\u0004\f\u001c྆\u000e.\t:8b\u001e\\Rs>5usq\u0006\u000f\r=)Wٕ_Q\u0010\u0004/z\u0010\u0003\u000eB\u0007\u000eΞy@Bk>HjX\u0002ܛ.\u0016b\u0017'52|\u0006\u00162\u0014յn\u000f3[\u0017,@F\f09ý8\u001f8i?\u001b:%\nc~+*k\r\u001f\u0003\u0011ӷl͡;\u001ffGI\r{wqfzb.\u000e\u0001J(هU?\u001f\u001bM\u001e@ׄl2,aph\u0016]\u0014\"Bf:7v1jjy5()\u0006Jk\u001e\u0014;8%UB{w\u001fD\u001a\u0012ֆr\u001cBz_<\u00058_SnT\u0018A\u0005\u0017?9,_s\u0013&[Zf.Nv\u001f%5$\f>g{Sm%dq-\u0003|\u0002(8VrTӮ۔?i\u0000(!\u0007\u0007\u000eҳhYRC>h..՜,8O\u0001t5\u0005zњ\u0001Y\u0002G\u001eY\u00156Kud\u0017hIWϹ\u0000ޮƚ\u0002ŉq-vI\u0004\u0015lw\nh\t\"^t假\u000ec\u0007l3s\thiRCBp\u001f\u001fnoP\\\u001ckq'\u0019ó@˚^\u001az4~rKd\u000e.\u0018 0ڛ\u0010G&`Rs~mbtR/\u0018a\u001366yQ_\r-V\f\u0007О\u0011;t/)\f\u0010ζ\u0012l2\u0017e\u0000)\u0019ԝ=_:ZJm-iܚs\u000e.\u0006:8\u001c]8M\u000erW\u0015rix`\u0003\u0007s\u0002,jt\u000elN7d.LHn%FHH\u0014\u0015%t\u000e6@(D4<̨R`\u001b-\u001c\f\u0018-\u0002V{{yt[kom\u000f'wꪐ\u0016gu\u0015\u001eww86\u001e\t\u0014|mT*fc9,^^U܎F{RC\u001dpWI<ŕ^-9w\u001e>a\u0018!bͥ\"fbrj\u0006JؖhoY1h_\tw\r\u0012\"j>^Zo\u001c.DC\u000e¡T¶48z\u0015&h/]j(X\u000f)n^\u001bε̵\u001c\u001cc!\r8\u0003\u000e\u0001dXc]'a/5\u0014,GT.ՠ-\\\u001cI\u001cqt\u000b\u001fr\b\u0016QVla0\u0006\u0016665\u0003zYX\rwHm\u0013kqZn\nW9xF\u000e\u000e\u000eIl{Yʚz,\u0003QK\r\u0005\tIЀ\\koFZV7\u000b\u0016\u0007Df\u00007qLO\u0011EM,\u0005\")\u0012إ\u00069\nwi\u000f\u0001mqs7o:\n\u0017R-\u000e\u000bh\u0017ѮB.590Z!\u0013ws\u001a\u0016\u0007k\\pNc?\u000e\nټ&)ĄovZcvj\u000f\u000fIvŕKsY9Ks\u0002\u0011\u0007%i\tƺ\u00014)q~{ld_*wXZ\u001c\n^.Rប\u000fc\bVyvvrh\u0010Ԧ/5\u000bhOhJ$ymX+\u0006qϑ\u001falj\u0001\u000b\u000b:$ڑK\u0002WP{?\u0018}p$D^4/5\u0014\u001d,\u00152ڣ\u001e'2\u001b\u0002킣@MHm\u0002JrB\"2a\u00168\u001e3vq>\u001df\t=oL\u001f')\u0012\u0001\tyAOg6:@MFJB\u000eG\u001dp\nV\u001d\u00070NG\u0015\u0000g\tp\u0014frS\u0017SRrN[pq#\u0014Zmj\u0003-\u001d.s}׫^֚\"0\n\u0014ОK}\u0018Ԕt\u0014(}!7\u000e3\u0012I}\u0000\u001brh}\u001bZg*\u0011s:/2.]7W\u001cVRYYt)-#\u0004=1\u0016@L1/XysB\u0003Sb\u0016\b-@T7[@6h%7N\u001ew=Et:88:\u001eh\u0013\u0013\u0011=\u0007Z;'&0Q\rm ^iUsv<\u0014\u0005m,]?\u0005K\u0017U\u0014\u001a\u001dZ+\u0017ⱸNhG\u000bə@h\\]v}GD\t(;⚨XÌLG=p3f\u0007&\u001b\u00002eVc\"|8<\u0015}67>\u001aZ\rߔ={\u000bzʦ\u0003qq=]qohNԱ\bMܨ\u001eYsٽ$\u001c{h\u001bnc/F,\u0001o\u001b!7jۓm\n\u001b\u0017\u001eTР\u001d\u0006usQJlDC\u001b!]\u0007\u0012Ǭ)uw7٨\u001bUvՕ^Na{_7?`g\u0010\u0010oP@\u0000-\u0000~\rendstream\rendobj\r148 0 obj\r<</Filter/FlateDecode/Length 2574/N 3>>stream\r\nHyTSw\u0016oɞc\r[\u00065la\u001d\u0004Q\bI\b\u0001\u0012BH\u0005AD\u0005\u0014ED2mtFOE.c\u000e}\u000308\u0016׎\u00178GNg\u001f9w߽\u0000'0\u000b\u0000֠J\u0016\u0015\u0014b\t\u0000\u0003\n \u0002\u0011\u00002y.-;!\u0007KZ\t^\u0007i\"L0-\r\u0000@\u00198\u0007(r;q7L\u0019y&Q\u0013\u0004q4j|9\nV)gB0iW\u00198#8wթ8_٥ʨQ\u0014Qj\u0001@&A)/\u000fg>'K\u0002\u0000t;\\\u000e\u001b\r\u0006ӥ$պFZUn\u001e(4T%)뫔\u00060C&\u0015Zi\u001b\u00018bxEB\u001f;Pӓ̹A\u000bom?W=\nx\u0016-\u0000\u0004[\u00000\u001d}y)7\u0018ta>jT7\u000e@tܛ`q2ʀ&6ZLĄ?\u001d_\u001dyxg)˔z\u0016çLU*\u0006u\u0016SkS\u0013eO4?׸c\u0001\u0007.\u0000\u000b\u0000\u0000R\r߁-\u000725\tS>ӣVd`rn~Y\u0002\u0002\u0002&\u0001+`\u000f;\u0010\u0002\u0010\u0002A4\u0007 \u001d\u0002\u0014A9\u0000=\u0007-\u001dt\u001e\u001el\u0002`;\u0018\u0003~p\u0010\tGp\u001e|\t[`\u0012L`\u0006<\u0005 \b\"A\f\u000bYA\u000e+\u0005Cb(\u0012R,\u0000*T\u00162B-\n\u0007ꇆ\u001dnQ\u0004t\u000e\u0004}\u0005MA\u000f0\u0002a\u001el\u0007\u0018S\u001cx\tk&\u0013^\u0007\u000f>0|\u0002>\u000f_',\u0002\u0010\u001aG\u001c\u0011!\"F$H:R!z\u0015F\u0006Qd?r\f9\\A&G\u000brQ\f\u0015h\u0012\u001a\u0015E]a4z\u0005Bg\u0004\u0006E\b#H\t\b*B=0HIpp0MxJ$\u0012D\u00011D, V\u0010ĭ\u0003KĻY\u0012dE\"EI2EBGt4MzN\u001d\u0004r!YK \u000f?%_&#(0J:EAiQ((\u0017)ӔWT6U@P+!~\u0019m\u0013\u001aD\u000beԴ!hӦh/\u001c']B/\u001b\u001fҏӿ?a0\u0018nhF!X8܌kc&5S\u001d6lIa2cKMA!E#\u0016ƒdV\b(\u0006kel\r}}Cq9\nN'\u0003)].uJr\n\u0018\fwG\txR^\u0005[\u0004oƜc\u001ehg`>b$\u001f*~\u001f :Eb~\u0016,m,-ݖ\u0007,Y¬*6X[ݱF=3뭷Y~dó\tt\u001ci\u000bzf6~`{v.Ng#{}}\u000f\u001c\u000e\u000ej\u0001\u001cc1X\u00156f\u001cm\u001d\u001c;\u001c'\u001c_9\tr:\u000e8q:˜\u0007O:ϸ8uJq\u0015nv=MmR \u00154\t\nn3ܣkGݯz\u0010=\u001e\u001e[==<=G</z^^j^\tޡZQ\u001bB0FX'+t<u-{__ߘ-\u0011G,\u0010\u001d\u0013}/\u001f\u001a\bH\bh\u000b8\u0012mW2p[AiAN\u0006#8$X\u001f?AKHI{!7<qWy(!46-\u0017aaa\u000f\u0017W\t@@`l\b\bYĎH,$((Yh7ъb<b*b<~\u0014L\u0012&Y&9\u001e%uMssNpJP%MI\fJlN<DHJIڐtCj'KwKgC%Nd\f|ꙪO=\u0006%mLuvx:HoL!ȨC&13#s$/Y=Osbsrn\u001asO1v=ˏϟ\\h٢\u0005\u0005#¼\u0017oZ<]\u0014TUt}`IÒsKV-Y,+>TB(/S,]6*-W:#7\u001f*\u0015\u0003\u0007\be^YDY}UjAyT`#D=\"b{ų\u000f+ʯ:!kJ4G\u001cmt}uC%K7Y\u0013VfFY\u000b.=b?S\u0017ƕƩȺy\u001a\rچ\u000bk\u001a5%4\u0019m7lqlioZ\u0016lG+Zz͹mzy]?uuw|\"űNwW&e֥ﺱ*|j5\u0001kyݭǯg^y\u0017kEklD_p߶7Dmo꿻1m\u0001l{Mś\r\u0006\u000enLl<9O\u0000\u0001[$h՛B\u001cdҞ@\u001diءG&\u0006vVǥ8\u001anRĩ7\u001c\u0002u\\ЭD-\u0016\u0000u`ֲK³8%\u0013\u0001yhYѹJº;.!\u0015\nzpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\\dlvۀ\u0005܊\u0010ݖ\u001cޢ)߯6DScs\r\u001f2F[p\u0011(@Xr\u00194Pm\u00198Ww\u0007)Km\u0002\f\u0000\rendstream\rendobj\r146 0 obj\r<</BitsPerComponent 8/ColorSpace/DeviceGray/DecodeParms<</BitsPerComponent 4/Colors 1/Columns 500>>/Filter/FlateDecode/Height 500/Intent/RelativeColorimetric/Length 8281/Name/X/Subtype/Image/Type/XObject/Width 500>>stream\r\nHyp\u001d\u0010H\\\u001e\u001a3\"Ria\u0012R[PKRZZ\u0018F\u0016T\u0018KKQ\u0018EA\u0010{-V\u00062؂X,3\u001cc >wKVLMxg\u001e/fgywĈg\\饃GN5\u0015U_Nu\u001b-C;\u00072@*aaO)[\u001a\u0005ƒ\u000fضsRP2[Q]F04\u000fo]=6i$hR}|\u0010C-\u001c\u000b=d\u0018/[\u0001\u0007\u0013<e$\u0019%H'-\u0012)݃||cv\nq9\r\u0002tW7&COL\\&E8z:Ǩ/ﰂti)$\u0010\u0019O1\u0003g\u001b:D ){W)[\fI\\3:\u000f-В}l\u0018d┴G9x|䜣Qq;*\u0015:8Bwߡ(҇ґY\u00073^\u0000-]yrN\u0006=\u0011>\u0014bmnhZhyy.tr1\u0015C\u0018\u0006_쑾\tZ\u001c\u001b\u001d\u00070Xt<NP\u000e:Xa\u001a+.^8$x\u0002niLh6\t:hg6hK;t\u0003H=zl\u001b-WzooWg}JGը7X\n7E4\u0007:he>/߬<}\u0016W@`_$\u001dF#9\r,.q>`tvKN8ژb7hUf.\u0006JMo\u000bs[\u0003\u0007f@\u001cMY\u0007{j5w4\u0019+)IG\u000bi϶SW.\u000549\u0011:h@D\u0013[&}*pms\u0013\u0007'ʒ`Q[\\1ۙvAg\u000e\f\\\u001f\u0015YNT_?3s#\u000fȁ\"\u00159ph\u0003[cd&3ʋ`SmO'C\u000fy\u0014\u0002\u0011(2wk{\u0015h\u0003\u0019w(%( \u0017Yk⟧A[\u0010ʣZì,>էᱎu\u001e1혆.jxJ\u0018\u001a,h\u0017x:\u001bN\u0010\u0015&/3gGB\u0010\u001dgdz=\u0016LyF\"MFڷ8PiP>\u0011ܕ\nm%d(\u00031S>\u0001N/A{\u001c\\\u0003ﲙ\u0002|Kt\u000fv$C\u0010N%ᲆ\u001e\u001eB\u0007\u0003v\"2w-\u0007ejF%Hw\u001d\u001fFs\u0013S\n(#B\u001aLT\f#d9)Wq`\u0006f\u0000%6\u000eP^6zDs'\t\u001e\u0005m\u001bSPT\\I\u001dlTSk8wB\u0017ɇv9Czk;smq\u0007>≛c\fxi:ha̤xN_K@Dzz\"3F2CS1B?\u0017&\u000b\u001a\u0013K[I\u0007uo1JC\u0001ǠiG9D8eS c\nG\u0015Wid\t\t\u0003F\u0014cpa:=M\u0011WvIc1H+\u0006\u0002?\rD6\\Iќ`,bk&[ AjrF3\u0013^#ٗ<\u001e!%?&\u0014\u0017\u0013\u001ef;u\u001a)%\u001bң=XƧ\u000f\u0010{;\u0005$1%誝%ئh~\u0012KB\u0013cd\t-\u0019Nuם6sd^\u001b[fOUU-}\u0012E4J9\\<I[\u0002m\u0014˂\u000e9\u0002ȮC(S\fw\u0013LT\u001aVP\"X6U$\u000f|qQ\u000f\u0001\\h-W\u0004_\u0011L'&\f\u0004;\u000bmV5\u0001|1\u0017\u001a\u001ae3[\u0015\u0013\\JC7<\u0004^;,\u001b\bl\u000f!_\u000eZP\u00136<_C:qU\u001dЎ?\u001ahM\u00120DEn\u001f۰R\u0018;\u0006hσx\u0010\\!\u001a':\u0001\n)hӷ߃k+oo\u0004TtVVC\u001f\u000bq\t%ީí/}v\\n>?\u001d\u0012h׹\u0005צO \u0000\u0010,6>bj-\"i/\u0004ŀ[z\u00171\u0005\u0016M8`k*\u0005;AO\u0012\tA,(HtPL)v)\u0004Â\u001c)_iM\u0015Ba]rgRq (e \u001bm:$Y\u0000ǗR\u0002HD<zCp\u0013薤rV1gzhη`:5zb\\+XC~o%??%TyF+\u001b=\u0013\u0019,{\u000bTRՂUB\u0011]<YVlR9/0\u001b晑\u0010H\t).\u0012|!iM\u000fǑ\u0013\u001e;R\r.y,\"ݟ\u0013\\!:\u0003K]q#ew\tفs\\\r0;灈+C}b:&N\u000f|-*\u001cU1v\u0005Um\u001aY燐I4~c;GR8vs#|U'7˷\u0011By>\u001f1\u000fv\u001dS2fT1:R7 2sQ)#\u000fΗ#<ӋT#aƄ**K#|\u001d\u0001\u0013JHc#|\u0013#['\u0019\nU}-\u0002g#>0Py>04v\";\u0010Սta)\u000e!Nw^\u0014I\u0007yQYvćtp\u001eMB\bu2:?jh\u00125\u001a{\u0011EK\u0012OQ}\\<\u0004\u0005U|q\rF@IM7&mD\u0014OsS ,l\"\t\n\u000bJNuFaH\b@զqF4\u0012\u0012NDq\u000b\u0017c¦\u0010\u001eP|a$dv\u001c{\"!$X^\u000b/`w~L(\u0012R\u0010wwUy\"n\u0012\t1}\rr]\u0018\u0012\n5\u00186M!1)\u001f$n\n\t\u0015\u0016g& M:qfP3;*n\u0002\t-Sf\u0013:\r R\u001a\u0017\u000e\u0003H1hT>G\\\u0012\rBs9%ZЫѤ|H\u0012\u001dUK,-\u000bl^\rz=\r?\u0015׺D+\u000eՊ2AqK4S\u0013V-Z\u0014%VLZ/\t[j\b\u00020C\u000fd9(k\t\u000b\r\u0001\u0001*n]K0V8_-g\t\u001b>/h[\u0005,aĨZ2\\y%zUKO;W`\u0012f\f\u0015+\fw>I\u0014ҮC&u[`\u0012\u000e\u0010*On\u0012خ\u0003ua\u0006\"ەZJ}JTH߮QH\u0016uIo\u0017ש\u0017\u0004ʓ\u0005*DNwV%0V\bnqS\u000foZ?{lw\u001d\u0006/r,\u00031Le&-\b1nj\u0014\u0014bH\\$D42&#d6'q\u000b\u000bAC\u0010\u0002m)ܺ\u0002r\n\u0014(kmiO{\u000e<o}4isaU~uT)\u0007|91\u0004t\u0014niʇ\u001dd攀Рilt71SJH[dQt竈!%\u00064\u0014YN1SJPh>1̌\u0012֡\u0004\u0011š\u0012N4(|t33\u0004V\u0006)o3\u0013Jhg\u001e:b@\t\b\r}d#3\u0004\u0007\r:'ο'%F;Qk\u0001|\u0006*\u001f~\u0019O\u001cERw>N\\\u001cEE;\u0019N\\\u0014s;f\u0013\u00175hpTOaf\u0013'T͌&N/Ru\u0019MG\u0014hbF\u0013/u`=1y`0\u00124X<GM\u0005\u001a\u001b6f0qr\u001e\f\u000ej2qS\u00063w\u0019K\u001c/{w838:\u0006\u001bw\u0019K<\u001d\u0007}Q\u0006v>\u0019J\\;v\u0019J\\5\u001f{v}*/\u001f5_\u001f,f$qV\u0006\u000b{wcf$qր\u0006:f$v\u0018oH\u0014||Ht%f q\u0016\u001a,'@.q\u0006\fYj\"qJz:E\r$û+\u001f\u001d\u0006\u0012wg1\bI4Nw狙q\u0001?8BP\u0005֟8BP\f֫;?@#\u0004`Nj\u001c!؇\u0006Ӻ:I\"\u001c-xAW\u000bi\u0010Xe,±\u0005\u0019j\u0018(\u0002vu^H\r#\u0014e`pWGab7X\u001c|d\u001aF(N(\u0002ֿ(Br\u0010/Iv}j\u0014!\u0000\u000f&;95\u00145Wa+0\u0014W\u000b\f\u000f9\u0011`&y%\u0018/\u0004\u000b5`lc`XF\u0018΢;o\u0007|\by\t&,Q\u000f?k6\r\bG-Xg\u00150:\u0014EH%f\u000bhW\u0016\u00025[%'#ffxBC\u0019^\"y\bI09E\u00112\u001fu`g{\u0004[^\u0004#g\"yb/Xe\u001a\u0018{e\u0011#`ά\u0014v8E\u0011`Y5\u0018\"\u001chݬ\u0016кsh`V\u0007& y\r\rF\u0019z\u000448EKm<\u001c>\u001a$MPC\u0016jpIW\u0014!Sc\bQ=XWC\u0017zRCW\u001dX·\u0003`\u0006yS\u0012aٮw|;o\u0007\u0013up`W\u0014!A_\u000b\bW\u0014!Ac`R\u0015EH\u0018CoqozEK̬\u001aLvRsHpdV\u0006F<ϡ\u0017\u0006\u0018\u0018U:E\u0011C`l\u0013\u0018\u00135`}_+p\u001fj~\u0007F1(B_6%\u0018\u0015ze\u0011-`}+p\u001fd~\bF\u0015^Yc3XwhW\u0016@̾\nFu^Yc'X_j6\u0003\u001a\bAl\u0012)p4ϙ\r\u0000\u0013^a\"\u0001?ef`+01w\u0006mq\n#\u0014\u0007z`XF\u0018v׀aS\u0018\nc\u001f\u0004m^i\fMv\u0004\fk\bvp9`F\u0018΀\u001f%;jpJ#Ҽdt73Պ\u0006ӓ[=nv#\u0004`K4F\u0018:\u000bZ0.#NqW\u00000BǮο\u0007M\tj\u001aaXh~\u0019F(n|<o%\u0011]\u001b~F\b:F^%a35\u0010yr{\u001clx\u001aG\b6tw\u0014lh\u0011\u000fww>\u001bÌ#\u0004;p\u0002(\u0011ӻ;ZGܵ\u0016|_\u0016=ۇ\u000f*`KHhO\u00153IhOG}s;\nTP\u0013^\rl:I$*{Un?EjS;v\u00151#zw>&\u000evR3;J\b5:٧r{\u0002;\f%6|!W\f%$o\u000b3o\u0017;N%~-js\u00071xz_\b\u0011S;v0c;`g\u001aL4^1hֆ\u0017\u0006Tn2f0qsǞ\u0007{\u001bhd-6W\u0011)*\"f4q*UFO3:h{%3h\u0019ߢz[\u001bSVns3mtaiG6\u000bʙAԝztE\t38(\u0007ۭ|\u00122Vt6f>\to*.)evm1\f3\u0000JRVL(݀;ZfB\t:r]Ĉ\u0012Qy\u0017]V(A%֢_\\J\"+\u000b!%;;/8.L)\u0001MVK\u0012cJ@/\fR]@ឧ9X\u0016C67\u0010sJ0o\u0017\f\"xqSY1h64\u0019U\u00026x\u0012^o<TF6\u001d^~\u0000mtn\nbV\tԨ:\u0001<\u0018VuZۘFx>bZ\t 15m\u0015<\u0018W\u0002o\rZ\u00183[vn/3W\u000fO#ĒҮ܆\u0014\u0013\u0013KΎKs\u000b\u001e\u0013?ċ,9JE˸3RbfI|J&CNܗڌ*-Ԓ:'Q5ܒ\u00173ܮó\u0012sKi\u000eE\f.*ɸr\u0003+A.Yy\u0011\u0015Kܦow%+dӹ=\u000fѢKv^ͪrd\u001b<(1d:egY}\u0015xx\u0003Ĭl;=\u001bmȺrh3>Vk\u0019wn+\rx y>m9|p)\u001e$#s8v\u0013U9Un#kǚx!;3!mAᅴې\fܝcf;y7\"Ws[4͹r\"v'M\u0001*\t\u0007ϻ\u0019IGu!:#>bO\u001bn$\u001d\u0005\nF|Fu3WD|HG\u0015~dp\u0007\u0011r,~$3=+u~و\u001c$RaĬ}FnJQ\u001c$BU\"bpmX,ⓚ\u0002ߗ@OD\fkFܮmꨯ\u0018\t(=jŠ\u001f\u0015&@I+\u001d\u0011Q\u0011$m\u0011Cwn:\">з'\u00035r\u000f\t!\u0001DZ%-\ravRΤ-j\u0018lf\u000fPD-XDm2CgEQ((ֲw_I6o a;\u0000Ivd7}k\u0014\u0002qwc9{\u0019>]9B\u001e\u0016۞lу*(G9>#\u000b8ppJ\u001ej۠ԉ\u0012U#,&-Z\\JO\b7_%(\u00163|I\u000b7ڛs\"{pCo\u0016\u0017Ibnɵ)G;؅a\u000f\u0019\u0016J\u001fQQ9B>ƱK\u0019TbGTux\u0010d\u0015N-ičߨr\u0018\"-|8G\bv1#[Gzx6kq\u000eB\u0007TW5`W^#-؉ߝ\u001fR9i\f\u0018φ-\npH\u0003\b=%7~؂\r\u0007~T\u0013\b\u001a\f[\u00160_H9|\u001b\u0010\u001bM\u0013<s\u001bR;͍'\u001d\u000eޠrVGk\u0011]<\u001b7/pj\u0011*/6YαsҌgIT9B/'׺Y91\u001f?lQkޜ\\#~\"7#'c\u0005+G _T_\u0000;\u001fO\u000b\u001cbEB\nl\f\u0010\n6(Gh\u0013a]\u0013U\"0\u001b'\b{\u0003H9B;\b+YW6Y4\u0012NkZ\u001f/qW\ff.B()G(CXh\u0015y$\u0014t\\\u0003\u001ck:\b\u0013\u0005NI\nX:\u001cT9Bϐzq$8DBAl\rrHs\u0004#ƧRZbT!~\u000by\u001e$m@RO$NX$iN~K&iN\u0017d\u000b\u000b|t¤K<J,\u000emz\u0006e&\u0013S\u001e%\u0001%ܓ@\u0001̌$+\u0019К/e'\u0011\u000e٤)ZrLhɗ\u0002yI}$+\u001bZ,2^$/;T\u001eO:R3F92\u000f\u0015ȠxKI\u0001\u001d⤳?\u000bJ`ˠҌ\u001a)S\u001aWRZ(z^g'lLן\u0010(̂()v@{\rIӌUT\u0014*1&\u0002T?4?~\u0014)u\u0011naq\u0001\t;K1\u0018Q\n>\u001fiEab*>@+O[DY\"h\\[EvC\fP-UYǍ.Yxݤ6\u0015+\u001a$\u0003k]~pe=(c>G6Jv0 <C\":\fh\u0014S|3\"Mtu\u0006e!Rt'`\u0016+<\u000eڟ,ҝM%iRv\u0006W\bmO&_͢᤼\fC[y4\u0017ڝ|=%\u001c24\f\u0013\tԶ9┰61;NgLD4x\u001f5,\u0011c\t\u00185S6\u0000L1sw\u00063ؗ\u0003m\u0007_\u001dn8\u000bð@kşŉ[[\u00039dĪcm!\"hWy!\t\u0019`uK\u0015`~}1)\u0014x\f\u000birq\u001b\u0017F\u0018ÏC[̵a\u000b+Ȗ\u001e\u00191jnvĝ(K\u0002g\u0003l\t덀k<#\u000bڐ\u001ala\n-b8>!V\u0017\u001d\u00025<u\fZ=掳M8\u0007F=3sN2\u0000'Y>\u0006h/ei\u0014\fPFlC\u001f6fT%Y\u0000ZZ6\u00013nvS\f\ts4'd#Ʌ\r+k\u0003MTT4$U`]\u000bB32\u0018\u0011밠[SΡ#\u0002h\u0013Z\u001dYv\u000b橊bM!\u0005Z}ODu\u0018u5dM\u001c\\h\u0005ڳ`˸̜m2gr$Oؕ\u000b?\f\u001f(7\u000e{}L\\Nx̷\u000bu\u000btp|R~a\u0003\u0002\u0017p\r˟eA(\u0019T}6d\u001cΖS\u0003O˸  Ԅ\u0014}\u0003\u0003&[kE/^\r\u001eX'PEp)\u000e\"Zg$\u0007nN[/Yr\n\u0012-\u000ew\u0013LNZO!)By{W]Bg;_\u0014o\u001a:eQpXrb^\u0016T%IA(NX\u0006\u0013l\u001d\u001dgHW\u001fy+}kӄzZvQ\u0007_>oS]Cp7tr\u0005X\u0007Y7>{'T0x?\u0018ZTNKQ%hJb_!tF`ɶSЦx\u0011ڽ\f:M0oqh[<UI\u001a/\u001cRcW\u0015؃sC4\u001c\u001f&3&YQP\u000e\u0005\u0019e\u0016\u0005Щ\u001996\u0001?ςN,-X]C\u001cĊ%Y\u0011וUC\u001b%qb2Ҏ?\u0016/Ϳ\\\tO̥ǃ|fb&KJ\u000ev<MK31\u0001_IhwOq\u000et\u001a}\u0014﯀Ntԏ\u0018\u001dywYeOk;O|CUq-t'\u001b\u0013\u0019ZL`Ɨ=\u0011t\u001by\u0015t\u0016{#O\u001f&NuoΆ\u0002GvW6+=\\Go_\bݏ\u000559ݷi_>\u0017~׽ogi\u000fBw`!Ϳs࿵@lD`{w{\u000f\u0015ݼ\bz\u0016ͻ>syyA\u0004O\u0001\u0000\u001a\u000e\rendstream\rendobj\r139 0 obj\r<</AntiAlias false/ColorSpace 136 0 R/Coords[0.0 0.0 1.0 0.0]/Domain[0.0 1.0]/Extend[true true]/Function 149 0 R/ShadingType 2>>\rendobj\r149 0 obj\r<</Bounds[0.0529018 0.216014 0.451278 0.498372 0.582743 0.717518 0.839036 0.952136]/Domain[0.0 1.0]/Encode[0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0]/FunctionType 3/Functions[150 0 R 151 0 R 152 0 R 153 0 R 154 0 R 155 0 R 156 0 R 157 0 R 158 0 R]>>\rendobj\r150 0 obj\r<</C0[0.913725 0.0745098 0.533333]/C1[0.913725 0.0745098 0.533333]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r151 0 obj\r<</C0[0.913725 0.0745098 0.533333]/C1[0.921569 0.176471 0.180392]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r152 0 obj\r<</C0[0.921569 0.176471 0.180392]/C1[0.980392 0.792157 0.168627]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r153 0 obj\r<</C0[0.980392 0.792157 0.168627]/C1[0.992157 0.913725 0.168627]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r154 0 obj\r<</C0[0.992157 0.913725 0.168627]/C1[0.839216 0.866667 0.192157]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r155 0 obj\r<</C0[0.839216 0.866667 0.192157]/C1[0.0 0.619608 0.329412]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r156 0 obj\r<</C0[0.0 0.619608 0.329412]/C1[0.0 0.658824 0.870588]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r157 0 obj\r<</C0[0.0 0.658824 0.870588]/C1[0.2 0.2 0.568627]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r158 0 obj\r<</C0[0.2 0.2 0.568627]/C1[0.2 0.2 0.568627]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r131 0 obj\r<</Intent 159 0 R/Name(Layer 1)/Type/OCG/Usage 160 0 R>>\rendobj\r159 0 obj\r[/View/Design]\rendobj\r160 0 obj\r<</CreatorInfo<</Creator(Adobe Illustrator 19.0)/Subtype/Artwork>>>>\rendobj\r137 0 obj\r<</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>>\rendobj\r138 0 obj\r<</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask 161 0 R/Type/ExtGState/ca 1.0/op false>>\rendobj\r161 0 obj\r<</G 162 0 R/S/Luminosity/Type/Mask>>\rendobj\r162 0 obj\r<</BBox[-32768.0 32767.0 32767.0 -32768.0]/Group 163 0 R/Length 86/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 137 0 R>>/Shading<</Sh0 164 0 R>>>>/Subtype/Form>>stream\r\nq\n0 g\n/GS0 gs\n224.4700623 0 0 -224.4700623 399.1927185 327.2288818 cm\nBX /Sh0 sh EX Q\n\rendstream\rendobj\r163 0 obj\r<</CS/DeviceGray/I false/K false/S/Transparency/Type/Group>>\rendobj\r164 0 obj\r<</AntiAlias false/ColorSpace/DeviceGray/Coords[0.0 0.0 1.0 0.0]/Domain[0.0 1.0]/Extend[true true]/Function 165 0 R/ShadingType 2>>\rendobj\r165 0 obj\r<</Bounds[0.0529018 0.216014 0.451278 0.498372 0.582743 0.717518 0.839036 0.952136]/Domain[0.0 1.0]/Encode[0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0]/FunctionType 3/Functions[166 0 R 167 0 R 168 0 R 168 0 R 168 0 R 168 0 R 168 0 R 169 0 R 170 0 R]>>\rendobj\r166 0 obj\r<</C0[0.5]/C1[0.5]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r167 0 obj\r<</C0[0.5]/C1[1.0]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r168 0 obj\r<</C0[1.0]/C1[1.0]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r169 0 obj\r<</C0[1.0]/C1[0.6]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r170 0 obj\r<</C0[0.6]/C1[0.6]/Domain[0.0 1.0]/FunctionType 2/N 1.0>>\rendobj\r135 0 obj\r<</LastModified(D:20150720142046-05'00')/Private 171 0 R>>\rendobj\r171 0 obj\r<</AIMetaData 172 0 R/AIPrivateData1 173 0 R/AIPrivateData2 174 0 R/AIPrivateData3 175 0 R/AIPrivateData4 176 0 R/AIPrivateData5 177 0 R/AIPrivateData6 178 0 R/AIPrivateData7 179 0 R/ContainerVersion 11/CreatorVersion 19/NumBlock 7/RoundtripStreamType 1/RoundtripVersion 17>>\rendobj\r172 0 obj\r<</Length 1471>>stream\r\n%!PS-Adobe-3.0 \r%%Creator: Adobe Illustrator(R) 17.0\r%%AI8_CreatorVersion: 19.0.1\r%%For: (James Elliott) ()\r%%Title: (Afterglow logo.ai)\r%%CreationDate: 7/20/15 14:20\r%%Canvassize: 16383\r%%BoundingBox: 78 -440 624 -151\r%%HiResBoundingBox: 78.77249999999 -439.372100000157 623.66276550293 -151.135416666668\r%%DocumentProcessColors: Cyan Magenta Yellow Black\r%%DocumentFiles:/Users/jim/Desktop/Beam.png\r%%+/Users/jim/Desktop/Clojure Beam.png\r%%+/Users/jim/Desktop/Clojure-Logo.png\r%AI5_FileFormat 13.0\r%AI12_BuildNumber: 54\r%AI3_ColorUsage: Color\r%AI7_ImageSettings: 0\r%%RGBProcessColor: 0 0 0 ([Registration])\r%AI3_Cropmarks: 0 -595.2803 841.88957873208 0\r%AI3_TemplateBox: 421.5 -298.5 421.5 -298.5\r%AI3_TileBox: 141.44478936604 -677.640149999999 700.44478936604 105.35985\r%AI3_DocumentPreview: None\r%AI5_ArtSize: 14400 14400\r%AI5_RulerUnits: 1\r%AI9_ColorModel: 1\r%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0\r%AI5_TargetResolution: 800\r%AI5_NumLayers: 1\r%AI17_Begin_Content_if_version_gt:17 1\r%AI9_OpenToView: -92.0000000000009 -113.666666666668 3 2307 1254 18 0 0 46 133 0 0 0 1 0 0 1 1 0 1\r%AI17_Alternate_Content\r%AI9_OpenToView: -92.0000000000009 -113.666666666668 3 2307 1254 18 0 0 46 133 0 0 0 1 0 0 1 1 0 1\r%AI17_End_Versioned_Content\r%AI5_OpenViewLayers: 7\r%%PageOrigin:115 -694\r%AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142\r%AI9_Flatten: 1\r%AI12_CMSettings: 00.MS\r%%EndComments\r\rendstream\rendobj\r173 0 obj\r<</Length 14015>>stream\r\n%%BoundingBox: 78 -440 624 -151\r%%HiResBoundingBox: 78.77249999999 -439.372100000157 623.66276550293 -151.135416666668\r%AI7_Thumbnail: 128 68 8\r%%BeginData: 13832 Hex Bytes\r%0000330000660000990000CC0033000033330033660033990033CC0033FF\r%0066000066330066660066990066CC0066FF009900009933009966009999\r%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66\r%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333\r%3333663333993333CC3333FF3366003366333366663366993366CC3366FF\r%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99\r%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033\r%6600666600996600CC6600FF6633006633336633666633996633CC6633FF\r%6666006666336666666666996666CC6666FF669900669933669966669999\r%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33\r%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF\r%9933009933339933669933999933CC9933FF996600996633996666996699\r%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33\r%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF\r%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399\r%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933\r%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF\r%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC\r%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699\r%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33\r%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100\r%000011111111220000002200000022222222440000004400000044444444\r%550000005500000055555555770000007700000077777777880000008800\r%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB\r%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF\r%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF\r%524C45FD4BFFFD04C4BDC4BDBD94BCB6B693BCB5BBBBC2BBC1C1C8C1C8C7\r%CDC7CDA5CDA5AC81825D5E333A1235123B133C143D365A5A7E5A7E54FD19\r%FFA87D7D27522727F8FD042752527D7DFD22FFC49BC49BC49BBD9ABC94B6\r%93B593BB93BB99C199C19FC7C1C7C7CDC7CCA5CDA5A57B82333411341235\r%133613361436305A537E537EFD16FFA85227FD11F82752A8FD1EFFFD04C4\r%BDC49BBDBCBC93B693BB93BBBBC199C1C1C7C1C8C7CDC7CDC7CDA5AC8182\r%575E333412351235133C1436365A5A5A537E7EFD13FFA85227FD17F82752\r%FD1CFFCA9BC49BC49BBD94BC94B693B593BB93BB99C199C19FC79FC7C7CC\r%A5CCFD04A5815D333A111212351335133614362F5A537E537EFD11FFA852\r%FD1DF87DA8FD19FFFD04C4BDC4BDBDBCBC93B6B5BB93BCBBC1BBC2C1C8C1\r%C8C7CDC7CDC7CDA5CD81825D5E343A123B133B133C1437365A5A7E547E7E\r%FD10FF52FD21F852FD18FFCA9BC49BC49BBD94BD94B693B593BB93BB99C1\r%99C1C1C79FC7C7CCA5CDA5A5A5A6815D333A113412351335133C14362F5A\r%537E537EFD0EFFA8FD24F827A8FD16FFFD04C49BC4BDBD94BCB5B593BBB5\r%BB99C1BBC1C1C8C1C7C7CDC7CDA5CDA5AC81825D5E333A1234123B133C14\r%3D365A547E5A7E53FD0DFF52FD0EF80028282E282F282F062800FD0EF87D\r%FD15FFC49BC49BC49BBD94BC93B693B593BB93BB99C199C19FC79FC7A5CC\r%A5C7A5C7A581575E3334113412131236133614362F5A537E537EFD0BFFA8\r%27FD0BF8272853305B5A5B5A5B5A5B5A5B5A5B54542827FD0BF852FD14FF\r%FD04C4BDC4BDBD94BCB6B693BCB5BBBBC2BBC1C1C8C1C8C7CDC7CDA5CDA5\r%AC81825D5E333A1235123B133C143D365A5A7E5A7E54FD0AFFA8FD0BF805\r%2F305B545A305A305A305A305A305A305A305B542F05FD0AF827A8FD12FF\r%C49BC49BC49BBD9ABC94B693B593BB93BB99C199C19FC7C1C7C7CDC7CCA5\r%CDA5A57B82333411341235133613361436305A537E537EFD09FFA827FD09\r%F8282F5B5A5B545B545A545B545A545B545A545B545A545B5A5B2F28FD09\r%F827A8FD11FFFD04C4BDC49BBDBCBC93B693BB93BBBBC199C1C1C7C1C8C7\r%CDC7CDC7CDA5AC8182575E333412351235133C1436365A5A5A537E7EFD08\r%FFA8FD0AF853545A305A305A305A305A305A305A305A305A305A305A305A\r%305A302FFD09F827A8FD10FFCA9BC49BC49BBD94BC94B693B593BB93BB99\r%C199C19FC79FC7C7CCA5CCFD04A5815D333A111212351335133614362F5A\r%537E537EFD07FFA827FD08F8285B5A5B545B5A5B545B5A5B545B5A5B545B\r%5A5B545B5A5B545B5A5B545B5A5A27FD08F827FD10FFFD04C4BDC4BDBDBC\r%BC93B6B5BB93BCBBC1BBC2C1C8C1C8C7CDC7CDC7CDA5CD81825D5E343A12\r%3B133B133C1437365A5A7E547E7EFD07FF27FD08F82F5B305A305A305A30\r%5A305A305A305A305A305A305A305A305A305A305A305A545B28FD08F852\r%FD0FFFCA9BC49BC49BBD94BD94B693B593BB93BB99C199C1C1C79FC7C7CC\r%A5CDA5A5A5A6815D333A113412351335133C14362F5A537E537EFD06FF52\r%FD07F8002F5B545A305B545A545B545A545B545A545B5A5B545B545A545B\r%545A545B545A545B5A5B29FD08F87DFD0EFFFD04C49BC4BDBD94BCB5B593\r%BBB5BB99C1BBC1C1C8C1C7C7CDC7CDA5CDA5AC81825D5E333A1234123B13\r%3C143D365A547E5A7E53FD05FF7DFD08F82F5B305A545A305A3054305A30\r%5A305A302F00270554305A305A305A305A305A305A305A305B28FD08F8A8\r%FD0DFFC49BC49BC49BBD94BC93B693B593BB93BB99C199C19FC79FC7A5CC\r%A5C7A5C7A581575E3334113412131236133614362F5A537E537EFD05FFFD\r%07F8005AA9A9FD05FFA9A97E5B305B305B5A5AFD05F85A5A5A305B5A5B54\r%5B5A5B545B5A5B545B2FFD07F827FD0DFFFD04C4BDC4BDBD94BCB6B693BC\r%B5BBBBC2BBC1C1C8C1C8C7CDC7CDA5CDA5AC81825D5E333A1235123B133C\r%143D365A5A7E5A7E54FD04FF27FD07F87DFD0BFFA87F5485A8FF27FD05F8\r%52FF847E305A305A305A305A305A305A305B28FD07F852FD0CFFC49BC49B\r%C49BBD9ABC94B693B593BB93BB99C199C19FC7C1C7C7CDC7CCA5CDA5A57B\r%82333411341235133613361436305A537E537EFFFFFFA8FD07F852FD12FF\r%27FD05F852FD04FF7E5B305A545B545A545B545A545B05FD06F827A8FD0B\r%FFFD04C4BDC49BBDBCBC93B693BB93BBBBC199C1C1C7C1C8C7CDC7CDC7CD\r%A5AC8182575E333412351235133C1436365A5A5A537E7EFFFFFF27FD07F8\r%FD13FF27FD05F852FD05FFA85A305A305A305A305A305A3054FD07F852FD\r%0BFFCA9BC49BC49BBD94BC94B693B593BB93BB99C199C19FC79FC7C7CCA5\r%CCFD04A5815D333A111212351335133614362F5A537E537EFFFFA8FD07F8\r%A8FD06FFAEFFCFFD09FF857EFD05F88585FD06FFA95A5B5A5B545B5A5B54\r%5B5B2FFD07F8FD0BFFFD04C4BDC4BDBDBCBC93B6B5BB93BCBBC1BBC2C1C8\r%C1C8C7CDC7CDC7CDA5CD81825D5E343A123B133B133C1437365A5A7E547E\r%7EFFFF27FD06F852FD04FF8383575D3327F8277DFD06FFA95B7E2727287F\r%7F855B85A9FFFFFF7D27002E305A305A305A305B3005FD06F852FD0AFFCA\r%9BC49BC49BBD94BD94B693B593BB93BB99C199C1C1C79FC7C7CCA5CDA5A5\r%A5A6815D333A113412351335133C14362F5A537E537EFFFF27FD06F8A8FF\r%FFA7575D335D5704FD04F87DCFAEFD04FF857F8585857F857F857F8585FF\r%7DFD04F8285A5B545B545A545B2FFD06F827FD0AFFFD04C49BC4BDBD94BC\r%B5B593BBB5BB99C1BBC1C1C8C1C7C7CDC7CDA5CDA5AC81825D5E333A1234\r%123B133C143D365A547E5A7E53FF7DFD06F827FFA75E325D5757572DFD05\r%F8275D82A8FFFFFFA97F5A857F855A855B855A855AFD06F82F545A305A30\r%5A305AFD07F8A8FD09FFC49BC49BC49BBD94BC93B693B593BB93BB99C199\r%C19FC79FC7A5CCA5C7A5C7A581575E3334113412131236133614362F5A53\r%7E537EFF52FD06F8A8AE5D575E575D578226FD06F8888188AEFFFFFFFD04\r%857F8585857F85857EFD06F8285B545B5A5B545B5B2FFD06F852FD09FFFD\r%04C4BDC4BDBD94BCB6B693BCB5BBBBC2BBC1C1C8C1C8C7CDC7CDA5CDA5AC\r%81825D5E333A1235123B133C143D365A5A7E5A7E54A827FD05F821835D57\r%57575D5757572DFD05F82781888182A8FFFFFF5B857F855B857F855B855A\r%FD06F82F545A305A305A305B2FFD06F827FD09FFC49BC49BC49BBD9ABC94\r%B693B593BB93BB99C199C19FC7C1C7C7CDC7CCA5CDA5A57B823334113412\r%35133613361436305A537E537EA8FD06F8275E575E575D575E575D8352FD\r%04F85788818881ADFFFFFFA95B857F857F857F857F8553FD04F8525A5B54\r%5A545B545A545B00FD06F8FD09FFFD04C4BDC49BBDBCBC93B693BB93BBBB\r%C199C1C1C7C1C8C7CDC7CDC7CDA5AC8182575E333412351235133C143636\r%5A5A5A537E7E52FD06F82D5757575D5757575D57FFA87D262D578881825D\r%825DAEFFFFA97F5A855B855A855B855A855327277DFFA9305A305A305A30\r%5A3028FD06F87DFD08FFCA9BC49BC49BBD94BC94B693B593BB93BB99C199\r%C19FC79FC7C7CCA5CCFD04A5815D333A111212351335133614362F5A537E\r%537E52FD06F8335E575E575D575E5783FFFFFF88828882888188828882FF\r%FFFF7F8585857F8585857F8585857FAFFFFFFF5B545B545B5A5B545B2FFD\r%06F87DFD08FFFD04C4BDC4BDBDBCBC93B6B5BB93BCBBC1BBC2C1C8C1C8C7\r%CDC7CDC7CDA5CD81825D5E343A123B133B133C1437365A5A7E547E7E27FD\r%06F8FD04575D5757575DA7FFFFAD5D825D8881825D888182A8FFFF855B85\r%7F855B857F855B857F857FFFFFFF5A5A305A305A305A3054FD06F852FD08\r%FFCA9BC49BC49BBD94BD94B693B593BB93BB99C199C1C1C79FC7C7CCA5CD\r%A5A5A5A6815D333A113412351335133C14362F5A537E537E27FD05F82657\r%5E575D575E575D57FFFFFF8288828881888288818881ADFFFFA9857F857F\r%857F857F857F857F85A9FFFFA9305B545A545B545B3000FD05F852FD08FF\r%FD04C49BC4BDBD94BCB5B593BBB5BB99C1BBC1C1C8C1C7C7CDC7CDA5CDA5\r%AC81825D5E333A1234123B133C143D365A547E5A7E53FD06F8045D575D57\r%57575D5757A8FFAE825D8281825D8281825D8281FFFFFF5B855A855B855A\r%855B855A855BA9FFFF8454305A305A305A305AFD06F827FD08FFC49BC49B\r%C49BBD94BC93B693B593BB93BB99C199C19FC79FC7A5CCA5C7A5C7A58157\r%5E3334113412131236133614362F5A537E537EFD06F82D575E575D575E57\r%5D82FFFFFF818882888188828881888188FFFFFF857F8585857F8585857F\r%FD0485FFFFFF545B5A5B545B5A5B5427FD05F827FD08FFFD04C4BDC4BDBD\r%94BCB6B693BCB5BBBBC2BBC1C1C8C1C8C7CDC7CDA5CDA5AC81825D5E333A\r%1235123B133C143D365A5A7E5A7E54FD06F8265D575D5757575D57825252\r%5181818281825D8881825D81A7FFFFFF857F5B857F855B857F855B857F7E\r%52527D5A305A305A305A545AFD06F827FD08FFC49BC49BC49BBD9ABC94B6\r%93B593BB93BB99C199C19FC7C1C7C7CDC7CCA5CDA5A57B82333411341235\r%133613361436305A537E537EFD06F82D5D5D575E575D5757FD05F8828188\r%82888188828882FD05FF7F857F857F857F857F85857EFD04F8055A545B54\r%5A545B5A27FD05F827FD08FFFD04C4BDC49BBDBCBC93B693BB93BBBBC199\r%C1C1C7C1C8C7CDC7CDC7CDA5AC8182575E333412351235133C1436365A5A\r%5A537E7EFD06F8045D5757575D575D04FD05F82C885D8281825D825DAEFF\r%CFA7FFA9855B855A855B855A857F8505FD05F8285B305A305A305AFD07F8\r%FD08FFCA9BC49BC49BBD94BC94B693B593BB93BB99C199C19FC79FC7C7CC\r%A5CCFD04A5815D333A111212351335133614362F5A537E537EFD06F82D5D\r%5E575E575E5727FD05F8278188828881888188FFFFC8ADFFFFA9857F8585\r%857F8585857F27FD05F8285A5B5A5B545B5427FD05F852FD08FFFD04C4BD\r%C4BDBDBCBC93B6B5BB93BCBBC1BBC2C1C8C1C8C7CDC7CDC7CDA5CD81825D\r%5E343A123B133B133C1437365A5A7E547E7EFD07F85D5757575D575D04FD\r%05F82688818881825D82A7FFCAC15EFFFFFF5B855B857F855B857F8500FD\r%05F8285B305A305A305AFD06F827FD08FFCA9BC49BC49BBD94BD94B693B5\r%93BB93BB99C199C1C1C79FC7C7CCA5CDA5A5A5A6815D333A113412351335\r%133C14362F5A537E537E27FD05F826575E575D575E5D57FD05F882828881\r%88828882FFFFC3C182A8FFFFA97F857F857F857F858559FD05F85A5A5A54\r%5B545B2FFD06F852FD08FFFD04C49BC4BDBD94BCB5B593BBB5BB99C1BBC1\r%C1C8C1C7C7CDC7CDA5CDA5AC81825D5E333A1234123B133C143D365A547E\r%5A7E5327FD06F857575D5757575D5733262727835D8281825D825DAEFFFF\r%93C75784FFFFA8855B855A855B855A85857D2627002F305A305A305A542F\r%FD06F852FD08FFC49BC49BC49BBD94BC93B693B593BB93BB99C199C19FC7\r%9FC7A5CCA5C7A5C7A581575E3334113412131236133614362F5A537E537E\r%7DFD06F82D82575D575E575D5783FFFFFF888188818881ADFFFFC3BBC7AC\r%35FFFFFF85857F8585857F857FAFFFFFA95B5A5B5A5B545B5A5B28FD06F8\r%A8FD08FFFD04C4BDC4BDBD94BCB6B693BCB5BBBBC2BBC1C1C8C1C8C7CDC7\r%CDA5CDA5AC81825D5E333A1235123B133C143D365A5A7E5A7E5452FD06F8\r%2D575D5757575D575733FFFFFFA78181825D82A8FFFFBC99C78134A8FFFF\r%AF5B855B857F855B85FFFFFF85305A305A305A305A3027FD06F8A8FD08FF\r%C49BC49BC49BBD9ABC94B693B593BB93BB99C199C19FC7C1C7C7CDC7CCA5\r%CDA5A57B82333411341235133613361436305A537E537EA8FD06F8045D57\r%5E575D575E575D82FFFFFF8288828882FFFFFF93C1C7CD3384FFFFFF857F\r%857F857F85A9FFFFFF305B545A545B545A307EFD06F827FD09FFFD04C4BD\r%C49BBDBCBC93B693BB93BBBBC199C1C1C7C1C8C7CDC7CDC7CDA5AC818257\r%5E333412351235133C1436365A5A5A537E7EFF27FD06F8335D575D575757\r%5D5757A8FFFFCF5D825DADFFFFA1B599C7A55712FFFFFFA8855B855A857F\r%FFFFFF5A54305A305A305A307F7DFD06F852FD09FFCA9BC49BC49BBD94BC\r%94B693B593BB93BB99C199C19FC79FC7C7CCA5CCFD04A5815D333A111212\r%351335133614362F5A537E537EFF52FD06F82D5D5E575D575E575E5782FD\r%04FF8188FFFFFFC393C2C7CD571385FFFFFFA9857F8585FFFFFFA95A545B\r%5A5B545B3085FF52FD06F87DFD09FFFD04C4BDC4BDBDBCBC93B6B5BB93BC\r%BBC1BBC2C1C8C1C8C7CDC7CDC7CDA5CD81825D5E343A123B133B133C1437\r%365A5A7E547E7EFF7DFD07F85D575D5757575D57573283FFFFFFCF82FFFF\r%FF93BB9FC7A581113CFD04FF85857FFFFFFFA85A305A305A305454A9FFA8\r%FD07F8FD0AFFCA9BC49BC49BBD94BD94B693B593BB93BB99C199C1C1C79F\r%C7C7CCA5CDA5A5A5A6815D333A113412351335133C14362F5A537E537EFF\r%FF27FD06F82D5E575E575D575E575D33ADFD06FFCBBCBBC1C7CD81341385\r%FD09FF85545B5A8584A9A9FFFFFF52FD06F852FD0AFFFD04C49BC4BDBD94\r%BCB5B593BBB5BB99C1BBC1C1C8C1C7C7CDC7CDA5CDA5AC81825D5E333A12\r%34123B133C143D365A547E5A7E53FFFF52FD06F826575D575D5757575D57\r%573282FD06FF93BB9EC7A58133130D84FD08FFAFFFA8FD07FFA8FD07F87D\r%FD0AFFC49BC49BC49BBD94BC93B693B593BB93BB99C199C19FC79FC7A5CC\r%A5C7A5C7A581575E3334113412131236133614362F5A537E537EFFFFA8FD\r%07F8515D5E575D575E575D575E5782A8FD05FFC9C9C8CD815E358584FD12\r%FF52FD06F827FD0BFFFD04C4BDC4BDBD94BCB6B693BCB5BBBBC2BBC1C1C8\r%C1C8C7CDC7CDA5CDA5AC81825D5E333A1235123B133C143D365A5A7E5A7E\r%54FFFFFF52FD07F857575D5757575D5757575D3357A1FD07FFCFFD16FF7D\r%FD07F87DFD0BFFC49BC49BC49BBD9ABC94B693B593BB93BB99C199C19FC7\r%C1C7C7CDC7CCA5CDA5A57B82333411341235133613361436305A537E537E\r%FFFFFFA8FD07F8045D575E575D575E575D575D57769AC3CAFD0BFFA88357\r%A783FD09FFAEA8FD07F827FD0CFFFD04C4BDC49BBDBCBC93B693BB93BBBB\r%C199C1C1C7C1C8C7CDC7CDC7CDA5AC8182575E333412351235133C143636\r%5A5A5A537E7EFD04FF52FD07F8265D575D5757575D5757337C70948CB599\r%C9A7CFCFFFA8845F602F2E2D5D3257575D575E5782575D575DFD08F87DFD\r%0CFFCA9BC49BC49BBD94BC94B693B593BB93BB99C199C19FC79FC7C7CCA5\r%CCFD04A5815D333A111212351335133614362F5A537E537EFD05FFFD08F8\r%2D82575D575E575D5782769A93B6B5BBC1C7C7CDA582111213362F525782\r%575D575E575D575D575D26FD07F852FD0DFFFD04C4BDC4BDBDBCBC93B6B5\r%BB93BCBBC1BBC2C1C8C1C8C7CDC7CDC7CDA5CD81825D5E343A123B133B13\r%3C1437365A5A7E547E7EFD05FF7DFD08F82C5D5757575D575D519A6F9393\r%BB99C19FCCA5A5573A123514352E58575D5757575D5757575D26FD08F8FD\r%0EFFCA9BC49BC49BBD94BC94B693B593BB93BB99C199C1C1C79FC7C7CCA5\r%CCFD04A5815D333A111212351313133614362F5A537E537EFD06FF52FD08\r%F82C82575D575D5776709A93B599C1C1C7C7CDA5823334133C132F2E5D57\r%5E575D575E5D5D26FD08F8A8FD0EFFFD04C49BC4BDBD9ABDB6B693BCBBBC\r%99C2C1C2C1C8C1C8C7CDC7CDA5CDA5AC81825E5E333A3435123B353C363D\r%365A5A7E7E7E5AFD07FF27FD08F8045D5757337C709A93B593BB99C1C1C7\r%A5A5815D113513360C2E2D5D575DFD045704FD08F852FD10FFCAFFFFFFCA\r%FFCBFFCAFFCAFFCAFFCAFFCAFFCFFFCAFFCFFFCAFFCFFFCAFFCFFFA8FFAE\r%FFA8FFAEFFA8FFAFFFA8FFAFFFA8FD0BFF27FD08F804575D82769A94BC93\r%BBBBC2C1C8C7CDA5A6573A123C14362E52575E575E5D57FD09F852FD4DFF\r%A827FD09F82D519A709493B593BB99C1C7C7A5CD815E113413360D2F2E58\r%575D5727FD09F827FD4FFFA827FD09F8204B9A94B693BBBBC1C1C8C7CDA5\r%A65D3A123B14362F532E572C26FD09F827FD51FFA827FD0BF84B69B5BBC1\r%C1C19FCCA5A581823312123C14360627FD0BF852FD54FF52FD0CF8206F99\r%C1C1CDCCCDCCCD815E12350C2E05FD0CF87DFD56FF7DFD0FF82626515051\r%2C2D0404FD0FF87DFD58FFA827FD23F827FD5CFF5227FD1FF8277DFD5FFF\r%7DFD1CF827A8FD63FF7D52FD17F8527DFD68FF7D52FD11F8527DFD6EFFA8\r%A85252FD072752527DA8FD56FFFF\r%%EndData\r\rendstream\rendobj\r174 0 obj\r<</Length 65536>>stream\r\n%AI12_CompressedDataxu5\u0004\u000eg~\u0018pc%\u0006\u0014>\u0018 L}\u001aȶ1A}.QUmg_#v\u0004y.ݧl)7-O&$\u0019\u0011Z/oͫ߬\u001f_zWwo޾\u000f;?EoƯ|~uW+\u000f<zǻ7?}oͧ??ݽ}W|;-^\f_ηqw7\u001fs\u001f}w\u00170}ٶ]_w_\u000e\u000fEn'~\u001bU3Ծ\u0006xwﺪ\u001a+t1fOw~7\u001f?߾Ww_^[xѼ_>I_.ûg^ot_N|ӝoͿˏo~\u000f?~op\u0016mO\u001fC|\u000f|u\u0013Gx=~~~xo߽\u001b\u0006.l\u001f޻/{UUs78N0\u000eM]w\u0015\u000f\u0016n\u0002bm_uw_\b?\u001fZl:\u000fjv\u0018+\u0005axշ\u000f\u0017{\u0015^54ʖU7?w'p+\u0006;?O|OO߿<E?}Mg?'Y߿\u0013\rQ\u0000W路|Aw\u00178`?>~߿/\u001e_W~\u001f?Gr_U\u0001wxxM\u0005;85#\u001da\rd\u0007?H0ңvkzhs=o\u0003ܮ\u001b\u001f?\u0013+\u000fʗ\u000fowPߍj~n}︡g]\t>^ͨ^WQ[#΁x3H\u0017~O\u000b6pWÛwM\u000f߽\u0011\u000f7[\u0007?_noa2O^ ??|\u000eWxOi?.X_݇?ǛoJ)?\u0001\u001b\u0014V\u0015S^WE,\u001dk\u0003y\u0001Gs\u0001\u0007Vo\u0013\u0012y\u000f\u0005p,\u0003驽{\u0005_7\u000f7pl\u000777~p\u001f>?IuNn\u000e}fyp\u001ex\u00160?wa{g\u001d\u001co珟0S\u0005=0_wç}\u000fe-[aa\u001b\u0017/m\u0011ܿy-~|>=\u0001\u001dﻯ\u000f_\rv\u0015/[ޙ\u001f^\u0006:\b\u001a;\b)N/\\YXǻ[eYV\u0013\u0006v^kz\u001aY[\u000e\u0007\u001b֑lZgeiΧ\ñԀ\u000e?\r`i\u0002q\u000f\f\u001fy<X5`֑d\u0003ظM\u0019ll'0|:{\u0001kϝXO6\u0018\u001b\u001d|zzOww\u000ft\rKsomiovn\u0004[:𼺾\u001b3_m}}wO_lC5C;O\u0002<\u0019\u001fqsf\u0001|\u00056Ws=s?\fs[^ڥ_\u0006LpQNp!\"t'8':5[<xFOt\u0016k8wx&8Mp|:\u0003WMZ\u0017kwYOxJAI\u000fe__oڪ\u001e{/G?3?>\r\t\u001fY3\u0001\u001bZ`QXhp&\u0001ac\u000b!~{\u0001\fk?`\u000b\u0018\u00174q0Ә#quSd0j\u0018;0\bq\u0018AH\u0000qiҁyព\u001f\b\u00046\u0001\u000f\ff\u0000j~3L\u0015i5\u0010\u001ba0Z\u0018t5\u001cj5m<쵌3\fq\u001c``vc\u000bC\u001e\u001b+$6\u0018+\u0019F8\f0;\u0018\r\u001c\u001f*P6\u0018K?S?a0\tp^*t6\u0018V\u001ef$F\r0_t0k4=ܳvd\u0019en'[\u0006a:\b\u001b8+``Ya\u0016\t\u0001fi\u0003ć&љ&ԑ&מ&ږ&ݚA6iWa\u00026|8Lp6o\u001dL\rkt\u0015N0\u0005\u001f3@\u0002j\u0019`B\u000e&vi\n;g><p\u001d\u0017f7OpQKC\u0017G.\u000f_ D|2K\u0005\u0017\u000b>p{7_/\u001fsgTv\u0006k`>3\u001d-TB%̧ѹdeT\u001bzcX\u001bIu9Ӳ5\"k0,eg\\\u000f\u0018b<ļ\u0019?\tu9\u001d_q`\\T/I\u001b\u0003lE#gq\u0005ŋȣ\u0002@Ey\u001fo{=x<tt[Wt3<m3\t\f-=+0]0dDa\u00129$2\u0004`i8Ѽ1\u0013F\u0005\u0005N\u0015\u0013L\u00138I0Al2901p<̎'\u0018\u0013̡=\u001d]\u0015f\t\u000efnܞv1\b@\u000fB{\u0005׭nԪ\u000bgCU\u0005j.\u001a`͡lNI`\u0005ᷢu xwE\u0018\u001c\nVCt[X\u001d{GgO~\u00110>\u001b\u0018\u000e\u001d\fyX\u001c\u00133x)\u001eN\u0003#\b]\u0001F\u0004;]`V=\n~\u0006\u000fhk`u0\t3\u0015j\u0018x^\u001bG碧`}Z`\u0004`:aT7umH`[(\u0006$ȧ\u0007Is@\u0018ft\u0005JK\u0000vK\t\u001cs1jX[\u0001\u0006\u0005&4h\u0014Pđ`'g\u0018g[:xW>\u0004;9#pr,,g\u001a5m<Nε\u001cM>|Y>aOZ4l\u0004\u001c~\u000e\u0012~N!\u0004]d]>I .kx\fs:\u0016\u000f\u0005\u001e\u001ac8>\u0004'WO<?g>.S\u00185ڨ\u0002c0\u00060lAQ\u000bD\u0006o\u0010rİ\u0003\u001fx\u00181\u0003M\u000eG`\u0002z;t m%)[Y1\u0001FklN~{Jl;ヿc3v2ԟޝ\r#ӣvr=4se=^&_\u001a2޶3'dL|ڿxe7Pv!F\\Hr[\t<+\t:W\t8Gq[3+1W/9$\u0018S:\t)1#w6ƿ1?]\n]\u001a?=w\u001aC\u000f3-\f\u0019XVpgr\u0007X;v1ޢ`\r\u0003|\u0011&Ğ|\u0006p\u000e\u000e&\u0013M84?lЬ^uT\u0002\")Y\nZ\u0018%\u00104NBm\u0017k\u0013X\u0002\u0018:Kl\"g\u00131,X!r-~u\u0018#(Y\u0019\u0006'581Hr\u0013\u001c$9ZT\u001aIvVI̩\u000f'@8\u000fp.n_Q\"l$G:Ip\u0004vVI΄\r\u000fn,\u001bhuzcC4\u0007w`X\u001aq,ld24hme\u001bK|{`D\rFc1\u001b\u0018u´&D\u001e9ZW\u0019j\u0017\u0013!p<\u0000Q&G\u0007#y5\u000by3gJԔ\t(1Rt\u0012b1\rIMЗ~5gMd_T&?9\tXaׅ\u0018\n-ȟ+x3ntt͸\r[up<egJݬY\t\u001e:Ή^>[\u0006z\u001b\u001b\u0017\u001aHdIq)\u000eȓl1/i蘌V\u0012;GK%4Fiw;\u0013yH\u001ch\u000e*,\u000e4tKpO iLgѴ^Z&g)\u0015\u0013MWgK9\u0007+9kOYGt\u0010&W\u001eVzhj\u001a+X͙nN?J[ݚϹݿ|a\u0013W7d󣴟nn\u00172\tIĦSkb\u001cCXǧPwt^\u0019\u001do/:5^qY+.∮ :\u0006\u0013I\u0016v O'\u0006@_=n\u001eWrc;гc\u000egЛ\u001b(/4\\\u000bQo\\\u001e\r\u0016GlR%\u000bs\u0019;[2\u00039avgY\u001d\\{\u001e98ϕ\u000b۶f\u0015fSd0gvgF|\\`;7;k\u0015ߛp\u000bI\\쭘ƫZt\u001a]Fr!7nKr]\\+2YIauϛ3f~\u001cnӑ=V,`G\u001b\\\u001ec+D\u0004\u0005Ǩ\u000bW\u001dX6a\r8'\u0016\u001e;uko-\u001dͥQ\u001f\u0011Md`\u0019]p8~Dk\u000b>\"fN\u0010a\u0010[LpM\u0011\u00060Sq\u001e\u0000\u0018+\fzOE\b\u0004=!䩁q=ކ@ƶ\u0005\u0016\u0006FH\u0010 N#\u0001\u0002o`\u0000b\u0019ACnȦ\u0006\u0006\b\n>?5@M\u0013A64*0=k殿h\u001a\u0015\nMew\u0019F4\nѼ&\u001d\fXC\u0015R\u001d>-\u001a \u0016!7\u0002qA\u000fNOx9F3gP2ϒ=s\u0011#\u0013gqW\b\u0013zƮ\u001d(a\u001cfU\u0006U{\u0011<8|\u0006B\nxJUեa\u001d>sٺ\u000e;x`Ph\u0000rtHG8C\u00038\u0018j\u001bތ<#\u0006\rs_zPrɫ\u001b\u001az?\u001dvl\fyn#y5G\n\u000bx33c8\u001f)f\u0018|\u000f\u0001`M\u000fw&4<\u001d\n\\\u0007j#\u0013\u0004c\u000b7 Dx$\u001cUG\u0014d}]Oɪ8\u001a:/\u001e\"'\n]3Э75=qN;\u0013s08a\u00027\b\u0004{\u0011n\u00037+nGҍ๦{q\fhTp\u001e'\u0018S-j\u0013\u000b\u000b^VA,\tUW\bb\u00180iPG2egҴSŗn̈NI\u0013y\u001c\u000e\u0019kvQ\n\u001fԶ0U7xAHZ\b>f\u0005G\u0012gݱ\u001d\u001fIװ\u0000@՛\u00139\u001c\u0017\u0018-\\\u001e_a\bӝ:U0a9_y\\\u0006nk!Pv\r&7|&;p$\u001f.\u0019\u001c\u0017\bpej\u000e\n:\u001esXۺi\u0006aaF>ݍZŋ\u0001{[K!\r-\fW0yHXMSrf>sBӇu\\Ll;AwoǏw\u000b\u0005GhGvkϺ\u0011svF_\u001a@\r!&j%\u0011%Iٌ\u0015vkAr1eo)zw(x;ImzڜLjMHLF\\{o?%x-(DEY9r]fNv(\u00199\u0006{pz\u0002Ҧtw td9!\u0019,=ɡJaQ1rIʑ7d\u0016]9h\u000f+kEW4^{h̓FC\u001f\u0002c[Ls]Jڑ)*VЅ\u001btH=ÊB>M\"\t\u001c\u0011u+L_a-C\u0000\u0007\"yu\u001bu`\u0003w*7{M^n:\r+5l)\u001171,w+L9)KN)rMsz\\ij\u0013&-\u001dqJE8tV\".\u0015f)u\u000eiq\u0011IK\fϺi6RnW|4]Nsc\u0006.H72`ӂWRsI*Pu\u001b͋\r.\u001cv\u0012\u0001TzD.{-5l5\u0006#\\n,3\u001c$\u0004W(.P\r>$\u001ey\u001cmMhP[[\"1[\u0007>~$>\u001d#'\u0011AhWLֻDb='\u0015hW?Eb_`ÅJޝY+.Kr[\u0019*aSƂ\r0i+Xr\n?؃O1Ms\u0001\n\t\u0013k\u0013OƦ0*5n)/R%\t7L\"T\n2&M4\u0017:\u0000N\\Uu\bs\u0013E6#/RG[CqJaÔ\u0016cj:t(fahLNÊ\u001f)S\ro`.\u0019g`ek\u001a/8y+8\u0002oYr\nu4ͱgKU\u001b$/\tbI\u0012t\r&ZMD +M\u000bGj\u0019\tj\u0010LʊB\u0013\u0001;lV^\b3jK]4y$N1\u0003M}n$h>Vz\u0014\u0016*gOԩ0R>lE\u0014Gh]()%@U\u0019<iҫeKN\u0012T\u0015ѵ$7U+A!\u0000\u0002\u0011S\u0005g'.\u001afH]\u0018-\u001d\u0012d\u0011w\u000443\u0002g8`1Nwf\u0019g\u0004\u0001\u00160\u0006r4p \t>\u0019̌Hs؎9f\u0010qP1@0 \f4\u0014ALR\u0002ZjMu\u0019\u001e\"'9\u00161\u001cmϬ\u0004uf\u0018цi(V֕:?0;S\\\u0011b\u000eͮ]s%˹.ŶWB/Ik\u001b\u0018IY\u0018V𐚂CTt\u0013|\u001c9e\u0015b\\;)ev5x%n#:uޗl~Rlc\u0005nE\u0016Z fqp/ƐE\u0003\u0016dV'\b\u0013N&\u0010\u0000n<gbG:;\u00046T82\\\u001e\u000fCDG7\u0000˱w8\u00033qdtR\u0017S\b7TTxtNo`<Q>\u0018\u001f}\u000e7\u00141JhPtVܥ>:L\u0014bsvq\u001e\u00163/\"5BH/\\ HK\u00125R\u0016?!kC=\u00126\f3\u0018\\۷Q.KJ;]<\f\b\u0005-o7Rbi`P\u000e\f{cK9P7v0V \u001b\u0011\t[\"m\\\u00137z\u0005/bɴsW\u0015tvg8\u001b\u0017\u0017\u000fVN3ږ\u0011HnEg$sE\"\u0001\u001d!\u000ba\u001f\u0004tUzళnGĹ\u001fB&sKVa#\u0005=0OQ\\\u001e\u001f͒6$@\u0005\u0015Ac\u0006\u0013 `P_[==-%e\u001c%x.1\u001e|\u0004?ni\u0018S\nƜ\u000ey\u0000N\tbF=\u001aas{ex\u000e\u0006l>DQ!0\u0006\u00069\u000e\tF\\}55U\u0010y\u001a<¹\u0018I\u0010pn\u0002\u0002\"$#\teϥrD\u001blWp;q#\\ɩm-\u0013fp+\u0002\u001d\u000ew9ҟu9a҄\u001b4#и\u0004'm\u001fpF\u0002\u001dpt\u0016G\u000f\u0010w<ݍ&%aVQ\u00057iB\u001c\u000eO\u001a\u0010  \u0004_5xWv-T5=w0*X\u0006Vk|\u0016˻\u001d\b/$Wܦ`!KDrcj\tr%H\"e .\u000e~b\u0013\u000341AOr\u0014\u001bBo\rx~PGx\u000eB\u001f)\u001ci\u001fuς\u00159Q|E`\"\u001a\u0011͚\u0018rDk*Q6=57Bd\u0012asȡ\fC|Y<0-X\ry\u0003\u0015%D^z6\u0015AEp\u0012|\u0015\u0006\u0010tf?YrSkI-f)\u0004\u001ah̑+&tecv=rBzdJ]\u0004fȬ\f;=>BRb%.\u001d\u0018|{:@ \u0007cf]N}c\u0017; s`pf5\u0006cPhi32w6\u0002ڴ9P;\u0016p^uR\u000fgqآD'v*Q:in&crr\tӞ)nM\u0005Ʀ\u001a9U>hfMШ:!Y\u0015í_\u0013\u0003PʹĖ\u000f!\u001a.\\\u001fK\fδ\\6D6%g\u001c\u0007'\u0006w:Y%v\u00052;gZ\u001eY9\u0017ǡc\u001cA\u001d\u0000kf\u0004\u0019\"kr8#Gd\t\u000e6ټI/\u0011s\u001eH\u000b3:\u0000wк~#|-4=v݇1x/!p\u0013\u0006$1\u001d\u0006Ӡ=ŀ=)\f-j,v\u0004K`\u0000\u001eTCն,A\t;^GmI\u0010Q\u0000$\u00036x\u0007\u0014.\rF\u001e\u0016F7ۆ0\u0012ʧ\u001fm/E]\u0002 yK\b\u00047\f\u001bxM\r\u0013H5 bǷ-\u000bl<NE0lq\u0001K\u0004,]\u001a\u001cSqaiV\r\u000bOO[:I\u0006v1/E8ˌt8\u001f543wŉ),ywՎ \u0003oݺ@E\u0015xb\u0014\u0005\u0002\u0007\u001eÚ:*ڠ\u000fTnT{Q\u000e~،l\u0019\u001caV\u0005'>'/[\u000b-~ZbR#JD{f\u0001ށr=0\u0012I:StSiK\u0015˫t&V(A\u001f\u0014]+ZFZ,+8NLi\t\u0004PbxPo0F)tP\u000ex\u001dkL6i#\u00172(1B\u0013\tFl@2\u0015BRR\u0014=hqo>1Z\bN\u0010v JjJS\u0000jSsfm`<x\u001c-\u0019\u0014V\u0007\u001dդ\u0015-{1/w\u0004ՀG4q\u001d\rjziji\tո\u001e\u001ax\u0015EPU\u001b\u0014IWEnaDeL\u001c\u000feԯv\u001c\u0014ϡ\\O\u001eW\u0017\u0013\u0007\u0012\t\u000f6\u00166m\u0007\tP?x+f{.N\u001bp35Йh#v&g\"~&\"h\u0014C\u0013P4s\fl@\u0016\u0010\u001a᠚\t9$$#j\u0011\u0010BBKZ(xjSHH\u0000-\u0007w!\f`:~-|/,\u0007Ip\u001d;B\u0007\u001d&+M\u0006\u0014֑Ě4QIX\u001e?\r\u0006GNZ=z\u0010\n4\\$\u001f\u0014Ot[\"1_;|A\u001cv#MZW=XJղ\u0014r_\u0015b\u0012˧h8ZدjXMdiO\u0005E*ceT[&˸\u0003}׽kTvM\u0014]s9WWPq:~IE\\[\n\u001a:G\u0011*\t25(՜L1>b2V0L&\u0010ThX\u001d&\u0004,\u001b}eޓ˔mVS:G:c7Qj2NG8\u0010\u000e:PRE=.ꎮ\u001aۄP7U\rnǨk.ir~\\U\tqYVyK]Γ\u0016tb%7mRM\u0004uR\u0019\u001d?]IrD\u0017Vm\u0016\u001bpR\\qNKgt>#Twk޵\u0010]\u000bԍ5\u0000w-|wtFV\"y-l1\tWZ\u0005e\u0016\f&r\u0019\u001b2\\#n՟σJJ\u0007/\u0015\u001c\u0013\u00071m\u0010\u0006\tl>\u0005Ib:\u001c\u0006$MhP+jˤhlrf%YYvNa\u001f$M(#q\u001c\u0005>Y〰<\r\u000b\u0017ulެ2FN\t^H\u0016}]M\u0019\u001eYpzj)_Lԅb\u001eX/\u0001FÞz_\u000bt3V0u\u0000&sJ&#\u001c\bP\u0002\u0001\bwX\tpbh\u00058M=v[3DWWvSXT8\u00065O\n\\2{a\u001866\"0M=\t'8Q|0\u0011'uRoYԟi\u000fɒ.oݿܿ}Oݛw͎3\u001d_H\u0019ƅ&M\u001f=OE|\u0007\u0018\u0015ͅ)(mhb!\n+z/:Z\u001b%ld\nKP\u0016H\u0012>ub}A\u0002\u001f֨:`\u0014<ע&*0a\u0003e\u0011eՑ\u001b6$O%\u0017(\u0011\u001c\to^\u0010dq\u001ao3V17J|f􏕦|\u000f)w\\\u001fY\u0013\u0010!Ϩ7t\u0015䕀'*#<Y3\u00110e\u0001*SYuO*6\u001f#zBd@Z\u0019^W\\)rޘM|I«`؛\u0011\u0011W\u0005IK\u001d7򞺋5_P\u0015?zF뾱k \f\u0012\u0010B\u0010'tg d4Yl?wS$\bC\u001681\u0010i׊\u000f,2C\u0016\riHF\"?:\u0007a\\ԋ\"\\s13Ӽ\u00078mEeoHd<ɀ\tyf꿌\u000f7\u0017xj.8礩 x/\u0004Ǟb!\u001b\raHz\f\u001ez\u000ekq\u0016}>C\u001a\u000esq~\u0015p&\u0018ҡ;T6dhnvI+J(\u0005m>k\u001cW l3UF2i%2T2\u001c/w\u0017VP!\u0005\u0012\u001bΎ\u000bg\\\n\u0010gS(p\u0012M3'a\u0019a\u0002af)*=G\u001cNC\u0018m)߇/I5\u0016`rCJ#x~qsD[sM\u000f9ea?sDU6{\\zǵu܅|\rKնolL)7H7t\r\u0010\u0002]D\u0017GVR\"ͪ\r\u0017?z4aM%\u0004hE++ȗɳ\u001fi\th1Y\u0006W\u001d\u0014@\u0017im\u0012=%\u00033W\u0014>D\u0010\\\u0004CX\u001d';Os}\u0000fؗR\u001a|,۽RKKWAe/5TL\u0001P\u001bٮN\r@br[\t\u0016Q8Y%q\u0013\u001a\u00118D~ªQ<\u0019rSKld+uk\u0015I^fp\u0014\u0004h9\u0012'\u0000C'e\u0007\u0015*n\u0005ZwAK\u000e9\u0013ͱ\u0017\bLS[I(؊Vc=̭չc\u001cޔhc6PY~O}<G%(\n^xh:=g\u0016o\u0001g˵1\u0007\u001cڈ5$\u001a)\u0007T\u001a>i8Q\u001e\u000b\u0016\u0005_.b\fW\u001aiHg\u0011c@\u0010CDƋ\u0017r@EBL\u0013R4\u001f錜L#<W\u0010/\u00170ݭTT/\u00058uQ4POStHA\"\bG\u000e}rtLtsrP\u0006=Ͷ\u0004\u0001$-\u0010\u000f\u0015g\u0014Vv\u0016\u0010tuw\u0016\u0016\u0004Ŭɕ%\u000f)>\u0003XZ\u00022ݲʜsIJM4r+lȖluj\u0017Y*B,\u001fSM\u0010J<*'8\u0004D\u001ayv\u0014x\u0015a\u000bEp;S/F\u000fJ-\u000f\u0016Y6&\n;\u0007Z<xh)4i\u0011\u00046=Szr\u0014Y6Zs*\u0016z\u001a\u0013U\u0017JKt\u0014㕭\u0003΁L|)̙|\u0017\u0001?r|m!\fi>INùPz5N.8S\"lQ\r\u0015\u0005\u001b\r\u0005Z%\u001d[DL\bf\u001a$Pl[C}+\u001e)xkO.\u0017QR]22FJ\n<.Y\u0017$cՀqГρ2fzZhk\\jKy=U](p#Fن<}QI\u001bWB5zY:\u0017J-\u001deњKTT.n~\tT\u0014{]E=sO!0YR1\u0016nWV'\u001d9\\g}ާv[xnۖ\u001a]-Om&&sȳN$[b+ʴlBc\n5ccBrlhy]\b\f5\n=i'С:!m6oΐ]v;CS|͊\n:%v~8\u0018+Oe\u000f3\u0004,8Q|dx11⟘ℳ\u001d.LYM\u001cҤDĵ\u0018%*rU5TP@-\u0014y$Kk2+vl<*\u000e<\u0000QzxJFB8Z\u0013yU!p<KéB(\u000bUPI.Boy\u0017I\u0004FREIc\"`O.PUE[6_6Y.daE` \u0003\u0014\u00108w\u0006\nbvd\u001d}>}p\u001c\u0006\u000bm\u001fv\t[[/\u0019݁a\u0013]u\t^#'\u001e\u000b\u000es\\dqG\u0016/\f\u001eN\u0016Q\u001et'\\\u0002@b\u0005y-\u000e99~$\u0018q-ڎ)5^1\u001bcec\"~o.:\\6s<1O=R\u0014_3N\u001e\u0001\u001e椩v!\u0001<vM\u0015o`\u0007.YW//\u0013\b/3ʼ\u0011\u0010\t5\f\u001f{2!6|  i\"}$liޱ\f\u001c\u0017v=\u000e*X\txC\u0010\u0011ނ\u001f3N{\u0002.m6\rc\u0007\u0014\f\u0000!٩O\tf\u0012ߖ%h\u0001\fݫ\u001a\u0002pKNr\u0007!=cM\u001d\u0006\u0012\u0006O}\u0000\r\u001e\u001bǈ\r2|\nO\u0015\u0006o\u001c\u001d\u001e@o/\u0017\u0003`xŇo\u001cMr{St߽M\u0007!$?ڃwK}\u0007?뷈\u0016#\rk\u001dQJ\fzڑ\u0006Paӹ*d`}XO܏ʩo{ ]\u0018U=iXCN\nM;K\u0011<if\u0016\n\u0015t.f\r\u0010b6S\u0005\u0018\u001b\u001dyƿ\f6\u0015ߌ8\u0015\u0004~]w\ntAݦ{E7݁K\u0010\u001dϙִu<~\u0006ՙ{\nZMbZ\u0013OB\u0014GR\u0014)^B'ur\u0015:\u0014uLd粖Iժ\bz\u0015<Φ\u0017=7>кΆKh8Al\u0019vf\u0004\u001d\n=\u0012\u00070M+p(`-\t\u0003r 4rаt\u0016\u0016qm\t\u0017Cb-mhٔMLׄ\u000b{Z\u0005[eZmK6#h+F\u0011\"71rw^͓ğf2']NRDəe@-]brxd\u0017 |RdL9a%Z\u0012m\u001eVZk.j<\u001fŪ\u001a3P,d8\u0013Eb\u00063\u001f\u0019)IqV󒝙DR'Ŋ\u0012Քtl<Rvu'7kJ6)S\r\u001fd<8@\u0018\u0001k\u0000\u000e\u0007\u0013\u0013\u001d5\u001c\u0019X)V\u001a\u0000`\u0017<\b^ɏm-n@q\u0002?\b\u0001J1{#n|79\r/y\u0014t\u001e\u001b{\u001e\u000eW|_U\u0010(@\u0000w$\u0004~bF͚\u0016\u000e`$ƹK\u000e\u0001ߗ\u0016gI9\u0000<\u0012\u0005i\u0006E!?}7>\u001dD3\u0013puY\u0013\u0006=z\u0002\u000b)\n\u0006\u001c;uFb>\u0016icR}6\u0016JB$f\u0002j\"\f8qJ%ۤ2+\\݄?BY$+=iϓ\\naW\u0019\u001cZ\u000bp^ z\\\\Sumыgm\u0014=s\u0002G\u0018%Uwe\nK\u0000\u0002@Pw\u000537*p\b()(=1yJ2r\r4\u0004\u0018r8CR'K,. \u0005\u00183*'g\\RTK)w\u000b-RA2\u001c-\u0002Olyutreͼ9pϮ1yT#kZVd$^$?\u0018\u0007\u0000\fXPe7\u00198(@\u0002a\u000e\u0005\u0019\u0000O\u0002\u0014P\u000b\u0012\u0005%%\u000b\u0001\fRP\u00027L\u0001\u0004x\nxܵ\u0017\\)5?Tsװ\u000e\u0005CȀ\u0004~ȑ\u0014Ė\"],D.BuY:\u0004\u001f-l\u0011!6k\u001b(\u0005tqbE\u0010\u0018p<$\u001bŃQ0\b$-\u001f=E|DķgQ\u001e\nclW\u001b4D<Fq_bأ\u000f2]Iۙ\\斧'`j\u000f\f\u001dx\f\u0006@\u001epL'EP\u001fď\u0001yn@\u0002\u001dv(9Q\u0013z\u0013]5UQ\u0012@ډ2f\u0007\u000b=&&SA\b(!E]\u0000Н.\u0015\u0000rvq։;iv2{\\)#l\n.A`kh\fWH\u0015C\u0011yw\u0003pA\u0005`a;A\u0003\u0005;\u0010$:P\u0014\u0019p,'P\u0010\u000fX\\\u0013%hV\u0016m'\u0000P^v\nF\u0013y=\u0001ͮ<\u0012oj\u0014*\u0016;<\u001d`qE\u0019â\u000e8\u0011\u000e\rVof˫*}b@4xoO:\u001bę(_>!;\u0018y+C5L˄'\u0016]Q\u000b̂rY:3}VsJ1\u0004p\u0016&\u0017-\n\u001cYI@=)x~LC\u001ez7,}\u0004z|3晣=e~uşX0P\u0006'\u001c\u0013et[B\fYܙ?K\u0006f4\u001d\u0018D(<Zv~[St7T*V-E/ɋ2!\u0014\tt6\u000fN2YLu\u0018OC!ËX\u0007\u0007pNH@.$;\u001f{7FO\u0015yEüZ=\u0013vLo)9hZGet\tU\u0001^\u001eϸ&s\u0006(o޺syM%ٕd\u0006[n\\q\t?񚹢\u0010\u000f\\5\u00003]w\r6>\u0006\u0019\u0010Gw$؂_\t\t\u001e2odK62\\sN8\u0006p#\u001c\u0012?\r\u000e3F*\u0005oa\u001f`S\u0019|Z*)CQ#\u000f\u001c&1)dnń17Z\u001bF.xi+\u0014(\rFM\u0005cK\u001ajiJ0\u0000\u001cKt\rۿ_-y\u0012JsNQiR\u000e=@S\u001bX/\u0014'\u0004tP\u0001Nj3\u0004u\"\r\u0010p\u0012ɬ&DS4\fSR\u0014='t'ONXJj#wa7?5%\u0004uqG\u0003\u0001BRM\u0013jAd\f\f\")HNIBv,\u0012$<ܺiUvj\u0000\u0014V\u0011x_[WT\u00078`q+8&(=\u0015dljS\u000ek\u000b\u001c\u000e@/u\u0000%ڈ\tw܏\rVk\u0006v\tFv\u001a|\u0007G4z0Np,\u00035UK\u0010:+FHE~\u001e\u0015ÛÝ\u000e〮\u0003\fza'\"/R6ޅCmƑ\u00168yW*I-D2\u0014pyZq<|\ne&LkHqo|5\tF?*\u0002z\u001c\u001f6Py\u0011\u0011\rG|I\u000b\u0001ܺT+O\u001e1ci}y\u001c\u000f\t\u0011-\\¯iG\u0005rH=a4\r\u000bC\u001cp\u0010|VUIR\u000e$_\u0016d>P\f\u001c\u0010\u001dc\u0011\nkz\u001apa\u0011\u0010N^7=MPH\"!\u0013\\+H;;\r7Aev\u0010wx\u001f~\u0017d\u0001Dft\u0001\u001aֻi+\u00191D7AvTO}\u001a`\n\u0018q\u0018\u0007zW`޹\u001dš&R9\u001cCLnw\u0014w(\u0002}ң4I&r@\fzɃ\n\")h~\u0016ͻy?H@&*p[kLqC\u0007PD\u001f&\b4<%\u0015=F|\u0002.t\u0016IW'\b^n[9)w=\u0006^\b~oq\u001fN{\u0010f\u00132n%S5UQ\u00153\u0012(\u000e\u0001P6E\u00115g#&3e\bh\u0015Ң1hBL\u0013T'&`\u00023\u0017d\u0014[\\kA\u0000C{\b(\u000e B\u0014\u0014K0%\"v՝d)8GɢF8cBًYy\n92^xsݜp7'\u001d5ݗ'\\}1\foQ[\bb\u0012)!MZ.lR\u0018le'\u001f@Wp \f̨B\f[{n&d&\u0004\u0000#\u001a\u0004`\f\nf\u00105s\u0005[]BE 8\f=k\u0010Le|\rRH\u001d41p-\u001fVa`qM\u0005\u0006aW3L}$ajYl\u001f[K;)*Nj5L&8\u0002?0\u0014l,1Ee\u0013?Gx\u000e\u0002\u0002\\_v\u0017(S2l;xs\u0006b\u0014\u001b޴$ovSn2t\u001b\u0002H\r\u0000WH4q*vLu\"vSs2W̕k6 3b\u001dW9\u001bb0\u0007,ihu\u0013i2N'3I.IQz jS6!gs\u000fM),\u00132E.@E`\u0001+^8xQ\u0015k\u0017yB\u0002'ƌ\u001dRc\\.h *T=A\u0005b[p3\u001dO](\\3zgm@IZ\u0013j\u000e\u001d\u0001\u0001 IR\u000bdکQc(\u001eM)\u0001si֒Vl\u000bDgsBI\u000bI.ԒPKu>{|Ƙ]\u001buEA\u0001>A<T\b\u000e\u0004y\u001f\u0004X\b\u001ctjimі,d\u0016\u0012\\v\u0014m0\u0004\u0012I`\u0001{\u0004 %fre0\u001a}+\u0010i-5',\\W5'\b5܈͵M\u0003\u001f\u0007\u0013B}\u001e\u001bc㯐b\u00110\u001bZ\\W\u000b\nOl\u001e\fdN8\u001fqQ\u0005\u001cY#GsC>H~\u001aW\u001fכkL?N6d6J2n{{\u0010\u001d>\u0001&XXB*vй\u0002*\u0005PY^\u0007\f(=MN0חE\u0003\u0006H\u000b\r\u001b\u0012M@ө,Д3LG'?o4vNys\u0018ϟqByp\u0017>s:\t.\u001fсǵ\\౯\u001bbCp\u0019\u0011P7I\f9avlXq?>\ta/\u0004D\\~s!\bh\u0003FB4rkpp,\u001cxcU*w|/Wl\b#èeGq7\r.ڵ\rv=a|W7\u00197<t^<?\u001b)\u0002\u0012yD\u001a:\u001agMc\u0012`r\u0013.\u0010\u00185Ry5!9A&Ȉɐ*bYҳ@\fiȎrV]`^{\u001cJz:m\u0018QfK4\u0015Ä\u001e:*\u0013{bl;N{\u0010\\{lazY\u0007\\]\"\u000e4%37(V\u001c\nQkh̼ƹ#9tPh]]1j4lz^\u001e\u000e\u001dpe\u001a\u0016\u0012Mh)tKJ%\u0019JK\u0006񞬀II¤$bRm\u001d02'T\u0003\u0019#sJļX\\gtJYR\u0006\u000f(]g2dK:O\u0001\u0014a\u0011ţ\u0005JeQJ \u00180\u0011(hQߎcf\u001b&dT~*,3\u0011~X`a\rl'[;_k\u0002upņ\u0016c\fv1%CȎك_ \u0018`9\u0015oi?\u0012eY\u000f\u001e\u001fz\u0013\"q%\bm\t&`X^E\u0006˄\u0013?ژzft0\u00042;4o>^5\u001d\\zǤ\u0013l\\\u001d5`j\u001b\"#\u0014-VwD'F\u0011\u0003\"\u0001o-fU-kc0\bk?\u001dC\u0000w\u001f?~\u00124\u0000\u000e*$t#,3;L`\u001bQRӎsI,-T!G&rV*\"}wʥ9S)q\u0015N׷TG4RN(E-.ir`լ\u0017%Y$*(:-\\:'k\u0016XV$\u0016dڜɯ%R--\u0004@cȜ\u001cb\u00126{@,Vr[%0ςXIqK\u0013H\u0010g˼V\u0019)'a˓Dl\u001aY\u001b8\"i\u001bI[Hم\"Ð5C\u0015\\G[k}\u0012\u0011&Z.=\u0010\u001aKho/>HAu{p׭Nޭ.iE1Mc8ǝ\u001fw\u001c=]W:h@u2Ny갬E8TC3I&yIR|uea\u00159\u0001\t7r\tN腄z&h>I\u001b\u000b\u0011NV\tr\u0006Ķ)B\u0002{;$5w;6Fc.5\u0016h@ǆ:!ql\\/RL-{JkP\u0000\u001fI\u0017\u0019_҃\u000fl\u000f̯؃3خU1w94ə&X\u001b+y\u001eB\u001eVp羙ѷ}U\u000f}\r?!%p;nb\u0015I\u0004{\t@!E[\r0@\u0014\u0002\"\u001cl\u0003\u0016&\u001c\u001e{SH\u001f AY\f|vc\u000b\u001e\u0004\u0005|##\u0003\u0016ơ찂\u001bum0晔5W\tb\b\u001b}??ܿ~_'~}\u001clt\b}\tD\u0012nx\u0003-uM´gs0#xD@\u0014=\u001a\u00029<}\u001aO䘮\u00049\u0017ʘ\u0014n\u0017^3i\fb܁ݕ\u00143،\u0017\u0003)jr\u0001@\u0018\u0013G\u0005i\u0018zMI$%\u0015'nGiJꦐ\u0006ݣ\u0014$h\u0003\u0013.-\u001c&P\t\u000ebZץ\u0002El[ƶa\u0004/Gz\u000fU8h= 8\b(\u0018`,a\u0004d\u001cC\u001cs,o]Y)x#\u0016R=?\u000b,BRAO{lTՙnF9\u0010N&ځkŦX\u001aOj\n{o*u8zWSM.o8ۅ=v'ىw>8\u0003\tOnW.P\u0015$ع\u001d\u001bkް9\u0004\u001dޕ\"jܠ/oIj\"\u0016iZMG`ou;y%UZS9T\u0019\u001ae@jކP\u001f`hDr\bj\t\u0016:ږcQ2FsAL\u0007.\t^1]ʲSs\nN\rSH\f/L)k \u0001=ga\u000f\u001d=\f}s\u0016JO*?R*4\"pQ\u001c}2YjM\u0014\u001b4\u001ccHȔ\u0003ߤN·./T4.*6F<k'~N+^Ol(Q.A\u0015)/jeuPyW͇\nX\u001fT\u000e\u001f+Zj|^\u0002\\!\u0012\u0000Ye^J0oeRigknn^2?9\u0010/rvg{\nh\u0015\\w\u000bj[jN̖σ<\\P\u00113eI?!N8{\u0019\r9\u000e\u000eihIɬ\n>g+\u001b\u0015'\b\u0014Z~ \u001785h.N\u001cٴN\u001c.\u001d\u001c@&$S |Vv\u001d\u000b\u0004ϖ71vIF6\u0012'2l0pXTS\u0012Q\u0010\u0007v%]&`\u001c뜴L*vp\t:\u000f3\u00105ѣf%\u001ew6ɑv#5}\u0016\u0000[5kbp,A_\u000e\u0002\u0004\u0000&(}VM\u001cfV&_\\R\u0018w^0,\"37DZG\u0004\u0015JXP\b*\n\bj\u001f\u0004r6K&lNb8\u0002\u0017J0Pq󫒯Y5%]\u000bp=,\u0018rToL\u0017\u000f/{nҋ\u0015\u000enqjPphQ>D]\u0017u{\u0018E!r'w(ػ'^Ͳ<\u001e'읣Vݲ-V\u0005lp;0 vΦX攺k\u0015h0ƴڧX\u0005])UPgeuV\u001a<\u0015q\u0016fj`t\u00189`I()GRIB&`UQ.\u00107R0\u0005uUk8J'g[{GrX[ݼ\u0013]\u001b\t>\u001fgCy[g$֑]r\u0007˻+\u0004RoaEI\u0012gJHHU$5\u0016PuEg90Y\u0015ra\u0012Gac=T\u0016ux\u0016*\u000fd\u0018\t.\\p60\u0019\u0012da\u0006\nERRXJ56@\f~g]fmn.8lMĖk(F\u0005mr-\u0007.\u0000>j`ֻ|\u0003.43kK\u0012ZD6p\f6dBAaʅ\u000f\u0016{Mً64]X'tkP\u0003e\u0003\u0001|][uw\u0016t:|\bau&^0;Iw\u0015@|s\u000b \u0006-Ʀa[h\u0018Z괳Z;Kj\rH\f{|\u00013pe%\u0019\u0007C\u001a8C{9on2%.{n׃乻??Ƞ[l\n\u001d\u000f龜jiSk\u0003\u0012\u001f27f\u0007Vf3\u0016\u000eI\u0002Om1fC6+rh\u0014x#\u0005\u0011N*V4\u001ctSJ9g\u001c!)3q+$,\u0012\u0016\"p\u0012\u0000tP'9\u001c\\M\r6bAFLp\u00183\r3m\bibU6\u0017u0͇\u001d2pR~\u0005;\u0015l*.1\nO%)o\u0006i׵Qnm\tvQ6\nㆀp.Is\u0002Pop]<OĎ9䴥\u000f\u0011_Lh7\u0003>L\u0016s.1MLN\u0000mں6Me\t$\tViav&ﳯ\u000f;Li\u000f.0ob<xOg8}Ӳ-&\r.\u001ehMid)\u000b)ʑpJ5ě*KKzS독l;\u001f\u001b\\px\\ѡs-,\u001c\u0013-\u00057\u000eK\u0005r\u0005nzIbN9ɞ>H(H\u001a\ngR.h,i\u0019oJxLUR9}nT\nB`V\u0004VG%l\u0014mY\\Y jԁ\u0017eI߽^r\u000b.\u0013\u00037χ%sa(\u0016z.t.ozkTi\u000e2:sk-f\u000f\u000f*\u0014a\u001aL^͙?R\u0015/5>.Jx6(wS`}\u001eC^upy\u001eâ5wn~t7E\b}k{_\u001e\u001bL\u001070P\u001d]\u0010V]E\u000e\u001bXc:c`)!\u000eLBt`\u000fGRypc\u00029UC\u000ftG\u001aegG\u0016pci&5Q]\f\u000f/om+4uS*\u0012>\u0018:\u0000C=ꡧsD65x.CUm;o?0;s46g\\j[ֽ2?Ko\u0019p0|Vz<wcӎ\u0015RHnPHqC4x$0Ikr\"IX}7v\u0016x\u000f\u0011\u0016L\u0003\u0001[?\"d\u0003\u0000\u0017\u0013C\u001dpZq\u001d\u0019;wf\b?\f\u0005:\u0007u c/o+65\u0003D\u0006i1[K2SN\u0012R@fD1#Sd:=ѭ\b\u00183\u001c(rx\f{&\u0006s֬>CB1\u00078#AU?ӑRJ?>\\+H=}PÑzv#\u001a\u0001z\fD-j\u0010MK$i*j\f(VU\u00185OD{0>/\\\"o)iT/5dL2\u0007w\u001e\u0002:\u0010&\r\t+j.\u00119\t\"{\t*(bVf\u001f\u0012}\u0018\"CNeGb:\u0003\u0007z#b[V\u0007\\\u0013]@)rs\\\bS,Iʚ֭\u0002NuI?qo˴vwS1wPIu#EiZ\u0018v\u0012&\u001c\u0018Jvl\u000b\u0014c\\mZ\u0016 o(b\"M\u0010V1\u0004!L\u0005\u00002̌\u0004jab¶k\r4q-\u0004o\u0010Oi!Jr\u001c\u0000i!\u0006.\nW\u001bk\u001eϨ}G\u0011\u0015<h\u000ed\fsޣJGUŃ-Xs\u0015\u001edX\u0007ýd8[n\u0005{sB\u001e9#E|]9>\u001cg\r#~HQ\u000e<m\"-v\u0011\u0007Js6ʀtΗp+}ʓ\u0014^]\u0000\u0004\u0013\u0004vd\u0004GL7fX_\u0017\u0015hŜDID\u0010DaO+g>\u0005EEc>-ŒM@2<\u0011Kjd\u0011PBoYxa\u0006\u000eN\u001adrkqkf1eܼtj%\u0019\n?.Zٲ>kq\u001f\u000f-$]Y ~p\u0000RLi͔$\u000f˺{\u0005Ik\t_ф\u0006\u0013gυ0&bbrOk{i-V{=ŊA!l\u0011!P4J)TDxa\u0012nȯd8\u0002j$ZdK3ޥƆR#Cp\u0015bOrB&\u0014,B,К\n-d\u0007.cҧ:\u0004\u0001>\u0010\u000eij\u001b:XG\u000b6\tGsP+.?\u000b\u0016k2/a;rDs\u0002|h7\u0014JE+_\t{*Œ4\"z-19\n\u0016̷7&\f\u0006E\u000f(#GLEIu\u0016\u0015<ZѶqrwA9\u0012VgN97\u0010\rE<s0?9SJ}[S`O7YSS\tSܗײz_KєIZm`́\u000fb\u00065ښ\u000bkk\u00065-V9WӢ\u0011!#\u0002G\u0004:r\u000e$M:WyBН:\u001d[Z&\\U\u001aۺj;Xa$qZx\b`ͣQ\u0005lcX4'.\td\u0000X$Hc{Ir9\"珨'0<50_`{\u0010j`mƱ퉈\u001bl\u001f\u001b?\u0011\n\"M\u0018ΰQ_Q\u001b~X\u0010>E6yIkWMys9 \u0010Ԩ~Bn\\t2'L^J-=춇wTWm¯J\u0016[TrT^\u0000\u0004MP5\u0003\\u\u0007n\u001f`#^wBb\u0015.r\u0014J́TCm~_\u0000\u0003T='\u001dpRG\"pLxc\u0015U϶ŇT7?~\u000f|\u0000|O&{=]_Icx\"ua_R5w|}E9\u000b]_Qk\u0017XE\u0015j\u000bc\u0003_؂K6Ӥb\u001bfڌd6.y{m.Uʆ̕;i\u001aH/'\u0011\u0019PGqZN]\u0004\\iCL?\u0003OlY-zk^<5U\t\u001bW\u0001ք+1K\u00007lm*໗\r\u0017{k\nҽ\u0005;u{Ml~\u001a\u0004N,<\nYwDpX+opO w)\r\u001cmSQwm7*j+t(Y\u0019T\u0015\u001dk\\g`z\u001c-3Y˕TRSV ޢD<\u0015fH2$45E\u001a.H&I)LI5B\u0005\u001f,\u0013Տ\u0013\u001a\u0001#uj*hJj)<ՅU\u0019-T\u0007o3z)a~lv;zҾ'TX͖81?ht\u0007=Q\u0006<JҰdQӶ3]\u00074eT)or\u0001\u0011?Cx\u0014#\u0017SL9a^,\u000bI\u0012\u000e`\nu`\u00013d@pU\"vPZ\u0018mșDR\u0001^EF䲷[ZN>#\u001e'*Τ%x\fH\u0005\u001ay\u001eX\n$\u0010\u001a-\u0002sX]^M\u0007l\n71=\u0011!F/\u001efn\u0007\u000f=iyz%.N@\u00139D+)\u0019;p\u001b-(J+6i&sv7\u001a-Dl\u001cVhb}F3Ymar\r9C{gI.\u0010\"\u0018\u0016\u0017ygp4x27gv(\fAglK~0Ҙ7̜Mdc:B\\s*Ahި0OλߒcזPW\\CoTr)-x\rMPR\u001a&b\"o\f3\u0004ysH\u0001~'\u0003+Ha~\u0011\u0003Rz\u0001] ,Q]Pyn3J\\\u0012;jJ%K8.ԏ-\r$\u001a/nZ\u000bԼ|_!YjV9\u0000rKX&zmo\u0010\u0018b85\u0015H\t-VaZ\u0015^lF\u0019m\f|k9\u0007PT/P_؛p-dG2{\u0018݋׆o\u001f(gQmZEs5n\u0018Ōfʸq͗\u0015=%\tk>cKb50VklS7ii\u000e\u0004$L8d4'8\u0000\tTH8\u001a\u001aJp\u000f}\u0005G4|\rCEW\u001e&.Lm5\u000eaq4|glDYp't_TAŎ@+\u0001\u001e<rN\u001aܢvCG6pn\u001a;\u0018\b,չ@+蔖\n~]'l @&j\u001al6cE]\u0005[\rUӁ\u0004}jm;Mozy_\u0000\u000e:0ji\u0016n1Xۆz\f\u001b\u0018C\u0003G\u0005S\u000e7MɝDSL4dUE\\\u0017?}v8H\u0005\u0011\u0005\u0019O*<S-U\u00198\u00023owO|%Ee\u0007u2_d٫n;`fnyVi&\"5SCxE\u000egM'\u00056ø\bW\u001b3J\"H\u001f?~/~\u001f+>\u000b\u001b\u001eC\r1<\u0002d\u001e\u0001\u0006\u0018[0ht\tF\\\u000bjћjE\u0003PSlp\u0014h\rO0\fyܲ\u00124Bq(\u001b\n\u0014\u0000\u0012?\u0015N\u0011XrW޲ѝ\u0012e&:ܩ\b>Kqa8C\\\u0017J\u0012yOuXku\u0019q|\be\u0006RHda8\u0013zLnu\fL1\u001d9w\u000f\u0017~KТ6LV\u0019l\u001c\u0005@\u001f\u000e:\u0017:JO\u0002xVs\u0018t\u0004t\u001e\tϞ)\u0002Y5\u001a\u0012gX2\nF\"R\bcf!&\u0012b V\u000f#v\u001c2+4D\u0014\u0013ق\"/\u0012h~\"Gf$iM\u001fbMrY\t°; 5\t\fs3q\u000eIJ(G\u0012>^\u0019*tnB`I\u0010),;mQĬ[C̯PY:\u0015i\u000bY\u001c+oXF/):1ZȕųP`U\tIXYu=U.w1\u000feЖE\u001aإ\u001c9\u001at\\\n6\u0005܂bI\u0018{\bZ\u0014`\b{\u0017vBQg4vUG\u0015M\u00161pM\u0018y_sS\u0010\u0010'$\u000bC3=$k\u0010q}H&7m[\u0019\u0015k#\u0019\u0005?WAgDY\u0019!ϜtGYDYYD1\u0006\u001b8\u0007*%\u00184WPгVd\\x?\u0011GBR\nd*ۦM\u001cȳ$u SʘbU&'\u0016!f\u001bI[.g;\u000bfU)l;>P\bb-yR\u0013Î\u0000qls8%G\u001e9R\u0016fj\u0015W\"i|Y# -L:ޓ\u001b*H*n-궑*B\u0002m\u001dJ\u0018\u001b{\u001d]\u0011BHjJF\\P\u001b\u0007'^=\u000b\u0002;WQ\u0005=\neX\u00121'\u0005\u0018V\u00107\u0005z\fs\u0015|P[RV%\u0011mѮ\u000eWY\u0010-է\u00150qυV,ł\u001eSdVsRUÀzK,H9X+_\u0004g~.ڂ'd^UN0ͻn\u0012;kH=A\u00015 ֝\u001a˔C2:m/\u0004K86& \u000e\u001d+1;`g\n\u0006ˠ\"նދ\t-弘9`tv\b~\u00006<4\u0003)Msb\u001ed\u0012]\u001e3(xwI\u001dfՉ$-¬\u0001kʄg\u0016\u0001\u001bHy\u0016\u000ebDZS\u0002PJݔu>oL\nHSE\u00030H\u0000&\"Ψ\u0000\u0012Ǐ\u0000gI`\u0003\u0001kx\u0019:L8'b>\ts\r&TQ\\8e\"\u0003jYф\u0019iR;\u001d]!rE\u0012㎮~k&!O7\u0006˔n)]IiD-Hq\u0017YhK+ՂG\u0016\";t\u0002Oa\u0007\u0000;^C4S\u0018\u0007\u001c\fFdec7t{*b\u0010%֞=\u0016X=\rt{Ϫ#`)L\u001c\u0011<\u001eNL9@\u0001\u0007D^\u00100\u001c`$,Wxg+\u0016PKv\u0013^Z8b\u0013Gl㈍\u001c\u000bݡ]\u0019CUo? S*R\u0015\u0012+A\bR\"[G\n˸!?US%~ҩ=]'Ͱ[[gw)~fUFA\u0014rr\u00051%7$wR\u0006\u001e|eԼL\u0015/\u0013˨vI]Х\u000bJQ2UL5.\u0015.[\u0006qK'\u0017V-\u0013mK\u000e\u001d\u0018\u0011\\a)&6Q\u000baqdNqq2%P((D&`E6o-]rD\u000b\u0017Ȭ@$)cLǗ&:\u0013}KW*$#Op}\u0011$oM\u0011\u001bΰ$}\u0013\u0007\u00174c\u0014E5۹g[iz]rr\u0012\u0015VE\u0017$,0\\m\u0019c[\u0010XTDV.4LFg2'\u0019]P(O<\u0011\u001cD\t{#\u0003Z\nkU$r&^Bb)%\u0017\u0017J0\\:6~i\b\"I_\u0014%;u\u000eaLC\boyO92\u001c4\u0013%YdSBE\u001d\u0007\u0017<:qh,\u001cġՁ\u001c7pD~\u0011\u001f\u001c,e-){u\u0014U\u001cU't\u0015m4]\u0002>\u0012E\u0014\u001cFԥhӁhҕ\u0017}$\rs`\u001d@=\u001eUfq\b-2X8X\\%4HSrJ\u0014:Q$&Is2YV\u00152x5rY\r\\\\E4R\\.j\u001fjj\nڇz\u0007j\u0000_ÕDKXI{\u000e .h'KZ\u0003ʀ(甎],kqx]*%\u000b+VG!Gέqmyو\u0014D\t\u0012z\"\u0001\"D}bwI'{J/\u0010r@o\u0014)`1\u0004>TJFq7JKю\u0016:g\u000f\u001cPݺ\\E\u0017D.\u0010T$bnNv2:WxV\u0014ʣ8\u0014MEX$_֋+\u00194\u001cux) κsq\n\b5\u001bi\u0000V\u00055CGiTO6`c,Wu\u00006\u00079-%\u000bKs\\'<t2Yd\u000bp\u001a\u000bɁ8&;d\u0015+r`~\nlLjyI\u000e~uym+u\u0012 g\u000fsrܮ\u0000&&\u001f\u0001,j7[\u001eb{Z6\\k\u0006fΏn\u000fq̿\u000f1\u001f<նg\u00180^\u0016[Z\u0015\u0010r\fd\u000e~-%p\u0000mbGT¨mtVD&\u0013>164\f\u001dGLö7!vȘۡ\"9\u0005rwtԌUK+$#|?dg\u0011;B6i o70o2\u0017\b[ZUcO\u0012]ߴH#8`Dh>}UIoZ\nT{T\u0004vT{ǻ\u0010\u000fXq@̴\u0005\u0004\bj8\"@\u001en=TpaF{U?b\u0015PƱ\u0006ڬ\u0003EOr5.k(|\u001e;\b2\b\r&\u000eL_]M2 \u0019\u001c3l\u0005 \u0019'\b\u0017D~K\u001d\u0000iF\u0018W5u`\u0016\"\u0000e<\f~^=u^#d_4gR\u0007 ^2Ʋc:\u0014N٥\u0016}$v}!s%.\u001aJGE\u0012\"h\u0000$\r\u001cαYv2EΦe\u0015\u000eBֺ\u000f\u0013\u0001G\u0001Y\u001cLCG\u001c戎>.W7\u0010'U\u001eDZ}UB\u00154d\u0002QV&h\u0010JT#VPi=91\u0006\u0005@ɬ+\u0001\f\u0010\u0016C\u0014ʅ^JPMi&>Di/\u0014,ެS\u0010\u0011G]v\u0018L~\u000e@V\u001f#C\u0016\u001dapBc*!y\u0012K.%u[\u0010OǄOnaN\"y?^{|W,b.ޥD\u0014i\"\u0014&\u0015x\u0015QeJ\u000b\u0000ߎ{\u001cٌ#s~c\nN\u0006nhRkc\nuS1$^,ɟ9$\u001a[\u001eS9(ָkVJ\u0001CLreR[N+\u0001M\u0012\u0012\u0002/cly{u`eᦍ3|\"+'\u0018\b ȟU&X{We8\u0002.hq\u000eYO=\u0005qNI\u0013?Cn>\u0017տh\u0016I\u0013m3torӇߝ\u00154\n+\u001d4#{y>PhH˳@kJdb4ܜmdyV6T\u001bq\u00184\u0018L!r\u0017@4E&K3gg\u001aD\r.u\t\u0011Q%X$i\u0004;\u0019scv\u000f!\u0010\u0004=g#gp4\rY\u0006;䯶a2Ov\u0001%u\u0000(\u001c`_c\u0000\u001a\u0018\f\u000b\ts`fo'޺\u001d2-$y\u0016̽AN\u001aNv?Hy1N,gsLBF\u001avYi\u0000x\u0001S\b3ù\u0007\u0007Iv6r2:\u0011\f0醾4\"\u000eB\u0012\u001f\u0004K6VԻX<`\u001e~\u001c\u001f%\u001arY\u0004\n٦7~½\u001d_\r=lk>\u000e|4o$^S\u0016}\rL\r`\u0005ǡ\u0014;\u000bߋ\tg\u000fI|uw߾?\u001eƿ/܅\u0019i\u001ejI_nT\u001eLN+xz/\u0015Y-\u001a5/\u0005G8\u001cԳHa^\"\u0005\u0019\u001c5'd»VB-iYǈnOH\u000e$;\u001eK<ha\u0015dz+A@\u0007\u0019[{\u0017\u0002Ui\u00115\u0002@DRF2\u0018l\u0011rǑ\u0016HqúXR\\5#(\u0015U\u00103ݣ\u0013\u0005\u000b\u001f(>\u0012\u0000\u0015&A61K7iK#m/ܥ@@\u0005t\u0010rNM8sG)C\u0011b/ʝ\u0002igNA0?\u0005\u001cN+`9O\u0017Q\tni3yV!`\u0002# yP\u0006:d\nMtͱm`n\u0012?r\u0011\t;\u0006R)`ch>gN\u001aKLܬկc\t\u0012򓏼wK+\u001fuk5?\u001b}\rxs\u0012\\~`>B\u001awU.+\u0018CT3_3z۩dDf}O\u000fĖ%[]K<{)D:D0P*'s6\u0006c\u000bcQ2-4*\u00165\u0004ōbWJ<`ϟ%h\tl\bT\n\f7m)\u0007>%Yy,&\\[\u0016L'T1=n\u001a\u001eJFk}D>\"\u0014\u0002g\u0000f]&_F\u0001?\r\t\b{\u0000\u001b\u0001Cq'\u0017Y`Q\u0013lI\u0012\u0001K\u0000H͢a-=\u001e*EwK0R)R\u001d\u0006`HZI\u0005Xӄ4\u001cbE,\u001dæM\u001b\u0013\u0012WbxJ\u0010XB\u0012KDBS@bG,e@B}d[q\u0018]\"\n~G\b\u000f\u0005\u0010Za^\u000b\u0017\u0010.gc!E\u0000|\u000e\u000f\b\u0003\u0014<\u0014L.CuгfL%=?j4a*F֓\"\u001cY\u0013=\u0006ję\u001f<6MĂ;&\u000f}FyL\u000ee\u0010\u001fCD\f2m\u0004\u000e\u000e\u0003X\u001f:\u000f/`\"0X Q!lS\u0005`\u0011-DdZ~vHh\u001dŕ~۵\t^YiK<,nvpvu\u0002C\u0002wvKW\\ً=\u001d\u001cP^KF/Lk\r\u001a/%lw:Q+}\u0013@ʨʤ\u0018Em[Ek1v*\u000eؕ\u0018(>i9\f!31X\u001aa%eJyܝ\\~*m>?sP\u000f?\u001b\u00136\u0000B*׾\u0010\u0019-\u0007.y\u0006\u0014*\u0004#\u001c%sK\u001c48R\"\u000foQ(Ui~t\u0016D\"g\u0013ŠsY_Bo\u001fWd|j'Sf}\f'g3e|<e\b-)Z\u001eӔԞTM`\u0004k-蕟\u0003f\r\u0004\u001b|h_ta\u0010\u0006(eOt:\u001f4q7K7\u0018u\u0006_ku\fS1w\f\u0007DH\u001fd\b9Ih腖\u0014C\u0004W%\u0015zS\u000fVAjsiCbU͵\u0013'-\u0010Y5RUh\u000bC\u0015u!mC\tdF>mK{Lg\u000b,ch\u001aX\bS-=k^`:oxo!5̟f1R'< é\u001e!D[\f6h\r\u00165\u000bxD6\u0001l\u0001\u0001Nf\u001f\u0001d22\u0011\u0005ڽ9\u0019-\f'OZ\tҖwQna\\X=xqB\u0012ʚTŐ1Mfc\u0011\t)Id#*;|\u0017H3\u0012Sp.?\n=U,vtHnRQ,.skZ諴U=,5÷RHJa5/96\u000b.eKyu\u0011ee]\t\u001c3\u001a\u0013RE+-KEqrъx\u0013*\"$^KI,\u00021\u001dWRK\u001e\u0014vZUce\u000fB9pA\u001d,\u0016>6iE8((\u0001̭QSt|#\t\u0004D}\f7ú*\rW܌\u0015y\u00112ϴ'q%RzRQn\tn\u0001sU8QY\u000ey/|q!\u000b(,J\u0017%ًx\u0011(I%9(+(cdz% D޸$J4{NTL)\u001a{|/A\u0001vJO<ծmp}ȳ.\u001aP\u000eyQ@b\u0006o\r\u00177.őT\u001c\u0012rG< E7\fٓޕ<_\u0018v\u0016Yaz\u0014\u0013-٘<\u0013l\u000fkJH0~T>\n00\"\u001c \b\u0007\u001f\u001b\u0017=P\bu5\u0012\u0001Y\u0014>wp#X\u00153(!Yc;\u00180J|N\u0013qmB\u0016\\Gk\u0016\u001dRиxMnޑr*o9\u0000l.pq\u001cA6+J\u0002IKK\f\\\u0001Do =vH'&|TNة&:\u001dfu5%G8ژl\u001c;,wW(\u0000a]@V\u001aN`Z\u00025#QG\u0018ѹU\u0016pO\nioCg*[ͦ34-#&G\u000b@\u0016iԚ2sʌ4\u0015h{Zj\u0006ǋnp_}YM\ro]3\u0014\u0017`ŨR]\u0001#^fB\u00105\u0018Oq:#i\u000e߲?э\t\u0007\u001cCF#Go_wJ^x\rG!dK7X*< no~8ʆQ9(\u001bF爣l\u0018#a{D\u001cUh/rA\u001cr>d\u0011\u0011\u000bd\bQ\u000239E\u001a\u0001i,hbf,\u0002\u001e\u0014PjX.\"`\u0004\\('ܖ6uN}Ѫl\u001fAr.̸WSnnbKj.\"|ԓGc񑨸(\u001eI\u0010I2\"D6p\u0005@s k\u0004rM\rܛ|\\Ǚ\u0006beX[)Z\u0010\"ј>'Kt[+4?\u0006_-\u0019kh%H\u0016ae\u001aګȬ#82RxJ\"'Gr\u0013\"q$H\"G!O7*(D̴H_Gj8}\u001f\\ӹ\u001dAd\u0011!'|M \u0014F\u001b\u000b [X\u0005Q@\u0013t9uՍ.iaǛj\u0004\u0016e\u0007\u0017\u001c/\u0007â\u000ePZj\u0012_7)5\u0012jBC\r%q#p\u0006L}mKMl1|HF\u001ax=Њr!+\u0004<Y \u001f1w7\u0017\u0001\u001f\u0016\u0003?wEE\u0012MS\u001e\u0007oe뤖\bA[`\tB\u0007\u0017(C쀍\u0012v\u0014\u0017<&\r\u0003`\u000e]NkUfHD=z2B\bu\u001f[?C\u0005w\u001bDh౭8h\u0010\nB}8˨Hj0=Ù\u0001U\u0018R\u001a2\u000e@Zi\u001dx|OUo\u000eCb\u0010\u0004Tsp\u001bU;\u0017ܧtD9&=/s\u0000I i\u0016\u0000I+\u001d[˄h9\u0011-\u001aU^a.?2\u0017$d/\u0010@A!\u0019\n:zpA (jp=.M\rW1oޝʲD^\u0003Dÿ\u0001Чza\u0014xn\u001b:}\rc\r\"\u0006\u0006\"S-\u0007,zpޛ\u0011&1nE\n\bn|s̓4yF\u0016Nt'\u0011*\u0010R\tL\u0002s\u000bNp&bũ$!Q9f#6gw\u000fkRySF\u0017a<l\u0015FĲkB$C\r{MI/C3]RPH\u001b#¼\u001b9.Gg$\u000f\u0005%Q!\"3h1M}\u0000X\u0012\u000f2<O\u0010q=A\u0002+g\b:U>lS+ |vX\nŢRE\u0019!x^Q6\u0014*Fruo!HhD,\t=/=T!\u0004`Mq \u001aD\u001ar!a(\u000bɢ+IBvp\u00183V\u0015rPzB L$v\"EF\u0005 \u0003F\u0001j+tgX\u001fX\tCR\u001cFK=HgxãU}`>4T#˼wYv\u001a֥\u001e*\u001d%\u0011\u001fF\fDw\u0013 \u0001DI\u0007$\u0013\u0013\rGiQߐMi^fvn\u0015\u0011ɤ\u0019^Mi7ksI7EKd|%S{Oڗ_ݍ\u0011Ww=\u0015ooj\tIl|TdΠH\u001c-\"pqIXx$h\u001e\u0005\u000b:Z\u0012\u0014\u0019j*\u0002=,\r<ɣj<5j=.F\u0012\"\u001bJr&\\}G#gnKlZK(95\u0002:\u0007BxHT7\f\t`)$I͚2n(1˪ì)\u0007H\u0012>\u0013\u0012aH{'\r%k⽛v,]\u0014\u0011_\"茎/\u0013sTd|\u0017o/\u0019ʒe=9\u000765_L좗\u0015eA$\u0015\u0012\u000b]<\u0014)T\r\f\u0014>\u0010N/i/*=%ו/\u0010\u001fl{ˌ@G$A!u\u0018\f\bvb\tTIj9GD.d&*fE̮s\u001au`KJ-:+Jg٤46(IoiZζ%#HM\u0017ك$=3\u0010̜G'qS-L1\rL5\u0012c\u0004n.>1\u0006=7\u001c1Nq%ľ^`.;Om%-*$\u0014\t⡸9b|\u0013՚\u000eh%B\u001aح1xgF\u000eu73DqJ\u001a'KoるV\u001bD\u001fi\r\\\u000b\u001dA#\u0010&)+\"#'i\u0013ʿnewY@i%^>Vi;w\r\u0015uiVxY\bi:^p㵖M_3dIԠ\u0016c\nP:bKJT*\tt\f!\u0014ӈw>3\u0001M\u000e`Ӵ\u0000Wp\rPMJU䵕\u001f˖nM0\u001c\u0001Fn}}?kڍ8\u0000p<\u000eM>hԴp83Q\u0003]eUǪ\t|\u0011ʇ\u001c\b'Q`{7$dD)s\u0012Td팒`*ܝ,.c\u001eИ)f\f\u001fDlUVf>d`GK7s\u001e>\u0003=_f\be̠rʉQID\\Ym@\u0018\u00105W{+u\u000eq7d\r)#?G|I)\u0011TcFh왃5\t>ҍhU%ɐ mX \u0014*yCQ\u001dQ:\u0003_S\u0002]\u001c[&\br\u0019QBє\\\\\u0004\u0011$g'\u0001\u000f3\u0014K\u0003!4\u00023\u0005Iu)wћ<q0\u001eO2\u001enL\u0007$\"+\u001ey#\u001cŻc49f0\u001dyVy\u001fO5s1\u0019\u001b\u000e{\u001edi鱷rFLu-y\u001cñ\u000f\u001f\u0019EppaM씀ALK\u0019豁~bP+,nT_+C\u001fO9)x\u0012[\u00143\tTn\u0019\u000eyd5{25)T\u0013Ǐymi\u0006<K\\Xj\u0013ϙ\th\u0000]Ǭ\t\u0000a4]fjK3̶\u0006O5|\u0006mg$\u001f3ud)0\u0016_%q\u001a?eHm\u0019\u001e\u001cL\u0001+AxmMoO?17E}Gk^lyce&;^ד4]E4!M\u000frhwcSi;]m\tN>ټMaS}={_OxP/Z\u0017R*<\u000e\u0004\u0013̜[s\u00147\tJ9ߦƅXyZ[bb!5\u001bWSF\\\u0017c{V\\u8<щ/\u000e\u001d5qd,\u0005\u0010m/\u0000o;\u0016c_=\u0016.-\n܂5Ky\u0016|4\bzόO^\u0018\u001bA\u0002B,\u0000\u0014'a.Oh^R)=v\u0003\u0006%DOgi-|0=m\u001f\t3hMկ\u0019`&\u0005׌\trО&S&h>2>DIX5\tӹe\u0011If[!\t-|a\u001cAO\u0007#=KA\n&#>&ī$RV\u0010SM0Awi\u0019vgӴ,miz6%1Ӵ,mKvK|>M[1\u0013n'\u0019ZJVrfFM&ԿƏ8è\u001f:x\u0018z؏8T״:\u000bTǉ\u0015\\tY\u0019'{nﶶ\u0014SD\\4՝3/5\u00152e\u0011.w=N9Vvt\u0013r]&\u000eC%{69/|\u001e\u0014ǜk\u0011,7 \n\u0013W\\GNݒNMݹ\u000eQH{%흒\u001bgB\u000b6`K\u0015X\u0012X]x\u0002'\u0004G\u0018cwnxe1Gճ=L/{\u001f;\n߄y\u000fq۝ú\b\u001a{î\\\u0007\u0018vⷴ\u0003疞;+=\t%g&`\u0013\u0002694nWȮ(}\u0017/Dg.۹I$Z]M$\u0016\b,NκWer6-١fo5^W\r]\u0015*Ѐ6[bՔaw$c\u0002A>j\u0010@|\u0014ҏo\\rU@4,%ѭM(/],\tc-i܂\rrm&V\"8!L8\u0014+$\u0001q6!m9\u0013j.ʉpb*y\u0006GO$\u0006%UUB\u0016Yf)٫܏rSn%>1#\u001bO\u001aw\rS]dt7:O\fL짩Sj)\u000e\u0012gb\u001b}L\u001c\u001d\u0000Kn>\u001d\u001btR3\u001b?JAb\u000b)U*c)6մJX\u0016X>W~ZdL\u0015|\u001e\u0019'\\k\u0000RڥM\"\u0016y2\u0013guV᭫p6%cè0*\u001d}MJ'I/5D\u0002!\u0005T~ڗ,t|K&d@#^|\u0016dqb$G|9Nd/ǉG81R|J\"WF\\\u0018\u000br+A0&\u0017{L[V#\u0012S\\3sŽ/\u0012GIࢄ\u0017L_kbl3Jq\u001a%(F8ra2D\u001d!Kv\u0015\\b\u0012}#[6\u0006(T$^C\u001cȆ\\Al.T\f\\!Qh!1*fSe̪X+1b@/X\u0015\u0012DZ,\u001df\u001aٰV2\u0015\u000bkeªDX[Y#3>\u0001%l\u0007C\u0012l\u00199\"jl(6D$qͺDO'DH\u00024ٞ6*}\u0016b\u001aj,sEGa2\u0014.CS\u0011\t^TP\fG(>\u0002E\u0010c~2[!jq\u0006P7>5SI{TjP\u0005Rp\u0016\u0004o\u0007e3\u0002\u001aRt=\\|rosi\u0015ьՃM\tdxc\u001e;u\u001f|H@\u0011\u001e9x\u0014NHB9h>Jؒ{0K\u0012t\u0012Y(5w76)|\u0000LKHȢ\bWv<V\u0018]/\u00178܅/\u0011|\u0014nަm2\r[8Rr)@*9ٔM\u001e!(\u0013ל]hP(\u0005Bi!.\u0019\u001f}d1GkS>`\r\u0017vxSںR[L_PUy:Sk-\u0007F}Iom &$ȜNy5C|rVܷBV+Oxොr=˄g2\u0003\u000b<oS V̆kv\u001aͯu&\u001fb=d~fc1S\u000f7\u0015\u001f\"Pg\u0003'|gF҈H_\u001a1_\u001b3\u0016j#\u001a\"\u0011s\u0000Z|f=f?\u0012p_s\u0015(\u0013\u0007\u0018R08{\u0006R`-[u\fzkF\u0013%\nG\n['in>@UՅe>\u0014grlvpnʦ9=HG\u0010\u00036\r%\u0019,\u001b˥\fw\u001b\u001d$\b\u000e\u000eDTǶ\u0012!N\u001bF\b\u001f^\u0018\u001cy\u0004SٖcֻbqE[+yO⒦\u0004ۅdYN\u0016lXt39J[\u001d\u0012\u0019Or>-&\u001a$j\n\\2\u000f?~۟\u001e׿o~\u001f;\\+gqg\u0016\u0006\b˺.%'X\fK`\u0000O\u001a\u0013@\u0010g\r\"S/pP]Y:\u0010ǟt-,xo\u001e&oAŃ\u0007u\u0017\u000f.\u001eƻxPwQF/\u0010\u000b[\u0000˾.a;.f5ٷ\u001d[1x7_\u001f\t䇰\u0014r\u0003]0={K\u001f+k஖=ΦQ]s޴6ѳAm\u000e=\u000b6\u0015Ll* ̝\r\u0014'\n\u0006c~O\u0019[\u0016g\u001f3WBD^\u0004l#O6{'ЋT\u0010{$ZE%-0n͢Tn\u001dY\u0013,`T[=c\u0017L3[\u001e{wt\u000f;L-)r\tz=\u000e(\u0017(V\u0014f\u0012\u001f1R\u0013kA\u000eV XF>nʑS\r\u0013͝'MRļlRxE|\u0013\\[\\>Y!\u0013O\u001d$ܚ\u0001</2(\\Cl*ȇ\\)M`!n@&+WZY#-I\u000e.ښ=%{*C*v\u00148g?]%g\u0014\u0005mT\bՂOnjC)avRKO\f}\u001f\u001cr\u001a\u0014.\u001e3dA=לEPlKWօ\u000f,\u0017M0U\"yLj\u0011(\u0010,,D7ov a<9\u001e\u001f.xC\u0012\u0004ʥH-Gґ\u0013.J\u00001߻\u001d;\u0012Eٰ\u001dc[!n\u0018\u0017ާ;J9/i\u000bMm^\b(j\u0000i]e ^\\-|\"as\u0013\u0011,b|G\u0012\u000b\u0005upTv\u001b1ܑ%9HA\u0010\u001du:{Mᛸ󿗩\u0003t\u001eD~`\t2Mc \u0019zq^\\32AW\u0006?=CC3\fÁdM/95lC:C\u0007hwܗ\u0005\u001a*}1 \u0010W\u0000-';\u0017\u000fgҳudډTr\n.\u001d\u0017ҵ%\u001cssO\u0012ܚ6Ur;5\u0015\\f(\u0014mwL\u0005k-漢R\u0004=\u0019-ڿJHp*X\u0001M\u0002f2U\u00035\u0017\u001f2Io\u0002vH]@bʶο:fX^Uw\u0015@H\bɹ(֓(Z֫ң\u000eԟ(9Q䔎\r9M?N\tzk2m\u0012_P=6'Xc\u0015k+5y\u000b(VHQhv{Ǭ\\*HK\r{\u00017o\u0018\u001bW\u0015v\"2)nޛ\nqV`笣G\u001c2爾?cƷy?G|Q\u00142\u0005r}w0mi\u0019U[mrQ4\u0013=ΗT':ֽ]=U S\tS9%)\u0017ŧʟ\nN$seq\f;\u0001X'Um{ð:]_I*m[\u001b`gXO#܌$\\\nJ4?VV\b3\t_Vf:Si4(gW[cGG{$٢f\u0018t24\"<ɳf\nYL4\u001dʨ\u0011N#zXSyȩ`_\u0006OMq݃\u0006OOrs\\S/AK\"8U\u001ee\\֬\u000bt\u0012S\u0015*\u001d^J\u0002ބ\u0005*s\u000b`6=[pBR۝@\u0001߂v!4\u0000\rs->eS٦^c>zLUon\u0015O\u00156<j,*:gMvY[ݨ=\u0018q\u000et$AIS\u0019>\u0012\u00003/)C]]\u0003t=\u001a\u000fe\u0002=9=\tdO\u0006\u000b3\u001fr\tV g\ts{L\u0007IM/\n\u001b\bw\tw8\u001e2)&V9\u001cws/JrS\u0018%\u0004FwG\u0015vEH6\b?˾Z-.(\u001ai[\u001a\"w:3R_.{pǺY|&,1\u0016̒}\u000fqOwpX\u0006_\u00135iҰIYZCWD-z\u0006{Ӆ`\u000f\u001f\u001c<<\u000e~=4nuD\u0019~\u00135if\\a\f\u0004;<dN I\u0019K\u0005ֿUߡMN^q4qAlܽ(7\u001bk4\u0016\u001a]Q^t6\u0017ųȜEOEmQ\u000f,`\u001aT܁JO`i\u0000\n35=1Kr2=ȽEݹ\u0011\nm>\rvQ,Es,)o\u0006/Ř:;ZI_}\u0007Ic$W0{\u001f:\u000fIx^mV߳x%uxJ(gYe,;Ytp&\\0M\u0003r\u001fp۱[:E$5霓M;0\r}ظʧ@k Uh_\u001fX>wFHbazc_inSƥ{K#tKM:\u0013~5Jw\n{rg.޷Lt˙B_\tGrx\u000eRY\u00026w݋dkBIh\n:p쁌S<ztCK|VY)\u0001$\u0012\u0006*\\v\u0019΢\u0016g|u䟕#:\nͥzz\u0002ܮ-w?f\u0004aY;\u0005!ZI^\u0016┆p5Z*\u001c9hO5Gq8QLKKuӇ+i+wT2%Xgd!3kYrg}3xA4\u001d!^\u00112/Ѧq\u0014o1Mf8\u000eǐV\u001ee\r\u0019\nCyuˇi!$t&^s[\u0013[frV$ތ\"\u0005Uf>&u\t\u0013PMCK3qrRꉶ$5)t#NuXO7JaufX\u001f,FyI\u001f.D)V\u0014\u0011=?e%3x\u001arkJ\u0017\u0019G!R}.&Sob\u0013}஑\\zs-:-t\u000esn\u0005_zG\u0013\u0003ͣɮр\u0000}^+$\u0005\u0007\u0013w{9NQ~?'LO\u0010\u0002|)e@Q}c\u0000_t4#qݕ_\u001fHO\u0017R\u00073\nwDg\u001bL3_\u0003|l\r\u0019wmm)k\u0006>=:U:Kbe\u0007t\u001e_qZ[\"UkMJ[ev\u0012KS=\u000b1A:.xVeo:tԎ>ݳ앙N(i-#I>T~\n[HSq[m~HȘzi\u0017O@?\u0013?%ó\t7'If*ىkbxʩ\u0005/YM\u001cB[!\u00155uu5gJ\u0002buJ(gc9]0}=hR\\M\u0011\u00029y\u001f*3'\u0017+)5=1\u001eYs^|݈k#\u001c\rω\u0018\u001b<]זq)\\i?$QS@\u0005X\u0011!6Wlj\u000b\\9dTꁰU,W\fu\u0004G8\u0003v`O_c:\\] 8Z`,0'mAZtg\u0012\u000e٘9`28\u000b⯻ke\"/\u0019T%:?\u0016JX켔\u0017,n9S?rߐr؎=Vpj^\u001d\u0017L4EśH\u00180#\u001b\u0011C\u00180\u0005ʦ\u0004A;o6\u001ckB|к:OF-*;@r{!\u001a.;l\u001a7\u0011%\\\u0004]\u0017?\t:p6\fɑ\u0014<B%KnY{P4urQ\u0018hqK:-.K*,o^eqyͼPՄ\tUq\u0011\n(7Ga6Ue3|\b\u0004(7\t|)ӑ,\u0005\u0015\u0018i;Op\\\u000b/X\u0003;;Zy\u0011[\u0011<!Zp[{\tTA\u0011IV='dd]\u0016\u0002\u0019LNH\u0000\u0011x\u0017GĢ)\u0012\u001bV\n8G$\u0011N7\u001e\u001a\u001ca^\u001d'l=<_\u0017y\"k)6,2\u0013\u00020yL1p\"\u001b\u0005o5/C\u0017_[Y-4\u001fr\u0014\u001aJtB\u0002\u00173_&\u0015Z?+RX%=RW I\"\fX\"\"\u000f<>G<v\u0012Q\u001aY`K\r9\u001f+\u001ctϔ}Uz+\b\u0005YTm{ѷ7\r0-\u001dED{\u001a5G4I딶WiY\u00044qtO\u001d|\u0007y>\u001cs~;6</`*`oGf[)GLUxΟ*j|sjskx*k&)S\u0017í^\\9t\u0007si\u001b[S\u001fm>r\u000f\u0012w\u001dyӾt\r~}7n\u0002tPLbxxO{׎7]μxA:@='\u001f\t?i>tu'ܻ\u0013~\u0013\u0016x\u00065\u0003\u000f]I\u001aIseK+?|z+,Sc[a[\u0006s{a\u0000qYs%\nU\u001cd@CW{yQg\u001ec>c@zS8fs*$r5l/Rv[s7ۖo\u0005\t]I6\u0017yЂ\u001eG=Z\u0016:g6p\u001c09y?J#\u001b\tJ1\u001dfa^\u001d'.qIUϴȟ\"Dek]\u0014RD`zMJfm3}Y걓\u0004]ZÌ]g,~o:ٱ܋?՜d\u0012^%E&Ak HN\u0016E\u001ah-HkG\u001c\u0011EA\fK\u000fC7\u001e\u000eüco? Oxa\t|\t|W$V\u001ef\u0002X.\u0014-dHn\rfg\u0000L8\u001aZ\u0011-\"#\u001a`ĭa|4\u0019|d Vͅ\\2dr\naMf#A\u000bt橢\u000b\u0002ZqЏ\u0015\r]z[s<p\u0004uti_9^$8ʟ{}2R'>Y _ahm-\r[\u0012\u000eY\u0012\u001eZvl\u001d\u001eo{p~\u000b\u0010Ar\u0017\"oꋋ?~\u0013wsGc\u0005$>X\u0010j]a󩶱UDiEto{o{o{o{o{o{o{o{o{o{o{o{o{o\u0013۽۽N풻3\u000bbl7ص=u2sQ\u0017/׋WPKej八⻶]||\u0015\u001a3uhBrʁP:3ԋ+o\fL \u001feB\u0004zpu'QA@\u0001\u001fߥY?/'ɏo\\=R\\xLݜYz\u0011Yr{l+\t\u0004k~j\u001a\u0004%1f¥tZ\u0007Iy8pΆ'A'G%JQܔ\fv6\u001dfג\u00199\"I즮pp׷Mi+$6GeeağWy\u0004\u000fM!Gyq\u0014\u0012TKHn\u0000=]hgOt(\u001dѰ#ײnze\u0006U5G<\u0013)ڃ>?'Մ(GG80\u000egUS\u001f+\u0016^l&wFȦ-d\u0019\b*YBS#r2R{$8\u001b/[\u0016\u0007QtF{;ղ^>җ3\u0017DD?#~v|\u000f_s\u0017>ҷYn%\u0014m\u000f˾\"w\u0011NL\u0016\\4:8>%°\u001d%Pmr\u001cQvo>zyL\u001fB=N8?%/hrq8d9?e\u0014jzɐ'G}i\u0013\u0012#$$n+LXZ<nu\u0003/[S49+F\bo eC߻騽^:Z>ڤ\u0017R1\u001c\u0014\u0013~S`7V\u0013/Eȇ4R\\,\u0005\f\u000eUI&p׉\u001cqw\"w,QH\u001c\f[\u001eU6jr+F=$ʍ+r\u0005YEf\b\fMmJ\u0014[o9 \u0015\"2e5UVK=\u0013g\n6m֐ol&*'\u0017·Q,RNSJ2'M}`ɧ*HxkM\u0016\u0017V\u0007k&M%yQ$%\u0011~ev4\u0011U&id\u000b'c\u0002J_2nñvG\u001c\r\u0002\"SqJDSUĉ7%J7TDn6RmM7Mk\u0011o0E;9\fXCG?1-Erq;Dؼ\u0004#wݱV\u0017]\u001aϱ{\u000e0\u001f͙w\u0002\u0017>_\u001eC{2:q\u0017mM/\u0011v7\u0010's낟U\u0016\u001dK@ԏ.\u0019uMqː\u000f2k9ӤopߪH*MF/-\u0014f{\b4=L\u00132SsҊ*5\r\u0001v\t4̀|\u001a\u0002\u0001+#\u00060\n<0\u0007\u0011(Hè\u001f}7\u001f\u0013g4%Y2|$\u001dm]:%bcH\naD>f͊YJƧ5\u001a,\u001a48\u001c)W$\u0018\u001aII*g$\u0007򔝖 v[dG\u00063ɕ\u001c7d\u001eƖr\u001b\u0006Vs&\u0003HzF\u0001V\"H\u001f\u0005*\r\u001cBS\u000b,4״dHqHO\u0007l\u0016LI\u001dsXWu\\\"\u000fG}k/c'_ʂߒ|\nYp䙊U\u0011^S\u00122+W\u001eD\u0006w$Yyp\u0019\u0017Y0Ui}6t9\u001brI O=b®a\u00122,]X-JnyU\\M\u0018?X\u000fɭdm\u00050\u000ftX_8b߿19aMy:\u001cqI\fdOפ|^QWij~\u0006oF^\u0006ˢ\u0007,#zǷ~\te6I)$I=V@\be{cž{I\u001e]UG@wtwb\nDu\u0006=B5;û\u0011͚\u0006=B\u001b@w6(:,miVk\u001f.޺i8:IB\u0018\u000f~>0\u000f2pS|\u001bK\\.=WRzl\u0005\u0005W\u0015\u001f\u001cD\u001b%9\u0011Jmiu\u0004?PE?\u000f\u00062j>R5@)\t3(YXEAK|̷{F\u001dXkWs\u001dm\u001ed̓d,咊giꡳ:\u001c*\u0011gj7sS̽uu8pǌ\u0011ϝ́y1\t/\u001c~~?>nٔ|d0\u000eu\u001eC+\nBk\u0004ճ9A&R[-qg^2`OȜWf;q-!s=b79娥ױ:_\u000bN\u0014CatK~\u001dյ\\]\u001b௝\u001b]_\u0006REI/1e\u0016\u0007qK*~ѿY!H\u0015\u0000\"_t\u0015E~U\"N\f1ߌ;o~C7\u00121\u0016&FscɃjݎ_\u001bbP4s\u0018\u0012MݐI\u0011d7r?AqAOqZ\u001dNщAm3#&aI5\u001a\u0015dP9I5Ԕ\u0016]g\\H|M\u0016\u0006A\nW\\c\u0016\u001b)\f.0\u0003p\u0007˺>$1h؅\u0004D6.Cek\u0005;H:6mXָ\u0004[ڿ\\\u0012\u0015\u0007\u00020\u000bc\u000eY~\\\u001a:,Ba_Q]BmOt駪(\\UQzOϢcw&4>ٿq#\u0014%d\u0005GF\u001e \u0011\u0006|\u001f<KK\u001bS3t̃ݾNsM25\u001dgwiji5`m~\u0011r\u001fӿ=cgr\f/E7[fe-|PRO$6X\rutHwG\u00159\n\u0011\u001d½t54\u0005Qk5MӉzچ t\u0011{\u0015Q:\"r7i\bszʜ~M߃\u001disjR溿\u000eYα9VΦ4}ب7f\u0016̡R:( &\"\\_\u0007,_\u0006>oS7e\u00196{_}[N|wͲ?6\u001bȠRr\u00023m420۴E=, 1aY[d~ע5~j{j f˶;ɜCe\u0011\u0018TĪ!\"pCY\nsӷ.b\u0012\u0005ǖ2ةBJ7\u0003ᴃ\u001f\u0019]s\u0015_7\u0003x~<{1\u0002\r]\u0004Z*\u0006\u001c<\f'\u0015,@®\u0014(e\u0007T*f\bK\u0017\tL\rG.`&v<\"mMI;c_,[RmW|S\"=:w)\u0011ǕzZ3XK\u0013$,\u000b<]>ao\u0005\u0006??Zܳ\u00152S+e\t(ޚ,ZMsBk\\;V\u0007s]|hKMH7z-R,n^#Ho\u001av3(>&0n`.yw6=\u001eǥ\u000b%@Sǋ\u001dC̺C\u000e98x\"2$<m)u{.yKh\u0012\u000f̻ŝf/x6g5$uc M\u000ebp]M\u001d`yl$o5u\f\u0016zL6\u0019\u0018;X\u0005w׻\u001e6[z~݆[ߚ:eBZ\u001fk#w \u001eC:M%;\u0017\u0017+Ez\u000fI4\u0013[ n*\u0007@\u0007愽e޻mv\u0013i;5#^?.Y4\u0017\u001e\t\u0016\t\u0016\t\u0016\t\u0016\t\u0016\t\u0016\t\u0016\t\u0016\t\u0016\t\u0016\t\u0016\t\u0016\t\u0016w9;;;;;;;;;;;'`z`׿.0;;WXS`e]+O?rw<LK6>\t<yO\f\n1,\u0005\n/529\u0011U#*6\u0012wJHTJ\r,\u0007\u0003AIK&w`<f9\u001a\u001ajhهyE5E3l\u0001贎.ޭ\u001c+J\u0001$?~?\u001bd\bOjݎq9aj\u0005Q\u001cƮz)\tRd\u0002C!%oD\u0019\u0013ud*C\u001f9\u001fy\u0019&'苸\u0010\u001e\\θ\u001bEw'2]ɛ8j\u0016\u0004#S!t=9Ӿ\u0017V\\5w\u001fOiɣmi]J\u0018s~\u0018\u001a\u0006be\u000fe\"cXuҸB`dOxX_uɷgW\u0013?Gֻ]\u0013<7K7U~Uܬr=Qܳk\u001eݓ\"=%-plM[o\t\u000b%^\\|iQLbm5lRjYMe)a[=2řD\\k\u0012qZ-uZӔi]RۣK{.3cx*{T\f\u0019S׌R>\u0004p%ˍa&~_\u000erFc{gdo~ؚ\u0004ؾځfތ\u00181Sd}&X;fdt{qhfR\u0006L\u0010]fa\u001fG|\u001c~Hq\u0011agc\\ׯ\u000b;e31fuvlG\u0015^ˡ\\`b_l\u0003l! {~D&d\fA\u00116\u0014\u001fIGjqu䛸\u0017Wŭp\u0019^zYqf\u000f\u0012:\b?\u0003.Z`6+#յ&?\u0019@꛿,o\u001dj+ESN\u0001#W16o(7\u0005ل\u0018u\u0006*6ghU\u0016lEkf\fLwOw\u0002\u001b\u0002D{q bmyMs|\u0003G>}NXg@\b4!,\u0000/&ve˓D1wg\u0015|6\u0013En}&b0O!6KM>ѐ\u0012ߺD;C\u001c\u0018L\u0005hB6\u0010[Ss\n$hLfw~zԕܜ42_ȼ!\u0017ڰ<\u0007NT~}9*\u0013@\u0005\u0005#2\u001aG\u0006O\\\tdKJ窡<*bF秉XX:\u0014Ҡ?F܌PrrMFd]n~»4iq\u0013]˜GH\u0004R8Ո~\f'{IJF8\u0010\u0002 \u001a\u0018\b@޼\u0002*\u001fkm0\u0006\u000eu/Whh;SJ>wC_\u001atyzm͝\u0000.~\u0000٫A7w\u0003y!\u000fy#-$\u00023*W.4oJm-9Ws\u0000c\u0002`\u0017w\u0013b:\u0019<GD\u0003b~\u001b3qo%7N?.\u0019i>\u001d6Y`n\u001a\u00010\u0004\u0011OH\t5\b\u0000\u0011\u0007Si\u001eV1g'?,6k%\u000b\u000bB,7Yɂ}+ؙ*C(rBbgM1>F}j\r닿5\u001d\u0013\u001f\u001b2z9ӟ\rK\u0017'\\\u000f\u0005Vy\t\u0013!+в\n(!\u0019}\u0018CT\u0018s\u001f\u0010k)g\u000fД\u00139f5ss35 GV$A{0-`i57F$!\u0007P\u0002\u001d\b`8[fg\u0002\u001cFItï)dhz\u0019IF?ZJ\u0013RQ\u000e3ӧ\u001fsoO}~Z`IiҜ\u0010rcU\u0005GHi2fFWJس$AS\u0002t\u0017?K9\u00102LP\n\u0011\u0006*,wgME.˝,qOɽ'EGtϢ\tY$鍔\u0013[[h\u0014[&Wi:1\u0012\\$u<FH\t\u0014\u0005\u0012\u00101HR\nJ@drXB\u001a@0>ts^h\u000frSO\"\u0002Sr[M[\u000e\u001ffG\u001cav?7p$\tO=sw\u0013ZU(>اL,J\u001f\u001f㍆c\u0013\u000f3+۟y\u000eQG{G\u001cw\u0013~'l5C\u0002\n3NDAc\u0015)\u0019?\f9*vh\u000f\u001dBm>\u0015l\u0014ma^U;\u0005ʤo'iS2oOEV\u0006p\"\u0004h&Z\u001a\u0004T:\u0019;S@}\u001dfA\f?\na>&Ox.xRR\u001fX\u0011<P_\f\u0016KIu5l&\u0005+J]d}raF\u0003`X*X9`͛eڎ't%dgjsNծg|1.Nsn\u0017\r\u0018?{Ϯ73\u0010(ݖA!Ṷo&<\u001fE\u0015ҝ4k=bs~~qꘔcRۺXfS\u0007\u001fqfӏ?\u0013lpK>\u001c\u001fDZN\u001dI\u001fP+cXca\u0012dܗu[Λve_:g\t4حkES]f\n`=ۣ\u0017\u0018r4_\u0010\u0007\u001f.a\u001bN\u0016͹\\;㯛o>B%bߩt@,fT\u0016\u0013\u001a\u0004X~\u0016[\u0012R^#Kmk:\u0014r^RM-b\u0000\u00131uB,\u001af&Z=4O\u001f\u0005oӊ\u0007A\"\u0006Y;JT?TIn\u0019KB{ͺ-R\u0002\u0016\f}\\%1NNq.#U݇\u001b\u0011\u0017q]Z\u000e/{8\u00001s\u001f\u0018i\u0010]\u0010LgU#\u0010\u001e3ub\u0015m\u0011\u0005w!F\"\n\u000e.h\t+0M`6pw&W\u001c\u0019u^1V_ß<\\\u000eN5yԾЭޖtʤUu.3;4x^׸|}쪷iH[S5.{r'7ӬH6wWs=\u0004&a-\u0012&DjeXX|L49$>`kL66ϕnffcs5\u0018lFSӬt_>Gx\u001cci\u0013i\tN\u0002-Y*GUS35iUM{ÿ\u001aM\u0002R㨻@\u0007fs^ss\u0013#7$]&LfrN:Ql\u00120Udy\u0016m<PW\u00045L^\u001e|NF3\r\u0019Ej_U5jm\u001ci\u001c\u0017u\u0019~DnZL\u001f>2(j;sӌ8ze\u000b=\u0017\u0005_#\u0013l[/NF\u001f.^h\u0012.>\u0010\u0004O!\u0004T\u0004e9fzg\u0012WTJȝ\bD\u0002o\b\u0018Q\u001aI,[f~&W-ZG-ݵ\u0011GxEO&/k@?\u00142D;،?}L\u000bk^iD#JA/:=I\u0017!\u001c76T1f~xwD!$>؉c\u0012Ꮃ$Bܽ\u000b]\u001d7o\ns킴OD\u0011cг}s?~\u0017D/1c#{Z#~hU\u001d\u0013)]\\$%.\u001fЀ\u001fZi\nw̜Qf^0\u0007V;\u001d\u0016ojP0OX\u0017PkSC?(*\u0013\u0018E<N&2g9w\u0006MZNe\u001c\u0017hkRjiuZRK*g\"ZM\u0006ziZKkyJՌ]\u0019\nj5!V\u001f\u001b͖'Se[pK\u0006ZH}T-Sv\u0014\u0010\u0002!z\u001d7\u001f\u0005{\u001a\u0018:ߌG\u001a\u001fDR)$̽͗\u0011\u00139veDέ|\u00191SK\u0011\u0013in苀p\u000f\u0001]HzWa2z\u0004$$u@ZINf_Yuc((^E6ǧ9<6#M\u00067<ԝ\u00069aExw[\f\u001018cwV9Mt/\u00178K\n~7巿O/a_\u0007Ƨ\u000f\r\u000f?W?\u000fn\u001elX/=V\u0015x=6\u0007'\u0006lJ\u000f~/j1\u0019\u0002zͿ\u0001OW}W\u000by\u000f<\"}/Y\u001caS}<]_N\u001b󧏿W\u001f!U?\u001f/~ӏ\u001dgWg?ß\u000b'\u0019_轗Y\u000bض\u0000PH\u0017\u0002\u001f\u0011&ɧ\u0014o`;όQ:;\u001c)׀9غۅt=\u0012ww`M\u000fJ\u0003\u000f:nN\tlpo\u0001tla`\u000ea\rX\u0005AMλ[;\u0003\n|)܇\u0018\u0002,T`ӕc2\u001d\u00176Rza\f_`y\u001c\u000bpxgXU{ yWG<m`\u0017\u000e`.\u0015\u0010\u0007-\u0017l\fx\b~w~\nqP˹\u0007<\u0003x\u0016pk\u000fBh\u0002\u001eL^ux\"GUh.\u000eup8|xvl\u0019\u0015\u0003\u0007rn`\u0007qp\b\u0011IU\u0013U;?^mn\u0005率<<\u00076C׋56qLN\u0005[p!P=\u001f/\u0014)\u00068Vq\u001a*#,#7\u0007CtqIO7DB@|\u0013|\t+0qy<zWȞ/e\n8=\u001eQ4\u0016\u0016\u001a[<sK\u0011ZV0v\"gœ\tՅ)\bϋa\u0019/s`\"<X\u0014\u001c\u001c\nO8W\u000bY\u000e;Mr\u001c09@\u000fJM\u0000+\u0007 ehv\u0007xq\u000b`S\u0011-\u00118\fUU\u0007O`vq\u0017KPumD縒<\u0013\u00161\u0016LNX\"\u001cd\f\u000f\u0017`Qa~^yM&́\u0004O\u0014ea\u000b\u0006G<\n&`0+Gz\u0014\u0005s\u0004\u0015\u0012NcW*\u0005p\u0002T\u001aQ.\u001e\u0010_)^\"\u0004\f\u001eg+\u000b֬0:\b|\t\n\u0005k \u0005\u0017=u\u000e6\u0010>bx3X \u0005o\u0013V\u0015\u001b\u0018\u0005kO;q\u0011(>nLmCf8V<[o\u0012,\u0017\u000e\f,\nNp`\u00168\u0005߃MVɅV)'0U7,\u0006.\t\f[w-/asxT\u000e\u0011=B*\u0017\u0004Ǯoa{QZ\u000fܝ\u0006\u000b\n3\u0014\u0016\u000fk\u0002xj|#Ը08rp8,b[p5`JG.@L\u000bV/^\u001e^RҽX\u001dux\b|lV>L=W\u0011,eN,\u001f\u001c[\u0003\u0015\u001aCF\u0003$\u0002\b\u0005\u0004ˍ؍L{,i\u0012D.=\u0018#.^}zx\u000b$LƖdTS\u0001/9\u001bǰa\u0006\u0015\u0017,c\u0012\u000f\u0016\n\u001d\u0003o\u0004FLؼ!,.\u0019\\Y\u0016dUy\u0001\u0002\u001b\u00054p\u0016,TӰ\u0011($\u000f'P\u001f\u0000\u0005\u0010>\u0015\nfpb\u0006y;evhi`\u000f,J<\n_\u0015wf\u0004\u0013\u000eo\u001a\u001b\u0011,\r\u0002LmIr\u0011\u001byO\f>\u000fp\u001b\u0005\u000b\\xI\u001a\u001f\u001f?|''xtx.\u0019H<\u0019<ݳO} n\u001a\n\u0016\u000b\u0017\u001a~}%X:\u0018\u0019!@\u000f\u0005B#\u001eY]2f;\u001b3(X-\u000fEfl\u001e_ٸ0\u0014KX;#ILohh\n^~\u0014w\u0016/\u0000vQ8q\u001c/\u000eW!$n{ⱛ0L\u0007+\r}F\u0000\u0007\u0006\u001d&#f\u000eͼ\u001bm\u0013i\u001c&\u000f>\u001b9zw\\\u0019\u0005;-.x\u0010\u0018\u001c^\u000ex_\rWF\"=ߊ\u0013|=?mOǟL_`.I109/7>G?/\u001fW5\u0017\u001f\u000f?{g_ẟ\u001f\u001cx7(\u0013}\t^-9o\u00190g~\u00058]Z?[F\u0018C=\u0002`l\u0018*x\u00057\u0016,\rV\u0002y\u001e\u00037Z;\u000bxmw\u001f6Ó}\u0010\bo\u000e\u0003\f_H+w\u000e%\u0010\u0004Rt<.\u0011\"\u001f`a!nt[\u0007N\u0007;\b/\tx$<\u00166m9v(\u00129#7okf\t[\u000b\u0013<?`qnauV݁g=l\u0007\u0018\fƂx\u001cFt7G7}5\u000fx\u000b_3\r[\u0003\u0005rEx\u0010,\u0006\f\u0016+\\N\u0006N+nd'#a)\u0017!-+\u0001`p\u0017 \"8&\u001dU\f\u000bN-CH\u000ePɍ\tj?p9<\u001a9_\u0010\u0011s0Y~8fVi\u0018(OK%e4<i`1:!H\u0002\r\tvYg\u001a6\r\u0003|\u0015!\u001cħ\u0001'\u001ePQ\r \u0014\u0013\u000b\u0002epLt\u0003<\u0013\u000bO`$I\ts`c\u0006 h\u0012\u000f\u000fwą7\u001b\f\u0006\u001b*N!k\u0000\n0'[[F0yp\u0019Xj\u0000>/+6~JG\u0005x\u0012ͅ@\u00157D\u0006:\u0019w<\u001f\"I\u0011_=Pg\\\u00137\u0017\"\u000eХӍL/ܦ\u000bC\u0016\u001afW!n\u000b*~\u0004p\u0000|$R<\bʥ׆aDص3[JW\u0016V^ng%-:|l\u001d;O\r\u0000Q\u0006LEai̮\f\u0005\u001d\\ʞ\u0006,\u000fO\u00032\u000fp!\u001b<Tg<\u0003B\u001eG>\u001dk\u000f\u0011?Oo\u001fs\u0001sVqzð\u000b1\u0013\u000bD#j\u001bwA\\_L\u0002a_Of\u0015gC8J&\u0002C9ғC}p`/\u0018Ά\u0003\"^;6N4\n=}\u0013\u0004n3^\u000fl6-?d'<>\u00042x?\u0018xG[\u0005dsZ\n\u0019ð:I\\3\u0000\u001d/VzذY\ror4D\u000fsBc1NjgL\u0018f6 =8\u001a4`WyS\u0018\rIY\u000e\u0015\u000e_KLNf#\u0006\u0017\n\u001d\u0005zʚ4L9\u0013|_\u0019\u0018\u0007L0mˋ#H\u0016\u0011:\f=F!_15\u000e\u0004#^>\u0015Z\u001b?1Z\"\u001f\u00041ݔE\u0004NP\u0014\u0001:H^p}\r/nI{ \u0000;\u001a|.\u0004I㈚\u0018=\u000b3zr\u001e\u001e>o\u0016\u001b(\u001f\u0016L0f9\f\u000e\u0013,Xx0YT{*8\"Οg\u0010\u0012{H\u0011X2\u00170`z1].|\u000e\u000boaS#ÉQ~ק\t]\"hx\u0013Gy\u001cX<a\b7sx[\u00006\u0013;!^\u0003\u0013I|l <\u001a\u001bjh9Ti=rڙ)r\u0006[\u00071\u0001\tqA\u0012_~\u0019.\t_ŒŢ,S'!LI~7e{\u0013\u0011FsL\u00033ON?% ɂ D]4)#\u0013\u0012b-qav+\b/m}0\u0006\u0018\u0007rlo\u0006y`#XB3~x|.z\u001c]~AON\b^B\u0016\\AV7wd\bZy2s]:f\u0015Ӕ9 ??\u001a抻d$_\u0002ܫX\u0003<-\\b)'b\u001e!\"U\"F\b^Yu=(YWú\u001c.Ɛ1$0*\u0002W\u001b\u0011i\u001dVLRg{\u0013Zf}XxY)s7\u001cWmLG\u0004+3a5\u0017'\u00176ٵ6\u00140U\f.v&a-b#\u0013\u0004\u0006,0Xé[A\u0017˓`.\u0007JٝiME`_\u00130/\u000flTLsV\u0017+k4ukc\u0013[3vjʂq3%52el[\u0018=:ɰs߸H\u0019\u0017`2809U!2X=0\fA%xC\u0011Ć\b_ul8qܸ'`rgW(\u001aK8\u000fw#df!;[X\u0017z_q?\u0019\u0017<ir\u0005#Ƨ+\u0013\u001d\u00183UO02\u0005\u001fVQ8/\\=渉M,Uliw$@d\u0011:72D?fי@[6g㊗\u0015\t\u0005\u0016\u0010>ߛ[ ߸\u0001o\u001a7`z\u0003\r\"\u001b^y\u0013D&\u0000ht g\u001eEH#\u001c\u001a\u0003!3\t倩UBY\u0015Jh|\rpRڅp԰\u001d\u000fƱ1%ډl\u001c+\rdǁ|7t8\u0018^5\u001e\u0012ebnx4x>6teYh-x%2b\u001b!0W1Tӂ1%f\ts\u000b\u0014ƿ6N\u0014Ðc{_\b9;`\u0001\u0003X׉ҍ-\u0019\u0004&}de\t_Dm\u0001\u0007\u0004\u000b\u001ar\u0015\u0013qxά\u00067\u0006\u0007F.\u0003´1+U\u001bz/i\u0013[w&\u0004<Kmn]r\u0005Sq;\u001e\u0006Ք\u000eKbDD5\t\u0000N':ƵK\u001cg\u000b*j'YfRJJEGq?\u0011i-\fV:>{nĜ\u0014TeJDAMrzAgz\r(Nw\u0000qÇ`\u000f\u001bk2I\u000fMgFGŌʰ\u0005EI>\bex\u0003h)]`GE4_.#)|+.;7&#BLܷ߶\u0005\u000b>0qL)3X0M\\.]\u001c4:\u001e>U8\u000fB\u0018\u0010`y)Sg\n\u001a\u0004>^4e)!\u001au\u00143\u0007\u001f,0\u000el>\u0000`\u0007\u0000x\u001aYn\u0013yFЛ\u0004zQAf㲀l9\u0002\u0004מ.\u001c\bfe\u0017\"W\\\u001a5/W\u0003CX\r\u0004p5R-\u0014ӞoT\u000f]1ZnBzLcN!9\t5\u001aT\u000f?\r#\u000ba[\u001c\u0002#yx\u000e#όqyj܇\u001dˇ-]\u001cXOx#%p\f/+]\u001a6\u001fi_wFlvH\b߉\u000f\"\u0017\u0017j\n%\u0001\u0007VDW\u0000>j%\bpkp(#\u00055>O\u000f7\u0001M\u0006\u001f6\u001f!5H`fe\u000bթ\u0011dݝ\u0005Kel-76\u0011\u001c\u0014\u0019ۍet\u0004z<\u0012NKg\t1\u0004$-2\u0014A\u0010,0teA\u0006zhâ ەq\u0001&\u00039g,ZoM2V;cě\u0004\u000ej/qMa6b\u001dG:k91\u0002G5ލr7A\u001b\u000f2n\u0014W-\u00169az\u0001!$i3Xgꈬ)\u0018\u0014dAdoe)pn9B\b x8nTkF?1R3$\u0007wtXgb\u0013x9\u0007e\u001a\f:=\u001d3;\u0015at\u0014N6M1S&\u0013*OO\u000b/\u001er\u0002pZ\"QGd.p|t\tM8g:z-\u000b5\\ʱLAų74\u0005\u0018|\u0010\\\u0000}\f),Ö#b49F$\u0013g\u000bhyr\bDgM\u00031/\bF\\8\f\u0019.p\"\u0006\u001a103c0?1r4\u000eЫQ\u001dCA:\u001c$Ĵֱx\u001d\u0007V\u0016^0N0%_XCA\u0010\n\u0012\u000bS\u0010\u001cg'a0394<\n\u000f*j'\u0004\"#\u0012C\rA?\r=\u0005F[uu)\u0003\u000259\ttbgl\u0003ASpV:YAh$4R\u001d\u0010,NI/\u0011MJ\u0005\u001fܙ1B{,\t1#,&/*Or\u0013v\r {\u0010MG81{𢗸J(3[\u0004\u001bJfe~z՘/\u0004'\tM N\u0013\u000b*t!\u0006wx\bTFO%X^XX\u001e|9oգls6\u0010?\b@y}D]vB \u0002_t\u000eDyn\u0010U0q;\u0017IO\u00023y2\u001bZ\u001alm˸- @@\b2\u0004j1\u001e\tHʗ!1+\u0010Qϑٗh5y\u001a<l$|hߪRi208$\u0019jn\u0005[d~cc~xT{BKq\u0017)5&ōt\u0002EYCmtx3\u0013q[R\u0002$\u000f?ؘ}\u0019\u000b\u0001p,\u0004\u0011.\u000f5/\u0016\u00118ijmr\u001ftA\u001bu*\\\u0010\u0002Lo\u0010`,Pp0t6<4cńs\nu\u0016mi>{_XJ\u0005/NB\\\u001d\u001e\u0016\u001e|\u0016h!tg\u0017\u0003e)lR\u0007\u000f]LF䃝@y͌Ű46ވԋ\u0019厵;$\u000520&E)fNT)|\u000e1WGy*ŠjI\\*U!62+j=5O̜+S3;\n\\\n\u001209\u0014`܀4\u0016!o]\u001a04\u0000bA5tb|\u0015ݻ5\\c\u0015C\u000f\n(2uC\u0014D3\u0005R\u001c \u0005cO\n\u00040\u001e\u0002L?Q~dA\u0014SAz\u0001߫`Hmg\u0001Ť{RBK\u0002\u0000\u0005RqBiXD1HT|?1pT8Bf\u000fSA\u0013y!V`C\u0015\u000fHiܯ`,#BR 4rH̒P N:Q\u0018i\nFAHU*GOU:W$B\u001c\u0002ɪ4N`\ni\nܫ2r\u001a$<)\u001fTPTY:R\u0001K2SAU\u0016\u0000I\u0011r\u0005ޭҸ\n\u0014>\u0006+DyI%\u0010tV\u0000&P*\u0001\u0000*d뫔Bj\u000f\u0016\u0013ǢLP\r0-\bU_ѽ\u0015ciFhJ<+}]L5\u001d,DJ^Ӥj2`\\Xr.!֚U\u0001mcMCTɨxy!\u000eEj\u0004j_/\u0014rӇd۳*\t[YgIf,-AǑ\u0005^U)\u001c6\u0015uO:V9ų96q|%z&56!.̼Vl1\u0012r8%\u0013\u0016hX#V\u000f0d_X\u00168,n>XnsbVWSkY\u0003jrp\u00036\nHA/\u0011z\u000b\u0015]ji!̼Wd'[њ\u000e\r+\u0006aܗ3L\u0014\u0006\u001d4U`p0p\fW M,\u0006Sf\u00196`V\"\"\u0018\u001f>\u00027qw,KП\t\u001d\u001dW`$uÎ[:ٸ\u0005\u0016x\u000b+:,70B\u000bӖ\u0013u\u001d2(\u0004:\u001db7,u'b\u001d[G;h璄jd9\u001cq&Sn\u001eՠ\u000f\u0017..l?\u0015Rh)\b/T\u0012H3`2#4[}Up;5DfU\u0018N>ł\u000e\u0014º,G\u001d?K\u0013QH[\u000e\u0011R'lE#\u001eQ9L'\tjv9~-_*RkcdNf\u0017:Sz\u0017\u0011R:q\\D\u000e\"C\u0006Er\u0018\t \u000b\u0004\u0013FSEF\nTF\u000fS\b2\u0002y6؄d#\u0007`4If~#<ꭎ\u001bX;\u000ev\u001d-Τwv'tVF⯕̲ߘZ[93Z|wO7\u0003nlԶ\u0014;\u0004\u0005*-ouw85f\u001da\u0004.1sJ\u0018 Y/%ú1\u0016HH/\u000b{\fѡ\bR˞g*l00)X\u000f'sB\u001cƅ}\f0\u0019'f4)y#b,q\\'\teU;: -~fJk\u001aTB\u0002\u0018\ru\t\u0003KJ8|j%$\rD\u000b\u0001&:^iKRZ@@\u0014V0Kȣ\u001fXdLL1(.4~£C\"!\u001fs6\u0003cQ\u0003M\u0017\tp\u0015v@=r\n.@`W9)]\tg\u0002\u001eD\u001dC٘?m{+\u0019\u0001-E4x$B<c\u0007S!t1\n\u0000sG\u0007\r\u0007Ի[Y@\u001cW\u001dۊ@C\"q%q\u0007.dh7}Meh1YM\f2@t9$voؽ٨SQ\bNR6e\u0018TK\u001a\u001a\u0003oagG\f\u0007g|^\u0002x\u000bl\"\u0019L\u0007\u0018a\u000f\u001c8BD\u0015CFVJdo+.D\nBqGy\u0003)IM\u0007\r\u0004k\t]wiv\tt\u000fS'\u0004M-uATs'Nfm\u0010?UKo\\\u001a0P\u0012<32\u0002I\u0018Y\u0002#~$\u001a?zc\n5\u0014I縟\u0002$cRjsM%)q\r\u001cy]\u0005\"{郞\u000bqX9V\u0018\u000e&˶چp$8P-C0Io\u0005f\u0015N'G\u0011&>7\u0004g\fւ\u0018)\r+\u00193\u000b{4U\u0006+w^f4ӛSv|6ek)f}zs\u0018@o00j6\u000b7&i3Roq釞-U햌+Gs\u000f~zٴ\u001a\u001a+\u0004X.\fU\b,æn;O\u00062[`\u0005YI\fd\u0006({\u001f8F\u0014Z߆&sؒ\u0014+wY/XI%9)e\u001d;!\n$Z\u0014kt[Z\"O \u0014\"\u001bh6-ŕּi,#[XCظ6\u001d6ǅ\u000f\u000b\rt\u001eX1\u001d{gJI\u0015\t%hINJ\u0002\u0010xi,?bCv\\t\u0007x!R(\u0016f2mLxn#*\u0013_w\u0000!Ka/.A\u0017'Ĭ<X\u0003%(\u0016XI\u000bH\\\u000eVzc+CI_|W)<ᯄn\u0017\u001b!\u0011\u00012=Ñk\u0013cQ\u0014un\u00108YJ5ϥ]\fr%2k\u0011oB$̍;\n_i|ы0\u0001{R\u0015[=t[\u0017\u001f΁2.'Fy'𷔜\bw\u0012o\u0017I&6\u001a\n'p\u000b\u001fե!E\u0017\u0002]Pb{!wu$d\u0012b̉~uu\u001b98A{\u0004\u000eRA\u0016\u001d\u0006KΚS\u001e&߱؇@;\u0011O!\f1\ne$Cʖ\u001fo?l8Q,qs|W\u0011,lN|$V<>\u001e%&\u0005\u0017tDfRwlHW$Gβ3Wz#XM\u000f\u0014=2+\tyAD!9o~\tZf79oJiRŎ\u0014\u0019Bbar_\u0004$\u0011壕R\u0004\u001c?Q\u0013F.._lbBF\u0012`%.Q\u000fVr\u0018Df-)%\u0013l%,s\u001e\tp[\u0013\u000e!Nb\"\u0004\u0001\u0001I\u0016c\u0018[Q`\u0003}bړt\\ט\u0002!pKhH ѱޕ\t,ET]\u0011|H?=\u0011=,/T\r~66\u0010\u0014r5\u0002\u0010(g\u0011#\tGS(\u001a\tX3|OL%#ZfNF;m`\u0003;f<ǒ\u0003M\\mΗ@-]\u0017\txv\u0013ׇ]\u0017q\"}65/km6td]\u001eMNc2`,'H,O#2V\u0010\b\u0017Kj:jdOX)\u0013^0R\u0013P&_\u0005ށ\u0018\n\u0018\\_\u0018Q\u0014;\u0018Em)\u00132>\u001d\u0001\u001b9K_z\u0011\u0012~!\"25tY\u0010\bB>a \u0010\u00122qq\u0010Ltq<\u0019aqK=H~\"4G:\re|\t\u0005[%IOK\"\t_b,.\u001a=\u0017VDY\u0000x\u0004l!!J'NyEe\\g\u001a-~7QwUQR6O\rj(;wڎw\u0003\fk`7JN8Ѫ_\u000f?\u001f~I{p[/\u000f'\u0002r\n\u0003o\u0013M)\n\u0003JxB\u001dLхKu\u0002?%\u0010[-@gW\u0006o~9\n/{\u0002ȧB&\u0004\u0013\u0005F\r0j `Z\u000b/P\n\u0005\u0017cC@n\u000br+;\u0015d\u000b5)2T^ص\u0002ib\u0018\u0016\u001c\u0015<m.ǌ4D\u001eL5\rB\u000b.Ԫ1+89\u001e1ڹ΂#x(<I`Zgi\t@ģ>Y #=ٿZy\u00055\u001d\u0015x^\u000b\u000b?i\u0004\u0002A\u0013{\n|{\fq\u001e<x+jy\u0005G>)yS.g:\u000b.f\tݴ̂H0|ij\"{SL:\u001d\u001b#@\u0010\u0016\u001cSLz'I% .LI%Quio\fw\u001b;\"(\u0007/\u0002[\u0014\u0004!\u0001^$Wd\u001f\u001dePcoԟo\u001a\f*b\u001dRU\u0010+\u0017\u0013L\u0017\fE`M-8fوN\u0004\u0017``uF7>K}sX\u0018SpKkJ\u000eгm2-@@p\u000b\t.\u0005?v?\u001fbOA66i\u0011Zͱ'\u0017=jy&\u0017dcgc\u0002\u001dlZMqkQ҅\u0010IQfIoNF7f3WE\u000bm.Ƥ\u001d\u000e\"jiHр\u000f`+LєJc\u0016EҲ4cȦkcQk\u0011\u0005&g+i#flN\u001bĆ(5j9A\u000eŘ\u0007ȃ6\u001b  [l\"+&C>*Gm6齵̢b3E=\u0011..\n_3m6\"\u0006;\u000eyv\u0016'\u0010iU\u001b\u000f\u0012z\u001aZuVk\u0011B+D\u001f\u0014\u001b[n16X*x\u0005GWRl\u0018C\u0007%6\nǶծr\u0010\u001bnK\u0007\u0010n#>(8Z[`os\f|ظ\u000e\u0011<hJOF1%L3L3N\u0000۫ˣ\u00174\u000f*y}sWS\u0015\u0017V\u0000e#O]2wɼU\\\u0018\u0013Ս{`\u001bl\fʋc.Rp쫟W^`1Gsו\u0017qgCW~Y9T^V\u0007i\\)Gu\u00171;]\u0017^x~\u000bG:Q]fAsb$u\u0017[<ؘtu%,ܳ\u0007XN\u0010`D`\u0005][PG\u0019.2ٮ\tH{]w$K{$a0\u0010$\u0012\u0003A׺\u000bwZ'p\u000b7P\u001et݅]$V./O\fK*\u0011,DW\bSؗX;i%\u0011+{6HD\"ԞĤ|ՈkZD}\u000f%6\bB\\r[RoG[ܒ!\b_x\r\u0016l6\u001eD>rG\u0001\u0000\u0015\u001ds3k4J\u001b5E\u0013B\u0000+e\u0013g5=\u0016;*fqzЅ\u001cQx\u0004\u001c'V*d\u001fY\u000fCB?M7`\u0011;j.\u0005\u0000\u000eHVV\u0013Ȇ\u0018d=Dǐ-6ШM%_\u0013V\"\u0007[\\<殘%\"p|w2\u0003#Ǯ\u0012d\u0003IV&qfl#)@G?.\tSyt\u0018\u001cniJ\u0005a8e8\"g;\bj#e\u0012,eD7\t>){F$RqJ.~\fN+;3!nO3%FP,΃!Ob|BCϭO2M}rKcrK>W{j~\u00027YX\u0015R}+a\tԭ=\u0018\"܉T\u0004.\u0004t#B!\u0000؝B/N$\r\r̦df\u0001L\u001e g(\"8*\u000bW8/ާ\u0001$Ht\u0004H4\u0006|8Qvw\u001erȻXHƑ\u0013/Z\u0005\u0014[\u0004nL\u0006.s_Ǎ\u0013ˤ\u0015}\u0001a\n\u001c\u0012\u0015\bSpM\u0015M߭\u0000EYQhyń aUѷdMٰݪbե\u0011\u0016;H\u0006tS ta.o\bÅ\u0017B\n$1j\u0014;C:\u001f\f\u0005W\u0014\f\u0019&\u0013,q'y&yv\u0005\n\u0014]\b\tG/\u001c\\/y\u0011b\u001daK\nYDIz9\u0018B\n\u001b\r,ɍ&UacrƉ_K\u0019.gK-a\u0005I~\u0001\u0013q`Q/B14\u0012a\u0016.\"-Ø!Dҥ4\u0006+oѱ;52Qn\u000b@`6JD\u0015\rN\u0016\u0005.\u000e\u001c\u0017WEs<+umOI@K k\b\u0014\u0001X)@\\:[\t!92r]Bg0+T˺\u0018Ų(\u001bm9x\"\t\u001b\u001b%lI\tSL\\%yXFd\u0019펅cƇt-\u00142vp\u001d\u0019\u0010įI\b\u0018IY\u0010\u0003\u0019ֳ\u0011\u00136NJDBت\u0018g+9BOhc\f(BiI\\\u0005\u0016u\u0000d\u0015 *\u0004oЗ\u0016;BsKJ(KW[\"Trb\u0017\bem)鬉(DiJBg\bq2E.\u001a;)3@!j}g-\u001f$q\u0010('\u000b\u001f\u00062-%*_yխ\b/6\n\u0011ձx\u0015S\u0018MX\u000eb\u001av$I\u000b'\"\u0011sue?_0q[Ӆt4tlHG\rb8\u0019\u0019x2Wvw`zcd<0\u0013_]$3\u000fol\tuQ\u0012Fn׮D}ǠZ5c#Mk\nv\u0006\r\u0018HdI\u001c\u0003)q&h\u0000\tm-KGoxW\u001c9ߪ-Ǵv5z%1jBrк\u0016\u0001IDԙ䖼v%P+\u001aĳ|\u001dUL\u0016'MԸH'\u0019/$}.&|G9ݻ\u001d\u0010.úy%olvn٫\u00144l#ٝ\u00184O'2*/f>\"-&mC'.vIדaO\u0017Ck\u0011265A\u0004Q>]%s0\u001d\u0012ǯ4p־UtiP\u001d+\u0013\u001bѹm/GO\u000e\u001b6\u0019\f\u0001#[B\u0007{\u0015>w/'Lt\rE:u;/o|;Χz\u0006)0\"Uҍc\u000b)LvŻ3`Ͼ̕?3\u0005d[Y \u000e_?[L05\u0007\u0016wty3d=&j<52Nj\u00121\fd:\r0YH\u0010RC[\"FFo'e\u0016n&7 ]\u0005\u000b\u001cB\u00171\\1_ܩ\u0001\u0016\u0011hc*]ʗ#j\u0010fV.Ag9t&a9;dIPlAMU=Ly\u001e\u001b0ZS$\u001fgR/m.#$=63\u0017ǝʕ\u0010\u001eBS%h\u0017\\|\u0012hn1Q͙xo\n[!T\rꅵxE{i\u0011\u00114򂴹\u000e@\\H%SQbslf\u0002YQH(tX;[\u001d9,˞]3I$(\u001cmmcE䪜Oi[IZ{\u001fx\u0003\u0004ѲU]vu\u0004\"Uyش4U\u001a^H/\u001bE\bX'%錓NsEi׃fC̋gNWb,KR8;%_ԑ\u0014hl7\\(b\u0014If[\u001dfl3[JߙT\u0001*[T\u0018ZL{vz.󔍺5-ֿ0\u001dbFZ6¹Z6UoU3ײ)ؼ\u000f*ٲgN9j\u0006(nՖhrް*@q󎮄UȔ&X1nX@:N3Rcn)rd)eM89b*'&ӓO\r\u0014!bp\u0014\u000bWLʁ\u001f9\u0007fTS#x7\u0014\u001bR*Q*<R\f9ѳK8M\u000fTIŅ^ES-&\u0015\u0016F\u001c*\u001cNyK,\\SsX=\u0017\u00071))bt=rA\nlRI\u0011(ɄN\u0016rA3(P\u00183]j\u0012cjdPyJ(UQ\u001a%3\t\"Q\u0012IJC\"\"*yHJȗTdԔv+c\u0002oᢒ\u0012N\u001b\u000e\n2cq>JF:JNrTzU(ܣ?1\u0013\u0000ҟ\u001a\u001fX%5\u0016mHDO%T\u001e[F%՝OLH}J1o3JCՠ\u000ePfc,Q̧pu,>\u0016Vf,˨7\u0016t\u001dA?T\u0018O\f\u001a+_63b\f*)[_Jb,,\u001dT\"\u000e˖}MW=mQK\u001dUU[mf=[\u0015svjSgA9QK*#REBۥiS\u0015)\\TH\n9b\u0011G\nʠ\u001d\u0011\u0005|d\u0005y\ns\u0005.\n#tD\u001c\u0019liS~9FH#E\u0007Y#lf\u001e\u001b\u001dp|b\u0016wO\u00003!\bR#IgG^\u0011U\n#K#FX<1t~d\u0004\u0014ˈkk\u00134\u0019\u0003:\n5SC\u0019k7M()G>\bY\u001eL\u0001\ftB&3Βv\n\rY2}\n?r#rY\u001c*/@*0\u0002,jAt³69Z\u0005Uy]U)a\u0005&\u0015zW\u0015d\u0015\\x_\u001f\u0005\n<M+Pk`X \u0000Y}Qƾ@.\fCB\u001e1\u001f6D]\u0010J\u0006vagGpћRDIUQ\t`\u0017.8\u0018ItA?Ӳ\u000e\u001bbœ\u000b*$Fw\u000e6^D?*Tz&IjaI'\u001aG|J\u0018\u0017\u0017C͜䵎Z`s\f,$淚ǢX﫷9S26\u0016\t\u0018Wʙzl\u001eYTMf[ժ\u0016vǩ^zU׻!xdw\u0014h%)C\ts98R\u0012_D`'%,DDɖltd.Fܐ\u0006HJB\u0014\u0004+D\u0011Q\u000bc8qy&v/\u000f\u001c\u0006F]\u000f 3}\u0010ByK\u001dJLJl,;U4:9\b\nd\"R?\n\u0019!L\u000bLY3&UOA|OPs\u0002D\u001egBF]cy+Էp>Qg\u0013xE\u0007S/\u00128C\u0010wh:}\"o\fvLԈ$q\u000fCJ`\\.?2wwV\u0011\u0017R,?.\u0014 V\\o%+p>[F,+LN\u0002ַQ\u0010=yA\u0016jPL\u0017\u000eb8RO\u001baz\\Ɖ\u0007%\u000b3\u0006q.\"ԤeR'2LH=Dn=\tS6#UHZRU.QMEݘ,\u0015(ȒraGʅ`~Q W\u0012zG\"DzԖIyN,凹F\rG7J0XJqMdrHA'\u0015C+\u000e?E\u0019\tH\u0012)\u001eIH!2D0H`\u0010?%\u0010\n0\u0011\f\u001b\u001ap+\u000bk\u0006!\u000b6E6\u0018!\t,N^Sb\u001do3]Y^䵐4Q\u0010⧤&&FR2N\t)YXc~鎌5Ne\u000b\u0014˨c\u0007(T.uw(\f+\u000ez%Ia_'Kw|Щ\u0005y7y:~bHD$fѓ \b&ՆSF\u001a7J)\u001fN\u000b\u001cR@-z@G2\u0015Fٗq\u001acÎ\u001a4j626jQ*8jM\u0015\u001c\u001aG\u001dg=8\u0014\u001feWJ2K2jK=Qtz,\u0016q\u001f^FԘH\rҦCmjUβ;O'\"Q\u000eZha\u000bV9,ju\u0006\u000bU\u0012ZC\u0019ȪDlhxW\u0012zW\u0012(9pc6\u0010\u000fj\u001b\tfwD[ZY\u00142rSH\r\u0012\u0018\u0018\b;Xa\u001a&\u001dr)JfjQ\u0000#J\f_]B%\u000596\u0010'z\u000eR_ע`@h1\u0012.KDߑ\u0006L*\u0002]az\u0014{7QqNv\u0010[h\u0015g\u00111ϯo\u001b\bIqp\f\tC>ϛ\u0017\u001d,\u0007&;&/?@WΙXe8\u00191G\u001ad\fv =Cf8XRY90&2\u000e%9\u001a2dd$1\u000bm/=@a/<\u0007\u00171w92둘)\u0004\u0011\u001d\u0006T\u0018\ni\u001e9j'=/1qPKLf\\VƵ>l \u001bQe|2MǦ\u001865&١lt)\u001bf㌿9PA˂EI^\u001fH0E\u0012G?>\u0005\u001fND4oBO Φ8\u0012c4Y\u0000\u0002rWyQ0p\u001e/!n'y,mL>O\u0005#\u0010WVG\u0014.n\u0012q&Ab\u001e\t\tO0i\u0006xm*%'yEN\u0011\u000bbR$Q:cX\u0002GWD\u0014/ó痦\u0018 <j4ȄI+\u0011'yp ԯ0\u0007EZ)\u0011,G$2c<\u000fBC&zb\u0005\u0005o_Kr%%\u001c\u0014vQz~%\u000e|q\"7<Q=oK<D2\u001cw4n%ܮ'\u000bf6n$K' \u0014;_GM=j\u0005ml\u001al\\:\u0015{j\u001do7\f܂I}j/0\u000b%GLz6v8#VQ=:r\u000bɗ;vRTWo~G?\u001fu\u0019\"\u001crfp9,rx+\u001d68JgR\nÒt\u0007셓iA.]ZDv:x3Uv'!`z\\\fpbLDXd(\u0005\\bl&-\n_+Y\u001bW'\u0006}I|]t8\rq\u0016ڗ\u001c)I\u0018N\nQ\u0018a1\u0000C\u0006NF\u0018lg4Z\u001e^}?{ﶣْ]=AC\u0018\u0004RW,߱7t!C\u0005\u0016L\u0018\u0006Al\u0012\u0004m7)T\u000b~{oXeƌT\u0015[ŃMحWc<9ƣгӬe9p4\u001d\u001cAY¾v~C&Xҳ<\u0000^ZEPG\u000b\u00053~#},}_\u001dRe\nd\u001bnB('Uho\u0010:4í\\R\u001a!D\u001b\u001b]\u0011c\u001d(&C\rhEԠb\u0015L\f*-\u0011d\u0014A-Hg\u0016i\nB\u0014*7\u0002Z\u0004jr5\u0002~~&_p*c%\u0000\u0011M9Pp8\bke2g\"7px]B5|m=T](|!\u001ab\"m\r\b\u0018\u0016\u001be\u001fok\u0017\u0005q*\f\u0006\u000e^#QA9\u0019#!#\u0011#H\u0018\u0014\r\u0017+7\u0005}\u0019/\u001e$\u001fN[h@PkIa\r0{\u0006E4؀\f:m2\u0006\u0002\\­'ֽ&z0-ҟYb>x\u0018\u00168'\u0002Lۥ(.\u0001Fbw2&/b(̛|{{2g\u0001v\u0001\u001e)<\u0017K'(Ihg\u0012 ƠY\\Dȷ\u0002JA\f{r\u0000\u0007vRҪ\u001d0Šlj\u0006B?)\"{WI&Kaje\f%Q`˹\u0010OB݁\u0016[\u0018\u0003a\u0001EͲm\u001eś,p0b\f \u0017<\f\b֣lc&_,H]\u000f.`{ᦧ\u0004S\u0005_\u0000z×Z\u001f2v\u0015\u0011˙Z\u0014B\u0001pίʾ\u0003\u0002s\u0014\u0013}ʨ7̏]GSe]BKbF9A\\Rd[Ch\u0017yi\u000f7@/\u0006gПcΖ\u0016ۂ\u0001\u0019\u001b2O,Xj@\"v0+4\u0006}\u0005b\u0016_}B\u0002H\u0018/T\u00011jj)k\u0007Lkq%\u001c+3.Y7O\u0006س:3|\u0019c8^ZPU\u0007B}pd2`\u0005ۖK.¯nTc,\u00067] >]ޭei)\u001aCIm[|:\u000b\fkH_\b%-*64eW\u0002S}\u001f3ce\u0002UmO0\u0017\u0016\u001f\u001e\u0016\u001c{U'1;A\u000eKM/`\bv>\u0011\u001e%l%\u0016BA?-F3\\ڂĶ\u001cm8C5plQa!ͩ|\u001b~\r\u0004CȒQZ$Ѱ\u001clʗL~$\u0002\"K3/g,qN4l0me\r\"J-269ߵ]kX8\u0010,?Yd||h32E\b\u0006dl!V\u0007p\u0010:ˌ\u0018P^\tۘڳTf\u0005,\u001e|酅\u0004|}}{ۗ2{Lތ+\"\u0002D\u0002\bd\u0015jB\u0014\u000eG\bF%^|\u0018**I1s2LC\u0018y\\z:@\u001d\t\b2Lm\u0006>}<.ƪ\u0006\u0019Cv=\u0017\u0002\tK\u0016U\u000fo6YDbG0\"\u000e#ۘx2߅\u000bMlQ}5T\u0003\u0017G$Y\tmۀ\u0014eX\u0005\u0005ڝ\tH}\u0010\u0019adȽ)\u0007H\u001d.Aqv%j\u0016\u001dk{֕n\u0006YXn?vK\u0014J{z{@5YR|\u001c\u001bdZAWG3U\u0016W\u0000&V\b.Ӣ9RBF\u001bq\\\u000e\u001ej\u0016\u0017\f̘\ftsk6C^\u0015RٺG{<ģ؍\u0002M\u00174'4cg\f\u0018w5|Q d'G\u001c\u0013\u0017.$C\u000ePGV$.4אKc(n7͒(F.\u0004)\u0001\\\u0018E7{mrBMTŨCy욫K]Γ\u0013&CM|[0-2Ŏ^*\u0018.ǧ\u0004 \u0015\u0003cAb\u001eSc\f\u001bMëz^!\u0017JF\u0007`3kQb\u001fb+Ga\u0000N\fM7\n(edi)*j/ɀ\b~\u0010#\fWc-\n`\u000f{xI=\n-1\u0006ikӒ\u001b\u0012[P%Q]d}T*=j~\u0001)\u0007h6R\u0017*,K:ă~ME\u0015\u000b3F-ؒlwL\b\u0011zZ\u0010Pu,7\u001fީэ}!:D\u0012p\u0012lZg\u0010~#GTq;NH\u000bT\u0002\u0006BK\u0007Z!F\"hՓ\u0007>\u0003IH17\u001f\u0007\u001bї\u0014\u001diNmA^f\u0010\u0004\u0013\u001dQ\u0012Qb\u0000-TV\u0011*Q+\u0010+\"ͶKB\u0000ޟRRw\u0016jy\u00119\u0000:i\bƣD\\NfMA\u0000Q}]蜲H\u000b]l5?7{,oE?+(\u0007gǔj\u0013n%\u001cqzxjneB\\E^mN\r@g'sS\ra\u0018w\f\u0001IDuqZ]n\u001flH>,ΎT =jn@qz\\=\u000b\u000b#>-^E\u0016mwZ^%B]\u001d\u0018\f\r\u000baQ''\u001fMa\nl42Ӳ-\u0010_dtItك+.mQvDRM1!\u0005\u001do\bX<\u00002Yd)\u0016)\u0000;z\u0010=/K$\u001e<\u00115Jѓ23q0\u0004 \u000eW{pݩv~\nfG\u0011ڴĘ5.j)=Lx\u000ft.d/\u001cZ=\u001ei}A4CYb3(ebC铕lGA1|,sy\u0013$Z5FqQ\u0015k _8+(z(i̓U;EIC!\u001b[jsh/N\flg\u000f}]^P4Avĩ1'\u0018^wDREX+\u0006R\n0\u0013n\u0011K\u001abO}SCr:`\u0013^0\u000e\u000b-R\r;-M\u000f\bO|@;Q2\\_+J:\u0007BAM䘿#Ny`<j'҂%,\u0011rR,iɳ\u000e\u0019-\u000bĤҡbրꈟ{_y<)\u001a89\r\u0000>\u00100kz\u0017XSqv\t@<P\r\u001bbP\u0000k0`\rIrՅ7\u001aۡBA][OD.F,t6XtW9{x7j0\u0003|\u001cF\u0001\u0005WTW,1Dw.`Ih\u0003\u000fB\u0006Y\u0007Bo\u001b\u0012_jo\n-bmP7<cߘ6\u0001W\u0003+GI\\T+wJ4.4ҥ-U1;\u001d~[f`\u000f[=WC;>\u001eXS\u0010\nJjʱ\rx?lN@!l\u000eF08\u0002[1'Ȯ\u0017z2\u0013hTTZAe>C\t\u001b\b\u0003\u001a\u0018X\u0005\u001a\u001e\u0012~.\u0013d\u0007jQPZ\n>|ܻXA\u0004ݱ\u0015@Cї\u0005]u\u00128)[V\fB\u0013^`fVF<AJy9A\r\u0014=B\u000b/ᄽ{}Q\u000e\r f&֦7mА\u001e\u0013[\u0019B&>]Z%-\u0015IhGr ImyЁlӚ\b\u0001_\u001f\u000b1.Huث \u0011n\u0003!\u0005s\u0007>XbdJ!\tH[;NʔpYf`3IF;uDT0a\u0019üWHg\u0012|FO\f\u000bFL\u0002\u0013\u000f]I\u000e\u0002%\u000b<\u000b/>\u000e>>\u000e\u0000&ڀ\u0010u\f\\\f|m<\u0014dt\u0007.'E\b@zWNQ\u0012nC\fxEt\u00055\t GM°t}4Cnɼ's=-Q_NOZ:Z\u000b-\u0002@`U<_H$]\n`_(~eXz\u0002\"Q}$D\t4A^e_tT\u001a:Rr [X-e\\\u0003]}7M\u000e@v<Vi\u0000@;\r8\u001eS>\u0016\bk\u001f\u0007t\b\u0001A̷ǐ0\u001bb.`(\u0019/Ә}B6<ݭW\u0003apB\rv\u000bq0\r$VM\u001ag٨\u0011&\u000ean7}}|\u001d\u0003M~Ox\u0012s4\bİӱD\u001eR\u001aol)?\\Wf\t6$4\u0006|\r65QU\n^ir1IcR3o3/Yv\u0007,\u0013hI\u0002?\u001aXOehE8\b\u0004\u00164b$\t]\u001fE=\u0014J!\u0004x\u0012\u001eR񶑈0\"*X,fLԑsЌ\u0002ۍO\u0004\u0007I{==-@rj2YbP\bJשcZmyC=\u001an!\u000b@(!6[GRkvBh%u0vDl{xϪ\f$Wi\u0002h̄ºҖn4_M&AA\tLm73f|g2o#{\u00067o7O\u0016&ɛ@c6\u0017ee>\u001fxPiA\u00133a\u000enaܙO|LC\u001b\u0017\u0004^3/!G칳~љkʢ\u001frp\u001dD\u0004!o\u0013!֠y>\u001c!0ђa\u0017z\u0000vk\u0018J\u0012}\u0019<0Vz,l`dI'O\u0017H\u0014D`-\u0014Y8\u0014v\u0017Q^,4x['9\tź^i'բf\t51(\u000ecթ1s\u0004hF?T\u001aO\u0019T\u001e`\\IӮԙRW\u001a\u001d&\f(\u0016*rfG\u000e\u0006\u0007\u001b+{\r.UoMx\u0010r<\u0017D\u001bhkSϤ\u0000mqVA\u0015\u001d|u>*\u0004\u0015Ƚ^\u0011\u0016P,]9B\u0004݀@#o\u001b\t!Ss\u0004o\u0004\u0018 F`o\rd\tD{l.7WmaSnyl\u0001\u0016n^\u000b\u001f6jꍁ\byRds>\u0017\rL$Y~h\n4\u0006%(Dn\u0004VTnMD\u001e\u0012\\w\u0016jz\u0001bw78\u000f=)\u000f;$;\u0006nX\u0015|Ѣ[\u0001#k8SKw-|\u001a\f\nK|+{G\nAH\u0002N\u001f:P\u0018F&lwZEƪ\u0012nXP\f\u0001\"ʌjZ[z\\\u001f,trhYeElq`\u0019\u0015yZΧ\u001bۓ>ޚĕNv;IC:{,)LK\u000fG\\Ypj\u0012y<\u0005p{Ϸ\u000eb.1\t\u001d3b#m-p\u000e\u00128=R<*5\u001f_q\u0004\u000bؿg\u0011<+\u0001\u001f\u001cB,ŷ\u0010\u000ea\u0006|q\u0007EE;R#ĀdG\u0004\u0004\u0010'\u0004\fF\u0005(n\u0002&\u0018˅9ڀ\t&;\u001ec\u001f0D<D@ \u0005\u0012PLG\u00054\u0005TU\u0001\u0015m\u0000x\u001dv\u0000\u0005\u001ff{\u0004\u00110k@$`B@B,\u0014Pw\"\u000bqXX.\u00071a!04 \rendstream\rendobj\r175 0 obj\r<</Length 65536>>stream\r\n Cx\tI\u0019\fu\u001b3\u000f(\t\u0003'\u0004@j7\u00025,\u0001\u001b{}\u0002vO\u0002:7daS6\u0017ڳ\u0007h\u001c\u0012\u001d|K?\u0002Cr\u001bq)>\u001c\u0001\u001d2\rA~\u000f\u0004\u001cz<ˎe\u000f?<\u001cO\u001f%\u0001\u001fJ.\u0001,݄P\u0002\u0005{\u00195pBɆ\u0015#B9,\fY\u001ciaX#TGS0̝Bc]Ka\u0004X\f4b\u001apR3s?\f\n0]t,)!PBq;K\u001da*\u0014S\u000f^2\u0018\u0017\u000b͂0r\u0016\u001a\u000eapظY}01\u0017Z&az\t\u0003|s\u0013\u0000O%<CPm5zlkAYy֪ͷuaa\u0001V\u00196>naQx,B\u0006\u0017Ж۰a3\u000bay-@Qsl\u0011*¯\u0007ی\u0003\u0019LP\tWغ{hV/CsL`\u0011WT}\u001eu͍\u001dK7%\u0013ClT\u0018Qٻ^Ntx^\u0006fh\u001b\u0017[q \u0003aȃ`\u0003z!mvDy;<ȯ,H\f-5w\u0000ٌ\u001bDd>\u0007Q6B?]d'E\u001b0\u001a?\"#\u0017H<AuAB7<H'_M:\tlD0_H\u0005i~=\u0018&\u0002TgvTG\u001f.'{m']\u0019\nu\u001e\u0011T4_\u0014R*\u001ftBQp$>9ͤ\bBcB\u0011CBw98\u0018C\u0004\u0001Ƽ\u001c~n,\u000bX`\u000b7p\u000f\u001d\u001bGtўOK&mپ$F\u0006_FBwo/1˷>/*.lZ@VA\u0001[n\u0004t\u0010n&Q\u000eև\u000ed\u0007q2X13o\u0012Yh$C\u0011\u0018`K\u000e@R\u0012-y/%V\u0004L\u0017OV<2\u00019_Wy[~bg7C,\u0012\u001d˗1\u0003L\u0001QRrNGӣy=fq^ya/'w`\u000b%\u0001K(er#]H+h\n֞\nhi\u000f9%p\u001f_\rL)Kc?F\\wD\f\u0015RAfg\\WeOrߓ4GjUJ`%Aq:*\u0015v&f\u001aBYɪB/jPQ\u0001D\u0004\u001a#3U\ni\u0002x?vvZ\u001b\"QLLS\t6%5\u001f#$l>B]ܞL\n\u00182X\u0013ETwUCC )\u0015\u0014\u0006\u0006\nU\rv.+T=r^P3\nEAp.ڶdɳi\u0017P\u001aZ\u0017M(.\u000f7fOcw:X\u0006\n`\u001dpv\u000b#p= )n1FnXwկP'\u001d\n,|E~J!O]֡_\u0001M:\n\u0016vQ=5KEDBsT\u0017\nR,y\u0005IqgY\u0002?,.Vfxwa\u00157\f8r\b|J\u001d`\t^%xL\u0010\u0001s&\r_wB\u001d\bVx+\u0002\u001c=G?rG>\u001eظo'\u000b%I|\u001a\u0019ϣ\\}ݤE]/B;\u0013\\ \u000bA|w\b\u000e:|S-(|F\u0004\u0001\u0019A\u0017mX\b%\u0001o\u0004ݟTz!3LUZ3Za%Üˤ|[↠$\u000el\u000b\u00156 \t-^l]|\u001fH62\f3\u0005^\u0003lf4Ԙ\u0013solTZ9\u0019\u000fsN\u0000#k\u001dγ\u0019x+==>H!\u0007/>EO/N+(:}%F-袏׆\n\u0015㣞tTv\u001d7_\u0011߯\u0016N&s2,wcO\u0004Fd_p~\u0004\u0006hYDU\u0019܋\u001e\u001d<\u0004TZͦ\n\u0007.\u0014L2\u001b[P\u0005\u0003'R\t3%f[\u0016\nu\u0000\u0014I;\u0005~Y\u0016\u001aL\u00195q;}w\u0011\u000f\u0001:&ZA\u001c?GuLn/\\\u0018\u00020\u0002c\u000b\u001eKDJg\u000f\u0000yN'4 ,\u0015*\u001dpv\u0019r5!u\u001fsE\u0013\"ϖR9j\u001eA!77\u0015\u001d\u0014Z>\u0007} \u0016\u0017abG~Q\fˎ]O\u0002\u0005>o\u001fYcwZ\b\u0000IaٕٛI\t.\u0001k>\u001089\b]x\u0004Q\u0001B<dAk\blJְ\t/\u0011px\u000ewj\u0012tF&\u000fp\u000e3 d\bI\u0003yP&_\u000bK\u000ft\u0007j\u0012 ^1a\u0011^~ ȷ#4\u001a~0S1z\u0013hc\n\"D\u000bVJ\t$u\u000e;.7ߡ\u001f2MI\"\u0012\u0005z٦@-mW@0\u0002ʫ\u0003ػ\u0004ٱ\u001da\u0006\u0002-y\u0001\u001e\nU(!oXݾ\u001bxb1\u0005ǃV1\u0010!\u000b\tf7h\u0006ʒ+:{W*q-,\u0014$+\u0005yH\u0006\u0006'5\u0017OL܀;\b{`ta\u0015Bv&Dw=\u0000\f\u0015Ct'֔dK?G<OX2C=ff^Y\u0000\u000b\u0014-\u000bo\u000e/'_\u0013\u0004u\u0006\u0010\u000fIsLhFu\u001a\u0015\u001dV@vT\u0005k*S+\u0019YC\u001fY\u00100\u0015;KM\u0003\u0006\u001doOI\u000b.Ȥ\u0015@/fraIt\"'^Ieq\u0012\u0001\u0018Yԕ-c\u0011hZ'0I\u0015`\u0013Ȩ1pL;0\u001f{\u0014]\u0002w4q\u001a@\tUh'uɸ\u0001`\u001e3\u001b$D&e?\u0000,<'\u0000\f\u000bf\tr*f?ߴ2^;{\u000e\r\u0001}n\u000eyxs,Іՠ>\u0000x3\u0016q\u001dq9\u001a_4_X\u00101<\u00059 FO@q\u0015_\u000f+?cά$=Xt\u0010WC\\.-O`L\u0005\u0011ZАLIg\burU>\u0011\nz6ɥR-\u0010s\u0002\r7Z4ƭ2,\u0014\u000f\u0017&頖q\\Env\u0004vXlU ahXQ\\c[\u0014\u001eD\u0006Hn>Ua|ߖ>?n%-M|:~`\rF3h|26|_\u0007?OO;}sq$;\"贈]\r:]\u0010sAH*fPIWޝM\f?IX\u0011v!!g$A۩79Ԡ}\u0011\rt\u001d\u000bCבuT\u001aY+\u0016#\u001f@d]uI\tk(h$7Up\u0016%(X2#\u0013\u0002~\ng]^WBfP\u000fle#\u0019h\u0006\u0001\u000b!\u0002;idZd-̤'bDfBGrey\u0001\rFK\u0016\u001b~s\u0007ˌ(&v>\rϟDǨnS5W\u001flb{\u001e\u0003\u0017mPJ*1v\u001a4\u0015\\}\u00138*n|\u001dD\u000b;8[ĥ\r\t\u0019upصx\fh\u0013u^Ϟ=3bYQERB\rO\u0003\u0007bƪ glDg$!B\u0011Ru!'`\b\u0015\u001f灿/X\u0017yu\u001b}1P;p,ߕ0e7/\\m\u0002Be^\u0019Ƴ\f\u0019g[u3IiR\ts_\u0000颲4\u001f\r\u000f\u001e,jv\f^ao{qI&'XJ`\u0006CRv\u0016vC[DM<\\2<W0ov\u000fn?\t5x7Ųi5]\u0010]7&BT<UgEgYc7#\t%\u001f\u001c};q\r\u0007eaL\u001b\u001a1T?W0,GN௮Yb\u001cdt\\-ALq\t,o~\u0002,Px*ศd\u0000rēR(s3k獎k0\u0011 l{j\u0007e7Hss|8OJ\u000b\u0007E\u0010kN^\u0014\u0005E\u0015G`{,Jsݫ%{y\\VՍA$9x.!\u0018+g%p\u0000x'\u0001v\u00181\u0017=Pc\bQǲ'AJkg/~y,f\u001dڒm豾u`j$\nU5ڼw8MB:Znb\u0006fp+Z&K\r)x\u0004Wos5\u000b.vO[\u0000HR\nq_\\ӕOղ\u00075hI8,\u0017hL%\u0001Cq|F\u0010\\NRRBvy&'b-uB\bӗ03L\u0016ax\u001aD\u0011^6j\u000b\u001d=K\":g-\u001e!M\t3$hjaМ67o$e:G!:ɹՎΎģ\u0015\u0005\u00137tbu=\u0012Z\u0003\u000b1\u00178uj\u0000[\u0019~\u0001oԥ0(n\u0002f$\u0006CD\rs\u0012)\u001a\u00142]A\u001dqT\u001dN\u0016\u000b&@\u001bʠKo\u001a\u0017`\u001ax/\u0013.o4D}bߨ\u001b]~O7a[\u001at0Jt\u000bs3!1\u001cKUqq0?<\u0000_\u0000j-L\\D$t5ə$į@rʕcp\u0012\\ۄF\"h*\u0016V]]\u001duZ0n!۲\u0013IWd߹/)bW$sZtӊ\u0006]wq\u001eDX>FL3·on\u001f=\u0007<\u001a\fm\u00173Ɵ?xŮ~Yi\u0005r\u001c~P\u00059\"\u0013]/xm\u001c'\\\u0017,\u0013e9=5M9^\u0014\fR\rN\u000e\u0017Maпj}S/`Q[\u0015+\\\u0014K[-4\u000b\n\u001eKcC(2\u0002|j\r\u0013M4_T/m~г]lҩgg(L@ :ϳLO,Z\u000e\u000e.U4\u0019\u0002}.Daze2b\u00166V(ۣ:\u0012h\u001f\nbB)x@~O`~v\u0004AYȺv{F\n}\f\u0012)\u0017ǝ\b߶tn\nv+\u001aK\u0016w\u0005z\u001f\u0010\u000b!h\u0014Ƽ\u0019\u000bn\u0011\u001d`\u0013\u0012cE7e10o]Ў\u0016y.\u000f:؎/ O\u0015h{\u0002\u0010\u0003\u0015oG[\u0012;:!/n?]O\u0013\u001e%RH\u001aG2\t\u0019\u001dZ\r2\u000f}\u0010Z oBrF\u0003Ͷ*5L`BJC8Ua,s\u0015<1^\u001b8$QI\u0010w\u0004\u00024@\u000e)2+L\u0004޺#о;:\u0017\u0014R3\u0002K=?_5[1\u0002\u000eG\u00123i}\u001es\u0012\u000e/9Ј\u0005\u001e\u0002H,\f\u001e2F\u0017\u0005W(,\u0010m\u0005lMr҅y\u0005B,R,IV\u0017:igjΐd22 &hF)!DUV1\f\u0017j@eδo,\u001asT\u0005\u001a\u0017\",^[d\u0015`S\u0016t \u000eb+!ZJ5\u001eE\u001cm\u0002-\u0019\r\u0016;\u0011\u0005\u0018eS,'!\u0002pr4\u000fzh\u0014p}sSnsCe\u0014\u0010әK˷(\u001c\u0002fT&V+@R'\n y\u0002Nl\u000f݄rɣ-)\r8\u0002e\u0000w;f\u0000\b1\f\u001ei\u0000.\u001cT*\u00163\u0000]\u0017ҋ\b*f\u0000\u0004\u001b\f\u0000=#\u0016%Ӌ+1\u0001@\u0012\u001d\u0019G\u0018\u0012s\u0002i\u001e\"g\u0002eʒ:\u001d3\u0001R\u001fz9\u0011@IS5`\u001f@g\u001fY՘\b{\u001c2o8A|L\u0004(ZR&^LD+i1ە@\"}[W\u0014K\u0004x'&\u0002E\u001d*p7S[W\"P@\rY&zJ\u0004,.*I\u0004\n\u0016W\u0004c*\u001dCtBi?P:-\u0005]AB?M\\(08+ ZDt\u001a&X\u001b&+b\u0000\u001a(+.0ٛ\u0004\"\u001dF?_\u001cf\\x\u0007|\bw\u001d*w\u0006h)Ć\u001ftY9D`H=^OvS\u001b '\u0018\u0007\u0010OR\u000f{.fF\u001b:\f+\r`*|C\t&\u0001'Tn\u0016c\u0012`Ý\u0018\u0005\u001fٓf\u0002Ta\u0001͘\u0004@\u000fX\u0018AL~N\u0002\u001a\rP\u001dC\u000eJ.`B-\u0007\u0018V\u0004<C\n@k.ۥ s\u0014@4j\u000ed$\u0016;\u0000f\fuC2f5\u0014I\u0001\u001d8P\rrN\u0001 lb\u001ci)\u00009\u0004AϘ\u0001Z\u0005#\u0000)\u001dR4\n\u001d9\u0003\rBv\u0000.~OY\u0000_n(@6\u0000A<|\"j@?|\u0001P/B\f[5\u000e6^\u0018=\u0017jLRa\u000b\u0015r\u0001nG_h\\d{.J\u00156.T\u0002\u001a{.\u0018\u0012Vÿ?\u0002\"[C\u0013Z?\u0002\u001bG8\u0002o\u0010q\u0006<\u0002\u00115\nw\u0005 \u0014E1K\u0012r\u0001z⊴\u000b\"Ҕen1\u0017GQh{\nM\u0000#\u0017>۱-\u0012h̘\u000b\u0013{3[C\u0006\u001a@Fc3[v20\u0016,3+slf@ׄ\u001eKkB&\rQ{ZDغ\u0016\u0005\u001a\b\nK\u001f[n!C5SH?Ȉ\u0015[gG7Q#\u001f5KdMʹu\u000bފɝ\b A\u0013\t޻n\u0019`5vbC^Q{\u001alAv]xa\u001e7u]L\u0002V\u0012\bYkCULu%I2\u0018\u0002[Zap\u001e02+\r1L94(c\u0017\u001bgQ?JLzofvl,m\u000bE.6Р~\u0002<Ɓ^]6v|\u0001\\G(s\u0013pul̬?\u001e\u000eZbt'3-{\u0013\u0007=ܫP\u001f\u0001\u001f\u001aYd\rf81(\"Eb&\u0003X{E\f\u0010\u001c\"(P_!\u001aG|dC\u0011_aV\tC\u0015_|Phgf\"F\u001e*s\r?C\r\u0006j*^}f\u001al\u001c\nu~ZzN3\u001f|u؃4\u0013Q\u0015{\u0007t!XT\u0007\n: X\\bG\u0015{$+V\\`\u000009=H``\u0019W>æ\u0000\\\u0005\u001f\u0014^LsYZ\u000fO[>K\u0012ݸ\u0011\u0015j+pdbF=.\u001d\b\u0004\u001eknYp\u0000dEl\u0001$ِ\">%1.LDfB\r\u000b1yZhD\u001cKvSEOcm/gbP!r|.gr\u0002O\u000fSon_>D#\u0013?-|eyH\u0012!e<\n\u000f<l.a['WK,r>[\u0012\u0012\b3=\u0014(ѽ}\f\u0010U\u000eļFdl/69\u000500[7S\u0005\u0005\",!@\u0015|\u000e\u0015i[h:\u001d\u0003?\u0006Y\u001bH\u001fhb\u000b_yہ+9a$c\u0017x%IVҩ)`GLd7\u0000_6\u0010}eHzQAfnGd[\u0004{5\bm\u000b4\u0002\u001b9\u0011\\P(ӯ4z\u000elMh\u001ajGV4T/`_\u0017e i{Z؄Hʚ\u0013je\u0001,Kqo\u0001=˗JZ\u0003\u000b:\bh\u001a%k&\u0003k\u001e)H0,3.^Ҹyƫ@^]\\<\u001fGʫ,_]\td7CM_Ӻ\u001bJe\u0005\u001aq[\rEnA%!xpc\u000bw\u0010@#\b\u0011!JMr4ăyޫ\u0005H~S-Օ\u00135k$+m\u0013 c+d\u0000\u0000\u000b*)ƞʖ9On_rHg\u000eH-<\u0012ҼG\u001f,\u0001\u0019ڮ#bU1ļM\u0018J'n\u0005,wY\r(oV.LCC@#\u0012ұRu%'V\u0015\u0017sD8\u001b3,\u0017>v}{wa\u00123Z7@SjI0\t{\u0010ԁE\u0003\u0011*֔H_ۛ\u0012\u0016ZL\tW\u0012%*\t*\n._NbE}\u000fIA2Hq\n?x\u0019-\u0014OD1\u000f=\u0005\u000bG\u0014\u0019e\u001b+.\u0010ZM\u001fyP\u0005\u0013M\u0004 _ \u001eDv\n\u0004v\u0003ڇg\"2B\u0014\u0003\u0014Nڅ`%\u001c1C\\D0)\u0007uj0usGQ'k\u001ejY3\\E\u0016r`K-m(׫\u0016\u000bm2\u0014lj|\u000f\f1\u001bb<#ܥu/.AdqXc$Bdv\u001a\u0013\u0016\u0012I+˚\\5t9\u0004,0JZ\u001dp+~z؇E\u001a\u0010!\u001a \u00159kJ\u0005%N=X܌\u0004tX\u0019.ba4QuN\u0012@KZ(58.dwͷD\u0017\u000fUJ#[^].}61:YD'J\rĪb)&@\u000fF'\u0016x\u0011J!RbVEU\u00005ˍ\u0001\fj+MS*V\\q7\u0010,o&ʻd4y\u001dpj:淇-\u001amhzAp\bE\u001e\u0018\u001baTד\rr2l,\u0018\u0011\u0016߷d\u0013*L\u00148#\u000bN:t+F\u0019\u0016R冥\\M/y4U>R>HN\t@F\u0004̄%(Ү\u0004fIV4E,ǍՙG\"%$\u0015\f\u0002\u0005'{yjo<\u0003Ҭi-**E;/,\u00011(Ce4Z(!\r&\u0019$Ʋ\u000f'BC(4^m\u000bɲL\u0017A\"\u0006r\"&uE!?!>o\u0000?2Dٺ;a \u0007\u0018dJ\u0011T:`_>lY\u001eu8:UrN\u001e34s@\u0006T_HH)ڲk/3\u0001n\u0019\u0002\u001b/1\u0018\nb\bmn@\u0013qV\b7n+Ձ\u001e#,`\u0018׳\u0002\u0017\u001b\u0002\u0015|zǘ\u0014r\u001dGOsE\"\u0007\u0007\t\t*Ҏ\"jy7AV.]\u0017\u0001\f4\u0016v%qH٫Gcꥢ\u000bKD;+B[3\u0019\u0010d\u0011ay2(7h:\u0012E4S~h֗-\u0004D?q*>28\rtRb%AN\u0016`bcP<\u000eE;2#M+#7\u001e\n\r01)f\u0011\nSfUdHo<L/ྡྷI\u0003~׷\u0004N\u0004O\u0016O/kP:\u000fiF\u000b\u0001\u0006;(&;n^D\u0006EK\u0015GƦ\u0005~qo\u001e7@H\nyͨO[\u0016FZ0e\u0017u;s#)G\u0003*\u00114׬H:\u001c\u0019J\u0005w\u001bjژPK\u001a)ƞV\u001ct̲\u00039;\r=&+/̉\u0017ݝ\t\u0012cls_#rA|vc\fEG\u001fZ`\u0002\f\u001c-\u000b-4T3wzED\bm!.(s\tsآE`G\u0000\u00111D\u0001-Ȉ!U\u0003{CGC1Z⡙kU9F])T@1gGo\"WicGЮ\u001apS\u0015kX+B\u000f7\u0006u%ݶ\u000e\u0017K[e\u0003m)-__lm\u0015\r͛C\u0012r\"\u0016C_Qu\u0000ͥ\u0016\nݫT !q\b\tuS\u0006b<Y{\u0001\t̠9[\"\u00126?C\u0003f@,N;$O0EQ+\"_yWᔶ\u000f\u0004\u0012cH\u0018!/\\#\u0004&9lp\n|H_\u0013+8]W[|\u0011T:\u001c\u0015Rr:T\u0000vTdHE%̡* G\u0006S!~/@̾NSx\tl&*}Vhc);\"vc\u0016\nsZv\u0019\fвH;\u001c%ԅT'*\n\u000fX^\b2TitULm\u000b\u0018\u000bK\u0013Pԅ0\u0015RT1ev\u0000{MA7B;#x\u0010[|?\u0000J&t\u001fkt\u001aq/b=f\u000fX,\u0015,!f|_,>KX\r\u0005Ǯ\u00066Y\u0010ӽZP\u001e\tUdDuY˔BYWtu\u0006}4\u000f\u0012Z¹Č\u000fRcZy8\u0014\u0000bۃ˃\"j9Q\u0005TbgY6;TOj:V\t\u000e\u0001\u0017BAoM\u0006v7$İx\u001bP\u0000;Gh\u0010L9v_4AӯE\u001f8J\u0005{x\u0004^\u0016CSTcG\u001d($*vTB\u0018\u0007C\u0013^X\u001cE\"\u0018K`LPR\u000bƴ\u001c\u000b\fh8ڬEKOP`fz<8\u0015\u0014OӤ@CsJ֞hK[_썷B{\u0004V\u0015]2ay3atP\u0017\u001f&]@l\u0013\u0002꺟fX\u0018<\n+\nmn*I\u001a=_\rw\u001en\u0014`k+W\u0010JL\u0010Jt:\u00025&/\u001f/Eja\u0016\u0002o2u?~\u0005\u0001lՌ'NO5؛&}Q\u0016\u00109C\u0016UMG\u0013\u0013.WZĻ\u0003[B-B(iD\f6Vogt,QPm.;\u0019z43DѰ\u000b\u0016\u0001\u0019lβ}qkx\u001bpEҸ`Ro4\u0016\u000e+\u0007*\u001fLk[\u000bo`Fxk\u0017!\u0010\u0000fE݇=d\u0012:Sl;v;\u0011oq33I}K0:mjnH?w'\u001a\tƁGt(\\룁(]}ysQ`n\u00065[KN,Æ\u001dL/Rs@\u0010%,h{\r-C~G\u000e\f |@ŏÇ\\<|y\u00114 U0u\u000f>\b`_5l^NKb 'F\u0017=_yPk\u0006\u0007C+;\u0011)\u001a\rI%6?3^\u0014y4އp\n'\u0000!*<%\u001fVw:!|!TEP2\"\u0016B r\u0014Y\u0016Zb.#(Rթ<_J.{$f܂c*\nh\u001enRz\nEG\\o1%\u001aB_rXǰ\u0019J[`\u000f\u0000{t\u000b*\u0007?\u001a\u0018'ݣ˩'czCsM\u0017ffSƃ#|\tƽH<\b< 4\f\u0005\u001d(טJ\u00152\u0014[G\u001a\u000e\r\u0014`m\u000b$\u0001G\u0003u?Fȱ64Vh\nÖU)@\u0017j_#{\b,p=CEA\u001eI\u0011{\u0005ya}XTO#~V!8gI\u0011)k\u00030_\f@R1T\u0000D[j\u0003s\u0001\u0003q\n(·^VPpyZ\u0016DƭR+Pj\u0001M%h)\u0018cUo\\S:5?L\u0010\u001a>25H\u001e\u0014\n+ݫG㼖&\u0006\u0012gRPwG(<-9ϱlU5xE'g=|(qhCYXEB\"g\u001aD\u000e8JN\u000bn(\r\" ܴlZ\\Y?\u00129J\u000e`rr$>C7ytXtB鄨s3ByTr,`\u001e)\u0012+J|\u0001`%˰Uj9a'UPL8\u0005[\u00027P,k\u000bD!YN,:ҫ!lq')ۊHUPlG\u0016\u0005{\u0001\\&J/?ϱb\u001aq0Shw[\u0011m^\u0001[\u000f|A\u001fR\u0000[dR?5\u000f}\u0005Nø#F\u0007wRJ3ͱѫʪ!!,Afhi\u0006˱\"OKFW^\u001aO\u0006Gd,dErE˄]-]#\u0002Jf*|Oah9\u0011\u0000җ\u000b*\u0019hh6\u000bTŧ\t}WBE$[\u000bNbSY\u0016Ulr{G\u000b1\b4Uw\u00152\u0016НČ|\u00014Z%\u00062HD\u0017Eg\u000euYpK:\u0004>W\u0003^klu\u0013\u0006#\u001fɟW~\u001d\u001a\u000fǻ{~\f\u000f\u000b\u001bFwZwyȃvB\\;\bw0ED;\u001e\u0002}\u0003*d;$\u0000Pyot\u0002%\tnG\u001cf\u0000<F7`}\u000eߡG\bإw\u001em\u0005\u0002*\u0000:\u0000\u0002\u000b;\u0000B\f\u0010hC\u0000g\u000b\u0011Hą(&@Ѓ\u000bT\u0000,`\u0002\u000e-|\u0000J\u000en\fq'd\bo\u00032ɿ}\n\u0019\fz@\u00000\riC\u0000cǸ\u001eS\rPنt*xOiY<j\u0002`8$\u0001w|L4\u0003~yOX#\u0006GQ[\u0012C!RD\u001fK\u001a\u0001\u000eF\"~UU\"\u001eT\thP\t\u0003\u0001OY(\u0013Jq.\u0001\u0018\u0019V*\fC\u001c_qb/\u0010\u0017\u0007<ޕ|^\u00053&{%1\u001c+۠KkQP\u001b\r#7Kab'TfS}fN\u00058iב^SOvka*ֱ<\u001fBu?N\u001d8v4\u001d8\u001cw=ݩ{\u0012.L\u001c;9qp\u0011jK\u0006z捰\u0016)DC0}k{9ƱŊ\u0016\u001e2+=fD\u0001Iv[!C\u000eQWi٘\u0010\u001f^ǝ\u001d\u001bĳ{\tъf\u0002³IL{\u000fT\u0011E\u0012:^c/fK\u0006\u000eb4~lC3S,c\u001bϲ7\rD{\u001bޯ5\u0017\u0013>vvܿVƩ\u001f\u0017\u000e s 5~2Ľc\"~a\u0015\u001e\u0018\u0019*\u000f\u000eO+퍤 Mt录3Mw\u0018-\\殺2K\u001dQ7}쾲YIr\u0012\"\bvILBB/\u0006Kbr\u000b\nѕ]O\nԕ\"\u0002dFV^,w+xj\u000fsJADL\u000bُuF\"o\u0007p\u0002o}_WsX5\u0001QB:(謙6tU-OLA0we\u0015W&7\u0016\u0010Y\u001f(M\u000fcѡeUs%\u000by\"\buQ~m׋\u0007|_V1A:u%\nFlId`\u0011z\\zL'b\u0014Ҹ\u001bzo\u000eu\u001em&\u001f:_r~/$`n5 \fƻݡđ\u0005,.3\u0007g\u0004g#\u00075\u0012AZV\u0001%DlLQT\u00011u\u0002Ѕl<\u000f\u0003ZY7ϯwŠj\u0003RQ7\u0003N_׸\"\u001e%Z\u0019_`TL\u0001\u001bs\u001f\f63u~~㿜\u001c\tW]<5\u0019z*g\u001a`T3m$*<C\u0012f\u0013XAj!k`E\u001e~\u000b\u0006\u001a]#v\u0003\u0017J9\u0016|r6{KEPq9\u000e\u0013RԀ\bԂ=\u0018-l|F1\u000e+ad\r]D;xYV=\u0014:)d\bF}yIvˎȥO\u000fiK$X5irLWŬ#\u0014\u0017@\u0001dpLoE俐ӎ]4M0\u0002aWfZAA\fgӻ\u0000X\u0019[\u0011>6H\u0001WDho,D\u0006C4@Q(|\t`U\n\u000f^\u0010o%FN}ۨ^ \u0004%=\\{\rkЅ\u001b\"fEAѫc_5`KBc\u001b4e|r\bWS;PeM_3C\u0004Ҿ0\u0004N]\fLE\u0002TcF^Nn:^l\u0005t\b\brɇ\u00177`\r\r\u0010=\bI)5\u000er\u0012Ias\u0013A\u0006׾\f\u000f{f+Ĺ3%~\rN\u0005[ex<\u00164\u0011փ%\bһ(<d\u0005\n#[:\f\u001d\u0017\u001f_)\tFSU*~\nE \u0016WI2 ӹ>6(\u0005\u0001y\u001e?C7\u001f\u0017|͎$51g\u000f\u001btG4\u0006AV<;!\"+\u0000[ܻv%[\u0003\\p\u0001 u\\ԇ9₆L!2\u0017\u0011\u0010h)psvc\"\u0005FD)\u001f-_`<;\b6 \t\u000f!\u0018.8~\u0007O{gQ.𸤂'\rK3x}u\u0007~$!8\b-\u0015aOz!7oZ\u001c\u0013t\f\u001f(7WޯxG\u0013I]<eʺ4\u0016ĠO\u0007mc\u0012g9;\u0007u\u001cY\u0002sTg9;,9ȳ\u0004r]\u001cYvn9H<~J\u001c\u0014KvޥX\u0002sb9<\u0007)H\u0004zrwvQ\u001cDY\u0002;s\u0010e9;\u0007Qy>\u0004 r$y\u000e,9\u0004 r$y\u000e,yWg\t$ϻJ\u0007]e'y\u000e,9h\u001cI6K y~Y\u001enoom\u000f\u0005d\u0002\u0015\u0016P1*xVj\u001f>qD}R;\u0018H[\u0015\\\u000e]wE<+g\u0003\u0015ʀؕ1<Uu\u0006A=?9\u0003+OnRQ\u0019bmM11ݢT; zA\u00131_%՞W'ɱ\u000bqjp\rݥڹ7\u0000!HC㋶@fR\u000e\u0002qbjO+d\f)?A]wZSh\b\u0007S\fVh]hj#][VA=>xf\nYD\b.ގ9\t\u001chnFv3^R4O7\u0004\u000f*[>-1߈k1^;t\u001c)>\b;HA\u000f(\rҕ,\u000frR\bA>c\u001f@3\u0012ݫ\u0012o\u001bfR\u0011\u0012<p^\\뫖;h\u0014-U\u0006\u0012\u00071w,{-wɖ{Cy1n\u0011tde?^Jbwٮؗz\u0019U8%V?\u0002ٗ\u001f\u0018RO/\u0011/\u0011/\u0011\u001f\u001d_P#\u000eQ#\u000en\u0011\u001f\\#\u000e^.\u0011?^.\u0010Kxr\u001cqprA\u001cqvQxyG|rvQxwvQxsvQ\u001c\u001cʢ.EEE⓳JŻŻFA\u0007\u001dmŖ4|,G]WbKm.$Ő\u0007/Y_4\u0000;˜Fy.HwYFQ\u0018\\;b*`KCi,\u001b\u0010G=K\u0018ԻƷ\u001fg0]0ϖ?\u0019_&IiS2\r֌\u0005AiY2+oTAiӬF-ۿD<xl\u000e{a\u0004\t\na¦\u0019\u001e\u000e[@e\u0016:(l$I$¦\u0006\"`b[M&,1zIAa\u001b\u0017LP II\u000fba\u0000t\u0014ؔI.o ٖV.\u0010\u0007͆X3#Ti(\u0012žz\u001d\u00046\u0011Uò^\u0003q9\nlFT\u0001c{u!g5|\u0010dU\u0018,sVS\nB̔M]q|9\u0010csQ鑄N@$\tH0OsA{sD ݫEo\u0016yƦg:`9\u0003P\u001f46r>\u0007O\b͋YMestu\u00072)n\u0002\u0003LA4O3c:tE\u0014T<\u00126C/fhXw_\u0016s^\u001e0c4]5Ǔ,o\u0011\u001f$L#\u00002R\u000542-X䔻_\n@nI?^q\u001fmt@F<\u001dq\u000b]b+\u0004j\u0015\u001c={p\u000e\u000f|X\bGK\u001eU9c8\u001f!XnǺ{'ܰ/JC2CP\rHV(e\u000e*cak\u00020A\u000e8?`91\u000e\\\u000bc,*Q5e)0\u000b\u00032>Eh/7=U\u0000\u0017\u001ev\u000f_\u0016z\\7͈Yn䇠[\u001aT\u000e\"$_\u001fH\nm13r(e\rKnb!??YQ\u0016%o0;\u000f+h\u0006E3\u001c\u00165\"\r3s\u001304PjV,c\u0013BxKS'r',>39\u0016ߩ\f|̘r\u0011koӤl\u0014ރ\b\u0016LD}Zxg_\u001d\rJ-\u001cd\u001eVY#&\u0002\",9H\u0004\r@\"\u00167M<(\u0007$<`f\n\u001ef~\u000f\"`e«\fI\u000b6Xΰ<\u0005~\u001e\u001dd4xa@)wz\t{\n|а-\u001eމW)p>J)\u0018谛\u001c.(!;\u001eWs3r:U\u0003Z\u001d4M \bu0ljA\b2$%Y+};E(\u0016vOLLjj:E\u0013u_Hb^\u0000v8z:-5y\u0011B\u0017\u0001+\u001a\u001e\u0017\u0002Rvp)b+$\u0015\nT֓\u001c\u0003i.J\u0016O\u0017|o\u0011,hf(Uq vMN\t\u0000xP@u6!_S\u001d:ki\u0007\b\u0012RK>\u0005]@E9CE}\u0001^ٵЗ0\u001d\f\u0017\r]W?\u0015שr2q\f:>z*@2jXJ̦\u0017~?E4c\u0019K\u001aa\u000eJxä\fh.`\u0013Ul/K-\"04iv:t\\\u0004;7\r)KuQ֘Ey\u0018`W$}\u0007Y_\u000b8Uf\u000b8CC\u0015~̱Me\\4_\u000fg\u0003;\u0001[}iO\u0007,\tkǾ`\u0014i\u0006\u0019K_P\u0003\u0000\u0019p8ۧo{9йT!aP:e\u001f[~%g;tv\u001fxz[2`\u0006,!on\u001eٿ\u001f(B\nGNǧVlkoW~?\u001c}\"\rJ%.[>$\u0006xziq0,G\n0$d5aA\u0006>T\u0018z\u0015x(ދsv4jYS[|VA5sYB\u001c̀߭ьy\\/\u0010䂃\u0017\u000f.bR\u000fOX6\u0018r;n\u001a-\u0007fs~Q\n\"\u0016\u00024\u0000\r^$`\u00057KLWͅVT^x\fL\u0012QQS$\u0017ő(*L\u0010Eo]tvf|v \u001bqW܁\u000el\u0004\u0002FPs|mn`#\u0013n\u0003W\b^)`LfȘ\u001c\n\u0011hYN\u001b\u0000}03\nTuȹBaV`1e\u0005ѸZQ\u000fhʗ:ԐB\u000b N\u0014Z߼jY*egum<[2Y\u0004ᦳ\u0004\u0016bL\u001af\u0015mۿ|/tL\b*@~sQxA,\\[dSR}_,\u0016nDa\u0003%$\u0000K%%\u0001(L\t%A[⁶{j\u0019!w\u0007\u0012)%\u0003\u001e=Փ\u0019$3l\f\u0004%n?A6\u0015&BC*l\u00192BW$%0NP\u0018aJ/j\u0015\u0001g-\u0010pf:8\\n\u001aK>ȣT\u0003;@;I\u001at͛\u0004\u0012Ғ\u001dc\u0002\u0000X2K&#\u0001JyWb\u0001w\u0013%\t\u001aհ\u0012\u0010>\u0004T\u0010R\u000fAM4Mٶ3nK*\u0016d\f\u0014&ļX\t\u0007\r~~)F&+\u001f0\u0015p\u0003\u00019;2~]\u000bA\u0014e:}˵\u0017cfUK\r2%l\u0001%eɨ:;\u0014%hg8=\u0019cܧ\u0000r>\">F8׊ug%1=3֚\u0005oMI\u0012\u0011\u0007\u0010@c4ؖ\u000b\u001f\nM5R\u000f۪$!#Ooq\u0011\u0005Y\u000b\u0006Z\u0012^x@YN\n(H\u001cH\u0005`*׆\u0011_\u0005<tv*aΗJ6\tkq3^r\u0014q͞sER֋V\u001dܸn*`/\u000bΙzh١\u001d\u000eR[\u0012su>9^\u001c.`W>\u000byQkWb\u0016O\u001a`X \u001caKv_(\u001c*\u0000cU?`f27<ǖaIdrf5id\u0010.*I'F\u001c\u0002\f}/C*4R\u0019\u000bB\u001bZCM\u0012+i'C^',(\fp\u0001DM8&32.\u001e=ϫ\u001c\u0010\"\u000eG).e\u0003v\u0007c\u0007\u0001+\u001d߉+q`߳7\u0005PfV+e\u0013]\u0004J\\E>a\u001b\u0003\u0018/EWE^K\u001dnkim`\u001dZm\"OĔ\u001aDB݀\"^\u0000,Ptle\bI&z8}\u0011z\u0014eAnS>SXsI&Ӎ&\u001cRq{Q\\0LJ\u00076\u001c5B\u0019\u001a}\u000b\u001aCJ@c\u0003>\"kOAUX\u0017ZfI%7xL]X-8\u0018,\u0003KPCĐ\u0007h\u0002j͒Q\u0017JUI\u000f$n\u0018\u0007p*\u0017uӷea-~QR3\u0004\u0014\u0013Ow&&\u0012\u0017\u0014op-_LId\u000e4bUb\r?\u0014\u0005\\T7y]\u0014\u0015X%s\\4IP'\u0000ͷON8$}ۜ\u0000,Z׳#f-\u0010\tQ4މX`oTR[\u0016h/\u001f߿=D\u0017g\u0015Ux3\u0007*Ep\u001eF*`ӣ}9t~/3»!Bapm\u0019$$E\rϾ2Vyb&\u001b\u0004T\u0004Y*E`{\u001d3r\\g(\fdqXT\u0005t\u0004u\u000fk\\By*Iq#L\fk-ȸN?]M6f\u0001P\u0007\u0003\u0002qBr\rJأ%\u0007YݰD\u0001-!26T́F\u0015L\u0014q\u0015-xSZ\u0018e3ԶT-0ߟ\u000eEųPh=\u000fTRn۝DCc\\3໧\u0002Ro%݃`UW\u0010\u0010e?9dz/\u0019\u000f\b%G\u001fC CG>AC0JSG\u0011sv/==ORlQ-v\b -\u0006\u0016継\u001c @1\u0010צ짣\t\u0001-\fl\u0016\u00169JM`RFܣjqDC@纎<\u0005Y\b\u0015M!%mo8A\":]wO+\u0002)z99;UWJC\"}f\u0012\\P\r#T8*b\rY\u0004\u001e\"C\u001a\u0007'\u0013gleH%u(<je\u00016\u001c\u00142c\u000f\\f)y1\u001fD\u0019\u0011`>&Jo\u0002\n,<Ւ*CL\u0001׋\f&\u001b\n#\u0017IK\u001c\u00160?k'\u0014\u001cC|-J!2 \u0014S|.O_c 3 )Z3(x\u0012P\u001b9֖\u0011N\u000e(Yť \u000eŬdv\n&U\"Z{,\n`\u0004gyy^F-n1qr.\u0015^u^iX\"XIzh\u0015\u001f+\u001ejAu\u001e8TRE\u0003]Ֆ\u0014t+ڢ\f{\u0013^\\#ڵu\u00123\\\u001fy>%i&\u0016;ؗT\u0003ƫ}i2}zJ9\u000fןxy\u001eg~36\u0016N\u0002 i?{\b3ew\u001fd⩡$]\u0015(s\u0017]\\\u0002yQ\u00018 A7\"Ee\tYhd\u0017f\u0000\u0018Ee\u001d]\f\u0015\tbvmA\bق$ek\u0006\u0014,N\"ͲƑȊش.5Y+'cJz\rzF)uv6˜7WCX\u00000m7j&>/\u0014\f\u001a8\u00169?eXj$Jۉ>\u0013\b\f\u001aw\u00125գK*L@u\u0005t{a\u0006\u0000L\u0002Pu_f2@!l+\u0001H=\u001aG\u0011Ĭ5u\u0014]\tUF\u0015?rM0k~*\u00121Qbfy/yWg\u000b,Ӄ\u0006%@\u001dbY'3S=_~h\u0015?*c\u0000պZ2[\u000fKyv\u0018$]\u001e_;a\"BMfɨ<;1\n\u0010\u0010Ь\u0005вRt+\u0000*A~e\u00008\u001d\n\u000fk#lGbbadN\u001e\"\u0002pؚERBϢz-2\u001eƎ\n`'uY6ѾFϚ[\u001bBTbTB}AX^f1A\u001fL\u0001{?f{`ٽg?Ɲ܂\u0005m>\u0000E(sy㡮-e\r\u001d1ϞO\u0003$d,\u001aC&V>|O HY\u000b\u0016=-amqk6\u0003\u00038}\u001c4<^e\u001dg\u0012)lo{}F\u0018p#c`K϶\u0007-ŋ=M;!B\u0007\u0019\"c\u0016\u0006y\u001de(ݯ\u000bI9k\u0014kd\"#fI8s{1\u001e\t\u0019>t\u001blO\u000fq]S\u001f-cC\b\u001fsQᑞNԒ̢>\u001e=gj\u0016\f\u0006\t\r\u001e{\u001ceE\u001fyO\u000bi֔V#\u0003o\u0012I^\u00179\"z?liKClp0b]\u0016\u000bJH0;SォD)#rQ\u0011\u0014i\b^X9\u0015\u00135\rj/|y@_@BY@4dX\u0015\u0004V\u001c2Q!U\t\u0005Eo!\bsc#\b)L\u0018Y6\u0019I\u0016\u0016?>VדgC&B\u0004E\u0014lO\u001f9v\u001fR}xu\u0015W\u0007X2\u000e\u0012]pBC^zYXs,Zx[E\u000b}_`t@F\bS@\u0003{{#(g~3?\u0014)E\u0006\n#\u0012ΐ\r<%Nb/\tּ\u0014']\\ A>!]CЭbR\u0016'\u0002ս=';}\bWŪ[_?ͳ\\H͡zƧ~{bKrW5\r\u00110\u0014-\u0010\u0017Y58M\u0014\u0011V%]\u000e\u0013(8tRP\u0004Ի_\u000f+5]q*C$*\\r`<KG\u000e\u0000/kG\u0005L[\u001e\u0015S\u0007ՕAhUT]\u0015]Ξf\u0015\u000bb\u0014&AB\u0015\f#\ne`B\"S\u001a\u0016|j⾪D[r3\u0013f%\r\u000fUl\tL53\u0005z\u00188/A:|$hٶŏP\u001a\u0002+!Voy{Cܵl=q\u0003{_\u0001vg]!WT_5? Ki\u0011p\u0004<\u0003ؐ\bǣ\f\u001a\b`*\u0013\n\u0006i@\u0005\\}\\Od\u001e\u001dx/3»ٻjݹ\u000f_gO5\u0005_kbo)ޚ+sooսIϻdoͶ7l\u001b[l\u000b-`7CkhuC?\u0018\u000ex)x\u0012v Bt(\u000b\u0010\\Q@\u001c=YR\u0004G\u0018\u0018\u0006T\u0003?\u0003d\u0001r\f\u0017\u0002%\u0004\u001b\u0001\"\u0013\u0000y\u0017\u0004N\u0002'\u0004S;f\u0018\u0005Q\b\u0002|)\u0001\u0006\u0015BɟOp\u0018\u0010~h>bCĞ:ˎx0>`b*C)Ŏ\u000bT\t=?Dj\u0014dlG&\u001d\u0018\u001d#\u001dG\u001cxԞnϘ*sʽPyv kL\u0003 TEq\u0006csc\u001dc!;V8U\u00028fv³0{}(ci\u000eu\u001d\u001d\nb\u00115~\u0005y\u0005^\u000bc=0C91@\u0002\u000e?\u0015-)U\f\u0003{]4\f\u001f\u001ca!\u0014eP\r\u0013*p\b50TǱT\u001dGB;L\"yc9yVa\t\u00150vsl\u0000?\u0013@[!\u000e\u0012\u0016%⼝<*]G$\u0011Y{D!>'mWCۥ\u0006-bY{ӆz\u0002U|V\u001etS\bVMf\u001c{E\u0012cjN\"Oh;oR\u0011qykA4wPݯ-$-\u0005\u0011l>\u0018;vފ\n_wՁz\u0012k!꩝Z}?[{Wu{/Ow0;\u001b\u0005i^{5~S6\u001b\u0016`h\u0018uͼ5\u001d`\u001f\u0010'\u0012K\u001dȌ@s%T<\u0006\fl\b\u001cZ\u0006D+\u000e\bĂC6\u0001&~7//}\u00065`xdMP{r \\ \u000b]\u001b\u0018\u001e0 #0u!>\u0001gp\u0011\u000eo^\fnMF\t\u0005~]G\u0019HfU25u\u0011%5\u000f?Zx:^LeS#Tw-B\u0019\u0014+\u001fe\u0015#?\u001e\u0005I=Y\u0002!`:Tca\u0002OՖX\u000eO`k\rV2Xol@O\u00018gx\u000b_~]\u0015|\u0013Mk!p\u0006auI01\nw2Epf\u00118AFV\u000b|+/\u0003wu߾>,>}/ZO,f\u001c\u0018\f\b7`\u000eP$&\"zGws7\u0007_/_a3=2-cjo7C\r.\u0007s\u0006\u0018G\u0005c=\u0005\u0018\u0012\\O6m[uG9dJ[i/؂D\u0007BiT\u00140\u0000\"YF\n<Z\u000eY\u0015C5\u0002`\u0016΍ؓ\u0012IA\\FeDjdVh\u00129%R\"\u001c\u001e\u0016 \r\u001eB{~)f`\u0010\u001e\b\u001d!@T\u001a41\u0016m\t.ʁ\u0006∍\u000fPEZ\u000fr=\\r\u0005[DydڪJDJ\u0002S<#\u0002\u0011*#x\u001a%\u0000ܲd\u00195a6\"\twה:jegdrԨr\u0012lM@bt5]<L냔ZtŊ%u\u0018V8\u001e\u00005,\u001b8c\u0010}Ј\u001cI?y\u001e&N('Ƞ:F?:RH5ǋM\u0015h\\\u0000γ\u000fa1pѻK<\u0001F\u001aT󢪸Ê\u0000cļU](Sp{f\u0003[dsT\u0017r:BgGU\u0010I\u0007$G\u001dm{qF4$ \u0015(a\u0001foFqQm\fNt\u0011\u000f\u001bo\u0005:䩒\u0014N@\u0004Ϻץk-\u0019!\u0013(\b=Ne]E֝v\u0013}-\u0019Zג\u0010\b(G 5^aI,\u0000\u001c\b@AU\u0007\u0003UW=n05/(\u0017koagy\u001cMף\u0000r\u001dӾ7@ƝrbV-\u0018\u0018\b5\u0002c\u0001\u0011\u0014̊G.xd[\tDn?/\r%?hYaI\u0004w\\Y\u0019\u001f\u001f~\u0016?*\faCG<n\u0010\u000480cw\"J{\u001dDioU}\u001eZ.\u0001Ӌ3(Ņ,JKq\u0005j\u0018y\u0019\u0006>\u0011\u001c՚HAzQ;wHa<T\u0013*T\u0017[R\",@Hjx=;1oSӈtm]08\u0013x;Zpf \u0016B\u001b QS\u000e_O4Q&$^O\"UR\u0003\u0000Ҽ4MEn\r_-ՋFW7r9\u0016败R\u0003A\u0018%\u001aSTfɼp1\"\u0004YUNUռ\b_Ee\u0007{iUq-R\u0002hG!kX3$pI\u000bh\u000b>=\u0017\u000b>\u0007wR]\"\u0004yA/_\u0010Dy̬\u0003*9$\u001a)9\u0001\u0001Zzȷ(6kiJ]\u001f\fM\u0016an\u0006RެR&\u0015\rn\t\u0004k+ID8K\u0012*\"\u001bffI\u001aw\u0012\u0001e5C\u0012iϨp/.W4DDN1\u0014y!W\u0010\u0006:\u0006/\rC\u00070tZ\tڙy\t'\t(mL@؟R\u0017\u00068`\u000eꇸ\\\u000fmT$kHn=\u0003R\f\u0017 \"ŮXmOWr&\u0004\b\u0011\u0012mR\u001bZx\u0017YP\u0004?.B3{n.f\\.[(D}VU\u0001\u0007@@H\u0003Ѓ[\u001c\n5j\u0000U.,\u001dj\u0017\u0005O\u0006]-\u0000\u00042\u0019D\n!\f_\u00054Cm+_Qi\"wk\u001cC:\\ʦ!3m`{<\u000bߜ]I UaM{L ?9\u0007[3\u0001:Y-\u0017.E0pe:\u0013r5;*Qw\u0019Cב8>\u0012\u0018!-@h5Mk!Eܛ٥{y`]\u0002\u000fˢ\u0005{e\u0013$h\u0011.\u001cR_2\"mJ\u0012X`\u0015\u001fbu\fL\u001bE\u0012jw6\u001dd2Z`\u001c\u0003\u0001<JtQ:!\u0019\u0018 #\u0001l٪o+F<D0`!\u001fqP\u0011\u0001>^s\u0016%;ݹ\u001ex5~ޏ9Uah쟐gKtK\u0006:J7sCP\u000e\u0003~7\u0000qL<ԔNɞ%#K\u001b@I~o\u001bv>+\u0005\u0017م\u0004yc\u0007S\u001fD+\u0017\u000b\u0000\u0002Jc\\b\u0003MrK>!W}sb\u000fG!!P\u001eX<S}ߣaK\u0019Vk3g4\u001bJ~\u001eM3coW<Efc_c[Rǋ\u001b_\u0017.\rS_Jwb\u0013\u0019'`Qhf^P,XnW\u0002gm\nw@C2O4B\u0016!0=VDlO\u001bA/\u0002}\u001e\u0003c*CsMeQYu(_;\u000b],\u0002Mr!;P\u001aD\u001a\u001bCS;lBFM\u0018\u0001\\ዕ\n\u0017\u0010)\u0017׃1&7fGrAIsTղjj{\r*!\u001a;d)?}S\"x]\u0002\f\u0004\u000btݺ~Puxj`*Q!fy2C]1r~\u001a\u0004\u000f5mTm[qR/G\u000b۟&uW\u0002$`Xč$vʇSNsyoQ8Hx/Ws6Rƀg+5S߈;ҙQeh0T\u001d\u000e\tV~\u0000m\u0002\u0019^%\u001bSG)i|{\u001f\t:O\u0007\u000ejљ!ʯq\u0007\u0006aq\\c!C[R\u0007\u0004w>..{-}~e\u001c\u0007\u0012aOo)A\f!\u001aâ\n9hM_WTۿ_e\u001e_?W?w\u001fO\fo~UD|q7\u001f'lo/ֿo_\u000b\tn1?\u001cli,\fD;~:\u001c4~z#2\u0019hr_o>8=~~?\u0007y|gJKq\u001boNG7\u000b~Awg7\u0017?Y\u0016\u0016`{_5Ehb0&OH\t\u0013I]\u0011s\"C\roN4\u0003Ю\u0006[Z\u0015\u0011\u0013\u0006/#\u0015YU\u000f\u0018,3o\u0003t>!\u0010֏fI1q\u0007\u001fW\u0006?\u0003zdT?_tX\u000b*3\b\r42/2!Q5+\u001a\fZl\u000b\u0001\u000fTlS\u0007Qp\u0006\u001b\\\u0017b6U\u0013i*`(!auhz\u0013,p\u001b7mGx.k:?し46l ZyB\u0001wV\u0011\b\u0019ؚ\u001fqvtqZG@\u0011c\u0001>T=Td1ţfR4B\b\u0011䎊\u000ehhT1\u0003E)O#;jXұ \u001b:a\u001eo\u0019_D陘G'\u000bs{ҩ͈z+4ehP1\u000e_f\u0011\nݔ\u00100(.iѤ\u0010G'ߞ܄s#IJ\u0015Y\u000e*z\u001bS}dPkr%Wp\u0018\u0007\u001c%#y.cgs&\u0002鲃~U\u0011t\u001e\u000bt!Y5F(r@\u001b\u001d\u0019f\u001cv\\Fj\u0019^&\u0018&igO\u0005ȶ吺\u001f/1W묽i+\u001biz\r%x\u001d_n\\\u001fh>~HY\u0007]7\\ƈĥƜ\u0015q_q\rbP\bGT\u0018\rg\u0000~4#D%8ӛ\r<.\u0014f6/gB\u000eg5qQ\u0010?N\bqH\u001d@R\u0001g͵`~VvY\u001fA0^\u0013|\u001cS$N=\f![ƭі\u0011*u\u0004=*HaRM\u0002@\u0002Ҳk$Ɨ\u0019eO\u0014K^{rZte)~>i\u0017u#%Qag]Z\u001d\u000eP)]\rEy\u0001W\u0013k*ҭ\u0000_RUo\u0001i0\t9r@<\f(\u001e\u0013@=\u001cqZ F6q\u000b\u00005BbDW4s\nu%'_\u0007yiҫA.sN\bPn/ޢ9}&t͠={\u0006 HS\\\u001c8\u0010w!bZo\u0019;[ޢ;\u000f\u001byElDӇvS'C[%mGͤ\u0014:\u001cL0Τ:Gqwh{8t\u0000k\u0003\u0006}~]HX\u0018;}+L˪\u0012ɉ\u0016nNl2S\u0012;a\u0001 1~.0\u0007mlJ6ϙ\u000eLK'\u0017F\u0010 \u0000x%ۻ\u001e}Ѽ\u0015?^\u001di|z\tb\u0015>\u0002k5j\u0015eDSVN^\u0002\u0003mf\u000fdaV{KqR$`&Al\b\u0000KAݪ7,)E?Y6e,P\f7~]P\b-t?bb\u001eI\u0003\u0010LgR5\u0002ǘ\u0000uuQkv\u001dE\b\u0011tx\b\u001d\u00100s\u0004$;҅\u0006\u001c\nf\u001f`oJ\u0007Oe3:-K\u0006\bjh/\u001a\u0010r7%ե&k%J\rdĴK\u0017\\\u00153%\u001a\bx\u0013\u0011\u0010\u001bٟO\u00070\u0000rl$G05'\\U׈m0LS\u0019QCP#ԉ\u0001w\u0005\u0001vÝ\u0003{1\\USfHT`M\u0017K<\\C%\u0018g.D\u0014\u001cQZ\u0011\u0016-dέ%n;\u001aĎ4JLr%(J\f\u0017hz&o /Pl|\";2\u0005O'\u001f\u001b\u001bÀ(4\u0016N\u0006enQs~讈\u0006ZE*},\ng\u0010|\\4Xx\u0014l3\u001e\u000b~\u0003S#\u001aG\u0001j7'ѥ8ڀute>9\u000b\u0011lLY&GD\u0019@N\u0000@\u000eRy;Byf=\u001ftLk\u0019\u0006\\WB\u000bc@\u000b'4\u0012aQ\u001c;\u0017@ѴުWD\u000bm9\u0002?&\u0000r\u001fiOٿ3`?vC@wG\u000b?tl\u0017r\u001f-n;r\u001f(\u000fa<Ϟڕ`-\u0000nƶ+`g΋>~Mn\u0019K\u0016aqZ\u001a\u000fk\u00012xt,Bg$z-\u0016~;\u0007=?N\u0012\u0018\u0017w\nP\u0004\u0016\u000e<?٫0\u0010$\u0005\u0001V\tA\tfC\u0012\u0010϶fIKIŹ8-bp4\u0018\u0012dU\u0005D!'\u001f\u0004r\t'~l*\u0005{TsY\u0004r\u000f\u000e̦fc?\\\u0006%\u0019heJbȏY4ĉG\u000e>gK7h8n\u0001\u0000l4=ʥ\u0003)@\u0014pM\u0002K\u001d\u001f@dn?\n\u001eS2LY=o[\u00003[^?xn\u000e\f\r*,*x\u0016i*>QOh_3AZ\u0004G\u000f*Юa+w\u0010fu\\S/x\u0004wcY\u0015Io?Q6c\u0006:@\u0010@\u001e:k7A,<!nΊ쾠C3,ΰu\u0012ѐ\u00008涉t:@H\t.ȅqqn\u0005\u000e{\u0000}k\u001e\"?ckJ-݂<K-f\u0004~N?$\u0006+_Q\u0011\u001f&\u0012AwH\u0001\u0019'\u0005G\n(vX%J~\u0010ILL\u000f(\u001cP\u0012\r@Bҩ\u0015\b`\u0003M۸\u000epU{Ra\u0002]Sa3\tf, \\\u001c0t[YnQhNϾ6I@E<;\u001f_mז$;{\u0002ú\u0004\u0014ǌKd\u0018\u0002(ؐ/l^5\"m\u0010\u0010\u0004\"\u00119׮5WA${E9\u00101\u000e7A|\u001dd\u001b:$o\u0006\u0004а!}vX:vĜiPqSD~\u000eD|R<\u000fDy8nͩ\t\u0007[EƳ0G4,(<r\r&]ȓ$l\u0005Y\u000eX=\u001cXU\u0007GC+N.\u0005`cU[\r#\\.$xx\u0005bQ'Le\u0010E\u00061\u000b:6L$\u0015\u0003\u001b\u0007\fVԎU\u000f({~\n\u0018>\u000fWi_*\u000eJ+\">ES!.vH\u0013=Wc\u0000\u0007k:\u000fb\nQ\u0001˷ȵFl}GYRq\nQP\u001a%\u0012j\u0017e/HN\u00175\u001fMV\u001c>\u0015\u0017t%52\u00008\u0019\u0016\u0017\u000b9i\u0005v\u0001j\u001f|*YMy\u0019~q$K⚣\u0004x|\u001e\u0007O{, \u0003H\u0007\u0016>m\u001e_\r\rh&\nRtk#6U؇jt\u0006<\u001cq@PS\bN\u001a\u0012W\u001e+f`R\u001dn\u000eb\u0013٤\u00104\u0011:\n`@07\\]?\u0007\u001f,\"AǬވM0=lLZuIh>\u000f\u001f^U̱T\ntżl1\u0010p^E&*y0ݯ!\u001fXnT@\u0001_e/C\u0000B3,f\u001e.\u00157?\u0011\u000f\u001f\u00192\u0010Q]<\r6\u0015VWE_y^{\u001e!\u001cw\"\u0011q؈c!;*P௾\u0019 :ϗ:HsqYj\\aܶ\u0003W-HZ{\u0010t]\u001bCh뤔,5K\u0001J`_\u0007\u0017%\u000eȗ\u0011_L $q!MyߟGD\u001b\u0005\u001eѺ[zWv<\u0006Y\u0003}E\u000fA\b\f&w\u0016Z.\u001df\u0019ȟ\u0007H\u0005s~~\nM!)\"\u001bsatOs.CDm$}bf&\u0000\u0000Ԍ\u001e;\u0003''Ht\u0017`5\u0006{V\u001b{f~\u0000pK\u0006wɋ\u001a!t\u0013\"Jq1~\u001d;\u0017m\u000fClez=\u0000U>^į\u0007)\u00104\nO6ҫzGԂvQuE\u001bN^p0)/P\u0003\u0004V}kw7\u0005:Z.G\rce3\u0007hFM:P\u0015 1p<+79ƅg\u0006\t\u00101s\fN\u001e\u00000#/>lM_\u0007\u0000\f j_\u0006\t@! wۍ\u0012׋Q\u0001\u0007\u001f?ir\u0013J.#u|$vYjD\u0010H6\u0015+o,S@fYX)HLZ|\u0001\nt\u000f\nWX\u001ax\u0017A*B<N?.r\u0003?onh}Y]Ūc1\u0018+$fJf{,\u0013?\u0000Όaֱ\u001aH3BĂj\u00035ˮ;\u0013\r)% u|$b'HhO4C\u00117V],l\u0001:\u0012.>! \bXGvDGLgL4==P\u00051Qw\u0001΂\u0003#\u0007PEXWeztJ\u0019\fp7V<>\fx\u0018dx\u0013.k^9!\u001a\u0002m>\u001e[\fJ\u000bC{s\u000fn\\T͟\u0016bv욫 o\u0014SFE7\u001bz?\u0016\"\u001em0\fR\u0016a\u0000\u001bB*OZ'0\u0000OÒ\u0014/\u0010%)~\u00184AT\u0019D#\u0007J\u000eSq\u0003%p6Kvl>\u0005%i\nz9H\u0002l\u0003\u0000 h\u0014eEacݹ4|/-\u001ecCO.cbًX\u0003oׁ[S:X\u0015\u0016\\<(DܻDT,mq`\t^(\u001d\b\u0004\r\u0014N0ؒ5r\t8p5!'^p+\u0010u\\J)p\u0019E'L\u0002\u0006FO,\u001e;ba:M!JG#Bƈ+HŏpbvS:\u00181PziZ\u0018'|ǉ\f\u0001y8\u001f\u0012%*лrD\u0011(\u001ep\u000bbǴL\u0015dW\u001bLaw\u0012\u0001\u001bt\u0012jo\u0004l2FYA)ZL'P bϬax&P06^:d\fʧA(\u0010^mv).=E7YHy&9Y\u001eXS̢W\u0013\u0000T/^\bd4\u001a\bG{\u000b^\u0001,,1\u0012UfF\u0001\u00049|H_g\u001b;\f7MB5\u0011=|B\fd-\b%!Nç.ZR\"x:pW\u0003qщH0|ͷY\u001c\u0006[u(ta\u0019otz\u0007X\u0000ĳw^/3N8#j]ǜoHl^\u000bϮ5ێl]3\b2\u0016Nc\u00023YG:\u001eΆ %҂FjQ\u0016XT%UV;\u0010\u001dy\u000b>(񤶴nƒIE>송>qn[mJ\u0018.I2g\u0000\u00183e\u001cБ}\u0002N\u0007\u00194cƀ\f\u0017+'P+)\u0000\u0014ϧ\u0003f\u0000#}29s62!NLtS;+1]\u0019Kl0x\u0015\u001b\bby\u001b;;Ν}^ַYd\u00187?\u0006^|u\u0016\b\\5\u0003v\u001bl\u0017\u0000\\\n:\b,.J%o\u0012kF\u000bk\u0000c8!Z\u000fh\u0012\n|Z٪iA>\u0015ϵS[lox\u0007O6Gܺиnԉlk2\f\u0012P,sؕ\f>H:\u000b\u000e+mqȴ\u0011?\u001f\u001b3\u001a\u0019h\u0006l\u0011:\u0015\u0001{Dx3~8l,le\fD?\u001d)(!ƕ3.i!\u001f\u0004+ݦ\u0001H\u0004\u001a(Dp4<,\u0016ƛ^W\u001e>\u001foW\fof`t%ū7͊\u0002TͮFVncUȎ6\u0005Vad<\u001c\u000er¢&\u001cwV}\u0011i)\u0001is\u0012݌!Ǯ(A\u0017\u0007\f`V\f\u000f\bM\u0000\u000b'\u0004بgV\r@jTʙǡ^ӹI:\u000e2dP\u001e^Y~k\\m+/#-X\u001e43!؂}k\u0017O:'2ji\\y&cF:S.O}~Y\bCĆǹQ\u0019*C)v\u000b\u0001ٵ\u0004JC,\u0013Pmuy\u000b&x\u0002\u0006.,Y,Kw,uҎ>BcA\f=',;G*V\f\u0010ѽ,gm/<\u001eҒĦ\u001b]K0'\u000e\u0007A~[\u0019Z=JGI;\u0018$`\u0017\u001a\u000f>o\u0002k\b=p\u001d\u0007Y\u0011/ \"\u0005@дm\u0007ƕ.;\tЍu&v\u0001rKay'\tE@\n\u0005\u001e!\u001aiڮ\u0012\u000epPŋͱ\u001aw~c\nե9uq_fd\u0007~=Y\u0004\u0014bV\u0000\u000f\u001e\u0002736^Y\u0011\u0007&ڤ+Q\\퉈ƚ~aU\u0012H^_\u000bh\u001b%м9\"g]\u0007OC|\"0jkuZaGPS\u0010Y9Rgllh\u001b\u0002 yE\u0019\u000bC\u001b'\n5_=1#\u00023f,z\u000f@H3;\u0016[iȅ[\u001d-\u00107 \u0004]\u001b\u0005^\u00053o/ЗAR]Ç\u0001$\\W{oedx\u0017o>}%Ӂf%\u0015\u0017; ̌@CF\n Rdˬ:_\u0003 j̢?6%3\u0019\u0016Cb\u0005Vc\\\\\u0001\u0013F5\u0007\u000673\bYQ0Ϫίf]J\u001c\"P\u001b!\u001c] %=Et<I>I\u0000ђP\u001cs}2\u000b^8Rs~uX9\u0012y\f\u0000V[+xKQ &2ΧBԶXgyQ++O3\u0004C\u001fBZqNo-.6\u0002<_daa}d4'\u001b\u001b.42Z\u000f\\Hóǌu\u001d\u0012>m1\u0017m;[8$\u0003mn\u0018=̒6\u001d\u0006Ψ>\u0001,\u000b\u0014\u0007Q@lj\u000fYA5\u000b\u0002+\u0017_B9\u0018\u0004'`ƽc`E6tc,mn=(\\\u0002֩Ƞ+;x#C\u0003e[\tt\u0001%\r8\u001bs%RAf\t71\u000fxF_\u0000gӀh?\u001d\u0003\u0011េ\u0005\u001dH\u0010by\u0007\u0011\u0010{ێPɄ\u0017\u001b]\u001aR:\u000eA(< Oht2C]w=Ξ\b^`t#&%0P\nH<B4@\n9\u0019ML+%Jʖ1 \u0017\t;\u000fD(75[gkE5ʣvR\u001f0rK@˦J\fdrF_\u0014\u0016\u000bsV\"(E\u0019WMǄL\u0013\u001d{ߘO?\u0002\u0019u>c Лe'\u0012r2M\u0001,fIVJ\u0016\tcU\u0003}vBR0@$\u000b|iZc\u0018v\u001fIr\u0007\u001e\u0017^`]j4\u001e\u0011`\u00005Y\u0012BJ\\dj\u001f?\u0013@XS\nkE0\u0001Z\u0010ml\u0016}i?ۊ\u001f\u001cj\u0006m`7E1я\u0003LYa>\u0003u\t;vy\u0002/g$ug(j\u0017+cCy\u001988.V'w[g\u001c\u0005)Ő \nD-=\u0013?G\bp\u0007EB\b\u0017%\u0004\u0017\rleI,C=6Ti;7\u000f\n\u001d{_S۝ݜ+\u001e\u0004Z\u0014\u001aP\u001b\u001aN.{Us<W~Ch\u0013OH鄋0\u000f\u001c\u0013\u0014+{\u0012\u0014\u001f\u000711\u0000l\u00045AS8q0~]c!G8KwgG\u0016\tI,\u0019켎\u0018,V\"]?{*ԬT+\u0002\f^UfT6S\u0016\u0000f<\u0001\u000eNP4}sMkI(,0\ngP`\u001b\u001b3\u0014\u00103\u0003\u0005Ǹ(\u000eŌ\bw\u0014$xt^\u0003Քy<+7E(\u0014մdCdy8de^w{'Io\u0018Ra\u0006Km`\u0007{\u0018ұ\u001d'R1\u0015NN\u0014DS\tVcgXuV\"iBBFUi,\u0014`\fbPi\u0000W#iVE/+A@\u0006Vxf;WJ]R,P:\u0012+\b=\u0015џA\u0010\u0004\u00075b\u001e*L-b)KFӒ92*Ai]|f-(ݠE%M̠F\u0002\u0010Mt\u0005\\I\u0017\u0019f\u0017;w|@V0\u0003U/sL\t\u0011z<\u0015򑶃9ᢟŝ3A\u001e\u0016#(sr1\u0001;e_ăbO໋ɮ'A\b+\u0003\n΃\u0004Z4:XL4L/\u0010J:7!gK\u0016\u0000%W\u001at\u0001\fב\u000b>\u0011Wxg*dV \u0003+\n\u0005?\u000b7\u001aǌ&E`OHp_/Pc'm?///o0W\rIK\\1$x O\u001e\u000eh>\u0007\u001eb\u0002'񠍁\u0014&\u0011X_N@\"\u0005\u0018>\f%?(8P]jd\u0005\u0012\u000e|u\u0003\u0017KI\u0001|t\u0005m3\u0013|\u001f/& Cԓy0'\u000fk:$Ѓp:\ry\"N\u0006[O*;.\b_Yn\u0002d46\u0005Ot8d[wp>\u00120\u0000x\u0001jy9\u0000!\u000bӛ?bIG\t9Ϛ\u0003F\u0010bguhq_zv\u0002Ys\u0012KN@\u001b\\\u0006z\u0006&}\u0003\u0004M\u0003,SKY\u000bo\u0002kp*2&gBLY\u0011\u0014,\u0019\u0010Ϛ0\r\u0000~$\u001cG\u000b\u0004,pi;E\u0017w'#,āZRţh+cm\u00152*o\\y\u000b{mf!Fz\u0015\u0003XYk\u0002LůĆ4+l\u00177\u001d&xۃ\u0014\n\u0012\u0007\u0017{ԃ`[ ,#V\u0000+\t%uM\\pxdF~\u0011bXXjE\nUSk\r\u001a3Ϣbf \u0002\u001e9\u0006<\\\u0004;2\u0016>M)\u0002=&\ba\u00197\u000e\u0014DŐKI\u00124dW>2c>;\\6Psqϼ\r`V0z\bӔ\rlO\u001d0tt\u001fNZ2ECUF\rc\"r\u0004e\u00181\u000b:\u0001w\u000e&\u0014su%\r>=Jx\u0010\u0014\u001b%_i8\u0006~<\\x\u000f\r pK\u0011,ՕGrfz\\֢O:ow[R1\n-6\u0005\u0000A?K\r|\\\u00104<\u001d墇KB̻^ꕹ\u0010\u0001\u001d9\u0017N^!Z\f\u0004z'\u0005HQӐxj\u0004${8j(\u0013[\u000b\tf3kۃ\u001d:gkw\u0001`5\u0007\u0014H>߲ɞ3\u0015Qhr\r\u001cD\u0016<Q\u00021\u0005AEe>gȘ\u0014\u001emY\u001f\u0002\u0017R\u001dwtHkЌ\u001f*\u001f.ϲ\u00125\u0013J\u0013G@\u001a\u0002'b{9\u000b\u0014S[B>N\u0012\u000fAx\u0017\u0010hȰ%aǤ\u001e\t|h\u0003,\u0006$\u0002Gn!8({8Y\u0006\u0006N\u0014.Ly\u0018ʬE)ymxRl\u0005\f\fXY\u0000;.P\u0001\u00123(\f`?AIx\u001c?%G\u000baQ\tN,׋̝8v@\u0014hUwuͧP\u0012wB\u0015%љ-A'\"\u0007iGGb2J\u0016nl+\u001f\u0011n\u0006#e\u0016\u0006:$\u000e\u001d{1?\u0011\u001d!\u0000\u001fs~,G~sN$\u001f$?nHI%.\u000b_@Q%@nQ{%\u001f\u0018\u000bz\u000b>\u0005l͕k\u0006QogUe\u0011Fq\u0011\u0019\bv\u000b^\u0000=x(\u0018.q!ne;gK՝kƽ\u001e̚A\u0015\u000bH,\u001el*S\u001eJZ\u0010N\bJ\u0015Ayd\u001e(<\u0014b)) аUTlTLB \u0003\u0017Eh\u0010Hه:\u001c\u0010\u0018\u0006)xs\u0004Q/\u00039xA\u0002\u000e~Mfi~\u0003\u001f֤qN'\u001d\u0000g<#:Tӏ/pD\u0010qY7T2\n]n{\n\bTPՈ\u0017P\u00187Vdi1H$n0`H\u001fn(KH\nLiޓꧤx<K\u001d%X\u000f/@\u001cJMEXj\u0002CjA^4Y7\"\u0004ACX?X/\u0016 \fҲD7z: 'dX:p\u0007(ߣO\"\u000ef\u0003>m6_\u0003P ZWl5,\u0002A\u001f\u0004=1\u0003Ŏݲ\u001c\u001c-1Bɲ\u001e\u0018\u001c$N<\u001a:\b\u001bW)t\u001e\u000bSV<6+{<s׋@\u0001쥠`<3\u001criQuͧl\u001d o\\Df]\u0005>RvB\u0003Q\u0017I\u00122@|߷&B\u001e\u001b\u000bx:;q\u0019,JǛ\\?\b\u0015eE\\]\u0001'S 0\u001b\u0005\u0011 \u0014\u0001W\u0013^\tW?\u000b\u0002?Pk3ۿ--I\t\u00105\tՒKj1~mu5π\\7\u0004)$ٳ\u0010wc5|D\\ pH\u0010U\u0013[kB==x!I%y\u001b]~]m\u001f\"PJW>\u0012\tƛՄe\u0000B:_\u0016\u0010xXHd7K_\u000f~$}h\u0017q Y?5\u001a.)\f\u0017\u001f\rzF\u001bRԣĚ\u0002\u000e+\u001b?Q@S~Y\u0017\u0010Oͩtu`G\u0018\u0014r\u0001\u0019lh\r\b/<U)>L\u0011罟aH\u001a\r\".dnhT%ܱP˕i:H\tFک88\u001b;v\u00003-|\u0007vbWPlp1$`\u0017 _\t7n\u0004\u0010R\u0003̱u̟njG_\u000f\u000b\"<ܖ \u001fb0e\f\bU:\u0000(\u000f\u0003\u0015U@d]\u000er[A\t0@\u0001\bvzjjO\u000eA\u0014G^ʇ`\r1c\u0003[ddC\u0012<\u0004T؏\u0002\u001e83oPUM@\u0012OWC\u0010Vdg\"D;^$\u0015\r\u001eFwl8=\u0005#\u0016\u001f\u0018P\u0010\u0015GV:uG铱/~:=\u001a\u0007Q+65U>\u00041\u0016&o\r\u0003ZکRD0k\u0015`\u001cn),oZt7V<E\u001ch\u0002\u000f\u001f$PAO3Tà\u0003Ew\u001duGTЂMLҵ3_B\tX\tmHTA\u0012GGȡ9d\u0006;9\u00164)\t\u0016*Nqa #>0rԖn-\">Ƥbb}d*1Kߺ˼\u0013pi\u0006˛\u0003\u0013AB8Dגc\u0011g~Y\u0007Yѫ4dןki\\{!\u0003\fTOOOdHc\u0005\u001e:{Э'θ\u0018`Y0\u0015\u001dI\u0007\u001f㬹@r*LP5r\u0018\te\u0013\u001cO\u0007Fb\u0011E,\u0016S,\u0000Uv\u0002\u0010VK\u0011ןd\nhyd)TuT\\8%\u0016\u0013D-\u00002hɒPRT/V2\u000b\u0013f\u0005#ܛQR\u001c\u0004{̝`;[݊b\u001d;g~\u000esk\u000e}\u0001&\u0000v)9\u0019l\u001eǟ~HSQ\u000f*]?ǿE5(9C\u0003$?k\u0001y\":\u0018P\u0007!!ݪ0wDh\u0001$\u0010J4İrF\u0017\u0012񱲞,~Ŏk'z\u001dt\u0015\u0017,\u0017te\u0015\u001c\u000e\u0014~\fAJM\u0012e\f)d\"(\u001aX\u0012s\u001a3Pº\u001fȬMY\t\u0016v{\u001cIfV\u0002e\u001bY\u0019XuX\u001a\u0002tᣊ旻MF;a\n#,zfXgY#H=c28\u0003THv\fr\fi$٦<|\u0017NY\u0001\u0000ܑ\u0004GWa%q7^\n\u000b\b5\u001f$V\n\u0010߫'\u0007R;OL\nEhtiWIjLnse\u0002\u001f\u0000pSC>[_;Q`7.\u0015\"\u001aoJ\u0003M\u0005ao&w-Jʭ(iy(YA\u001c1\u0000 e\u0012\b\u001cӮP{cP)iS>0\u0002L.5gEŬ\u000b\u001d\u001afwM\u0016aft$:şkx|2\u0004١6\u0005\u0006\u0001Q>\nrzyjh\u0001Ȩ\u0007\b\u0014`g\u0007dv=mfC u_\u000bѾ\u001eG4ax\u0001 ¶\u0017z\u001c9@:üaX+#RÜmXzڛqDsf\u0012r\u0002\u001cLX?\u0014Q&YDE\t\u000f찑AW;N\nکB\u000e]\u0002G<\u000f9g=ہz~\u0012a\n\u0006r\u0001\u0004 2YHd}\u0001\"^rEi\u001e\u0017\b)6\u00023%\u000bS]\u0012F;\"\u0012o\u0012UіHV\u0001]ɻ֝`;\u001eqh.j-\u0005\b\u0014Q\u0011\"D\u0011B@\u0016xӑz>^vF\u000bh=\u000fxR{St\u0012\u0007>`G;\u0003j<;Y\u0019LR×\u001af<\u0006/-6V<6ǉ\u0015\"$(0;ضKz\u0010kf=b\u0019.I\nbLs\u0017\u0006${\u001bM,n\u000f)\u001d\u0012\"\u0006ë\u000eDƤ\u00133\u0012pk'S\u001b\u0004`>3i1\u001fτ\u0010ϑ0\u0011m#lk\n\u001a\\\u0007n$7H&x\fɻ\u0014=ﲉҦ\u0014k\\\u001eyuP\u000e\u001c%ƣCoFd_y+\u0004\u00059 1&y\\,MyPr)\u001c\u001f\u0000*H8t\f\u0007k$Ȓ#Ï|O#^\u0016D\u0012\u00022o\u0019#{\f\t%$ӟ\u001ahx\n$,\u0016,nȓ\u0018nTezGdt\u0003{鱰#,%%$~P<\u001c*Bq\u0010<#\u0019;_L{9!Yy4gyg\u0016\u001eu+\u0005$冂[sO\"񉺏./X\u00193ӜH*}p\u0015+'\u0011\u0010N\f\u0015\"wj)\nj3\"\u001a\\ah\u00103Nf[R6Y\u0018\u0007ѽLO<.پ\u0014\u0018e1N\u0017c|\u0013dD,iW$73UZ\u0012\u0001&PG#\b빋rّo\\*\u0012He\u0007[J\u0017J\u0015(fq\u001c\u0018S\r*7@\u000b/LbD~-c԰!H\"0'HB[\u001cvr;#\u0005Øє#bT}D\n;B\u001cCTN(GHk_`4n2\u001b\u0015$Aa\t\u0015dM\u000f\u0011\b>`Cik\u001a(]\u000fBw@D\u0015*Y>\u0017;<StR\u0018?nd6\u000bʹb#\t,z30UG뻔\u001f\u0010j\rF2KI\u000bU0\t8\u001e8M\u0019%\u000f\u0007&ley|RĜ]\u001eh̞$`\u0010:S^(Y+R^\u001eR\\\u0010g\u00165yJ\rwg\u0011\\f|`~Z\u001fG\u0003GYyTO\")}\u0003Ff}\u0002v:3LϘ\u0006W\u0016Xp\u0003&f)}A\u0005U\u0015\f#?\u0016S\r[Ŗϣ\bgB,\u000e\u000e!0J\u00039@<`.|b%E\u0003ڔP!U\u0007K|\"o\u000e]YMo\u0001\u001aNK,\u0019zOH&\n\u00185kf\u001f\u0010\u001d\u000fTv UĜ~0\u0010{\u0006䅙\u001f\b&u^,z\u0003l\u0000\u001dl!kiGy4^>S+r\u001er:TP+=e.w:䞋אָ?,i~TQX~<-/s\u000799q$\\cQ~p\u000208\tQK%eAY.}^r[90w~E\\q\u001f^ dݎGEc\u001c\u0001\t\u0010\u0003y_^\u0001R#\u0011WD|xw+Jط˨\u001fNī\u0000\u0012ϴpEv\n\u001d\\(\u0016\u0017DguYl(b\u0014?wx\u001dͪnZnl4h\t\u0004Yz1\u001630p4\u0010\u0013WñXEQ\u0006<Jw\u001eGXH\u0017&;7kݡЭ̵L+O\u000bg?k\u000f(A\u001e#WWJ9u\u0013>\u0000[J<Ԫ\u0006\u0012Nx\u001cuU^\u0010НC\u0014*JC=JFwXgeD-lD&e̒:_\b\u001aeT\u0013^\u0012\u0017\u0005\u001e\u0007\r<EJ\u00062<ASi^\u0003z\u0012I\u0006\u0016m\u0002ӭ7ܬI$X\u0010R\"^fW\fn!N\u0007PSu3c#]\u0017%\u0003l\u0003FV\tO\n\u001f4-\u001fU\u001a=\u0011\u0018U>*0T>w<|0?;jڞUmd7A.'??@iS\u001f\u000fZ,ik\u001b\u001fxʸ\tY}jYRG\\XPMFɲ\u0003n7\u0015PO7t\fjjp\u0012нC˯g?\rie\u00184$\u0010DЊF\bOw\n\u0017,\u000fa۠q\u0007\u0007:T~`PT\u001aPCQ{\"p`\u0015l<:1C\u0003\"Kͳ=R\u000bu\u00125]Wb\u0002#ݯLl\bd.6lYU@ؒU\u0011\u0016,\u001c\u000f \u0003#>^epJdC=h\u00107Nf=䚩\u0014,\u0012$^p$s\u000er0вb\u0011\n4|ŀ4_BvnbG\u0000E\u0006Tb<2)59<ͭ;\u0011Gc\u0004\u0003{\u001açv\tY\u000b)kTk \u0018'^-J#$Z\f\rp.`=G\n\u001b\rt\"!\u0004&\u001aTtBnz@EO\u001dXsGx>4qi(A0Gy\u000f\t)G61 \\P?)\u0001\u0018Xy\r\u0007\fcF\r^\u0001a0h%\u001d=\u0013M=\u001b\u0006\u001cd\u001bSR7Go\u000e$DP})L۱\u001a|{{x\u001e 2n7F6\u0017Ɣ\u000b~ݔVs19\u0000\u0001\u0006\u0010ʭ˴O-\u000f 0\u0015q\u0000Bn\"˲mqS+Ag΃HC\u0005\u001d2\rOUdA.T\u0000HU\f\u0005u!S\u0015@-Q\t\u0015`vOPn4\u0003\u0015<yU\u0013Ӵ*D]πX 0{KS\u0005Hn]@jj\r\b\u0005C숅Tv\u0005SF\u001173%\u001eڏ\"6\u0014<\u00073x+oYSoQkT3Kb9Eݝ;\u001aQfAi86%\u0017\u0012\u0000\\Ww5@\u0007}6e-+\u0012\u000fi(怸]ئW'#C\u001a\u000bJђ\u0006rT\bL~\f@JJ\b2F\u0007q3\u0000\u000e\u0004]#F$&壟e+`I)C!(QǭG!N.o\u0007#`\\\u0005L\u001b]]\u0013# XUmtM*+d[8P{W\r\u0000<G[Z\u000bVctmPT{\u0000FJJ>\u0018W\u0006`X{d]dr\u0005YVK\u0011ԟ\b֚b:?q\u0004\u0013\b¤H\u0001;Y\u000e\u0000\u001a\u001f\u0005\nb!6/~w|*\u0014ޑS|ɖw=1\u0018H$P\u000f\u001e`M\u0004kȌ*\"\u0015\u0010#Sc\u0014'6:I+%@SN|¤a_8\f\\6\f\u0018T1\u0003>3\u0012M袜c̙WXbc\u0017IۏU-t!\u0002\u0002[\u0010ܼSiȤ\u0013Cz\u001e\u0019\u0019ˣ=YC\u001an$\u0011W\u0018xtZ؄\u0014/$9OC\u0005I\u0004w2̢,t=31\u0019IR\u0019@a0\u0001'` \u00042qS? p>\u0000\\WG\u0012\"\u001b^-ۺ9\u0010LϗEM5B}4\u0002fwPD)\nb0aBIp\r'E\u0015%_\u000e\u0014\b.gZA\u0007#P\u0010\u0018),)\u0012T'a\u0003+\f\b״6\u0013\u0001c\u001a\u0002\u0001l\u0001%\n\u0001\u001b`TVo,˺\u0005\u0019bkr\u0001ofI\u0016I53\t2̇w\f\"-'dߧ΍pIC\u0015\u001a\u0001!z\u0014\u0007Q5{n,$zN0RU'Rd\u0016.YvO̰ ?\fg[U\u001fpB^!O,(\"]\u001f\u0003\u0005\u001d~9u\u0017u\u0016Ts.v\n\u0001ʙ\u0001\u000b)yKX%\u001d8A\u0013Ņ\u0017+Bo\u0006\nV\u001cFzsUmfMq?u֯!п4k?\r)w1\u001cFWQ16)_'b\u0018ō\u0015v\u0018:d\u0015e\u0019s4h\u001eY=:ot[q\u000e\u00020]}\u0013΃xwXG\u0005\b\u0019X/{\u0012\u0005\u0005EVN(\u001e\u0010Yq(.:Jы\u0007zC;\u0002 \u0015\n@\u0005\u001a}4\u0014E\u0010D6\u0013\u0012̍\u0015>\"s??\u000bkvk@\u0018@-\fR\u0002gT4\u0016s!we[2\u0004-+\u0011\\\u0010>5\u0013[3\u001fR\u001et\u0012 bS.Tre;wJh=,J||:\"\u001bWI9\u000bJiA'AwX\u0005DʟVz\f9Ɲ%l\u0007@Z\u0011ƹIC\u001a\u0015T.*\u0007X48I\u0014#\u0002G\u0014HgZ\u0001\u0010\u001e:Ip#qD\"!2IV`<>\u001ePu\u0011P_8MBaC=}fQEYږ8mY[-bu/;O\u00027'Bm\t\u001acL@^&;COrLcQ*\u00153cOS :}T{ΠwD[PE̲}-\u0004#ZPV\u001b\u001dkGT?tPժAxP\u0006BQ\u001b\u00035\u0001|ɵp!\u0001\u0013>\f\u001f{\nc7\u0017~WE+eBCbel,p/\u0018b1ݥL]U{jx\u0005O\u0005s%䬱\u0017/\u0013J~=g̃>\u0016jFCn($\u0010<vz\u0000y޷5i\u000bZ˚\u0018:u\u0013\u0000\u0013-\u0005\u0010\r\u00114\u0003L˯\u0013\u0013,ߘs!I\u001e@I\u0017wcqܹ\u001bԢr\u001e\u001e\u0004N]I\u0004@^\u0000ߢU2aPl\u0010A\b\r^\n(ԯǢ\u0007;\u00151a\"rXsd-PP\u0012\u0006\u0018曚dܵg<\u0019D\u001c26t%\u0014\u00027P\u0013\"uf\\.\u000f9ӗY<X5J}M\u000b'\u001e\u0004V%gF93\u001e\n@2\u0001҂b\r[c->R).u\u0006Df\u001fo&@\u001e\u001d\u0019\u0002B,[\u001b\u0001wK\u0015\u000b\"({6yL\u000b4\\AIn&2W\nU\u0000bk\u000eͪ\u001df\u0003W`vlba\t3\u0014f\n.ˡ\u0006#R\u001d\u000btJ&Ho*z\u0005JhN\u0000\"\u0003\u0007EK\u001ef\b\u0019B\u001bi0>5\u001dLWhl>b(\u0002c`^z%ufKjUJ\u0006\ny{7/g\u0018iA3sì}&]yK#{~HL\u0007B3at\u001c8{Nu\u0012=\\gZ\u0012\u001dʩhS׋k\u0010MKV\u0012oɼ,>#/\u0018bnp+qJ\u001a%QG\u001a\u0006AW\u001c\u0012e]z\u0006Yˠy#3{\u001a\\N\u0015\u0016.i;2Mu\rg<o]wô0~\u001c̉SH5\u0013*7\tG\u0002\u0017\u001f~8h;'ݹH(?\u0002[É\u0004\u001a5\u001cH\u0014=\u0007,@l<Qh\u0010'mZ3J\u0004&Pz;#\u0005lb\u0003:ʸf~\u001ad@lBؓO0aJ\u001dJ\u000e<%\u00106h\u0006\u001a1qFiZ!C%|@$[5Z\fIz\u0014UX\u0014Z\u001f|SjNH#\r \u000ffg5Z\u001bpKGlCux\u001bBRQ!PΌS;,\u0007u_#V$ jH(~7c$r-bW>\tYAiTH\u0003)\u0014e\u0007Q\n{\u000bkغ\"\"\u001bT5P\u0014/ծQ\u000b윥C\nr]B\u0002מ>\u0019D\u000f\u0011\u0019Ȟ\u0014\u0019\u00063i\u001b6\u0017,:SuI4\u0006W:\u001e[>gʰ\u0013.5\u00161͛(\u0016r\u0002#yͦy?QqzmS\u0000EF\u0000B\u00106Vc\u0019\u0007\f\"{꺍^\u0014:Kɱct;b0k[ޔ\u0011\u0005gZ;V^\f52&с\u0014 `84z\u0010:NN%:|3>d.\u0002J{Q\r\u0010Mi,BgFi[U\u0019<,\r%k|s\u001c}ImDq\u00022\u001cv|_&\u000b;\u0016B\r\u0016\u00042r\u000b\u0011\"-XjZ\fY-\u0015H\u0006Ot\u0014n_^\u0001`x{)#\\AGQ\rvGV\"K\n0\u001cu9>I\u0013T2\u000fJ\u0012s\u0004o\u0003rjGY\u001a~,e\u0015A\u0005\u001d\u001dAR\u0019\u000bKX\u0003׺d\u0004/I\u000e=Sr`=8D'\f:e$^9Z0\u0016Hיr\u00069c\fATǌ91Q^CU,R\u0015YwgzU+#IV\u0015\u0013\u0006P\u0002g`r] r4/[:\u0005\u000eL\bh͊/qZ@*^[C{\u001fM\u0012K\u000ee\u0002\u0011)|bԱoH\u001b\u0003uk59J~55UE>k>\u0000\u000f[S~!:qh>Rߐ8\u0016\f\u0017qY\u0004?O}@\f\u000e18pǽ a|7C\u000f` y\u0002[_\u001e>4/SE\b\u001b\u0007\u0012VJ,Ш9(FB&c\u001c{c_\u001d\u000fwW*PPƌl*(\u0005)SA>\u0003ΘI֣\u0017t\u001dye\u0018ۺsRyR\u0015pBܥu'\\L8W\u0010\u001dxI8K͇~!~=\u0001\u0007`jbxo7\u001b|:$hE^\fRtȝ?HE:TȲ\b\u0015Ƒ\fNAF(%\u000e\u0010P>E\u0004O\u0000\u0003\"f:xoq\u0014ָTyn3'\u001bY)6\u001d^);ɕ3?5$\u0002-\u0001S 2*\f-~m8\u0018\u001c-]i]\u001cʝF\u0011x^\n<\u000ba+͏ۋʶ\u0012\u001e\u0017+Ve>O\u0004^[ݤ\u001d@B9\u0007-OI\u0007\u001b8A˱WRb&3[\u0018\u000b=++)|gh[j\t@C]\u0004\"ep\tƤBH_ņHj\u0012(|Z\u0011q1\fDmʻ(*~~#_RcXr?n{JM\u0018Z&\u0013\"c4\u0007EDeJG\u000b\u001d\u001atQn\u0007t\u0017\u0003*\u0003=(=2Ѐgt@un{7\tG݌\u00014hv\u000bdeo\u0016pL4\\\"\u0018zNO,>é\u0011c\\l v\f_\u0006\u0011N\u001akR\u000b\u0017@(N\u0001gu]DXGc͛@$5ۣ\u001b\u000e^g\u000b-5j\u001d@h)~qO\u000f\"9\u000ej\u0000ɋ\u0000\u00071-T\f\u0017%bp\u000eE\u0011\u0010Y΄ؑ\u0018~\u001f\u0003ڹ)_p?\u001dXdO߅\u001ee!\r\u0006;d\u0002f^\u000f\u0003\u00137\u0018b(n 0^t^v\u0005%\u0012I\bw?\u0001O֝qsPIͯ\u001d霦@.=\u0004\blE\u001cTr\u0012\u000bi\u0006\u001fGz:ïVi\u0002\u0015>wME\ruެՎCp+Ԓ\u0010*\u000b0KTɹ8Ox#q9\bBꋚDf\u001a\u0018 uz\u0013j꧒2Ϛ\u0003\u001arE\u00020\u001d\u001eg}-\u0006̍\u0016\t1Q\bL0'\tr\\\u0000} i7I6\\\\\u0019\u0010HQ=N\u0011cZw[\u0017 Bʫ]\f调dW'yC.``ACcޡÓG^h<G\u0015\u0004z\bJGO^\u0018\u0000'\u0001$\u0001\u0005\u001aD(ؑ~Tg(\u0002gXg~Op!|!u`\u001crQ\u001e`O5AYgIk@\u0003CT1B\u001f ?v,;I\u0007e\u0013֐)|\u000eҁ%yry\u0015\u0018@i\u0006\"a_p!\u000bքE70R\u0019­İ¬\u0000M9NyF/h_V\u001a2;pIA{\u0006p-wp\u0004\u000f*F\u0002rZs]KdLm8=^d\u001f2\u0006t(s\u0006k\u0011%K0u7f\b*\u0019䥎m\u0013\u001b%;B\u0015;3\u000f\u0018;4f00{t\u0016\u0010\n\u001by\u00161\u0000\no˒IxɁ\fPសJo֥$-\u001d\u0002}8^#HB_ Arv}dQK\n\u0007\u0014rItS\u0000\u0007Sv`y\u0011\u001cW*j\"\b\u0013O \\!]e;LX\u001f˥z%{Z$2+\t\rtd(\u0001H%j<\u0016=\u0003\u000fb\r5b?\n71;\b\u0006D\u001e!YI_!\u0016\u0005R\u0011\u0004\u0006S\u0019K;c*\u0017/E)k'^&_\u00075E\u001b]\nkK)m\u000e\u0014\u000bw\u0017LjYKv\u000e -'F\u000eo\u0000\u0007+8\u001f}r}ſ>Y?O?\u001f_??!>~?\u000f_}\r\f]\"Y\u000b2_z\u0003s\u0019j@\tڂ}Šۏ\u000f*\bԊ2\u0005%T\u001bpuA#o\"\u0016w$\u0016r\u0000A\u0004\u0017\u000481((:4U^\f(#r]?ɼg\u0000\f\u0007xAx\u001cQF\u0000%v$\u0006B*\u001f}HP\u0019M!&.Y\\\u0006\u0007R$\u001bIQyV%n\u0000\u0018PYg\u0019D\b\u0005@\u0019\u00171O@cͰy&\u001ac#\u00191N\u0019l!3.!q'{X\u0011ŌJK(g13a\u0002wR\u0012A\ne\u0003iGdհ1\u0004Ȏr)EآHe7\u000b7JLc=\r\u000e<fǪڭ\u0003\u0015T\u0012фtj\u0006H+Qqxmќvzى\u001fg#\u001dnbQ,3vC;A\u0016L;\u001a&\u0002ȤP\u001bG<@.\u001d%kx\u0010xw\u001e@4@,\u0016ޡ&aJc\u001bqs\u001c\u0011FLj\u0016\u00018._dX\u0015\u0007䄓T6|\n*\"\n\u001cH3\n\fDl\u0016\nyL\u0003<zQU?0\u0018p\t\u0000lsT+.\"<9&\u000b>=|>D*\u0006xWI;E}j_8Y\u0010\u0001\"*R\u0016y\u0019\u0016UXa`y\u0019<ulE#I|\u000e\u0013\u0017q\u001fFU\u001f̪U9!5uN\u0012<ϬgRo\"\\.(\"SbgYSy\u0000~\u000fG$\u001a+省{#3t{\u0013L.2JJb^x\u0000\u0002+\u001bd`D\t\u0003\u0002\u000e>AN\u001cnVVcڠJ8\u0001JU\u0019\u001eߨ\u0010\u0001)o\u001e3 s\u0000,5\u0005cUܷ͌I`}_w\u0005R%8tb\u0017 F`\"\u001f0\t\u0002J?b\u0003'<v1\u0017q\u0002JM*$[ |*EY\tsg:M[\u001765!\u000f\u0005\bv\\йN$/:L1\u001c\u0007%Zӡm#\u0019p\u0001\u0004\"f$\u0007\b6,\u001f*M1!F;--Lx15[ZlB69]K3\u0013\u001c\u0001\u0017ϚFt\">KPpB\u001dtcJ+\u001d>9\u0016;cqH\u0018}\u001b2\u001e\u0019\u0015A}Xꉬi~ǯʞAHK\u0003M =,\u0011=K\n.IC}ގ\u0007\t Z\u0002;Mz~%p\u001c-\u0017mŎ\u001cT!J=?\u0003%&\u0003f\u0001uMB%\u0014e?У욘ܩE\u0018i3Ogf`J\f9\u000fΠ\u00183'Y`B_6k\u0001&o)\t\u0006\f\u001e_T\u0017\u000fp\u0015JDP\u001f\u0005\u0018%c\u000fԥc%_&L\u0006 ԓ/Hk\u0011N\u001e(wIR¯SzS\u00101ZܡZsB\u0000\u0002k<}X[i8\u0012[9 ;΀qC1\u000f`0\u0010Ēy&ڰQNF\r71\u001af\f1j;\u000b|fܹR\u0007Cfρ\u0005\u0006ߡ?\u0013\u000e\u0010\u0014\u0006\u0019\u0016Wjjcd{!s\u0007ǴH)\u000b4EW,\u0010i譡sxS\u0005OJj\r*,\u001d2S5\u0006 f\f\u000e\nG1\bCO\u0015d\u001br bևn\u0015]xyDH'z\u0014\u0003dqS*\u0000*,\u000e \u0012_Đܦ-3\u0013@s=z觯\u000fڡ?(vh\u0000J\u0005PԔbޥVE\u0013\u0007b\u0018$PV\u0018$љ\u0016\r\\]\u0018|/e\f\u0006~00\u001f\u0002\njVAbH)<\"\u0004>Pg@237[/φ,UDr7q\"|h4@#Ź\u0001á\u0003\u0000\u001bq{\u0011Ofd&^\u0010<'HBNvX_/SE,m c/|\u001d\u0014IkF\u0003}t\u001cۗ\u00021a,\u001c@~JSs\u000e5\u0013\u001e\u001f(?]\u001f66\u0004qOkʡr4\u0018l\u0003$F\n?l=Ekխw\u000f԰:Sq\r9*%{=c8x4j\u0000Tɑ<Sʙ=@<\u0018بRa\u00184\u001b*7\u0014yYx\u0007fJ)ebKjnuTpkD\u0013\u0010|k Ҟn|>?\u0005rB\u001c\u0012:\u0004t0o\u0003O\u001c۠F~:\u001c\u000fGƨi3ED;\u0000Nρ-!r'EFk0!7\u0000\u0015]\u001bC07b\u000eWΣ\u0001ũ\u001a4[>x\u0019qǢ\u0016sb^CӖ\fV\u0005Sţr!m\u0013+7RPUj\u000fxK#O=ι~\u00171X\u0000\r>2\u0018\u0018\\\u000eE[I08Csd_`\fDϤ?!\u0003ȱ܀\u0018qPMHQ{\u0000Qt@ˁu\u0014Ckh\u0012\u0017h*^\b~H\u000e@Rk\bIA\u0003U,5\t\u000e\u00136Ў\u001bpbf0\rz$_Ff]\u0003ut秴1i\u0010\u0016t\ti\u0014;v e\fvK\u001e\u0002w↿k@Gל0\u00121?\u001f,\bUkw,wE\"ӊ\u000f$ǴhEfD|&\u0015J2{\u0006Y+[)\u000bx\n\rYj&I\u0005\u0013jRh4ld1\"?E\u0003\u0002\u001110h\t1L\u0006]X\t.+W>qU>of\u000b;!\fÅ(aϕo\u0003^d/cP\u0000\u0000kғݦO\u0014\u0018\u0011o\u001cai3<1c\n&ϩ +\u00105.j'놚\u0018A\u000bdb`OÔ\u000e5el$\u0001YйVŠ\u0012\u0015\tɍ@\"P×\u0019Ⱦ\u0010w\u001aê8oǁT훪xu>\u0007O<\u000b?@Tj>ha(@?qWm\fd`\t\u0002\u0006?S\u0000cӿa_i\u0007*m\u0016Tm\u000et\u0014\bx:\u0015plتUk5,d~j-Q\u0012JJ]bnҾGc\u0014/*2z2jN\u0000/\u000b\u001f\u0015\u001a\u00036)\u0010z\u0013C܀Kwb%\u0005J(\u0003\u00103b\u0000m.[\u0017co)yED1\u001aھ{x*\u001a\r\rlnDߋ\u0005g \\RR\bSC[n4F\u0000f|\u000f\u0013mKJ0v\u0000\u001eS,\u0003E!;\u000b0\u0006\u0001\r\\\u0018\u000e.ٗA$׀tȏ+.\nf&џ1uy\u0006g\u001f&cCmƭ,-%lIA5y{w\u0012Bc]\u0004?\u000bC@X\u0010S{,6u\t\u0001tK?MNxëy\u0004\u0003ґ*|uύ>_b\t\u001eTZٴFb ~}q'\u0007\u0013\u0003\u0007\u001eZ:烨\\(z)Dp\u0007lB\u0013\u000b:IϿs\u0003r\u001d\u0004a3 Â\u0003ő\u0002\"elRGuENxq:桿\u0014}{~܃/\"\u000ec`S[5$W\u0012\u001f\u0019Rp}\u001d-\rA,z4TA9\r$\u0000X\u0018<``=\u0016\n\u00037E\u0001w*\b#g\u001d8q0\u00035,9\u0006#\u0019:`Bx0\n.jSkh]_\u001f?\u0007\f\u0005\th5H\\W'\u001a^>\u001aVJdŢkHJ\u001fT\":\u001dOAd\u0006~yv[\u0002\n\u0014ցD+H#D\u000brmWAD`\u0006aCq=6\u0005Dո״>\u001cdSe\rpZZPѠHģȵP2\u000e\"V\u001a\u0014\u0001envI\"\u0005\u0003W^Btl\u0010tT[<p\u001d\\u\u001dj\\+}Wi\u0012C_%ErP=8c/d\n$\\=\u0019Ö1J\u000e\u0007{v\u001c\u00189@Ӝ5ug}2(:\u0016h˲.\u001c '\b\u0011N\u001dP<\\夑\bJ\u0014YIn#%|{\u001ehrƎ\u0018\"$\u0019\u0005G\u0004͟uv9N\u001eL\u0019ɍ9~d\u0005L\u0017\u001fK[\t\u0004\u001dD\u0001Fe\u0000b(ޡ\u0018K\u0000Leܤ b<K\u0010\u0003\u001ec@<WBu\u000b3.\f\u0007W7Wh\u001b\u0016U,i(U!\u0005\u000e!]W%\u001f\u0013Hj/(\u000e!c\f:\u00144N46<T`o\u0003wM`fVp\fmG\u0016S\tڹ\t~jԓd%\u0004~l \u001a\u001a;%+}$y\u0003vJڝ'9>\u0006{\u0017B9\u0015U\u000eۇ7\u000bz\u0018tD-C\u0015Y\bX\u0001&vYGP\t\t<L-_pd5VA\u001a\u0003v\u0016c۾;L阕\u001b~\u001f\u0003+L1a\fپ\u000fJa4iEt;D(~G\u0019\u000bd-QR4lEMMqS/{8\u0001\u0015&h|xR7\u001d)YtL1\"\u0006}h{J#\u0019Ed\u001dD?S\u0006\u0019J85}erV>2\u000bFH3Q\tL&-1~IhTi\u000f%)$E^70$lQRAcqr\u0000]i\u0001i1#͌\u0002\t\u0001\u0007uͰ\u000f zmQc͇fd|g a\u0003a\u0006\r \u0010\\!6\u0000EUIgf\u0006ش\u0010\u0005\u000f'\tL\u0016$s7h\u0000h\bkeFKe;B~\u001cxx\"\u0006\u0007tofH\"h|3\t.[+G렩fȖ\u0014{\u0016븸dQ6y\u000b\u0005eEY)|Q\u00128vb'\rDf\u0000$@V\u0000t3t4\u0013\u0003:@C\u001dʯs)w\u001c_.\u001a\u0013\u001a/3(X\"}s\\\t'm_LY{Uߙq@Qoۗw\u0003ÅǩR$5Kp\u0014;/\u0000\u001eO7\u0014U\u0003y[ǹ7,r\u0012\u0013Z|+6Q)C\u00023^u\u0014_~A\u0010X3v\u001c:@\u001c4Of .\u000b\u00152R-+G\u0017ھ٨!ւi++\u0005 09\u0007R\u001f9'|Ef1\u0017v]t\u000fYz\u000f=\u0005i͠~\u001c\u0011*_R\u0007t<\u000eJp&Ό ގ'3\u0006*A\u00016rzLT\u000f[YR\u0011HMr[L ?\u0019Z\u00009v'%\u001elA\n\u00174];\u0007͔xX,l\u000b*p\u0017\u000erѷ\u00197ЯXl\u0011:\u000b\u0002P;.4ލn\u0016]%?zu\u0004\u000er\"\u000e;7/k&\u001a6\n\u0010Ѐ}Q\u001e,z<6Wz+\u001e2\u0013ex0p\u0002x2%t|Z8욚q\u001e-łD<+5KO,HZ{G^\u000fY\u00037\u000blYf1xv\r3@5'\u0010V0s\"\u0016\u0000\u000bD;~(ݧ<fӽ=pڑzMBaؤ B;q:WsEL\u0005zz0\u0000\u0001\u0014\u0005y.xIh`\u0011\u0002huB=\u0017\"{H\u0018F(ͅNl^޵Dݲ%j-\"-P˄!8\u0011\u000fQf\u0012\"\u0002\u0010/z\u001eJ\"I\u0003IL-\u0010'\u001fnҰ\u0018`\u0003P\u0000yQN\u0006xV9V:\u000e7+q\u000fpI\u001cWy\u0004Sl#\t\u001eZmCp,=JG\fqDfU0\u0004sl`V쿯?0(|E홇h\u000b\b \".\u001bi\u0005DXu^\f{=\u0004s'zeKXxoHz\n\u0017*\u000eo\u0000uP?\f\t|(=\u0017ⰳze\u0013\u0014jRu\"P9\u0003\u0013\u0012_W6s\u0011\u0015W-fqA\u0005[\u0002b[\u0002܋\t\nC>\u0013U\u0005f`RRQ 'v\u0007\rn4MhL-ޫĺ4AͮB_\u0006&\\.UۿVv\u001d݇~\u0003\u0011Y\u0002\u000fee\u0005&o!HY묿:bEsŒD`?e\u0011qj!\u0004\u0019+1M[t5fZa-r?\u0011P\u0006\"!u\u0000w,6bq\u0013*uH\u0000ϒH]Ko\\\u0010d\u0007)\u0000GW \t_wܬ~,d;apG$a\u00199(\u0012\u0019#RR>\n`<m1W\u0002<\u000f\f}\u00015cDo\"B9T\rw\u001fZ_T=lD\u0018˺\u00007uxV4%O\u0010C!\u001f\u0000\u0014\u0015\"\u001aTic䥚>\u0010\u001c\u0014.\u001ex;8\u001dp6Fr^P?G\u0012}B\u0004&de!6)\u0005Yo\u001c)퐦vZ\u000eW3Sȱ}\u0019\\J!\u001a\f7;\u0012feuc\ts)4>R/?\u001fn\u001b\u0016B\u0015\u001b\u001crQjwV\u00073#/WaHG\u0010h#ď\u001bmBl\u0001\u00010[Ĥ4AaS{Ygbm\u001a\u0000\\Β,(\u0012\u0002I8Ϟ\u0017z\"|~c\u0013*#=\u00129\u0016^\u0005\u000e*6\u0013Z6\u001fq8q:\u00126\u0003M=)m]EJԅiG\u0011\u0016R\u0007f$픡,RAU\u0012Y'nzy93k<\tA..\u001eLLh<0~\u00110*4\u001f\u0004|;\u0004mb6\u000e'w\u0000\u0003!\u0005#m6\u001f\u0001ݰ\u0016AC^\u0015\u001fE>S\u0019uZM^\u0018k\u000bo4Ewd,xyao\u0011C$\u0013\u001a\u001bQd/\b+[g\u001ft=\u0013sԏ0(r\u0004\u0001<$tSK^($h\nx;>1K8ka\u0019NZDi\r\u001c.Y\u0003\u0016%Q@E+]hY\u0000ufi\u000fb\u001eǚFLPi\u0014dŠҠ5uKbIpB\u001a\u0013ZvtaP8Uz]R\u001as\b~l8ۊbr*r\u0010\u000fj)L\u0014:\u000fb}aH.N\\B6Pd\"i\u001eq{\u0019V\u001bB|4,`\u0016;F\u001dPXWSL\u0019\u0015?\u000b\u001fG4}+9e\f4?\u0017\\?y\u0007ƲyMe~J_A;5%;@\u000fN8v\nT\u001a\u0016fPb\u0006MHfTWcM<ʜ@R\u000e4\"\u0002\u0002>$jzv;cH\u0005d!rf\u0014p\f\u0018XV#<~6C\u0011\u0001̚?^\\Q\u0006')\u0014x\u001boHf%rgЋ2\u0013\u0005Unm5l\u0001y\"\u0019z\f\b\u0013\u0005\u001a\"ҌB݊'j\u0000K\n\u0002ode\u0006qyj\u0012>=v\rx\fdS#n\u0005%'\u0005\u0004Etq!\fbTF\u001d\u000bT\u001c߰St\u0005`\u001f\u00065Y^m\u001bi\u0001\u0011\b-V,_fΩM$\u0000 \u0002UG\u001b\u0005Z6u+GF\u001f2ME3>eDD\u0000,9[z\u000b3kz\fO$#A3ZtFXs6K\u0003?*@\u0019/ٹ~\u0019`:0DШo:8\r=<\\q\u00193,3FhHK/\nߘ\u001aCeC⩣Ě_k8S{\u001fo\fP\u0007`q\u001d$n CҕX鷚\u0001\\ңe\u0012hu\u001bIi\u0018\f\u0007.tc\u0011OCӜ=gf\u000fZ\u0004Dt%a\ncֵ\u001fn\u0017u\f\u0010/\u001fhGJL6[\u000f\u0018Jѯ\u0001p\u0003[\u001e^U\n[1\u0006lTBe9\\m\n\u0017XӐ\u0017^Lo1\u0000\u0017;nV\u0003JS;c\u0010!'5\u001dHq`\u0011Y\u0014Wi\fX]\u0005Ote\u0018V`~Syd\u0001RiN$q\u0014:X{a\u0013\u000fHdwS⵮\u0003.\t&w^ޞJ7\u0018%\u0006<\u001a>NCH\u0005t^\u0013\u000f\u00103E\u0016\"(\nȘ\u0007I\u0013\u000e*\u0006HW»V\u001e\u000fgV\\e\u0015v\u0004\u0007\u0011\u000f]ZBvjcAu\"${y̲.RYr\u0016z\u0006̪q\"CP'\u001fGo\u0005yBέ9\u000bW\u001d>\r/uRẮ\u001a\b'=\"\u0001\u0001c\u0014?\u0003kwy&i8\u0002\u0010\u0011\u0000*I&rPN$T@~ߣ3Zpޏ\u0000*_cG\u0006u֫ \")\u000eZ@\u0019PY'p\u0006$!\u00063ɩ3a㚃¸;f*=5Qn\u0014lَ 31#rƭ\u0003&\u0017\u000baf\u0015\u000b\u0002\u0016o,Sy&#QD(Zs\bK\u001c\u0013rR=5'NOw\u0002^:ɴ\nLY3Ec7]\u0003nq{ }*\u0002\u0001y3Z<\u001c\\\u0015\u0017\u0004\u0012\u0001b n`O\u001e\u001c/\u0006\u0002h\u0013\u001ckS\u001cN#\nB&\u001es\rK+Jߎ=\u0012B\tH#hHL\u0005\u0007\u000b όKK&9tO\u001d<\u0019F\u0004Msg\u0003\u001b{i,u1\bh#\u001d3!|\u0017l\u001a\u0016\u0005rtﳡ\u0007P\fV\u0002\u001b5`#\u0000!\u0002-SO\u001ea\u000eM\u0006f\u0012鈇Av:S\u0011U\u0014ύ\u0015v2E<2QO겜_D5$Pյ)\u001f:B\"~B\\,\u001b$GKy:<&cw\u0015\u0010dE\fxtU\u0005\u0004CWx~^;2dw\u0018U\tAUbF;-LO3\u000fǭOCB,xd7F\u0014u\u0002=H\u001f6uaxv&28S\u0011_wNJ\u000e)z\u0012#!5\u0012vig&\u0013N\u000b-1$2\u0001noJ8!F6iwt#\u001bi\t~&\u0013\\7\u0004tALW\"\u0011\u000e%A+\u00157Re@,? x\u001a\u0007\u0002w6ʋQ72,g\u000e\u0006&~Xdb:\b^U\u0013}Y\u0010E%\u0014]\u000eQѿƀ5/E_\u0012Q;\u0005\u0018\u00027G{dn\fо\u00004<\tl\u0011\u0015vF,,J<.f/1\u0013r]EĻmoH\"QgҦ\tH-+ٟ\rw~4X\u0015%[\u0001ԣŽ Q<\u0014IbG<Q-vWL\u001c\u0014\u0006փs%\r>2W\t\u0000ՃOߎԥbه[t-y\u0012\u0006\u001bC\u0003*Dp\u00121Pu\u00001\u0003!\u0019̞S3`E\r!H\u001d\u001f\u00071E\tt&3!cLmx|\u001e\u000b!BCFOJ8\u0017mE\u0018f\t*(\u00164@R'Ь*m\f.g5Բ`\u0000YY\u0007qD;\u0006s\u00144xr\u0015\u0003\u0011\rJq\u000eAĐyӷ\u0010\bh6&ȆIj1t\u0017U(xq\u0002>NVf?x.r\u0004:ºFlxAO7\u001e\u0005\u0000RXND\u0001q?\u001bpIV\u0013΋\u0002c\u0012\u0017b5+\\Mm'gȵ\r%{jrͰ9o\t\u000bJfu<h]($*N\u00034OT\u0015^(K\u001bmi\u0003̕#y\u0012eW\n\b,#\u0011Sa!\u0001\u0006\\\u000e\u0012$\u0019\u0017TR\u000b\u000fn<־\u001at'\u0001J\u0000)3$j\u0003!8>t[ډŰJ\u0017Zx\u0013+Yц\u0000R\u0013*{YZq\u0005\u0014X\u0003\u0016\u001dݍW)2^,s\u0000T$o\t\f(O7(M1\n\u0002>\u000f\u0002NP\u0001pBM}\u001e\u0004\u0012\u0013((\u0000\u0000?ЛZHZ&eqrAmi\u001fsbc\u0010 \u0004\u0015WHSa%&eDA;_r;ɝa\u0016\"nkA=\u001bʇX'\u0007ݛ\u0001/Kwj>\bhZy-rTjhgPәz3<\u001dlSLP\u0015\f梊\u0000NL>҃\u0010\u0010\u001b\u001aQ\u0000h7ty<\u001bȕ#|a\u0019\u0019@\blT\u0019\\\u0017\n\\1]L@\"v\u0001jg-u\u0004:\u0016]yp\u0005\u0002 /4-ͨzĚJ\u0001aJU*[FȖQS\u0002<Ƿ2:]Ie:\u0005[gm\u0000B\u0000\u000eQ4c`u:JHȔ\u000eqĘ\u001e<\nLq\u001c0E;\u0015ͮ\nd\u0018':v^}\u0001݁˭+bl\\-\u000b7wP\u0015\u0019\u000eH}\u000eW|\u000e\u0010ϻI\u0014Hь\u001f.\u0003J4\u0004&w{\nvo\u001d\u000b˧]3Bz#^VIiD\u0012\b`T@\u001fÑ5\u0001v\u001b.\u0003\u0012\u001a7 ʾ\u0007Y1j\u0015+\u0005\u0004{ta\u0001L/>\u001aevIћZ\u0003\rqp\r\u0004\u0019(8\u0000\u0005]\u0010R\fd\"Չ0xNa\u0000$x`\u000e\u0003nH}?!uGS2\u0000\u0016\u0012Xqs\u001c!*\u0015zJ}txw1b\u0002&A\b\u0002!6`ӥET#$vnb!F؉cY)4h \u0010.0IV-\u000f]xhl.G%\u0019WZn\u0005#\u0010lL8>\u0005)6v\u0018D\u001c\t\u0007u\u0000UnD죛P\u0012L\u000fςQ ǟOӚ8\\Z\u0015]xq+\u000e==UUR핇6\u001aܻwBF/#7\u001aIz[oZ_\\\"')c@\u000f2\u000b\u0005\u0014\nxN\u0001Ty(D.\u0005TG\u0001Egfu%\b(ShYe?_IHYrX3i\u0005(\u0013-2\u0000M((\u0013ڋ\u001b)\u000fȆi\u0011v0\u0012K{|}f6l y\u0011gjmڥګ3nj_@\u0019cf\u001c5y)rXO!\u0000oqR >C\u0010+U9B4\fm7c{\u0004k\u001a}\\+cd]c\u0003)<ݼ\u0002\u0006ԚJ4uؖhqo{\u001f$EHU4-\u0007|8=/&)/k\u00009*\f{\t3hL\u0011\t\u0000ֹ\u000b\u0005\u001aU*Mr{>\u00047\u001dpK`qA\u0012x-\u0013fwt::s\u0011\u0006ҷdie/\u001e:R7%6A\u000bz#ح@=o\u001aZhm\u0001\u0019wÜF\u001a>\t_ƚQ}pXz:\u001290k\u001dӓ\"EJlL錤bW1oHe*5-\f\u0006.Ax\u0003\u001aH\u0010iDe\u0001*)yTlJ|炋\u0005dÙ`%a=Dp$<+\u001e\tOT<q\u0016j\u000ejE+\u0019\t%\u0011LOz&j|IU⺏;m\u0007C0i\u0004άx(e\u001a\f\u0014])\bv\u0019GҔ_=IY\u0018\u000fjMT\u001faM޲zyʂйⱫ\u0007\"h~ը\u0002֚=\u0000SpSf\u0002\u0004\u0014\".f-aoIɝI\u0014u|#{A_\n5Մt`b\u0003at99HQR*`\u001e\u001eۛS<L7꜀\bvѣ\u0010ZDx[\u0004\u0005H\u0016\u000756n\u001fCiSw*r\u0007'GK@u\u0006\u0010\n7-P>C\u0015^#\u001aR\b*5\u0004zA\rRG\u001c\\F\u001dYX\u001f\u0017:\u0014\u001cA\\晒z\u0005cF2Ԑ&w\u001a:+*6yq*m\tc\u0013w\u0016vv$&\u0000aP3\u0003\t\\\u0019\t~}P$\rGP\u000b\u0001\u0004%_E\u0002R\u0012<\u0015$T;SزUJ\bBRkYVV76GX滦{(W\u000e/w-\u001aOd6\u001d\u000eF\t|\u00199.|g`0Й8~m#qO\u001d!\u000b\u0003\u0012O\u0016-\u001bM~,bl,\u0014>d)k*cLѤ\u000e-3r!QJ?gB\u000ec<E~L%぀:\f8!\u0011%$i 3\u000e\"I~\u0017D5V)6-:)Gщ\u0002M\u0016iyi\u0010މ/^\u000e\u001eܡ\fCwX+Ro\u001eCs\u0012]\u0011|\u000bU{Fs@ H{Bp=\\#\u0011#\u0010fv.e|\u001b\u0012iNoM\u0005'O\u0012o8<\u0004\u0001FO\\>zs'JS\"ؓh\u0017bP>E0LW\u0010\u000b{rVT e\u001b\u0011cD\u001b\u000eRg #]Ayzn5G4f\u0019h+%h\u0013u.\u0007\toHJF}k\u0004f8uD5\b\fD0ME|2\u0004:)\\\u0019ɨ\u0016{3/24\u0019ҥL(P\u001f~n\u001eMȉٗ\u0002SN\u001a>'\b@%k^,$QPNr/Vaο\f߽\u000f8.n\u0007Er^N\u0017\u001e;\u001cblY;ԤB2%\u000e\t04-0\u00011\u001c\u0006Xl95\u0004IJƥ\u0003-\bۢdʷ2\r\u001d=*$p'Q=&K|#WDU\u0004E\t\u0004Qª&QX©MmTi\u0014C\u0018#J\u000e6Pě=\u0012PO\u0005w;k\\L\u000e7p)\b}.\u0019\rYQ4|WҲ\u001f\u000bv|yLMC\u001ex\u0007\\\u000e\n\u0016\u001d&\u001eg6\u0001%ì$*4\u0015\u0000kK\"VlKƂ\u0010\\0Xo\tv9)\u0013̥}\u000b\u001b\n<Meϰl\"\u0012x\raTL5?\u0004uG?k\u000fbQ\u0019.0ptטLu&_\"4\fgEV[`\u0001_6k&\u0010Z\"3\u0010-\u001f\u0013#;$y%V^RMt\u001e;\u0005`gEEi\u0003Fej9\u0014\r\u000fb|6H\u0011l`\negA\u0016$L1.1\u000fWM\b0\n8O\u0004~p%e2/\u0007\u001f)\u0006Dq\u0016$C\u0012Ê\u0006\bt$X\u0013\u0001Bγt\u001dQ+ѨZ!UG\u0015%냌hi\u001c?\u0002O\u001e[ne\u0015x\u001dC\u000eӐ3\\>~ssb3C\u001a?@,\fu\u000fq9:\u0002 q\u0005ﱜJm(RgBi\u0019ӆ\u001e\u0006\u000e)\u0002Awo\u0012+qV\u0011\\W]0\u001eJ\u0010ʷ\u0012\u0000lp\u0005UcP\ne\ft?\u0019D\u0001\u0014I.J3M$\\\u0005iaYPm\u0013#ߵlA.M\u0016^$z*C\u000et\fe4iauB,L\u0013j\u0003]uV1\u0006n]@\u0014/%#\u001cPܬY\u0014T\u0014\u0011.<\f}y1H\u0011']4s/*T.*'\u0001O\u0015/)@SA\u0007(A4$%\u0003V\u0007-aYa$ylAa\u00014=n\u0019Dp~\u0011'{s,\fj\nb\u000ey\u001d\\\bq\u0015Uu<`\u0004\t%!\\*{-\\r2K)#_ܢz\u0016S&JGgd\\\u0017B8%~t\u000b$k\u0017E\u000b.\u0000ć\r\u0012Uo\r()&W\u0013׿>ȍHQhO|r\r?\u0012\u0012`O|N\u001c3\u0004dRƺ\u0001&\bI\u0000Q\tx\u0004l'ܛ\u001a΄(4)k\u0006_qCixLjc\nwR\u0003\u00001\u001aeziPm*}\u0013\u0000[0\u0013K\u001f~\u001cx?㺘;Cy%\u001f!$S\u0018d?Gp\u000f'\u0011Nϒ7\u0006Xd+;<>M@\u0005\u0014~mE\u0012{/$\u0003yԃ\f\":bmT^g%ϝ\u0015ʕQ)Wز<zq\u0000u!\u0001t\u0013R\"d,;\u0017t8\u0006bvk\u001eM!\u0018\u00184\u0019ݪ-9^p.۾HG'\u0013c\u001a*Ch\u001b\u0018bsECpȽ\u0015\u0011+B!MO\u0012\rճ?\u001a^Qxr[\u0000sCg\u0007-w6\f\u001c)E[&aE/\u000e\u0005~?\u0004\u0005!\u000e\u0019O/%`\u001d\u001bledGrO+̡d\ra\u001a\u0017+UF]\u0013Я\u000b\"\f\u001c]{J^AG\f4_42ޤ\u001eG6,кy2cǬt~\u00068TBŜ\u0001S;!y8/7Ak}\u0012u& $ݸ%s[O.4x΀\u001c\u001b\u001a?97\u0012Ρ\u0006\u0006\u0018\u0018\b|.P=\u000e\u001d#Y\u001ca\u001bjb\u0018t\u000bm;ˢ!\u0016PИi\u0010T}ɏxw\u0015\u0016A\u0003=\r\u0013\u00016>n4xM M(@\u0000i\"?\n?bg)433\u001e=\"|\\ڡQȏv$d`=̠>?R A>5\u001e׆֥{¶T-Ҁ_\u000bhq6[<wnlx\u0000|4HFa𹱃9\u0000ڭ\u0006Pl\u0012D\u0014u\r\u0019\u0006磪Р4,\u0002'\u001e)LX\u0003\u0012S7yV4F4\u001eA~j SB\u0000\u0007r\tT.|7U\u001fY\u001b(}f]asw\nm\u0019T\\v-\u0015@$\u0019Mݬ\u0006gu-\u0019p\u001a8}m}-ڮ7\u00184z*-Oِ+97*L\u000ff\u0007&֚\u0007grbJz&PTj\u001ee_=~ҡY5H\t!#\rѼ)\u0003@$X\u0000\u0014\u000fR~%G`\u000ewI\t'07XG\u001b\b*VC\u000epc0\u000eg}\u0012NApH?-\\\u001b\u0018y?gL\u0004*+/ۮG)N&,4܏}\"s-)i~r\rĕ\u0016\b\f\u0019cA&>4:0YH%!X!ݟ.\u0003\u0013\nӌt\u0014)t?\u0005AX|u<~NDcB\u0018\r\u0002ַl\u0000\u001fFx0=)vğ,\bBް\n8HPc\u001b\u0000s0\u001d\thFN\u0014!,zW5\u0006\u001ç\u0015sB\u001c\u0012^\tSg\u0002Ը7ʠn\u0001RN\u0014\u0019EE@\u0005\n\u0004壞\u000fJN\u00050\u0003V?+\u000f\b1w\u000fTuD5\nJ4u\u001f`tj(\u0010{#\u001dr%Jڌꙇ娝sB\u001fBFJ\u001c-ęr\u001eۖ]\b9\u000b\u0016{]\u0010\u001e\u001dG\u0000\u0019Zҗ`>$I~ \u000f\u0016\u0005c#q|EG\u0015_\u0018\u0002sGX\u0014Y{d\u0002T\u0007C&~eR\u0007\u001ci \u001f`\u0018\f{o/F l怐SzJ'}\u000e\u0015\\\u0000\r\u0019R*\u0018!CL\u0016\tdeo\u0017'`kF\u0016,?\u0016\u001fdo\u0007B\u0006#\f\\/v}NF!n\u0010if3/sJ8+\u0000+\u0002\u001cAK˒\"=(eի>I^\u001eEyNJ)?V\u0000\u0002<nh[,2!]H>l\u0011@)Ueޝ6*\u0001\u0016)t.qN%\u001e1!Crg\"s\u0011ի(\bUgLuI\u0012\u0013\u001fN{ \u0007%,Ćw\u001cH_I\"D`G\u0001?\u000f,<ѡTme=,\u001d\u001eQ.lBtBYE&{csbk\u0001#*r4!Tj+6ٻp؜;RlA=G-5~?/^\u0012esƾ\u001a\u001bf-x3J@\u001a#u{\"8\u00060\nDQ:-IȮyk\u0000(%쥳K?+\u0004P];\fSg2{\u0016^\u0015)T\t1@\u0011lC-\u001b$gh>\u0003E\nKY\u0001b5é ޽\u0012lg&n\u0004\u0017AF\u0014\u0003kO \u0016\n'\"\t\\;y\u0002HÅ\u0015v\"\u001f\u0010F4sqbthY_BLIc!:w[n\nu؉P(\u0001\u000f>Dצ\n@\u001c\u0006\u0010EC(f<VrY\t<ϩdQ>J\u0005M)\\\u001c\u001bX'>$\u0003yz\u0014iYb<\u0006\u0014P`\u000bS$k\u00148n\u000bĮ\u0015ΩI\u0010D-\u0013%{2@brT\u0000Wdr<\u0013\\\u000edZ\"\u0004qٙeJJA-ZМ<I-]\bʜ*F\u0001=*_ePL\u0010ΑהP[=.k\u0015F0 [;=ng\u0012?S]gaLvKz\u0005P\u001f\\Q\f{P{1Czk߄\u0005jOJn\u0003aY9 \t\f\u0002أsKXQ\\\u0011XC}W,M\u0015Ӳ\u0019\u0000Z\u001d -D\r\u0019[=h\u0002#\u0001D>ve=\u0003&\u0010+I\u0012w O\tp]ҡ\u001et\\A=GkCT\u0015\u0002j\u001diƧ\u0007ᴄ4d`Ŀ\\\u0005u^E5\u000eK_k\b\u0018\u0000?E\u0002m6\u0017 {G^\u0006|^y+/u\u000b~!a\u001c\u0011\u000ei5Z5<$`(O8CؽG\u0000\f\u001e\u0001\"I8q\u000fM|DBa\u0010RQ&y?h)wq2kl55O~kՏJI%<vCăã@Q{Z&br~%~y}p\u001e_\u0015#\tA=\u001eߐGTd=0e!vᝁJ\u000fwQ\u000f\f#~ɭ_Ǳ{<b\u0019a_(nK+R(\u001es15vu\u001frz4\u0006 Rӱ\u0015y-H]Q>\u0006[̓mB 8qux\u0006Pg0\ncĎ Ћۅ=A#\u0001}\u000eUp( 8AZŞr'+\u00044Ol4qZ#@J$\u0000\u0001~\r\u0015\u0012\n\u0014/$ ?@6\u001c\u0016)\bClk\u0013U'\u001a\u000fC\u001a1WYR2L+\"'D᾵H\u0012gl%V)ü}|\u0013sz^c^W\u001ehZ\u0015[A\u0015?ԯz\u001f\u0007\u0016ϙz!塖zU\u0002уh\u0017\u0015<~n&N&#[B\u0011~@\u0003\u0000\\qp߻I%\u0018jAU̔֋O\u001b=lFbZ\u001f\u001a+\f!\bk\u0007#.dQ\ty?\u001bz>t= x(4s\u00022|ك\u0006vό?6\u0010^#\u0013$\u0010\t\u0006y5kS$iG\u0006=tdJ}\u0015K\nȽjA-hv/~UU{M\u0019\"ꛧ~2-Tk\u0001\u000b\u0012^ڬ&f\n\u001b\u001b#>,4\u0014\u0013p!\u0001\u0017\u0000\u0011[<8-q*{7.\u001e\u0003\u001b⍯J\u0006pm\u0018m\u0014\u0000YPW\tP`rЎ=%TY;8t\\GdUGZ\n\u00193W0أ\u001ezE\u0018B@\u001aq\\^2\u0013\u0016搇\u001cׯzH\u0010׷Nإ)\t`\u0004\"\u0004a7y)\u0013@1TςK\f&\u0005Ӵ\u0006]8P˩/=\u0004T\b01W\"\u00037zt\fį \u0013Q\u0012=\u0005(a-cu(y \u000e5\u0000Fkȧ\u0013%\u0000\u000eRNjC#<\u001bn\u0006φ\u0016=\u0014fmZl&\u00075V\u0010|:.Ƶ9\u001d5\u001f\n\u0002h\u001efQW=\u0000\u001e-93}\u0014Y\u0014\u0004bi\fٸN,Q\u0010/-\u0015-ș}!sȆG㤬\u0016SV*L+vo-yTU\u0000wLjsiZ馢I/zݜi:\r\u0005+R=\nߑLf!\u0003\u0002]\"AV{\u0014 (%d]YW%\u0005UX\u001b}eZ~TAѺX2za]Ң\u0019D?\u001f%\u0019K\u0016\\\u000el%\f\u0005\u0007w\u00165\u0016]B\u0015b\u00121e\b\u001e\u0012r{Vt!g^\u0012\u0018n\u0013HR5c[2l\u000ebRH\nn[?TR_\u0017ܜux\u001a\u0010`oA64\fV\u0001u\u0012\u0015:Ⱥ\tu|\u00046\\vj\u000fy\u001c\\c\u001fل${􀰟\u001echO\u000f;z\\ωEf\u0013\u0019\u000fk^I\u001a.Ր\n?=M]2H\f;&\u0017A\u000fU\u0013'\r\fA\u001e\u001ao%5\u0018Ҍ\u001f!l)K\\!6ɡ<G1_7[\"P\u0012g\u0001ƶ*c$MM}Q\u001fk+C\u000fly`\u000b`L\\EM\u000f\u001c\fZ+=\u001e\u001fNګ/?WB/{\u0004B\tV#\u000f\t\f2Z.:cr$\u0014\u001d'\u001a\u0003qzo\u000e\u001cB5`نðd\u001d\u0014\u0015\u0018f\u0003C\u0019k2ip\u0010![A6\u001epʤU2'0GU4o\fVi\u0018x\u0006L\u001c1,y XOi64\u0010l/ͭn\u000f'\u0005_>\u0017Q\u0017ܙ2yEF4HxR9d\u0014\u0012a\u001a\u0006\u0012-R!=?hلh\tDܦ6\u0006#oXdP\u0019)\f<f iE/\u000b\u0012rbhW\u0004N>ը,\t|d\rR\u001b{dR\u0011l\u0002\tSm\u0010<&xKnp9BF(YY\u0013K\u0007\u0003+OJ$s\u0004\u001b\"S\u0011~\u000f*m[\u0011\u001b\u00021\u001ed#i}K\u0018״\u0003G5\u0004-5\u000f\f+\u001ajOs\u000f\u0006NL\u001aW;j\u001bfmZ#H\u0018l>Nخˣ\"c\u0013[\u001ea\u001aQ\u000f)&U\u0003\u001e\"s\t뜓U\u0010l16\u0005:&;\u0016F\u001e<=}5<֬\u0007C`\fxbZ\u0004\tB|^7\u001b?w7O\u001bW\u0004kڢ}\u001eOI\tQz\"{/&X$f\u0004\ra6#du rQi㹒\u001aIWua]}RxsƓt=w[d\u0004*9[?ȍqqa0S*.*o=| ~jj5y\u0000E\u0007lfǽ)gS$\u00024@h\f枢op9Z,3I\u0002A3_Z\u001eM;\u0007wSSbn9\u0000\u001d\u0018\u0005\f=͉\u0007d+f\u00145\u0016G\f#JyP#mϑc.\u00029\u001cue:fA y\u0001\u0017o\u0000mI\u0016C`S\u0002lV\u000eEլTj#z>(\u0000\u0018R_\u0003Ժ\u001akn\n#'\u0012}\u0004ʶoH>\u0002&O\u0012Z@啔B\u0017wCf+N\u0003+uF{D\u0004\u0013z\fb)b\u0011?=u\u001f\u001a\u001fUȪ8\u001bb\u0015:x\u0014\u0015\u000f̃\u001a^/W,p>fn?XװqYZ~Sꎠ!@qC]>Ȣkt6K\u0006|QLDN\u00154@iA\u0017pY)\u00161\u0013ˋX\u0007\u000f$hf\u0000\u0006jkGWbR:#?!\tr0e@\u0012Nz+Kję \u001e\u0013׫!pkU=B;?[o!T\u0006\u0005a2\u0006\u0018C({\u0015Q=l3[ƤzSI1F\u0012>\u0004czyyB[A?\u0016su\u0015w$B+T\u0017=%Xb\u0016\f_ƃ \u001b0È/Ƿր\u0019A1x}nh{}n\u0011\u001b\u0016ݺ)\u001f\u0007\\\u001d\u0003\u0001,\\+F\u0016F24h%|/\u0013:\u001d=?\u001b˝7\u0017ặE\u00112\u0016kb<OuIiDEev< '4!BF<\u001bA~oVx\u0001?s\u0019@HQ֦>(/\u0002\t\r<?g\u0005{*Ǘ&\u00000\u0013o&\u0005 \u0006\u0002{\u0018q\nZ#\fBAx>#),e>\u0012P\u000b\f\u0005gN(\u0002i掬\u001b-oh\n\u001eH≾zW\b0b\u001f\u001fF0i@&ބ\u0001\u001a[z\u0019\u001f\u0014{?vt\u0004Ⱦ>\"hcX:\u001bv0Ѯ\u0016mP\n O\t\u0011f\u000e\u0016h\u001b\u0004Pk`]mKa)j]\r{4\u001eFZʰ1#l\u0007-K\u0000Bw\u000bo8}Ã\u001ept&da\u000bi\u000eޟ?V·\u00121Cy>L\u001dѤ\u0014Dg\"\\U}B|r|Ωn6{Q\f~w6HE*nemrX\u0004W\u0003HmXD_542\u0003,;_y\u0003c=o\u001f\u000f~??w~BNu_~\u001f/_ß?񇋻_W\u0017H1B\u0007\u0006/;al}#&)m=\u0001K+\u0005\fXVI9-\u0007*\u000f+䨑kA*\u0014󙚙g\u0010Q\u001d\u0013{c\u0011Z`z:cT\u0001Q\u0014r\u0013>Sf\u001f\u000f\u0004\u001e&e8M'7p\fy\\\u0001(\u0006a&ԧ\u001c!V\u0006f'3fm:\u001ajڠJJ\u0006i|6E#2\u0011T \u0000U&4\tBgV&9_;WM^ђ.j\u001a@~Ef\u0003꾉4eݶjAtJ(\u0010\u000f4RKR\u001dYNe>V\u0001m4/;`f\u0010\u000b>َʶbe\u001a-r{^ϫK`<\u0014\u0012mn\tϱE1,7I|xl`el\u0004)tS\u0012Ղ:\u0005(\u001d,ePd@\u00012C\u0012fB\u0010\u001fa?[.R{\u0006ܩ=G\u0018W$\u0017\u0003\u000e^נ\u0015!o\u0007\u0000︔|\f{\rѨ+f=.`O]2[1\u001fq\u0005iB/\u0015ZBdR\",q\u001f⽯\u0012ͩ(p^TU2g\u0001\u000fw\u0006\rn\u0019\u001f\u001a\u0013f\u0000c Ȯw\u0006\u0001X\u0012sw\r\u0010\u001a\u0010=\tHTqQ F銚wg.=u\u0003vNh\u001c~{o-\u0016J~7\u001eb\u0007\u001cJ`\"/G\u0011H)?S\u00164VH\u0013/%wxael{\u0011-{!H\u0013\u0003ko=\u0016\bS`icS\bSKy-\n;@e\"\f\"ǳӆ?\\pf\u0015M\u0006j\bR37*E\u00197\\6t<M\u0017sжf;ӻԌ8vk({\tĹ{#OQ\u0018Fh*\u001aFV)\"mF1艟'\t)4r\u0005\u0005\u0010\u0015,\u0012\u00002\u000eu\u000eg\u001bڴ@w*~\t=~\u0017,\u0003\b4FS?R_\u001b1J~U;\fȼ+_+k,a^{\u0017P63\u00141pȄSc$+Q ~{5{b>ψJ30\u001fK\u0007,͈ 16E\u0005A0+j`RIgղM\u0014܊B~cJ\tf1|[/<\u001cX3k{\u0011_,{b\u001c\u001e\u00191u՞'#hIgհ\u0001x\\α!J`hŵ!\u001c:~츍o`սZ:\u000f#8s\t\nv\u001eԑkP?lg>\u0011\u0005C(\u001b\u0011ͽ\u0006\tF(\u001c1ŗbk,̺\u0011\rEYj-B\u0017h\r%L\t/9ȑ]U>A?`{3WӨ c1w?\u001b\u000e\u00106a*´us!\u0005\u0001'顧D%\u0011=k\u0011\u001c^\r.*\u0017\u0019@u-\u0006UKZ{f:<ao{\bɉ{fᣆ Á\u001fV_/\u001e$\u0014\u000e4?\u001d5`@\u001b!\u000fV\u0013;\u0007\"R5-.6XmK\u0014Fkcխ\u001b\t²Яķo\u0006X4[\u0013Ïo/M\fI\u0016{\u001b|.\rV2\u0004\u001fxȑ?AgwH\u0005=\u0007{:\u001d\f=B|\u000b5^ޙK]gK\\IAF߮\u0012w\"\u0011\u001de͸x\u001e\u001e2ٟa\"8.Y.1gr1o\u001a4{>y(\b\rQr|6[9\u0018g2V*\u0015¾\u00143aZ\u0015Vj+E-znɽmsӝAߜ$g\u0004\u0014\"\u0007;X2w \u0019ęލ\u001c&ZwK\u0002!_Q]_4\u0017\u0006!4uS\u0002qB/̵ةH.q<Q\u0012𲨥\u0001\u0018\rdl0U\r~x>S\u000eQp\u0006\u001e~\u000ek}>+t!\u001bbR\u0000\u0010RA骎\bB\u0013$E\u0010W\u0005%D2}9>\f\u0014\u0010\u001e0\u0016A[)bj,'-漷ff\u0012LH@0\u0010m̟Fbf2\u001dƐ\u0013r9Zӗ\u00189Dơј\n/(ex\t\t\n\u0010\u0010\u001eŞ\u0017z\u0015\u0017ۯ/\u001c޴!\u0010m\u0015@N\u00055|ID\u0001LaN\u0016@_ìQp\u001b.*:ݟ\u00124\b\u0003p\u00059gV4Uׄ؀^Ȓq(\r#m@cɆC58AEԧQ\u0006\u000e949A\u00026RXA3r8/Ui䪓\bBCAfG\u0013z3=Gs\u0003Hgo\r8{\u0006Ғk`\u0018ygJ\u000eKj:T\n\u0003a M*'SW\u0001\u0010#1\"\u001c\nS;A\u00037`\u000e)6;ی\u0016Qi5\u000eg)d{\u001e;G\u0001\u0017uV9\u0004jg\u0007@Y葍RV)fS/\u001eב\bHr \u000b]<cFڄNj\u0010 R^\u0016+\b\tj2\u0011\u0017`Il\u000b-G\b\u0000X=>L\\\u0005\b\u001a1[Gwh<k\u001b;\u0007Ώo(\tv*<쉦\u0005u\rW[9JB\u000f\u0018\u000e-[\u001aX/\t95qe?&\u0005&M\u001bM#\u001c\u001a\u001aX/X\u0006%Q\u0010\u001eŽ\f%\u0018#F\u0018IR2H\rk~\u000b\u0002\u0000{\u001ab,\u0003܍v\u001aud[P)zkucZ\u0004{:\u001a.}]-rFB\u0014{{\u0006k#!Qp\u001dI\u0011Ԉ\u001bf\u001cݎJ|\b\u0019,NP3ãX\b?\u0000?%|+Ԩ,k?]RC\\a'\u001fwa@]\u001fe9\u0015<\tvZ;eqtP7\u0006G4~Ѡqęo\u0011VKE\bG3(zj\f.s\u001b`3\u0006GAE=}Rb[}PL\u0011-\b0(\b?\u0005{\u0004WC֚3`\u001ehrC\u001e\u0004Cͷ\u0006y/\u001aFf\u001d\\\u001eQ ע/%Ө{^aq>\b\b\u0006rx\u001d{kp֭\u0011b\u001cxc\u0003Zh\u0014D==\u0000VlLr4DU\u001b;x;F\u000f\u001f|\u001f\\Lesݯ;d4pEWZ\u000f]:hAZ^'Rː^\rO\\\u0012/a=KfƘMrh4a50Xw'U,\u0015=_\r>ɿ\u0014ۉaǷ0X{݅R+T\u0011қڶhHƉhD\nA\u0011 \u000e_P;T\u0007?\u0013\u0014ƵϾ\u0000:h\u001fLi&\u0000CQ\bC\t\u0015dgE*Ww$\fk[sS\u0013\u0003\u000eDe\u0012m\b\u0001\u0001!ڷݐh쏮3]m]߻\u0005\u0013\u0015dS϶\u0007\u0006ʐdO>޵}\u001e2kdO\u001bO\u0018\u001b{g-z\u001eu\u0015Z]\u00028\u001f\nr0\u0016\r\u000b\u0003ܓ`\u0018&{Ci-j\u0018ޕTLxp\f<׍$6\"?\u0005\u0002}k.H́\u0017h~mϤ:3@$\n3@\u0007\u0001ظ]yk`y\u001c-K(\"4+\u0005&Ɍx\u0002p,yGA*<\u0001\u001cLO(x\\\u0015hsx08VrpS\u0014fo\u001cF8'O$\u0012ÖFb#ƂMw\r%!\u0016L\u001b:S\u001eqSA(ܾ:6I^jC01\u0000}|&x|Ȅ\u0012\\\u00066\u001bw-lX3\ng\u001fS!yǇ0B\u001c5\\uRO緹U\\v|p*wcKZa)\t%\u001e@\u0001b$sb\n\u000f(=<6\"\r,\u0005\u0001ze\f5g\u0018n\bMZ6lt\bs\u001e!\\\u001fexX\u0018\u001c\niw~ÊnI/\u0001~vP<«s\\)\u0018@NI-E'C\u0014ߞ(\"ѧ\u0006 矿7\u0017d\u001aܶ\u001b\u0001OcPNb\u0018-AG\u0001z\u0000GUhX\u001e,-\r*\u001e\u0017P-vcjb\u0017=3mӴE\u0015uF\u0018\u001c\tp\b'jjӰ^\r|\u00051s\u0007\"p#m6\u00070OU\u0017d2\u0013{(^\t\u0015Y\u001c@^JX|(V|M.\u0007R\u00175\u0007B9@9o1g\u0005\u00185籃e\u00017o\u0016L1p\u000fCjtQHSm@V]ɭ^\r׷pR^}/Co\rym?+\u00171o}Y׾M=S>Ąm\t/rwR\u000eiQV\u0014q/B\u0005\r/7\"O=m\u0012\u0019\u000e\u0018\\nۊQp\u0016;H8eamb&hԭ\u0005>\u0010\t=xr02 a\u0004IKuh\u0005\u0014\u0012ư\u0011m'@B%f0=@\u0011Y_LN\u0018{əqP+>C{4!0h\u0003Xh\u0004^6ٶt59/zDzg\u0000j\u001eKAvMj`\u001f}gMM\u0015$ȍ\f}bw \u0004dM,Oz5f9\u0001$3Uz<r\u00013Lκ#|`{_w^\u001bQޘ{݆5|p*\u0010U\u0000OTz([!&G\u000feMY%Jq\u0003\u001eI7\u001eKʔ\u001d\u0007*\u0018:|[J[ay\u001fH+k>>&<\\\u0001ǈAfk\u000eú\u001ed\\Vn\u001eXݩ?;d9\u0006D\u001fz @>uНzv1\u0015_ڮ\u0015F0>v\u0005;O'\f\u001cqzG{3>2v\u0005XTj\u0015íV\u0003\u0002\nMpǹ~\u000bϔ\u001a4\u000b\u0018Y\u0006n[\u0004in\u0011$)WL~ѥEykB#ԵN@\u0011 @@,\u0018ު~\u0004Ru\u0018rm\u00035Y\u001d.1\u0000oq'Ah\n\u0017Q\u0007ê#nD\u0012_Wo\rn\u001a\u001f\u0017\u0015r3]ý\u00118+i{\u00165\u0002Sq(\u0013\u0000\u0016\u0011\u0001f{\u0002<$ɼO=/ʖb[|]\u001cTdDW7\r\u00142(t\u0019NC.\n<x\u000bJ=t5Dr@Nh۠\u0010 \bTЈ$Pzv\u001cKdZ4LhV\u0001\u0015\\)\u001e*\u0014P$W\rnS\u000053DphUU0]~vl)5]I\u000e \u0005\u001cS.ʎn;5\\;M\u0002h\u0007YC\u0017ŇfIh*QkQ\u0012]Hcq.c\u0000ȱ ]_$yWoAd!А\u0012S\u001b̴\u001aT6W]BSS\u0001Uktz\"gi2\u0000SΦR4\u0012xBHh\u001c\u000f:ƻgo\u0015d夈Es-GRCGA\"\u0002:rMzYJ\u0006\u0005\u0010=\u001c-O<\u0006ު\rP\u0004)3\r\u001btO'%zd+\u000eo_ַ*z\rendstream\rendobj\r176 0 obj\r<</Length 65536>>stream\r\n\u0016+v\u000b*넛C\u000fJzl>5\u0015y\"`wO1j\t\u0003P%\u0003($\u0002m@!(c`a\u0012Y\u00000o ['\u00164\u001d\u000er\u000e\"6\u0005\u0011=76\u000bMp\u001f?C;\\Gi0\u001aw\n&ױ\u000b\u0017̮#*J\u00183\u0012FΙIvE58A\u0011+\u0019\u0012\bsJ0*=8SBed\u001aZd\rЕ5ݷKlP0a\u001b[}\u001b`:\u0005%(k2t|\u001c\u001eU\ndO.S\u000e n;\u0007J~7&0ʵ-h\u001by\u000bjb%*Fur\u0005wCf2e\u0015=\"T B\u001adfN\u0017\\#\u0005KG\fܤU\u000e\u0004]\u0012w\u0004\u0018\bR3B$P>}7jE\u0001etZk\u0003:咔N\u001eeG\f\u0000beX\b \u0016[6\u0018A4C警Y'H\nm2~4[B␀hݒñӹ=̺ۙ9-z쇒fL8H_F#Qz[*ǖd?386:%Tю\\Z4S4\u0007c=.G,\u0001\u0006\u0000;u{;ll0\u0015ZXs>F\"\u0014AFU\u0014(v\rd;v=0\",Ĩ:֑Fu\"K,\u0013Q\u0007\"\u000fu<\u0001\u0010C\u0007zH\u001bPrǃ\f\u0007\tu녙\u000f^\u001aR<\u001bi$&\"4y1\u0014&Vi\u000fS:F\u0012g K|U\u000eS#gh4=X\u0000u\"r&9xW\u0019a 51\u001dG\u0005zX~tgIdƈ\"\u001b.\u0010,n6`bQy\u0007D\u001a\u001eԶJί߂Cz\n@+\u001e\u0016Ej2^7]\tיA\u0010P!(5U\\]\u0006\u0014H_1Vd\u0015)d*.fKřT8f\u00015o2;:\u001a򢁊{h#\u001e=$v.\u001b\u000631eZSv})\u0007dy\u0005D7W`{\u0012О6;\u0019v\u0011Ɇy;o\nzcg\u0010a\u0003︶\u0004BF))3v&OFEj*$\u0015\u0002NaE;aڎ#\u0013&7\u0019Vw^A\f\u0011序.KkH\u0010\t\u001c\u00120$׮\u0019M\u0007r#[\u001c~l^`@VH>\u001ao\u001dֶz,TJ\u0013\u001eB\u0013\u0004z\nL\u0010wyR\t)7\u0017}+$]@'q3\rCL'iЫ8WH\u001cKW>&A\u00015ȡ=H\fMZjmU\u001c^=t\u0011\u00135\u001c=7f2\u0010)[99k\u0012\u000e\u000fSAF\u0007_ʕ\u0006R\u0002n'Aj*y=8)halz~ɂؚ\u001f\u0006\u0016wbVF\f4\u001c7\u001fF'$zf\u000b\u00147*\u001e4(\u001bVQ\u000e\u0006\u0002\u001296f\u0010\u0007nޏ\\z3׮\u0012\u0019xu87G@݁\u000f<@ߛA\u001dI\u000e~^\u0004|G@Ԡ1\u0011B/{q!\u0001\u0006͑]\r/!z\bvxKص\u000bVVxe8-\u0003<P5\f\t\t׌f:ۮ\u0011_q0\u0003\u001d#$`\t\u0019$\u001bOۥ}قX\u0013 \u000br-S\u0011\u0019ƝPW=\u0014\b87GC\u0002K\rJ\b\u000f0\u0007mL`5e.cO2л`@`cU}g\u0004\u0007\u001e]A\u001a8)~; қZ!\u0017 a\u0016L\u0010\tb\u00141y0Hz@\u000fz\u0011[D貈\"'קvњ=5҅\u00057P@]\bt>\u000fdLޥ\tT`H D]\tO\u0019EO.;<L\u0019j01AfZ%g\u0006uMn?8&Cͺ\u001e\u0011fm/[y \"G7)H1\u0006U\u000fB*\u0012(<Af׈:\u0003\u000eI*\u001e\"\u00019ڂ\u0010091jZg-\u0014K\u0007J#١6\u0005\u0013'&@T\r\u0006҃<\n~\u0016dwk\u0018OSaeԽj\u0019B\u0013}&f\u001b;Mi!Y%9\u001417\u001dlB|\u0019m\u0016{#v3t8\u0002\u000em<b·\u001e\u0003\u0006R\u001fZ|\\$\u0015\u0015g}\u0007gS\u0007L°SK\"?pXH}Z#X,T\u0000pCH\u0015ez\r\u001dvȿ;\u0010|Tfz\u000f]e.\u0019f\u0007\u0018;,\u001f:\r\t7Jsmwެ+,8IH!2jQM\u0007#{cУ037=;\u0002V؜x\u0016\u0010vhPm\fx(qZBC\u000e~\u0010e\u0017`$\u0006`Kq\u000f\u0014MB\f7-u\u0007s\u00039\u001b\\$*\u0010DyCB{rLk&wN0\u0011DDu;\u000fm^x\u0015-c\rcCѶ1@\u000br@scbl\u0000xH5%\u0019RO!&AYad[\nj$\u0010\u00077%gdK\u0012\u001e!\u0016*tLYr8.3b\u0004ql\u001f׊\u001d`R\u0000T3\u0015\nyH0pH8[$#\u001b\u0007Gu~XTC'\b?\u0011u%8mQpAa@֫zDo<y%?\u001a^\u0017T\t@5ehu\rw_\u0016\u0017\b}\u0018gbyHkB6\u0018?p,\u0012f\u0014zkw\b8Si\u001f2*ǖ,+\u0002h\u001fs0V`x'HסZ\u001e\u0017\tר=񐉷&O|RvM(7n'\tWΚL\u001c}ȓ\u0010\u0001\"\u0016\u001d\u0014-7\u0003\u0002\u0000QO1\u0010Y>ʔŦ\u0003~++:]z~)2\b\u000fr!lg;<\u0016pd0'ׇ\r</\u0018c\u0015WgX>DF)j]\u00126r\u0003f,;*j\tQظ\u0001\u0004+[3 &>+﫩y>\u0005q\u0017q\u000b:&L8Ό(:72\u0011\u0002\u000152:\bJmf\t\u0019ys_P\u0011lW#\u0001\b5\u000fi:Cx_T$W\u0007/@U3qc*CҤ+čqI\u00111\u001e[\u0016\u0002s%H\u001c\u000f\":\u0002=%g\u001f\u0007z+\u0018}\b\u001f\u0014 ܸ哹D\\>;\twid!.z;n#Cȸ1/~V#B(}\u001b\u0011:v#)G\u0019ޮtC9P=_LI-˳/o\u001bzJ\u0014:s=tɏLtGՖ̔\u001fd'\u001d}fG\u00055r$]1\u0005\u0013C:\\\nCi)\tO! áMә]\fTgmU½1_i{}UΟĆJGJ\u0002\u001a(&u:B\u001cK2#\u0013\u0000;D-\t|\\f\u0011\u0007sٙ_v´8G\u0005y\tl\u0002PeͦDQ{ۉu\u0018M\".\u0006\u0006w\u000f\u0002# S_\rM_ć\u000epLl$Pcc\u000eI\u0013+NaM2b4$\u000f_\u0006_\u0002\u0017\rf h\u0004HT \u0010EEI\u0003\u0014SGG+\u0000\"\b{>a5έ>[Lv9B&c|\u0019_Q\u0002s\u001c/!^e\u0015)PS\u0013\u0019ᓨ\fUԟ\u0012,'\u0002g\u001c\u0019\u000b%.sW\u0014>O,\u001diKf\u0014Φ=tEo}2\u0002xzʽ/k3QfV蠖Y\u001e\u001d\u001a9Ńգ'\u001e ҆Ygvb\u0015x\u0012&bXSY`=\u0001\bRhC0,FV\u001d\\>ѽ\u001d$Y[\u000b/6\b[\u0012lMz|=&w\u0002)\u0012\\Э5w}^=]3oW5\u0010|L>\rzd3v\r\u001f(I\u0011o\b\u0006\u0016'p_b#1OcP+{^xº푱:bM\u001cձS\u0017\u0019ID8\r#\tю.f\u0013`^gu{ےg\"&\u0010Z}۲QI`>\u0018=\u0015.ND~p\u0011p18U\u0017\u0016\rX\u0018]mVดNDb\u0010t@W=\tq\u0018/ \f5|\u0015\u001c\u0015\u0000\b\u00067Yەsk*C\"qY_S\u000f \\\u0019z2T8A\u000f9Rdw}$G\\L\ba%\u001e~\"\u001f__?i坈\u0017t-M*]nϝN\f\t꼚\u001c:-|Fu1߉V47\r\u0001Eӓ>n\u001b=vǖ5+ARDh*u\u0007\u0011z*\u001aT\u0001҉L\rj2PLңy/E\bt\u00100L;7X!I.F\u0018\u000bj|u\u0015D2leTkQ\t\u0007=ɽXF7<\u0006\u0003e\u0010\u0015U\u0016\u0000t6\u001bju\u0018xg&\u0002g\u001ctu,U#h]_0~⦓\u0000O3\u0019ch\rwH\f\u001d.=Sz\u000f sz&@\u001cc'ʋ{:\u001bB^kn2*\u0001\u0007PsJI⇪Ez<O}w^$\u001a\u000f4G}V\u0016d.\u0007xV8Y\u00036\u0012@Y>+JG6k\u0014RA'dK^\u0000\u000e>±U4+sw:=L!(\u0019A\u0013m{)\u0005Y743t۸N5^!\f\rtlk\u001fD~6/-v\u001a\u0013\u0004\u0001YQ`Bag40jY/r%Tt)\t6,Wo;,aR\b$M$!7V/a M]GJ9w\u0014c\\(P}(9w0\fMAtN\u001f׮\n\u0012PHle|\u0013\"̔%e+*tyKD-\u0004l\u0007\u001d\u001b̘\u0012\u001dID'L^mƼ\u0013`&Os\u0000y\u0004 \b\u0019]ي\u001b\u000f\u0004\u0005b!w\t y\"+\u0000\u0006\u000eS\rmށV\u001d!|>M\f\u0003\u0018ԽgLZ\u000b%\u001ag*-s:\bӔ|\\W@&|Jе\u0001xQ#C{ͫSi>\u0013\u0013Fgzf ԍTt\u0014-\u000fȖ3-H\u0015\tpkl\nm^C\u001ea=G\u001c\\\u0010vg*SSGw`2ḓ6\u0002\u0015\u0010\u001eTb\u001e#BCyq\u001e\t~\u001bUO8UBf9u\u000fRI\"ʽ\u001c.Fݳ?0B\u0014B\u0010^{ \u0003\fm\u0002q\u0002^Wd>.L6\u0017sh\f`=9\r9B\tD\u0015\u000eo\u000e\r^̐ľ\u000eg\r\u0007\u0000_ጩQܑ\\\u0007se:\bRz\u001b\u0006Ľ7\u0019ף\u001e\u001dL!@(V\"\\}Ha\u000e!uj\u0014Qt5@\u0003{L\n\u0012\u0015\u0017.q\fQ\n\f}\u000f\\\u0011]\u001d\u0015=#\u0011\\B̍N8㦿$b@\u0016\tZMO@zӁc\u001dCtJPgb\u0017Iu&\fFjС\u0016\u0006\u0018^ݚH9)?\u0015ly x{H52Q@@¡v\r>gXPkj\u001d\\|\u0012mt\u0011\u001d\u001f825\"\u001cec,\u001b<$/\u0007xH\rjd[($#q޲)\u0018χQ;V[\"h\u001f+ڂ)ul̸=2\b}\u0004\\5*)$c\"_L)ߖ\u0019dvCb<8'\u0018|(߳ˢ{\"e|\u000eRn-\u0011l_(Pz;#xf>S`\u001cQ_Hdz^[@,\u000e\u000fh'汗90se;0\u0019y~)\u0014Bw-]+:hfa\u0018\\y\t\"&$\u0015\u001bL\u0012\u001c5O\bzWC ;E,Z2HG\u00147PC}ck\u000b\u001a\u001c\u0011\\x\n]jQKnWέpZNpe$Q\u001bS>\"@/1RҸ\u0000Ϗ%Lyh0ʪ>\u0002[\u0007\u000e\u001ae\"c\u0016=vʄH3I\u0004\"]Gw\u001c\u001cirl\fȽmPc\u0005O4Jth~`\u001a\b8+7}9\u0001>4v\\b^\u0000w۪`./#75*3V~~\u0012-~xRdH\u0001\u0018= 6uED\rFe\u001bY-p\u001d:Wdfb\u0014\r\u00036dO#=Z\u001c\u000fׄ\u0014H\u0010ǕٵCG:\t階{43+Xݩ*gkrDrME\u0011\u001b\n-2\u0018[<ND:\u000eMm\u0006\u001a˨3?r\rjE\u0015\u001cX\u0014\b%R1\u0011\u0005R0\\\u0002kݟ{W\u001e/\u00184\u0011\\\u0004\u0001\u001enE4\u000e9z\u0004ęr@K\fɬCL\u0001|DW3@-ga\u0002Ũ\u0014^.Ɫ\u0010HB>\u0016:xbM4լ![#\rkm\b<ج\rIL\u001bZHy.8!AڴnZ\n\u000fZ\u001d=s+\u001bBYO:sn5E\u000bQ\u0005ABhP{&u\"\u0016j=s;f-ـ (YFj̝5K\tW\u000bKMBc[/=C\u000fWt֒tjv\rvkDͧd#\u0004\u0000T\u0007B;+4\u0000'59\\u\u001adPJcjȷm$Pmz}4Ce~)y{Zn `K\u000eia+{X\u001e֥\b\u0015T떇jph\u0010`V1>\u001a)5D\u001et޿\u00015~=[㙵,h+~\u0013D\u000b55y>ϵ-^?KwP;1@\u0019]i\u000eF+\u0006s\\ʩ>?괴[ml|l\u0003q#\rç\u0014O\u0003w\u001b\u001f\u001a>33:D\r\fDY\u0015\u0012ƴ4\u0017& 9ڣETt\u0001\u0007n\u0003/;3cس[\u0004aǇC[cݮEH\u0012\u001141\u0015IteãR|)׊q}m[\u00012;=*\";hV~na<|n YBey\u0002#H`<vpN@n\u0006\u0016B8\"rN\u0004o(_\u0007S!6&[\u0017Fd\u001e$\u0003EA\u0013Δd\b \tkW!2!v(\u0014\u0006㈨1<$#؞'UCޫ\u001eЮhq\u0001gz\n\u00181\tbxuጾ-\u0016\u0011\tAv;OC᯼:\u001fޑC[q;\u0001G\u0018E\u001d*:D0R\\b:\u001e1\u0017-K\u0014Jb&D\u0019S#,:^3?q\u0017C#fN\u0003Ōھ\u0005w2/TlM0\u0014%Q\u001e]\u0005nGumD\u001bvO.\u0000່N㙪gLئX\u001bZQ(5\u0019[9J\u0018augnAdfc~zr'\u001dG\u000b mK\u0004y\u0001\fT Z\u0016XԔE@s:2\u0018/\u001f\u0016lVZ\f*ǖD:\u000f6Q\u000f\u000fE\u0018A\u001f.l\u0000V&bll\u0006θ\u001eIeIAA\u000b/++G\t-6\u0003sYg-g&\u001eXqVx.2\u00184`-w?\b\u000f\r/-8S\u001b\u0002.?3~ki\u0014\u0000++0\fCQú0U\u0001\u000e^2\u0016q\u0018c\u0013\u0019\u000fYE`.\u0007G\rPM.\u001fU@\u00072\u0001M-ux\u000fi||\f4qq\u000fN\u00143Wc\u0004mA\u000766b\u0018;li9yarCN2}l<QM~@u3m:IRT9a|/\u0017e NHql&׉4>䑐\u0010NpEVmH7\tDdsxDI(=TQ? 3%@Mzщ.q4\\\u001e\\\u001e%\u0005rPؼZ\nt\u00123-MR&'Q<\rĥ/e-!I:L\u001b\u0001@WX}:%T8aB\u001eI\to.\u0004\u0013W\b0\u000bńE\u000ff[E}fo.gà\u00014ܸpSMPPt^\u0018m\u0007ם>9٧^R\u0003\u000fMj2\fAȶ)4\u0017bu\u000f\u0017BFQ瘡\u0007Gz\r`\u001f\u0000\u000fRPH\niH\u0000\u001aωbNg˭\fHx8L{l-a;Ex\u000e˶Io:\u001b^'\u0002CkE5XZ=2qo7Y6@&8[\u0000cxy=Lט3\u0005yv\\ȈC[߮\u001e5DQis/Pܔ1L\u001e\u001eN4B+*k}nȄ,a\u001fb>yeq_4\u0000q{nr{7^k\u0019'\f\bc9*yL$.?ܦ[ܳGRH%\u0016%\n\u000b>m$ڮFU襪Z/\u0003P\u0000 oRmm\u001fN\u001a2\u001f׆E\u000blqi+f)RS]|^WpQr30cзSd|p$cpn\u0011\u001c\\q[?wZ\u001c,\"f\fLۇyfeHõz\u0014.Ia\u0014ң]\"7=\n-sk=+J΀\u0014fTb\u0017ZΜ\u0005ymd]Iơe7\r*Ɩ\u001f\u0016V\u0005,hFx2u\u0017c+@\u0019rLU-\u0019[Г+\u001e,VZ\u001cPۑTiY\n\u0017\u001eӷW99%ɺ{KFLޙFvnA\tm8\u001c\u001c\u000eYm2Qչه\u000e\u001f\u0003\\>L!$ԁnL\u00026\n;Z\u001d\u0010Y0x\u0010\u001aՠDRֻל|6GVvh\f)gs\t>\tsEwm\u0005,ӓ7AIHIu%,2\u001e\u0007=\u001a]Җ[\u0015\u000bZ!\u0006-iv%\r\b_\u0016P\u0006!Z;L\u000b\u0016Q\u001aʳ\u000fho6\raW\u001crmVz`X\r7ɫ\b\n5\u0011ZZ>1t\u0016Dߡ*t[(/|!FǃBt\b>L\u0014 jߜ>C?k*AVt3M$Ik\"5R(mGc7u]zf!\u0011\u0013٠\u0011\u0015U\u0011\rc\r\u0007CeR\u001f/:\u001d[wW~T$/{]SR܈,lY42{(Jm<\u0006AO>\n>hEzr].\rM_e\\LYʷA\u0002iнem۩\tUIm!? D3\rq;]CQab=\u0012*e7O\u0018\u0018/su m\u0002fYsO両q94^jݨAץm]OU \u0019\u0004\\H|\u001blq8(\t\b1&9\u0006)<J4\u001fel`ī>W_LgOR\u001aIx\u0014l[\u000f-۸\r(nD(\"\u0014\tT3V\u0000Mn4@k%wnb\u001e\u001b9\f[L\"?޼.T]\u0019xkH˦`<\u001cľڮ5\u0019\u001cG\u0011o\u0012!R\f\u001a\u000b\u0000\u0013ԊQ!vIMT~x\u001d\f\u0016'\u0012$Xfh&bb|cP޶Sa\u000bM{Vl]CֿT\t\u001cpjs:\u001bn;S\u001a{:Q[ߏ\u0016\u000f΂OjcZ\u000b4}ν;4$=P\rc\u000f՟˰zFG\u001bD\u0017S.\n8=I\u000f(ӑfs\u001e0\u0000He\teޯ3\u0001m_*\u0005נ\u0018I*-lQ`a\u0015\u00014z}\u000eOV³iiM%\u001e%\u0012L7\u00000~փ\u0004Nd\u0019\u0018?\r\u0000ką^>ՠkn\u001aҨѡZF_{\u0019%UH%NB$\tQ\u0005jÓnw\u0014｠\u000b&\u000e\u001d4/r\u001bOE^\u00101{Ѭ=k=\u0013QFFΤPBZb\u0015hy#\u0014B}_@]d:0I1Bm.\b<5\"\u001e늏SߖN\u0011\u0013x1\u001evn_\u001eE\u0011`4G+\u0015\"\t\u0016\u0006Nr\u001dbtC8GRVh~>SۋNCx\bQ8HCEt \u0006\u001eo\u0013-']Qk4T7|SjYa\u0015\u0018t\u0014/g==th>c0*\u00199b=R\u0007\f\u0004S7RmSUwFW\u001d>DciΣ\t:}䴚xmcc\u001e$/1~'F,c'\fLp:\u001dMn\"\u000e*e\u001bF@Rp&ϱ\u001b\u0015-X\u0000\u0019f~\u001cW\u0002\u0006WmI[\u0012W=6\u000f\u000f\u0016AqVUmۚ\u0013p\u001fHʆs`-H8␒,\u0000S\u000fۄ0)g\u0004~Qg\u001bÕ]\u001fXfMvII~^/\fܷ\u001e0Udm1%0nuFUF>\u000b\u0010՟(a-\u0007T<\u0019B\u0011+m\u0015c&<\u0018jfCiId\u0012\u0004\u001br\u0012ע\u0001[I&-2s9\\\u001d1/Mu\u0010Œf&g]HnpAGF\u0000N\u0010p?^ydsv\u000ePIJ\u001e0PK[?^jK^$4kvU_tA\u0015==gy86v5}JN\u00163<RӪl~BGZ)=\t<&PZVASzۆ\u0000\u0019\u0011\t_\u001a\u000eoߒT=\u001c\u000f_C&^;{ \u000e&r\u0013l\\ފ|ܯ1z\u0003̳>O\u000e=\u0015\u0003j\t\u001dКcߢِC+|y;\u0011\u0017>ZU\u0016NoѺ\bdGX|p>܂5\u000e9=q\n\u00048۱\r4LVϙcԲѵ3<ᗯmx\u001bay\u0016i\u0000s[һ^W\u001ek*C)Y׵qOJz{Q\u001br>\u000bo_\u001e:\r$A<Y9Fǵ/c\u0016$JZ$g}K#_(XGT\u0012r\u00175n\u0010NxKGVcnTAA4t:H\u0001\u0004\u001b)\u0010N\u00169=\u0007\u0000\bFc\u001b3\u0001S\u0010|8BkUXbرbHDKfy-\u000e\u0003gZ?wA=TE\u0006\u0001SQ1hB\u000e\u0013]\u001b\f\u0002fZj5hG\u001d\u0006\u0018\u001dMҖTn+w:\u0004g\ty}J+\u001c;Flԯ\f{+\u000e\u0012[Jw*K\u0012|}~gY{\n[?4>BY\u00144Dr{\b8\u0014^YI9KP'C\u000fĆ>9ow䉋P?E\u001e\u0000a.|\u0019\"ඇqLc*\u0003\u0017J||\u0000i|QD|Gt?0$$\u0010\u001d#0Dr\u000fw}\u0001(\\j\u0015(\u0000#%\u0003k&~\u0011\u0011Wt傶\u0002\u001ex\u0001+%|\n{0$<\u0019sh\u0014\u001aD\u001bz1~)gvđsah\u000b9[M\u0006g-]*.\u0000\\\r^(\u0010\u0005a\u000e5}ݙ\u001c'\u0004X!ڍ\u0011a<\u000b\f~|\u0014f7ةY>o\u0010৶\u001a\u0015+-v\u0006`ayiL\"F\u0003%^Ei\u001eeR3{d><e\u0003a=\rpE\u0005@4F\u001b淇1zG\u0003\u000f\u0012\u001b\r\fQ\u001fT\f>7tJi[ORP7\u0013+c`l~lQ+\u000f\u0006oU\u0000\"\u0001>_\r̬|G9\b$[;Qrzj+\u0004C;{\u0019ic\\i+}.VO+\bml\u001a\u001152\f>7p\u001fύz򭹳\u001d{⛩\\$՚\u0007+\fQg̵(\b?\r3\rP\u0019)\u0003}n\\oe<qKuݺ\"rjd}a\u0001L<_T(ݿJl+WS@\u001bT|h&zMC<&\"t.Nuf0\u0007\u0017\u00003\u0014bkdXgwol\u0012>%tLW:y/e#W\u001a[e\u0019\u001f2Zp-\u0003ȝNB.0lYPgIEʃ\u001d\u0018\u0014yBoɭ~?ۿ7oo??7oY_ȩ_~\u000f\u000f??pq\n\u0002/z%\b>o#&\n!iz6$^\u0003\u00152'+\u0000Kiwɼho|R>)+dN\fd\\5\r\u0010\u0015\u0000`O,\n\u00042w:qʕ\u0007/ztRdE{V>EN\u001e\u001a\u0018!7\u0007\u001df\u001f\u001bB-[Mp@@)\u0006\u000e7\u0013\t֬Zo\u0005s8&O\u001bw*j\u0013;&\nر/\u001e͇۰{gR1ir\u0003G^\r{^5IpOdפ\rM\u001e~[ӭdHMQ\u001ey\fb\f\\h}\r$MO\u0001\u000f\rFM_\u000b-D46\u0006:K@\"\u000br<Dg\u0013\u0012s)i\u0012\u0015y\nK+]ynd9,\u001bwn\u0012@ι\u0015V\u0003LeMIFэ?o\u0007Mڐ蠖\u0016/5]\bFS6\"z\u001cM/g\"p8*\"\u001dk\noer\u0018>谖\u001fju+\u001e,v\u0016DkDM{X4\u0003X-E\u00178\u001dB\u0012(2\\\u0011$0\u0002u\u0011\u0004J,O/Pz0Yѣ1Xwa:y\u0013GwqqdlF~\u0016ήv%@QΘ@\u0001{^/zpXT`Ag+J\u0000h<*\u0003\u000fs\u0006[\u0012Ơkv\u001cTo._5s;hv\u0018\u0014iW\u000f&Ǡ\u001e\u001dU\u0003x\u0019(\u001eL3Qj\u000e~\u001d7uf\u0006Bgz)\u0011\u0004IADH\u00146F.1\bW\bE\r\u000e8\u0003\u0002\u0003xZ\fnKy.:U\u0000v\u001ca\u001cj>\u001d:Yac`\u0006py_ȋaM\u000b>\u0004Ohz\u001ez\\\u0006(\u0019n\u0012TA֞\u0001\u0005h*k0~\u0010jwQ᳠Pm^d㫑c}s]?ש`\u001d΀˘?V`| ؅fE =֚Q+5d6\u001fWݙ݁]B0+W¡t0>բM4 {\f=*~\u0018M5k+\u0004M{\u0001(]a}a/\u001dg^*Q\u001ad(Z~\u0003\\\u0000=X\u0005j3!8[$\n?!\fԏ}\b\u000bF%\u001a&\u000e Z81]\u0010v\u001ah87xItO2˯ޔ!\u0013}ǎu\u0017\u0012\u0013DOBðl\u001bEbzn'3Vz>\u0005o\u0007NF\tm\u0012>_\u000eÞ<F\u0002\u0014n^S2 6\u0010>\u0012D,3\u0010&@Z\u001eH`k=ۭ\u0010\u0013~\u0019Rp<ȏବh\f\\z\u0014\"/M\bAԊzz\\=`\u00033=4p@\u0017p{L_*Q#-\u0004e`\u0002<\u001e+&L'ʲA\u001e\u000b\"V=\u0013[uT\u001e\u001a$aHC4Cp#D\u0012a,fNo*P&\u0010=<#wXxL5H6Ҽiv\u0019Gf\n\u001cP:$\u0000sX]fp\\ii5׭͘\u000f\u0001VU+\tv[~ÝuqXժm\u0007\tN{\u00163<dkg,['?\b\u0000>/\u001e=&l1{0z\u0006=U;*|ʉ\u0000\u0019\u0016Xs&\t\u0002\u0003-ܒX7غ?\u001202YϿ4T\u001b*[L\u0005\u000f9\u000f\u0006~{54!\u0017-\u00184tjk\u0013c@\u000b,ts>:ޠ\u0017IܐPL:M3\u0000j-T\u0013G=B\u0013U)R[/$5ƣҴf\u0016<ځɻC\u0001\t\f ٤\u0004'v\u0004p8 \u0001~C[B){܍\u0011֡~\"O,\fZB\u001eW\u0010Z\u0016u\u0016ˣ6߈Kܩ\u0012\u0002\u0017\f ֯p\u0014Wٓ\u001c*UH\u0001|DAsSv\u0013i\rx\u001cd\u0007\u0006O,[v<\u001e\u0003\b`\u000feF\u000bK\u0019Х\u0011e. n#-\u0007Fn\ridZO\\\b\u000bo}(\bWLS\u000e\u0011P\u0015-&1=ݷ^lKCj3:JrΠ:˰L\u001e{>GRa~߄= yH8zPڻ(>\u000e\b\u000eo=Nԕ\f[c\u0017\u0005FlR97s\u0019)5W\u000fRj3js'!_I\u000b\u0004詐7@\u0017J/5O;P\u0012Lz\u0018uv\u00104 \u001b\u001eeLfv \u00065Z;׉gm/Љ}4\r\u001a5\u0015uN̵\u0004ĚuuAJړ2spG-Ms\u0002c_M{б\u0018zR{Q4yb\u001d6Tc\u001e\u0012nI\u001a2t)\u0004'\u001eɦP\u0002V\u000e哷〷2SdHɯ\u001b{\u0007G\u0004\u0010K_\u0002\u0006\rvJ\u0007!V~PAqj]9,,K;]\foG\u001aaܹ\u00138`!āQ-\u0005U'\u0013IMܺf.\u0013́}H\u001d,\rCl5\u0006p0\u000eؐ\u0006im\u001cGx\\\u0013?ҙ\u001bR}j1@H:Hi^\u0014\u0018Og戚\u000fd؈R\u000e\u000f_pUq:^Vec/֊q\u001dSe\f{ɶW\f\n<G\u000f\u001cp퉯Lk\u0000l\u001e\u0004{\u00007m۰ezM\u0001ECq\u001ez:Q,dW-\u0014rYr-\u000e\u00033\\*+݈\u0013_\")\u0012X\u0010eB\btEf3\u0010M_I\u0001Iu\u000bf*~W*Jթ3\u0011\rtw04\n~2\u0006\u0015\u001a߾ys\\[W\u0007hMkI\u0002;G\u0018\t4SӅ{a8\u0014~{=\u0006qeâ\u000eca\n\u0002͕@N\bKB<'Bi8ĮW)\u0017V\u0014\u0006+{]qp/\"g\\N\u0001E]*#]\u0004\t;p,oo5NX\u000bk@U#eN=\u0003\u0015+\u000e\u0006y\u0006\fi@K1\u001e@t@)\u0018}XM>741\u001fb\u0001I\u0002t\u0011}\u0012+t\u001eG\u001a\u0001F\u001b\u0012\u0005\u001e\u0011\nEVQ&S\u001aGO&X\u0001Q\u0005Te\u0016w\u001d^,<q?ze\u000b0x\u0016=Xӑw\u0015S\u0004ȿ<TT1neE\u000f5\u001fAطK\u0003r\u0000𭀨\u00062\"z:Ng)|2~iWY\u0005p~q\u001ciJd\u0003k\\\u0010k߳F۠\u0014\"\u0007#!v\"\u0006B4+]\u0001\u001aFU%IU1խa~t\u0010z.~\n$D\u001e\u0014LI1_0rގ\u00030Ϝ9u\r\u001dV^-[y>G\u001f\u001f^\n\u0019f7rL\u0015Zbɿ`ƴk\u0012A\u000bΟ\u0006˧\u000e0\u0011$u\u0014(+Z\u00073xi܈\u000e(\u001d!+\r}<\u0016^o(C\fߧ#<f%PH\bPOdɁ\rSIGjE\u0002\u0017=1WǁDAzj\u0010\u001aqfDz_\u0017ߣFg/guH1r0~L\u0019P/!\u0007T\u0007\fĞRx\u0017<gDJ-o݂R\"=κ\u00024S\rܲ\u0011l`\u0015ᙶS\")|\u0000;{M5L)80)tIj3\u0019\u0016\bŞ=Iy[{N(Rа\u0017\u0007!fCw\u001c\u0013\u0010^ *7k{maȩ=sN(jQ@k\u001afLL:R5_`_ߧf\u000f]D6\u0001*[\u000eAhB\u001fY(>\u00033Ɋ0\n_\u0018)6>'֫\u0000R^ƣF!o=v\u0014m8iwx^Q҈o$rq\"\u000b+_|.K\nHɂ~\u0000g~98\u0010\u00122 ;|\u0000[r\u0015#\u000b8U\u001aP>S'Y\bV\u0017ǩz\u001a1{k\u0011Y\u0011\u0019ٻbY\u0010]\tu\u000bu(\u0014b[\u0004k[la\u0001\rST<\u001c\u0002;\u0003AMdkuAn8Z2\u0017g'Qn+M\u0011GX\u0019r\u0005@\u0000Xr\u0005\u001eӮ\u0007\n֯Hv\u001e\u0004\u0014\u0015(l$ZH\u0013w!KִC\u0002Yn6bO\u0005׈1\u0003}\u0019B}Ezю$v2\u000bIo\nn\tjw\u0013o,*ܞxK/\"\u000b}RCM\u001eՆF:\u0006M=\u0015\u0016Rg\u0013d/Z<IzJ2\f\u0000\u000b\u001f.AN\u001c\u0010!RP\u001be3\u0018V\rDΩoRBs\u0003`jgC*`׿w29N4\u0007kaE\u000fSv'|u+P_كu\u0018x^2.Įrb}\u001a^\u0003x\u000e`oUU2A\u0001\u0004.`$B\u0000{\u0018N&\u0005Ib8\u0019Rs\u0012\u0003=.I\u0016\fֵW=Q?\\d/Pͼ\u0000VG(\"קw^y&\u0004L\u0018\u0010W=X;ӄ@\u0000?JK\u0006ڊc&!w}\u001d2 L(/\u0014 M\u0013IɁ\r\u001a\u000fk\u0000\"~Sq\b5-j\\\u0015\\\beX\u0013\u0005\u0003MA@@D}ٔ[$Xi\"\u0015㊱á&Ldޯb4@-P\u001a]\u00014T\u0007eE wV8U`~hdQ6\u001bK10K\u000f\u0012e \\)}\u0003ӣ\u0007\u000edN׉0I\u0003\u0002N\f\u0014zcAs\u0018#!\u0000=\u001c0M[yzP:%j%\fCy2{\u0003+sM\u0005\u0000Û\t6\u0018Mj\fry76\u0013la8\u0007@Z\n6\u001e\u0017`{bx\u000e\t?\rU/%|1\u0011w 7:vrsrI.?Q\u0010N^$)\u001eepsq^;N{8[P\r01Ygl\u0002\u0004\u001eTA\u0002O`󶴱vq`\u0004y,O\u0018[\u0019Fx\u0013<mI\u0000Ix3\u0012<X6<Z6Jz9z꾎5\u0004%\u001a_%fY~_%}s }{b܈-\f=?\u0017TȆU\\\u001fINu\u0004]P{ɟ^_\u0015=\u0006yP\u0015W{MZW\u0002Ts(Z{ն뀤4H Z\u000e\u0018z]3Ȟc\fY\u0004Hzg]B\rjǵ\u0011,;ի\u0005sE\f\u00076\u0015u\fzTa\\N\u0016׻jPIk51^]=\u0006L2,߶Z֭\u0013maX=\u0007\u001b\u0004f\u0017J|\u0003PE%\u0005&%`#Z\u000f\u0003U]0\u0018&TA\u000b[\u0015ӭIDI6\u0007\u001eN-\u0012,K^3}toj(\u001bD\u000f6Z?Y=Pr-\u0000>JW\u0013щ|0D[y]q9z\u0013Q[\u001a\u0003\u0000<#0NwB ͫ\u000f6\u0005g\r*\u0019s|\u0003\u0005n\u0002rھ\u001a\u0019lyط\"!n\u001dL\u0016\u0005y~_$z$[y\u0004q.MdKa;վqmz3}5FJ\u0005\u0007\u000b\u0003d\u000eOoFFTGvoB\u000ej(س\u001eycr!3WaL٤g`k`\u001bSy}\u001cOղL5\tTź\\!8Y\u000b\u0001EG\n\u0004mPc\u000b\u000bç\u0000C\u0011\"\r\u000bP\u0006\u0004`\u0013ꁟ]zN@\u0010/\b}^$\u0002ʍj\\\u0010&\u0010\u0007SO\u000f*\\Й3*@OH\rA_!\u0001=d<g2\u0007J+<\u0016\u001e,\u0010ܲ)l\u001cr!q\u0000\u0006I\u0015\u0011=2|\u000eގC\bA}Ԁ}\u0011e\u0005\u0010\u0011(q\u001dK>^7\u0011)\u0014n/\u0006wke:ں/\u001enPA~2q^\u0003\u001aPSap&'S\u0019\u0003\u001d\u0019k\u001beW}\u0011u\u0005#'#\u0005E#HNڱ8$\u0000Ui\u0011\u001d\u0011\u0010,Jà_>&\u000bkf@2&\\\n=ε&\u001e\u0002P+В\u001e5\u00149\u000e\u001b~)+/za-n|{\u001c^\u0016z\\@䊝_=܀y&\\\u000bn\u0012)>\u001euσdQʸNn\u0007F5Ntii\u0014Qfρ\n';\t6At!Otǐ\u0007Oh\u0005Ta5&?7#0<\u0004L_}X{I\u000339q\u0010(X!΃~v\u0006ˋP0T@T@%,#p%F\u00004HˡkZ\u0006Ugiq\ni\u0013Άşw()C\u001bNW`Ȧ${Ȏ\u001e]5\u0005\u001c\b\u001a3!F\u000f9ϙ2_\u001c\u0000T}kWy+A!\f\u0004SR\u0006\u0019lu\n?)\u001a7C-0Df\u0000\u0014\u0018e6'l\u001eȡz[sϽN\u0010\u0016״\"ܺ\"|R\u0007B4/C\u0002NR܉@\u0002p'\u001fh%D\u0019;|S9M0?F\u0011\f@\\y\r\u0017dhS-\u0010|'vlnf\u00079Er\n\u0004\u0004+\f\\!`(0N\u0010oU\u000e\u0002^\"צ\u001cn.:Bd9G2qu\bJ\u0002j\u0001NUu\u001fg\u0004\b\u0016W\u001d\u0000Hy^{8hC\u0011\"\u0010\"\u0015he\u0014㝵W4{=\\z/dY3:LQ͈O$=2\u0012@\u001e\u0016F:$0d\u001e\u0018:pTWÚRn3\u0014B\u0004AIb\u0004\u0007R,\u0002􎯂4xm҃1+HUB:\u0001<zt\\Qk 7D\f\u001fϺH\u0003|PmxF䣊&\u0001d\u0004\u001eF~yKK4^I~_|-%\b:%\u0014)\u0016j\u001fg7!<dþQq\b}w2 r^@N4X\u0013^!T^뚩ftf\b*ϙU\u001a\u0012+\u001cBY\t3L\u0007`e\u0012CD\u001a\u0019(/ɦ\tCta?=P=]\u0018=vad̾8l\u0001ו\f\u0014I\u0013dEϋnϽ\\\u000f\u00014k&o͕BDpv\u0016d{6\u0005\u0010\fn\u0012L\u0015\u0019U\u001a!\u0012!`\fd\u0015\tBp5\fOɀ\nqZ\u0001Ŗ\u0004@bL8\u0007\u0007\bi\u0000\u0001\u0007(,N\u000e8pM\u0001\u0016\"5~WPFgmOfh\u0018v-s\u001dZX\u001d\u0000\u000bȃ\u0014\u0003 iW<{Q=YGj,-y\u000fL\u0010ɑ>kʨ\u0002\u0018F'@\u001e@/l{'m\r/Q\u0016:\fKwг\u001cpi\u0003\u0019\"+\u001b7%4sn\u0012\u000fA#eD.~QĝXw@\u0015<_F\u0004>A\u0005\u0003i'4\u001f*b\u0006\u0000 g]vY+\u001eVt8fd6a\t!KF :V*\u0017%e$x7rk1]\u000bK[73sȌ\u000e\u0001Fs\u001eӁ\nK/(}fX\"q\u001cȄ\bhڒs\u0010!ari$ȥxu.;k˷\u0004p8lhW\u0018(\u0003iNuE=U\t_\u0004\\&D^GK\u0001N+.\n\u000bHW\"0zylߤ.LD#YRƩ\\ەʵ:T\u001d5ŭ\u0012\u0015\u001ebq\u0011};\u000fR>K_9<VI\u0015Z#+綆\u0002f\u001d}a\n6\u001cho6.1 \u0011\u001a#\"\u001a\u00156B!~q_\u0018\u0012K\u001de\u000fׇ\u001c\u0015\u0006ޭ\u0016Ap)-g\u00169$ګ\u0018:\u0000h3\u001f\u000fh'8H\u0000.\u0013!^\u0003+9>@PVl\u0006~!\u001a*Da ^?`\u001c0w\u0018\u0012\u001f<hU\u0000אY\\2yb\u0000R4l3]r!\u001a>۴^1B4ߎEƁ\u001es7\u0012K\u0005o\u0003~\u001fWSZO\u0010d.ϠC7\u0003H!N\r~[3T(Q&o(dm%\u0018\u0006\\(A.^I\u0014\u000f6{LBr\u0000\">EH{\u0017\u000e\u001aQ_%fk\tGrZ$P\u001dr˨t\u0019e\bY\u0019So|XUHRTB\u0015\u000fPu\u001eIA2cz4\u0003k\u0003 g$>\u0010C%{\"lDA\rXEP\u0002\u001e~\u0003\u0005:\"Rd͙e`.=g\u0002J^r]}řh\u0013\bh\u001c㢅D;R@\u000eVuǧ\u001c\u0006|wK\u0002\u001fEy9_iX\u0003aa~_R+7\u0010%\u0003\u0017xN?u\u0018P]\u000b~;\u0010\u0006W7\u000b{^@AjP\fM\u0005\u001e\u0001j\u001fB\u000f\u001f\u0010`Z\tp1\u0014d9Fg_s} &q\u001c-R5ǻ`<^JPM_\u0000}\u0015\u0015>LA=KP>2\u0000\u0001o\u001bX\u000b}3w;'JJ\u0014!+8pѣpM~}\r+J\u0018hA\u001aЍg7{*Ѓ7h\fG\u001cAa@8\\M%\u001eٵf7UR+\u0011\u0000)^q#e0U%%\n0\u0017\t$,xŧւǗx)ۿ*^6pk\u0011צUwZ\u0006dgȝtk!Q׬e%N\u000eN,?6\u000fLb=I#i\u0013\"\t)7\u0004M\u001a~a\u0007Z8jU!\u0011\u0005v\u0007\u0002\u000fg\u0007b\r\u001aé|\u000fM^\u0011\u001a,fɾxI\u0011\b\u001er}AtDw4XF\u0016\u001f\u0002@eEod\u0002UDZw.u?%N\u0006\u00182\u0006x\"uֿΤC;Ł\n:'\u000b\u0016;db)p1\u00023<;a=لd\u0014\u000e\u0002@\u0011DP0\u0001\u001f\f۰nB/ e@Xdf}\b>fpKg\u0010\u0007\noJA\u001e\u001e\u0001DI\u0006\u0006~r\u0002\u001dG\"\\\u001d\bDJ\u0002<u[lFxR@\u0004i\u0010\u001fǘ^\"Ltr\f:\u0001\u0011:pޤ#9=F:G\u00114\u0018TI(WwV\bbGB稝\u0000\u0000\r\u0006\u001a\rD@\u0002<*#JCcT\u0005\u0010ݟ'\u0015MZI\u000b\u0003;|2A|+i\u000f\"Q<\u001fD1\u0006LKJ\f\u0019S~\u0003*\u0018}\u0007DL\u0011qw\f8Yr\u001d/o9!\u0011Q)cQ\u000b\b\u001c\u001a\b!\u0005I\u0004_a\u0005EA{a\u0004,\"A5$\u000fzzj.N8DiuI\u0015.\u000f|^[DP\n'ma{\u0018\ny&\u000fZ\\e\u000em§=\u001chI@%d\u0004n?nD-kG4C5l\u0003\u0004'\u0015!\u0001Ϋ\u0000:~#_B(}q\u000bR3o\u0004\u0013\fA\u0004V\":KF \u001cM*}_\u0004\u0017\b9\u0000ʑLx%QM\u0002TU I\u0003'\u0006ۘ\u00015\u0016Eu{\u001d\u001f\u00150\u0011i`R\u0015A>2BEԢ́JV\bjIae\u0001Ƹjə'ƹ<J\u001b\fh\u001fsy\u000bK*_G{߉\u0013sIbjuD\u0005`D/>W\u0012ir@HR\u001a,hZ\u001cA\u001eL=b.s\u0018 m#55i~=O\u0014\u0011pj*\u0004yf4Hyp\"\\ba\u0014:\t9|%]5Q)|j*@\u001aJee-\u0017L\u001b\b7,RT\u0010\u0016Ea\u000b\u00136x9e/\u000b\u001eel9LQen\u001f9_\u0017\u001b<8_*\u0004\n=>276I9@\u0007ҁ1\u0018sƠU\u001fDek`<j\u0001?|24n\u0015I0LU͙h\u000b9m\t!\u0019z\u0015\u0010L2z\u001cւ7<ǀ\\\u0006\u0010B\u0000R*\u0017\n<ίJT\u0018 ؁y\t\u000fQӛ˶wn\r$Qӆ\u0013JBG+@Z\u00104y\u001b\u001fBwA\u001dJ\u000f\u001cortN\b\u001eQ\u0004gf豈\u0004%y\u001aŃ[2\u0017$|C=~s\u001fQ\"?j0A^\u0010.~X4IV1\u001fuEa\u0002M6{sPZ?^R>2G=J\u001e\u0007ZJ˦i![\u0006\u0001dj\u0013ps\f\u001cl\rb\u0017||f3U6\u001e\u000eu{\u00126GGf\u001f#E`g`\u0000:1hU\u0013Q1|Im9.\u000eiuj/ۧ#F\tS_\u0015KE(\u000fW|YP\u0015Yn%\u0019)kg3fWxsk\u000bk2V\u0015~[c\u0019_\u000b1od\u0006\rv\u0014\u0017:\u0013|O>\u0006g\u001a)DQ=[\u0016Ȧ'y+\u001d7\u0016m\u001f\u001ah*Mz;^Q\b\u001c\"*BynF<Bz̯\\\u000b\u0012Ǟ\u0011lDθUp{z\u0000\u0018-bNb~\u0010JҤ\u0012=)[۠:i\u0006>\u0014g.i\\\u0003H$f\u0006 4\u0010bTd*At\u0019S\u0000\u001eR\u0001oª6pᱷ<\u0011n\u001c:rDEIQ\u0011\b6\u00190qq\u0016\u0019%b|\t QH?FMQDèI\bK>)_RrɈ\u00132\u0001jd\nB\u0003Tq{BؚL\u0006^Ջƞϱ>HN#8\u0017\u0006Ќk_\nB+\u001b\tˆi\u001cg\u00019pqau\u00007\u001d\fz\u001e\u0000\u001cfD7̱]y>_޸Ƒ/\u00012P&G\u0005\u0014h{\u0015\u001ciCxOq1Vj0co\\>LAc\u0005&jlCwDFuCt\u0014mdke\u0000<Ɔ؜7E/^\u001aHFz7}kB\u0003\u0000ԥ\u0000i,y2O{\fx?W瀗O踽t\u001c/\u000b]]f@&~mn\u0002\u001a+e1YjcDtH'\u0013GĤ\u001b\u0006/S~Q=2\u001f3G\f@\u0002U)iЂ\u0007AG'\u001b]9D;`v\u0007xu玃\\BA\u0006ҜL\u0000\u0003Z.R4Zˀ\u0004k)m;\u000fV0y#X_L W\r[O\r՚O%k硫I%Zg7{\u0015P\u0006,IKc4\u001e\u0000p=S2s-V| \u001fm'\u001a\u000f|>L\u0006\b]o\u001d[*\"_PT-P\u001dZz帯年\u0002.$Xܨc>\u000b\u000b\"\u0018G\u001abx+W;Dד9-\u0016A\u000eIkNIF'{\u0013\u0019\nr80'\\\u001d\u000ec\n_\u000baؿ\u0010Pb\u0018D ]nƽ^ (\"tc)G(\u0012\u001c(\u0003$ȅJUhF\b\bWT*X\u00175X\tvMC~\u0015.)þ.I\\CThO H\u0015\u0019|\u0001@\bwql_\u000bCC\u001eۄi\ta3b>L\f77\"g3<dm\u0005~9\u0013%~G\u0003\tG_`a}F\u0007\u0006vcG\u0006O\u0001a3j@.-U\u001fk\u0019\u0000Ao<\u001cG\u001dvD<F\u0014\u0005F0mLLq\u00053d#V\tDe\u0019\u0013՛EcA\u0014ʘ{$caWQ@\u0002-\u0011\u000286y`MPHi2*qEbQ^\u0001\u0003.BJ2)\u0017׫]mj\u0001\b&(\t\u000fੲcN)zTR\fl%2Ō\u0011\u0011\u0006\u0006֥ofweV\u00142wRpAɼi_+,C~\u001cG<\t^\u000bث\u001d}~f۬@\u001cؑ}wIw.Ϩ\u001djػ#<\u0018\u0011\u001fqL\u0003ӣSJIDD\\EF.\u0017?f\u0002(\u000bP@j]z#\u001f63ayS@\u001f@4uHdj\u000fmLz6d\u0019n\u0006\tz׋e\u0013w/a\u001bqR\rR;:\b&\u0010S)7]v\u0007⁕\u000fs\\%J\u0011n7{\u001dU\u0001lp\u0007T\tas1ڷ)\u000eiP7\u001f\u000b,7h!3\u0019B˦~ge1^-klkC\u001auR;yNXQea\u0000^\u0007\u001czН\u0006iϸl BQ>pbq៓\u001ey\u0003V\b`\u0000^)=\u000f\t\u000bt^DRFqyS\u0005qe8Y\u001b56S|u^\\G;JjǐޝW\u00143.i:$p]s&\u0012\u001fD\u0004\u0014qgWL\u0006u0\fF\u0015D׻1\u0014OP\u0002\u000fإ\u0011\u0003\u000e\u001a\u001c\u001bXrD\f\"\u0017:ս\u001aZ\u001a];\u0014ϽWrbQV\u0013q\u000fhX@\u0011\"SD\"<N0}h`kIZ v\u0000\\DP6\u0001\u0002C\taޗ\u0013\u0001\u0000\"D \u001c?\u0006Ȍ\u0007Q\"\u0015ꣾZtz\u0001]x~R+S&j\u000e!\u001f6Fu*b*=[\u0004\u0019{%\u0002mwШ+G4sSa>\u0011V\u0001\\k\n7oC\u00187\u0006\b42h![\u001dQ[kt\u0003\u0014V4KK\u0005Vz2@7_\u0017:\u001fXTwR=I&_D8>\u0018n\u001f_\u0005Y&Ui(+-+w28\u001b\u001e ͑p\nے]5aw\u000f\u000b.9ܨ!fIQ\u0003'}~*\u0002_X0\u0007[0@9Ko:\b?G\u0002A\u000e~\u0016oh,fGϘ9\u0003\u0007|ٟ>q<r@G_?\u0001Gn.Vg\u0014PF'+\u0005n#SOF\r,\u001c\u0015VyLm\u0000\u0011@\u0000\u0004\u001fns\"1/\u000f\"9Qܛm\u001dK\t\u001c\u000e(F?Р'z]o\u0000\u0013?+i=X4\u0018\u0000M=\u0016j\u001apDʿ&`\f=\u001c] CR\u0000\u0016)z\b\n0cD)e#\u0005oM\u001cdՎSi\u0016H\u0011\u0019D#fw\u001b \u0013\u0018_\u0012 \u001f\u0016P7[\u001b\ni=(@u@}uSbZz\u001añ\u0001\u0012 V\u0006?6-\tx\u001c)\u0001-\u001cUwא-ٔl\u000b\u001a !əT]ǛV&O|*,IYv\r哎S5_D\u0010\u0001ˊ4\u000ftW\u0001\u0000o\u0014Bhg>$wd4\u0005\u0007\u0015\u0013\u000eegfz]\u001b`w#sO\u0003鞙;/\u000bڃ{µ\u0012\t;W\u001e\u0000W~\r\u0002)/(i\u0016{\u001eփG \rN\\5p5*֯1\u0015_\nG^w@\u0012\u0010\u0006\u0015mdrS\rE\u0015\",n\u0001\rOD\raƎF~dzJ\u00181@~QX:\u001a\u0000``\u000eL\u0012\u0018fH_\u0002NXq\u00113\u0006r\r(pBD\u0014Haf3!E\u0004Ts\u001a\u0015\u001fdz)\u0011D\u0002N\t\u0019n<I$x)7uY6@K~c\u001d^DGxf@V9w\u0006=:^a\\K?H<y*=Fg/T\u0005{\u0012:X({.R)Vz4,\u0002\u0018\u0004\u001e;B{Q]\u0017\u0019!<ٳ5,Ж\u000f1܏QzE@6Y(Ln{\u001b,,x\u0006YO\u0007\u000f~L\n5;H\u000f##A+h\u0005ox?@d\b\u0015A\u000b(kKO7R$b\u0012\n2bV\u000f\u0019\u0006\u0003C1D\u001e,j\u001cw^oJ\\:\u0016.UQ9L8#&]\u000bT\u0007j\"13\u0013E\u0001\u0003)9!\bjί3Q7lK\u0015[S\u0011J\u0002\u0014D-+w\u0000;\u0000C%lropČ)jJU\u001dy`􊭩w1\\GJ\u0010\tpN|Nx\u000b\\&wacFOPG$\u001cHT\f\n\u0006_aYT\\w4n\t\u0002\u001c>p\\0mfwֲ̽Mc֧\ra5:H\u001eB2WvH\u0006Z\u001fHR'lJ\u0016S9Wf rMt\u001f0dN.\fxg*\u001d9\u001eo\u0001\u0007\tB6Ʀ;\u0005$\u0014C\u0001ucﻩY:\\\u0019AF\b2NS(t+ TmT*\ni=pj#q\t`9\u0017ѿhQC\u001b\u0003\u0017\u0002h-v\u0002\u001f\b\u0007+W,s\"\\ψO\bs\"J\u000eckC|\u0013)X\u0001\u001bE\u0000s\u0019\u000201\u0007ϖ\f\u0007\u0005Jx(Yz\\'\u0015ߗ|{\u000bÔܶ_/:-`ܒ6(A \u0000V\u0018\u00191K\u0016jpp\b>a]u&>S?4\u0012w괳\u0010\u0010 c\u001aq͠\u000f\u0012\u000b]Fw\u0019<oz̐k\u0018Z=>؁\u0014\u000f\n\buِZJA/:\u001e[l</\u0007:<$JE\u0016m\u0007~hQJo0sAw\u0002\u0003\u0013\u0001\u001b-GYEW]m\u001c\u0000\u000e\u0017=&\u0015uCgw<bɊj:o\u001fc+\u001a²\u0015@\u0012G}s\u000e\u0017u-<8|\u001f\u0006/L\u000f*՝䉳@9z3|c\u000bj\u0015\u0002\u0012|KIx/k̎b9e\" \u0012Q^W\u0000:ҟ@DEi\u0005\u0016>;\u0006n\u0011h\u0010K#(/XLmʔ'N_3}\u000f\u0012,@C)[C$\u00056e\u0016ߩ\u0003Ï\u0012=*bȈ2*\u0002\r2\u0000`̤z\u001d\"0t\n+:N\u001e\u001bB(\u000f\u0004'؝bY3+f\u0016\u00180'aD%\u0007->S\u0011\u001bProfV\u000f\u0006iAߊ}W\u0003v0Lb\u001a\u0015܊\u0002t\u0018\u001aY\f\f\u0004xW\u001a\u0002L\u0010ݬ\u0010\"Жw\u001dc61񚻲i\"nN?:`\t7hDLk-kj\u001a:%\u0019\u0013O\u0017)p3tV#HM-q3/F(%iE\u0016ח\"\u001ds+i؂T\r*ڔɻ&.GN&N\b)@\u0011$\r\u000e~\u001e5Hxp\u0016U^`NF'@\u0015Plo\u0015dLh[1X)x]kT>\u0002p/\u0004{oO+1vg\u0017gSY'\u0006ؓ\u000bHH*'\u0012D\u001cZ^\u0018\u001e\u0012-bLF@,4\u0018r>*C\u0017$\u00038Օ\u000fB+\u001e\u0007\u0002{\"'ܕ$<j*H\u000f@XW,ԸQȊ_G,\u0015d\u0013i+=\u000fM\u001d\u0011A\u00153&j?\u0013\b&P_@bsTἔ\u0004\r\\.،'\u0014\fp^{\t\r=JB+5\t*\u001f\u0007\u000347=5\u0013SM}p2\n%\u001bT=\u001dX\u0011\br:LFB\nm<\u000e0de\u0014\u000e>\\Q[BƗS\nJo|i\u0004\u000bѱ#{Exs9c-!F\u00043<}O`\u0002?UұV\u0017X\u0003{רL;ʙ\u001e4b6\"\u001b9Flw}\u001eK>̭@[{iMw=S_\u0014M\u0013ב\u001e&Yۑ\u001e_~W\u0014Z\u000bdsnvԄ%\u0010J\u0015`㧔O\u0011h:\u0015\u0003/\u0016b1z4\u0015\u0002>;O@w`.b%\bR/GP\u000ev47:=y\u0016Ⲳ.\u0010ʎ\u000esI;\u0017\u0004QȰr|+O\u0004`s\"4E8>[hQx)^\u000bP~7an\"\u001c%(\u0015nPn_K{+p\u001d\u0011`\tޕ\u00047K0286J)T*!!9\u0002!oCD&e{QN\u0007\u0002=\u0018O;&5\u0006X`P湾>\u000b|\n@Π)޿B]\u0015\u0000\u001c-v\u001euۉOE\u0011\u0001ć(v\u0000[xO\u0005aS~1Xp\u00155\u0005\u0011s\u00130\u001bj\u001du\u001c\u001b\rDUf˘(\u00008W;b<q69R\u0010\u0007\u0011A錰'8;}K,'&\u0003[_\u0006\u0014j\u0010BП\u001fu\u0000(4_aϨv\u0014o_}\u001cʡ!R&,zUqr'f̽e;M\u0019ua\u001f3{_\u0017}\u0012\u000e\u001dCOOgT\u0003*\u001a\u001d\u0017v0`{\u0019AX\u0013a\u0017^e\u001fk35O7Gd֡\u000bJ󫀟\f\n\u0017\u001eA\u0019\u0018;ą\n\u001f\\p^\u0000u\bX\u0003(|0UÚ\u0002v\ti\u001b?\u0001\u0014\u0017@HK\u0016'\u0002\u0014\u0019Ux^u[\u00049(wg\u00106y'2v\u0010A\u000bPn&.+\u000e_~v\u001fé`A%\u0019ZD\u0019VU\u0003*lD^\u0016\u0014apr'a@\u0014\u0012#\n@ؓd(JU׈<\u0017\u000efߋ*ھ \b\u001bS'P\u0002\"^$S\u0016UBHY_7\u001a@.\u000e\u0003|IqtZpQ\u0004<z094삗\b^㩢}`.Uz+\u0015]}LƤ\\z fΤ\u00079_g=ț=+6Ջl@J\u0010\u0013rW񒢐tpt8t0$[CHuy!\u0005=Zo\\\u00190\u001a\u0012\u0000Fڢ\u0014\u001b+`2\u000bzPY z\u00062s|wi\u00079tb8*)Sg+-\u0011\u0010(d4@ebѰ¾gYCӡ8Nao\u001bLV\"\u001aw:\u0011\u0011J\"\u0002\u001f9zs\u001f\u0011߲\u000eb\u0003sp\u0014Lb\u0018\u0011|\u001a786\u00146k5\u0011E^T \u001aJ\u000f\u0013z\u0019\u0015F)r\u001bFKr>\u0015\u0017-Pa\u0015\u0001\u0012\u00124]\u0011\u0015bW)T\u0002Ui\u001d\\A\u0007\u0005\bq0M\u0013\"dI\u0018\u000e<NTQfhD@=2\u0016qvNЈ \u0010T5\r(bʤ3\u001cd\u001d\u0018\u0016\u0001*ڿ<\u0005dt_jW\u0012_Blf\u001f\u0011Ja\"\u0011E3\u0014\u0000p\\CŁe4:`!gư$Cet8\u0006\u0018K)Dأ0\\GӞ\b7uvrh1tGHS׋]\u000582\u000bP8\r?ڱT(J\u0014Dn\b\tkxz\u001d)\u001dt\u0001Z!Fdµb<;\u000fzt*uA\u0018ۼɫ\f\u000bNd\u0002wEM\u0019t\u0011;[]Υ89vzp|pY\u0000Ң7G\u001a\t0AŪ\u000b\u0015)\fgKΤe9\u0000\u0016wg\u0000\u0012U\u001bm(]\u0004_$\u0000\u0013ek|G_\u001f\u0004\u0014qn\"H}\u000fb1TlZtF\u0019\u000b\u001c*-\u0013.)\u0013(\u001e2\u0013ٔDږ@Ң\f\u0006la~J\u001aS\r)ߑUTM\u0007(F\u000b-|&\nܯǉ\";@\u0001\raÈ@y<w{g-Q(^2YfXg28\u0010=W\u001e#E?\"\u000e%uxw{\u00149q>4͟C\u0014]\\\u00014\u00184Qjo\u0001Y^l~\u0018/\u0015+u0\u0003\u0000}t~~}FEˈ剅26\u0004\u0001'RR^4@^J\u00145Q\ṱGe\u001dcp\u001a\u000b0\u000fχ#I]\u001cW\\=f{3'<*8\u0000P&:eT:j\u000f\u0007XuZ{$4^B;*H\u000f:˞\u0013+\u00129NT]\n#)\fⴏ1pVU\u0010GY1fC\u0013ń6{Ndm@G\u0011gS_X\u0016\n\u0011ѣ\u0006<OUt}|9\u0019U\u001d&\u0014C'&5nX\u0003:2\u001fϖ\bN8ēK=PxYP!\u000bt~!\u000e\u001cZN 3\u0002gׁY+\t\u001b̤ϲfa\u0004Yrb4DVP-\\^\u0003\u000e\u001f}4P[wr\u000bӥLQT{\u0004\u0001>#RW]O\u000f\u0004Q\u0005Qny95u:RʦON3\u00018uL_!W\u001fDiD][Iu\nJ\u000fR\b\\\u0000ק\u0011s?\u0010٤)\u0001B\u0003Od;}Qw\u001765ihh0gU\u0007i%zTĕp.̍\u0019\rREN\u0019-8\u0015ʟ\u000bY\f>C9\u0003\u0002\u0000l#+$)4#\u001alV#\t\t\u0011DY}#HI\bnM/y`!\u0015u\u00012d\u0007kD\u0018YCY $\u0001x Au\u0004L]Ka|\u001c@\"wh\u0017V#L+$!^\u001d\u0019I9Ybf\u0003w2`\u001bt9\u0015?Bt\u00171ʓP܃1\"\u0010%\u0006\u0004\u001bl\u000f\u001eJń6H\u001c~;<m#\u000b*^\u0013ChPUyT:YU,\u0017L3{ag=\n'\b(藬`\u0012\u0017\u001d\u0011\\\u0013\u0013q\u001d\u0007wȿ_v\u000e4)!\u0018\u0010+Q*\u0006\u0018h\\Dw? ;2˨\u0003\u001b<\u0013Ɲ(,qU3\u0006\u000f\u001c\u001f\"̘\u0015\u0016_Fi\u0019b\u0019\"U\u001dǍ\u00024ju!\u0001b4+8\f>\"g)\u0012\u001a=q)twqŕ\u0003\"CO@z?{\u001a\u0006)S^j֐\rx{O1ffY<;eE7=R\u0016IDWT\u001fEA\u000fƕ\u001cD$D\u0011\u0011?\"Fb\"\u0002\u00065\u0011yf^?9Fҧ\u001a\u0019į'\u0003Y8u\u001d\u0016\t\u001d=|iuu]gD~\u00112&\u001cf'L\u0004YH%nT\"2w8\u0015\n0\u000f\u0001-(]114G\u0010\u0002])\u000f\u0006B\nQݚ\\\fW)i\b\u001a\u0005c(:\u0001iψ/q6Ad\fqJ|'\u0019D\u0003\\?zICԦ\u001a챽\u001eei~\u001e\rl,XΐF\u0003ʂg5wA&SNL\u000e\b1[\u000f}Di*\u000bD1]\u001e\u001d=[5r>fA\u001ajvȝA\n\u0001!8Ϋ\tyG\u000f\u0005ls'z1#\u000fBm?Ծ\"DEPE)#\u0001b\u0005c\"p>hw\u0014^\u0017}km?j\u0003\roo_'Ш\u0011T\u0013\u0012X\u001e.ÅxG\fc!\u00157\u0017OJ 1\u0013\u0011R\n5JF(4\u0001\\KNH4̋T\rqO`,ʈv\"~k\u000e#J\u0006\u0013f]\u0015V&\fZ->#j а_gsV\u001a(\b?\u000e\u0001=H\u001e\f#\b+\u0015\u000bK\u00044!\u0017\\|\n\u0011G\u000fGܜ\u0011;bb\u0005j\u0004\"[iF_!%I:St0!g\u001bWU\u001f+\u0011B\u0017U:\rPw-)^7ZhQ<\u0006\u0003g\u0018<&q\u001cQ\u0018Fc\u0019}\u0012\u00044>\"D\u0019z\u000b(\u0015Fg\u0014F\u0019\bt\u0007<`.O띎\u000fj\u001am`h\t}u\u0004)\u0001gѳȘ\u0011 ƳVΤ䦿-F7%v\u0014!\u000f\u0010\u001e\u00168\u0001\u000fC⦶x|x\"\u0013s3޹\u0016&s qw\f(c\u0011Cq\u001eu)7\u001c㓻;Je\u0001xPgEj\u0000ؐWylLƙ9\u0000K\u000e\u0016\u0010r\u0005j\u000bT\\å{)O>~\u00038\u0000\u00198DB($ػ>a\u0019}|ϧÔ\u0018.EM+Bne\u001d`*֥6;ۭ\r*רJE*\u001bF2q\u000bN:\u0011u\b\u0013AfG'ysaI]^p\u0013\r\u0002$t\rӵHK\u0000Rt\u001f\\\u0010PzUy4*\u0007\u000euiT[\u0001h\u0019r*\u0016gmJ;\u0007xk\u000bu;k͘N{{?1-\u000bg\u0014\b\u001c|pb(˭~ 2&j!\nPS\u0004z=]g<*5#\\6.\f^q\t4@\u001fWH\u000f6c\u000fc\ng\u0010Le=YX#k \u0005y ZM\u0003L3\u001f]\u0000\u0015\u0005&\u0015<}\u0011aS5R,\u001c\u0012^\u0000T\u001d>(()0}F``\u0016\u00126ƨ(J3\u000e\"\u0007( 2x\u0006u \u001en(&:\u0003Kl\u0007w(PsAҎC^)\u0016i\u0017\u0019Ȩ*i\u0013M\u001d\u0006Rk`FW 32.yP5&\u0010\r\u001b\u0003^ػ\u0012a\u001b\b\u001aHDFRcC\u001c~Edo\"зK:] a4L:\b\ns\f\u001e1\"J%F¦zMв1LA\u0006\u001f\u0002\u0014M6.\u0018>\u0011M\u0003H(\u001b\\j3\u0003חE*;jNL\u0014>\"\u0014z,V\u0002Jܷd`vX\\\u000b\u0018\u001d{&\u001b)̥e>ZGNPU@:\\Վ\b{W\u000b<ɕ fU_?T}k\u0011:\u0007E8)Exh\u0010(\r\u001dm%\b\u0017V;᜽\u0003ڏw-Ȅ$\u0002C{dg~\r￧aj\u0002ڢ7\u0011\u000eC\u0006\u001b\u001f\u0011z<\u0017B1\u0013Ӥߌ\fb΂~%%)`\u001de~\u0003յ\u0001e\u0013(\u0011W\"|Y|R\"ԟ\u0011IH]+CfTSÃǠ\u0016ۅ\u0016\u0018\u0006`\u0006\u00007T\u0010;\u0011\u0017Fʋ)\u000fݺ\u001f~\u001e*$ >H\r\u0005pozSމ\u0010\u0003$\u000e\u001d~T\u0006E/8}8p\u0015K^\u0004@MD>\f\u001bo@\u0007/W݀~\u0007e\r\u0019/\u0006\u0000n\u00060`8\u0013\\{\u0003\u0011}DH\u0001FC\fa\u0018\u00189jI\u0017\u0002F\u0014}O\u000b\u0019\bڙvM(\b$&CBӀwp˅߷pdOJ%*e\u0011GTT:#y\u0003]CC\u000f\u0018Rs\u0015\u0005aRlx\u000b\u001fEʶ`{~6?\"\u001d\u0007#:/.9Q6nҀLe\u001dE\u001bE\u0005職N\u000e>i\n4Sc\tݫ}E%9)\u0004Iy?gQX\u000f\u000b\b##I\n\u001fou`ܣ[I\u001bU̞&@b\u0015Na,*w\u0000e\u001c\"po)g\u0003f\u0002\u001d\u000eO$hÐ}\u0005i\u0016`~\u0010U8\u001f\u0014\u0019 79K`@>\u0014KrP\f\u0017[r\fQ;Z\u0003;ٻgD\u001e\u0017,\u0019T>\u0014O\u0013By\u0001=Khײ^QoQ\u001f*\f;B\u0016\u0014^y5\fZ%0\u0014C\u0011ʩavhak\u0014$hY\u0002\u0002d\u0003[swf-z$t.!%ք\u001c\u0003V\u0003\u0007\nRO5~ATy\"\u00149\u0006_Q\u001cfX\u0003\u0010ޝdlFs\u0004Ko\u0004D0_i%957-\u0006\u0001*\"_\u0007<~uNh\u001eǘ>>|\u000ff+RGOܭ-6} B^ψ\u000eG!d>\nW\u0015Q\u0007 ك\u001aR@K{r:\u0001b\u001dn(?\f\u0019\u001aN\na2,\u000f\u0016-\u0005sZ\u000fg?YE\u0001\u000fP7\u0004'Eԫ:g:(\u0014\u0019\u001a@L\u001cBR̪\u0018^iY!bsY&}XA\u001a\u0005㌣$6\u000f\u0016dgD}\t\u0013#Dr\u0019\u000b\u001cnu8AIn#n~'̵_2J,/|\u001fPP\u0000Sf\u0003Q#\u0015\u0001g\u000fFO\u0017,\"R<\ni\f_FmC\u001eCe\u00115ǁke\u0015Rq\u000b\u0005IkE~\u0014v\u0012cm\u001e~\u0005XtGCbGҝ\bL]/n\u000bH\u0017=-j\u001e\u0001XU^H8-\u0019Mu\u001cxKP'\n%{DԒ!`2yrJX@0NW(PI,kߗ\u0003C}%/jm=a>7:Do<zLc]j`w:C\u001b&\u0000\u000b%]9?Fb\u0015\u00029Nqy\tʳZ܈E\u001cl\n^J$VǈL\u001ej\u001co)\u0011#ɩ`;\u0011ω?}#M{Ti\u0018\bL\u000byǏ֊%@j3\u0005S((.\bX\u0018X\u0018W*^46Z\rp\u0001[׃F\b,iz\u000eϡ#߈<?zKR_/Zì\u000e\u000f/\u0014VO\u0000w\u0014V\rKI.uɅU2\u0002ɵ׷|\u0004H'W\u001d7\u0002\u0016b#^\\R\u000b>DշaXf=\u0006\nb#\u0010\u001atV\b\u0003\t>~\u001b@y0հegt\\6P\u001e\u0014\u0015j\bŏA[\u0003\u0012wGs=\u000f3\u0012x\u0002hDh&vO\u0006E_y#1~Wo_>Y\u001f\u001fO?\u001fϿ\u001f?➯+\u0013\u0003\u001d\u0007Y\u000b/)Ӽ,3\u0005e9\f@ĆoEaѫi,S\fNl\u0003}\u00170v\u0019\u0003\u0017ڐ\u0003Ib\u0000]\u0000\u0016\"=xc3\u000f'Jc\u0017|F\u0001\b\u0018v@\u001e<\u0014\u001d\u001ehh9\u000e1IGYWDu헏G\u00184GH\n\u001b^(\u000e\u0002\b\u0010/\u001e0c dh\u0019\\g\u0000K\u0019\u001dwZ\u0014^Oi\u0000g\u0004Dȿ1\fh\u001e\u001d,/b:bFmڰm\u001f_}|\u001255\u0012\r\u001b>]+=X1<\u0006i\u000e\u001b\u0017\bG_\u001b*Άj\b>lyz|bEl\u0011\u0015\u0019i\bL\u0011F0c\u0019h@\rXC\u0007l\u000fZqFk\f7UAjf\u0000J\u0012M͂Z\u001eI}@LtfÖ\n\\\ny&}S\u00111QKJe\u0010s\\o\u0017F7E\u001c&^N\u0003!rCA bQ\u001e+'*J0Rwɔ[\r\u0003I\u00007:W2l-\u00152,ɦ`#\u0005P\u0010(\"RlK5\n\u000f%5RZ<zVR1Y_o2`.F/AM?~|Gk;B\u001c#jt\u0011\r\u0006cHn}b\u0007 V\u00180b\bG'\u001a\u0006\u0010\\\u0013<I0mXh|QS=_*\u001cY*1p\u000f\\Ws\u0017Qk_EU9L\u0013>]@x)]\u0005\u0003g0!\u0012Qt>d?N$En\f'K+mfZHt{PQ`C;GP\u0011@ul\u0018+abX@<I!~}\tȘ,r!)%2uƮȏZkb0>\u0003Y4olMo\u0001\u001e}8Kw{߮s<\r\u0013\ny?D~D\u001c.1QO\u0013\u001b\u0002i|\u000f\u0019@z\u0019/s\u00131`\u0007O\u001bQ\u0017w\u001a!bQ\u0018Rν݀\u0015\u0010N.vpzܫN9,D\u0003\u0012Qqw\u001f ?+~eL@\b\n ŵ<b4r2(~\u001a2ϝ_H\u0012ARO\u0004zQ(94;\u0002Gs&Z0 2GwnN3u\u001556\u0010\u001a\rHA!/Ԇ(\u0002Z??pq\u0016{EzcXhy\u001e3-\u0019K%fRLz̥e2Hx\u0012y\u0019%D,)\u0016KT'H3$O\u0014<\t{s\u0005e:D%vl2\u00070\t3GA/>c\n~\u0006&FYXX`\u001d\u001aQ}si~d)\u001b\u0007a=\u0001;s{WC\u0017U[\u0011\b̀pmǻ1b}Ŏ\u0001u\u0016ɉ\u0013x#@\r\u0010\u0001R2\u0007喃c޻%jPvD_<wL\u0012Hd(nE{\b3\u0019\u0013\u0000\u0014vfwM0{qk6+\u0003\u0011$\u0002\u000f\u0004\n\u0012\fj\u0014 z;BUd\u0017ο9Y\u00112\u00048C\u001e<~\u001dq k\f<\bv7\u0014j\u0014MүЌ&k\u0005Mw\u0014sԳ\u0004p,Ȁ\b\u0001=\nD<(\u0001\u0014+\\\u000f82ňi~@>W\u0019`\u001fje^)c>4D!\"ຒ=8h&|\u000e!٫2H110\u0001<=\u0006INB\u0014ZDA;1J\u0011\u0015)\u0006݃ц8։ .ؚL``5F3gɊ*UBK~/\u0000$0ߏhP\\]\u001d\u000f\u001d&\u0000\u001c\u0019J\u0004H\u000eưk0ŦZ\u000e3R\u0006+\u000fLR\u0013pЃ~=\"\r%\u0017ˣF\u000fg+\u0001n@5sH\u00040_L\u0000\u0007\u0002=\u0011zڣT\u001b?\u001dfl\"f`:Rb| 1D\u001f\r\nN,,(Qv\u001c-3\u0000\u0002C\u000bms\u0004\u0010#S`}$rp[c\u0015\u0006\n͸2\\zڕc)@\u0001g\u0004v?W@R3}D\u0003xل,\u0014\u0017>A*u#)f=}w'\u0013ٰ\u001f%hd&\u0001kp\u0011\u00011>?$z\u001fP(8cp\u0006\u0014\u0006\u0001δ7ӨnzO\u0010\u0002\u0006OtfD\fe=\u0006\u0014D3>OX|^\u0006\u0001\u0019\n\u001fy;든NB\u0016\u0011Uɧ\u0013(\u001a,BF\u0006XJ\u001by\u0015%ց\bL\u001e\u0003\rM>h\u0018\u000fz\u00144L˗[䐯|iA4_\u0000gD\u0016\u001e.pR\u0005}\u001e*|۫\u0010>\bpI#\u0003 !\nz\u001eþ44&~RP>CbFCp\u0014v\u001cEw\rs4p\u0014yԖ\u0016rf}1؏m=\nmv\u001c/~xN.C\u00138Q`<\u000e%\u001f\u0019\u000bC\u0013hd^O\r\u0010}4K\u0019!o~ഖW\u001aɦ\u0019ycܲ\u000b\u0003mL\u0014ߦ)06\u0000\\n~5\"FwYg\"Sgg.k\u0000A\u0003=#)\u0006մ0\t\u0012J^C8f\u001a/3HΑL^t;za.F\"\u0004p;⯡gs˥\b\u0010.\u001f*}]\tΙP9g{^\u0018ѱaaX\u001az~L`<\u0003\u0016<5.;e+\u001a\u0007I@[\u0004P٩)X\u0012F'?3ʕ\u000fp\u00015\r\u001eu/}\u001c\u001fSx{W.\\\u0013LfrL/1Na\u000bSw3O\n\u0016\"n}gza\u0013JkJ\u0014I\u0018٣&ݳl\u0017\u0017\u0005܋1K\u0001d\u0004\\kb̅qK|\u0012\u0003\u0001mx:]\u001c\fs\u0007::>-\u0000J\u0001\\u\u0003vB_\bBb?i]H=;\"p\u001f7U)\u0007Uu>0;7*9OO5*\u0003ȉ\u001e-#=\u00146g\u0012\u0015bG<uprFS2\u0011cJf\u001fW\u001d\u0007&\u0006y6\u000f_C5e}=d\u0007K\u000bG^0K\u0001|*\u0018{Hd5v:\u0014?D\u0000n\u000f{,ZI`\u0011\tak1hБ\u0017\nrFxqL|X\u00158\u000e}+(7\u0018zQ\u0000y\u0019`\u0013GQ\n\u0003eZv$\u001c:dd4\u001e4\";jVK;煼m\u001eaV-\u0010:`\u001f}ϣ\u001b#)\u0006|G\u000f_\u0004)̤a,O\tDR`\\R\u0011ʷ6c>\u0002ox\u001f<\n}Ʉ\u001eX#vhSG-ߦ\"\fNfn+Q\u0003]bmϊJuu6?#gbwp\u0019\nzW=㏁>0^\u001f3Gݟ\u001f8\u0006\u0002\u0016\u001f\u001cQǻk0Vf[(v#\u001ck4+;\u0002\u0015I\">xD.PO\u00038aD\u0018w*r&T45_)IT\u0016TNTv\u0002rR\u0019raLdGELϟKaܽRLW)طF\u0001}?\f\u000e\u0003>2t৾EI?NN3(d\u001dұy\u0007}C!D,\u0011sNb<o9\u001c%>WS\u0019C'Jc<\u0014n\u000b3t\u000b-{\u00182g\u0004\u0019~Qh튷Osj\u001fm&Llu\u0015~}m\u0007gӟ`\u0003TC៩,0 \u0002o\u001b{T9NKhW|<u\u0013\u0017\u0012\u001f$\u0010ow\u0007\u001e\u001fo\u0011SR |\u001eG3!kzdd|U̯ ʛD4J3 _X\u0005c.\bc\u001f[\u0006\u0013ĳ\u0011\u0016z0s\fmB\u0005\u001c\u000f2v%\u00015hNcY9\u000fl\u0013(\u001eC8 z{\u0003%xs\u001cZڻ\u001c&{3ı\u0019G콚,\n87m΁~|lJ3\u0015ENqL)\u001e.y\fk\th6޿Կ\f\u001aQ(\u0018^IwC?\u0011~\u000f#E\u001aU\u0019HN$\u001fT\u001601.ʉ\u00120=̌绲)0~b\u0006?h\u0003\u0001\u00054\u001f<d)aTӭkW|M\u0006.\u000fKY\u000f\u0007\\{\u001e܋\u0011\u0002#h/\t8r{\u0002Eu4v\u0014\u000b_\u001fm-6\"\f\u0012aN\bj'*<Ǡ\u001a'ˉ\u001f\u000bc\"Rwb$s\u001c ?zt\u001d\u0013\u001bqᯜdQ(M/j\u001af\u001f*DQ9t[2$WW\u0017՝<ѳ2\u0011\u0014M?Wa3u݄ySE֎9rw\u001e\u0013\u0005tc?d'ֶ83Y*㧈6 dW`BroGgZ^\u0018뮻\u0000r\u001dCu\u0010֎FћW;k\u0010n!y\n\u000ft\u001c\"ҏb\u001aDIc\u0011L6YN#ZZ8F\u0017<J}e:\rKj\u0013^@@!:-\u00166w}}zoQ~}H\u0017\"T? ]\u0011PfM\"YB.C->\u000f/b\u001e\u0016\u0010\r\u0006S?Zs\"F\".H5DPhgRIE07[K\n;7C?E߱)qQ2g\u0002ݤ(\u0004E\\񁫲R/݁\u0011\u0001\u0013\u000b\nW\u001cֲҧ\u0006A\u0018VQ\u0012E%SEG1J\fyze\"Hb\u000b\u0006\u0015>\tC\u001bVK(:\\\u0016v ^\u0006\u0005N\u0007~F`\f\u0004AL_Vot\u0016 ٵw$Xs|^9u\u0012\u0006h<8zr/\u00013\u0001RB,3ڱ\u0005D\"S\rʮ!\t\u001d:\ntnevdoҪ*\u0003!=**\\p\u001a@}8a\u001d\u001dq\u001f\u0011wH\u001d\u000b\u0006\n\u0006\u0000\u001c\u000fe\n\u001cs`U\u0018od\u0018{U*]\u0002\"h\u0007d\nEb;ĝ\u0018WD~\"X;`:;$\u0015uIj\"(\u0011\u0019Fm\u00171.*{]J^\u0011.-#\t\u001f6r\f``C'\ni\nBx\u001e\u0005{\u0011hf?>\u0016ͩ\u001c@G'X\bo(1\u0010\u001a&MG\rg\r\u000e1\u001d$q\f^^E\bT\f&\n1Q\u001a$\u0014O23MU{=\u0018\u001e\u0019GcLy;3O^5AyhfgΉr\"OOU^#-,{Fz\u0004&m\u000f\u0015\nn\b\u001c\u001a1_]?E,к\u001a4\u000fR|O|yh4d-<5<X\u0017A+ζ\u0001ȍMC=\"\rhc>b\u0005]}b\u0017v4?#C\u0001қ>\u000bݏ;\u0000\u0015=:\u0005B\u0005\tq\u0012\u00108膬\u0002\"_\n=$q0\t*@pMCOz\u0014A+-\u0019w5.%n\tM-9GλgDd\b^\u0002\u000eȒ(g9@~\u0010mD]\u0006\b u]\b>WA-<\u0011]\u0011Aw\t\u0016$8@k<\u0006=\"Eo3\u0001\u0014l0:wc\u0000]\u0016\u0007\tP\u0015u\u001e\u001b}tht\u0013*P<z\u0001\u000bqO\u000e4N\u001ekq\u0006W\f\u001b /\"|>ts@o\\Qc`\u0010 [\u0011\u0018y\u0004\n=\u0003L\u0005sWy\u0014p8\u0015Yuvz~FA9ʞy\u001cW\u0001\u0001^M\"`X\u0005\u0004$gS\u0000Q\u0001pa\u0015hp> \u0001^o\u0002F)B~\u0014vOg\u0014>A\u0007\u0007F\u001axV[\f\u0001PqօĒ\"3D'\\\u0001N\u001b?|;DN\u0000T\u001c5eD\u0000xounGx\u001f:;/ӂ\u00126\u0017S@\u001c\u00157\u0003,<\u0011\u000eN8\u0017&\u0007ɌAʨd\u0012Sb\u0007c\u0018\u0010P<w\u000eFQ88bht+++YXyg̊\u0016;\tJ\u00122w}5\u001dxҏB%\u0014K\u0016\bT\u0017g5X^4zA!\r~@y}]V~7#kebٻQ9:jrybR:73x\u001a5)m}ز\b:DH\u0017\u001a0|9Cv\u001b0\u0011u?;\u001e+\u0019\u0007\b=9\u0017̶\u0005\u0000Oc;L\u0014K˘\u0004\u0014\u0003t̗c\u0003L\u0018>\u001c\u0013A^U-\u0001\u0017@%|[@M8BX\u001fAj\u0014d41ש!\nqJ'\u000b@H\u0002GX9<,ϏǙa*#%H~|+)\u0000L>^BV[icL\u0005įG/xw\u001db|=%q2ED4XfYO،ӜȴNC6\u0003n\u0002W2\u000e\u001fgX:QuoS(LSz\u0007\u000e\u00022 \u0010uiMh}n7p\f.S\u0015\u0018yoе^(H6Kp\ft\u000b\u000719T+W=\nf;\u0001Uw7\u0000\u001f/fW\u001fsw=\u0000I\u0000`v.Y֨\u0013`[\u0010B\u0016Σ\u0001QȃS\u000f:(v~\\`~6D$\u00109\u0000ss&\u000e\u0006˶\u00192jȪ޴Ѓ-\bUd<6\bMٿ!Պ\"\u0019\n~)\u0014/\u0012PO\u001dV\u001fw\naVd\u000e\u001ftr\u0003m$bo}7*pCRx.43\u000fd\u0000LJM\u000bN7\"zIVe;\u0017QDVI\u000eWC\t-;0`\u001a\u0018\u001aK\fE[\u000fǴmo\u000e\n@fcQ?\u0003oie\u000bBfR\u001a\u0004.>9\u001d*%ixH-?Fs9\u00022z]\u0018{\u0001O#1]ZM\u0015Z}\u0004_y)\u001dBB\t\u001e52<*`0\u0016\u0004\u0010\u0010S*Wiߞi6\rZ\u0017\u0016YRw1,\u0018k\rb\u0001]k\u0015HC\u0012r/d\rǟx gQ\u0010\u0019d\u0002\u000f\u00119X\u0017f\u0000L\u001c«!\u0011438\\؝\u0015Ĭ9ҍc\u0006wS\u001dCг\u0014.k-\u0014\u0004͵\\MB\u0010,DDeWT\\>9\u0010\f*\u0012IPQl̃1<s\u001cnA\u0016փ\u000e\"i\u000f\"\u0011{\u0015\r6+c\u0014^\u001f\f\f\r\u0015\u001e;\u0018 c\u001b\u0016Q.{*#Fi\u001apuc̴j)\nb\u001c\u0016:M4nj\u00110\u0019UP5.j;)8d\bh\u0019_K+\u0012$\u001e,U\u001d6\t&S+\u0015ku&\u0018XD7(U50\u001a\u0007\u0000gcױ\f(\u0002#~\u000f7q&:6Gy\u001bz\u0003/a?<S+;3F\new\u0018ǵ\u0019X\f\\`1ʷSN\u0003\u0000UC\u0012ǎ#c䑑AR\nD\u001f}sSF=/6zr_\u0014r\u0001\u001e/\r\u0006ls\u0001;W\u000e\f]\\*\b:\u0010\u0002\u0007(|B\u0007akt)J\u000bk0yU_sc: ߥF\"{ \u001e\u0010:F\u001e,\b0˂A2\u001e1J8L:[Kz4bY˄2 =ٴ]\u001b\u0007p̙,Jd.\u0016ZNGqr\u0005\u0004R!U\"r6\u0002\u0011\fѫ\u0006(`{lQ\f\u0012\u0010\u00062S`\u000en[Z,P\u0017\npO\u0001'7\u0013S\u0010\tXzdg*9(GT\u0007\u0006khأx$\u0007B/MpޒGӊXL݅fO0ľA7iF\u0015,QS2a\u0017C9\u0004\u0001}j\u0007l\u0004=`\u001eO7\u0016E(H@\u001cr)8~\u0001FDxr\u0011*1w3lȈ6\u0018!d\b\u001e\u0001)@\u0010ޥTn\u0006=b!ĩ 7ݨ@m\u0014zT+ս^b\u000fl\u001flm\u001cEkWS\u0001%hŰ2zЧd\u0004;{Gk\bF\u0002Eō\u001cOM-\\\u0005[g_gj\u0010\n:\u0013\u0005f\u000e;O\u0005@5peC\u001bF\u00147Hl\u0003`0\u0019t~It\u000e\u0002k\u00184uP\u0001\bV\u000f\u0005\r\u000b\\wt=\u0000>:o\u000e\fm@a\u000f@wLԂQ \"8=hȱ_)\f\\AFU^\u0018\u001ajwF\u00176\u001c#uQ`kqx\u0011\u0018`{tEh\u0015>\u0001O\u000f:7\u0011\u0010l\b}\u0013Ӯ\u0011+wY\"o\u0001~Ш@\\r/\u001d\u0005\u000f//`$ҳ犷AŻk\u0002$iwM\u0003dE>\u0006jM>RVRH*j\u0000@\u000f\u001fL=n&F30\u0002b_LތG':FWPEB\u0003pg\u0001˸O7v>pk+3l\"Lc:XZhf@$m?)\u00071b0|ޱq\u0010BkC`'/U\bzG\\Kd\b\u001a@Wn)KѼKW3)Dq{\t!A\u001d2Gs\\\u00136\u0012\u0001:\tFF4I2c\u000fH\u0001O\b-@\u0015\\\u0010m\"}\u001b\u0003\u000f/9\f\u001b\t\u0001bLɱ\b@\u001c$:%K!\u001aG]G\u0015\u0013\u0010}'*i:\u0000\b#\u0016wR(@*;\u0010@RZc\u000byEx\u001f.V%\u0017Fϛ~馜ϝsT\n\u0017Hn\"E\u0016kDL?\u0014j\u0004\u0015=\u0015lNb6\u0010h=\u0003\u0019ҏ2l\fIhO?\u0002g*\u0015aDZh\u001fџ'\u0015LD\u000bf\r{AkApm\u001coG\u0016[^W:Q\u0003\"H#\u0001\u0007C\u0013X-\u001aXG\b=L\u0017PE\u0012 Q\fe\"\tq\t!#D6DW\u0000TF%n@U-/9\u0018a\u0015\u0001%TH%v=\u0003Upl6\u0011-h!X<~5/\u0010if\u0003ښL$\nR?\u0005`{B\u0006m$\u0004.V⸦=Hj\u000e:=Bf\u0015=)l8*,\tm\u000f|[\n\u001cOuYFgO0J)\u000b\u00134\u001d1TT*B\u0000C\u000fV\u00119\u001fR\u0017\u001ak\u0014\u00157K6WMqTn=\u000e\u001e<\u001c\u0007\u0001<\u001d;\u001ew%H\u0007so-:V^u {6;t3@\u0016\u0019\fF6s\u0002\u0003>s:қ\u0010q0^\u0016q`G΢&\n\u0014$%\u0002$\u001d\u0016zH:yDƭE+:,&F5hw*\u001cSb\u0002PRORDj?\u0013\u0015\u0000\u001c2lC츈'\u0002.\rg\u0003F\u00126\f\u001b1<\nFH0\u001cz\u0001lI2Wp\u001b4\u001cQ\u000bJ\u0004Ց,\u001a\u0000h\u00161NTV\f\"\u0005\u0015\u000f}\u0012AGCm\u000eS.I. :6\b<\u001bưr\u0007గK\u000f\u000b(~\u0010\u0006v_g&(\n(\u0013-\u0013^N\u0016(\u0017\u001b3fn5֏W*C{'S}@Vlc8$\u0005wz\u001c3)ud3O1,!ޅ6q̦j\u0003\t_f\u0017ȋ}\fD0t~|9I#e\u0004\u0003\u000fCgn\bŧ\u00154\u001c,#\u0007ʌH#\u0004?ι#\u0003\b+\u0005i;9\u00006Ej5X8\\s\u001eww\u0012$<Ug\u001ew\"٥\u001brK^v⩹)/\rb(R\u0006O({\u0003j\u0011}W\nK0L7ÐϨkEa47/N\u0018\u0006+R1_w\u0011zN\u0007OIz\u0018tD|M\"5#rv\u0007l\u0004\u0014|\u0000}\u0018VB2\u001aW-\u0002q][\b+d˫OjS\u001d9{p#\u00079/;Ͳ\u0007-\u0003`l\u0016fwHMhJE#1oG\u001cr!b[9.\u0000D\u0012ɥ[\u001c{\u0011xRV\u0002dPn\u0017QT(0fhx;kY$J(f)JQ:jmWd$Cd<@ˬ\"\"x\u0016U>\u0007K\u0017'\u0019A#Z+izZ\u0013\u0003\u0007\u001cG6BwYLj׫\u0016\rK\u000f\u000fI!9H@eȅSM?]͛/\u001d\f\f4#\u001cA\u0005DOO(g~\r\u00195O4\u0007\u0004\u000752P#Mh:\u0014txK\u00199m\rkPi&Bm\u001d1􎨣5\t\bx>I3McT\u000er\u001e++bS\bu\"<]e\u001ano]: '%\u001c4\u0016I(\u0018\b#\u001aW\u00144\u0002]\u0010]\u0000*t\u001c\"%!ھ^SK(B%b\u001e=E\u001dVD\u001e\u0007ꁎ^\u001ail\u0006\u0007\u0004?6\ngP_}\u000e\u0015u-T\u0019T}f\\_#S#3_]'\rVx`\t[#1CŻTQr\u0011L`B\u0019\r,8]A\u000b,i8<\u0007\u000eAc\u0004~4\u001c\u0010펈~U\u001fۻS\u00123}Em$63+\u0003 H;t<\"\u0010GkS\u0011iQxuq%4;Q>>kbg\u001e;2Af#t\b\u001c\f :N\u00173;.L!g\u000fT\u0015oq;Z\u0005$皭j(uM\u001es$\u0006g\u0004\u000f\bC\u0016\fg\u001f\u0010B{-oD\u0000\u0003t\u0006a M7u:U`F\u0004t\u001f%hw\u0007ڤtǚ͏ cCz\u001co7\u000en'Ddq<1\u001a7\nFNnV\u0018QWzr4Z\fp\u0005\u000beA9QJ1I{I8w\u0019iV9x\u001ar|bPB#K\u000e\u001dʺ\u000fϕ$Rt:TNL\"}\tP|\u0019;~*i\rN\u0012\u0012\u0004=gK\u000e1BdF9D$펾:\u001eIYO=o4\u0007ً/<:`֮u\u0015n\b\u0003p]H \u00153Sj;u9EީD_>G*\n\u0000_:\u0010VG?^ן\u0019;^\u001fG\u0003_U7gA)ٮȂ3lנ_e\r\u0000\u001e]\u001a\u0000!l[b/_]x\f6ޕ\u0005g\u0016_&V;\b}^\u0004yL\u0011\u0018uə\u001btzTZ̙_zM\u0013ۑt\u001e\u0015\u0011\u001147J=w*VbxzxӐBǮH\u001a\u0002;\u0019(Zc\r[\u0010\u001fYˌ\u0011i~CWN\u001d-\fڴrR\b\u00029\u0011Ѱ\u0000;33[\u0012Zq+_UlRDgA\u000e(z$Y\u000f_RoTt_,\u0004<&M(Ɍ\u001eUTFMQ괋\u0006\u0003mj$Y\fTW~{=>(P}`5Д\tzX휥)t5>\u0011ғ)@;Kϲ9\u001a0p$\u0005\u000e0\"x齣h@IhC\u001f7\\X!i5a)gd^;G\u0002^a0\u000bR.4q{רO\"b͆\u0014R\u0007U\"Ly&2_'z\"\u0003\u0017\b+S\u0017^TD$K'p:7D=ix-W4]Ɇ\u001e͠\u0017:DD\u0002_$K㞝D~Bu\u0019%@oNΎ\fdS\b鞸o3S*v\u0003ft/ BR\u000f.X+>YGU\u000e\u0004\ni\u0012yX\u0012Ej\tjT^VwЏp\u0004WAUI~_-0C\u0006|\u0013/\u0017ВCKMP:k\u0012gq3\bу\f:\u0003\u001cs \u0018TC\u0019\u001eY}-Po55\u0004_l\u0006Ad'\nFܱbjF\u001c˂\u0012OptU\u0001l\u001c*IB4.j\u001ayEz\u001c>ͬhj234]\taISAzt\u000b;\u000ew3\u0004(ߠnO\u001d\n<M!aTO۰\u0005\u0016<L%\u0013r)hvVi%G\u0001xF\u0011[|iY\u0011}\u0010\u001b-C/(6F\u0004z\u0015nu\u0019Q@{U\"SD\"<N@d\nܢX,Gjౚr-\u0011P6\u0001\u0002m3W.\rL2eM-9\u0000r\u001eo\u0005B4|hq(ӿ%̹8/=\u00135\u0004õ/'\u0010$h*Z\u001d{Si\u0005]\bcF)i@Fz&F\u0000joCޝT;\u00026[\"\u0006$us\u0004D'#\u001b@\tlPz\u0006%\u0004\u000f\u0017\u001b#\r(v!(B+m粌MR\nV\u000fM%kz%QUIӃ\u0016U2w\u001axw1PL\u001cGb:(\u0003\u0004\u0019|\u0003S\u0016$8߁\u0017P2%بfU<\u000fDƢ\n\ba1o\r~*\u0007ћ2WP\u0012,a4\u0003%1\u0006{eYS4S\tl>Lg\u0017Y%W\u0007{:;ľL\n@\u0017v]}EB\u000f\u000f;{ũ'ba[٫#~q\u0005\u0003Óc\u0001\u0019󞈶ة\u0013ŭ\t1 *st@\u0014g\u0006?\u001a\"\u001c\u001bY`r\u001f/\u0007\u0002*0%\\\u0007p)\r7Ƥ|\u0010pp\n8e}`UtT\u0005\u0012{^2N԰KwI?nTz<R~\u0013$zM;@\rv}*\u001e{rrvP?D\u0007GT&'_#\nʺF 8E<'xj\u0007M,K2\u0011&\u001eN\"\u0000JC\f\u001f!-xg\u0005s;N2y]μz8v\u0001`\u0004\u0001\u000f\u0018]ng\u0007)1KԈ\u0016}!E_)yWtd2\u0004д3\u0005JhGEt./+\u001fwP\u0011@<ب\u0016`/\u000bC\u001aG\u0004`1q\\yf\u0006j\u000egNLRX\u0016\nzRjs\byEͬJ<<t\\#8;nZ\u0003d/\u0016=#ð2\u001dC\u0017Uo'\u000fKM\u001e\u0002y.\u0013\u0016mǛ\u0012(q\u0010i]=zo0U\u0016\u0014$c\u0004ui\u0010i\u0000y\u0007SgC\u000e:o^(h\u0007<\u001cfx2H\u0010!d\u0019m\t\u0011W\"HΙF{\u001aCPT\u000b,)G1$ƒKzֹJ\u0013WpC%ū\u0013۟\u001f_\u001a$\u0005\u0017U-X<\u0014\u001b4/cep\u001f8%_Tc4p(=x\u0015a!P\u001f:\u0002\u0016T\\B\u0007P\u000eP0ܜ`?f\u000f6\u0002cih,7X!z\u001189R&PVI\bjjA5hlw\btCHB\u0014\u001amMt\t_\u0005OT/7~\u000bi续\"_\u001bkE!AW?e\tgp\u0017\u0001\u0000|q\u000b\u0010ČU9QwϤgz' [QDac[0\u0002\u001d\f\u0004zQ\u0015Je\u0017\u001fny.\u0016\u0013|%\rj}:C?`H\u0010w\bk\nk?gWv>(\u0015^0\u00112ߺ\u0013?`.]$b~O\u0016R7j[\u0019,9\u0001X{C\u0012\b1\u001a@\u001d䰠n\np|L\u0019\rE=65nS%{1Z!\u001d>x%J8cP^\u00054L/f\u0014ߋp\u0014驵e\rg2'\u0001?\r\u001aܯ\u000bژ8\u0007sXVp<v7Ïa\u000e0Bb\nIOс֨ ;k\u000b.8UZhZ#zA\u0018\u0000x\u0000\u001dp\r?JzHL\u0007tWWN\u001cQ\u001a\u0005*ϳ\u001fG.8d\u001fX\u0005˘'\u0006\u0005\u001a\u0010Fr\u0007׶|'7,e{7dxy=\u00151S\u000b)\u000b3\u0006\u000e\\ⰇP\u001d_f\rJzv@\bbA̠]\",\u001fUW\u0019P5י\u0004R\"AI3Q!\u0018[n1Ɍh)qD{;jJA~\u001e0=v*=!kԜZd\u0007S|ͥl'604hOA\u001b\u000f\u0017}ţ\u001e>O@P裠qur\\L\u0005#\u0004n\u0019XY{Jm0u9d\u0011ר综?\tJ\u0005\u001a`\u0000pбU\r`u\u001dr\u001eHTT1\u0005[ؾ\u0015Dw]\fxtw(kC͈>0:L.\u0019ç5\u0015\u001cLi|j\u0015\u0003\u0012q|K\"=&l1;\u0002ؕ\u0011B]\u0013\u0001ɗ\u0000\u000bJ~wh\u000e%\u001b\u0006\b4D\u0019G9\u000b\"\u00123\u0015kL\u001b %oQ_\u001c XЀ75M\u0018ekx\fV:\u0003\u000e>T\u0010}s\b\u001a\u0002\u0003dT5x`XZZI˔YZCbP4\u00180j\f%@\u0019eۈ;3\u001ag[cdG[E\r-C峝n&\\8)s\n\u0004\u0015<X\f#+\u001cQ4ʷ\u0015\u001d;J\u0018\u0017_z\u001f\u000e'\u0001ZȒ\u0007\bڡ,W\t1縚`Q\u0012\u000bfo\u0004Kq.\u001dPʫO~\u0017߆\u0001\u0016V>*\u0002a\fO\u0017\u001cuS\u0017\n\u0016\b'd\u0015\u000bJ\u000ej\u0005\u0019z5\u0006̰\u00047?Z{֦D&<1a`6Fz\u0003ר\u0005!'\u0018\u0004\u001a\\!\u001f'c-\u0000xN`LFs\u0002\t\u0007z@BsWZtv,+Lqd:ʊ\u0000GwRӳS0-\tߞW%0\b;CC\u0003Sz\u0005\u001ctF/1\u0006Y\n\"n\u001c\u001d\u001a7?+\u001e(\u0016CUX,/.oD\u0005\u0010[F\u000bCa?30p+5m'bȬI$w=1\u000f\u0018VzS\u0014*ۍ#u\t\u001b\u0011)\u0013\u001d\u001cg}Cy\u0001nWi4:Sf\u0014\fJQ~j\u0006d\u000f\u0019\u0018&Pz_@blTżAz\n\u0010M7{38AYIi1\u001fd\u0003R\u0003.AӎL?H\u0004`ݒ Z>$!2ɁEA] L;\fJ\t1H\r\f\u0004^Ȩ̮v^\u001eoqGɷEiL6\u0010,L>\u0012\u001c#XԌ)\u001d_>`GX\u000biEw\u0001C\u001eAqk\"T#Fh\u0007\u0017SXH\u000fW5\u0004x7m$Й\u000b\\+\u0014\u0001Rgth\u0005\u0015\u00184TE\n\tKv\"W\u0015h֚\\\b99}ǘй\b@\"nBS:=\u000f(O\u001cT|2~\ngw\u0003V9~\u001d'ů׹\u0011VJϦ\u0013JH:G8,[eea &9\u0005eyM\\Xܮ\u0013 AT\u0017\u001fQ&q7\u0013$\u0002w+m\u0007c\u0019h#%{nW\"?;1SA\u0005o q0a\u001er:\u0013Vj:mq\b\u0012\u0000S\f^»q\u0018\u001b xe\u0006H\u0004T\u000f\u0011P\u0001\\\u0018Q3}D\u0016d\u001f\n;\u0018#\u0005_\b^W\n\u000e`jbA\u0001\u0010\u0015@~}8;m޴\u0005(zN!(B+z\u0003\r2i'\u001c \u0010\u001b~?{^rEtM~e\u0004َrQu\u001cu&eˀ2A\u0014\bE\u001eD'I7P%H\u0004ol렸ŝ6ҟܹÀ\u0003\u000e᪸Q~D#D\u0013! =h(.U\r\u001e\u000bH@'fF\u0011^|?\u00064/T\u00055Lqܥg\u0010 \u0006Q\u0011?>\u001fQ\r\u0000.;8`«P1E\f֣1o\u0014\b\u0003lG\u000eg\u001eR<W*Y83\u0003pUEtusׁ\u001b\u0018A\u0014r\u001d\r#@qսc\u001a!fxN?[Kw\u001bYb`w\u0003`[vxG\b:RVe\u0013@U)\u0000\u0013!`yl`\u0000$}\u001c@~\u0017+2Cn*\u001fȠFl~ψt^^OǱ@\u0014#b4M\u0005y V\u00005[6WÅ({$?H!(z'\u001eGX\u0010g_#?S.7X\"3±\u000e*k\n\r\u0006\u0003x(*YXT\u0017ŌAb KM,N@̺_\u0011\u0003ZLm!̥ʮJ&Ry\"9<vcQss&?&-\u0017\u000e{ qv\u001dFQ(\u0002\u000eR|\"@j0,^x\u0014tz\u000e\tI\f\u0013牬\u001d_S\n:E\u0014D=\u001c-\u0012ccn/{W\u001dݞxƆ\u001dsAx+p\u0000\u0011\u0003XX.-\u000byYkh}6\"[\bun-w\u001fǊ/6j\u0013\u0011\u0006D2\u0013D\u001b3'\u0019ኔw\u0015C\u0007ącD\u001eF8\u0011ҩjǪ\u0014v;ݴ-W\n\u0011\u001b۟\u0017\u0015E*j\u0013(JcVmY'0.}\u0011K{a@fؾZ\f\u0002[%o}5z*\u0004\u0012E͑9#Z\u001fz\u0016`\u000eo\u000f.2~amH\u000b\u0003OR^\u0017RLt{\u0002\u000482~\u0016f.QNOw\u0013cd\u001a\"`F 8} Y4t{cӅ2\u001bXGt\b2|-/0T|w$2\u0016|GS\u001e\u001a\u001eE\u0011'8mہ~УR\u000f8vDA~=m2f$;kJ=ZLnhCR=\u0005^D謝(\\9.l%jOS5#E\u0006|FHS\"ګWLVѴ\u0001?Uj.]Y\u0003'T+gl}Bf~l͌BT~z\u0004\u001bJGxTBi\u000f>HZP4$ԏFs\u0013\r\u000f\"\u0012g\nŜ\u0006\u00158\\TlS^\u00155\u0014C\u0006\u001e\u0005[\t4xEv*)p\u0007ĘI5\bDF=Mq\u001cU;D\rBI\u0010ڋX\u00140\u001eVdqk^\u001bwP&b̙Z|\u0011O>eT\u0012N4\u0000h3b9\u0019\u0015ۋ\u00060J\u001e:gmNu\u0016\r\u0018(\\؊`\u0015E\u001f\f\u0012C?\u0016^䭶::`G\u0004P\u0005P.)[z9\u0002XWН-x\u000eBgȡU\u00040\u0005t\t׭\u001buEn\u0014Q\f՝1{I'臊ViY\t\fXRX\rX;zJ/*-\"kyg7n0\u0003\u0006SV6=\rm)\u0004}I\u0000G\u001e\u001e\u001fS5mN\u0015ט'c|w\u0011PTNhj:G\\(]&\u0014h\u0007<\no\u0007.)~\u0002_\u0015ds\u0004ޞb\u0011\u0017H,rQYr~oB߮@:T!z\u0015s_VkZF\u001a\u0015sl]G4@u\u0016Q]ՕArn~0t3@WsGѧ%Jr\\^^\fX1f\bTDECW'4e\u000f?C\u0010Qtv{$\u001b*uw\\!0tH8o۩^n'삗b\"\b)D\u0002\u0013\u00014t<,\\zd\u0017\u0003\u001c\u0002dv\\\u0016QHh\u001eM-vX\u001d(?uܠFK\u0011<̴Ǖ)e>z/v˜)!(\tK)\u0001۴n0z`\u000fb4QNy#\u0002\u000f\u001d!G\u001a\u0013B\ba$W\u001fC\u0000=\u0019:|\u0011뮃\u0015Tn1s;\u001ed¢ا\u0011s_\u00116iE:N2\u0014(\u0006\r<h\u0004w\\qVj-19W?\t:\u001d7\u0006\rL&ΐ\u0000#i%baa\u0019_!rrd\u000b\u001fWsImg!Jg-xEH~-\u001d<QI[{\"ȥLӥEi\u001c\tj\u0012Q\u000eq\u0012NǸW8F~I\u0012pDRM$1=kZC8J\u0007lϓlyL1\f^u -\u0000Ad3\u001e~QgEBq[٤\u00003[5#d\fMBzS\u0010GIL\u000bɟ$8B`\u000e9\u001eAowr޹\u001f\u0016(\\ޟ:ۘ2\u0004Bg>bn,0\u0018OKw\u001f7=ҷ\bOm?hYYcȡm&FC\\9\u0002\"\u001e+gJˀ\rbu\u000f2NUDL^\nDGIu1W7O?ˈ<ΐc:QJs{lVFǺOm\u0017-'_~U\u001a~\u001b{\u0019\u0010a䳼7 rBpfYo\u001eн\u0005<oҩ\u001aNMv\fJ\u0003\u0014ڃhMB?<u'\u001eY<\u0000.Qw-vpugY-wgOk\\cX/S[\u0001d\u001cM2nOӦs0F\u0011Q\u0016*ɸ]Ո\u0000D\u0004ҧD]c#E\u0013\u001f-4!n\u000f^ՂjH\u0011Au\u0005<:c=\"\u00078cYvF*\\殀S\u0016K_fK'5'\\\"wE<aQxP)z\u0014P\u0017EJU\tz\b\"OqFq#<\u000e\u0019PS%\u0015~豠\u0003\u0003`+ׯ6쉹3\u0006\u001f^o9\"ׯ*ѶQ\u001bC\u0010\u0000>4\u0011'{8k|Aqt\u0013bF\f\u0014jūۏh\u00041\"p \u0011\u0011sMYYouM\u00143fBR\u0016\u000bU4:ݰG^4m<BX:o\u001a5Q@XQ\u0010N\u0018W?\u000bd*K\u0015\u0005&=\u0011\b;00Xe\u000e{\u0013CT\u001fQyO\u001d@\u00014\u001bTG\u000fl\u0017\u001b^\n\u0015BEf-\u0003Υ\u0010\t\u0006a\u0014Gqi2\u001aPb\u000fI\u000b&H\u001e\u0005\u001e\u0000+\\\u000f\u0019Wĵ\u0010W\u0003b\t=JdkeDCL2y}hA6-j0;X6\u0002\n\u0004+D\u0018Ӣ\u0002̕\u001c\u001cn|h#\u0013x\u001cd\u0014_I=\u00135n1b\u001aʹ\u0001\u000e\u0010\u0018Ɯ\u0003A%\u0000YׁȅG|8|ԕ\nVj<\nq(6\u001eNI\tnd\u0013r7;4\u0001X\u0000^\u001bh=S;\bW^Z`XoFDq\u0011\u0013\u0015\u0003x<(GgG[Kݓ\u001fvb\u000f>\br\rC=\u001f|}|wy(?QɆϽ\u0014T\u0006URy.\u001b\u0010\u0016m\u0018HHJq\u0004.\t`?(\u001d\u000b{\u00103F\u001a\u000f\u001dt\u0010LQL񕡏\u0017\u0002\u0001##~\u000e\u0017*\u0007yCEʚV#od!o\u0011\u001fgQLAjk\u001a刲#)\u0018\n#\u0014\u0003s-sRϢ\".\u0002z\u001diA`Jb\u0018\bCui\u000f.{\u0003o\u0018@\u0006ۦ,.Gb(5\u0015\u0006E/<\u000e-#\u0019!\u0001\u0006\\yX\u0018Ho\u001b\nN\u001d\u0010ƇwDYnWHjG=\n;\u0001rX.d%;wb88\u0019+jT\u0010\u001edi[]P\u000e+\b\tD'\u0004 TH%C\u0015$$-.e\tœDuIL\u0016坮\bDls$M1 8<\nŻ17?o\u0004\u0013PԾ\u0002vG\u0014#:\u000eO\u0007Mkg\u001ay{tmU^̮\u001fQy8)\"+X6]\u0017^=p5xନ(U\fV\u0004\u0019zvCv\f6\u001cz\u001c{;lo(\u001c\u0013j\bH#\u000e\u001bEGDm8|2=\u0015c綞S\u0010TEv4 i&\u0016U\u0005Ǻ\u0015KOLv(&=v#\u001a.gʺ5S:\u0001\u0006\u0016\b-*Xڊ*\u0017.JM\u0000\u001e(Cm\u0010\u0006sN\u0019\u001ex\u0007ơFZ[\tCT,R(Ͼris\u0016t8\u000e\nA\u0013l\"{sAcʲD0Fw\u0001;3^~\u001aw.<yn)\u001e7ƨ-\u0019E}{}G5aN1\u00127`G\u000fc\u001b\u0013Y\u0015 \u0018+cuET\r \t\u0010͖R$\u0004֚qZQʮ4\u0010<J\u0005[Qv$\u0016\u0018shb\t\u0014fasδ`2:\u0017\u0010#\u001d\u000eHSeޮusfm}Q#?W\nɶY`\u0005kEG@A*\\^G̺j\fsk|ըͲmy\u0016Ӥ_\u00038xFNp\u001e\u001c=ڷ@BHâ\u001e\"Ul\f8'k \t~XnDkvY\fчrۘy\u0011)L{\u001a\u0017PŵH;:\u0003{\u00116S5\n#\u0011\u0003~#g]\u0012'>dmR\u0017R^\u0012䧈+\u00055n[uꎭO%\u0006*aP|#/d\u0011n2uWe\u0015Ź\u0006rf-ٞ^qq\u001de<H\ne8P(\u0005=ݝh.jo霉\u0005~20Ȅ\u00079:P[W\u001eńV*ޕ\u000fg]\u0000\u0000m<LYE.~o\"r2spv9\\\u0011~\u001e᳝y=B3ߣ3xu#'`ib\u000f\t\u001e-\u0007/\r\u0017`@i\u000fQ\u0001U\u0002*b/\u0018SKccN|+Y{^N\u0006\u001f6\u000b-oq\u0012e\u0005ja\u0014^~WZ?D3Q\n:B\u000e\u0017ᣈ팴\u0005d,Q\u0007ڶj\fۺbJ2\u001cF\u000fJ\u0004Mn\"t\u0015s\u0005W!r\u0016aJ\n\u001c ZJ'D`?Z\u0011\u0003\u0015r\u0014ԋ@qm\\gȀReg1ĵ\u0006Ta\u001b\u0006Cd4QzT\u0005{:\u001e`=Go\"8Yv\u0011T8d5->\u0006\u001fզ:\u0000*UX%y\tH&|z\u0013\u0006\u000bɟ&C#Ws\u0016^crĔ{kl\f\u0018ݗ@rq*\u000bu\u000fLp!rǾRW\bGaHJ\u001dF\"&\n\u0014\u0002\u0001dr\u0015t*fh&Tn\u001b5g\u0001Ǵ\u0011%+\u0011\u0010\nI\u0011\u0014P)\u00008\u000eȴXu$o9ui\u001b`ͨ\"%f\\::(\u000e3i3f\u0011<#\u0002N?\u0007߄znc\n\u0018\u0012K\u0006]=\"/U\t>|n4+UvG\u001f\u0014\u0005@{\nU\t\"\u000e\u0016gG\u0005\u001c+\u0011R\u000eQ>rjDđb\u0004'(p`A\u0016DV\u001atPJ$/\u000b\u0016Q\fm.gy\u000b2VH\u001bP&I9]YvkN\bt,+\u001fsz\u001f\u000b{:\u001eEϊ\u000eLޣ(2cN(,q*תme\u000b45\n\u001c6b\u001e\u0000-=D\u0019\u0003@Q/q\u0005\u0001\u0012\\уأBDT'C[<ϯZ\u0016}2\u0005f?*bhpV^\u0011bжI3 <1$\u000e2\u001fP\u001bM3\b3XRL\u0011s/#Kj\"@e\u001d\n򽿰ߢf\u0010y\\\u0015>|%2\u001de7\u0005Y\u0011W{@Lpc:٩Xk\u000fɿYE\u0019E3=Y^ޖz{\u001f5C!&Qi8m\u0018&\u0003!/ptmp9nm6qJp\u000eX\u000b}\u000bM+u+Ybed@,,!\u0007HǧUSSz\br<\u0013i4)5*i0\u0010P0Ūoף\nc\u001an7yT0\rf\rGF\u0004U4_\u0016\u0018\u0019\u001dg<QG~]\u0004\u001bG\u0007\u0005RJJ++\u00050$Z\bTuM\u0000ԯ,\u0010unIf\u0007A?rסL\\\u001a%N&\u001d0,\u0012\u0012O:\u001f#\u001eR\u000bNZ \u000eK\u000b\u0016(:\u001amGV-\u0018(;\u0016=U;\u000e\u0001Џ\u0015ω\u001c*k\u0016,f<p\b\u0012tK\u0017usbOhȔH֧\u001a]ȋ*F}|yT_\u0012'r;0?n`~տ?\u001f\u001f\u001f~s?C7z\u001auOb$rIV9p\u001c, t\u001c=\u000e\u00120\u0002\u0005\f\u0018\bT_c\u001ai//{w\f?㣠\t\u0006\u0018S\u0007(x!N1\\Jq\u0012\u000edl[}óRGְ:\u0007N\u0007SGُ:\u000b+MG^\u001aU\u0000_n$ś◔Q}5rx\u001f\u0017\u001b4T?TQi\u0017=(ͪ[U5\fpj7+ɪ\r|k\u0003ea6ha\f1wPi\u0007YHbCm/T9\u001ckLvcr\u0013\u0000\u0017\t!/,C/jn&A~\u000fdN]ҽ Z9\u0004yƝN*g-&.\u001bI?\u0005\b>WzV/'\u0013g\u0016j\\6[@F1#Pg\u001aQ=\f\u001f|\nK\u0012+Gq?6\u0002>O\u001eV[m<w(\u0006\u001ar-x\u0004MDl\u0019֟\u001f\u0012\u0004{#\fpذ\u0019jb*cƑ/?Drh\u0001]ة_k\u0001:\u0001\u001b'\u0019s@?Eڟ\u0018+Ě6'Y\u0005S\u0013(\u000eT\u001f\u0011}*+Mh8\f=;(!y<\bN:*<\u0017[OY\u0000.D\u0005\u0000׊\u0001\u0015\u001bd\u0014*_\u001c\u001a\r`;@X0q=g#͘#͘C/@.L\u000etj\b}m&J=eZTԶ\u0016`%g,z\rBJ6\fdY\u001ac\u0004]9\u0000-\nH㐌@\u0002\u0015&\tq r&\u0016c*Q\n~\u0007\bwr4l\u0011x@$fm \u0019c\u0003UsIWA\u0014KgfuS&ݕϻu\u00000bhӮqsC~o`wЈ'eK|B\u001c騳xQsT4eG1\u001d\u00123t|2\u0010S|\u001av\u0005{t\u0005\u0004jC3pJm\u0018SQEE(:vq˄\u0016\nSa50U=+Yj2\bр::j8j\u000f\u001dQ ô\u0011\u000e\u001a-V\u0019nč\u0001gC\u000fWdB䞮\u0012P4\u0013XQ\u0017P\"\\\u001f'z8H򴈠G\u0004\"P\tX+IqZJf@g(iƞ{ύ\u000fh#{\u0014Nc0r7כ\u001dJ\u0000\fXGW><)3sX\nK]\u000282\bv\u0014{}\u0001\n2]駮{ri-\\FNkm\u0010=X\u000biȯG,&\n\u000bnL\ffh\bg\u0010\u0017 _\u0015F\u0001ȴI8ɩ/m\u001aOv}GD\b<-gR\u0001TE$z)7dL.qh\u0019~\u0016\u001eo=:ۮyasL\nkB@_|F\u0003J1w@\u0014Ʒ\u001e\u0002$ԇȐ\u001b@߇\u001fIoe6JOA\u0012z^\u0006\u001bhJ\u0004d?xoq\u0018A}\u0010?\u001d\u0018U?=tǱ^\" !U5\bZU\u0007J%EfhM\u0001v|pN\u0003َ\u0007jʵ]\ru\bzwt\u001a@x,\u0019^#\u001b\u000f_\u0004戃\u001fA_P8$L?Oha\u00117z6QU\"su\u0003$\u0014GW3cA\nF\u0010qΕzz\u0011~\bө=tfV\u001aؿN.{jt(\u0019\r*Y\u0004\u0007.=\u001b\u0006\u0001׷²\u0018F|Ǡ1mҴ7b}YOoI&p\tCᵁs^\nq\u001fh\"Ni\u0014\u001fK=SZgu~\u000eDeѥ8\u0015>V\u001b\rp$֓ht6\u0016)W!oy66la<;k\u0003K96P`D_9~05\u0007|\u000e3\u0012M,\u001c4cJ?#^fc}m4\u000b\u0016\u0016C%\u001b?6\u0011I\u001di`r\u0012WG\u0003jy[Q\u0006\u0003*aڐ)Rjt⯿X\t\u000bQ\u001f\u001bP!i\fw\u0001^[Q\u001d_\u0001r|U~\u0011\u0007^5ݸ\u001a\t)\u0019ső/w\u000e6i?%fL8m4\u0004lО4HmYZtG\u0018%L8]!\u001bΠ`Q\u0001\u0005;C\u001a+?\u0018vB;ȿ\"O\u0000\u0004SE^VY%yR=Nf?\u000eӨ]\u0017\u001ek$\u0000o\"(&¯\\\u0010qnSpŉe\u001e_y\u0016k\u001c\u0017\nXrZ\u0013t#0\fI\u0004-\u0007v\u0011~7\u001c\bX\u001a,oyS*t\u001dڻ}5m\u0013'\u0000\u001d\u0015ϔi_~j~bMx\rceAy4}^к)2t\u0005>K3\nLrJdmF485l*G\u0016;Sdi¼:-\u0019\u00038u\u0001ȴ-xb\"\u0016bmL\u0004\u0018\u0007\",\u001bLqc_/L\u0012Egp\u0000'\u0018\u00131\u000eUKBߍ0RQ4V\u0004:\u0001Nu[$/?\u0002u_T'\u0017\u0019Y\u0014l$\\\u000e\u000bN9ϑ\fJ\nxF\u001a\u0000\npod=Nvb90a%ԪO;z`\u0010Vb\u001fqT_&\u0011wf-|\u0002<\u001a&>%0q\"ˤ:\u0019},\u0015(FA?06iZqm\b\tn띊$\u001fԑ\u0004s}O7_.70\u0019\u00198n\\`~vo7PFm\nsy\u0006o\u0018<\u0012ni{M{\u0003\u001cBKO9G9@$슘\u001cN05\u0003Ov\tO=r~cT\\C,m`Y\u0017\u001d+δwiw\tHK\u0003dͲٷ(mFQpy\u000eK\u001aG~~\u000e*}^Fâ_$twTI>SK\u0019\u0004\u0002rڬ|\u000b\u0012J=62Q*d)ow\u001aA.Cek\u000bmng}LxrW7SF\u0010\\\u0002\u0005V~.n\u0005zyBPz-\\Xc\u000ft\u0010b:DE (+p?~+m,y-f|ʎepŵ\"0K\u0001\u0014s -U\u0001%\u0010dxG\\vޑ(]!9E$H=.9҈}샹6FO*rq-PJY\u0016- \u001fCEllMڡO\u0011[<\u0016]\\\r\u0005}\u0003\u000e5\\%2҄c;*Gso\u0019t\u000fL\u0015/\\+qE\u001eN\u0010Ugy!L\u001f\u0004\\<(D3J<>rV\u0010\u0011e\u000eW`-\\%\u0014\u0012S6\u001a\u001f~>K1(\u000fPQ\u001f̢fA;}B\u0005Mf訷՝=\u0014@Ό\u0000@\bmCnPCï-uaʬfeVJ\u0005\u000b\\0\u000e{\u0010ۓ$!Ks[A7S!beÈ<h&Eܴ>(\b9\u00162TK1#X\u0014>:\u0007\u0001Xs\u001aHn\u001fu(\u0016tz#]Kbʫ\u0013 MsiA\u0011\u0016#8@\u0006,-&J{\u0011Gc4\u001f$\u000e糊A0C\u000f\u001fĄL\u0015m?>D|O\u000e\u001c[ԈT HF]\u0016r\u0000T@}Kfb/R*Zc^ƻ\u0010;%\b\u0011\u001aw응^7\u00195\u000fۍׯ\u0011U#ORVzuwJ>\u0000\u0006תn\u0012\u000ejbϳ9Y]\u0019\u0003\u0018^su\u0012gOȁP\"G\fd\u001e垷\u0016;yhk,~3\u000b\fL7Q3km\u0005~\u0002\u001bBQ홳q\u001dLw\\YG]\u001fל\u001e\u0002*3-)죕\u000bw.\u001f\tf=&͔jC\nm#~4evՉ\u000e-}?\u001d\u001e\u000eǏ\u0014i{\u000bRE놨ϺFؔT\u000e{n㋉;\u0003\u001a4d\u001c\u0007\\!U35.ڣJϨܮk\u001c\u0019栵~ę\u0000ƺ{/IjJ\f\u001alv<p\u0006+\bb0\"ej\u0003\u0006|l#\u001aO?58\u0000Ngżs!\u0003\u0014\r[cp\u0012;\u001d:@HjC\u001egC6PSj&y:fz@\u0000\u001d\u0010`oL!T[ņ5iGRswc,Ox]\u001b|ҳ,yӭ?jA\u000fzuc\u00140|?`Oy2Ŧn|\u0013Td\u001b\u001fƈ\u0007F?ŋ\r}{jx=چkF\u0016?G\u000f>P%wgY\u001cݡpӶ;zBR\u0002Ԩo\u0011\nDZC\rVB\\K5tCv3JG1\u0000Wr\u0014EG,\u0001n\u0000z#qf2*]dƓ\u0011l\r/){<\u000b-DQ\b!E[\u000bm;c\u0011CY\u000bI\u0014Ai1S>_\u001fҚlHQ\u0001\u001c0\u0018()\fd\u0006ȼ\u00114\ni\r;Ǔ=˲UQB\u0018Y#޽͐O\u0001[Z\u0001d\u0014k^F\bZѽD)\u0006y'|\n\u0012\u000feM. \u0012O_l1ɍ|'wvcȸ桕9ÄT\u000bwJ;\u0013RD?\\`ig)\u0000MD\u0015\u0006Hh*tP\u00071k#\\FWֈ(*)G]N\u0000D;R\u001e<ch#2i'U\t%\u0004L0(w\u000e.8P/5ܞ\u001a\u001bV:ʈ\u0017(E?7dcT\u000bN\u000e\u0015N߀oZ\u000e\u001e\u000bn\u0015,T+\u0004 Ld\u0011sػ*4\u0001w\u000fTO\u001bݭ7xZ\u0002m\u001f~v._\u001bwS}\u0010qby~҄ZV;k\\\u000f8[[\u00190=\"\tJ%*\u0016w\u000fAwx\u001c1\bm_z~\nIc0XߣhQvIki(3ɒWq<}\\+U8ר\u001f?u\u000b8Ō\u001e}\u000bt\"\nM\u0004P.5Pkخ\u001cE`-\u00049\u0004'.\n\u0011\u0002A.\f+.#6t;\u0012W\u000ed\byw\bc\\Q\"(\u0012Q\u0016Tm\u0012>\u0003\u00151\u001a89#/%\n}\u0017\u001a%\u001e'=[y\u000f\u0011BqaA}P{~S\u001eu1Ws\u0012Q'\\\u000f\u0012\u0011a{\u0014\u0019=w\u0005\"\u0016r\u001f\u0002\u00068\nh,E$gxzcPy\r\u0000|L\u0007\u0005\u0001\bA*;8\u000f\u00116m,\u0007(\u001aCjF\\@2, \u0001&ů\u000f,m\u0011\\\u00149\u0001u\\޽\u0014jA\r\u0003EqU\u0003Dn\b1%Ra*u̅+k\u0019\u0016\u0019`XHGj؉^8\u0015#\\\u0011\u0004\u0013q2P髏cH{dߚP/\"{\u00023Ŀu\u0010_!\f\u0010?W\u0016\u0005VQ,Sa\u001f\u0006([ͮ.R(BN\u0016U>$7z[y`\u0019?\u0005U(m\u0013ev\fVO\u001cC\u0006I>(\u0001\u0006\r\u0013\b\r|\u000b\u0004\bgӦ\u001aq)4X\u001cCa\u0004[\u0018#7q%ʑ\u00144[:\u0003\n\bj'[|lȋb\u001f\u001e}\u001b\u001eD@j#k\b:c\r\u001e\u000eud\n\n\"ND\u000fYS@9>\u0003l5C`\u000f\u001f[Һy\u0019i(g@JmLr]YI>\u0016\u0001ZB5r<(%!E\u0010_#SJ.o#E+7r.7^r\"΀%<\"wj\u001c0Ĵ$ɷư턪{W&Q\u000b\u0016pUINUC_Q2X/\u001e-2y\u00068@]}owA\u0005}ۤKem[\u001f\u0003#4]@g#t>j`\b\u0001R.\u001fc[#\u0003BSR{\u0010\u001dZ\u000b\r 8u4Yw|v\u0010\u0011\u0005\u0001vd)+>\u0014\u0005F>\u000en \t$]w0В\u0010#(/4K\t;6Z\u001bv\f9<ЊAtftͯy ic\"\u000fx\u001c\"h1-71p\u00177OG6~Fg|؈'\u0018\u0011\"H\u000f+g[E\u001a@V-ࡷc\r\u0017kO\u001f!NVfC\u0007]4ǆu DƹE}u]AhI12=\u0019>\u0003Z\u0010'Iu\u0013(~Ft\u001fk2lT&1u[$QX\u000bUYI\u0019dKZ7\u00037@2c-dG.8\u0010i\u0003Q\u0000L\u0004o\u0001\u0005\u0015~kmw\u0013Z)\u000bg\bd<\n=M\u0019\u000b\rr\u0005¨\u0001\rqIt\u001cpT(}\u000e\u0013\u0002n^Ԗ\u001b<\u0002\u0017\u0018$\u0003EI)\n\u0007kx᧑\\@2\r)eoYO]U:\n\u0003\\B5v֭s!\u0002lz4\u001ff[ЈNGNW#3\u0002VcB^O#ei|D4o\u0016RS\t|EEIfNl\u0002AӰ\u0007`%}l gaiA\u001c׵y\u000b\u0010(A\u0015\u0007bVWڢw\n\u0000\u0012!!8C@OcR\u0004#jq[KB\u0000_tfHưU==\u0012=_ŕ!׭$Tܷ\u0002\u00195\"\u0013蠵V2D2]]+1\u0016\u0012\n\u0011t6N#\u000e1Ewq\u0000\\dm?\u000e`齔\u0013\u0015Κf#WĿkbw0\u0012;\u001eY%[3>49\u000fȚtL\u0010\u0010\u001e]Vwd\u001fedisN\\\u000fv@6@\u0013ۭ\u0016xj\u001fk\u0006QE\u0005ʖVBtKO^~'\u00178=\u0007W\u00154##v%\\hCI+C.9T\u0016In<xE?:q^rFX\u0018\u0001iO<nnۀa?uc'&\u0015$4h>\u001bq*{kI\u0001\u0012Ѱ=j\u0004s\u0002\u0007x\u0012\u0014!Y(\u000e+Uw\u0015\u0000\u0000\u0017\u000e\u0012@wmOwaA\"z֊*J\\s\fVA\u0019FiuKW\u0002\u0000zuDµ  \u0007\u00001Ҋ3p\u0017sÊuV\u0006]D(,\nt<\n\u000f\u0016e/LZ$E\u0001$Iץ2\b\u00155B\u0002SB\b\u0002\u0001yDxp\fd{\u0017\u000e`<j\u0006э9\u001bJ*t$\u0004\u0019aE\u0004!kD0F`\u00158\u0015:\u0016[C\u001cI-m*V[ڪ\u001e9\u0012\b>\u0001|\u0007*\u0012\u0018{^G)ɐ\u0004C`*\\Q@S:j?HB{h<Vx`SɷID\bBmk\u0014N\u0012hp(7*QPX.x\u000e5ךT԰QSZ\u001aB\u000f\u0013b^8ՑV\u0012׍-̞qc`\u000b=5Q\u001f t\u001d2S\u001e<uf\u0000^KG?2}\b*\rG͊\u0014F.\u001d5ϑ\u00034\u0013\u0004J|#܆XJ\u0002w>mq$J۴\u0015\u0002<k5p\u0000bB\f\u001a\u001b!ʤY)\nK8ݏ\u0015O\u0007+AcfSpD[^\"Q\u001dٿ\r͎Mi\u001aZ6|(TOFUv|G$\f[`Jmw*Xם\u0019rRcBɊ\u001a@)bNEϔņ+Ul9\u0010I}\u0003-~*з$ȩ4~\u000b\u001c\tٓ}\u0014h0.p2\u0010\u000eo#\u0013.k\u0000\tq~U\u0012xx\\x\u0014^dLS{1V>\"1^!\u0004Z=\u001b/m\u0018Ev}GI,CZ\"\u0014]\u0011[\t\u0002\u00062\u001c?G<*[tja u$fk?MN\u001dېV#E\u000eZ\u0004OiI\u00069V܀F\u00002b\u001d@烎@t6\u0001$@0ZeC)Ad˚HnǢEٞ+\u0000l\u0006Mm\u001cXJ]\u0012S̒\u001ex'$饹gPuIt>o=tbqU:bt \u0002\u001e\tvI&_~2BXsr4CɖS8\u001c~wvW\u00077Q4yӜ\bvǪp¯\u0006ǌQj\u00056Y6O\u0019\u0011\u0019ܿ_<f kk\u0016\u0013\u001e(ŝmi\u001f\u0005гO{ZH\u001a=2k\u0003\u0018l6\fo𥋮큈\u0014w(w}WG5E\u0005a3=UϠ#=0OB'14Û\\k4i\u0000jw\n1v]g/+HRܣ\by[>i\u001e\u000739$2Ng#0\b0eE`mkƆ5[N7\r4_5=m7ZU\u0017-\u00178\u0013״&0\u0017mR<\u0012\u001eV\u0019\u0005Z,\u0007\u0013\u0013Rs|\tcY(cxU\u001b=C\f\n9\u0015\rt+uh\u0015\u000eV_Ȳ])\u001fDکװ^\u0015\u001e#\b6\u001a-I)8y\u001d\u0010\u001b陵0\u000fO\u00063Mܫ\u0005\u0014\u0007\u0010\u0013j\u0005E\n3\u0018\u001f'2JwVr\u000e\u0001ku<#\u0002\u0003\u0011z-S\u0018\u0003\u0000N\"\u0005*C\u0004(LUhaѭrZCz1,E/#`<-\u0000%\u001b55Uݏ\u0017ZFZVyz.\u0012\rp;\u0012*Ϭ*ѹ4r\b렷^t{QDڰ\u001f\u0018wݤ\f\u0014.\u0002V\u0018Ej,'yF\u0015(\u0010x[WQp2ᱮ8׷)\u0000?ѯ9\u0003|\u000f;QR1Vr ËjE\u001e3ҧ\u001e3{%ku\u0011U&eǌRNu\u0015]_LkB\u0015JЭcbkg:5Gkç\u0013\u00108_:#1ktŌ$^Yu\ny{\fq#T0Ջ\u0019v}0_H>+P\t^\u0017d\tY/u+PN@\u000fp{Y5S\t\u0016v4+5N\u0019Jw)E|\f?¿EwUz,\u0005eY\u0012\u0007=v!u\u0006ɿa\u0000=\u001b\u0004cr2e$V\u0001]LD\u0000>N\u001c\u001bq\u0007ʽ,pTg\u001eǟ\u00123ȂRX\u0006[6ÒY&5^S\u001e7\b\nO\u0016-0><|\u0015Ъv4؀p6X\r\\UyǞr9;;ӓ]ggo\b[}GEU\u0014V\u001f+\u000f\u0005Mo/\u001dK\u0013?l12Uʒ&9q{I\u001f\u0003\u00050T ?\u0004+DUo\u001a\nձhF\"\rȶa<\u0015,1?T\n94\u0018FD. \u0011\\7xP-\u001eI!\u001br҃gkcg\u0012Hj̼ŔP!'@G+\u0016_\u00063\u001ao9\rTD4h\u0004)KS\u0003ܹ9ɷ;pOߢ4\n\u001d\u0015}`Q}\bN\u000etd\u0014Vպ֓X;\u001d6dTuVJ0\u001ex\u001aءHÏS\t,\u001a\u0017'\u000e1smPϤ*Jk\u0005'\u0017O~k\nn[\u001e@!| -X@Eq'_c|\u0006]+\u001aJ\u0003rm6o50\u000b\u0015d`-C}+K|\n\r\fJ!oR|C;|=n\u0013Z\u0006S\u001d\u0003'\u0015\u001a)B*(\u000f\u0018\"N\u0016RMt(f\u001f\u0015rGc=Ѯ(~\fSɉίl@[C\u001b\u0003.\u001a'HI\r\u001fI\u0012?\u0016gm8|9\u0019\u0007qL% &[t&8_l80\u0013\u0000tNih\u0015\u000e\u0012x&,6\u0014.-Ek/\u0012ra>6pQ^\u0013]r:J6#\bg\u0012zt\u0012N-\u001b\u001dd-#\u000f\u001bQ\u0018\u0019\u0015xmfw{B^gIc^l]N׉*ʑR|j `\\\u0003p/\rQ|]4U5[9.qu,o{9!ڳ@\rHU]8~?V\u001b~E\u001e\u0016Z1\u0010݀ͮ0Ǡ\f&B\u0014ikxbF+b}I\u001d\u00010Zk޸#\u001fY߲Hg\u0013\u0004Q\u0002wXf]5v\u0004ᷕ\u0018T92\tQ\u000f&\u000f6\u001c\u0010i?\fP}\u0015\u000bpV\u0001\u001eN=\"N~׫q0Ap\u0002\t@3h̷~q=K5@\bp҄xjXp\u001d,pIc\\,\n\u0011\u0011oK\u0015󐽤|*\u0016~+#.D\u001a\u001f\u0010_\u00018\u000b\u000eU/B0\u000fb\u0017\f[Ǵf˯a%1\u001dS\u0010|\u000698ǳ!\u0006@:ؽJR 99jC\u000fzu=^Y\u0017[IfX&׉Y\"4ui\u0013\u001ap׺\u0019XRl|\u001d\u0002\u0018PO\u0012ְ+\u0007m4\\@Z|՘OUC{\u0018Q2q!֠;8f\u001a(U%^\u000buuהKROVZXn%0i2#@i:Of^\u001cD\"LGz>o\u001a(\u0001@E\u0007\n\u0013\u00185uh\u0001KǛ`rR+Wg\u0000\u001f{2#ce*Ww|ˀb׬뻙\u001aَ\u001d\u00070>Kg\b$\u001dӶ#+h; ;Yr\n\u0016U]]d;[\u00111[\u0016<\u000f<\\ù\u001bsɢYOzݩ\u0015\u001321<\u0003v\u0004ߢ\b\n\u0012a\u001cQk#\u0010f^s#>EOIج@\u001atV\u0004\u0005'\\\u0000\u001c\u001e^*˛Lۋ:\u0012\u0000>^\u0013e(\u0015Z\u0016@\u001f\u00058\u001e˩\u0014\u0017\u001cFN_D)\u0005\u001e\u001a[W\u0003hC\u001dM..j}=.6\u00183mv\u00068$|H\u0004mqq͎dK~ԳJV\b\u000b*&\u0000pʲU\u001bg&&\u001e\u001e΂lʯdKxuё2B& BNg/VXFf/T2F\u0010\u0002\rZ\u0000)\u0007a5< 6{̮\bq b\u0017p\u000f\"!iaMg]PZj,\u0000\u001d\"r\u0019\u0014A7b\u001f\u0000s\u0014\u001aQ\u0016^Sƀ5\u001eW8\u001e#ZTrD+\u001b۰sFq3T\u0017\u0010\u001c\u0013WhtPV \u0004\u00037T[\u000b\u00054\u0006\u0004\t*\tn\u001ej\u001fR[\u0018 \b\u0011۱ڬfL'Rh$~׌36\u0003G\u0018B\u0000];C90g~\u0004X<#8|m\u0007]qW\u0007/vk&M3Éŵ+|\u001cWP`\\@V@\u001b\"(6\u0015; EMl&)q¬\u000e1ZX^s\u0012r\u00003i\u001a\u001f4 ig3!b> ,\"\u0011\u00008\u0016\u0011?4\u0002^\fZ\u0007ʞ\u0000\u0013-YF|nX\u0006ՙL]~ץ\u0012Aksg^m\u000fJ|r/*\u0014\ff9{\u001bqN\u0006qj$&Q_b廲.*\u001auX%*t`5-Nw\u0018v\u0000MM2\fSB92O{xAsmO\u0001Q\u001aGCAߧ حUv\u001ey}hs\fmM\u0002\u0014h\nOpM2sp_)D\b+T[b٧ӤE\u000f_ʜ'_#l\nFYdtX4չsL\u000bch\u000bOįY6Ud,$-\u0002kT\u001e|o\fqC1\u0002hp)\u001c8\u0005h \\N\r~ڽD̵_\f7iD\u0017#(F\u001eh1\u0015]3)U\u0004\u0003rց\u00037(&sú9\"\u0006.gu\r.|\t5ٜqȉL:E\u0019(yq狨Ko--1aA,e%mscGFLg|\\\u000fM^+ua\u000fޥwRFGid{YX?'xᦺ4]\u000f5g\u001e\u0011!aنs\u0016t/m D`+\u000bh\u0006m\u0012])\u001a\u0012\u001c?I\u0012R,$I\u0010Z\u001c\u001bGjq\u0004vW*)BDdcS1͒\u001f5\bW+Q\",\u0018-Kt\u001aHbe\u0000~#\u0004l\u0012\u0007+\u001e;*\u000btQĉ\n,3{{.D}?\u00187\u0004\u0005/J۠\u00113r𘺂GiUb\u0000@R֧\u001a⯷9\u0004L,A*\u001d-&Ŧ\u0018+\u000frS\"$\u0001<JOM.:Gz4(k(\u001a\u0017k|+)5#/\u0014\u000eJDWH=N*Aò;G酲TXo\u001f\u001d\u0015P(^2\r\u0018\u0006N\u0001W\u0016}tz!I]ɼQ@LBLRxBbcH\u0005\u0019IEU\u0019CX\u0012\u0000V\u0001<.t<*:=li]ᕪ_\u00028~\\/ҹSӪFݭ0@\u0011=h.\u001cO\u001f\u001b+,\u0001A\u000e\rZ߁\u000f)\u0013\u0007X\u001d.*\u001c\nXsL\u001c盛B-Vx,l@\u0007|\"Ԛ\u0014PnhAL#Z.sUQ76\r+_\u0001l{D(V';\u0013೩a\u001ba\u0011c.g%%n,\u0017l+Gj\u0013C̴5\tڝ< ;\u00075H3&\tG[d\u0003H}5\u0002ε_:MգZ)\u0018\u000e|\u0012\nr\u0006\u001e$P4`7בH!?Wvy\u000fw\u001c\u0018jq|v\u001fLeF3\u0015\u0002:%f5\u000b\u0019ҩ\u00167`֬\"h\u0017m\u0007\"\u0019K^\u0007QkW-\b!2\u0017R\u0001g -eWз7D[W\u001au\"pirY\u001fLu[\u001f@\u001d\u0005v}N\u0003c\u0011뉸\u00071\u0012룻\u0001u\tƃKRo\u000boH,]1\u0001(\b3\u0016UZ{f֣&\u0003Nb\u0004J:ib\u0016@G;\u0005䊀M\u00031z\u0006\u0003\u0016DĮ7):P\u0017\u0014\u0010F\u0016?\u0014\u001d5Xjβa\u0003\u000b6l@vE\r\u0003:2o9#\nV\u001a+\u0015:\"\u0001I=y\\{?6<\u001dQ]o3{@(3JC:s\u000f\u000eUH\u0019&)Nd\u0016m*r\\7%2V\u000e%02-\b\n\u0017:\u000eQbX#j?\b\u0012McM3\u0007\u0013\\\u0003(fz)ӭ{e\u0015q\bk%!*[~ۣk*rV@ΙȂ%@nG\u0019WpFF\u0000\u001dأq\\('Ye\u0001j{2HS\u0006׬AU\\\u0003Nw?\u001fWndHT]\u0011Y+$zt.\u0018e\u0019\fkr!e\u0005<\u001ax*Sd2s9>[\u0010vDB\u001af|;=F;iǖ*$-\b+\n\u0015P\u0018gH`hk\u0017\u0007JuBjc\u0004S\u0006kh%?\u000eT1\r\fV&mGtMtم\u0007ː\u0005\b&6RY\u001f\u0014\u000b\n\u0002\u001f(pSvzA\u0018p/>P<\u001fQI6P\u0004.L47s\by\\ﺲ[;}IϞs\u0004\u0005YܰK\t<rAJ!ś\u0002\u0003܈_H=kɇHH(/\t2UrGƫ2ik\u0011ZqPW\u000e\u000fxr灻\u0012V(ooB)PHND\u0016ع\u0001<,n\\#X)dЧ\u0010ӮLm~ӭ\u0012\u000e1m\u0018JOxʵ\u0017~\u00055h\u0003%͌ʦs:쁡8\"F8]0\u000ff֟gc \u0019#\u0010Bv\u00172i[&[Dyo\n+\u000f\u0010qd:5.\fY_\u0005X׺\u0013DX;f|'t\u001b]\u0018*p+!\u0011>,\u0000\u00079J\u0003N8Vw\n9\u0003Zl\\Mבm®Ǯm8!\u001e*@y*AK\u0002<\"eRnS7gI\"O\u0011D5A37\tYg̪|;CU\u0003(9\u001ds'^vhn\u00028Y{O͔AV\u0005\u0015OX{t96z\u0014\u001fm[\u001e\u001a\u0013fuVf=#\u0000\u0017Anx~ڭg\u001e1γ\u001eVޥ9Ҿxn\u0001\r\u0016\u0016S6>f\u0012sͨRE\u0002\u001a:cAL\rendstream\rendobj\r177 0 obj\r<</Length 65536>>stream\r\n^okC\u0000\u00045\f\tzE`݀X \u000bՄю^k^Wx\u0007pgc:x`\u0001DmE\\=\u0012>&LO~\u0013\u001a{\u0001<?/fX]\u0003ЎH\u0011.\u00061\u0012\"\u001b\u000eD\u0001\u0003=7O\u0007ã\r`ADHUE\u0011`S[~\"-j/1ڋzš\u0011r$1\u0006'Ay+\u0007-^\u0011qDƀ\u0005M-Ȧ\u0000P\bJ\n\u001fv/+3\u0011\u001f_ҷ(]Q\u0007H\u0017q\u000fMT\u0012\u0007d[G l{\u000e\u000f\u000bu\\Ah4\u0017fZZu\u0014\u0000\u001cv-쯑8Ҵ-\u001f\u0018\u000e;UQv3N\u0003)w߮Rض+O\u0007j\u0012!ʏ1juU6Q\"B\u0017C\u00118{St9\\\r8\u0004\u0016IaS\u0011+u3\u0015+%#]o$<~,`\u001ezO8?ggI,\u0007fu\u001bYKۓ!1\u000eIh\u00115%\u001awR/qϞlI]c\u001f̺dtS/(]\u000bwF\u0004\u0010\\zw2= \u0013!4@]%J~(\u0018\u0006H+iĞO-\u0000(U\u0005\u0000\u000e'\u001eE#:c0\u0000EPJZ\u0017\u0004jL-\u0011w{\u000e:\u0001YHݞa+U\u0015uDHp_k;ȥF/\u0016LFhq\u001cm\u0005Q<)I{\u00130\u0010ZŤ*V *\u0014CHu?wPGU;E\u0006f\u0015P]\u001f\u0006W\u0004`\u0000!u5/a\u0002˨Aq\u0018ȶeيB\u001e(8C\r\bd?',Q.t\u0011\u0010\"F?\u0012\u001b\u001f73G\u001ai]\\k\t\u0001\u000e`v%BXvjN\u0013\u0011Z9GN\u0016eIa{So?Qj#_wwg?\u001f'0j:`\b&rdk\u0012\rjk\b\u0014\u0012\u0010\u001a\r:*y~9Ke1,$V(\u0004\u0012Z-- \u001f\u001c\u0015ՔXgL`xrH\nIAk\u001f\u001cc\u0011!\u0007\bN\u0013V\u0016U\u000bcVZ\u001dd4GN^-\u001dk<!TL%l;\\\u0011Y!jq}*&-\"4H{(tf[\u001e\u000e\u0001\u0003N9HM04MԐֺ5F8P0\b#)}\u0003uH\u0011\u000bwDWaN@0݈U)mh~X@\u0010A<1B;B~s$XD|J\u0017\t\"4@\u001eMQӼPܷ\u001f3(螡r渭ɯ<\f\n׀g\u000e!\u0000\u000ezʞ!ޅ\u0007T\u001a!\r\u0000߷ƶ\u0000E\u0015\u001bi\u0004\u0017\f)5\u0005v\u000bB\u0016}MڶLm]4{b\u0003bܤ\u001bz6!3VʮW78Hޢ\b\u0012y\u001aV]QÐ#;#\u001a\u0000\u0014F\u001aq7sU\u0015NkܦT\u0012A8px\u0002.ض\bdN\u0012 dԗcm\nq\u0016as&\n\rf\u001f<5$Ul[@p=J1vg\u0019^ҋZLíꄯ6UZ~k+{0\u0006-\u000b\"*3XE<\u0012q̽r4w\u0006+)U>l`V\t#V\\_@5xw}C9GCT\u0003l1LKk\u000b\fR\u0019B\u0014a))ڿ^oUT\u000ey\u001d(WeL}ػ6Pv\u001f/\u00138\u0006\u001b\u000bMP| Ԁoі\u0001;{\u0019N\u001d@y)zǥC\u000eNC$\u0018\u0007\u00052[@-{yA{\f\u001f\u0011cTk+\u0007\u001bi\u0001PqC4PE/\u001c\\\u0015{\"EmChX\u0007\u001f#ҹe;~l3]QȵO.x\fY٠R<hȢ3\u001fcsA!h'u\u0017}\u0014x\u0016\u0002C953_r]4JkL`\"l\u0015 DAv:m\u000eP\u000b\n=r\u0011\u0013C\bY,ch69npjzX]\u001bʉ&C^JjQ?W<x#(;{9z ݢ\u0007\u001f\u0015\u001d\u0005\f\u001c?M\u000fԛ#jz\u0003\u000f\u0006l EFIկ\u0019w\u001eCN\u0019[à\\\r\u000e\u001d<3\n\b^U;\tk\u001bճ\u0001tfp\u0000ZmPȌ%qJfxed.\u0004iF\u0003\u0015\u001c<\u00045'w(Vi\u0011#Cw\u0014B}2\u0004\u001e\u000e\u001dL稿W}ɍg`m\u0014/t\b\t~\u0017C\u0018j+\u0002J(\bf\u0004EM$\u0012tP/|\u001d\tL<\n\u000f\u001a\u0019i6-\u0006\rtr^\u0003@E\u0013\u001b8\u0016l.\u0013֭-4tj6Y\u0006*\"_zσoZI+\u000bXIz\u001f]V\u001bjWOad}!\"\u0013\u0001\fG\u0007\u0016UP!\u0002\u00193xg(\bWVKԽ<oKzPtQE\u0007Vv@k\b\u00178/`x5:\u000b pJ6\u000ej=ȫ{^y<'+Nbp#nt-*)7D(S@S-<\r6FmEfuR\u001a!N{eʻR9v P-ڡX7\u001e\r>\r,ΑU\u001b$v\u0016lՆ=Kq\u0010Us\b*\u0011r}@[2cQ_<\u0014Q`l\u0012}Nk\u001c\u0005_mPJCݫhP}'{@\u0012]ʁKۆ\u0005V#D\u0000\"(J\\rTi1V\u001aړ\u0010`r\">G\u000eWn#p`tOK:#s_h\u000f,Dy\u0003Tx]aicdFMcԺG\u000f&\u0000^\u0003:>_Jf\u0005\\9IĿi\u0001\u0005\u0001E~=b3b@zE1FΩUb\tdq!\u0019\u0007\u001f~NSD\u001bR틦2s3\u0018\u0000Q;s^\u001bʧ}uF&\u0004P7&\u0002ǆ\u0016\u001eF\u000f2q J\u000e\n\u0002W8\u0011U5$Aǟ\u0006H8a#iV۲G0\u00019x6{(\u0011L\u00136\\xn$\u0005_ʺalh\u0001@JR\u0006züV\b>U\u0010\u0010?/\b[\u0002f\r>;<\u0016VpV&lSxlFx\u0011F\u0002S\u001fY?7cl\t\u0007hʹlK\u0006(\u0006vs$5\\3D\u000bZYkPݵ,k\b\u000ez\n(z\u001b~t\u001chj\u001c\u0018'\u001e\u0005E/\\u\u000fxMYo,^\">oQ\u0019ơ\t~\u0003Ej\u0003\u000fUg/k.\u0010cxőn-\\\u0005*vi\u001f`\u000bO:\u0012}\u000fK^p\u001f\fl:D2߷\u0018,R\u0001\u00012VF$f3\u0004A̟x\fo\u0011Rk`GAQ\u00011N,#B\u0012P\u0003f~ZϮCS\u000b+rǼ1;0jb\u0005\nX\u001aYmD\u0002\n-\u0017ę\u0000\u0016<\"r;ADR\u0016R%p7t\ri\u0002u#R\u00102\u0013\u0001y\r^&D\"cȃ\u001c@غޑ-,QN\f\u0014 Y_5&M<w\u0010\"n\t%.\t1h!\u00017\u0007Oi&p\r@\u001fb]\u001d\tW\u0004ųBnZN\r#P\u001eS+B\u000ff\u000e\u0018\u001eV\u0006\u000fEҮ&K\u0006Qxg>E=2S]r4i\u001af\u0012~ x֩3M>H;\"@\u0013Ӳ1\u0012i-\u001e\u0018*J,oz\n_t#d]=UمD̊\u001e}ԃ#F\u000bWZFGUr\u000f?\bAL\f֊o\u0013Pܼq\u0014\u001c\u0004\u0015pipk\f31\u0012\niAZ(˟RƟ'rCA\u00159/vs?Jj-\bM{a=4ؑ\u000470\u001dGȶW͈\rI<kr\u0016ҕp\u001ex-jc\u000bZS5(@D(\u0016)\u0004qg\u0011XC<z*9\fP\rx35\u0004rD\u0019\u0002%%.\u0018i4A۔|\u0018St\u0012L\u0015\u001b5\n\tb%@q\u0015\u0000x\bg\bdNٟ=\u0015gB|8\u0010V'F)ASM\rxH\u000e\u0015gmf\u0018q`igBYK\u0014F5}DpXW\u0015>Lhf]V\"AR\u001c(\u0005N\u0011~\u000f9-\u0014L*6)*^=4l7_\u000f\n6\u0002p\r$BWjȤ`/'K\u0016;Oe=\u001cQ[xp \u0014\r4(\b]\u001bYl8ay^\u001085租y/HNԧ_mzaΠUYo\u00009۪\u0014\u000fɬaG\u0019F=@7)nE_-<QWM]\u0003G 0IE\u0002\rLÑ\u001dIP\u001b-׵;\u001f,\u001c\u0005!C\tJt\u0006\u0011\u0014\\6oه\u000eq\u001d=Z^J+&_r'g!Sr;\u00103aB\u00020K*ҷ\u001fV53\u0005OK-G:H#\u0016\u0005Dݑ\u0002:V|w\\6{\tO\u001d\u0002!J$a.z,\u0014\u0014I+G\tʟ6(F@`\u000b^@(P<GeUh\u001db@R\u000b+;\u001f\u001e~W$#\u0015\n/V߰Qڗ\u001ft\u0011CW5('bKۃQTщ,\u0006a>+0@{4J@i]c?<SJ_\u001eUrۥ\rn \u0005p X\t,,i;I'x\u0003\u0004.s~.\u001b\u0004o\u00183[A\u00195\u001cYS#([#=\u0003\u0004\u001e2Vwiڏtg2\u001e=\u001f\u0018z\u0015)~\u000f؆<&LէO%Y\u0004\u001e:]zG\u000fH_uSyȷpę}?gu/\fL\u0016/s\rn}\u0010 \u001d=<oQot!?@\u001b$,ä\u001dP}\u000bx\r\u001f:nHa7kLM\u0003$UDN|QǛMª1\u0007.UDI 6\u0014zY\u0000ߊ5p\u000b}\"55ٚl\b\"2cp\fKDx]Qw\u0012fU~hB\ta\u00025%\u0010\"hV⇻ב\u000fV\u0006kMTK7\bN\u001ak\u000bog(\u0015\u0014;&._YG\u0019v\u001b7)\f\u0007=\"ԕ\u0014s=Ǉ\\@WI1FL\u00151\nJ^<A,\u001a8tV)sg)\u0010\n\u001e\f\\&.4\rQψ􅱰\u0016\u0003\ruo-L\u0010b-\u0001ym\\\u001a:\nJOPb(\u0005VaZfk=rL֪5,D\u000fi%2DC\u0014\u0002\u0012{@{Hr^\u000f:{\u0016O\u001c{\\o%l\u0016\u001eVw\u0017zy9\u000bBU\u001bkc\u0016|!\n\u000f@V\nCv2Z\u0013P)\u0014\u00047\u0011\u000e\u001d,PMa\u001e\u000br?L2\u0000=s$F\u0011\\<z\u0001G4e\u000b\u001bVd\u001b\u0016=x\u000b]Q\u000eB8Ϡݶ&e\u0016vO\u0011{Aql=xoQ<\u0014z`+eD\u0002\u001d\u0001^\u0003CK\u00044zH\u0005J*^~\u0012(\u0006%\f!@e5\u0014\u0003\u000eb[ASyŇ'>\u000eGÐ\f%@4Tp\u0010>Co-1>\u001eaEb-_WD]jXy0\bmoh(;O\u001e^9\\Z2j_X^6G2`o*\u001d\u0011WIG\u0007cm?o\u0013;j-38V(F\bQ\u001cJ\u001fȑJ\u0000\u0015\u0000*Y2[\t\u0000V̎Z00\u0005,B1O:\"+ơbAc0E?<\t[\u001f\u0019B*FJ\u0002!\bAC&/?5\u0011\b\u001av@KSAa\r+A?;k񾡀\u001a(\u0003yo\u0018Ld\u0000IF$l\u0002'I\u0014KV\\imY\u001bkcJ+n  \u0019\u001f#5L蟔~\u000eƲ8FP'hE30ۯ?KBQJrg\u001b,[Ѯ\u001f?X_\u001f/\u00079\u001f\u001f\u001f~sr\f\fs?\b\u000f\n3G֕QB/|\u0003G\u0004*\u0007kpAz@Oz\u0019α)\u0004_I>\u0014p=W\u001e&\u0018>\u0003\u00187\u0012ri\u0000\nK[\u0016OoQD\u0000;%bRt\u001fv킿\u0011t1bR!\u0002]:@ObPY_\u000fj\t\u0012\u001aAJk\u000e,7hW\u0003\u0017\u0010И\u001bh_],\u0007:@lG\u001cP\u001a\b\t݌;f\u0006\u001cq}\u001a\u0001\u001dk!\\R,Vz\u0012\u0012\u0002C\u001dh\u0006r\u001e48 u\u0012q*XCE\bg9\u0012\u0012KC5\u001aî~S7u~B6Bl\\ D3AVjtqd*\u0004T2w\u001eY\u001f.gDklY#)/ ¦wϠ\"Hȡ\"3*\u0017#\u0018\u001bœR6v\"h\u00010f\u001d\u0013t\"h\u000fc.xWTD\u001b\u000e%\u001a\u0007\u001d\u00166\u0019ZOJp\u0005p''N:}\u0010hL\u000fU{K\u000e\u0002(%\u001a\u0001{EL_Ǚh}B\u001aJGv!\u001cu<]z|ׂ6zY9\u0013X\tW\u0002\u001e\u0013|\u001c~kH}ti25C\u0014\u001dicOCP\u001c;d\u0005u\u000eF \ta\b\u0010I\u0007\fӧKg\\\u0014U\u001e\u001e{,v+Ƣ*f=/\u001dY\u0015[\u001ec\r\u000f\u001e\u000bb\u000f۔5~\u000f/r\r]g\u00062\u0019\u0013\u000fi(1\u000bZܿCN\\I\"r &`9\fҳn]\u000fa\\\u001atf\u0000:>Q\\\\#\"#s=qhcn8\u000eM9ij1}\u0013^K\"\u0019# <\u001e#۟N\u000e\u0001L\u0019*\u0013K@\u001d\bIQܫ\u000e*7\n=\u000fl\rX't{J?6㥍`\u0006E)|k֓e\u0006B'\\\u001a\n9/- \u0014 ._}*\u000e\u001b0\u0001\u001b8yew4Â\u0012NᇈO/[\t#SJ,@\u001e\u000fpY&e\u0011wq[\u00054Uj\u0004җi<R3ó`xgX\u0018b^\u0001*\u0014c7\u000bP\u0005!EP؋\u0011n*a\u0000va\u001bA}\bݠ&\u0002QXa/\u001do\"[ B\u0011xwL\r\u001c\b\u0015atg51l:m)&k߷\u0013 bkrB<A\t2!\u0002<\u0003\\\nv>(EM\\M1#AҲ%il<+iL|G(t{,L~aԚ@\u001a̞\u0004\n\tԑ\u0004O'bO~\u001e1&ǋOI@06^n[\b\u00064m\u0019Gp6\u0007]\u0014Z\u0019N\\?Ac@\u0002<Ubpps5p҈\b*DYC#+ͨ\b\u001dZ\u0018Zyhq\u0012E!~&]\u001a;\u0005\u0012sr\u0014\u0002:4Ѓ\u0013@\u0003\u001d\u0005`VjN\u0001իUD\u0012-ڛjs\u001br\u000f:\u000bL7u0id#v9n\u000b\u00153t>LvL֣X99M{ZnI\u001e5\u001eT\u0016x#Q\u000fE@\"CReY;\u00024sz̯3Yo\u0000\u001c9\bp~&Wv8~\u001c1Aֵ!MER\u000fb[#\u0011\u0012\u001bbΤ^\u0003`z]&b<\u0016\u0003D*9|S-6+T\u0004uKm_3>i8\u0007\u001c\u0016+\u00057\\ |0&\u0017QNp_WTG#LQo0Ba\u0011\u0001\u001cб\u0011A\u0013\u0006A>\\X\u001epa\r@\u001ce'\u0015!;uҮ\b\u001cir\u000ed@ ?s4F^z{\"2\u0007\u0015hLu*\u0006n]8Y%\u0014K\u0015Ay\u0005\u0004t\"<\u00006d3D\u0002\"\u001fi0N=a4R)R/K\u001ee9b\u0010\f\u0012p'\nfQG915\"\u0000\u0019;<\u001dm\u001bnR[ b,!\bq!4,*r~jTM \u0016U\f\u0005\u0012D蘮c\u000et򞬈=3M\u0011:tt\fVZy`kT\u001eݎ\u001fJ0A[\u0014-p\\\u000b1^\u0002\u0017\fJ\u0001Jf\u000fh,L\u001bE\nMCI\u000eU\u0006?lL\u001d\"G|ɮlp[7ĨqZZg潝\b\u000b~\u000b |rd*8jx\"oh\u0002\u0001u\u00101X6|7\u0005qPXA\u000bFjSN[MNOO֦\u0019\b9e~$D=v\u0010tݍ\u0011\t0\u0001f^6ݺz-O#u\u001a#\r\u0010oFPbz5\u001d\brгdC*1*\u001c\u0014YY=z|\rOn\u0007\bH\u0001@tKL\u0011\u001an3\rS@9i\\loQ!\u0001?h\ti\u001du2x\u000e\u0014)~4;kuH\u0011>8~Y١pp3;y!*}oҢW=\n)T\u000e\u000f)Z\t6$mbMe,@x\u001b+\u0001\u0015\tG\u0012~-'fm\u001c@\u001c\u0013?\u0011z=6-)\u0001%fZy46a\u0014ֵ֕XWb\u001f=\u0019%\u000bv\u0016έ\u0012v\rx L7\u0006hULw3e]Qƛ9/U4ʚ+Nm\f\u0007J^v[s\f\u0014Q\u0010w\u000fy\u0003JKkyVC^%\u0011ogkI1\b\u0018BՋ\u0001AE\u001d\u0000\b|\u000e7N\u0007\u0011\u001d#U!U'B\u0016kp%\u0010\u0004;s\u0001ےЌ?\u001dʌۼ#(\\M\u0016X\u0005G9J\"SgEV: wYGJRtG\u0018\rP7դE\u0012~\tb}BtљcIj%SwFd\\s\u0014 NiǷ\u0012Zbt\"GS\u001bQGw?\u0016p\u000fZ[9\u0012L\n|O+\u0002'\u00017WWbV\b\u0012\u0012hކy@0#V=BY0&d\u0007d \u0013#}l\u001ed\u0014̈́]\u001f\u0017y{sm\fT00G~l4\u0004`wm\n3\n\u001d7\u0013T@3G\u000e\u0003(:[M0\u0001Ci؝H %m\u0010Y88VVM-\u00186`ϟL'\u0005AI\u0016M\u000f\u001fPbN9(\rF~/]%_u!\f.\b\u0012L\u00024SVKʫ\f}7x\u0002 89G\f05|߈OqD'7r\u0013\f \u0014Uħo\u0005oo\u0011\u001eI\u001d\u0011\f}\u000f[,|\u0010F(3э:XPﰄ9G\u0004L5\u0002n~>\u000e\u0007\u0012\u0017,ԉK芘B\u0019h&KA\b{[Ǉ\b/S\u0001X1%~p\u000432sq\u0016-+C\u0004<({Cgu\u001eM\u0002W.\u001a\u001fsjhswƹGxM#\u0012Y~<\u0001iICv;ˌ\u0000r{\u0004Шf1{\u0016E\u0001\u0002r'D\"H+YǾ=\u0003&R\u0007s{1v\rޠZ&>\u00003\b^^Tdh㢗0H\t̡Ezm\u000fh3E9\u0004lM.M7n!4B`9\u001ah\u0012aW3r\b]EXr=D\u001d\u0005-Q6\u0007Own\"Zz\n\t'\u001dr UF]RReu@ڣ6\u0012\u0003\n>,\u0006\u0013\u0006\u0016\u0019f.ϫ\u0013\u0017\u0007@v\u0014p{vC&oM\u0016VƥZJiQ\b(\rg~\u001a\f\u0002˔Hߤ'},^s\u00180nݠ\u0002.\u0016\f)]a7.8i}\u001eV[)GDU\u001a9ҷQ@k@q$ўp̐좸Re\n$h{ZJ.zIwr\u0006.p#٤c<Qp\u0016 ^Hˇ3%b1S\\#\n\u0013۷'p5~\n\fkpfegܧ~g\u0015{B2Jf]\u0015\r+\u0016P\u000bO]ms|\bW+bH`\u001f\u0000&\u001aNn0\naX\u0004f:3؛\u0012\u0001\u001cT\u0011ך\u000f\u0006\u001d!ϕ>Rc԰4g\u001eE+\u0000\u0013\bzS\u0018L-9\u0006y\u001b2]H_]:\u000bD*!*.}%孿\u000ef Xå\u0005\u001b5+/S Nr)y@FȺl\u000bo<\u001aƑ 6\u0000 vJ@U뀞\r \u001b\\Ou\u0004֔ 7ц\u0001N\u000fo䔳7\u001bKy(܍=h#¬5d<_K\u0000(\u0015\"VR\u0016\nfE\n\u0002a|\u000b@FZn{d\u000bG\u0001<s\u0000L\u0012\bH\u0016z\u0000KctwuD'v]:Qz}\u000f]n\r-\u000exH\u000eOʵuN\u0015U]\u0014\u0004E^yʮkfɞ\u0012%<\u000eo\u0016$F\u0011{d259@r^׮\u0004tNJ\u0001{\u001al8ЪV=;_х\taj.\u000b}1Po\u0011(=_4\u0000iVVKcF\u0016M\u0014\u0011\u001f\u001fe!n%Z\b@,ϲ\u0001S=C\u001c:D\u0001NL\u001dM\u0001\u000b\\aЉkh\u0012J#\u0003/&3MD<E!\u0005\u001b\u001bӖ37\u0001bŰcA\u0014`(r6-#8cqF\u0012Cln'`͂\u0016/\"\u0005-uwh\u0004\u0007M=ĥV61]Mڏ+\u001atFD\u001cOH+@}+\u0019bX\u0010\u00137\u001bpqr/>G\u0012\u0000jFAGJA\bzG7%j\u0017w9DҚ#yzSQþ-|E>c?P$!)F+c\u0003:l\nUoZen\u0006\u0001Ϻ\u000fTU{UUA\u0012߾\u001fy\u0011eUu\u0006!]\u0019mgiO[\u001e\u0004׼P[QM4<Hu0|\n8ܯ0F8X\u0012sxE\f4_GҠ\u001d&%mH\\-\u0011H\u0004z\"\u0010Bɑ_(;pC\t\"s$p_%?s%}s渄]A~Gdp* zțk7r)YB\u0019yv]]1]IQ$#PA;c\u0017 >?\u0005\u0016\u0013\u001aX\u001aVK{\u001dG+\u0014g#mۃօDb[\u001ap\u000bru>5\u0019H\u0000}#m\u001c\u001e\u0019\u0014m1\u0017Bt\t)IT\u0010z\u000f({+j\"\u000e\f}KFr\nk\u0004BD\fjTy$\u001b\u0010uiV9Q9\u0017;liΦr\u000e\u0005Uܥ+rPlzy)Wn#\u0014u4VB:I]\u0007&m奓p\u001dg \u0001\u0015dh\ftju\f|\u0006\u0005M\"\u0013q\u0001\u001cs\u000b@fE0T\u0018֩g=i\u0014aҽ^KO;G\u0010E\u0014\u0010S$\u0003\u0001VZ~\u000e_O$r[h^M\r\u0004\u000b(\u001cμ?{.|YG ]X˒m{^QXQ+_tf\tBb}oIr\u0000SdfS \u0002R\u0004=;u>}˚w9ItƹQtqW܎C\u0000\u001d:&\u0005}Zɩg\u0010\u0019\r\u0010jh1#Ib$Y?(b'W9\u0019l͵V\u0002~@\u0011MT=mzt2ڻZy\u000evFdl2\u000e\u0018Ol\u001d5\u0006\u0016w<\u001b9˂\u001f̑#3ۼ\nۼl\u0016WF\u0005mQ\\/#7A,G\u0000G\u0014#\u001d%\u0007_̽Mg\u0005\fQ\u001d\fM\u000eWs&18@8\b5\u0007\u001e6\u0003f\u0000\u0013q)\u0001$`Z\u000fZ忱x\u0007u\"\u001b~n&؎Y޳G\u000em:.\u00144\n>-sfX\u0010X\u000f\u0011Yd|AgnDh%kݦ>\"|\u000ey\u000e^G\u0014&\\l^\u0004\u0010{\\1-\u0013Əx3~t޿W}I`ψ\u001e\\CIr<?\u001c\u0007\u0015{9I^!\u0000|\bhr]GD=xrpQqu\u0006\u0018\u0011p;\u0000\n#Է[\u0006\u001eɋ\u001enL?\u0010-]U57e9zMMD+\u001c(*y\u0000\u0017MS\u0019Q̝\u001c\u0001\u001f\"BUM\u0000^\rs\r2XY\u001e3e9\u0012G\u001fh-#h9\"n#zAq$ªk\u0011BҸ+8\u000f|*s\t~d\\}|.P{\n\u0012t!d\u001f\u0018@נ0䇠t\u000b#YT\u001c\u0007=\t\u0018\u000e)S姿FE\u000bS\u001axtiA$\u001d\u0012>\"Po_@?|\u0006Q8/\"\u0014q\u001c¿nX`(\u000f\u001chmN}\u001e`#\u0016\u00180>8|\u001e\u0007\t'*X̪\u00155[Mwkty\u001ewHߠwF1x5,$K6\u0000\u001f\u0014:4D\u0013\u001f!28r&ܣ.:S\u00163\u0013L㑨}9x\u0004%pz\u0017\u0001(\u0012\u001erm\u0004/Vw]O\u0016\u001d\u0015Ӿe]\u0016~\u001d.'\b \u0001%!W1mx\u001fQ1ɋ\u0005ݩ#2\u0015?x#6IXӄ\u0015\u0001- \u001bl\u0013u\u001cQ>J\u00131t\u001a*\u0004\u000b\u0004\u0004u8*PkZ\u0011\u0016q\u000e\u0001oMM\u001cx̤)̨3\u0001dwfW5Ul\u0004w214Hq\u001a\u001a\u0016plU\u001f`\u001c\u0011T5W0\u0016\u0013};O\r(i\u0000@-\bNuL\u001fQK>\u001bʠJS[F_!\u00035޸*_(=ؒJy>\u0014,ǉu\u001e}Ar\fW=`N\u0003#4\u0016&\u0010B\u001d\u0003zih N\u0004\u000bDaGVG\u000e5ҁvS\u0016w&p\tk#i\b|tz\u0007޵Y|\u001eԁH1bsÇQ\u0005\u000b2\u0017d\"}iI\n[_\u0006\u0018\u001e\u0001\rl\u001chO\u00053?޺}\u0019\u0001%7QQ\\\u0006\u000e+\u0006g{Psa.\u000e\"ڲfq\u0013̠po\u0011̷\u000b*co\u0011\t\u001ai\b\u0002h 贆!J\u001a&İ>h\f0Ru<-- Q:8ϡN&/CE[\u000fψ7(\u0004}F!u'kta%PJ`tڑ\u0000dKP3I\u001d\t<4YXQ>p\bA6Xc+l\u0007lfʹ\u0017G]2~\u001ej}\u0001JL\f'\u0003!('\u0000\u0012[=\u0007gI\u0010U\u0003#\u001c\u0005ӝ3&ceč\u001a]\u0007^$jL UN\u001f\u0010r+LCUդ1 Cǰ>r1'\u0010\u001a:\u000b#C\u0004x\u0018H@w\u0002\u0011`ђ\u0001wVh$pi\u000fw;\u0002X\u00010A\u001b~~#\b4q\u0001\u001b\u000e\u0003~\u0000&GJK\u0013|\u000b$T6<_ θ\u0003x0 䩽\u001a]rO\u00077~QXQM)@q8csvf\u0011\u001b&%)\u001f\u00114Mg]du\u00117S\u0013k\nąv\ti֠cI{#H\"r\u001a]\u0004>֬75\u0012/\u0000\u0004z<M.kؚ\u001a<3Bvϓ\u0016Y_\u00026y\u001b=]Iô\"u\"DuPFIED\u0006q˝Hg<\u0000\u001da\u0007)\u0004]_\u00190K\u0002NԻH\u0010:\u0007A@`\u001bxpAه#~K\u001du>r2\u0000޲ ~\u000f\u0004)3靜\u0017ߛ@&{;k\u0014gVA8R\u0005\u0001\u000e\u0013.K@)(9裝}bo\u000eiˁ\u0011nhqzq2,\u0019s{\u001d*\u000elX{~ze|\u0000Yj|dhF\u0001SA?։=\u0011oc\u001fS\u00033\u000bl<\u0011\\\u0005\u0011!\u000fF|'.K\t%\u0001d^\u001c~\u0005.a[fsv\u0001=esw4J祈{+se\u001e˹\u001c]7P!\n\u0010\u0014\u0017F\u0013\u0006'/\u0006BA\u00007\b0\u0001H,\r\u0003&ap5\u0014\u001cR\fp\u000e%V\rݧ\u0007~\rxpU(\u0016qFQ\u0014rū ם\b\u0012\u0004J>\\\fp\u0018h\u0004A|HˇxWFԩs@%\u0018f#h\f=x2\"9o9\\_\u0011ѻ(KΤ>\u0016_\u001a]\u0014h~\b\u0016\"x\u00068^@\u0007\u000b\u0018fL0\u0013.\u0003\t%`hԳ4x\u0014;r\u001cr~c\u001bCr\u0017\u001d \u0005wrkdP\u0004\u001fV\u0005a\u0015޺_+a\u000b\u001cb\u0000`剎S\u0007\u000fz#teiy\u0010Q\u001e|+\u001bVǅG!\u0003\u000b?nW\\y=\u001d\u0003\u0001\u0001r_Ptækc0\tv?͐t9\u000fǡ~V\u0015@qlBv}tF,R9\u0002\tl\u0007m\u001dWb]V\u0004\rH\\Ib2\u000f\u0006Ɏ\u0002[bGbR?0=v\u0000pN\u0017݇D]I8x\\-%>\bY\u0003؍gr\t\u000b\u0001C\u0015D8\u001bNgΫ\u0000וeDi\u000fe`\u0001\u000fP=\u001f\u000eHU\u001c\nx_B.W\u001aĭvRsGt\r.)\u001b\u000bO~Ƞ\u0001\u0001q\u0007m\u0003א\u0011j̨nR̨PJR(\u0001(\u001aYݏ\u001aP@;X.<KL:Jqz?uȒW\u000e\u00033z3\u0011V\u001fYGiRh8CZ<~%I܈C\u0006\f)X9\b<C:Z苋ɧ9\u0015Tۙ䃔#\u0006\u001a-\u00016ѶQOt\u00191\u0001\u001f\u001f\u0006~g~ b7PD 셿2;a%\u001b4lV(G$\fL4Bd\ntE\u001crtT_&\u001fI\\K\u0001\t[\u0018=\u001anQ%5\u001d\u0014\u0015\u0012\u0013Ɏyi^t\t~w\"V\u0004\"A\u0014\u0018\f\u0014\u000ePB\r\u0001\u0002{#/fҵ\u001b\u0001{\u001a\u0010oCqNŐU\u0004\u0019R^#hb\f\tB,w\u0000\u001aW\u0004Q7V\nb\u0007`{r΃^\u0003X\u0004}:C] \bm)'\u0005\u0016ߟ1ҟ\"\u001b.\u0005`eر\u0001?\u001aM_[\fq׌i?..m/s-ǩ[4\u0000\u0012\u001a\u000exw|+\r\u0013l}S\u0017Rr\u0018U\u0014|\u0003\u0012ql)cDF\u000eX|㏶\u0002r\r\"\u0001\u000biS\u0003PKi\u0005E&++\tGhhn-\u0007\r\u0007QF\u001f\u0014\u000e\n\u0012I\u0014Pm^! i\u0002`\u0012}b\u0007QT5=A3\r/f\u00182A\u0019EnG\"A9ѥ\u001b\u00013\u0006\u0010r^\u0007a\u001fI\n\u000e_\u0004|rx7M\t䬻0\fe<-\u0018gEyO\u001b HI{!^L`+Vbs\u0018qs:\u0003O\u000e@\u000el@\u0004(w\u0010n-2\u0012\u00189vFNu.fnx|!mO1Au\u001c10|z0`{<k;57}W\nW?R\u0002.*JvL/\u0005\u000emT9N\u00147h\u001950JBO@5r\u0002|嗌&K\u0011e\u0015$K\u0013C\n`Jp\"bcY3\tP8-\u001f}%\u0010\rI\fI&\fؚ}m\u000f\u0011\u001d\u001d\bhh\bA\u001dǈ_6eN6}\u0014K3Q)͐=P\u000ex~N9WN\u0000\u0019\u001eK\u0019)e劋s:%hpZL|Y|'D 6qJF\u0017\u0000e\u0012|Ur\t\u001d\u001b\u0002,\u0003لX߲v\u0004<'AA@j>6=D!f\u0000d\u000e\u0007[\ntx\u0006t\u0018zk]\u0010a$\u001fiM\u0011* WGE{̭:dA\u0006>]6\t<*0..)Dmsv2r\u0001(\u000ev\u001cE\u0018\u0013J\u0010!\u001f]\u0004o qFN\u000bJ\u001dwU8\u0002P\u000238{KZZBpBAWR\u001cŤ\u000bC\u00027w9Y23vD\u00156e\u0014JuB\u001dnٴK)\u001f]A֮\u00107\f\u0015\n6L\u001a\u0004Ih\u0005:kZ\u000b[eI`4\u001b_Mi4&\u001f+čp\u0003\u0014_ _\u0014\u0015f32XB!P<\u0003l \u0001z̓A*],\u0005\tDգXa[\u001e\u0003M\u001do^|(\b\u0015\u001eD*hjqm\u0006Kz/_\r@O\u0010b%M\u0016w\nr$a\u0013eށ?\u0005?G'=x:Y8ǔ.:\"$X\u000fY\nB\u0005\u0010Z\rDAw٩6M#0Kd\u0018^E8x7hAJz<0g0TD˽E\u0004(k\u0005\u0006\u0011~=DHX3}\u000e#ګ32\bu\u001dQ^wDM\u0004h\u000e,*Li<\nKz\u0004A\u001b\u000bK9P\u001ac\u0004N.5ȕN2=RT/\u0018x\u001a*\u0004i\u000f(<7\u000b\u0003\u0015\u000ea/\rˎB֒\u0014e\u0015=bW\\\u0018F~\u0016\rt\u000b];A|\u0011\u000b(~kLZ\u0012\u0013A\t>K`z\u0003\u001d5bu)V\btW\u0006\u001b\u0005F\bu*V\\r˟|\t4\"jJ8j\u0000\u0000آ&\u001eH)7\u001e;YŴWK`\u0006[(+\u001bۺ\u000eFw?ť\u0013T[;\u0007mȟ`]4XwP`-\u0014H\u001c\u00173CА!ޣ/^\u001bHc\u0019C\u0006\u0016/s/\u0003x\u0007e\u001b?D9\u0010BPϠuaBK\f\u001aV%\\jut_e$\nIy\u001e\u0005vA\"PVadH^1c] ~Ɵ(f7J\u0013l\u0003\u0012?k?\u001d\nHwڤ`W9MF\u0002)\u0019sOڵ7O=%g{/+pA\u0001b\u001c\u0014\u001f|\u001aAL;\u0001<\u001c\u0005(W\"tGt|pN54\u001chʮ(\u00021`\f\u0013칒eg#)GYǟ>|l^2ŒmٴEn\u0015*\tdc\u0004`TjC\u001b\u000b\u001a)\t1\u0017=SZK`h-B މ}y:ZMĳuΤ\u0013\u0015<~\u0019\u001dY@=ҙ@\u0015=DXdcp ,r4ʘ+VībML\u0014\u0015Q7X$ˍ\u0017:\u0011\r\u0012Wʚ\u0010%B>\u0012Y1\u001ck`\u0016*\b\\j\u0003֝REwHKXR.\t\u000fBK\u0016}D\u0002,\u001e<\u0006ʚL+X'\u0007\u0014v\u0011kl.E\u0016*\u000e1H4x֗uhP(X9O\u0004uZ3H̶;0\u0017\u0007my?\u0014\u0003ЈMwl/u,\u0016OL0YRy9\u0003\u0005)\u0016T\u0011\u00025hBwCe\u0010G\u001b\b$\u0007&\\oBo\rs}Ϯ'P0|ݯ4\u0013\\Y\u0005,}\u0000i\u001c2.`\u001f\\@_\u0018kdZ\u0015[j[\u000bŪOȪl>]<4vİ\u0014]~B6\u000f_AG,\u0000*=\nP)Ve\u0004\u001c\u0006Phh܌\u0006^j\u0017Za=]d߭\u0000\u001dw\u001dŚ(\u000e\u000e\u0007/\u0001n\u0004s&iL̶bR0\u0012\"W \u0001\u000f\u0002\u0005\u000b7/Is\u001f\u0007Y|\u0015M\"Z3y`M(\u0013\"l\r߃&bIc(7աP\u0012/2[U\u0000/x\u0006óa&\nGq\u001d[N4\u0014Z#̬\u001a=}0۾.GF\n$|\u0010#k\u0003'6\u0018U9\b׍LL?=f;g\u000eI\u0014*;\u0006Q8/\u0010|';\u0001W3B_$=%Fzzt8ӢH\u0019\u000fT\f9}\u0007LCrhJq\u0004T]\u001bO尼(\u001d6lG\u001ac\fI\u0018}aд\u0003\f\u0014nQPk\u0013-.|N\u0004Y_q\fk[խ \fQ85?\u0005\u0000 n)\u0006\u001e̅}Jֶȫ(\fDY\u000b_o0\\YkI\u001axo\u0014<\u0015ɜݎ\u001fz\u0014qM\u0006f SMK\u0011%\nZ]\u000e,6\"0\u0004MQD*3K*\u000eZ5D\u000eno\u0017&24,\r=\u001byf& \u000f\u0005N߮Jd7:\u0006\u000b^{xlG\u00144iFUJ.\\\u0011և4\u001e!\u001a#;\u0000\u0014O^]UU̻dLnUlm3de8\u001e\u001bx4PtB:\u0019\u001a\u001c(5-\ff(Uыg61[\balU>]\u0010\r\u0004/OY(\u00078\u0019>HE\u0018 %ZJǙCI}WS[=K2uշ9c\u0014\u001eQ丽2|\u0000\u000fN@{d\u0013J\u000bRueV!1f\"#\u0001R\u001dL\u00160$VP\u0018j\n\u000e'_N\u0004\u0002Ȉ2\u00032#\u001cȕVo\u0000\u0010}\bgMzh\u001cC\u000fԣ3a&\u0000\u001d\b\u00123\\#֏x\u0000\fXf)\u0017\u0015Z:Eb!b&_\u0004j.F\rj\u0001܌\u001fm\u001d1f8;+t?̮nu\u0007o-i\u0002Ң??\u0007k]3\u001a$0Wq0px\u0000\u001e-\u0019&\u001a\fVpx\u0005\u000b:(\u0003+\"\u0007S?Vc\ngfz\u000f\u000b&y٭\u001b\u0002\u001b_nQ}\rmU}՗*ج\fy\u0004kB\u0007K*m\u0003i\u00079t\f{Y()S\u001b]wN\u0002iw\u001e\u0010\u001b\r=<w\u001eN[\u0018\u001b>\u001a\u001ei<S\u00159oȒ\u001dңE?N\u0012.;wn\"&B\f\\Q\"\u0017ϙb\fi$\u0012<}W<ݟ!\u0007Fx&\u0013(`\"g\u0018p-\u001d;쓀,;\u0003\u0012񥪼\r\u001bWQ\u000f\u000eN\u0015b\u0007\u001eP=hPSMFqٛo\u0012l虍W.\u0006s7mae\"M\u0001SPgND~{M6\nx\u0002Tu~\u0016PE\u0012\u0004\u0015\u0001\\|z6{@E?ǈo\u0016yk2\u001e\u0012WBbEJ@0b\u0014uVCw\u0004\nܴbV΄с,Q<þ-(DNVO(I\u001f\\w\u0014^(u\u001f\u001eL$'aTSac\u0006%W\f\u0003\u001dn\u0016\fs\u0014t(F$ϞT0J\bٱ\u0003ݥ5e-+\u0018G=s&*\u001f\u001f8WBaf]\na\"\u0017p\u0003d@}J=%5(\u0019g8\u000eԐ.?@y2\u000f*\u001ePnm`\"\u0012#\u0016O\u001b'm\u000b H_\u0006=\u001daƎqp\u001c*!܊ǚ}g\u001bI}\u0005\u0018`I\u0007ub3S\u000fa<WN.)sP\fS\u000f\u001aŴ[M'\u00137\u0002,z,m'n0^Cyp\u0016;eI_Z\u001c<q\u001a]T[FJ;\u00039\r\u0013\u001f\u001f5y{Ţ{q;5Ga\u0006r\u0004!ڋ_UF9[:8\u0014)\u0000\u000f\u0001̻!*&6\u0001Dۣ;Ls'\u0017\u0002'ڤYpd)\u001aQ8yΖ_b֛(_\u0019\u0015nkA\u0011\u0000x^YD\u0014V>z={]:ds``*(kgN7\u0005o@U:\u0016%QL;}@Q!\u00172;UxiS5\nhT\u001a_\u0018Bn-\u0002AIXf30r\u0015\u001aouČb\u0002f,\u0014աP-#&\u0000p?Ps~\u0014#txxA0]!Gl:\u0018#H;͙bhlP\t{f\u0006U\u0005\u0014?\u0010ķԷ\u0004j^$Av\u0016P\u0006\nY\u0003\u0007Dt?\u0003ލ%Xm\u0017Z%^!tt;,\u001b`sdCmHL~@\rx\\(%BC9\u0011>\u0019e|\u001a\u0011]L7,ϥ(\u0005SYvt\u0006\u000f@\t\u0019J~'\fn1S\u000b2\u0004,\u0002ޤb\u001f\u000e\beM\u0014p|#7HjeF;H(FS嚑hD`}\u0017\f|-g4\u00193%zha,}*h\u0007{\u0007hcGɗ\bVׁۛWxygʙ@sZ0KEq\u0007(FJ\u0003\u0013tp],&\u0006\u001e\u00023smnG4\"^*֋\u001dutlp?\u0003\u000eaW´5V\u0004Z/J%/`\\; I/\u00162oQK\u0006\u0000w\t<\u001b\u0015\u000e>a^L~%Ơ\u000e0D\u001a\t`c\u001e珆\t$HdA HfW\u0013\u001e$\u000fa\b#\u001f:k\f[֡S\u0005\\Of\u00172r֩sRY\u0015\u000fL(wHEp:>_X\u0004Yz-\b=Y8#*\u0018Z\u000bgQ\u00021~*3*\u0003\u0011\u0011\u000fZ+|Ywt)\u0005t/zQw\u0000y\u0018\\\u0000\u0016Ez\u0003}\u001f\rBuP\u001a\"M#r\u0019jL~\u0019\u0015_5UTE?>a\u0015\u00072skʽ\u000fKw*\u0006999'zTo\"~\u0002Ȇ\u001eu@w;N6|YƆsyn\u00040!@ЃϚi|3\u0013ZMHZ=L &ۯ\u0005\u00168R(D\u0017/e\u0006\u001d\\=\fYxR0;'I\u0004o\t\u0004bzm\u0012w?qHO|g\u000fi\u0012ݺ?\u0003'υ3`\u0004w\u0016ec\u00043k\u0015U+#N|$'RK\u0011Bc\u0014>Dks5,ɒQA\\{P\u000f\u0014V\u000f\fXZ^\u0007\u0003\u0003ʶ\u0000Ci\u0017u#\u0015s\u0013L\u0004dq!\u0019/9\u000fÐr;*38\n_N7fd\u0016a\u0017Q̨\nE\u0016\u001fآ\u0014T4B\u000bKס\"+(Vձ\u000b,Rj:r64cd\u0000\u0018?\u000b<Ʉ$(\\\u000ee=_-I%pP\u001cfl^\u0015_\u00026\u0014[\u0016tW\u000b\"\u001bs(iJq͈rZ,=B>ځT\u001f 9\u0015\\@\u001daQʤ1*Te\u0018p\u0016\f0\u001b\u0004\u0018\u0005i?-N){X*c~$!U\b\u0004/DT\u001a\u0006{\u000f@ُ%|\u0007\u0018)6:{UnHyJ\u0002\u0012ru]Έ$a)8\u0011R\n|ɽ_?XVj4f\rB9cYD+*udA)o\t*k8П?@/u.e3Ոк\u0005sХjn\u001fA\u0002]w\u0012<7f\u0018\u0006,U=%\u0013ڥ9B,<K GOZ͠֌m\u0014U}\u000eq\u0004/Z/,>G\u0017\u000bQ5}:\u0011:\nC\u0000\u000eL\u0000x:\u000fѢ\u001c\r2\u001c@TrT]P^a2_P>\u0000F(Ӷ#z\u001e\rym`T߳*\bN[z|;3_\u0018:$V{7&\u0010\u0002-T5,N;z2|3BsB\r\u0013\\T맕&\u0003\u00180e\u0000fӽJӡdO\u001eO(Q|X\u0006+]50q\u0000ݎHav\\V\u0004w2E7~\u0017bҳ,\u0010\n\u0006(k\u0003A3J`T\tȢ\u0013\u0001\b\u001d^nEK\n#rY:\u001ehV\u0003wM\u0002w\u0002zgc-7\n\u0004\u0011\u0018-p\u001c\u0014*%<WNve\u00013bB\u0006j\u0018#g;ЎX\u0012«;>ލ\u0014z\u0007*\u0003\u000bָ\u0014d\u001e<H\u0011:@G\u000bH~\f\u0005\u0002o\u001a\u001fT\fE$+\"nG.tm\u001cQO9eTc&[2v%cR\u0010t\u0004sk;U>V\u001d=BH=\n\u0018q:E\n\u0005\u001ft^ฃӾu\u001a]A\u000bADA;8\u001e\u001c{\u0014B\u0013\u00018PT7o{ج1\u0019/'>\u0011\u0007\u0004ԡ-şϨ\u0001\u000b.^Ct\f,Ǒ\u000fg\u0002@X^_\u0000*+m6\u0013\u0002z (?//-\u0018\u00123Qʮ\u0006\bcNk\u0001B69`\u0003fzM\u0001\u0005h\u0011hG\u000fn}toK7[\u0005Ia\u0013mU\u0012 \u0014OE\"K;\u0011*t\u0012x`-q'qT\u001b#3jow(\u0016\u0010oh7Ȩ՞ψ\u000e_?ǹ_u\tMthZ\f6/\f\u000e\u0019EyB^\u0016\u0014IIJ\u0000QW\u00008鸍hړ-1Ӥ_4忎/\u0014¶<\u000b^SpX\u0010p$zv3(KPO*ْa \u001at>kpx*\u0005:T\n\u001fptq\u001f+^uˋl(1\"%\fRC\nLe?\u00112Z\"d\u0005*Qu&9\u0016 ;^k/\u0007~ӣa\u0015QY\u0000`,L\u0000\u0004)_;`DU\u0011\u0007\n\"\u001eFJ\u000bjcU5\u0016\u001bN!|\u0002XȪ}vB\u001c_m#V3lh\"\\QA?\\Tv=+]d\\[Z]v\u0017K\u001a$>3QLM4\u001f\u001b\u001bd3\u0001S\r9\u0012;\u001fܼ\u0007\fÐ\u001f'~8#.\u000bͰ\u0019̤ v\u001eJB+\u0005+K_%\u0000/-D{R^\tG\u0001\u0002\u001c\f?}/7|\u0017e(|K}q&Y;\u00126y\u000b\u0007k7NM(\u0000gDu*\u001cwN\u0001%\u0001%\u0019\rVui\u0007#\u0014`Ӯ\u0000*А\b[\u0012S\u0006FٽvԎ\u0011hDIW\u0000T\u001f(.\\Ӊd|NXA!P\u0004\u0014\u0005;u_\"Z+LS\u0012iN|\u001fw\u0011)VƤ4DC\nH\u0013\t\u00126\u0015\"V:!aĄ\u0014\r\u0017\u001dB2J(0WQ\u000b8D#\u0003ߙ\b\u0000?)U:%\\\u001b7&c\u0011\u0019+ǱB\u001e\u001d\u0016(\"0%⏞gӑ\u001cWK6\u0014-zOj!&dUWh4pѯQ*t\u000e&(ȼ\u0002*\u0013XLw^i\u001d 6\"t|]v>#\u0013j\u0007ňEG\u001c\u0019a\u000f7\u0015%VpO8\u000e\t2\u001c\u0001L/RF-\u0018ψ\u0001Hm?DJ>\u000eB1'\u0013=v>?c;{ڷQW\u0017\u0012'BՄFMtM4LhnyEMEzM\u0014]m:X#5(\bݕp{`Mw\u0004\u0016\u001bH̯3!\u0003LO~\u0015]\u001e]}L`lR\u00131\u0004\u0012;ra\u001cLw:ܹ%C8TQ\u0005\u0019\u0019\rZ\t/Iް~8EGu>\u0000,t\u0014\"+Hɀi\u0014҃\u0011\u0019޿l,1\u001f\u0006܃&P\u001b,\u0013\u0003@~}FY\u0003\u0017\u0013\rfZj@\u0015\u0004\u0018\u0006\fKq(\u001a\t?;\t:G\u0010(7necy~~\u0018%H\rmc˾O\u000f\b.x]&Jr\u0000oo\u001a\u000eyե\u001fC,kd8%#\u001c7\u0019+o_tjuvV]\u0007\u000eD˦;HyQÈ\u001a3\u0016;qDsU\u0006\u0001'L\\\u00130+F_1&ӯ\u0015\u0000A?s\\VP\u0014j\"0f-<K\"nzQWe(2{\u001d\u00024U\\\rEA*x\u0013\u0000&guLѐQ\b\u0000]z\f9\u0019[\nzhdHo\u0017ߦqPw~VlTzNHs\r Kda\u000eϓeyD31'\u0014k\u0006O!}\u001dA\u00181\u0017\u0013\u000bvp^J\u001a3ő\u0005(?fzr\u000eu$16P6]yǑ\u0018Me45\u0014AU=\th6w\u0000f%!\"VO=.Oc\u0013x\u0011~\u000bC\u0017jkL\u0005\u001d\u001dQ\"cbe\u0016\u0012\u0011\u000e\u000b\f\u0013E^\u0000oQ*r\u0017=T*]\u0005\b1q~sA~1mh(Bv/pS\u001fb\u00104J\\a#\u0019F!\u0010VNk\r_W\u0003:\u0013>\u0004e.\u0000N\u0004T.\"HE\u0004\u001a73eQN0jH/I\u00002xL\u0012Wfg̿ ,g+Kם\u001dq`\u0010?\u000f0it&~3\u0000ջ\n\u00160N\u001ecVve\t\tza\u001fT`wC\u000b\u0013\u0004\u0018Vr:;ѡk\t,v\u00197\u0000_#svٞUR򴘊\u001d\u0019ܯN}e#e\u0017C6a]\u0014CS\u0015&jé+\u0006\foW\u0017\u0011\u0019x\u001b~IY?]P\u0015\u0007\u0016\t'b\u001c?W\u0015\u001b\u001e!&kt`VGS<\u0011~hW\u0001Њ\u001d^\u0011/\u001f39X`\u0011\u0011(gE!7\u001e\u000b\t~xj&M\u001ft\u000f=Dz7xԞhᎨ;\u0004uq\u0003\u0007):\u001aO8\u0014e\u0015ƈ;\u0007X\"dvr\b0v&{.\n\u000fU+iF\\-h\u0000ix|\u0017HÕ3z\u00014B1[<U{5X/\u0010<.iDox)(E~\u0001ԝә\u001d\u0011\u0012uq\\\u0007\u0019\u0002QZ9Fҧt>\t^+v-\u0003\f!D:\u0019\bZS19\u0001ҷuψ\u0014-e96tȭ\bgf/d\u0007eπ\u0015ו{̉9\u0003UN\u0014A\u0010\u0005IC\u0000\u001bR(\f-0<?#rhv*Iޯǹ\u000b%Vb9&>kvKޏ\u0018䢐zI\u0019T2qٔ\"\u0017G\u0011[\u001aH\u001e:O\u0001\u0014PA\u001b;~DW(\u0017\u0006{\u000f\u0011\u001cCL\u0000\u0001,}+\u0019?1L$\u001e\u0003U\u001cy\u0019;U\u0002\u00153\u001fvS:\u001eH\\\u0010Q\u0007nOϻh\n4ãAߡ\u0005>\u001b=Dv\u001dg\u001eg&J׺^xw[5Gïfk7 \u0010~U5 aj\\@\u0011,FJ\u0000ƽ3bA]N2^\u0016R\u0019aSϼ/hɓn.='|RlS\u0017\u0015\n\u0003Xٯ\baE0\u000f9G\u0014ۂb( z5mW/tYMwaDFRiˬ|)u7ՂX\u0013+\u001cSq|꫈3\u0019ED uvXG\u0001n{\u0014e-tJQ}LL\u00035\f\u001d_D\u000el@Ni0\u0004>=~G\u0003V\u00145<\u0006}w2\u00195kz\b.$'1?\"*r\u0005h?\u0017b\u0011\u0004XcF/\u001530wH0X?\u0018|=j¨(lwT?BE0eD(\u0003\u0014Y8\u0005yGx_`YUDY*\u0011\u0002\rf\u0007xn\u0017Sj2\rij\u001aE\u001b\u0018,!N_;ëp_\u001a~EQ\u0018@Ħj==#\n=\r\u001f4\u0002Cv'Eu\\\u001aR.=\u0016+\u000en(Oz]\u001e\u0007{\u0010k#\u00063`\u0018Hӂ\\(\u0003\u0015\u001do\u0018jt\u001cGcick_谌>>^JC\u0014]Q\u0010X\u000b]3pЈ\b[\\Z\". Q$%1\t]Ll&\"hڃ!\u000eAηK<\u00113\u0011'@,\u0011W(˵\u001a6֓d'Ԧ떓4ԨT\u0001}\u000e!\u0000tP!_dx_J}5mըvyAW`M]\nm\u0004K\u001fii(W^\u001c)\u0017h%]%w&\u0001\u00038\u001dOo{?0`V3\u001b\b]\u0012\u0007A\u000eǒg/(\f~\u0015Y\u001ez9Ί'{\\f l\u0012\nN\rP!>lq8{\u0007O\u0011E\"_EKqNPC\u000fk+Ξ\u0003@<ܬ(jfv\\\u0005\u0011g{oC?&(=\u0003H+w5g$~\u0017 1{\u001d\u00185\u0013%\u001f4E\u001d8c3U҉_Hu\u0016r`W=Ö\u000b] Z8f=$%\u0011\u0016}~.ṼDM>Kc\u00130JɎja->\u0019\u0018D]ݮNQpw=q|F춟\u0006,\u0011P\"4\u001f\n\u001f N0#hOr\u0007e\u0004+pw\u0001\u0001\u0015\u0011\u0011\u001dׂc&M.2r\u0010*_1o\u0004صv\u001fMBCDF~m1Z\u0011M\u000380Ǽ3@2ݝ+7~oD%UQ\t>QWУ49\n(\b\u0019e\t!bs%\r0u^u\u001e%2U32>g܉:l9-iz\u0003ݹ\u0018$L\fe廮Ƞ1H\u000b*i_G0No:2@}Zi\u0010-xG\u001fG4F<'?\u001a\runݺӥ\u00115$'}\rbDz_pk$\u00004&旴GT\u000fHwq̣\u00194]Rըi\u0016\u001b\"cHė<\u0010\u0018\u0012va<W$碿t7x?\u0004PT\u001d{~\u001fP\u0012%|A\u001dTСN\u000bҺ9\u00121~Ғ19\u0015R\u000e1i.)i\u000bs̴j\u0005m5=!A@U-\u0019\fP\u0012kx\u0011\u000epAW\u0018.y\u0011sF7O\u0013\u001fH?\u0019#\u0011\u0012̷\u0000Fl~\u0011Yf\u001d8\u0010\u000b;\ri\u0002\u001cQ\u0000\u0011A\u0010dj\u001fݍ&4\u00056:3Zv\u001f\u0011=?\u000b\b\u0012N\u0012Ҭus\u0003]cT6\u0011y/`\r\u0016]\u0006\u0019\u0015\u0004RS\u000eYzB{\u000fŘ\u0005`\t%\u0005\u0007Hphq#`Nji\rA{#\u0017-D\u0002^\u0019Zn[-\u0012\u0001Y\"m\u0014\rSt_\n\u0004_\u001bXA\u001ew}S&:.LtMT\u0011\b~\u00111h1]僩Bh\bbX@ul\u0000ۣVz-\u0005Hfś\u0000T w!¶Zˁ~]ľ\u0001]ϯYq}O`ߪR\u0003O}&*AsW8>Es\u001c[W)Js|-\u0003A\u0014\u0014Fʌ<=\r\u0015\u0006K\tGD6;\u0016X\u0007Q\u0002\u001e\u000f=E|I\u0013>S/oL/vj9\u0002\u000b)\u0007oY^\u0011\u0019D`&\u0006`ٔ~\u0018$zF\u0001\u0007D\u0004\u0005L\u0007̶.{faHF\rn\u001f]7܂\r1\n^JOct\u0004]\u001cv%E\u0010syfa\u0004Y\u001a_\nwv٫\u000eM\u001aX\u000bޯ\u0003PD |?}`xi\u001fؐB;PՉ\u0007W\u0000¨||1G\u0012qaH{3\u001b\u001713VMj)\u000f\r\u0002:\u0019\b9~yy\u0019G\u0013VWIR](kkG\u0016\n\u0014nFt\u0006`;UO\u001c%%\u0012Oie>~l\u001e<W\u0018Kpz<\tw\u001b;\u0016N`&\u000b)U\u001dP/R7.\u0018'b&b_H`\\;qQF\u001a\u0018\u001co[@x5x97W\u0002?\u0014\u001f6C\u0011B2*!6A:2T\u0004+ܪ-\u0017\u0005\n\u001d94@9\nn<\u0001t\u001e\rRAόG\u0005\u0016\u0011d\u001a$\u0014E:QHqR\u0016r\u001c`\u0014\fIhOy\u0005ijQ\u0016f\u0000coqk\u0011ѐ.\fbt \u0013\u0018_\u0005\u001fu\u001a\u0019)\u0002ܕ\u0001a3}2u݌g8pXGZ=qpNĐ\u00113$z1hy\to(W,؅\u0012\u001bѩ3`أ]>K~;+rQ\u0002eSfow\u00133}gi\u000b3ᾝVxvc\u0011\t_4Ђi\u0016諸ݼ5賍!Y\u0011\u000fgd!\u0003=Xރ/';Rǩr%A$w5T\r0b\b\fҾ\u0011ګR\u0019vA\u0014|@z\u0018\u0000_)t\u0013u\u0004?p\u0016Z˷#sŸ\u0016>\b\u0013s)\u0007\u001c.\u0015\u0005\u0019\u0004q[,f\u0011Wvs|3L\u0016wEjB.95g/4\u001cspId$BS\u0007Ԑs删\u0001'ddk\u0006_h(~xHi*|\u0010j%ކiL\u0007\u0001FL\u0005\f\b\u0005\u0003o`|FcE&&-;[\u0016*bcx(\u0012\u000f\u0015+B@Mxq\u0003\u001a\t2ڟ\u0010uA2to\tԓ1ϲ+\u000fviO_o'+w?\u000f?\u000fÿ\u00079q?wO\u001f[_W'\u0002^no\b59ҼL/0k~C\u0005?\u0013\rߨ׫\u0001w\u001bz@\u0005L~@V~\u0014`=̆6b3%~V'\u0013%6>Bn{q kWp\b\u0001h\u0005GR\u0010ɥDE\u0011Q\n[E\npȏ/,dޣ@DIާdgR=<uAE\u0013\u001d3_Q[oG\u0015f\u0004]ػ6\u001aI#'\u0002t2>#gfLa\u0005:?BI#\u001e$bm\u0000\u0013њǐ\u0018\u0004zg#3(U)oO\n0Ⱦ]OKW\u0015Viaȹ\u0019DU&)-\u0003Iap\u000f\u0004}*A\u0012@/*|\u0013l\u000e:rJ t\u0007\u0001z\\8r4)Fnu\nɃsS(\u0001at+~QjE\u0003E(QV3P2&\n?D\b\u0002\u0010#`Tݴ<3R\u0007\r7!\u0003:^;'G\bo@bYn\n+'*8\\\\oF3N0\u0004coW+ޗ1rq\u000e\u0002:\u0010ąfܤb\\f\\\u0012F{f\u0005KP\u0000gq9jOo0\u001b\u000fZLm\u0010a\tHz\u0017.\bisA\u00160UCE\\YטTu\u0019P\u0015Es0um\u000fDI@ν8p\u0004c߅8X<\u0017\u00197M\u0014\u00150<x=\u0019\u000eFab|EG\u0000Q8\u000b\u0010F\u0016\t^+\u0011\"v\u0003!\u0011~<_\u0011)\u001dT>\u0005\u001aݿ&MWLJ\u0004e\u001a\u0011\u0019w\u000bV7]ә\u0004\u000e;ۇ9S\u0018]<@P@\u001c0}C\u001fg|Fr\u001b\u0010+\u0002\r.VM\u0003\u000bh\u0019DGGM\u000fW\f\bѿ\nvÙE\u0002?#~zt?o?g/\u0000AGzO<\b.\u0006^)}RMy\u0000L!>\u0005@.7^\u000bebL,U$\u0007vOޅPpn<\u0015DA;\u0003۝\u0011D̃\fQf\u0017e\u0010\u001bӺ\n4\u0004ya\u0000.\u001ff\u0010rm?p.T\u0010\u001bi\"\u0010\u0010c\b\\\"Y97,\u0006PU\u0013Н8ш%G_;/\u001bnc\u0015]:t\nlȃ=q\u0011+#\u001f|X]\u000b\u001d?yG\u0018$^+duY,0S˴BIIh3\u0019dN(\u001dxثIV\\1byҧ_N<\n\u0001t^t\u000by۷K`pBy-\"ԋPZ.=ѢiO\u0003\u0000q\u0000{;Eyc{w/f\u000e+=\u0003@v@u\b;\u0013P5SO\u0015=O5;U\u00045R1:YfPb\\\u0001Mr,وrw\u0017H[\f@\u00000\u001f9Q\u001b\u0004\u0015gD\u0018-Vd\u0011@\u0003{x\u0010\u0015֘\u0000&\u0003f\u0002ҭ\u000e2t-c\u0010r1}O!~3һ`\u0004\u0003CN\u0004\u0003w:8pt\u0005)1Br\u001f7G;%Q}\u001ex\u0014yWlvJ\u0001#{׍Ii#\u0011\\=י\u0000s\u0011\u0005\u00161n\u000b\\\u001fB\"s\u001e\u0015H\"@\u0014\u0011>/R\u001dbUh<G1;M?yDD>vQ7/Ź]hv[\u00010!\u000b^QcT\u001e{םi\fIqr\f=tб\u0011c\u0004D<;Q\u00122#Jݔ\u000b\r=3f.\u0001S>ʈ\u001aOP:3!Óc:nT\r\u0010{܋F*W0\f|FHf0)@c\u000b\u0004:l\u0015*\u001d{\tC|\u0006\u0010\u0001\u0007\u000b\b.ܷ\nH#>OS\u0019\r\u0010~~\u0012RHf9_>_/\nrд\u000fxAw\u0010ސ\tLy\u0018\u0006l&=/ɞD0^L\u0004bDT 1TGa#E\u0010~\u001cH\u0011Sf;cR\"hS'\"{u7UD-'Bbsor\u000bO\u001co\u0007˵:<\n\u0017`*)p-\u001b@w\u001a\u0003R7\u001b\"!NbM\u00062L(T\bjqeIVbIt@D\u0003}\u001fQ\u0001kGUQmB^*ؒ\"&޾-n}{/(~\u000f\tJg\u0010w\u0003i>]\u0019E:ki\u00156{\u000fe\u0011\u001c&r\u0016+f\u00078kJ4;\u0007!\u0001!M;Cz{S\u0019ӔA\b5X2\u0002uNx\u0002y\u0016\u0011X\u001dM#\"6\u001d\r!%\u0015ݥ1\u0006G\u0007,ZZ\u0006pOt\u001c`-\u0019ʹp%ihY\u0014DD#\u001fg\u0013\u0018i?\u0005pY\u001eFԊV\u000bFq/3;Y]k_\u001e\u000e6e?\u001cݞ3\r\u0016JM\u001b\u0011άxJ\u0001\u000e[(xxLI+]\u0018wk\u001ckqe\u0018qSptRL7vN\fi'Y\u0013s\"V\u000fK\r\u0018\n\u0012N?'\nE?{\u001d\u0007Jyyd/4ygyl UZtɾ\"\u0019,\u0016j3[1S_Wk\u00049\u0007\u0019[s߬eDر2>]_m@-\u000e5\u000b\fȗ-t\u001eK\u001b׿|᝶ԗq]2i\u0016FwU}\u000bui\u0015N\u000em8\u001d\u0000=\u0001mzX;{K\t.Yu\u0004\u00170K\u0017\u0010\u0005֊\u0001-W8N\u001etj\u0004{Qy\u0007m;:x\u000e=[\u0015逭k\u0005۟gKoA\"y\f/DYT\u000ei$t2*t<yx\u00155'\u0006FrAv!\\\tE;P(Եb#֛ؖ޻8\u001emfL.9\u000e;7g\u001agyN!Լ\u0001#7\u0003]ɽ:\u0018阪c^1\u0017z\u001d֠a\b@'\t\u001e\u0017K;\u0001\u0017t\u0002x\u0014ssn%d\u0015{q䔎#z4\u000e\u0007\n\u001f\u0001v,;X,52\u0003g\rNئT}\\ \u001f1Bs\u0013\u0019<:gp\\畽\u0016Ө;8/o\u0007_\u0016\u0013gutqzaF\u0013֐l\u00045%r\u001b9?|\u000fh\nȇ~Q#\u0003p\u0003d\n`\u0017юFF\u0019!\u001cί\u001f'^ƭ\u0018j\u0010=_IP]ggj\u001c:u~V\"zѭƣ\u001dX2\tB\u0003h\u001b(q\r\u000e.\u001c,!!0ӤDX@\u001c-CD̮y8\u000ej\tH/\u0011-3\u0018}6{}m-^\u001fB.\u0012\r+v\u001cK*GDj淚{8\u0000N\u0018\u0003QxWs\b4Y3\u0011%dł\u0015\\~#?q|!g@\u0018Qպ8U\u00116ؘ8NKŎ\u0005a{ 91w\u000f^Omܴ\u00142\u0001q2T\u0014ŏ0DvDs>\u001du\u0016fA\u0019-\u0011M\u001eݗb\u0010d\b\"ąà\u0000Ģ\u0018\u0010EAFҡ)GŰD))\u00129\u0000Ԣ؄\u0005\u0000\u0014Ͽ4罢ohrh<xG3\fȏ\u0014bdh%y/\u0004?681@\r\nڰBi{o\u0010\u001b+NQ \u0011KM2V=b͘:5q?\u001cge\u0012\u0012Â4tCZT\u00102@V:SLߢT,kN^bA\u0007-d\bVo\u0007+ox_rUyQZg˭7F\u001a\\i}WR\u001ceΛ+@D\u001cHeP+!0{Dԣ,\bWJ?\u001cD\u0005\t>o̜\u0005^e]%(ބ\rSS$2ZSK`cCf\u0012,yxV\t)lӾΤ:펺t\u000bsA.dw\u0000y'\"=MM7F^\u0015\u0012\u001aGNn\u000fwV&-c|T/pʖ\t~>9\u0005J2?HrQ䗚3\u001e}5C7\u00034S\u000e_\u0001&\u0011w|e\bB\u0017\u0016\u0001\u0010\fv(ZL\u0015\u0011F\u0014ߑ\u0018DAMa\rF\u0015_5\u0015>A@1\\P5|W+%'umKH͞\u001c\u0013\t\u0006II{\u001bq  Sj\u0003%L\u0016QAnz\u000f\u0005:\u0013A\"h/7\u0006\u0016&Z燧SO\u0016\u0019E-ds\u000e}\u0004\u0000W 1<OG_\u001elSV?\r\u0017P>\u0001#]f\bx?zp\u001a\u0018<+\u0006\u0015;?UYX\u001bf@Q\bq۱_=֝m\":l.'˭(\u000fm\f\u001bϰ}\n7۩\\Qf͍׸[_Z#\u0005\u0007Wߏr̫q\u0004C͓B-k|ӟ\u0011?ߣ\"(jfv7KҎn\u0017I]brbp\u0016?G5RE\b>|\rw$}w\u001c\u0014ӎ}V2ܾG\u000fqDM\u0010(8PEGcr}H\u001ao}j\u0007H\u001aU{WZ\u001f;7@~}X!O)\u0019=KK%DY\u000bJV~rL(|\u001eE\tٵ0JpVIH\u0003ϟ+#\u001f\u0014D7%b{\"J\u0018_'R=}c4\u0003@gۚ y\u0013\u001e1\u0011r\u001d)\u0004x2#T3\u0015S\tBҤcr}q\u001eZ%\u001f`}dV\u000f~U03YN\u001bcmSa22DG\u0011\u001ag8g\u0014GC\tGsͨGi/gMlL\u0019\u0010h\u0002'B#uD>0!ЩQ\u0002-oz\u0005[Ͱn®\u001eU9vD\\, B-KG\u0001=\u001c!8{ Evry҆H\u0019}eX>PL\u0014wj\u0005^|\n\n\u0010!\u0004sWy$8\u001b`\u0016k\u0000H7\u001d\u0012XBB?\u0005X\u001aKÿG5lQt(\u0015\bk瀮\u0015foc?t\u0006Ό\u0002of>\u0004ܮ}|\u0003EJ\u0007ec\\\u0014\u0019D?~:RJz\beՋ!\n|\u0006wt\u001e:.+{i_WAh\u001aA2Q\u0015HE\u0007r?\u00184\u001b@T'⟿av\tqE><+ߎ^\u001a$~Z\u001c\u000f I0]-Z\b(Ag\u001c\r *#pD\u0000W}]\u001dq\u0001\u0010\fzQ(rܴǱ\u0011JZ=p\u000f#;\u0000\u0019L0RX\u001e'I3\nX{S5QydGv\u0018r&P#\u0014+/F\u0017>=DXD\bkA\u00170S'\u0005\u001e\u0000k\b\bp}uU)C/3\u0002wa!\u001e:4a\u0005\u0013c[x\u0012\u001e\u0002~E\fv\u0018)MԊXr\fH>bp`P\bb\u0013\u0006&7\u0006g\u001d捚j/3*\u00169T\u0001\u0011(͔yމ\u0007{\u0003b\b\u000e{D~BZo췏G\u0007!\u00151߅b@y+*\u0019ŨugqS_aryy\f\u000bOoP?7/}.\bF2\u0010!n`\u0001?L5'u=x4Hۑ\u0019x\u0018*F5=G5\u0011Z9;)ǩ\u001a\u001b+\u001azNcÏn%\u001c>\u0004>w\f\u001f5!*&p]|a\f\u0002\"|>\u0003\u000ft\u0014C}6utd!h!8Ϩ.R\u0004b>~x+\u001eQQAߗڅ\u00007\u0017F\u0014%t\u001f\u0003\n< +u\u001aPNYb8w\n&*(.\f\u0002ځwU\u0015u\u0007c~zj\u0014\u001e>#\u0014ս\u0015՝*>.%a\u0018\u0019X\u000eT\u0010H\n\u001eZ\u0006+hY{N8\u001dKU#{Ng\b㉸o\u0017\u00156Rk9\u0007\u0011FDlv̚328P\u0002\u0019%yLa\u0010\u000f߽w\u0007ȂD\u0013/MںBl\u001aeƠhK2\\`\u0016\u0016Ў6퇈եy\u0003k8(t\"^X[\u001b/&/Z\u001ax\u001c\u0015\u0002}ѧ߯Lo?>ɿT/BZ\u0007Z\u001b\u0004?Tr={\u0004\u000b\"Y#)\u0018\fz#4L&\u0007'\ttJ'%{\u0002w\u001f̑GHwf?)٭ݿ͓r_q\u001aI¥FX\r\u0014\u001aiֆD%bD\u0004\u0000=N\"j;\n#\u0018,}()sʹ`6/6\u0000&\u0011%\u0001\u0018\u0010'c\u0017\u001bē\u0000MG2uƫp. 1G\\\u0001كK@y\u0002]ۏ\u0000\u001e\u0014\"{E\u0017\u001c ;xt\u0015\"`?2(}\u0004Z9Rt\u001e2g\u0007]TL\u001dQ\u0007\u0000۝Kho%A|\f06ﭩ\u001cf\\ϕZYѠ/\u001b]\u000bb<bQ]E2rxfjM*۽WJPZ%|';tAV\u000fh\u0019\u0011@<05^\u000eSoT\u0016ЄU\u001b\u0015J3KK#ji\rƉ2.äR\t[dow\u00141\u0010|5|\u0001n\u001e \u001f$`T\u0019\b&#7\u0015\u0000a$3#bd\u0014\u000f\u0006QȍHI{տ\u00051\u0015\\\n\n\u0012\u0011\u0012:5ׂ]?\t}\u0010\u0002@\u001fva\u0006a\\%c%ż3 \u001dКzu[\u0019o,\b@>l*TAqJ\u0001н`3\u0019\re;F\u001dO\u0001\u0002bR\f\u000f3t&\u0002\u000e\u001cPץ=_hTܱ2\u001ef/\u0000.U\fȓG73-.i\u000e~D\u0019G,\u0014#{!dS}\u0018J#\u000b!K!V\u000bѡz%\u000f([\u000eٴt\u0011Ly@1\bp\u00160\"\u0006I]\u0017Ѥa \u00198z\u0002D\u000b#gV^\b\u00049\"\u0005*\u001f\u001a\u0004РK 2p\u001c>G). ]\u001fee\u0000\u0004Eb:\u0001hkD0}R\u001c\u001dr6Bg\u0005\u0005y9mT\u000eCo,Fk\u0018=*\u001c;\u0001\r)_&\n4[~ߐ\u0014\u001c?I# v\u0007S1\u0005\u00011U\u001ep\u0001o\u0003S\u0010j!\u00023\b\u00180Y?\bEkN\u0006\u0019\f\fŪhK\u0015G@Q\u0011D]Xxga\u001e\b@\u0010\u0012\u0015);\u0005tOa/~PO|{}|<L#\u0019wQrW? B\u0004rq@d1=\u00120PZOa\u001fw\u001bdFHgh1ܱQ{y5\u001fp\u0013\";hAӆ\u0013c2ڔ'/J4UGXGeWinaR]U3'2\u0016\u001cZW4g4M\u0004\u000e#\u0005`Zd{\u00131ޯ\u000e\u00065N\b\nQ\r~t\u000eY,\u0001U\rorz\u0001\u000bj\u000fs\n\u0005Yjs\tA>^ꨄ=\nV\u00015ҐVC=O-%-\tB\u0014٘_8q&D\u0017y\u0012\u0016H\u0000X\u000bڇ%%>HԪRʁ|+&\u0005-0\u001f(\u0002\u0011\u0019\u000eE\u0003TЊ!& ㎯A3hຨ\u0014ƏOZN\u000enF~$\u0007i\u0000p>jobf\u0014d@m(\u001cB%}Y<\u0011\\1\u001f\u0003'On^ǞMDhR}]1Y\u001f=yE\u000f=\b\bR3ê%wgB0\u0014vbC\\\u001cq]𕟈@Yc&;V`.J\tA|x/|\u001dHBOƎ\"dC`&G\u0007\u0006%3nT\u001a\u0014w\nj<^\u0007IH)ҩvR,{i\u001aHz9s\u0005!\"oRFbFLmb{\u0017\\\u0014C\u0004ܒ+J-{\"\u0011tm\u0019\u001f`kSLή\"\u001f'\u001c\u0017hD.\u0018Pal\u000b6{5\u0002t#\u001a;\u000b[\t\f7`tMč*_\u001d|#\u000eJ\u0015|X\u000b\u0006o\u000eѴ^;=\u001ft5\u0014F\u0012//\u0019sI\u0005 xx\u0007\u0001/\fx\u0001\"ɍ\u0000%\u0019ȗ;Ԯk?_7^/\u0015\u0018=0<TGa(\u0017\u001eE]hR\u0001>\u000e'/\u0000m\u0015\u0018\u000e\u0010\u0003\u001dbRzȆ⣼\u0002h=t\u001f\u00008-;bft0Un\u001c\u00051ƮW*Q'Jv4O\u00140\u0002cCԼF,ߋ\u0019Q#n~-d\u0002~\u0010\u0010U8y\u0012\u0015^{9d0^\u0006؃7P\" \u0002W\rtotD^QeˋB5rC~SG[o5\u0017\bMqw\u0015\nY|!M==\u000b%m\u0003^xV\u0007aR.R\u001b (aEBr^\u0016\u0000Ç!5\u0007\u0006ɍ\u001f͍zZq\u0004\u0016+v?ޤG' \u001d\u0016?e\u000e]8*t\u0017\u0017@\u0016mق\u000fg->\u0007\u0011\bsh\b'ш}\u0017g;NZJ$fb-ݿ\u0006$-X#\u0005P\f?KH\u00047T\u0006):kz?\u001eKJ*\"I2\u001e\u0002dǵd23lBB\u0000?7Th\u001c4=)u\u0017U\\.2LB_1;\u0012e#\u0005\u0012I<3&A$O\u0016(ODɅe+\u0016?\bg#E|OUy\u0001\u001a&Q\t5\ny[\u0005˖?T[\u0017\u000b\u0013Q/m\\l\u0013\u0013\u0011.\u0017\u0015\u000f\u00176\\O.Hr>r`>^R\u0010ֻYZN\u0004a\u001d\u000bH\u00053϶Z}g\tkr,\u001a] n\bܜ\u0012q!LO\u0015u4\u00016y:\u001b\"z4DÉ7Fp\u001eUl,\u00006v{h(\u0014@eM` q$\"\u001f$j\u0014EI/,Q=B\u0019Ҳʉf(#.RO/e0`\u0018e'\u000e׵up1<6)\u000e\u0010c-\u001d踚O\u000fP\u0019 E\u001e7p_\u000eAtzaXuUbk䔫`{\u0017L@\u0001*U\u0017HeDj\u000b<)(¿q\u001f\u000b&}nh(Ԑ0\nkT\u001f\u0018pGj\u0017_u|0Tn+\n0\u001f``j!#\"\u00134\u0013zܾ(\u0011\u0013\u00076Hws\u001ahhT4dXj?@\n,ʌ!\u000fM9S_\u0016-ʕ\u0014\u001a=\u001bq\u001e\"~\n\\BoꭇQ\t?UPGܱ\u001b\u0011Nn޾o1aaIsrT6n\u001c\u0019*o\u001e\u0006\u001a]=\u0003[x\u000b\nÓ\u0016k\u0011%?\"Z75潎VtrP\u000b\t[&JH-f@~se\u0017K$\u0011\u0001q/o\u001bD4Hjb?\u001bJGV\u0001g\"5d\b<{\u0005\u0016 <]-]ЪSOs:O\u0000\u0014%ԥii}{p[Τ,w\u0005m\u0004q%Wڹ\u0000=u\u0004m\u0012&cw)c}83\rZ8\nG8\u0000.\u001f\\\u0018C\u001e7\u000bD{2/\u0007V\u0017[\u001c}cE\b\u0018\u0018t\u0003bg7ag강_-\u0007\u0000&S\u001ez\u0007<jܼ# D.س\u0019;8*u\u000e\u0019\u001d\b[#\u000b5L\u001e.&\u0016.iea\u0004ѷBc6٠\u0007^̒[A@\u0001T>j#54\u000fAfH`\u001d=HX\u000b~N\u001au\u000e\u0000lԧƜ@\u0017\u0018\u0019;!V\tu3=\u0003/% \\~\u0011.%0\u00027 >]lBͪ+f\r\u0018C\u0002V\n-7+(\u001cX\u00057RX\u0002\u0010J\u00194R\u0006QĽ\f\u001d*q$3RlMfWH#O\u0000t?\u0007[1w`\u0005OGߢy\bph\u0000A\u0003\u00000bJ\u0001W\tF˹,v{/\u0019'ꖯ\"?(!aX\"\u000f/;~?{Oׄ\\\u0018\u0005:\u001cVߟ[\u00130HFZ\u0001ю0PN9J\u00127*\u000b@*fÈ\u0004$u\u0017f3\nE3\u001a-wI,P%KO*\n\u0005\u0005\u0011-tC^z&LLFj\u000e\u001cw\u0014\u001b#Hfҏ3\\k>֎dx,,ơ瓖|oӓ\bisK\u001eg1^t\\;v\u00169\u001a@9\u000f\u0002p\u0000ݫ$M\t\fwfc\u001c3c%\u0013jORAN\u0013\u0012X\u00114K\u001f&\u0004=*4LOT8&b\f.r'{KpG~d۩\u001a\u000bB\u000e\n)^RG']X\u0010\u001eP`h\u001a0t)!6=\u0017:\na\u0004xf\u001d\u0000\t\u000b2Xf\u0019oy\u0004\tP\u00151Q|\t{ ea\u0012p}}k2u\u0003>(A-ywH3u|v\"z\u00070/\u000e\u0000-\u0016qcVtުV#q\u0006÷wP8\u0018\u0005*GO\t~\u0015\u0010鯒@\u000e\u001e\u0001Jjуm-h}{qɎ\u0014\u0019|˨'}=}\u0001/Ւ:\u0016'\u0005!7K!p#\u0017\u001b\b\u0007Y\fFj\u001cJ@F)\u001ei\u0005xg\u0013&\u001e Qvt\u001f\u0017\u001a\u0002z\u0016G1\u0000ݤ\f5PED{YѪ>cEOϰ٩\u001avA\u0002\f M܀`&\u000b?\u000eA<F\u001d [,m\u0015P\u0001aAرj~uYO@\u001b%`bI\u0004㔖xM<[L\u00158\u001e\u0012׵FqK\u0005\u0010]vX.\u0017\u0004-wC@Z\u001dqfӫ\u0002ɠD6۝-&M\u0016;W+eQg\u001d(,2U=iO\u0001\u00148*T\u0004~D櫭R\u00061\t7pzoo%\n+!I\u001f>mbӒa]\u0005O7ԝ\u001bQkjɭ[%/\u000f1\"`H=\u0011[ #\f\u001bb!x4(~|]E}\u000eîLQ0\u000e]S-dߥyf\u000fg\u0001>E_\"\u00126v\u00140A\u0014zuc(j@\u0017M\"jM<t[g\n\u0006/W\fwJz]}\u001f?\tt.\u0001\u0001Y\u0001\u001fb\u0012*\u001aE3]WhU\u0006\tjWOf1f˙\u001d0DB.2ިr&G\u0014\u0014\u001f4\u0012M<\u0019ZO\\a\u001148r$԰*\u0013sӐG\u0012g\ff~\u0012YBlzL`v>DOK#\u00191\u0004=\u0002K5\u001b=\u0012\u0011Q\u000b\u0011?י\u0000\u0010m\u0002mÛ&j4\u00130\u0011JU\u0011\u0011O\u0007\u00019*BAR3/\u0013\u0013\"d]P\u0019%C:`A\u0002p\u0011up2?|\u0005[\u0016Odbs\u0012F\u001a$\u0002yW;.xY5~#P\u001a\u0015\noh\u0007BgL|L/+J~\u0007\u0007\u001dzTOz\u0018\u001cFw\u0005N\f%K.\u0005I\u0011y{c;U쁦@T#&;FYCۍaA5\"l\b\u001dԨކ&s\u0019\u0019PQ*ݿB<s\tJH{_' \u0019\u001d\u0003+֯*1@\u0013.dӫCދD\u001aI=~4َ\u0000\u0016cD\u0003O,\u0017\u0012\u001afg\u000fA;j\u0015V!\r疒;Z(6\u0000Ea{w\u001dL]o\u0006Ƚt;\u000b}Y_\u0011G7\u000ev2GBuM\u0005׆e\u000e\u0010nOK\u0003\u000f٢\u0002ӭ,&e__T+\u0014mV\"Y}hNf|Zw62^hALr\u001f\u0003 L\u0003@B\u000f-[O<4>޵Zvٰq\u0015\u00143\r !\u001do#L~\u0015cS6\u0004\\y\ngXvԨQ%n)ifnҝ\u0016?\u0000(8\u0010qFf\u00039w[=\u0018'T}Gp?\u000b`l?D\u001eJkyx>\n\u001aQ~ZNP\u000eo\u0019m>hE\u00065\b%\u001bI,w\u0018<jO>tNqE\tWZ\u001fߧ\u001ftFD\b\u0011*[\u0001N|u\u0002@t+]D ~\u000bnm_\u001e\u0016ꌾ4Ad?$\u0002O9jAz.@L;I\"qhzOD\u0013.^\u001e')ң\u0015룶}\u0017\u001b\u001b|\u001b||r\f!>HQ\u0003)\u001a{[a!AnF\u0017^:0w΃\u0002%\u00199ԋJUE:z\u0004I\u000e/Ro)MȈ\n\u0013\u0003\u0019\u001du\u0014\u0005vD\\Zd\u0015PB\u0019v! |h\u0018jJL_\u0005%Cs0mk\u0007&I_\u000evfV\\>81 \u0015d\r\tN5XO\u000b\u00076^\u0000U&α\u0000z\u001dneFXlgw{x@J\naO?]ɒ5͘{\u0016Z\u0011iV\u000fE\u0011R\u0000\u0004y\u0004,G ͡\u001f\u000e\r\u0005X\u000fh}\u001dV\u001bɕ@6\u0000|6(WXR\u0011'\r'J?\u0007P]b-A\u001e\u0015\u001a+}b^8#\u001e&dO'\fQ!t\u0018\u0005z\u001cY&a\f\u0019Q>䟑_8ߊI}\u00165ҿ\u0001QfX9y0W~Vq\u0001\u001b\u0005\u00048ibdw%#eD)eC\u000eR\u0015Q$tJ_Tu2\u0018H\u001aǠ+ނۍ\u001b\u0011\u0019{!\rGBW&g\u00163\u001e\u0010\u001dU\bZ<Y?܀\u001a>CnR{\u0019tv\u0012PQuTÔBe+Ns2A_;\nکFWc{Cp\b\u000fCU\u0018Yڕ}\u0006EE(;Sdw\u0004\u0000;g\n\u0019J\"\u0012\u000bN\u0004*h꺍U<WƨԠ{!iHk\u0016\u0003l\u001ed\\x2Aa'_fuE\n\u0001\b\bG\rWtʰHK$>KJ9Oodѵ\t$MDi\u0001sWL\u0006v~u\u0018\u000bU\u00069SU(x]2`?\u0006\u000f:cs2x^1\u001aC\u001bc2>\"c\u0000ça\u001c6\"\u0000{\u001e?\u001b%8\u001c\u0011\u000e \u0017SjDhD\u0012\u0010!t\u0019/uΤ+(բSmLUSRVH<YTPm\u001e{\r&ׂYt{s[\u0016\u0003#)+_I5}5oa\u0010n7\u0000\u0007\nq*'zE\tJ\u0001CbSr!\u0010\u0013Q7)\u001b%t\u0018b\u0003swGTElWrΠ\u0006ȂY\nP&z\u001aP\u000e͛\tG\u0002\b\u001e'^J_֛6(_)jtE8\u000fMG$k\u00156.)^fh@\nUQG5_{\u0012q%V\u000f^W/\u001d,:~Ӈy2\u0004-$\u001bNT~a5ں@\u0002p\u000b\u0010\fF\u0005\u0011\"n7NO\u0002B\u0014\u001aoĮ\f;\u0019'A\u0012,\roOJJv0Ո\\+FRFI:\u0015>~\u0014;\u0018\u0017X\\ߡ[T\u0001P\r*d./ot QTF\nu\u0012k\u001f>2[}\u0002p}e.ED>K\u000fw\u001dPի\u000ele\u0019nQ\u0016RZ[3\u0011\u000b\u0005.\u0001\u0002TѲ킕O8Z\\J7/3 tҎt\rn~Z\u001b%\u0003`\u0013%\\G\rLLm\u0017+aE\u0014\u0005\u000ea\u001c&eG_0-Y<l6\u0016cv**YtZ&Hz\u001eX\u001a!\u0019EԵ~i\u0014\u0015]d\u0017c\u000e\u0004z|\rΐ\u0005#GL!\u001e\u001d8\u0012I?<0\u001b;b_cIDkߛA\u0018Pky_;\u0006\u0010S4=R\u000ea\u0011\u0005E\nU\u000b]`.X\u001elr@Ёy/\tp%\r~X,\u00125\u0013tŞ0]\u001b\u001chr\u0018WXIK`W(p\u0017Saꀸj$#LUMDt>\u0017|zL\u0002K1.\f{Sn\u001c\u001fyY\u0014RG0\u0012 \u001a54?L!O%22[㭽\u000e*\u0005\u0011~'\u0011w,n\b̅ϣ2\u0011*^c\u001eѤӲ\nb#\u0010nAXXf|\n{V\u001a%!J\u001c\u0000\u0000,\u001f\u0004|o~5\u000eã\u0003b\u001fh6kB\nJ0\bj{\u0003\u001d\u001ex~0o\u000bjSU#_ҵNk2-2_-vU \u0014_FYyHĥ\u0019UC 9\u0012l쮽'\u0010Jwl<\u001eRxE1p\u000f\u0001Lj\b\rJ\u0000\u000f\u0002ʗ=\"\u001a[^пN\u0006x}}o\u0011[\u0010\u0013Ȼ\bzEF'[?Kc80\u000b\u0019ne\u0019h6)0X\r(-`7H3\u0017\u0015\u00104z\u001eo2׋\\b6\u0011Z\u0003eƃ'E\u0001# ϽI\rq\u0014l8.RzE\n\u0013#H|$#'AntN\u00015\"9\u000e4~9'>\u0019\u0018=*\u0006\u0006\u0013_\u0007ndTCp\u0003ye:)\bX`! \u0011\u0015@\u0005ܻڒ\\OPn\u001a\fq6\u0004C,\b\u0010,h\u0014\"e\"\tDνj\u00020C̱2s!b\u0018P\u0016Y<iGV*n4w%\f\u0014z\u0000O.\\,Y!̗G8trb<Ȅ0%Mt\u000bjr%+=\\L&\fG3<rE/vlxDz fh}!JپƝJ Kk\u0015ڗzYM=pX\u0005nv\u0016>Y)ܣK0$ޗR6.\u0016\u0003C핀c,~Ec\t)Ǫ<<\fV\u0014 #U`v#܀\u001czi\tw!8M.\b\u00196GcL\u0011/eKZ[Z\u00130Q^RH\u0012swL3I\u0007Q\u000ea$ܗQ u;?$uW#G\f\u001aG2;(-c-Kƽ<ӵ)7igEI\u00057ڥ\u0012(\tOg~LX\u0003ӽwWJoJ\"TJƲǈ@)my\rҝ@\rj\u0015\b;\u0013*\u0019-dLϚOf\\40Zz\tB-Si\u0014|ҩ\u001dN\u0010͓BV^\u0012\u0015g/\bB<7xG퇋G!\"AT\r\u0011\b~&\u000b\u0011P\u000b˗3\\&8%}9T\u001a]ԟH\u001f3Ď5t\u0018\u0000U>\u0015%\u0011$)Ѧ\u0011\u0011D\\g6$s睶7\u0012(o04-\u0010\u0013Ҽ^Byptup\u00179U^ZJD.\u0010\u0006Q:edd\u0016rI\u0019q@\u0005lJ6=1E\u0019X3Y6`OoCVx-:4d5\u0001҂[&\u0002^\u0004N*Ŋ[B\"g^zifÕqAw]jD!k\"9\u00012\u001dz6\u0002I\u001d4\u0010|qn6U_6Mr_\u00164[1~/8L\u00108Vt=;%\u0006MٓKpk2\u0004˛èX*@\\\u000f\u0012`p_\"n\"9gJSD\tP%,:\r{U2B\u0019\u0019\u0015Ekw\u0017S\u0001c'\u001f$a\u0015\u001fkW4,*$7\"\u0006[|~l\u0003\f\\E\nɡw%gIt\bug\u001e^4\u001bQ\f\u001eBNMQ\u001be ۉUwD\u0003%̸\u0004\u0018\u0014(\u0007k3ʠ`\u0010ԦR\n\u0004[!7;j QĎ:4(uǇhI%(,mC&N\ng%wG\b\u0014P6?\"\u001cF\u0012Xw\u001c\u001c~\u001c\u0019{3_ b\\l\u001d\u0013\u0016b\u0005KQ\u001aTy3^\u0013ݨ\u001cDj\u0003k7rH\u001e7\\Kktb\\50\u0014g\u000e\u0014E,(#bVmH\"\u0012Q^$/>j.\u0004/),s\u0010$!{\u0013c\u0001*`sѢ\u0002\u0017tG\u0014ixSP\u000eג`\"\\\u0019Z<υ\u0010T\u000fi:\b>G^u:؛hyd闟jt싡Ԕ啡\u001fYb^r!JM\u001cԁ\u0002\u001d\u001d\u0015!*\u0011?\u0015ຕɟW\\\u0016{3Omj\u000f\u000b\u001a*,'ch\u0016\u000fX]3(^xR\u0012\u0010#0!Y2+zuJxkf \u0006B\u0015Hu]2\u0019\u0010t.Q$ =\\\u0004>!\u00013\tL qzIN Yp\u001d\".%\"^[جDV\u00121G\u0004\u0012;b|F\u0015J`f錫R\u0012}\u000b;sJf8\u000e]h0Hmk\u001a5ii\u001cMuٽޓ<\rW\u0014QSLJ{;e1\u0005E4-Z.U\u00157yJ6J\u0014~g\n\u0010W4\u0007\u001a8I\u0011\"wKo\fL\u001f?Ѯ+&Rtwp\u0010(reu\bUP\u0015t\u0004O¿\u0014f#oZb\u0011'\u0011dj*\u0004W%\u0000ұH\u0006E\u0001\u00002\f\n\f5C'f;ۻiz\u0002T\fQMD:!\u0001B9e\u001fh \u0007\u0004am\f\u0010f0oZa,w\\a\b\ngX4+\u001bE;1.Lo\u0001\u0013ϑ\u0007}j')t*uCMݏ\u0015\"\u0004i&µ\u001cMSP::/x\u00100zt\u000bya?$@a},Kw4\u0005]\u0015܃\u0015!Y\u0013\u0001oyGIːvJӸp=\u0011;2\tn\u0002\u0002,e$M\u001f\"j\u0011&#I(yX\u001c*ut|'\"eOyeݶw]󓎦No4\u001bY\u001eb߾y5pz{5N\u000fI&̈́\u001b\u001a\b\b\u001eS(>\rL\u001a\u0006\u001c*\u0013\u000b\n&kPUQ@g\u001dd.U2\u0015\u0014a.*-#\u00187\u0006!)b\u001b/<\u001aCCv*s\u0004(S\u0019+\u000fH;yP8ш6bcb\f=41T_p\bw:\u0003d&F:~9\nGPDu\u000fC'SUi(̳!n,(]{K'j\u001c>7EL*]Y9u2Ba$jX\by\u001182(\u0003\u0007A\u00114J\u0001\u000eۄո7\u0016MDTjǣ5\nO\u0002{Tf\u0012\u0016c\rh$~m)ii]O\u0011~]U;qd\u0015|\u001c@\u0010=!uFa{Pk^ov(s3q8/Q^$\u0019M#\u001b[k)\u0010\b\u001fPx\u0004\u0014-]m?\u001eg`a&6\u0018@dX\u0005k\u0017VE߸\u0018jdAbd4c\u0015x\u0013\u0013\toBmI,\u0001,2\n\u0002[Y\u0015ުd\\U\u0007]<\faRnCީ\th\u0010$\u0004sK\u0016H6@W\u00132#\u001bk\u00045F\u0015}F\u001aWW\u0004e#@\u0006W\u000eeb\u001d'I=?\rlV\u001e澃F \u0011AmA`Tw&5\u0010:\u0006\u0014ǐ-\u00054\u0014@<\u0001\tD:1\u0001XL`1pbNf\u0012_\u0001\u0016O#XL\u0016\u001fyN0\u0006l풁@>0vdd@\u0010dٓ8~Qs\u001a\u0005\u001eɶK\u001e5>s/zi!Q\u0005dfaqT\u0011 \u0011|\u001e<E3E\u000e\u001b\"\u0018ڡ%E+tmGq!t9*,\u001cz\nj%n\u001a±~'\u0001goc<XgTaS\u000evEs^ ]A\u0007\u0000S\u000eC8Uj[R7\rZ|s CA޺Nᬩ\u001b^cT\"\"\u0010{>\u0003\u0005;YEVxg\u0007\u000f6i}G8J;F\f\u00151$Db`wDPO\u0010m,&'\u0006\rq&De\u0012IUE49\u0010E%\u0001@SP\"T/\u000b8Av\u0005fD*;F,ts\u0005GzIZ Y\"\u001c#Qvv\u00155\"hI/0\u0016\u000f\fW|I \u001a::5\u0010<ESlw\u0013N\u0011/i5?D3\u001e\u000e_\u0004b,\u0004J\u000fO\u000f\u000f\u0011^#\nF^Kh\u001cn^B\n\u0005\u001cDWwg׫\u0011)BWbsr<[#Hǋ֪;\u001f'\u0018\u001d-6ą/\u0001Ͼꪆ\u0015/\u0005\f\b-B{\u0010h:--Y2:u2T(Z :\u001d/ad@M\u0004^sYi \u00190\u0012rM\u000b#=TJx%\u001c\u000eA0GFC;_\u000e\u001e\u000fdxU\"y24G~ө\u00162\u000f~yH\u0002HB\u001c.(\u0003\u00042L\u000b\u001ah%>\u0014dv\b\u0004Q{\u0016u䩈\nMQ2K\u0019_9jq\u0010{g\u001fU\u001e\u0011~ec8slD\u0004rCփ۸%e\u0000Vfwc\u000f%\nV[z\t\u001d\u0010߶\u001aS34(Ru\u001e@j\f\t\u0019 \u001a\u0015\\\u0018ԽD\f44 %4R\u0015WJ\u0011ɒ(EOhDDph\u0000N\u000139NrҘ=<v\b'$U?&g\u0017\u0015eQ4EaKm/\u0003fi\u0010J'5|rY?\u001awQT55aP\u001f%\u0019d\u001aSͻ\bVSF\"~WG;jx\u0014\u0019\u001dȯµ\\%Vۖ:\u0000:8\u0002(\u0007\u001b4\u001a{U#7o\u001aosTA+z\u0016-`q)S\\\u0001'IV4\u0005l(G=!iG\t\u001aHac\u0007HdwdX5~4\u0006\u000e\u00116wX>00$se\u0017Jz8EqM\u0019Z\u0017NK\u0002xID\\˪eS4\u0001Yψ$}=\u001c[\u0012oG3Iײ8?\tyM/~kfDk9W\u0015?_1TvVr4EUG_\u0010dJ*PXQr\b#OQ.ٿd0\u001b⹣atkxs\u0001b\u001eI%B\u001d'rE\u0004X\u0004\"|\bu֘|\"5Pi^k)\b[\u0001PT$Ř\f\u0012'r3KAފ&k=\u001cn\u0006\u000fg5GjB\u001akx\r\u00020IZ\u0005j\u0006w4=#Sq&AIݼDH!O\nBL/Q@N\u001e\t크!j7>\u001aj\tDr}j#\u0017S\u0019L94nw\u0014z>$eX\u000e\f\f3\u0000L\u0012\u0013\u0018}1r)079\u0013SBv6Ԭ[P\u0007\u0004\u0006\u000fqW_\u0012V%N\u0018\u001d׈\u001fN\u000f\u000fB\u001ct$}|\u001c\t\u0013|^\u000e1\u001ao\"N/QjzfiZTnV^ጲ\u001f_A\f\u001a^u6t`%IkmLm<=\u001b}pI\u0016pͷkE0\fv5A\"ngFBshrpSY\u0006\u0011LF|\u001c\u0006ˎjcj}{RI{KBbXk&\n\u0000#\u0017\u001b7\u00023>\r3I^\u00059jP!ENM̢\u0018hgDD=\u0011\u0002Hs.ӧЫ\b\u0015Ti\u0013!DTĂ-`!\b\f]&$H;7\u0017CU@\u0010\u0013nC\u001fQ@7vٖșюxFv\u0017E]\u0019Pn&œnQ\n]L2>H_UmpG5ĳ\u0007\u0015.\u001d\u0012;\u0011}8̲G{V{\u0001H\u0010Ѿ:콳/Kw9\u001e5\u0011r?CB@!-\u001c[\bf)lϽ<E'HYF[\u000eaY\u0001\u0002uoQj~/N\u0006s`\u0015o*\f\u0017\u0002eS,֙\u001a\u0011y\fWb&a}\u0017ox.e\u000b\tEQ7V'gly\u0011cTvܳ92`%,9z\u0002\n(\u00130\u0016t\\\u0000S\u0011[V>\u0010\u0005f\u0014lD\u0015wmg@\u0015\u0014{wTM\u0002\n?m,Q\u0005(\u000få&}\u0000~\u0000,\u0011I#!\u000f\u001dYǋy,ɞȳ.\\\u0006o\f5?W8\u0001\u0017|$/c$)`O苴 dgqU\f6Uw\u0011t\u0003<-\u0006\fr\\ \u0006Lk\b@b\u0001@;\u001by\u001a\u0001+LQ0tTS\u0014M\f\u0011\u0016f5@,\b4/z;B$G\\IUӔq\u001eUMhS\n&\u0004_gN*\u0007'h\u0015\u0011ɇW\n\u001e;=aL&\f]e\u0019\u0014\b%%:^\u0002(L\n(S\u0012&)cy̖y)ޝڗ@E Fk\u0007ehVIxwq$=v\u001d\f\u0018\u0014O\u0012u\rZE\u0012I\u0004;[\u001b@\rÏ}\u00015&\\1ZEWsc:LC5͐;b7\"`\u000f\u001cTQDw1\u0003ɒ8<yy\u0005A(\u001a1F4סp%_@Pm\"+20$aJB\\**\u0000rw\u00169)[\u0013RGݐ4;\u001c!?@D\u0003be,x;<-\u0003ݔ\u001e'\u0000\u0004Ta\"d& ,C=qTY\\I\u0000.6HXHb߂%H\f\u0011\u0004e:wjP!)w>?cһD5^'ZGK\u0011zO60A\u0010D4T-:\u0013C\u001fLBIBe`yls_X,7QFS-qջN\u001bЀ+8\u0000}5RT\u000b0\u0005\"Bu){u3UP\u0004SR~ͦF\b\u0011\u001dp\\\u0001\\BYiZj\u00166LlD(\"f hHQ6Cs\rEM3\u000b\nQD&\u0002qnV\u0000.O[\bPUJÁ#\u0013x\u000eB«\u0010L\u0018\u0016*qۭ*KQ<\u001a\u0010&BZq\ts:8\u0010]Aø?5f8(\u0001r&7Z\u0012\u001d#2qlDmO\rG4U\u0010uwrPa\rV\u0003_\u000b\u0001\u00022ym\u0007jjo\u000e\u000fEt~EK'bґ\u0003\u0014$M\u0012ehY/\u0000\u001ds%wIc\u00074}{G\tЊ\u001a\u00078{*\u0006\u0015)\\ֶ\u0014N\u000eB5(K<}C\u001d\t%M1\t6\u0003&\f$4\u001d\u0003*>A1\u0004U@\r|\u0000%U꿤h\u0011Di \u0010!x\u00182yo\u0015ҟj\u0005\u0013&z<{t+\u000b\n\u0012net,\u0002^پ\u0018)~yi%\u000eq閚\u0003HQG\u0002Uʞ\u0002؎J\u0010\bS-n#F\f\u000eH|P!^\t\u000b7G\u0010QqR^4۞'M-:\f+̤\u0015Xv\u0018\u0000URũ\u001b\u001aNFŦPix\u00060&v3\f\n-\u0012CWkYTU\u000fV5hB_a\u0005K\u0011\u000fX1\u001cgf:]5\u0007w\ng;$x\u001aq(\u0005ƃzr%U\u000b\u0019!I\u0005zLS`S+\u000b'\u0005J\u0004\u001b0\u001e\u001eؔ6l}lqjat<\ri.}|4PYJ$$ynG!^''Dvǡ\u0010\u0005\u0017* \n%'B͏h*@s@\u0006\u0012ȸY@7~#r]ЋN\u0019\"hV`'C{R^^2\u000bPչgkbq#0z\u001115<\u00075'z(50%xBH\u0016\u000e\u0012Nj0K\u0007imz:\u0017\u0005\u000b\u0005a=FNտY\u000b\u001d\u0017䑼(蕠\u001bJ_\u0015ˆ\u0013ۣ@ΊE\u000e\u0012\u000f\u0002\u0014\u0011Z\u00039N-݋#B`7DHOQ\fϿX@2e\u000eu\u001c2eERL6˲&&\tݠ\u0017V\fY\u001c\u0006-\u001c\ru\u001eԽ!\u001b\u0017,|\u0011Qkh1ĥGT1.ݑ\u001f%\t\"\u0010`i*$\tK\r\u0012@4\u0001fp\u0006\u0006D!g⥡\u001cRfo,NEf%\u001dE\\\"\u0006B\u001a+Q\u0007E=_Km\u0001%T\u0005YB2\u0019SF\u000e\u001aRհobq̛8u5k\u0002PG\u0000J[1*iϯB\u00053%\n\nޗIJʶ\u0018\u0012\u0004{\"{a\bjaц#\u0001?\u0007c\u0002ģI.\u001fx\u000b5=^\u001fO\u001fO,}oǟ_/~_˯~_w\u000f|q_~o?o.nW3#9\u0015\u0007rgUi\nu\u0005LlAxO~NK\u0007(Y\u0002\u0012rTIbVh`\u0014ve,\u0006~N:;\u0007PT\u0002_ر\u001dǷu|\u0005 Wn\u001fғ,h[q \u0002z\u00121\"_\u0013&R3CJy{g'C`*\u001dk\u000b|2ŕjAL\u000f/$YEr{\u0015d\u001c\u000e\u001291pL\u000e\rf2wM`яXf\u001f\u0002=OA*\u0003\u001aL*r:\u0017B XF\u0005\u0002^\u001b5ET?\u0003!4zb3ČP |\u0015\u000bO\u001bN\u0001FG\bq0\u001e\r\u0010qAOw&d$3[\u0015\u0015n1\u0014ǰH*\u0016Y@'k\t\u000f͢*q0ef8D4]BkTP\u0002~2\u001fK)T}Py8\u0013\u0014_d=\u0015Lw\u0012?=Z[M\u0018j~Q;7v\tK\b.\u00124Ǹ1OS\u0018\u001e85INLG/ɋe\u0001P &f@Z{\u0003\u000b\fM\ns\u00035Ktj\u0003V\u0015<;Jn>A酳e+N!\u0016 \u0018ّ\u001ap\u0015(\u001f\u001bHb\u0007%\\f\u00109\u0007\u0018\r\u0002U\t9\u00115\u000f\u00189a60d\u0001ת]\u000e#f\nԽ\u001b\u0005N;6+ftJ\\*\u000f?\u0012`>\u00102;!_w^0?ߣ\f;L\u001f5\u001a#`A&ϒb;l\n:P{a bv\u0015,S&;m-M^\u001e+t[QyF\u001d\u001e}Jȯc\u0016\u0016o@JR\bJOZfZi'f6QZ\u0000HP\u0010e\u0006\r}`(%\u0016֨v\"PN\u0004/yh\u0000ϡn\u0010˴NQo;8t\nh?K3\u0017B\"Y셌7\u001e=+ٳi\u0013mk{?KbCN\u000eي\u001cP(֏IOAsjµR+:H\u0016fbG\u001d)\u001e4hmd]\u0010rp#\u001bc82hx\u0019\u0004Zh&\u0003Ei&%\"3'@Lez|D\u0014\u0000t;5K%\u0006)&!U\u0014Ez\u0014P'\u0003tӣ\u0005u*I\u000b@A\u0015]cI\u0019\u001dN2d\u0014h&hpqCbٚ\u000ek%1Чh\u0013UwJ#\u001b\u000f\t :\u0012Ь<G$O;;ཱྀ\u00003LSS\u0001\u000e\u0014\u0003ԴC*!\r\u0003V&J\u001eז\u001eWpG\u001a\bO\u0005@k\u0003@I\u0004{G蝣CS|\t\"m8f\u0019-oTS\u001eʍ0lx\nlox~h}\\Hf\u0019@W>/B\u0005UH\u0000]UKn\u0004ˏ\u0011\u0005\u0002NK)Zsxt΂\u000eֲ&Vȓ\u0015PsK1j7;iPp\u0015Y\u0017z\u001a(믵8E8\u001d1$\u0012>֤\t\u0001\u0004؏K0ܵˑ`c-uTE\u0002ڣ\u0004Y\t\u0013X\u0001Fn\t?GhBם\u001dQn۷n[U?N\u000eO%\u0004M}0uEX-ᯠh\u0007\u0013\u0014;7v,T5{+ɻ^%gu(s\u000eD@\u000ej~ځݰ,\nY>\u001a\u000bppM\u0004\f1\fX\u001fdUࣈv`iV\u00046#\u001d\u0003\u000b+\n2`\u0019<T,\u0017\u001eL\u0007w\u001a3̚^*1W\r\u001b\u0003\u0002wavv,yR}&-Xt\u0016.\u000e#۲߸\u0005JI\b#_>).\"px謇w\u0017)`Q\u0003[\u001cK\u0015*$4Y1LKjk=[EmWP޼c49\u001b\u0007u\u000e'\rb!Yi'>XX\u0004\r{x۞\u000e\u001eK\u001eWA\u000e\u001c޹eSt\u00160Hj\u001f;\nU\u000e}8sT枢} ?۸wȏ<\u000bɒz\u001f;\u001b(r`\u0004I̦ҙ\u00055?HUߏ\n{\u0015㋏V%/O\u0000&?\u0016\\_\"UI8TXκX( Ng&\u000538\u0019grv\u0005s=ZF.ˮ(LV\u0002JPl\u0000A\\c/f͒K\u001d\u000ep\u0003\u0017~T{-\u00173\u0006\u0017\u001e-K]0KIQ&MA\u0006<펆?SO\u0005(]iS\u0006=h ￦@\u0000ר\u0000UHz\u0015\t`P\u0004\u001d\t\u000eѥ|\u0013\u0001U\rO\u000f\u000e#\u000f\"\u0016h(\u0016\u0018#[&2|a\u0018\bx,B:Kf\u000f\u0015b-{t{بn!DLV,h\u0006\t\u0016%E.oi\u0012OЗ^K\u001cxҡ\n<\u0002KkhN\u0014]@!\u0001잭L]Δٹ1\u0011\u0013bh\u001e;Gbg%PgiD|\u000b%%$෶\u001ee\u0017\u00008\u0001gPB\t\u0014D\u0002<*Bn\tM\u00120\tV{mۡo\u000061\rhLZ\u0012!/\u0018\t$$>ύ*43FԠT\u0006\u001d\u000fӄJ6%\u000b+4\\\nH(\u0003g1\u0012yPW\n!{\u00112mǉ$bBm3.b&\u0003zs\u0004\u001a\\މ)LW2N}MY\u0017q%\u0002\u0011V|\u001e3k-\u0005.\u0016%t~l~.ɪSDC\t_#42L\u0016\u0002Ay\u0001J\u001dV$f\u0014h\u0019a%\u0002{\u0012af\u000f\u0017Y^\u0018{N4\u001aP\u001bېB=\u0007S\bt\u0005x\u0005zpaɷaaKz|^~\u001a1Pe ׈Pr})eSڣQ/U!\u0019HK+Q\u0019~Ԇ\fio*#􋆽;U~9N\u0006,.\u001d=Ԥv+\u0019\u0005{I\u0017;\u0005Ϩ2h\u0004\u00125o)ai\r\u0010e\u0006\u0016囈z\t9_/o3\u0017}h\u000bժjPF\u0001%~Oď\u000b\u0014>9\u0005\u0015!\u0005EDK\u0011),pջg\u0014}2~+\u001d'$ێD2[g,\u0015qJ\u0010\u0018\u001c:\u0015`5\u000e|\"eԶW\"gHJ/>Qϻ\u0017\f\u00191*0XkGz^-\b跊ڤj\bUts\bZ\\5`\u0014Nm\u0000t[y\u00170俸I4\u001a.J#\u0012\u0003:x0:3M%F<5lzP&gЈ /\u0003)?y7pt\u0001\u001fzKĪj,1qy\u001cSaEܶ-:\rP\u0007Tu\u0013e$]{Ƥ[Qp'C_7k}%\f6jQ*\u0012<F\u000b7h\u0017!\u0005&̝7;|J@9\u0003,Z\fe8C\n㦋q\u001eɎmig*5D\u0004\u0005g(t7a,e)zUn3\u0001ֿZHAzXgőмd/<x\u0007V@o\u001c11DS\"\u0014a㢂N=\u000b ]ܬe\u0018\t}X:5\u0019$l\\XJl)yD[^PGd.@WHMGo\"3v8/Q7D\u000e\u000f\\3]\r-\u0016F\t3\u0005\t+/#~pg+'y\"\rcAtE\u0010\u001dT)W(B\u001e0#DJwe)E~K\u001cvvd*VQ'\u000ex0}w\u0000\u000bsE\\\u0012O`\u0013\u0010zF\u0011\u0013nY\u0004N\u001b\be\u0016B\u0016\u000f&#K\nR`&\u0000\fJQ\u000bbksT2\u0003a{V7+ҷ\r\u0013\u0016\u001a_}q\u001dq$~x݇/FKb\u00101tW)vk+|;_O\r.K<,$}wBwht-\r\u0002\u001fzK$ŗd\u000b^\u0002~8M,^c~>ʾM\u0017~%<\u000bs9Jjաش\u000fkIlߝE\u0011f\"\u00179\t\u001a\u0012\u000ea\u0017r(@26/aQSnSz`69\u001eJC\u000f\n܆h\"Z/\u0001r뽮`w\f\u0001(qRGL\u0015\u001dXv/\u00069C\u001dɫ{\u001eN\u0001Bb`e\u001b\u0010n\"\u0015fO\u0000\u000en3vcG9; m\u001dQ߷?\u0004&9Rf\n\u0007\u0010yn-tP\r\u00035\u0015ҏPSbn2\u001a(| 6B\u0006\u001b\u0000~\u0010\u0016,\u0019;2\u001b\u000f|?UQ\\~sAu^ݓ&\u0010Dp7Azú\u0001w\u001aByyG\u000f\\gG\u0007W5+\u000eYA#{@~A͒L\u001b}:Cr{\u0007\b:\u0017J\f5*._K\u001bSju\t\u0003[\u00072qL%#PJ\u0014vp1_\\VcNӛ/I=v\u0007\u0004Tԅ\u0002)l,\u000b7B\u000f,GX>C\u0014Щ\u0015qgMHHFAx\nĄ\u001bt\u0018\"Thn\u0004x=\u0010\u0007\u000f2 <8wט!l\u0016\u0015\b1hc ze\u001d\u0019\u0017\u00167\u001aEvp\u0014t\u001a\r\u0005*PvˀHwꌊL\t\\\n\rWFh\u000bOCq\"<.&ϻo\u0007$\u001c\u000be\u000fm\u0000DJ-첞ca*8\u001dş(\u0012[4g:,\u0017k0\u001f\u001f$\u0016;A\u0016PK\u0011%KH\t\u001aAK\u0011\u0013\u0014~\\)\u001c6;\u0019\u0019ӽJݹ|.ˮu#Gg\u00180\u001b\u0001]\u001bU\u001cjX\u0015a^P}ߕ)\rbKz\u0005*Љ~3ن͍~((詆U\u001b\u00007=\u001dP\u001cJ/dJlaȕȩv]T\u00064=Mqc홗yo/F\u0000u\u0007\b\u000b\u0006kX\u0014|MЯb\u0015IX<G\u0011ܳ0qh\u001e\bD\u0013}D\nE-X>\u001c(LU54,\u001cqEd\u0001\f\u0019OLwiN\u0015PoZzqU۹)Tg\u0018\u0018_.L\b!}\u0015Qy(=\u0011`\u000e^F׏ M;^ˑ\u0002*$4D\b\u000b2PL\u0004\u00180\u0005P\"\u0000z\u001ePVwSr0\bUe>\\M̝\u000b'&e\u00174=VM6+\u001ag򔭼\u001e2sIm㦰ZQM\u0004\u0014N~\u0013_\u001ftK\u0014!i+q!\u000b!Dlr\u0001tthHҚ%\u00111l(o\u0002\u0004R\u0013ü\\Y$\u00065T߃!\u000bv|`>\u0004NF\u000bKB3\u0018*\fIU\u0015=/cX~\u001a-J\n]9\u0006\u0002Рy<~iNr\u0002:^?\u000fz/y/Qd@\n *\f\u001cʐ*з\u0001sOG$?\u0016\u00073y*Ifj\u0018anXdCz\u0011C\u0014R\u0016W\u0005H*w\u001315[\u00111fZ#j~<V;1*4\u001fz\u0005mB}\u0013A\u0001S\tnF~گIhf%Ҋ\"\u0017lFܳ^\u0019\u0001\\}!!xD-#$p&\u00154bO#\\~\u0012f\u0016f{!r\u0004\u0018.\nmߥ˒h$\u0019Ks=RH!7AÀ܋\u0015e]\u0014y.Zq+(D>VtK*\u0003ROj\u00024R8pt:\u0001\"h\u0006\u00132'8\u0006\u0005D,8v;N}&\r#@ Pp:\u0000&8j\u000bkw5PrQ\u001b\u00148x\u0017ܨ\u0003}LWT\u0007$\u001bq?coP\u001c1Dir)T=G\b\u0018%JZ1*\u0004k'\tUCt^i\u0006my.}S7+8_\"\u0002\u0007\u001ekCF\u0000':Z\u0019JZ\u0004{y1 \u0003KJg9ʰ\u0004\u0007a\u0007/͗+2?rEE3oSO;\fy\u001a_\u001em$SA\u0019^!(q\"| zS,\u0017\u0011#=SZ^!O\u000e<SL1\u001bǦ`\u0019YVL\u0005^Ѯt\nh,sgM$\u0002%5:\\\n&Zݲ͈y/SV\u0015\tj\u00197T|SO[uz\u0007:񐠛䜄\u0007r5x7e\u000e-\u0003ovb\u001ch\u000e\\$\u0006n\n\u000bXc\\YyY;Vlіc\u00002O\bd{\f\u0000\u0001i\u000e$\u0006ϻ\u0013ډ4iI^OC_\u0001SK\u001dU\u0010d $Tc^S\u001d^4(\u0019K{P\u0017zxU\\H|XeЋs\u001447ՅkH\u001b/ꄶ\u001a#jVv\u001e*\u000fm,\u0014\u0011RI܇Ƨ|A@I\u0007+v\u0003I\u0006YR\u0003HՃ\u001aV_Jy\u0006w\"IE\u0017ƻN(\u00054 ):<sX5i\u001dhT%\u0010ô00RW/E[}\u001at*/e]˾b\u0015\u001c\u001fn\u0018\u0000\u0006x\u0016rXN1H,\u0012uYGʬZ;&XMV@!`?uz\u001a-t\u0002\u0005ߋ5W\u000b<C\u000bx&u!T\u0016&.B+9\u0010A[lJ9LP\u0000俉sȔ\u0003|H~\u0018S]\u0003aс\u0015suܤ\u001a\u0013us\u001a\\\u0016ǑM\u000fNQ̚J/'%EUÍQ|\u0013&\u0000\u0004c\u001d\u0007Re)\u0005~\u00017w:TƟ@=pc\u0018mOM;s%'Ӳ%ZJP#\u0016~ꬂ\u001a\u0015_ыj\u000e(&y\fE\u0012,,\r:>\u00152\u0012OGj><=\u0015\u0012.($KWT\u0012]n\u0003!I\u0019\u001fAzNۤ=l?)\u000b\u0015qb^/].\u0002-\u0010\u00153\u001d\t7$)ldrK-\u000fױh=)Y\u0010!\u0007:I(\u0014e,R`\u0004V\u0003\u001d:l!\r闹(y-Ya>a\u000fF%Q}s֙l\fF2C\\Ac];R'QcFFJ\u001du_=\"J\u0018K\u0015h&@7KDUad',v\u00008dl*9\u000fZŻʙE\u00010FrO_ᒙY5'/]9]ɝ4@\u001c\u001aSo2Sc\u0017\u0016\u0013-ە%۽\u001aD^Z\u0004\u001e9E\u001d-:!Y\n}[uNa,|Dz%UH\fthKVzb\u0010\u0019~g\u000fF\u00034Q\u000be\\tɱ\u001d\u0006'-}Y\u0018KJ\b!{\u001c\nЀ\u0012><\u0003h\t\u0013p\\V\u0017[hL\u0016Fjt&4.|&n;ﻠUiW\u0004&(@ᐎKD\u0011\u001exy`|D-}RVѽѰ݇!\u0004T\u00020\ro$&[Ԁ\"\u0010\u0006\u0006\u0014\u001e\u0014&v`\\\u0011<J)NKH\u00199`ڙǞ\u000b\u0018Mi#J\u0011ȕa&\u001d\u0016RkR);M\u0002s^\u0012~Hr7D,>\u001a)\u001ab:\n\u0015h1g\u0017kߍ\u0007hWz\u001e\u0018]prX\u0002wi&\u0011|\u001fJ\u0018F\u001a\u00054\r\r,\r\u001b9 /*\\j^ ,P>~\u0015xE\r\\=կ$H%Q`\u001a\rN12)\u0002\"21OC!ƩKG Qj\\:\r֖\u00151%\u0015_\u000f\u0016\u0012yj@$iE*#\u001b2۱t70P\u0004\u0011\u001e/F`\u0006\bdPG?`2<(AfN^Y,& ]j\u0017ÔlU\u001e\ny6P\u0001\u0019\u001ey\u001a\u0004y5\u0012V!@k㴨T)1*S*q\u001cQ\u00196';Y[%\r\f$ɰQo\u000bqC^7q8\r\u0004L~'٪*\u000fP\u0014\u0006*\u0007)\u0004\u0016\u0019\\\u0007`N}741\u0015s{'\u000ep\u0014\tD\u001e;Q#5a\u0000'\b\u001a\u000eTo!\u0013X\u001e'<\"um\u0004\u0018Gi>J\u0012Aj\tX\u0019\u000b0\"&P\u0007WhQFAA\u000e.\rd\u0000w\u0010PI-\u001a\u0010\b\rF\u0002_\u0005[wg5tƾĮ$S\u0010W\f%%ݰ&e(nܮXn^&\u00078( KDLݩI3֊ףp])\u0002V\tBRb$n\u0007t5\f믧h\u001c\r._\u001fȉt\u0003#&=|f(րjZj$wHn\u0010]1\u0006\u0002%s\tQP.T\u000f\u001bG,X\r\u0005'PQ?z_\u001f6M!zX30TȜ6`jd;\u001778,\u0007\"Ңwe,\tѣ-*bY/pWUh{Fo&hc/<d34o&EIM|G *.k\u001a\b\u0012g'\u0004\n\u001dS\u0001ئ{4r\u001a:DPl?R\t0]\u0006ؑر˦\u001dX䰣a'F씪.=q\t\fcdc\fL\u0011g\u0019\u001dKnĐ\u000eQj{-\u0007\u0007\u0018m|ʾ\tfRyvL* D\u0002>&\"E\"WR:ǽ|\u0011\u0004S!ts\u000f\u0010\u001850㢸G4TPwao{ \u0003Dn\u0002`Sk4ϼ2Ϊ?%\u0013\u0011\u0001ᮆ<H\u0000\b>\u0002-A\u0016m*\u001f#\u0002NL?\u001a<\u0000;HϢU/[,\u0004AL\u0000R\u0011Q5\\z\u0015dM׀D6jTT\u0017\n\u0007qYK\u0016dE$8꾠cʽ@\u0010{wbig\u001c>e\u0019kk\r\u0014,,1IQEo Ht\u001a\u0014nV;+db'\u0018f\u0014实\n'Z_z4\u0012\u0006s0u\u0010TeԳT@\u0015\u0014UŠ\u0003A\u00028f@\u001f&q~ȫ*I\u0004{FݎI\u0003[\f\u001fe;6E_V7\u000eItF\u0006Ƕ\u0003}uZkCE\u0011\u0002\u00122\u0010dWqo$=\n@VzVp=vHwOd'^\u001b\u0005IήTC;WzH\u0007p\u0019\u001a6(T4*\u001c@\u000feqͲqD--p\u000b,d'RxP\u001b\u0017\u0012\u000fx#roZPAl\u001d>\u0011/\n]3]\u0002~D*7((\u0010+%o\u000b\u0001#a?\u000fd\u0012AFd&C~\u0014u?~jcUB%7\u000b\u0000yBg(~DI!\u001fH3a\u000b=СΚl\u000epP@/5\u0011gP\u001fD\u000e\tSV\b\u0017\u001c\u000e3aE\\,:::Bk\u00130%vfxtvc)ӵB\u0015 W\u001c\u0005RJn\u0018( [2UC\u001c?\"P?\u000bi\"L\"aTg_h\u0004xU\u000b!E\u001beZi_?\u0004/\u0015*\u001d3J\u0018\taVOJ';g' 18Md\"@J\fUWC\u001a+[!d\u000fgܐ+?\u0000sq\\A\u0005\u001fjh(>\u0010 t\b&\\zĈ\bb=\\I\u001a V=8\"\u000eqm\n\u001c\n('\u0014d@S\u0000p\u001aWMЫ&\u0016Z)Y\u001d%\u0004%k4\u0007R\u0016W/`]\u001e%Ҟ\r91}\no\u0014MQt څْ\b\u0014G\u0011̥\frD\u001982Js\"E'p\u0006r\u0000\u0000 \u0004/6>\u0012n!\u000eհU\u0010/L\u0017t=\"!,c{ݨ \u001c\u0005\"+]\u000bHRhv\u0003|\u000bշ)<db\u0017ʬ\t\n\b_\"FP\u001an*6d\u001fI\u0000[ɘ*VN0S?GiV_\u0012\u0001\f3@GKmM@@HFA<8\u001ciI\u001b;K\fڵݨ\u001d'@2U+mR銀\u0016\r\\d'UfX?e1tf.Ο\u0005\u0003hO\u0018w\u00171{\u0000ߣ'(0eB\u0005\r\\2\fC\u0019\u0012\u001aL(N \u0016H#I\u0012\u00044\u0010t;\u0002Q*|\u0018\f\f\r[z%P׈D.|QpkM\u000fcن>\u0001\u0014@Uc\u0004?J0J:Ǵ\r\u001a\u0019\u0007wq`\u0010\u0000\u0003\t\n=1csc\u001b\u0004'LC\u0004'*G\u0006PE(Oc\u001e#aՃ$35_\u0012*Z2\u001fRN\u0003gN\f-\u0004lepЖ`9\u0018}6BGeHP0k(\u0019L\t1\tU\u0006jZGb!)\tS%\u0011e$*\u0012@}NG\fW&$\u0017TEu4ֲ\u0017X r\u000epvJ<B喲\u001dR){(F_\r\rl\u0015$8:k[I\u00137n1\u0014bEyz1^*\u0010T\u0006s\u0005,}.ó!\u0015\u0016 ++\u0016ؔbњu=\"SE\u0017KbcH\n4Itb]\u0006\u001aU\u001cʁ\u001e\u0002`Վ\u0002u\r~7_z\u0002&\u000eq(kDB=\bYz\u0012\u001bW$ћ\u001cr\u0018\u000b,oOb%=\u001cC/3$\u001140\u0012\u0000eS\n\\!=\u0007sɮc>\u001d˘0*[MI9\r\u0011a6}\u0007@r7\u0001\u000f\u0017?5,6ŊۥZ\u0007m]ʭ +|wVu\u001fZΗ!;z;C\u0014\u0007O\u0001.aOY\bd$S##O4sX\u0001ի\u0016\u001bwnWmC\u0013]Z\u0012s\u00170\u001f|@\u0019R\u0011&W\u0011,\u001bN\u0003{\r\u0019ɗH\u001d?ˠ~\u0001&!2QFqAlHr\u001f+Hg=$m\u0016\u0018\u0014M06 Q\u001e}A\u0007\rai-C\u0014PX\u0015%k\u0016JB\u0014+:\u0016b\u000b!\u001dăn/\u0004\u001cKQ\fDA\u0013r\u0004!FDL\u0014N\u0012\u0016-\"pԇ^\u001fg\r\u0004\bkR\u0005^\nhV(R\u0002-ODR\u0011X~*-4\u0017a(\u001c\u0018D\u0016!-V|\u0006\u001f\t\u0015\u0000%EbD\"\u0012ykɒyF9ږ\u0005\u0014B\u0015 6K8=ȋ%B\u001f2U{7Ff\u001dU^̽(#\u0014!\u0016'.\n}\b}\u0019\u000fg$\f\u000e'?f)F\u0003KR\u000b\u001e@/eXo\u0017r\u001dm'I\u001f7?5C,\u0011ᆚ\u0004+\n\b5^\u0000\u0000u-g,Q\u0012)\\Z\u000bz.\u0016R)S\nm|EW\u001c`aņ\u000e\u0010yqEY>\u0017Ma%\u0000ds`TCߟq\u0005*@V#jf\beAT<\u0010\t\u0006;\u000e\u001deus0\u000bVe\u0014bR\u001aceXs^zˡ\u0004\u000fX\b\u000f4PvbhB~hb0\"B\u001bڛ{2\u0016Ft+\u0005\nEVZUOIj\u001d,+u\u0001PS\u0012\u0012Oc}TVQ\u001eqQ\u0004Zmu#\r\"[^PF\u000f\u0003\t^X\u0010\tO'r\bKX5j}K\u001ag\u0007\u00175#^\u0014p\u0019K\u0011$\u0012ou\u0000\u0015Iŧ)\u0003\u0016\u0006\u001a,exo,#Tr\t'\u0016-$\u000b^D~ʑn>\u001dx\u00106@%\b\nb\u001e|\u0003\u0016QՔ%\u0004^B\u001e҉\u0007\"YFm\n8<YM\b\bzwzʇ\u0016}&_:j\"\"zv\u0010\u0011]8*Z\u0019mHBR\r~WhZTf:\u0005XBi\t)T翏$e\u0014H\u0014#:<{Dѣ\u0017g\u0007jN\u0017\u0005\bC]{\fˢ\t%T.?e;\u0014(\u0007IWIGIK0RD,r\u0001=-!^\b{Epկ$\u0014\u0002p\u001d3o'N`^\u001elw\u0007}YΓ*5FdE\n3+\u0013\t\u0010~\u000ftˈ\u0013U!R:B\u001ep|\u0017\u0015L'O=V\u001ct\b|\u0011]Z\u0003A|%ln*0˺Y%z]+DSp\u0007p^R0ep:mAd\u001b#El\u0019kvQ\u0019\u0017Zs\u0013\u0006m07*\u001fӗά\u001e,\nZ9Oz$;9E1V\u0014Z$)V5Wǃ*`\fFsBȤ]m<׬\u0012ྒྷb\u0017dKd@Gzey\fһ3I(#\u001f\u0012K%((?*)Q4Ψ\u000f\f\fׯ4\u0015,1*\b\u000f NO\u0018=O]\u0012㦁\u0003e_%fLxP0䮨\u0010RxU\u000bGט\u0005:e \u000e\u0003AO0䦂x\u000f\u0003l\u000bEr\u0002h\b]YCަ4\u000f\u0011s\fq#4\u000e-\u0012կ\u0016<\u0000\u001ad]BmR8\u0014;\r\u0011a\u0005A2!\"`\u0018J\u0010X\u0010踈қ(\u0015T\u0001\b7\u0012p5\u0007\u00181\u0007\u0006XS\u000e$NmQ<\u001duنeO\u0004@H>q\"\u0000\nRw\fWSʚ\u0016B%\u0000N\u0001wD\n\t\u001a+\u0014\u0012\u0005Y\u0016ݚ\u000fe#`=0x\u001fx*;6ebB<]\u0010e\bx@\u0003\u001e\f@\u0012U\u0019\u0016uRmdӬqd\ru\u0014\\[\u000e9QR&Gd\u001a#\u001f\n%n\u001d\u001anWeX\u001aќΉj\b16A$\u00142DP\u0004s;M.\"\u000b\u00103I\u0011\n/\u0011\u0007Tr;dpQBO\u001e\u0010\u000e\u0018%%4L\u0019.\u0000HM:h#PX\u0019h]Je\u0010l|wᾣ2DHSZ\"jAȢVx!$\u0014̏^D\u0006\u001c\u0006R)\u0006$\u0001UcYDF8\u0010\u0019f\u0000w\bo\u001aT\u0002A*im\u0013\u0004`\"r8\u0013 >@GU\u0010Br\u0018xۚBC*X\u0019= mPOyuUСb$\u001dN{0łK+桃y\u0014CHߪg94QEa3!>X}%\u0010QX\u000fR\"c-UW<dD\nvRENl\u000e}sW+8ظ慩\u0001aۭT!Y]\u0006CD\u001d6q\u0011\u001cq\u0014`U`O\fb\b\u0011!@?g\u0012EٶCW(ڈnD\u001aH<D\u0001mf{uq\u0006%aKsM9݀2@i$ЧZ\u0001u\u00165\t\u0006HODzn\u0001\u0003*~<N\b#4e3D\u0001$#\rdn:c\u0015҂\u000e36(D#N\u000e(e_2 \u0004\n5ptGC@\u0016\u0000w&(\n:K/K\u0005ъ\u0017k}cJ\\9>\u0019@K\" kH%rqDY߯\u001e+m\u000eɒLҮ\u000f\u0000ҟzv\u0012X\u001a\u001fsa2\rVFLyZM@iY(\u000eͿf\"\u001281 Z5HY>*W*0\u001a\nSLښHm{\u000e\"\u0007I;\r#0'^\u0005﹄ٍ\fSU=y`QO+F)\u0006\u0004NI鼭l\u0011Ѱ\t!U\u0011\u0011VrbD%\u000f\\\u000b@'2fqZs_\u0007U\u001a=PPea\u0004TJX\u0004\u0007&\u001fc+N/z\u0005\u0006\u0015gp\u0004FɝZ\u00170.>*-$9}\b\u0006sML{r{fqKq'?\u000b/P#>k?`yM\"7F5(8>L}jc\u0004\taCaI\u0016n=\u001f\u001f%\u0007\flkjfڹ(\u0011U:Xj\u0016Q\u0003OH\u001e~ƼK;\u001bIQXVu7!G\bҠ\u0004l/A\"\b\rI\u0005\u001aIٰ]8I$k\u001bhgq\u0006\\k\u0004;\u001dTM\u0004鉵\u0001]B\u001cNoXT^\fa\u0003\u0017b~:/Y\u000f{u$I\u0016\n̴Vv\u0014Kl\u001d\u0007\r\u0011=D\u0019t\u0017kbV\fN\u001a=<\u000bsS\u001ax_v\u001aP$\tD^eU\u001cAbM\u0015):<].%N--󋻭\u001eơc\t+3;\u0001#\tw\u0015ґ$wZ\u0001\u0007#\u001a\u0018{2\u0014:\tW\n(\"\u0005eOIQk[{rO\u001bVD\u0006E%5\t\u0003\u0005Rfi\u0001I\tq\b\r}'I\u0015)\bfz\u0004\"<1H;<\b\u0010!?<M\u0018Rg\u0007-H*u]~g%K\u0000ZK0Z4})WѦт:ʰxR\b Rkݣ؞xİ5`\"NZÚ6r\u00158\u0015k$*V=j\u0000je\reS\u0007y\u001aM\u000bB)>kCBo(oH@\u001b2cq:\u001e ),;\u000bq\fԫr*Y\u0000,e`ݴ\u000b\t\u001crx)dIs\\1\n{_v\u0012v\u0000s\u0016\bDb\t}\u001fW,\u0011,a$\u001a6ԅ7*9E&u\fI̸Z \u0015[^h-pIj+B\u0002m\u0014vD9=\\-\u0001,\u0005\u0005\u0006\u0014\u0001~8%*X\tҗ\u0016:\u0014\u001dQLl\u001dsT_w{Ɋc_(ؤ?d\u001ay?o(Gχ\"\u000e^El{R$]T\u0014>- JxwKԢeǙ6GK\u0019RRv\u0000\u0015\u001dCRFU#rxq&\te\\Ap\u001f'G]j{$Z\\Brq\u0006\u000e@Q\u000bQQ;$\u0002\u001d!\u000b3I\u001a/}e0\tSRtJ\u0015ziVSEM\"b\u0011d\u0005h\u001c\u0014sofC'7SzRKdfK\u0019S]\u0003#\r|~`g}p\\?g\u0013<{ĞQ Uq0\u0012P\u001a\u0002\n\u0011LR\f@z\"\u001fQ%QD$KC*=9M4@\u000f`JP\u0019}5IWJy\u0014ք\u0017Hɬ%W\u0018U $a \u0002Q:N\u0012LI¸\u0002tE\u0004r9Y\u0014j\u0018w\u0016LJt}\f9\u000bR'=O\u00003\u0004>\u0005|\u0002qZvĞZ}\u0002\u0003a\u001du\u0019,풽ckZ\rTUS\u001dop(KNPC\u00112D7Gºo-KfMJ{*\u0015+:4\t[w\u001ax\u001dҺB\u0001E!\u000bA\u0011嵲D@\u0010L)N\u0004ƢxI?ONl^rLZ\u0006\u0014\\2\u001d?×5\r-wp.a\tRJg\u00144\u001a\"\u0004C\u0011\u0014!7ZWx\\D\u001d\t/}y,T|c\u0012B\u0002'h|\u0007\u001c\u0016cE,7\u0000\u0010\u00140)j_(#P\u0007ŉ~&_&|Z`k5Ƃdyo+Z}yI\u000b(`\u0002\u0012FT9\ra2Bm<$\r\u0011\u0012\u0005t\u0019\u0002d\u001ex`t\u0018ԉJ\u0012Z\u0001Z$\u0017\u0004\u0003l@ȃ(\u000be\u001c,\u000fT\u0014\u0006'0R\u0015,h\u001bP]6Er}+9k\u0011\\2IVE{&S\u0010k\u001c՟\u0001j\u001eȥCtg\u0004M\u001c\u001ed\u0015Df3A[\u0004H1[׷RҢ\u0014Q4PPğ\b;\u0002)1EX\u00021jM\ruyBerQPސ\u0002ϗ~${u\u001cVaxԂ$R\u0004\u0016:\u001ct,PUH`v{H{P\u0013Wj\u0001˜\u001cojC@ang<n\ts-<S]9\u0014\\>shZC\rU\u0005RŗC\u0013Ĥة݁^\"P'*z\u0000QÜ$)JIb\u0012x\u0013L\u0007`ӎ\u001f!\u0005\u0012j}%}Ӧ'2jG\u000ede,NDt<(\u001aU܆+\u0002Mi(#1+ NӔ\u0006t\u0014\b*\"\u00135\u0005w86\u0018d\b5\\\u0013/qh!\u0010&=@xJqm6EE3\u0011#\\:T\t2k0͖قP5[N\u0011\\Ya\u001fBeX`F\u0004an{z^4ǽ\u0017\bؐz^\r's%\u001d\u001e0\u0015@\u00010D^\u001f\u001dӖ\u001ey7QM}p&aҮ\u0003a\u0002\u0013\u0005Y\u0019Okpa\u000evO\tD\u0006a.κӆ\f`x\u0002:\u0001}\n\u001f1\u0014=4\u00183n[xd4\u001ak\u0019҉عq^BJ\bJ\rhNv%p$&\u0001k\u0013QW*$(\r9C\u0010_%H\u0016c\n\u0019- I\u0016$\u0002\u0002XoF\u0012ds\fj4,$EО\u000f\fe5\nÈF,\u0000B\bۇ\u0017H\u001e\u0010ͷő\u0000MjTu\u0015\u0004v~-E\u0001[\u0010TdК\u00108\u0000S@$ѳ[9/7[d!؀\u0017\u0011\u000bOzt0*](;8Q\n\u0011~\u0011i]>\n\r2\tj\u0015Vh\u0018梗G\u0019ʴ4zNtĴ GI!\u0002҃MJ2H9܎k@翔\u0016|Q5%\u0001oǸ\tI`uln=?X:\u0018#\u0013[ZB%^ԎejI)e\u0006%ux\u0010L=ejZ$@JL\u000f\bjU\t֦v#\u0012%S><mg5ՔвW(\u0007#ז9uU3t'㰣\u0012H؆MW|hn9R#Rwig A@|8\u0011Ȓш\u001d=&te.Qd\u0011\u0018\u0001U\n\nM\rL\u0000A.\u001brS\u001d2\bV,Y\bZ@ȭ3Z4!Ϸ\u001f\tX\u000e*\u0014\u0016-IG\u000ef՜k\u0016\u0014=L@vpE~`vEGf^jGka\u0012M%\u0003tᙠ::ʹK=\u0018vtALt^v\u00012`S\u001dW3dtY񾉘ٍx6\u001c$\u0011h&#.AI\u0000L$?o;sO6Ŵ\u0007\nEB<;6WJ\u0007\u0006q\u0007uHAj\n̤T'pU\u001fɌeKY\u001d\u0007\u0018*EB\u001cm\u0001j\u0010&T\u000eQ6\f\u0012a\u001a\u000eYjzX(U΢+\f\u0002~\u0017c\b2\u001b\u001dz̴ɕN7I涰.(S$lXw|c\u0019) D;],KDHK^[<c\u0001\u001e?B\rͧ\u001dї\u0013\u001d+^vY)3Ұz`\n>~w\u001d\u000e\"\u0007p)&Q\u0010B]2\u000b\u001d\u0005#E\u001e\u0012(\\8MRW\to\u0002H\r\u001f-Xs^S+\u0016z?k*=X\u0014\u0006/(^v\f7;9Vcfg֞y\u0017&\u0000\u0014\u001aߣ퉓f\u000e;7^\u0015W੅xYڨ/~Sj*\u000eU\"}++l\u00176Ш}aYŔ\u0001m,RDهZ+yQyg\u001d5\u0016-|^vRU6\u0000\u0013\u0016(a,\u000f\u001dxғ7[\u0014B\u001f;\u0011DHAȎ&&sAjIe\u0004ڹݗt>\f\u0012%4\u001dhL0Uيdce\u000b\u0013aa74ѤxNʏp=7s\u000b)њ\u001ex\f#5Ϗ(>o\u0016\u0006]WFv4D%\u0003\u0012JxNfĳ\u001c\"\u0007Mch(P\u0019Uc\u0004g\u0011FWo4ztXI'2R\u00139X9t 1;)\u0018-$̥[3D7%K+j&w\u0006T;]-\u001aJ3<|\u001d?\u0003SD\u0007s\u0014L=s\u0002;JlY8Tc\u0015\u001a^#\rٯQ\u001d|B\u0006U&\u0001\u00022@y\u000f\u0006yQ۞2Ta%D\"ZC\u001clM!Pp\u0011Dn],\"\u0016g\u0016O+{\u0016ӠpcxX\u0000k\f{s*C\u001dY{\u0013%Tm\u0000Bd/[Y\u00149\u0012VǉOA\u0004$*\b\u00017\"Vyz\u0004\u0003(\u00021\u0011iݖ\u0007\u0011\u0011\nj4UR\u0005bL\u001d\u001cd\u0018ꎃ\u0019m@wkG<!'-k\u001b\rSE\u000erTo=DئȅI\u0002\u00022<r0F|\u0019/;\u0004`\u001ee*\u0004{\u0004^&K^E\u00163 m\u0013cI[o\u000bLKtu\u0002Q}B$-S\u0007\t\u0005z#f]q\u001aqe̬vNѾ:.\fQٳTcK\"K=@\u000bs&B6!/c\nD\u000f)g:@i\tŐ~\u0016+RST@>HK\u0012waZՇJ/\u0012\u0012+zϒ%=\u0004P$J)dw\u0011I69C8K-\u0013EXVlcD\\m2C5\u0016W5X\u0017dUq\r\u0018OM`HiXS\u0003l\u001ey]\u0002(LS<~\u001b\r)\rQ\u0010n9v0W:J\u0015\u0000Njy\u001c\u001eluã\u0001s\u0015DWq!x&$TȩR @\u001b/![-_%9\u0015a(4S^2/ZP#NL\u0002EA\u001e\u001a\u0014)K2Cȇ\u0018ReG\u0005eRRݚ^\u001bh!\u0015PO\u00045\u00051ٴ\"u\u001b{#:\u0012\u0018aCGQ/\b\u000f.4(x*J\u001bDCe&gP\u0015\u001dɇ\u0017* u`~c5<\u000f\u0005OC:SuXtX*|\t\u0006\u001a\u000fxPhawY~h)H\u001f-C\u001a\u001ePZ-'KāG\f(̶Sl74\u0002/p\u0012Vx<fs%N\u0012Q6>G5\n\u0007\u0004a\u001fQ-a/=4\u001aRM3NKl&$\u0019i\u0013;nQ\\_rd\\Zy+:*]\u0003$ǎ2\u001f\u001d\u0016\u001dU\u000b%9E\bc\t\u0007K<〷qG1\u000e7VrPκեv0O\u000fjF^6\u001e>\u001c20+Y\u0013 \u000fG\u0017!ODy\u0013\u0000Ft}wD+;׫餣\u0015;mL\u0015-!21-Gx@7}M\u0019a!ހj;|?mQPKh\t\u0014\b=\u0007zz/AI\"!6\u0002f\u0013\u0005\"\u0007͔\u00150\u0007O-R\u0015'\u0000\u0004΃\u0003s\rwr+[B\u0013vUfD@\u0016p\u00190z\u0013Ve#\u0007+\"kDn_8x\u001dJvˋ\u001cttE{\u0012%\u00131\u001a-FHP\fA\u0014\u0014Jt!oc9a)%cbYr\u0019C+![|\u0018t\u0018>\u0007vHL?\tO\u0018vX={j\u0004ΐ/8 ]\u0016W\u0004KDC,\b?IG\fk>\u0005\fV+$PR\u001cӬ9\nESD֨>\u0007$\u0007˧}9\u001e}-V=;s\u0003))rT\fҰ(!k\u0015\u0011\u0016xs\u001cP6Bl+ҙ\u0014W$Jյ(\u0002Y\u001c׮BAԃK=v\u00179\f-R\u0014.c|4\u0004\u000b\u001fjT\u001a>Z5ӆI\\\u0002d\u000fЌY\u001d,>m!\f'Jf@I^*>ͦ\bv)t%VfC\u000f'\u0017_=L\u0010\u0014ѥLes\t\nu/\u0003hDR{\u0015u\b}\u0010w\u0007\b\\E\"O#[ݢCr|&z\\р!\u0003|\u001b%a87x\u0000;Oc\u0011B{PRH\n\u001d}\u0012\u0011n5L~\u0014RBͦ\u0011ѵ@~&-\u0012\u0015]\u001c{En\nw\u001aH\u0003\rJ!4͔(3jZS[Ub\u0013N\u0001rtȽ\u0006IҪ|ምh#cRSys\u0014+U\u001dJ\nw\u0001\u0017W\u0000\u001d@S\u0010$.NCLLGm\u0004QG;bfMwr<,\u0018Ad(\u001eQI\u00026G0\u0010\u0012Ҥ햂\"X􊅉`h۲ז\u0013٬-Q@E\u0006]!EAUEA\u000ez:p+c~Q\u0016\u0006P\u0003\u0004]c.JkZ\u001eE,\u0017.$9s\u0014A&;_X\u00112/k\f2\u0011,\u000e|pa:\r(\u0002\"?G\u000e\u0006ei.\u0007Ő8K*4>GR(j.P\u0013QT6\u0014zȱ{\u0019zPW\u000eoiU|,2P#C\u0003Pa\u0002(t\u0002Q\u001f\u0014U!cZ%)M\u0002ޫJq)ZHIR<MVtAky/TO\u0015O<@بۃ\u0019\u001d1\u001dA2/Qغ(+%ٹjK\u001e^=S$I'\tI?I\u0010n\rendstream\rendobj\r178 0 obj\r<</Length 65536>>stream\r\nBi\u0007)i\b>!\u0019&DE\u000ex/(I%H:ܟ觿>h\u0017\u0012\u000eEc\u001e@\u001cW\b\u0018?\"O\\VZԾ%SZKM*f3\fA}|uG 3OIi>5YUh\u00022(\u0016\u001fbP\u0011~q}X\u0012Lzk\u0018O\u000b20}1Ƶ\u000e>\u0015$֍ʟ\u0002\u001btP\r?\u0001c~DI\n\u001fx\u000b5VK\u001a4\u001f\u001f~d?o~>o_~_\u0017/S_O/w_~otq)/_ywo~nnߐ?3o_}\u0005_o~˞=/\u001cOW\u0011؋??\u0011q߾|}?߽?>_%wqHvⱧ\u001a\bO\u0003S\u001dn\u001fo~\r9ԇyq,\u001c\u00055D\nX\u0017YOJ}-}b7݂~E\u001fl;?Cj[}%Jab}޼rluOi\u0007*6?\nr\u001b\u0003<ΆOx6?\u0010*$OGAN\u0003O'=O<P=\u001fA雿|mn\u00192̿,~|\u0001z\u001c6[\u0010߽?rL%pOjW\u0007Z\u000f_o~o qu\u001f?\u001dݴ#G\"?6}\fVWފx\u0004q\u0003`\u0010\u000e!\u0013xQ_V3Eg<\u001b\u00142˛Qf3\u0017o\u001f!\u0012޸5m\u0013,G._l.\u0016~F\u0001t\n\u001b/\u0003\u00197_S\u0010CZsdٗ\u0005>ݗŸHh}q\u0000if}sČ-_\u00167v\u001a0$cW\u00137/lD /oD\t\u000f\n7Ntl~K\u00030{ݱވ\u0011״Ә7c\u0004\u0002e)I\u0002?A$n\u000ebzW7s|\u000b2Tڦg䍭n#̣Dy/o\u0010P\u0003:\u0000JkD\bU\u001aMz[{k\u0018.D|Uբ\u000e\b\u0014\u000b7\"\u001e\u0017noKŬ>\u0000\u001f=إ8Y\u0005i\u0018\u0000hc0۹ݫy;qy\u001eM1w\u001f5\u001c~@N@zբS햋{(\u0013>\u001aߝ?%?1\rhYN\"ll'+\u0013דF>\u0000i1v<wW\u0003gܸpRc0GQԖ\u000b٧G\u0007\t=KǼWE\fM\u0003\u001d;\u00013h#N]\u0015h\u0018T[\u001dW\u001eJ~m\u001d{y\u0019_E'o;CL\tG<QbNf\u0014JZYE\u0000\u0014sl/zS錃A<Mcfi=\u000e\u0010hޢ\u0017\u0018D0~̫ʺ4B\u0000>>b@\rc.ksk\u001b~\u0005ܛ{g;MsIk&>P*ĹD\u0012qoқ?[VL`\r\u0018!!?O;==~߽?b$g|O\u0007zOotc|>ѥ1Q^N/>wsftOG\u0013?qRfs'şNO'}=9)㓆'7:Ҙד>6>˱O_O.餏͟NWNmtcQ__~w\u0001\u0003\u0013$\u0010v)~6}'/bwI\u001bn[a~4UiU\u001e&hl\u001b,@셌o&st\u001f\u0000OÛ+غ8\u0000X\u001d\u0015\u0002\u0013\u000f툅Ώg3$)Ń\u0001duGW<{\u0010;C_0\b\u0014ͨ2^ɛՌF\u0010\u0016x\u0015tp+,\u000ejq\u001d嵡o\u0012ۛfg3p8=R\u0012?\u0004\u0015wC16g:3~\bv?\u0012\u000bmX\u001fͿvsI'\u0016$7~uQ\u0001Y\u0003\\O,QzƧmOG1\u0014K\u000f.ʦ~ߥ=m>odcǘq3憤wYd\u0015\u0012\u000fXiq96fcsߚ*\u0004.}n\u0014\u001d\u001255\u0005s55eqh%x3}>,L\"Bg\u00070|\u001c:\u0012|}WX\u001b\u001c\u001e\"\r2k̿~.q>\u001d|m\u001aE)Χ\u0011\\Z>!xW\\\u0019\u0016TWW<\u001fo=\u0006u>t\u0018H\u0018+F'\u001cl-ǈ\u00053Fhݶt:W\u001f垁z\\\u0007m\u0019\u000fof<ƞ\u0002\t\u0012zpl\u001ej\u0017|r\u000eu?I(o/qO'<W\\\u0006C\u001dVẕ#Ȃ'~s8_\u0015\u0017ͫ<#\u0019c߻Qgk\u0018]16ZV_5MRU{s\\6u\u0017Ц\u001f(ve/\u000b%8嫔K\u001c`\u000e\u0018刅\u0010\u0013̫Fg,-\u0003<\u0015 \u0018GM=O?<\u000e4?R\u0019AAz#\u0002rq\u0010:҈=]\u0019Ry\u0019/3<\u001a#$pi+\u000eJl.1H/gБ\u001b{S\u0018~K?\u0015\u001b[xwYM팩W'W3'ֽqPg\bǿ86R\u001c.u\u0013։\u0017NX/G}\u0010p\u0006|.m{\b\u0000\u0005L\u0014:9#85!3!%{z:.f\u001e&\nzW\b4\u00077j>\u001buF\t\u001c\u0014\u000f\u001d]'E\u001f\u0005p1o\u00184˹\u00194ϛ\riQS*\u001eZ94t\tKKq/VI\u001ds:^#\u001a65\u001e[?\u001f1\r\u00114clv\u0015\u001bs.TλYӾUoJ_9cx޴\u0001HohXg$\u001fv\u0012y{/>WzZ/\u000f'\\?/%H\u0010\b~\u00123no_ .\rAtR|O$O'o8\u0013|\u0000ƙGp_9[_\u0003ǹ\u0004Ɩά5=^\u0010\t;m\u001d1\u001f\u0002:ovdxӜ|B\u0013OlV徍5דc~?v-nC\u00151'v\u0003\u00171\u001d;]RuCdp\")4_!m\no\u001cȀ\u001f8\u0000|8YJP^\u0001\u0014Gww\u0012}v\u0012\u000e@h-8\u001b*Kk\u001c ;\u000bG \u0015쥥{-ldMe]{_,~]iQT}\u001ff7\u0014\u0011\u000e\r\u0013w9c\\o\b$o9{{8#U\"2\"\u00039T4r=\u0004_ǅ>{-^<iq\u0016X\u0000F\u001fV\u001b9\u0003HZI\u001bU\u0007\b7]D\u0000hF\rݽ,e\u0001%(i;3F\u0003Q(\u0012-,\u001c\u0014\u0014\u0011\u0019ʬf\u0001\t0[-\u0015p\u0010/3U{6\u0016$\u0014/r\u0018:Π\u0005\u001b\tG\u000f(\u0016\u0013HԠ\u0019PS\u000e}_\u0004؆5d\b\n)`MԞn%\u0015**?t\u0019\u00185\u0010\u0015`J\u001bR\u001c7y;d,̅ځ\u000b\"ͽ:}i/\u0013\u0012R(d\u0017:Y&U$\u0007\u001c\tA\u0002\u000ef+ë\u00127h\u0004\u0012\u0015M(u\u001fL\u000e/X/[_̠nni؝Rg%\u0014ϸ8b_;HΦ6\u001ag;To{`f\u0014nLO\u0000qG\u0014a\u001c\n(u\u0004F?}'ն1N\n8=\u0016\u0001:uf\u000b\u0012[n\u0014Zݎ[cvaNn\tWKt ֨ks\u000b1[&:&܈[oYz\u00190\rǲdJ<|_\u0000I\u0002\u001cQ\u0014vbQ\u0002Ө\t\u0018SXLC>@\rY`So]٪F\t3\u000b\bΏI,(!\u0012_ȦQ\u0002g j͋ͪ\u001e\b\u0003F'\n[\u001ddzy\u0019Cd&t{aH\u0013uOW$S(I\u0013\u0012=N\r*\u000f&\u0014<9v!u\u0013lou\u0016M\u0012C\u00062AFER2\u000enEF;\u000eFe\u0012I&΍\n\u0004\u000bmDͩ\u00056\\\t\u0012c|PN7\u000e9z\u001d͉\u0003p0_BA۩9Anl#x6,d\u001d\"3\u001aȵ:sbJIC3\u0003P\u0001vW\u001b՝Bby\u0013aj^RAY?\u0018\u0010l\u0016zRnf>\r\u0007QF<v\u0003\u000f$\u0015\\Ô\u00186(~\u0010j\u000e`f\u0014\u0005Hi3E;[\u001eš\b)w}\ni|#\u0017R\u0002`2ߨ(\u0001W1\u0013pg\u000bՋ\"\f`1\u001c\u0011d\u00005\u0000\u0002dgnE4\u0003K>\u001bs\u001aIX΀%k3(\u001f-\u001a\u0010=|&2\nʏD[rbFP\u001a\u0018H\u0013fDD?UpȾ\u0000#K~Mxq\u000e4SǙWqOf7M{\n\u0010\u001aV҄\u0005ɸ\u0006n0)r9(N<9sT1=%EU+|Y\r{avjV\u0019\u0002`\u001d6@應q\u0018l\b\u001cr]Q7\\LC1\u0018r茺\u0006\u000e$g\u00138n`~Tj1Y?TfDh\nti(cAHk\u0003\tx\u0011\u0000,CR`\u001dkCsV\u001aG\b%\u0000f{D\ftj\\'`PL\u0015yw\u0013?\u000fvUH\r\u0001\u000fMEW\u00015\u000b1@7<gu-&hV:\u000f{&\u0019g\u0015\u0005Ao<WxMQ\u0006V\u001c^jfi/j\u0001P\u00197\u0007\u001d,D>.9UoD\nju\u001b^V{m\u0004l@\u0013V;Rnh\u0005\u0001B\u001f@57\u00066{ʖ3xOh\u00143iLtz#sf>\u0007\u0003I'v:|k\rJ6eJd\fƩ\u001e0ҺEd*S<P\u0016\u0004a\u001dי3`rgF7PY?k\u0001\u00136`Z\u001125է\u0016G\u0014m\u0010:,\u0014޺khgϪi(\u000bQ>\u0000G\u00101i͖Zb\u0019\u0017õR\t5\u0001ЉRT\u000b 33\u0006,SE\u001fSZӪ`\u0019\u0000TA\u0011\u0006\u000fB\u0000T\u0016ـ\u0000f^G3\u0006mUh{\u0003j\u0007&i\u0000R\u0014PbFt>\u0012zQaZNu*\r2)$\f\u0007[\u0015lEQs; T\u0010\u0015x\n6-4JnhtJ\u0012kN1\u001cb\u0000D+\u0001!\u000f\u001d8\u0014㠃M\u00118Ĵ~`Rp\u0011\u0001{}\u0016U[\u0015\t\n\u0002fC{C`Fuqbh1L-\u0010l]M2@ǛU':ңkאF\u000f\u000b3FH5\u0001\u0003CqRUJk\u001b-\nkzpq\u001e\u00155\u0012Q\u0016-ae)}VmjOg\u001f*S\u0005s:\u00031|[I--\u00060\u0003mcg8T\t\u0004d8(.F\u0006@\u001c!\u001e\u0018N\u0015\u0000\u001bE\u001aJ(>oX\u0016JC(^o\u0003X밨\u0014B7\u000f9$\u00152\u00040\u001b1M9\f\u0013t\tNX\u0000a\u0011\u0019S5\u0019&`iT\u0015C\f6}\n4\u0013\u0000a\\\u0001k<+P1d\r\t\u0011#\nMǪIP)+'m֮4@\u0006DYO[\nENA~^\u000fʶ\u001ė\u0015\u0012G]\u001a%\nK\u0010+&)з\bQlp&N\u0010Ѝ\u0004:m(jztpC=j4\u0001O0)c4̥?\u0005j8V\u0002\u001f\u0014QK̞\u001a\u001e\u0010K'6\u0018%V?k\u0003\"wL\u0012Ԉد\u0006*E\u0004l fQbT1`ֽo(F\u0018G\u0005ȍR\fP:\n\u001c\u00157\"Fg8<+\"@M\u000f\u0001.'1\fng\u0013\u0006\u000eK\u0010Qot\u000fF\u0019E.DgYpAmYQ\tۭ:AU;pdj\fW1-\\ѬA\u0011\u0019<\u0004sbYSղ8guT;\nr.s\u001f vw\u001b-HQ]aw\u0018{`\\z=\\NYn\u0001Bj]%\f:j66B=a\\BVs3\u0006h\u0007\u001cakǍ:2\"\u0011ozu\\RI~\u0006Q\u0001E\u0019F3\u0001C\u0005'siI(JeAH\u000eTH\u00127Cg_\u0011ա[8\u0003S@ّ'\u0013\u0000z\u0013Nv\\z7Ļ\t\u0000\u0001f%XWAV\u0007LX_\u0005*b&\u0017`̶1g\u0010m\\v\u001auh\u0018\u0016lbI-zt\u0006C/le,\u001d8J.\u0000&@3d\u000eX\\Y/&3pr4\bT\u0010\bu@ \"j\u0000-Lm\u0013Bpl\u001e\fX\\\u0000#l98o\"wrT js\u0019\u00016\u0006\u0018\\4\u001e\u0007[L\u000byU(\u0000-4x\\\u0017\u0001Yw!lϖdaT\u0015o\u001cY%M(Y(6S\u000fUJvnz\u0007nV/ͪT~\"\u00139\u0019~\u001cBǫb\u0018&#iJ7\u0007Q>\u001adMX&ްɮ-(5\u001e#:x6v\rT\u0019^@+z#j\u0015l&\u0017f*<\u0019J\u0007\u0016\"\u0004Dc\u0005\u0015Jpl;e\u0011ذ^-O\u0003dv\u001a\u0015\u0014\u0007Ss4=)\u000f/,Hg}D\u0019o] 2̀\u00055;3(n!\\zכ\u0003%bƮG\u0000a(\u001c\n\u001dY#HQ@mIX\u0006p@YG;P\u0018|A1ߺ \u00048TLHC)~?9P14\u0007:#\u0007 sZ\u000fè]ǏJ&t4\u0002a\u0003\u0014<\u0000.{Dz\u000eM,=J\fh`\u001ex_{~_\u0013orUem\"`\u00171W\u000b8qC&duC2ԆKwqVod\u00028\u0001B'%g\u001e\u0015$En\u0002Z\u0002JSu\u000ea>\u001e0\u0003]Yj\u0013\nјO=\u000e\u0010RjN\u001a-Mx\ru\u000boĨެ{ŧn\u0011P͔zRޘZxDpC%\r\u0010\u0017C\u0016ZUFڟ]G!~\u0018@ȓ7UЩG\u000bRs\u0004zR\u0018v)\u0000Λ9؟-&8EZ\u001awhTT6WGVb5̢ӐuV\u001cIb\u0003>\u0000sM\u0005\u000e]V\u0003\u0018\u00133ʥ\u0007\u0005ѳ)Yl1\t/KZD\\\u000f;\u001e\u0000\u0007S,tK\u0004`\u0007\rV\u0007(*qx$\fg]Pu\u0015o*죆\"RW\u0015QYs\u0017rK\u0013\u001a\t\u0010W5\u0015Aq\u0003X@]hl\u001a\u0018h:#\\N<\t8idL\f7ʭg1Ȱ&\u0003n\u0010bXj\u0012at\u0012\u001c=(A\u001aA]\u0017$ʃd!lB,ZҶ\u0018ax]\u000b\u001a`\u000bG.9DPuu(!.\u001b\u0011\r\u0016\u0016 #]9es\f8=?6{kҦbQeQ<L\u00026#\u0002j03h\u001bf1`\u0010M\u001b`Q{\\h.\ncVs6DYnY!\u001d c\u0018\f8\u0007S1[ɽp\r@I4;ΎF\u000eL0[*ؤ\u00005\u001bw܉;Ԣ$\u00116\u0011#\u0007\u001eJ{O2Gn8out\u0012\u000f>\u000ev<4ޛЅ\u0006OZ\u000e\u001d\r\u0010ԯ\u0014M\u000e,Ixɔ\u001a4-~\n2Y\u0004\u001czd*\u0011?3s{ӂT0M\u0012@qt\u0004ؔ\u0001j9\t\u001b,({9M4J\u0015˵9_֜h/\u0003Lѳ-\u001c~qm_s?1*\u001du\u00156Gr\u0011bnlC@*Q/\u0016\"-hY\u0016;\u000fg~E\u0016Nr{֢so\u000f`l.\u0003y&Nо\u0004iG0ޫ8K6@̓=iJ\u001c)Z,z D1\u0016q1\n\u000b:bh$\u000bn_o\u00153Ʈcu{.k\"\u0011\u0010XIS\u0011\u00034\u0018h\u001b2O\r\u001c-U(ag!\\\u001a\u0012`.r27\u0010kDσd\b0%7\u0004@02`\u0004E9@k|,\u0018&\r#{-D\noU\u0018-\u0000OTylͽH;n\rg`\u0017\"$1C\n=\u00057\u0018Ao\u0001W\u000eUuu|\u0010_taZ\u0004}5ha^\"\u001cI&(\u0005\u0011M!\u001d8\"jO*ʚnUĕBO<oN?0\u0012jW,H\fdU7*=7i:){͡ SD`<By,dZ BޥHFo\u0016V\u000bO\rCq\u0007\u0002s1E׍-Z\u0004`t \u0001``6׬*q\u0012RZ\"1WA\u0003\u0000\u0019\u0016d˔1[Heh\u0006\u0010\u0010枟lf!SdcW8\u0001\f]=a\u0012\rԯxԀ!D.w=qε\u0019¨w#gQܰ\n졯Mbf0,\u0001߽\u0018ھMx\u0017}}\f2b\t\u0001\r-\u0017U\u0013anu픩 :L䅡+}\u0000ת\u0004\u000e,/>(ly{\u0015}\u00193\u000e\u000ftDC\\\u0006.*Fۡ\u0001feE^\u000f]\rf]P͖O\u0001\u00135-J_eY`NƘS\u00043\u0003W+v^b񃕽tǒ:\u0000ܵ3\u0013HQ}ŹAX@\u0013]f:\b=\b%2\u001c#z\u0013;zDs\u0019T\\$b^ +A55\u001aCm\u0018~IE\u000fW\u0013%yLC\u0002\rb9f\u0018Kͤ\u0002㘚sʶ&\u0001SCbˡR#2\f&\u0003O˗w\u0003X0\u000b*V\fq,4ө9ZMU\u0011\u001eG\u0007I\u0000?\r=}!b\u001c*Xj\\B\u000b\u0017q\u0001FlXrʢ&^f\bsch7{XA\f-ƀ\u0007\u000bN\\5C6$2`f̀&\u001e[vvPd̝n\u0014Ed-\f݁\u000fQ\"\n\u001e\r:\u0016\u0013Kݸ݊EBudkE\u001eű\u000fcYNXg9,Nk:If%\u000ePf\u0017\u0011Q6\u0006\u000bI=Qr!0I\r@y8]ʂ\u0016d\u0001kk[\btdJB Rp>\u001dK \b̖~=U/:\u0015{\u0010]Yt\u0010HK\u001e?&he_U\u0006\t\u0018]GY݈0*L\u0016Ø ' ƨ\u000f\u000eT+΍HG*'Z\nL\u0003t\u0014jF\u001c\u0007h#Ь\u0014%VvK=n\\ڸ}&4щ0ɇ1 b\r!I&M\r]}fi\u001a/puvK1ö\u0019\u0018SQP\u0007\u0017\u0010b\u0004_*}Q{.=5\u001d\u0006ՄNKÄ(w\fѕ%9tENqQx\u0016\u00030>5\u001fz8JYN\u0001ά\u001cAd9^V]*u((\u0012\u0016ߖcws̍8)Rv=Eo\u0013\u0011S,I/g,\u0003QJm\u000fܽ\u0019\u00176\u0000<'0bO\u001ay[Rqy\u0013}͙%\u001amj\u0011A&:*\u0004?lʵW\u0005MRu\u000fpiS\u0005a{\"AEX\u0005Q\u0000\u0007#cH\u0019z{Zp\u0013\u0015*\u0006]X\n\u000e:@],E\f\u001as\u0014Y-\n/'˙QՎ,7L6&]\u000bSu*\f4\u001a'jS2G1b:ޕԥ\t.1Zw\u0010MNdQ\u0013\u000e\u001a!\u000e~nL\u0005+y\u001bӥgk3}ϊ%Nz\n@mVj\u00010v\u001ac\n1ڠn\b}ڋD=ÒU\u001a\u0015&\t2/p+}|\u0013XT-\u001a6$\u0007!e\fPH\u0010Gz3Ѳԫ\"1a8I<\bN\u0007\bǦ\u0012d\u0010aԂO@TB-I{(n#\u0013\u0005БϙjB,s\u0011(\u0007K\u0017%ڮ74ב=ak(\u001b\u0001c/z\u0003ьEex\rm\u000bA/\r\u001c{h\u0001\u001ccό\u0006M,\t5(e\u001ee\u0000\u0010IVZ^EwC\u0013?\u0007-'yP|\u000eTu\bO\u0015\\\u0015;\u0004\u000bQ`k\u000e2fU%\u0001'\u001buZX6<K\u001e{ن^ r\u000b\u0014!\r^b̙9.ă\to`|,}~[g\fѴcW\u0006@ׯAw\u00007\u0004y^TbPAܙ*\u0013\u0018ZZ\u0016<~aU요\u0016ggK2\u0017\u00168ظMȳ;%M\u0005PA\u0007-'d\u0007Z\u0014O{|7C\u001a\u0012#-\u00059\u0016{~q\u0000-Nfb\u001a-N\u0005\u0006%M\u0013'c\u001a8FPB92\u0000\n\u001aXW~ݠ[ԛ3LT^\u000b[P\rfhC\u001a\rS9Up\n=R\f?\u001b$-\r\u0006d=r[u؛ߒ6\u0017ӑ\u0019 (2\u0000hYOu\\1\u0005h*-m6[:ڤFhl\u0000'-\u0014\u0018~O\u0015<\u001e؃\u0018f*YdRTVEТa9\u0000ԕ5ayF̅\t81j2\u0014RǛč%\u0005Gcj[޴ h{>V!AJg5TM{Fv\u000fd\r̈P\\)8Y\u001dC;5ȸrV*\u000bhQQc\t\u0010p#m%1/qj\u0015nU;K?]Cg\u001bUۇ10ٚf^]\u0017%RR\u0015!TY\u0004\u000b`\u0018\u000b,\b\u001chB)\u0016i\u0002\nYSK\u0006\b΁Cdڍ窔ҽcbw-2J\\wRffN4C\u000e\rĚJ\u0013\u0010\u0011L.4\u0002PN@\t4\u0012\u0013h\u0016$\u0018ha\u0005.\\8\u0014,3\u001bƎ!\u0005\u0007K\t\u00195\u000eEZ?k{\u0002L}Pn&@ױK\bj+-<]΃\u0002â}y\u0010Pu3\u000bWR6V\u0015q\u0018=-\u001b^^U\u0010gQMr=\u001c7'~\u000bx\u00111Q\u0007S\u0002\u0001GAG5\u001aw~Ly\u0013\u0016SMz1\u0012{XAG%ТIyr6ɶ\u0002\u00149\"齖XUY\n&}|rt\u0005\u001d\u000b}7]'\u001c\u0002G8CT)\u0019\u0017˚dB@k\u0015r6tX|RTg\u0004Q\b2G&\u0000Nvt%\u0004P\u00161T \nD\u0005b\f\u0013\b\r`e4ZNO\u0018ޓVͪӠ*\u0007)gMV[Zg\u0018`\u000b\u0010[z\u0014~n]kg\u001bZ?ܺ&\u0001\u00121q$n&-]*qNz\u00180sul\u001a\u0001bO\u0013\u0014Pem+q{q\u0015\u0000SMIZ7㙵i٨\\+e`0f\\ʹbd\u001eۏa0Y\u0002\t\u0014^b݋Ven\u001eJ+U\u0014Qⶼ~t([߯*CO3[\f}k8kٌԁvs҆ \u0004&\u001e\u0000\rp\u0010F/]鑘B\u001b-\u0004\u0018i~\r\u001b6I^ƻ\u0003pGDR#Y\u0013G\u001e<\u0006eص\u001eXaHLO\bh\u0016*/G\u0015\r\u0014I\u0005\u0012-sH\u001c,GgWZ=Sòvt=˰.;y\u0005n|)P-\u0007/QO\tWyl!Ӥ1\u001b%6!\tpYpʪy\u0018\u0003b\u0007s\u0010^&\u0012\u0011.s-]4q.\u0015Հc\"69|'cR\u000e\\\u0005h\t뜪\u001d2\b̀&(L}lC,zbYZ7aD砾%/!\u0016uE\"k-{\u0016^w\"%oԢ\u0015=&\b_+jb!\tO\u00133JζEJhZ@Sg̸ĨKURBT8͸\u0016\u0001$^J+q#\u0017~\fmLl\bfb￰v\u0012^\u0005\t\u0006a!\u0010@<\u0005\u0000L=\u0016˓\u00057O[S߯=փ\u001b8fϖ5\u0004\u0017+`,T\u001e;61v-yt0\u0016a\u000b4\t+2v$]B\"~bH]74[@K\u001bD%[au\u0006ث*&02+°QsD\u0002\u0015\u00191k[IwmȘfǽ\u0018Yiy)B\u0005`&h\u001bz\u0000z\"Ş1@5{y3{%*J^O\"9\u0017\u0011J>qu\u0001k$,Ȓ\t<-`AOLYAƢf̢΂>U3\u0003CO7ɥZo0X`\u001eZbNZ6j\u001dP_@.'6m/Y=6cr\u0012O3/H\u001aS;J6\u0018\u0002p\u000f܋Y\u0003L\n\u0019,\u000ecE8Q9Kbޖz{\u0012\u0017ImdHN4bד\u0010x5\u001ch\u0005\fXG'<k\u0005\u00163\u0018\u001eSg\u000fb/n>!\u000b/\u00016􌕞C\u0011{ 4ܽ\u0014\u001f\u0011*f\u001e\b.Yt\u000e6V2OrӱDdGv_\r\u001fP\u001cXxSYRw\u0015z\u0014Ibd>;)X>\u001c{\t6X\u0007tm`otH5#WY:\u000f\u0003\u0016\u001f'^n=ܝ3\u0002:\u0004\u001bV։bn\u0004ɜVS\u001de\u0007N7\u000fbT{\r;-[`\u001f3B;Ѳirˉ|V\"u\u000f4>׬\u001c\u001e\"=E\u001f\u001beQR5,\u0015zi\u001cۤ@n @K/t\u000e|sY6V\u0018\u000bݚiA\u0011n}T{\u001587ZQvh\u000b\u0014Xht1\u0017÷f\u0003jgZQ\u0005`Y\u001c\u0012ЖXy\u0001MV07pY\u001fh\u001ac0둪F{VZtse)z\u000eV¢(\u0007B3=&e?\u000eP}/\u0014z\fn>#F\u0019\u0014%g#bwxK\u0018]DH\u0006\u0010\u0018d>tQ\nkQ`/ҙ%$G\u0015ܜui|l1Cq\u0002$tn990Ji{3\u0012\u0005cоU&wVU'$uY5\u0006̞\u001cV!\u000e&5_l\u000bV3\nW*$z!X\u001d&N7\u000fb7\u000b­8Փ\t&~fv\u0004N\u0013\t\u0016\u000fBdx\u0000g;ݗ3\u0001>G~ݽyݟ/n\u0004ŷ7kvssv}r\u0015W7( KǱ[\r~_\u0007\u001f\u0004q\u0017K<c\u0001XW\u001d_B!N`U0\u0019\b\u001c\u0007o刓H\r$\u001c\u0011lGx\n\r':\u0014J\"U b<ۢs%CYk+.P[HW$)\u0002@7\u001a\u001fOI\u001f4@\bi\u0007\u000b\u000e].I#gHz4\tqW\u001fDHs\u001fHJCfx\\w\u0006\u0002hpU\rm1>S\u0003Im\u000eI\u001eab&:{+pm*\u0000\u0015{Ė\u0002\u000b@5ʤ3W\u0013tz\u0019-PN'&κ\"]\u0011\u0019̕F:%ù\u0019NfK>*9u\u0001l\u0006\n\u0001@R=#pm\u0006Sp8ںf{pF\u0015p\u001cf\u0004_<G`_t'\u0004p+x\u0013F\u001dkߟLQ'+Zԓˣ'8|]VER+\u000e\bVpA\u0013\u0006G\u000eR\bIĂ4\u00031a$\u0002\u001e$JA8&7x\u0016,D$m`Ku̡\u0015\tl9\u0005\u000bF\u001fׇw\ns?\u0018Ap\nC\u0006EL^F2_\u001c\tqS\u0016\u0004!hN^Tʄɉ\u0015\tQ`0\u0003\u0006\u0010\u0001S\u0004=\u001fDb iGv>p\fI\u0016Ml#Ǹ\u00191C@g\"g\"\u001fKUHbo(\u0001|]8sNU\u001c\"<[_\u0017\u001fTH__\u0017\u000e8\u000bP+Qܽ}2\u0000\u000bu+0߭iE\u0004ͷ\u0002fIk?~AW4o;W_\u0005~'u}uC:i]~oV跟ݝ͞8\rW7O_o\u001f~\u001f\u0017ݾyIs_Yo7̗oꍼWB޿W u\r;:|ޱ\t\u0015\u0011W^>+\u000f_zwg_mu|j\u001e#O[\u001fO{d]\\~˱\u0016S\u00172y7W\u00177\u0017nw\u001exU7__ޟ@kzOb{΃o7:?aM_yx:s2mo\b:\u001e|rۮ)=\r\u0005zL}3gN\u0017ݒssy\u0005k<X훻ߝ}aUwo\\\u0017wgw[g|.ϋo__pw><Xv\n꓃\nxP\u0001\u000f*ϫ\u0002nXA\u0005|t2?^>(OJ\tܚ<=%pkA\u0007-\u0003\u001et\u000ex\u0001\u000f: Vr쟍j\u0014j\u000f\u0017W_~wg#\u0005\\E\u0001~\u0005*0R\u000b\u001bZwx}\u001f.0\u001dK\u000fo޼{=]go^<kG\u0001{y6W\u0010-_\\cW^_ܿf<'^?潿\u0000H۫ۻwkSnS}W?y\u0007\u0002聗u`7w/<?^z\u0004֫}suv}{sq-_|U\u00177cOIS9Nð5\"\u001d[?\u001fc-nh\u001bx$QϷ7\u001fVySOO:z/¾{\u001fv\u0014\"]{ ~\u001fSSÝ/4aYz#|:Y\b\u001eㅼZ4]H|]w}q==%z?\u001f\u001a\\]]zӳ1l@a\u0003\nτ>\u001d=zwKΜ󋋻o/OO$ڕf<#p8\u0004\u001e\u001dOv[qyX\u001c{!V/no>ϭ}T\u001b_CT!\tI[0n'l]|٘=6HX\u0018\u0014r<5C\u0017ww{ut}Ԗ\u0003M;д_yL{NӞmSi;d7M;~6@7~<+Tw\u000f5\u0002W#`קV#`\u0007r,h^|\u000ez}{ϙW\u0013\u0018gzU\u001bvz>dw\u00048<[JJ\u000bz[\n#eknn.86|}y[w\u0017\u001f\u001d}~닛/ξz<\u0014t\u001dsaeY-~tk?nbi{\u001e3ܭ\n>W$\u0017*b\u000bdo\u0007\u0004s\"}S,Yh+t`_n߫^]^]\u0012bxϷ\u001f|᜝~ndUW\u001e|mw\u0017,o///aq5n/>B.o.ζNh ]'/<\u0011Cxq%>Z'&>GwjV짭O\u0018N\f\\xr5}NqGLn.w`G\u001f(G剗{.q}.a3&lf<5!lmb!l\u0003[~Z\u000enyo\u0015yl\u0002g_SMO9pf\u0007CΟM+y*3[=!p\u0011!pfﴥ\u001dswD<g\u00138J$\u0003gv@='\u0012:p\u0004lF\u0007~a\u0017\t\u00019w!tOX\u000e!vx%XY|y<\u001cMO\\a\f[I\u0017O=:Ϸt&-X$=\u001cV-\u001fہ=\u00115\u001eہ\u0000\u0007ّ\u000bsn\u0007@vn\u0007@ݞ\bu;n\u00075ü֋E<OKxD;\\kD[/p\u000eh7aD/|?_ni\u0018QU:Qv/;>NxJt]u>XM\u000f+\u0015\u0013zn5OfQeە=R/7//^]޼!4~w(2y\u00112Q--ܡ;\u0002j\u000fl~A]aB6\"J=6\u000f%?t\b.<]`\u0013\u0006Kjw<{N5];5\tztI\u000b[S\u000b;J\u000bN\u0015\u0007:lm3;l=^;<Ӆ.￻ߞ>%S>61\u000f\u00117=LXq\u0017\u001e\u0010c\u001e\u0007RϻZG\u0013iW\u0019\u001eh?|ә\u001f|\u0007{\u000e>yv\u000e>\u000fcD:\u0015y\u0007莥s~Nٟ.nv5W~wO?>GѭW6m//_z\rI\u00007ߨ{\u000fDs~;.5.+ҔܭK{dw[;\u0007\u0013cg|'\f/>yy'?\\^]rwۻwy%\u000eٺ\u000emn={sm|0\u001d\ft\u0007\u0003ݻCwoѵsz\u0007Ǳ.藝\ft7\u001e%+ɧ \u001c;󹨙J\u0005xN(\u001b!\u0017$=DjڶI[|\u0011\\ỮrgKŃ119j\u0011cZvئs0\u001c9\u0007cs0\u001c9\u0007cs011\u000768XT=隦e\n{\u0018p<s<푨\u0013.ϱkӅg\u001ac,CmCm<=quywYşg\u0003\u0015\u0001g\u0017g9衺ՁD8衲կ>@P=s8TzU\u001f!Oϰp%ʞ{Ⴇf>$\u0015ںwpiͿz![\bG\u001f|!^͸x\u0013~jTO_}9q=s9(q\u0007%n_c>vuK*!8l\u001f/_\u0010ѨO?kFg\u000b!G=}wKxc`xT-\u001f\u001fOS9?\nb~!\u0007ǞP`'~0\u001c\u001f\u0007~?bߟ\u0010\u001c=دϮx{}\u0019ۗ\u001eė0L9<˫\u001dJj𶈭cEo\\\u000e\u001d6}Wvᢽ\u001e:dzFߜ|{ub\u001fn-1ۯ\u0003D\u0015_\u001dn⫻\u000f?\u0002{;\u0014UzE\u0002n/b>R\u000ej}T\u001ej\u0007P\u001d\u001dRUz\u0014kՔ>%oysEdMϬ\u000e\u000eŞ\u000fTLv0\u001ḛ,\u0013LbІg\u001862įߑ'\u0004ж?=B\u0001~\u0005Qh[\nm\u0007\u0007~90\u000eyjdxf\\=0\u001ft_\u000e\u000b\u001d\u0016x\u0002\u000fZA\u000b@ZւA\u000b#L\u0015h@\u0007n]e[/\u0006ΖvP\u0003\u000fjA\r<\u00075W\u0006\u001eg\bg\bۗޝmOV\u000b\u0005\\\u000f\u0001~\u0005z\u0010\u001eܫR{\u0016ɡ\\\u0017*l\u001c\nB\u001esbz!N^]$.=훫~\u0012g?\u000e?]mo\u0006ק\u001f>\u0012|~vZSS\u000eD|zWRGgm]=~i#]9Q_\u0018\u001b>'vHڽҎ[\u0010=okI?y}^S\u0005jރ/q׶{N\u0007w\\Siu(7w/<?EX{iolnk[{)\u0019]\u000e^\u001fu޺\u0015i}ƃ9ՇH̕Nwqd}j\u0001\u000b]?U \u001dd\u000f$ތ M45\u0013ݿAj_2ugdAz:HO\u001fNz:\bO\u001fLxRӕe{H\u0018.\u0019>S\u0003\u0007`=]xa[\u000b|Ǔч4z!\n.$>B.￻ء)S\u001fA\r.|v.\u0019!?wTC\u001eP8\u0007Dzqna\u000e\u001cA\u001fRb;pG\u001fЯ>\u001dS\u001eKF\u001f\\x:GP\u0001I\u0015'W\u0001{/\u001f~<Ͼﶕc)v>\u0000\u0014$­\u0006Ϧ:dO\u0013|{{zò./H8!+~eQ~\rysOȃG\u001e.ֳ-rEɣ}8eT$y\u0003O\u0001\u00043\u0019x\"v\u0000>=(ڕz\u0012M^]>XQϾӯv\tp+\u0004/O<;d;)a@\u001fZg\u001c\u0010zwv.\u00073hߍ&#l|&{\"s\u001f,'\u0007x^]˖\u001f\u001e@c\u001e;iaѧp׿y[Y\u0001\u00007!ѱ?f?~cDӗ?]s{u/!\"a)\u001fћ1嫟A?\u0007~\\\u0017K<cOZuq|X]\u001f᧚[v1b\u0004moތp2\u001a.\u0015Z\"u\u000b\u001cS9d\u0002ehC\"0:\f\u001e!4<CZ}HE\n)R'!\u0014b\u001b\\C\u0010d{pΎ]:).BI\u0019VZ\u001fN|*uu\\N1ӊ܉|S9:N'DvK%H<)CM\u0004')\r\u0015V/D\f'V\bT8\tC,d#;y@B\u000b0ޣt9a\u0010\"\u001ew$x\u00025Wz|\u0017Gƣr'qI8)G\u0013V\u0014V?Ihⴱ\u0006;\f\"09pr;l\u0011H3\nJAz)_ڼ2\u0012PV\u000e!\u0005B;\u0006L\u000e\u0003M\u0013t9ŰZL\u001e+\u0002\ft؞VI뤣\u0018p.n l\n\u0004!T\u0018JQKsnjM\u00114\r\u000brkhB\u0010SBL\u0014:\u0004 I9\u0019xZCi\u0004JE\u001fn\u0003͓~׵\u0016ZL\u0000u&\u0010q\u0005o\u001e.~-قa*!N٧J_'58L]Lk$T/'t\u0011\"\u00056Д\u000bQ(x\"24[©>]\u0001\t#оҍi%\u0004\u0017\u0007\u0011\thmE(\u0013 9ڇ\u0017V:\u0017 f\f~\u0013߁Zp\u0019\b\u001cSo3\u0003\"\r'ѻ&O\u001cVV2\u0001=O\u001eYio2.`\u001c\nrBc\\\u001b*:l\u0006(\u000bGE\u0019\u0002\u0000\u0001XHc\u0017vET>B\u0006\n<6~\u0010Aixx\u0017@ǝ\u0001\u0016pkL\tL\u0019\b\u0005E \u0019D^L\u0005`Ȟ(bQ;.J-\u001a+p\u0002Z\u0016\u0013\u001a\u000b4\u000b\u0017R;Y+\u0011\b\u00044ohu`ܙ>\u0011r\b<]GHM\u001bj\u0005Q8T^0P\u001ayh\u0011M#\u0014کS4'S\u0014lDK*l'zF8*\u0018@Fw\u0004\u00039\u0003+bnD'\n4<0u',\u0015\u00020\u001e(\u0007\u0006߆c\u001f,\u001f_]@q\u0012vݥƬblt\u00159hb-B\t\u0016seC\u0013@9']e札\r>\b$\u0007f`|]\n%\b*Η Ğ@\u0013{aH^7~ 2MУ̌1,%BƐA\u000f|$nd(X\b\u0012B\u000eJ\u0014\u001e\u0010z\"S+^\u0018HSd\f\b\u0003\u001f+M>?x\u0014\u001d*G5 7 :`E&fA9\u0007ХJXU$n|%\u0006\\̓6vWw ,0XXꓘo~\\/Z\u000b2e`\u0003\u0011zϔDǌSő\u0004\u0001!&\u000bݢ\u0019ӄH'ּ<y?H\u001eCp\u0002Iad8\f1ژ9\u0004Ygr\u0010\u0019-h\u0000\u001a\u000eRs|Hnȍ\u001f\u0010JŧX~\\AZ }\\hsn<iׁP5jh}!,\"K\u0007+8tQ\u001bJK\nߒ\u0007a[C}\u0000QfXp,l\u0002Rk\u001d<M\u0019=t\u0000kAx R\nc\u0002ML)g-P>ɂd]-1$c\u0016\u001a&3k#\u001dD\u001fE\u001ahp@H\u001b،\u0017\bivr4D\u001f`\u001c\u001c\u001f'Br5\u0017D\u0017\u001b\u0017\"ƝYLKL\u00181\u0007\u0000 НyYo\u0005Q\u000b\b\u0019$\u0012\u001e2{㷜`6\u0015RHO\u00127S\u001c\b9@\u001fHr\"_\th{jkQ)SHUK5O\u0014t\u0014 -Km(,\u0015DW@))\u001b /\u0013E\t .HڸECK\"mID\u0016\u0019.+uz\u0005[\u0001[NHX p:ZJ\u0005\t\t$_?M_$\u0013G(=LH%\u0016L\u0005\u0000\u0001\u0010Xن\n2\u0010D}(l\u000bVmz/$|m!BgolǀNǉƽ\u0002$u3X\u00025\u0006'_9wz\u0012\n\u0017w\u0018\u0010\n,9\u001c\u000b`Du\u000b\u0011T2\u001d^\u000f\u0012a[%)`#\u000e\u0005DiQx\u0000\u0000.\t\u0019)61\u0005[t\u0005\u0012UiM<\u0000\u0004'q`Df\nB\"kÊa\"\u0015?:VQ\u0011m\u0012\t\tL\b\u0000\b?d8&oV'\u0000wJ窷 \u000bP\u000b,s6\u001f{)F[_PT6l֦XDy\b 0\u0003͋]lbfz7K0\u00101\u001a2Њ-΋\\cc\u001fY؅cȶA\u0012Q8O\bO\u0017\u0012q^z̀\u00142k3\u001a6\u001d֛\r\nnfkF4Zj3\u0005\u001f_l~/z3hb|>A\u0002/VGjeh%LYKlS\u0003T\u0005\u0002\"1r>A\u0016\u0016P٢\fSN\u001d<\u0006_v\f=\u0017$\u001ej?@$i$eQ*\u0002̗$\u0012\u0004.w=\u0011j[3;«H\u0015(\u0007i\u000e̾y\u0019-ņm\u001d<\u0013D\u0017ۤ\\Vƌ(\u0003j\u0016>d=\u0002b=\u0018b.$D\u0010l\u0007I+\r\n\f\u0016M\u000ft{\u0018,As\b@*WT\u0005E4\u001b\u001c^\u001f#\u0007AV%Aų\u0018hl\u0011\u0007'\"8\u0012y$;B6l\u0018.\u001dg\rK*\tB=F;&1;\f΁CwGB<\fft\u001e\u001e\bڼ(F\u0013}!aÀo\u0012s\u001c\u0010X\u0004z\\\u0013#\u0015J΀@#4 W\u00179\u0016\n\f24ND=n,\t]\u000fHC\u000b\u001ara#v\u00025G^(/| \u00055*X\u0014[*)Ew5\u0018\u0001\u000bOJ9s\u000e\u000e4ܰG\u00181\b.\u001e\u001b,$\u000e\u000e\u0019\u0016d\n\u0018N\u001d~_\u0019\u0010{欑d\n[I'\u0001\u00048P0zN7\u001cʱɑ}k;]Ȗ~|60%>GXs\u0013\u001cHX\u0005zF͔\r\u0004N\u0010\u0019{\u0011\"Sq\u00140+|<\u0010\t2B:C\u000b\u000fG\u000b¹t\u000065l\u000fL(?\u0015f\u001fL5nrg:9^\u0019\u0010#{Vj,\u0001\u0019\u0001M18\".HL,7hdXB<#`>8@\u0018\tB\u00133YQ4@tB8\u0013\u00064Xxf>BϏ\u0016خŖ\u001f-\u000b\u0010\bB\u00021^Oe\u0012c\u001bi@\u0003k'Cd̹ͽgLI]\u001fr(;v\u0018\u0002k\u0016\b͈IҖ\u0013QB2%#l\u0000H\u00131>'-DI20\u0001M\u000e\u000eỦa/:\fC:\u0003@l9 /\n`\u001b]\u001b1\u0006vE\"\u0012k\u0019pc0k Iq\u00187Xj/\u0016X{\u0019'-p\\Ν|b6 \\\rq\u001e[!r.^a%rnj\fqtd*0sL]\u000b&\u0013In\u0016%ʖil\u0006\t\u0003ќc\u001d:¦ Q;e1MйtWu\u0003$\u001f\u0000>;ՒFut6IJ\u0011#%ۨ|*<Y\b\u00186\bBl\u0016gT\u0010%)\u0012j\u001d{!z8\"l\u00057Zk`k\tMXHWd\u000f8l ]:,&\u001f\u0018\u0019h \u0016|ظ\u0000\u0016Q)YOߑ\u0016\u000bψD\u001a3\u00053<6\u0012^a5<\u0006/}g\bHj\u0003ɹ`DM\u001cI?0S?r\u001f\"\u0013]\u001b0v3h@@\u0007\u0017,dh\u0007SQ8 Ď\f\u00120\u0014g\u0002թ\bIJR҆J\t\u0011$5~\u0012(w\u0010L:\u0010\u0003a\u001cɢ7Zi<\u0005\bƐ\u0003#J\f,ɗ!/9u\t9yi\u0011\u0013@\u0017}\u001e7,X\u001fpdSaus\u0017\u0011}&\n*ܘY\u0002\u001c m\u0013\"쬌k$\u00129\u001eؘ\u0005T#)o̧\u001bQ~?\u001cm\n\u0019l\b\u0018űር7Pm\u0001\u0013>+\u00056a\u0002$o\u001fX<8\u0013#Nb\u0016Z=hS26c\u0016\u0006q.,\u0004D|Y{X6\u0004\t?\u000f&$V;8Gm\u000f\"$c\fbHGNjxG\u0003\u000ba$\tE\f\"Օ\b8y 2Xc\u001eZbs,J\u0007X>y\u0018\u0001\u000e\u0017ZTc6\u0003\u0003a \u0001DmM<5Iܗp\u0007G3,\u001c0\u0011\u0003b'}\u0012`\u000e)R\u001d\u001e?\u0005v)9$N7\u0005\u000e\u0000lmm)\u0017{y,P?\u0013/$\u0003\u0000c[0`^D+7$A0Q1\u0006\u0001[1?ʋa\u000f%H\tS1\u00163{|\tO^\u0006rI'\u00170,o8A<FD2yQ\u0005>B/%E<0(l,ql\u0013= b\fC82\u0006_\u001d8`X̄0뿳cy\fm\r4<\u00046\"qOJif\u0012Lc$C\u0012 vI\u001f\"¯9Ӎ:d\u0010\u000f-A3D.$=(\f\u0003]\u0002D\t\u0002ra#c\u000e$mG]_w\u001cO\u001aω(%U\u0015x\u0010E\u0010\u000f\u0004@\u0007\u0011ܘG\u0004p!nh\u0019[\ba&)橦\u000b[\u0004,mA{[Snb\u001bLĽ\u0004\u0016<c\b\u0002IUNX\bc%1F8\u0001\u0013\u0017Ⱥ/6b7;X\u0010b|\"q1n\n:?\u0010\bޚ\u0007xWe`jV$AQWdeSbd[ER\u000fGR\u0017\r\rAR@\rV\u0016gh\u0005\u000b,Y\ft~\f\u00105\u0012{1l\u001eJƈET<tGve\u0016a\u0010TU!\u0010)\u0003GyH\u00028f$k\u0010\u0016e<+\u000f5`΢h\t׆\rQI\f\"\u0002\u0011Hlb-jo5m\u001b\u001e!^\u00139уNtH\u0000\u0003F%\u001dKC\u00039灘 Ol\u0018\u0002 bCf2\u0010;\"\u001068\u0016\u0002*=[)$qy{H̉2a\u00127\bt~1n\u001er\u0012\u001e7\u000bZFlº\u001e뽂ߙ\r\u0010\u0004g8v\u0007;!\u001e\ts\u001b,w-7QٔJ)^\u0006\u0012 (u2\u0015\u0016:\u001bD4Vi#3\u0001m0@`g6-b&\u001159W\u001c\u0001-\t\b*ns<Ξ@\n)\u001cP8-\u0010Z\u001d^b\u000b:A|)\u0017}\u0018\u000b\u0014\\B9\b^u/Z<;އ\r\u0007&4rL\u0017>\f\u001dn#ҍY\u0019hw\u0000\u0006\u0002o8v\r\f\u0011S<Oz4\"\\p\u0016R(7\u001f;\u0001Y#QQ+׋ā>\u0012؅\b4Xw`'K\t\u0006'Q;\u0011\u0001ĞP\u001b\u0006\u0010Z7G\u0005Zދ\r9_HDS@T97e\u001e(Dg-q\u00118\u00133[9/iFN5\u0000X_g\u0003shAzgH\u0002sE\u00198d\u000e\u0005p!3\u0011!^\\4J(IK\u000eѬsx\u0014EpS\"n\u0016<m\u00116\u000fb\f9M1fcX.`Ѳ!Ul>\u00145D'\u0000\u0015\u001cZAw\u0013i\u0013l+E\u0014d&\u001313aŅ5\u0006wI^4|\r\u0006Z6Á9H\u0001d&\u0004M[\\\u000eQX\u001dl*Jή9\u0015\"1hNKl<]\u001cC\u0018\u0012ku4\f\u00115TL\u001dg1yd*(;<[UWs\u001c`\u0005\u0014\u0017*8\u000eNT\u001bS\u0001.\u0003\nŦA\u0005*԰(ŎBcQ&Z\u0013(D\u0007\u001087H~0O\nJa\u001c8\u0007 f\f\u0015YM|ݕ'\nlp::\u0016sNra\u0003='1FD])>\t&;58N#)>\u000b\\cn\u000eTc\u0013q3wj/t!\u0002߰Su\u000b\u0019#S\u0002;\u0016ώ0@5\"\u0012a\u001c\r`\u001eNr\u001c\u00177.\"I\u0017xgKj\u0011\r<^0\b\u0001\u0018}\u0004~3M*\u001cړ%(\u0007\u0011H\";\u001dB\u0014^#\u0000.\u000eocE\u0014\u0003G0dH贈0\u0014x$ATDWұ\u0015^ۛe\u001fmڎ6\u0015Nb\ts8RKA\u0004LC\u00148V6r(CX\u0007\u0001p!Lx-xsJAhۦ4\u000fl\u0015\u0019~Aes9\u0006>99XI\u000b,A\u0012Ճ\u0011k$ۏ\u0011[0=z;d:c\u000eo_ x4\u0016E\f^\t>?\u00145<*\u001dXD&wGv\u000fM\u0017Cu\u000f\u0015I}\u0012;3זt<\u0003\u001f\u001c\u0005\u0010d(\u0011M)1XF\u0004<z`\u001e\u001b}~4^DW\u0011\b\bg;_P\r:\u0016B\t_\u0018\u0010I8ã54K`URZ)spz <y\u0016\n8zuU\tm\u0000\u00024BQ7U.y\u0002QH\b ř\u0003ld԰\u0017ۋ4yt1P\"\u0004\n4D/q\r|\u001c,*1QDYATd|\u0013\bll\u0013|\u0011\bX\u00165\u0010y\u0013\u0007P\t ǝU(Qe\u001e\u0000\"Dz=z\u0016`bM{\u0011\u000f\u001b.&׈l\n\u00029el\u0018Awv7ͣ\u0016g\u0010s\"\u001a~6\u001cFYg\u001c:.\u0001/Ȧc\u0014x\u001cǊ,b\nlu=j\u0011u!2Kp\rpWgǑQ1쿽9r\u0011\u0017H!\u001a\u001e(rlN$UTTM\"$= t!].\u0015anA7@N;\u001aTl?O\t\f׺;??Z\u0006o\n`E\u0015Y\"6y\u0011|hW1\u0007[#޳\u0013Ң&g\u0001xi\u0011$\b#Zrz8\"`s@9/n\f+NT\u0010\t*nuEH>E&\u0013XB37\\D$n\n[\u0014ܸ\fG\u001fm\bT[\u0006\u00038NN}v\n\u0012\u001fl\u0016}XD3ke\\\"LG#Anlfe\r3`\u0011Y\n<f\u0019\u0000&q8cM)\u0006uWzq\u0019o-C5\u001c3Da\\>G\u001d\u001b3'\u001aw\u0010ٓU\u0014c\u0019fS\u000b\u0014.\u000b-\u0019̫՗\btEf\"/\u001d3\u000bͺ{_\"p6'\u0004#\u0006&`\u0019s_\u0003\u001fcn旄P&_]8%<+3j;3\u000e2\u001b,\u0016/_\u0001DT%ăiALG1LAs[ܜ\u0004\"Ix=xa{~47\\\u001dm4\f5\u000bk\u000eH\u0017\t\u0010,?]ӟ\u0000m\n\u000esL+\u0007^dβj׵Upu}vU.\bKJ\\i\u0005(\u0000E+\u000beGK!}.į˯,*\u0019\u00107%*S\u0019穎ɐb.S\f@WXdҢ.溰7\u0001V~O?CD\u0010ʲ7\"J;H\u0018*!-3\u0012/lb\t{\u0014Ks\u001beqE\u0012{S\u0006s^\u000f\f\u001cNАǹc|\u001dW#VބZ0\u000f\u001aԛd\t*:EaL򂔾I\\ذ \tAx\u001b7C=X\u001a.b9I\u0011\f\"\u001244.\u000b*lA%d4\u0004\u00034?<\u001e\u001a5tAj\u0006U\u0003  Č\u0014Sʁq6\u0005\u000e8vjCid\t*Ӊ$>f`Q٩,\u00025]FD\u0005\u001fcB#bQ2s\u001b7\u0017OFP\u0006\u001c\u000b\u00027\u001c8#\u001dd<9\u001e܀\f\u0011@\u0005\\L\u0016x\"o\u0010\u0002Ƹ$\u000eR&j|,b\u00030\u00100V\u0005B\u0005\u001aV_<ʫi1e\u0017#I㎤\u0000I'\u001d:D\"-^D\u0019\u0003y$\u0003\u0013\u0006s7<q9\u00168}63ĹSv\u0001gSa@IAJ\u0005!]7\bKD~b\u0019\u001f\"\\gl\u000e0\u001b\u0016\bX\u001c6\bDA\u0007l \u000fO\u0007لmي4F&}%D\fsېK=-ߞDJIM]xl\u000fN\u0004QS$v\u0000A)+l\t[\u0016J\r¢@eV(ŷA:`T ӸH\rs̵\u0018|nyB\u001db\u0013\u001e\u0007\\4\u001f\u001ea%\r5YE\"\u001c\u0016t<h\u0004\u0018\\L5};(;y??M\\mH-Hy\n=x?͋\\-:?s$[|X\b8`\u001a$ы\u001dBc>\b\"9pX\u0014&m0\u0001N\u0012\u0010ò\u0017׽Q*\u000fM3˝<\to\\Eן\f<>׿r<'o\u0013\bV@jGis09&wN\\ L_\u000b\u001bz*3IԈ)#\u001a3g/s^\u0007WfEi\u001cm}twu6\u000brx\r@X6)TkU$r2CE{ʆ?]~QѸZ8T\ni$s\u0016S\":tSPT]aEyʆ?]~\u0001أ%#M\u001a`\u0014E!XF\u000bv\u0018Z\u001a7\u0019\u001bt9㲭$\u001c;|yĴ\u00073`\u0016dgLgԏslp5^6G\u00188\u0014`NJ8\tK>\u001drY9˽[&B\u001e8S.\u0015\u00155\u0006KC\u000eܦ4ɵ9\u0000<C\u0012@\u0014BU){˞O\u0017ߒ{i0Eә84t|̫\f;6FP*\u000bT\u001ft7E6l*\u0014裯Z۟\u0019H\r\u001dEpuOwg7^lj.2f#nX68K0@GH@d[\u000b-i)ơ$1}\\\u001e@󷏗H*\u0001f+Rj\u0003+\u0013<\u0003,Ͼo7rˋUi#%Ͼ(G̲\u001a\u0018 2Ca\b-}\u0016:\u001cl$I\t\u001eZ\u0007'Wo\u0005M\u0017\u0004\u000b\u001f\u0003\u0015қ\u00175?>;|lIsFM\u001a\u001cz~U}6]\u000b4ӭB\u0006P}9,!i\n㞛\rvZ\u0018\u0012xHo*\u0012c;pf^N<̿˜\u0004\u0011%\"0Qn\u0013`aYA._tN~;=\u001avF\u0003IS}ﾎDkev\u001d*V\ri\u00117\u0004I'!Ѯ#2r_r9v=<\u0004goȂ|Ig|Α6Bg\u000e}I\u0002\u001b0Di*F\tA\u000efW'%/>bݧF[K$LX\\Rlh\u0016㧒0\"|xd\u0017G\u0016q\"\u000e'Jg~o\u0002M߂Z\u001d\u001d)oUܐϱH0',L%F-jJ&\u001c\u0007r\u0014\u0000ȕ\u0006%8\u0001r1u\u000fc4o\u001fob\"ǋNV%.\u0005e@ђ\u0012iHH_\u001c͉M_XcN'e,Tfl?\u0013]\u0002_\u0010b\u0015MI\trsXT\u0019ǃK\u0016cuZ\u000bx8٩s뭾x5M\u000b\u001f,snڀ\u0001\r\"?ۻj{Տ\u001eVj\u001b˗vwşn/^^۫-\u0016ܰ\u0003>\u001bd\u0010IZ\u0005\u0003\u001bH4\u000e\u001d\u0006\u0001\u00029]KmՇd%a\u000eyŷ4N\u0019=\u001eZx)c\u0000w^\ri+/rVk;k nH5/\t.kFv\u000e}fpSJ\u0014#\u0018\u0018j\u0018\u0018*61\u0013Z༠x*DѽǷ<\u0014/G!B/y&%#F.ӡD,kn\u000f\"\b܉\u00102e\u0012*{},$Qb\"0fM?\u0001\u0016\u0004H\t-=>\u0016c\u0001!判2\u0013~\u0013öЊ:J1\"c;u\u000b7>D\u001c\rhо\u000fq/EV\u0002\u0007&&ޮ\\<,\u000f&\\p\u0011w\u0011~f&~\u000f`b4Md:W8\fQ6ӓ >jk{:Z[\r\u0010f%pe\u0019*oi\u001a3z [X\u0016n3w\f\u0006@s\u001e⌦zH@\tP/\tIa($̍4VTq9\u0010ǈV\u001a49v\u0001̘[mHĽCuE9L\"jq\u001e<1pJ&\u0016a\"\u001bXDr\u0010֩RUѯ]uM8U\u0014\u001dFޔ\u000f\\ܲA_5\u0015Ny\u00182\u0001Z!*K\u0006|I50tI\u0002R:\u0004\u0016\u0010\u0018uQ\u001c}\r\u001ds\u0011uqx1ߠɨ<7@j9l\u0000kg\tK4'\u00118XS3\u0004񳴗\\~ͻ\u000f0=jv㧛\r \b\\3\u0013\b+p\u0014[\u0000\n\u0014ˑV =HKƠ9蕉c\u0004啢M|l5&ɨ\u0003\u000eIq嵠U\u0014\u0000-}}ιS\u001c8ɀnI\u0017sC9\n f8-_ \u0001@)\u0014BT\u000b\u0017\u001ah,@4Fn\u001f\u0017[cCDz)1Ļ\u001dS-\u001f d \u0016_Js\u0014\u000eH\u000e(\tL\\F\u0011)QjU\u0007\u000bQ}v_HxPIυ\rAQ\u0012\u0000 2K\u0018pj\r\fH\u000eG\u0017)9ć^OOH\u000f^j>\"\u0015+s\\TLA+*\u0011KRH&:x-\n\u00129>Xd7_]|>=?s3<*&O|\u0017]]ܼ$*\u001f>G[\u001f\u0019iǟn|싳zūۻ\t%q'p5g\u0007p'\u001cB\\18\u001aPYCIU]U\nš'Z\u00147\u0017r\u0019xdT/!Y;%E\n\u0003\u0017'G!b'%2\u00128׃qHH40G\u0002kprl\u0002}C\u000bgb9NY%I\u001d H\u001ayW\u0003{\u0016f_Vyl$&IYB\u0016PCKR5)\u0014yFD8̖\"Ʀq3AC (15\u000bWZ\n1T\u0011FݭѺ\u0012(Hݢx\u0015#o\u00176zF\"MueyȦtF\u0001_:\u0003Hy̵\u001aqy&+t\u0007ĊB W@\\\u0002'U#\u001e.\u0011j\u0004&P\ny\u000e) IQt٫<U\u0004\r\"C!\"\b\u0016[\u0017\u0014\u00016%0\u0001c#Q#-\r;-$\f\nB>\u000e\"\"\tR+9{ ȰCzKc>?c\u0000cA,}fvKWZ\u0003j\u00053kA\u000f \tw!9X!\u0015A4\u001cjcď\u0019\"vDbNF\u0014PpI\u001aq8Ccl\u0014\n)\u0011{CG\u0003˰18=NUmT-'(,Yd1ˁ`S$;\u0007 L\u0015xXZU1iǎEpI-\u0018\u0017XJU40\tV\u000b\u0003>\t/|\u000b.6\u001d\u0017G\u000f\r&R\u0016\u0019\u001dIP\u0007uF?R҂iCz\b\u001f]g@v\u000b\u0012ev\u0002,\u001cqIέD|\u001c\u0014q\u0012_ScJQ%ѣ{V#\u000b8\b#'<\u001dr5upAZ\u001e\u0018K\"\u001aLx\u001f3wAr7a\u0016\"U\u0011P(6^<\u001dt|m,S\u0014\u0004a;QV\u001cϥs 5\u001ao/oYB4\u0001\u001a\u0006%=f\u0010_\u0010Jq;n(6A^D\u001arStJAru\"H\u0001JX\u0002ևQI\nMd}9\u000f\\ڣ`\u0003\u0016\u0019󊎤jSڋ\u001d@}{.x@F\n;7p)a鋋R\u001e|}\u001bPf\u000e7miR\u0006Pz?=Wjg\u0005\u0005q[ƨw\u000fݱDh\u0011dF4\u0010i+\u0005\t\u00164\u0015!\u0018fހ@5:5\u0013K\u001c}\u0006\\҇;!<p\t\u001d\u0004'^ϲiL|i\u0016zo^a\u0000\u001dIb`>L\u0004L\u001cu\\Pa5Ǧ1yD1!x|hӢcIKWKQ`1p\u0001+%ŮN0lkعW\u0014q\"В+\u0018!\u001d\u000bMyd\u001fҦTCG\u0019\u0011mPbT\u0013\rР1\u0011\u00048[\u0004r\u0000i)I9\r\u001bȅ*i@yuI\u001dNNo\u0018\u0013~,\u0010\u000f\u0015\u001d\u0011 ]\u0003w4`ld\u001eVi\u0017R\u0004\u001b4Xl\u0013SD\u001af) 3]0(\u001bȽ<L\fI\"\\\u00183Ji\u0016XY\u000076dq\b`\u00188\u0015n\u0006\u000e-\u000fo\u0010\u0015K\r-KJF\u0014TR*\bꊖ&.2J*8r\nϴ>GrĽG*C(گ\u0007Ž\u0014wWP&J\u000fe\u000erY\u001e=Z\u000fȳ,bʩu\u001etZLpXEI\u001b\u0006jO%RUd&\u0012;!$J{@\u0003\u0013%\"\u001c{V\b*\r\u001c\u000f܁-.j\t\"\u000eZsnq@C\bۘ\u0013\t/s\\hCB\u000f\u001b\u0005M\u0019r[M\u0012XU\u0013A.脐[2HF\u001c\u0006oJ۷(0\u0001yܩXt\u0010IC괌T\u000eoӌo\t,+E\tof'Y><JT068<Adxt/W᯷\u0005*V#QDilf\u0019\u00068\r>Ԃ\u0017}\tl\u0013dz.Ή*G\u0017i\tgߤ\n4.>]a!#G\u0004)2&R`!c5+U$\\j*\u0012H%qO^\u001b\u0002&+\u0019`n\\/+eR\u001dcyP'L\nWlr9\u0011Vŀ0p\u001b(<:\u000f\\\u001d\u0016\\^C=FG\u000fmOdT\u001b\u0006\u001aBT~\u0005?\u0002Hl+{X\u001c%*Jqq\t,g.,\u0013Ð^PI\u000e[a`*(E@%\"F\u001aFE\t\u0019I\"g#s\u001cǎ\"غB8<\rvXA)ŘU\u001eUx5\u001bZ(W`\u0004m \u0003'O\u000bwY1|)\u0002=\u0004D\nU&+jc`\u0002)#9jc\bq\b\u0010y<\u0011'+\u001a\u0018CLb\u0015)x)Mf^;4PJ\bL$\u000bN:i^w{F[%(\u001b\\\u001a1z\u0004k&-Ѥ\u0010WL\\S@(\fOk#\u0015@&FV5r\u000516h 5\u000bM8\u0018$!\u001fʣ]D-7_rC\u0005.)G'9iG1i͘XBR\\\u0001sK\u0014S\u001aC$B@\u00076< r\u001b,]\u000eC\tbm\u0019f%boʑ+\u001b縞4?P^ǂ\u000e,NF Rr*{=8\u0011{\\\u0001wfئ3р&y\u0014\u0005P\u0002␴&*tbݳt\\qpe3\u0006MlEz$>Eˇp\r5n\u001e\u0001bUrZ]ʍqW\u001aXX\u001b\u0012{\u000e묰sN8Bi\u0003\u0019\u0006\u0001Tk3\u0013n\u00004_p\u0005&ADG@{H\u001f%9\u0001\u0011RF=r|:0K%\"\u001a;L\u001cRlO+9\f\u0012D\u0004dpT\u001az\bza5pRz\u0010s\u0016|M|wʇEFyBDVEd*bdF{V|V\u001f\u0011ߋޤZT\u00013+?v\\\u001f|lg}*MR/\u001aqx.\u0012W\r+\u0005&[\u001cf\u000f\u001c\u0017\u0012%1N,(a\u0016|s=D{Xİ\t}\u0014c=4Tb(\\qM%\u001062^{Ѧ\u0013\u0010to$\u0007ovz}\u0001\u001cCެx\b%Z\u000fNk;쟾G\u0019>\u001b4\u001fk5$^z?_?^j_^]_,=\u001am0Zr\u001d0T~9=8>t5J\u001aD$]*Q߈;\".\u0010\u0010ЇRlt3#W\u0005:x٤?SM?Y\u000br8wV1\u0006(jZ\u0000\u0015a86\f+L\n\u001b3#\"Ϩ\"$5Pع$ٝ84E'\u000fL~Ct\u0012\"f\u0014ʰnBL\u000eY\u001b\u000fJ\u000e{>\"\u0013%\u0013hH2\u00011\u0013:Af@2Aɏ\u0004S$\u0015d4.qK\u0010$W:r\u0006@y\u001a'c*\u0014t\u001bj\u0013\u0003\u001bվu~A>>)~`c\u001f\t@>\u0015Q\u0006-pi;RPޝkW\u001b\u0006&ݰI\u0012juo`\t\u0006'h_Up?\u0013\u001brђ\u0005I,J4@h`xyTy\u0004NЍW$Wd2+\u0013\\̖W\rK\u0006b^M\bj\t\b%^T)1ЕSr)?}.p\u001bdFe>@8FC*\u0005=]\n5\u0013)Z$^$\u001546-)2.WO M\u0013q\rz\u001f8iˎ FGWz\u0007@\"\u00153F:AyTQݕDH5Y$ĥh_\n\tb\u0016\u0012I8\u0016\u0012ͤL|G\u001e׷dok?\\\u0017*\f#j_$#\u0010 \u0001\u0015\u0012\u001e!by\u0006#D]\u0019X@4\u0014a3cLΕ\u0003\u001f\u0016\u000fΌ?h9ד|͇➎\u000b[\f)\u001eE\ty;\u0005\u0001\u000b\u0010\u0000b\u001d\u0003\u0010\fd\u0014\u001e̲\u0002\u0000Uן-QF:T:\u000f{M\u0001<]ӕgh/\u0012CbiF0\u0000^@U@\u0010Hߋ\u0004гbĠ, رg6\b\u0014\u0002\u001cv,<w6pG,+\u0015垢~\u0014]u\u0005Ĳl+7\u0001TH*~\u001cW0OH\rЀKcU.W\u000b\n30\u0006~\u0000\u0018v_rul\u000bbP՚\u0014Js\u0000v:lQ\f(V\u000eWQ4͟O\u0014\u0005\u0011eR?.\u0006\bE\b';}\u0011' (fe)ȃAQ1?y/1U\t! \u001bu\t|0\fn\u0004\\l\u001c*z-\u0001{\tk*@>;`\u001c\u000fxM\u0001\b\u0001Hc:\u0000IY_\u0001r\u001eV]LEF\u000bIrYAx^\u0014\u0000k3\u0014,\fq$\n!ϟCEG\u001e͐Z\u0006Qk+a\u0001ϺFiL3\u0003\rR\u0007j+U\u001e6\u00184ըg[`\u001a9l5ʫ\u0013Rs\f\n2\u001a[#۸ 6h\\\u001a\u00000IF\u0000:#\tTqD\u0003\u0019\u001er˵H\u0018\u0002Dn})Z@=a\nb;@P\u0000\n2E1\u0005n}$\u0014+q.07>\b\u0006\u0013sAs+9\u00067ccR\b[I\u0010W\u001c\u0016\u001b,DujѾ\u0011A(5\u00110-.\u001aK2h*Qi\u0019SK yηa$\u001b(\u0013E\r\u0015*=eGkz(2\u0013}D(*[,^|/AB\u0014(\u0018\u0002so|`\u0000/sS\u0013\u0006FC%\u0001N$\u001dfNB\u001b:\u0018eO\u0018\u0000\u0011HQ\u0013\\<(\u00163\u00116\u0007]|\u001dYsSS\u00061\t\fk\u000e╳Ux/\u0010 \u0000hG& #\u0011h\u001b\fN=\u0006K\u0010\u001f\u0019P,=848\u0006\u000f\u0007t\u001f\u0006#\u0005Ĝ\u0013.qw \"w\t@gK\u00188\u0017wPB\f==\u0007o0\u00180Wd[6\u0002Yr$9陑\u000f$$oROuw'\u0001d\u0012/77\nĉ\t x\u0002 dE\tr(ʧyV\u0014\u00018xZ&\u0012d怩cN\\AA݃Ic\u0010DdTe+RAJ\u001cv\u0011r\u00073-0Y\"^\n\u0012‱E\u001f\u0019>98\u0003 \u0013)\u001bj8\\&Sr\u001al\u0012±2\frlQ\u000ed?\"Sq/%k\u0004~L\u000bS\u001b;\n,wVa^~%FHq̤\tdkp\u001eBa]\u001c\u0004D\u000fV\u0001\u0018\u000b\u0004\u0013?f\u0015Q*\u0000:CgQZAP\f\u001a5DvJZ\u0002k\u0001=\b.\u0017Z{-?.\u001fBW.?\b89KJܡyP\u0001%В\u001em߅\u0004\u0004JKxiy\u001a\u0010)'UвN9)PC\u0000[%Ȩ\u0015e\r`\u001eGU\u00120gU\u0018uU\u0019\u0006\u00019`.`,~K\u0013<\n7˦\u001cèӹey\u001b0Qmߚ\u0004\u0016[ePiB> Oc\u0002\u0004w\fZ\u0002BBKX(hN؀HRU \u001fGFsJ}IBB3ٺJjOF\u0006'\u0010P)g\u0018R)G3T$<6^\u000bfQ*~WK]βAx4T*R\u0003\nݺ\u0000N$K\u000b\u0015UjGiS)\u0000s\u0012\u0014\b\u001e\u0018\b7,AYo&%;9.L) V\u0007H9O\n\b:4ln\n[\n(pAՕ9)eYX[\u0013E\u0000\u0014\u0007$\u0004m\n:syTuӵX\u000f\u000e\u0007LZ9B,)A\u0015\u001a\u0010w\u0013^\u0016{R<Lױ\u0007:\u0010<P(\u0019˸\u00009. I\u0010R\u0004%f\u0000:/}Q\u0003\u0005̷\u0004I\u000bS%T\u0017+\u0002@xc<i\u0004#It\u001dL݁vk{@|)P\u0007$UGv, \u0003PίD\feCx\u001d,A/j]o%(ؕ\u0012w㫪{,kg\u0013\u0013r:$mỈ0Hs̜;-F\\\u0007t83LEkH^tZ'!(K<Г#y'l5\u0005ʔ_yfWO6X;\u001bqR(W\u0007\\7b\u0005(?+\u0002\u0018UMבT\u0014\u0000BP+%c?jx\u0016~vtQ\u0013\u0004W1*X~Q\u0011oA`7\u0003KjVgq^J)P\u0001 \u0019\u0005]ܳH\u0017a`\u001eY&\u001eN\u001a\u0017lk\\+\u0000ō,eJnXJ1x\u0001\\1\u0012AON\u000b󽤘wqeY]\u0004Fm\u001fs\u00028iK\u0014ߨr@\u0011j\u0001:O\u0002y\u0001A\u0007r\u001f_UEnr^\u0012\u0003POIɠ\u00181\u0000:ǣsG;\u001e\u0007t<:\u000f\u0012\u0019.J幄\u0014&@x\bvǝQsL\u0001E!\t\u0001\u0011\u0016ɾE^\u0010\u0003)Z;9$\fa\u001d\u001a8*xDs%\u001c\u0000\u00152;x\u0004K\u0013.\u001d\b2dPQI&\u001cw<J\u001dW\u0001N6+ܞ;s\u0006:\u0010j$\"N\u0010\u0005!VK&\u001dI'\u0000AC[w:\u001e=(/\u001d\u00019\u001e3 xdתfPx\u0000tGvJoΡhl=ۼj:vR/U@w0w\u0002\u001dڒw\u0000\u0013gX$\u000eĂ*@7{ǣJ\b@)\u0013@\u0014D\u0004:\u001e<pm\u000eE`u\u001a i^k'9zvj7t<jwԹw<B/ײ%\u00181\u0000:ǣ~iC3Nsl9\u001b \t@qI帲7@ݴ\u001b\u001cy\\1;\u001eae+0˄K#\u0017Yՙw(\u001a\t2 wo8&Ng7k\u00103^YAv\u001bwhl>1\u0000G\u000f,X'+nu<\u001a+9\u0005.j\u0005o%|c\r\u0000Yb@#BǣT\u001a\u000fi.* ;\u001c?Gm2\\OXv\u001cYÚES\u0016SCb\u0015ˎ\u0017_K\u0019ʝ$\bJ\u0001\u0005\u0012neZ\u0011\u001bx&r \u0014y\u0003z{\u0011'Q\u000e!$Hqea;\u0015wø\u0012TR%\u0007rs\b\u0010h\r-s_̏>0pv\n[̙\u0004b-\u001d kTVou \u000e6ut~gp\u0014\u000bE\u0003(\u0003\u000e( 8l\u0016$\r\u000egWp\u001ax8r\b\u0007\u001e\u0000g\u000b\t\"\u0010ނ3\u001b\u001cf5+'\nޔ\u001c+-\u000e6\b^h8D\"Oe*b\u0014۪xa\u000e=(m@o5S]Ei[\u0002ɲ\r.vTm%s3\u000ed\u0010\n\u0006$6*HD\u001dGYN-Λ#q-x7\u001f%P\u0012N #\u000b{\u001ag\u00052\r@NtĽlg\"eoTEFUe\u0013mIĠT%[4wX+ȿ\u0004zğZƚz(\u000e!\u0003\u00175PyBPT\u001eX\"\u0010\nJJ\u001a*s*g\u001eŐЕʭVA*-\u000fLÏup[w\u0013ET/{̝Œ\u0017]\u000e\u0014zJ$6. RzNDTN!\u0011*/9+g\b\n~\u001aq\u0018`\u0005\u0001`PFuB`\u001c*%*\u0000ن|^!{\u001b_\u0004ޭ\u0012\u0014:w<\u0018cǬJdrHΏ+\u0019\u0000\u0003QU@E%\n\u0005e+\u001fsJ&\u0010H\"vU7U1$SN\u000ePM\"y\f\u0015:伕ȓAd7aCɄs\u0013\u00188>lBǛ8답HB:or\th&~G3/$\u000bDU\f\u0002\u0001f\u0015'\u0002~ҌSK\u0001\u0014\u0018bFJU<x\u0000A^IGYŵ\\>NؘCe3e{+\u001fy?\u000e7}ꁞJH<\u0013@HPUhN\"6D%Y@$\u000ejt\tt\u001b0Z58\u0004\u0006Dj\u0012( \u0003v\u0012V!u/,0\u0002lE\u0000\u0015\u001e\u0014\u0014\u0007t*z7'j[h\n'iCv/&\u0019#cZa\u0012>\u000e \u001fn@9>T\u0002\u0007\u001aV\u0000Q.S+IX\u0018\u000fx\\raD\u0006yϥD_𶗞\\v<ꅇY\"<\u00160@,:IV\t9HIZ\t*rhY\u0004t*)He +\f\u001a\u001b\u000b\u0017UZYvV465\u000fJ{\u001fN\u0016ޔ\"\rDU3gSㄳC\u0012B\u0006kPZMOcQ}`&}\u0018.RnM[dT-M1\"3\u001e\tD\u0010*\u0000:3Qx\u00184kI\u0005:$3G:**\u0018qLp=\u001f\u000fQH\u0016\u0013PŶ?ow*\u0016^T\r@\u0006@K~y\u0006D\n%\n]#f\u0004rurqaB\rR\u0003)FӸq+\u0000Sd\u001ajc.~K\u0016\u0014<\n\u0019\u001bH\u00100>]\u001d\u001esd\\\u0005\n'> |,>@\u001c\u0000\u0019ǫ\u0000@@n:]\u0010\u0006TŚ\t6:0\u0005(ؼ#\u0001\"T\rҢҰS8Q\u001avJP`@\tzRmjr\u001cθEI\u0018\u00058\nxW\u0003W+q΅?*C\u0014N@)`a\u0001\u0012>VFYCHq/ۂqo*!{^;CGf\u0007@iZbp=N/\u0007u E\u001cAqlSNFL\u00012Sق\b\u001b$$P;N:Ȕ\u0001%0w\u0001b`ȹ XrsTԮ;t<]`WB4u\u0004(\u0011O(B\u0003`RJU\u0006Vi@b=E \u0013\u001a\u001c0v+o9=vo*gXSkpf\u0014lRJV\fת\u0014\u0006,3+9\u000bb\u0005S]\u0010qꕑŇX\u001fcCX4jR+ZA\ng\u0012\u0007˦5\u0018`VqJ<\u001d\u0015QK4YLGX=rDS\u001a<tD\u0001L\u0001N +!^Л`,ٹ3ǡF-\u0013JB\n6 D-@TJׁ!M:o!®0a&\u001da-\"0M\nb%'&@4\nȄ\u0004,8\u001bS\u0018ޓf|e~{f\u0013\r{\u0010ݣL#Gzt2\u0013{iD(ӈQfBtO]&WQ\u0019ݣL#GFt2\u0013{iD(ӈ\u0006X\u0014Atsa\u001ee=LQ\u0011ݣL#\u000fG(ӈQ\u0011ݣ̄J;9$e\u001a=\u001c]b\u0012ݣL#GFt2\u0013{iD(ӈQfBt2\u001ee\u001a=L\u001ee\u001a=LQ\u0011ݣL#Gftҍ\u001e\u001b=JOQ\u0011ݣt#ǁ{\u000eڹ\u001e\u001b=*L+{nD(݈QzBtҍ\u001e\u001b=JOQ\u0011ݣt#ǁ<yDe]9q\u001e\u001b=J7{\u0010ݣt#GFt>\u001e\u001b=3w%G\t=J7{nD(=!GFtJ\u001a=*\u0010Si'\u000e`\u001b=\u001e\u001b=J7{\u0010ݣL#GFt2\u0013{iD(ӈQfBt2\u001ee=LQ\u0011ݣL#G{lnO=rnj9\u0002+ݰ\u001cfW\u001c(=r\\Jouˁ\u0013,\u0007\u0000,\u0007Uˁ\u0003U,\u0007\u000eX\u001cT>\u0016Ae\b\u001cԦ\"~0eg\u0011\b\u0016\u0016`ꖃʶ;Ap<rP9D\u001c8Pr\u001a1b9p\u0006\u000e\u001c/Y\u000eT-\u0007ΆV\u001c\u0000X\u001c,\u0007l[\u000e\u0000Y\u000enV-\u0007\u00005,\u0007,U-\u0007|ê\u0003\u0007ڭJrP\u0007\n+2\r\u0001[\u001c\u0003^GrZ\u000e*\u0012\u0002k`r\u0016r\u0010\u001c\u0004',\u0007\u000e\u0014X\u000e*H,\u0007]\rAu`Vd|b\u001a:EV+\u0016ʮwj9೨Z\u000eR\u001cT֯n9X\u000e*\u0014\u001aP,\u0007AN7\u000fu:<ϯn9\\\b\u00048\u0015\u001a`ꖃY\u0004[\u000eU%;nZ\u000ejh!F\u0002'ցMˁ\u0003z\u0001)BQL\\l9aP Gm\u0014ɒJZ-\u0002Qt'\t\u00060q\u001e\u0006ǻ ).&C\":x7\u0014n2M&ܿ]+]A褀_I`U\u0000sQ[\u0015@f3N[1JЀx:NU\u0001\tY8H\u0019]hAS\u000eV\b9DzpIlw֪`܏\tL oU\bΪtM\u0014V\u0005c3\u0001,*8k%y\t|\u0013KHQnR\tV\u0005,\u001f\r&ު`l&8\t\nΏ\u0016'ު L\u0005c\"84嘼J;\u0007\u001f'ު`lD\u000eV\n\u0000Jf`oU[\u0015\u0014b*\u0018\u001b<U]8M2W|E*V\u0005c_.\u0003;@Y\u000bʓ\u0012ğz\u000fRN\u000b\u0010\u0005\tDU!u:*yj_cUTiU\b`ΪQd\n}'ު\"\u001f*b-[\u000bR\u001b\u001fd\u0003dy\u0004\u001bF)\u0000\np\n[V\u0005c3\u0013J\u0015*\u0007=k`U0Ve\u001b\bjUؗ\u0000,b\u0015֪\fќ\u0000X%c\u000ev\u0019:b^YW\u001d\u0015\t?V\u0010\n\u0001Y\u0015Л`kUvjmK$*oU0sș\u0014zu\u00134f3) vL\nF\nu1ț\u0014J֙\u0014M\\!V`n\\,\u0012ڛ\u001cZ7xBjmgZ\u0011gRHXI!\u0000&\u0005\u000fLI!\u0013\\AkR@9\"t:\u0013rgRH\t5\u0015\u0004\u00044)Оa7hȕ\\(_\"13oR0\u0016'ޤ`\\ě\u0014liR6\u0016'V(L[3DaFR|\u0014Xrg#YmpKfKE0]!\u000fϫ$a\u0003:݌%)\u000bq\bO\u0017Dx8\u000e\u0013yS/AA\br\tR\tKr]a\"÷c:\u0017&՗Dx\u0012@n\u0003\n{\u0016a\"SIĵg\u0000(f8̣%{.;\u0003ت+9C8LWB\r\u0001Tx+%\u000eSX.\u0013\u000eSᥱ?mr`ι|*QIv>^2\n+ChJ'\u0010<qkL\u001e\u0016aF2\u000f\n0K\u0014u2VA\u0014\u0012U%\n3vTJbRc+V\u0015PaQ\u0001b򈫉$k\\\\M8K\fO\u0015\u0016\u00077!{!!Lgk\tq\u001c&Q\u0011nB.\u0007Y&`j:</ה\u0013`\u001cs!tx]4q-eV'\u0013\"k\u000eRj:<g(}~C8:(@*\u000f,Y\u0003\u0002\u0014uԿʩ1I\rSbQrJ\u0007c%\n36$((L6\u0017x\u000e\u0003U+0=(,^\u0011\u0013R@0jҔOL\u0015[\u0005\u001ffRU\u001c6OS\u0015\u0001\u0010\u001aY6%\u0000388E\u001d;.uaPB^'A\u001cf\t\n\u0010=a&>#^Eb*>\u000e3*rP(zw钷\u0017\u000eO\u0006\u001f#`lz,C;%;|lR\u00151DW6.40U >{o^\u0000)M\r\u0015\u000edp'7E:\"\u0004s:7\u0004\u0005\u0014\u000f,)қG-]\u0018윫C8r*rץrߥl\u0005Y0\u0004^Zz\u001fzS\u0002c0U\u0016\u0016B\u0004zV\u001fǊ\u0012k]\u0017g!{E\u001c_\b\u001fJyf\u0007Л\"~N\u0016\u0003kfl\u0002\u0014\u0004o\u0013]Vg\u0006s6\u0000r$|{Ri.A\u0004dHSa$b[tBbWkI8V\u0013Fن*@e4[s\u00064@91\u0001\n%4\u0019y]\u0002w\tX!|r\u0016\u0004,nLYgopJJzV\u0014H\u0018\u0018URT\rO,P:Pqmepv\u001fTWa膫2\u0005=)Aޕ@Kgmqn95;KԦ'P$/`\nb\rw:5`+Sѱ7?j\u0014;=)\u0014U\u0014[7uO!I\b{\u0017V\u001f5<\t\u0014Jj,vG\u000fQː\u001f%\u0000Ԭ\u001f%I`O%\u0019\u0012RI0A=pż\u001c*\"\r<G)oԓPU4GPjq\u0010\t\b\u0006ޓ\u00126(+\u00068'i癨9=S~lk>IuGL\u001e5Bx\u001e*0AΙL\u0013*v\u001dr)=\u001f*\f]1YVx#ja(\"^\u0011X(5E\u0011rQc\u001eŴ\u001cAXC\b\u0017d\fCYN~|X\u0000$Ly\u00199{#9#oT@<>3y/qAAQE\u000eT\u000b\u000f\rvu\u0018d\u0003]Ը~bY!\u0011<0\u0019L1ӳ\u0000E\u001aH\u0013iiE\u001b\u0001c2M䓉\u000f7,d\u0005\u0002Nf&)/u\rܨ^h@9sהIsN\u0017*\b\u0011ٸ\u0016X\u000brZ\u0007#\u0003X\n̫*͹AWil\u001ap&T\n\u000f\n7\u00038\u001c0r)=ĞϬ|C͏+1a\fDhA!ũ!#Cy\u0006\u0006\u0017%b4o\u0005@\u0001m\u0001rF0yeމ}X)\u0012\tD|1$\u0019k!(T\u000fp2͞n#L\u0010\u001eeaG\u0010ÕF`\u00177BJ\\s<\u0018\u000e\u00107q\u0010\u0007F89.\u0001܀\u0000X#T\u0000ܘ&V51v#@\nR%6޵T;/\u0016\t|\u001e\u0017\u000bU֘λ12\u0005\u0010;.<\"\\\u0010!H8O\u0000\u0016\"^KklxC&\u000f/v\f.by\u0011\u001blR3{j\u0017\u0015񰀓PraTT95xXl\\+&iBBg(:WMlF{`\u001c\u0002\b ]J8\u00062%r4AF Xp\u001b\u0012\u0002l;!\u0019\u001b[+Ϟ#R {\u001b\tE\b.\"\u0018љR=\u0002$k\u001c8T\u000f\u0005Cm¼3㖭4^\u00006iPow6)]2yM\u0016NVNZj)[Hn7\u0017ݚb |d\u0012\u0018ǲ\u0013\u001b\u0002U6(aN\u0012I<b)\b&QC0\f\u0013'gYL-\u001a&N]\f|_/`e\u001bvYpR\u0007SIsSPGXy+ε\u0016~\u001e߹\t,nCജ`rfK:,\u0001uZ#v\u0019h&˯\fo\u0015|(u_\u0011Zpn5Ʊ+\u0012\u0006**?\rքxq\u001d\u0006K\u000e\u000f\"*\u000f~f&?\"=r^$%\u0010>=ے\u001a\u0010KR\u0016\u001a\u0005\u0003<-\r\u001e` a?s>,#-\u001fa\u0005\r\r=\u0012\u0014%Enko\u0002-IbD,A\u0003]D\u000ey4z&\u0013G\nD(4\u00045\u0005w\u0014KϥJ,*VPH)Uc\u0000\tF\u001eW2~B'$\u0001\fyl\u0003F\u0000X\u000el\u0007\u0004\n8q\"I\u0013UXl@C\u000e=x\u00186s[G߀{\u0010-s\u0013c@T\u000eSA$dˤٺObS$~?jА]Oq1\u0006C'Pd\u0001v\u0013 U+━<%jP\u0019ՠ!8Ƅ=>B菛wIAvqo~\fv@:\u0004oiM0;ؐWwUol&PKUlP'\\\u001a\u001fN\"/\u00137I\u0013ws\u0002=p̄k?\u0001/&ސ@\u0013bC[?\u00117Elܕ\tCP[9aQ\u000f']T\u001fwrzMn7j'I'2gS\u001f\u0017.o\u000f\u0013ȴzlΰ\u001fNsQr\u001a5\f.*](;B\bA~y(2^N=\u001evM_V:/zn\u001f\u001dv\u001et\u0000`fNo3쎷\u001c\fzNٵ^`8\u000ef\u001ctp/w{A*Z3[/_LMSjO%ڐ<\u0019\r-a2«/%qVp\u00142Bܧ|\"\u0010{ZoE=~/B62T\nsɾ}q\u000fc;娢hC[5'^y\u0015ھ\u0010W\u001fA\u0012\tK<OSY\u0010h\tk\u0019^\u0010\rX-r)\u0001H\u0001\u0007OAb\u0018^fQa\u001d\u0014e\thJ\u0019?ʹ8S~ß\u0019&\u0001&YO\u0012;=\u0017\t?I\fn\u001d\\\u001a!ECK#$Af1>Sp#zyi{E2\u000f\u00016\u0019B\b\u0016\u001e!\\zy*ED'73N\bA6\"#K)ou?d\u0005\u0014nD&rB;((\u001e%yr-A8JNfUV+\u0011r9<bn\u0007Yo͹(ok7Qk\rC@v稠7+\u0019\u001f\u0010Dih\u0011\u0018ؾ.\rЉ}MqY.(h!\u00037A\u0014\u001d\"\\v5\b\u000b7\t\u0007G\u0007I䍶\rWȐSbNX\fxد,C.\u000fPh\n\\כKE\u0012\n\blޗQ9iSV6,G\\,w\u0019\u0006b\u0012\u0019\n.Iuv2NC\u0003R\u0018\u0001*pReN\u0019\u0000<Y/?\"G֗)\u0017\ff\u0010=庩\u001bԶ\u000f\u0019\u0017.\u0010W\u0000+njl,|\u0014\u001f\u0014EQ[Iy\b\u00114ri!P)\u0015>!e9\u0019$Gz)n4\u0001~ua\\\u0014\u0002p\u0019\u000f\u0002\"r\u0011:G \u0016\\[9.ŧ\u0011DcSӒ>\u0018\u0000S% \u0003τ6\u0002(.\u001d!\u0004T\u0014LOg)1\u0000\u001c&\"'/NM!\tRjR\u000e-\f>\u0003r\u0001\u0005\u001c\u0002H̐{\u0018vM虉%?+&GG01\u00044$cƫ\u000f2)@z\f4c_cƠؖ}\u0011Bd\u0016&\u0013\u001a,\u0019-\u0017F\u0004%\u0014;l's\u0019\nS\f\u0018S-#O9&#ZFVp}&ITH\u0005\\-&R\u0004-^gܻ`\u0010)xѶB,!@\t\u0013[&@\u0015,\u0014\n\u0015NMm\u0016QP$&}\u001e\u0011e\u0000$rBC\u0006p29\tA-(lT$Ab!t/\r\u000e$\">\u0000G&'@\u0005\u0018\bCL1\u0011V\u0000S7&g\u0012֢#\u0001)]\u001apؖkF9~\b\bG\u000b\u001eI\u0015q\u0011TFM:g\"\u0007&~`\u0004ҭՙ<eG<Lຮ<\u0012\t!0j\"Ra\u0010ҡ\u001cCQ!S4\u0012\u001f@H\u0010i!%aM&\u0000\u001b\bhal>\\(\u001e?׼Rr!4b*9\u0016D$\u0001E,vs8JVn/t:\"!9Q).\u001a2S4#JH<UKx|\u0010H'!\u001dz\u0001B\u0014HI\u0018U] \u0013\u00115\"I\u0019\u000bYBd@LR@L\u0010'`qD\"\u0017\u0018[\u000f\f*J-\u0003-9t\u0000\u0003kȖCȐI\u0017t\u000b$\u000e22\u0005}2_/n$\u00139!̏{Vrk3έ˸g\"I\tC\u001fi\u0002\bبc\bB\r\fFҩfQ\u000f_\u001bʌMY\fF\u0002\u000eC̐*+\u0016jA2h\\<s\nG\u0001}65[QD.)m!\u000f\u0000ZDZVK\u001d\\:@m^vjôK\u001b8;%\u0011@\"\u0011\u0002la\bf[Z\u0004\u0007˖<Gv%`@\u0018u}$,\tS\u00196SNĠˑatMP\u0007'PY\u001c\u0001rEL\u001b\u0011'J\u00138!AoȠ\\\u0012\bW\u0010]&k0T\u0002D\bLR\u0016\u00148猆K\u00101C@BnV0i\u001b\f\fr`bWD\t\u0005\u001b9\u00173B¦3\u0005T\u001cU\\Hq_Dl\u0015Ip\u001ad8\u0014)22\u000f\u0003ߡ\u001f\rOʣ8Eg1#\u0003nC\u001b\u0002KD\bH\u000bITG\u0003r^tHÈfɲg&`(I3\u0005\u0000K!4Cl<\u001d7\u0017Ts1\u0012yd6\t>\u000f\u001aa\u0019d<9&\u0000pR`_1cQ\t\u0010Fx\u000b\u0015q&0B7\u0006~\u0016acH3ZNb$R\u000b`g7-\u00038P\u0006\u0011v0sf\\Ӹ>\u0006E\u001ddAs5\u000f8)\u0000\u0011\u0014\u0017%cY\u000b\u000f \u0002(6\u0007\u0017F\u0002̮\u000faP\u0001d\"\u00049-\u0004ȿ\b\n\"\u0012\u000ee\u0007\u00137%]1G\"ۊ6T\b g{a+&Y\r4bcKZ!ϗ3D\u000b\"iӲ\tM35\tׯ\u0001jɉϫ\u0001PE9\"6S\tsaP{|IJ)HXR\u000f\u0003\u0017I`VX'\n ]]\\X)>N\u0012rH\u001djUBT2p1Z\u0002\"w5-@B7\u0019Sq(4јIYGaab\f%\u0007\u0015\nX%%\u0002\u0000<cтM\n\u0002\u0000aLL\u0013)6\u0014\u0018hiRٮG3V\n\u0004ª/C\tA1@\u00006Mq-\u0001#ns4/C\r\u0015N\rO\u000b+,yɾ\u00026#\"\fy\u0018 bٳiRNCGx]2[\u000e\u001dD\u0001#6V_0`-\u0001\u0018$\u0005a\u0014\tf9[L\nNcfcԇfQƔ'Vq#\u001eBS\r͙m\u0015bp\u000bj\"#\fa8\u0018\n\u000e'89\fv\t\u001a`R\u00139Ђ.+lZ\u0006)\u0000W\u0013صA]PU6\u00138b^\u0018\u0012@aq1N\u0012L\u0012F\\3\u000be\u0001`*st!\u001d\u0000A9?Rms\u0015@\u0012~gk%\u0019-i2ujA\"ͯi#x%\u001a8B75\ba's^\u001dfOD\u0015\u0011Ao\u0019?rMX\raKpk:QnC.6-gIMt8y*Z\nT%\u0017\"/G;/\u0014%;I\"bMm\f6\u001f:Zq\u0012g\\`̊x\u001af@b\"(B=\u0019\u0019\u000f,\n1@'z\u0015\u001d'xN2.{\u0017%~pcKH\u0002a1TJdud\"h1+AdPBRy\u0002o|\u0012w$sJA\u001c.c5)\u0015\u0018X\u0005Jj{b\u0015l+I\b&PQ\u00038y\u0007R\u001cL.\u0013V\nji\u0003V@]\u0004\u0004JEΊ0J`\u0018a\b@Acceb\u0013*t<!\u0015Dp=\u00150Rp@&CI2\u0013܇\u0002\u0003H\u00035%3)5\u0015R6\u001fK}\fF\u0014K,oxFbGh)/\n3[ 6\r,\u0013\u0010kO\u0018>t͠؈\u001aۘ%6\fL+\u0005I#Iv*\u001492\u0017\u000b\u0014\u0014n$ޘL[2jqih,sx\u0005rMV<ybIJ.wl\u000b\fIx-o2[\u001aI%U\u0012E\n.a\u001e`Vs\u00177kT\tCd3}\u00149O%q$O\u00123To\u000fH\u0013(qoAMb:q9Hf\u001ak8떼E_F\tbv\u001c\u0003r\u00069\u0004\u0012PkVy\u0015b=eHlS3k\u0017+VF\u0013%Mat#Iq\u0005`\u0005&H\t\n\r8l(>ٝ٤\\lpI\u001bS.u\n\u0000Pc`%`@\u001agV``F@%(#_e6Fw7\u0007>\u0014dǁ\u0000U\u001cS\u0016bt\u0014\u000eDT#!\u0006̮fl3bZI@xr!p\fYEt\u0001/\"*\u001f~`\u0014\u0002eDu\u0004ؒ\b\u0007T$F\\\u0000&\u0001U8lNSB~v\u000e\u0000\u0006@[S,H\u0011H\\$\u0016ʥCcM.eM`-by$\u0001Q!\u0013 E7\u0000Q\u001c\bA\u0012\u001e{CYi]\u0018\u000f-N'iæw\\\u001cւ\u0013\u001fz[8q,\u000e\u0000\u0018`.ܔ@\bEtQC/S,FL FvzX8wŁC璝ܻp_\f=69t,Ya\u0001$\u0007DYw!\u0012х\u0013\"\"IAi\u0005\u0010\u0007ؘItq\bF\u0010\u0000̗'\u000eçq{\u0007y=l]p\u0018\b\u001aqol9\u001cer|\u0001l.\u0002I#*,M#\bE1HN\u001f~$&.\u0014\blɝo\u0001,1̜n\u001aF\u001e\\%Q7ieZ\b<06\u000er\u0001,\fI3\u00024<'^^\u000f1@,v铐\u001d9gË,-DH\u000ejŗˢ1B|`\u0005;u\u0002[\u0013\u001b6!\u001ehUB@=Ӟ.k>'YK\u0001\rajl06X>K\u0004$e2ĶE+*QRq\u0004\u0002l.JfNG\u0014)\u0003DJt\u0017ؾH\u000fFHR\f\u0013\u0010\u0019 *\u001b\u0012,#9C\u0005$]Y.\u0013#\f\u0002\u0006:}M!\u0003\u001d7\u00001d(x\u0012aleJqp{%\u0010\u0007?L~#{6\tT\u000bf2-\u0010\u001d\u0017\u0014g\u0005.g2T@L\u00198\u0015\u0014S>\bf\n1d\fd\u0007=X8$~W1\u001d6\"(HE&&:\u0003\re\f|(ͅ\f\u0013\u0006cmax\u0019.Ey09&\u0004\u0012u\u0004F$\u0015\u0014\f`Ɖ\u0016\r\u001f.n\r%ʥ㉝Kj}\u0004\rC3Q&c\u0002\rP\u0013[~\f\u0004L\u0011}\u0012qd.1(D\u0011[\r<cP<wX\u0019\u0016aN3\u00005R\u000en\u001buk.\u0017|b3\\dpwްAdWJ\u0012u@\"\u001f܉+~\u0006!\u0001̑\u0010\u000eR\u0000'T\u001a-\u0010P)$\u0013?2̩,'0\u0001M <\u0002\r\u001d`\u000ey\u0005\u00159ObS88[u2\u0011,TȊ9\u0003.즥\u0012g\u001cZ\u0004HCbD1Nh\u0010sE+-'\u0019 ca(\u0016RHǆAQcFe\u0013=\u0010#:_G,+g\u0015\u0017b\u0013pSqq\u00023(\tP`1\u00057\u0011\f\u001af$aZĹ4a\tK>\t473\u001e\u0019)(g\u0010tdT\u0016#\\\u0013\u0002s\u000b\b\b\u0011YH\u0015z_\u0000gr97Բ\u0010\u0003/ \u0012\u000bP\u0018qFd\u0001+f\u000b*\u0004\u000e`H9\u0003z,\u001bb#&4dFl#(\u0001S\u0001)\u000bi0bHrw1㓧\u001a\u000e#mZ\u000b:LFqh9W3S塻\u000b^!Nׂe[\nAd\u001aڔPIqvi\u000buٺ\u0006\nTP9\u0017Fh\u0001gs9βW`[*\u0007\u000f4T\u00043g %\u00042d$NDb#\u0016_{\u001a6g0\u0006A\u0013q\bG,\u001fj\u0007%L\u0007wphTb\u0006leŦD\u001cb1Nr\u0015$7\u0015д\u0016\u0002\u0012;\rg]W\u0000\nq\u0014Y9Ź\u001391\u0012Cm\r?6%u4]\u0004 d\u001f:\u00131\u0000\\<l\u0001C\\\u0017)Z@![\u001b\u001fq\rЕC$p\n1:\u0002y\u000eS0\u0014\u001eD\u0012\u0017\u0019\u0000V-X\u000fΰ\\{v8l\u0014A2E\u000bE@:p<d4̯2\u001a˷\u000b\u0010\u00026qXb\tu*]\fbi3ɾ\tgu\u001aU0/%\u0002\u0002J\u0001\u0012ŞhP\u001cQ4VF\u0012\u0017^8d1-1`E0\u0014F?#\u0002:|$\u0001A9\\)\u0005x\u0010YX}eI\u000041<*chpk>:^'\boa c\u000f`m79HL\u0012EQ.\u000fSb&\tęOzį\u001bѠ94Y\u0001sT{ԣ#/c;h\u0005S3{Nkix<z\u000f:^gxZr\u001e\fG\u001f6-meZGS |L/\u0011wA\u001f<;]o]~\u001e5w1O<8\u0010qNcehZ\u000e\fOh;o]\f8\u001eu˭9\u0001B\n\u0006t>M̈́\u0007?qHu\u0015SX{\\i\u001f?\u000fLbR\u000bQNÇ-%=WY\u0006kŠ1\u000f8Bu\u0019{\\?]\u0019<?k']=D`\u0016Ya\u0015\u000f<\u0001Uko\u001fvZ|f;χ6Ⓥ[ӣ+b\u0012{<-MNPV\\&{PF\fӝ<9~;\u0017t'vя:r[g\u001c7\u000eN\u0017\u001dK.\u0017:έ^g45?W jf?_n?s$\u0019c~d;e+u{ 'D[@EM0<;\u000e=lۻ\u001bL`;鍩f{8x89,\u0014{<\u001fRJ\u001b8\u0018?\u000eH\u0016ÏcKrc\u001eH|g$k\u0011FȨxߌ'9@)EbkE\u0011#<-K\u0003#=\u0019\u000e\n\bGp1*Ez\u0015^\u000fCe \nI {\b\u0011\u001eߺњj\u0004syKmE<\u0012}?/ONRZε$]\u001d3Z\u001b٭}z;N6;OzԅaR\u0000z/e\u0016Q\u001d\u001dqM>/:N\u001e\u001dɏb4܉r\u000b\u001eN?h/RlY\u00151;=G{SK;3~Lg]䥥`\u001c;ze*Ϝp\u001c]v\u001fm\u000fܖD'Ϲ\u0011_u\u0003W=\u001c\u0007v׊\u000bA\u0006!Tı19ڰ4,K\"G\u0003dV\rOM6$ѓ8\nELs<^01'\bp\\\u0012uRYbQ\u0016\u001c!\u0014,3!\u0015@\u0000Iq2\u0014\u0003m-\u0010!\u0007E\u0015\u0010'!\u000f\u0019e\u001d:\u001f%E6s#]?8u\tK3\f\u0006\u0017sNE\u001a\fqf0\u0015k?z\u001e}>]v=o9[]ɱ\r\u001ai<}8\u001e}\u000fYK6jX\u000b\u0010N܄J_ۈ`4.h\u00078u\u000f/\u000bȗO<\u00075ڪ\u001aZ.\u001fHԕc\\\u001fM0ʳ\u0014L,3Μ1\u0002D(h0<<Cf'2\u0007c\r\u0018Us2\u001f\u001f.\u000f\u001dTp0n;\u001fvҋ폺A?4?\u001cyas\\\u001b#iJnGmH;i̕#APp#W{W2\u00176v`}~ \u000f6:(\u0006,dO5`\u0013\"10%\t~0\u001ft\u0007c\u0010\u0018ߌ/&!\u0007S\u0004GC<\n\u0018\u0017x\u0011\u00164&)Q\u001eϲ ?HN[b\u000eA^X\u000e\t;')sq'?\b\u000f&(?\u0003A\u0015\t%A:\u0010\u0004/9T;\u001807:WÏp\\k^}pw\u0003ԡeU#7l\u0006\u0005UItTPIŜ]O\u001aY\u000b$ʩ\u0015\u0013M{`\fu$2,5y\\dq\r[\u0005d\u0016\u0011L?\u001fH\u0004S\u0011.[/\u0010\u001f/nq'jjQWau;\u0012M\"\u000f'gD|^iףDy70 i>:LF~XMrvZ?i'$\u0012\u0015#P(^\u0004Pmq7??\u0018(om\u0019Zu>n(~Up\bMO\u0014j\u001d}\u000f~x\u000f\u001f8\u0015@\u0005'FZpdgOtN\u0010)\u00144E\u0014ijUei\u0016C6.P\n%/}&i''LߒC\u0007a\u0013i\u001b{w\u0001\u001e\u001e<;\u0000YwG`(8\u000bN\u0012+S\u0004gpT*FyG6w8H`JQ\"\u0012f]2F屶E2qڅ)\npTG(MkJ2fބ]\u001d:|jsy$3/>v\u001dL\u001bw\u0018K\u0002u\u0002FZ#\u001f\u0016!',҄fI+\u0003\u0019G0_ZP\u000f_=h=T)\u001a\fMBBj\u0014\u001d\u0017\u0019\u0018\u00154\u001cn`Y$mW^o/;Bnrh9Ac1jӤ&\u0019Y_\u0012ӑؗ\u0014)k-h\u001c\u0001S.'OrĻN\u000eS(I\u001c.gtFb*N\u0015I!iO\u001e\t_v\u0017(\u0014X~\"8H'i\u001e\u0019C*nӚP*\rE74nk,/\u001dt\u0001ѥ)\u0012uSԈNLG\u001e\u0012kta3sG?l\u001ft\u001d\"'\u0014LpI97c\u0002M(#\u001b\fy+6`yuZ\u000f~uyŴ&Oj\u0006\r*LDKմ`9\u000e:\u0018}\u0002E&~NB\u0005N\u001ff\u0016ݶ\u0007ʙqi攛XtG^L\n{/i<BM[ô*\u001cVn|v\u0002\ry%yРyBmu\u0014^\u0012M\u0007\u0017H՟\bm\u0011\u0004\u0004؆\t\u001b\u0018\u0003\b\u0006\"R\u0018֙a \u001a\u0014\u001cuCb\u0005\f\u0012\u001bpJU$\u0016*\n%X*aˡ\tQ\u001a[]\u0014tz\u0005\n\u0018LZ#TQZ7E\u000bG3I.`4d\u0002ysӈI$bQ\u00033\u0001-'\u001cd<\r/Li\u0015q;\u0005Wi\u001c\fk&Hљ\r3`\u001b\u0006ňDŮnAj$ˈ\u0014cXY\u0012⿑2hBEѪXҺK\f_yx\"8\u0011F\fyB ve\"4YMĀBLcBB^\u0014QbRU`<g_᢮F\u001clZ\u0011]IP\u0000\u000bbQ\u0013\u001d\u0013\u0012\u0007c\u0019|9h5V˘BMt\f/\u0018E2\u000bΡ5'\u001b瞆T)p\u0016^(\fG j\f)*Rs$%fZ\u001e*yFE&'\u001f4@*ᑵtHj8r{áqH\u001e\"ɍM\\f\u0012OtA(auUD(6\u0001x\\А*JėX=I2L%dbiy,ā6\u0000\bm=]q~yZDyM3e5\u001a\u0013\u001cSrZS&E}Pӈ})I\u0005\u001dLL\u001cSo\u0002q^Iw\b\u0010Vx,t H2Y,ēDJ\u001aHf%Qt\u0007:'\u000b\t&\u0005E_#bg\\(ͫtSm\u0012NK8Ĕ\u001aM$%\u00193ZyFPHr7,-qC\u0000)Y)nT0\u001dCAR$&њ\"I\fJQ1&ψ/`Z?:CDB2\r)ss\"\t\nb\u0014\"\u0000\u001090\"q|`\u0019#3d0k=IU\f\u0013I\u001dILH!i%DޑrAth\u001a\u0002\u0007+\t-S\"\u0018(Q\u0012k\u0012UwƯ\u0017'.TđDh \rd%\u001dN!&$!\u0014\r\u0007$\"tm\u0015!0\u0014Mڨp\u0016\bI\u0014CGa\"\u0015ޫ\"E?\nP\u001cn\u0010F.̴VȀQ`\b*'m\u0004\u0004X\f\u001d\u0014ψ\t3\u0011]Eժo\"\u001cm\u00196)fO4Dt5vG\u001bwF_ HTD0!1.gt%U(m&\u0017RZ2\u001b\u0011\u0013\u0002\u001d^TEWvxQHTh\u001a\u0019{2L\u0000?\t\f$vf\u001a\u0014;%<K\u000b\\ta\u0013rg9_!a6yU[vf8ǔgKȀ@G, 0&1\u0000´Dz\u0016\b}FYZ\u0012#!\u001fA㐘|g=!Ni?\u0017?\u0015\u0006qxCe@\u0014AQ1cC\\_@s.<&GF\fSi}MҬ!D*D>Lħh$\u0003FR\b\u0011d&؂D&nn\u0012MA$NZ(=\u000b\t$\rd\t2ǗW\u001061ҵi^$,,\u001cA!FI44_Z}F\u0012\u0017u\u000b<\u0014\u001bLvg\u0013\u001aw\u000bbj\u0011\t,\u0014r&X@\u0011\u0017D&\u0018`!n\b\t7QM\tfR|\u0014\\LW#eUP$3|ht\u0013\"ɔ;)׸\u000b\u0012\u0012\u0016-\u0017k\u0011M2h\bUe2/fk-\u0005FI1e\u001f\u0001^j~{I˙}\u0004M΢)![G!g\u0016ٶw\u000f\u001duF'N\r,9}[|Ar{:a5\u000f;{]\u0007e_+ּ\b@^k\u0018lY~o\u0006\u0007QK}6<^w܂\u00039p\u0001=T&}\u0015\u001d\u0000Qg|◓V}Lö:Ug~S՞WvR\u000f+z0\u0013{HJ\u0010;AkVHD\tn:IޜL&Kh@ޙT\u001aSޑknl3&<\u001e\u0012*\\;\u001eMIZ۝vgǪ_\u0004sjk\u001086\u000f\u00069\fN3t\u0007=&Y\u0005X+fEj%>)tg2$n\u0002_\u0017K[u\u001d~\u0012*5Ui%&*fKSCS0ԋ[jvjR\u0019-\u000bKؠ4,+\u0013 5ݱ9ʤzM\fIb$1v\u001bȁ\f \u001dvdBR\u0015i\u0003\u00049kRLEE(}Eǰ\u0013)h\u0018YJs\u0013+Bmc4Sκ'\u001cR?-Vu\b_\b#\u0013\"dᢥsE\u001b\u0015%Z@D:ZA\u000e!\u0016\u000fV\u0015I洼P<LD\u0001OQFڀлА\u0016ِ4J\u0019:RQIJ\u0002Z4i6\u0002\u0002T\u0006\u0018\u001ee#L\u0000*ix[?4\b\u000b2\u0011\u001f\"U4\u0011G9#Vƞ-q\u0019\u0003iNCy#Y\u001aO\u0017\\<\u000e/ORI\u001e\u0016\u0002)\"dJˮgC&B\"b\u0010Mw?A\rC\u0003{$\b+5u,\u0004tLci=8.Ɵ\u001dFq4[ܨ~ڋ8BM5iӍ&\u001cP\u001b\t`FI\u0015h\u0004nZ\\bB\u000eB\n^\b+\u0003S\u001d>\tsႌQ,&2\u0004S-\u000erl@5&XG9~d\u0004\u000b\\\u0006Ӱ6SNt\u0005\u00150J#\u001d\u0014E>UɃ\u0010\u0004M9b\\3$0N4XJ~o`g$r-\u0014BY\u0007\u0003Hn4\u000ff\u0006\u0012_`\u0017u[uM6ybym.\u0000-\u00175\u0015`7q\u001861ҷ~Rfgt=&iDR6')sn\u001f5\u001cv H\b6\u000e^\u000b=ğa\u001ewZ\")44zHzv_V1v^Ftwv\u0006$\fw:e;>8\u001cUح^\u0019\u001eC[iS\u001f߭W\u0010\u0011I.k\b\r\u0015|ӭA>\u001dnm\u000e9:uƣ^gbo7Z3>x<\u001c\u00135]\u001c\u0004._]\u0001\u0007v?v{{C(0hrʻ_?/G\u001dubpt#(\u000e\u00166+i\u000bvHm!LF\u001f;ؘ`3\u0014гwƵ\u0010[׵Ð\u001acm\u001ct\u001e\"^_\u000f:r'Sw\\wz /h<8?]܋C򟇇Gm=$銝\u0017\u001d{\u001a/;_\u0011)Ǡ'-rg0&:\u001f?&}?)749aH҅{\u001bx\"2\u000bs9韩1\u0011leg,_=\u000eulﻸY\u0014\b\f\u0011\u000e<K򽗥|\u000e\u001c.t~&&~v\u0003ဩxYuK\u0007þ\u0014\u000e;\u001e\tK<r\u001e\u0017<8\u00154\u0006Ŀu]\\/ZGm=~gi*&\u001ew\u0006^kw\u001b\f[\u0012L~'[\u0007\u0017=WۡSsUЊ\u001ciowPo=Z:\\̱%i76ig4\u001dה]:&wtNk=$\u001bl\u000e;(\u000bX*)t0ci{4\fS\fF/o\u0017KNgoE\u0005>/o49kH\nq뎿Ttp9\u001cw{\u0007/.i\u0013F~njR/>vw?6;\u00198\u0012.&E\u0004Q]B\u000f[N֛ycr/FOAW=7픶¦>a`0[T\u0010|J%Hg6}ߜ8Un\u0013&\u0005s5p\u0015Ҵ*.)\r1QSy$iWtr\u0006tC\u0006{\u0001cI;21˱v5dJm\u0012\u0002\u001d}O\u001bquۣ<h78\u001eNkĹ\u001aFN'5\u001ew3 w0p=9n㒷6y\\EVu47f\u0002p'_οhhv9\r'ڻEvPј/pɈ+\u0016򐉭=\u0012Dg/7\rnL碹(\u0010\b8\u001dz<\u000ehW+Cu׊Lku\u0004Iҧo1 B\n.\u0015\r\u001blàQC>l\u001d\r\u000f/KU[;tq\u0006)0\u0013w\u0019\u0006{;\u001c\u0013\tZha\u001c'\u0001g8pwpC\u0019\"\u0017<ׅ\u000fy\u001d}c\u000en7\\='&}boYսm\u000fNvnJX`\u00001y챾Qk8|:\u000e; &Iu=\"\u000fPy@\u0012٬*+_\fY]<;^IN\u001a\u00042Pg{53<ӍϋE?\b<r\u00118;;\u001f\n\u00131褯xO,|e<Mv}.\u000f\u0007GN[p55eY\"o@@i\u0003\u0010;굿Sn)S4TS\b\u0003ϰ\u0016\u0014w\"KTM(̜ʣp.ۃ2\u000f9ٲrSI\\\r{xT]i'\u00069^\u001e\u0002TxcbQpOIiuP\u001b\u001f\u0013nH}\u001b\u0004C.<5(nwԝ:\"en{{HX*m+a\u0013\u00044`3e[\u000e\\\u0010\tM\u0011*acܼ\u0006Dlv{\u0013t=aB\u000f~\u0019v\u0003lRͭ'Hs2_Z?\rv,{\r2Po4$u8꠷aU$\u001c}\u001e\u0010\\7\u001b\u001e%x{Vfi^\u0007\u0015}OBˁS\u0007;Aƾqw6\u0018dA\u000ePh?'\u0005+8\u0010qBV^x!bt\u001d9CL_\u0006tx#*\u00141hܛۓ\u001ey\u001d\u0006q̶/mth~=sw..|Ť>:\u001af\u001c\u0001[S\u0007K\u0002DIBkxԪ{HnGl|-\u0003K[LrX\u000eGmC\u0004!\\#\u0005z2$`x!d'^ڮ(ܴS\u001a\u0004S:5k\u001c:b\u0013v3\u001e\u0003\u001b:|Xi=rC6]{$\u0004r\u001cUs^Q=\u0005tcH\u0007\u0005-@#gOl;ܛ\u001b\fQ]!\u0013\u001bNq0\u0017\u0000&:Bi\u001e̝z\rݽފlk\u001c\u001evLnیI>tS굏\u00073a\u00109<\u0013oPZ\u001bB1ڙ̩t\u001bM6XDp3\u000e\u0007Gg4H%Yf 1Yδ\u001eN9Ǫ<Q2s4\u001e\u0007K:ma!\u0004&]\u001fU\b\u00137`4G\u001c6~g4\nt\tcSӏm;Q9g\u0018HuSFŻ\u001c:徖\u001e~\\hkUWquѤai`9lA?yHj98=\u0005[\u0001l\u000fiύ\u001d\u001e&\u0017\u000ec%g^h?ƶ\fnϾXopw&u'({LNw1Q\u001d\u000361'\u0004\u0015\u0014,*]+arXqD{\u0006ea'ox4\u0016Y=:;\u0007\u001cv>wm@-z65zi-\u000f\tۙ\u00177^n>\u0000֠\"g\u0015\u000e<YvSU\u0017]@cZ\\ou9=?E/\u001fbNkq(\u001f-QuCWg:0ިxc]9λ\u000bk6v]LE\u0013\u000e\u0006֛+k\u001frbh=l\u001f\u001d0FCv>-yѹc'T,)2k\u001e\t8a=초j\"Nֿ>vQwlc+\u0016\u0006\u0016G{\u0004q\u0001pl]V;28n\u001d\u0000\u001a[ts\u000b\u000f-\u001dD2е\u0016\r?Z[\u0001c4nz/0\\1\u0012j2:WX-,4~9|w:F/;yzw=:C\u001c9J*\"Ru9Xv\u000ey\u0014\u0011n}Zn\u0004~\u0004Zn\u000flO\u0004ޭq\u001byb;Ӎ>sT\u0017ت rHNݳV^ɌM?8\u001c\u001cvV\bD=\u0012b\u0005yl\t$\f\u0003\u0004.Ƥgѣml+\rf$'D\u0013B&5Gr7\u001etC<>u'Kw={ϳv\ftV\u00135c^]O&[A9֎%)dN퍼z2еrNi=o1(\u0011Cg\bnl=/k\u000e+\u0006-\u0013>\bo91\u0004KE蜗ӝ᧬.NȬڏ\u0017?$F\u0018п\u0006KgFNG\u001bu\rѢ\u0015\u00136DB|AYߪoɺTI-3pP w\u001c\u0011_K\u001d<8gs\u001e\"iR\u0011\u0007wi\u0012au*W\u000bϻau\u0019\u001cbp\u001eotDzy\"kʯ:نL.H\u0000}{\u001aKʲjK].n-f⛫7_ܺt٥Ï\u000f?_̥n{nKjz³\u001f;7^z0<V|\u000bQ4Zrp-e+\u000b7\u001d\u0016F\u000f'\u001b\u000b7ugk{ܥP\u001b{hlemzxӻ%z`c5xvzxmEbSҋ~Ɋ7o\u0017瞟<h-\\\u001f\u001d^]6}6swoj7kW:֕w/B븲\u001d^\\ٍ7~[y\u000b釦<Z~~@OK_\u0016f/e\u000e/{SŧGեG~|r/|uo|h\rzRoΥշǋ\u001b[\u0017//ܸ1No<߽tx\u001b[,\u001f'qw9m[vH6oR/<\u0015ژ^X^y\\ߤ\u0017ng˃Wo>{s]\\xOӂnW.Hޤ/'}ϗY6݅+\u0017~zQR{&S}M/V\u001fHkJgZ'}\u0019]}{Zsp\u001b{\u001e\u0013\u001e/\u0019;\n5Z'@<s)\u001au4OK+\u001fxIOWW\u001fn_e)y潕\u000f\u0017?\u00177}\u0012:ݫ\u000b՗9[$X[A;W=O}\u000b7^\t\u000fK3};|B\u000eS:+׮.\r.<wOrjj[3k+x)o܍tgpc{qs+k'\u0019;ß\u0000&:\\wOOţ\u001fӧWwWV:ᵨy놟lߌ\u001fǌm7g]M}0)kݗ\u0003ͷ~;|õy\u0014?[[;|s\u0019]ꥷ^}[m_U4͢x\u000e\r&(L\u0012_1hζnum|睢zC?ȍ`;ꦠo6\u000bU\\xH7eë\u0006=xKt,_7\u001d;\\|̚t^pp|{?y95}jo#v1XE7\u0000_^[\b76<޺wt%l}%=xent@\u001f\u00167~ێ+,ŕK+<ڇ?}e\u0010wJگ\n\tBL`-'/b[i¿.n][/wOd{{k7We\u0015k9җ\u000f\u0017z9՛~f\u0015\u0013euY`pgo)z\u0010-ʿ#\u001d\t^\ba\u0012Q\u001b۲m?|0s>D\\l7k7\u0000f֨ݝO+\u00041J|\u001aN\u000f~xÕz\u0017\u0017?Ȕ09G2GyyiK`3^\u0015[d\u001ct&\rF\u001eg\t?~|\u001a=Cf1Ji~'\u0016~~ѯrP\u001cW\u001cD\u0018x- OwfDm7>UCڕ\n0`\u001cx-,k9ϑ\n_nUO\u001a$8\u000b-^\u0011D&b\u00137KwmGf4\u001b\u001c&OX|c]Tg\u0013~}s2(A\\v(SC2GډIW;>\u0005\bT'ȿV\u000f_x_fLo5<X&4d[\u0019\fc_N\u001f\fY)\u0007'D?%\u0015ŧ\u0007\u000fH|pTc\u0018\u001f\u0016\u001fH,13i \u001c?a}eF/9V6K N\u0004RA]K\nMMb \u000bુj\u0016\u0017<XJ/w͉Tvb\u0007T\u0017t\u0015|p?Vg\u0007w~(K\u001f:O[\u0016뇫W7g\u0016#T<\\*_2\u0016\u001f//mBaecH\u0003\u0014V]i ld7v=]rxI\u001d,{\u0017\u001fxBrٳwG;C+mKĶyatt\u0001҅\u001dY={yd5|C(۲ۉЉt\f\u0018rʧ\u0017\u001f\u001b\u0007$^iOneO\u0006l)\u001fY1v0vYW=;2$=[YU|&[+\u0015a0\u0019lA\u000b0\u001el\b[\f&rRqyy\u00016H(\u001fLyL\u000bڻW>*RwzO~\ba}ݨ.\rdM56\\\bzUݕ\u000bk_tqӿy7yq\u0002#\u001f^|h=C샋Qxg3xsTuze۟_}\u0007Y\u0004\u001e,}~xD^gu\u0007o\b\u001d\"B\u0011vui obvlwu\\\u001b`;[Ϥ>~ŭ{\\n\r³\n>\u0003>[3Ǫ\u0003\u001f8:C.\u0010QQ޷ꇣxgƳKsL77?-n?k\u0001\u000b\tެu\u0003t[\u001b쟄1ono9oo\u0012Z\u0014OJ\u0017/֙7\bn\u0001aލ\u0015Z]ݕfn7ۻ#'ӽم>},j;ylM|G\r+/o,ԙy+sd'ww喥/n\u0019yt6qH/=>N^V?\u001d^\u0007\u001c;R˅/~ؿspZؕPl݋i7Jq\u0001-\u0019ǻt~ot\u001eo8^\u0017\u0000S+\u000f\u001f\\\u000e=ml\u0013ꇨne{ejzYX|ٻ\\\u0013e`3\u0011l4\u0002a1͙ۜlqt|N\u0015:@\u0011vtk0f\n\t(o}q>!\u001dO\u000b?଎\u0017󝣃k\u0016FGL/ͮ\f˵❍uUv+hvw\u0018\u0013|~޾\"n.ͶùP,2rb#nr}oof׳+Qr'Ҏz<R~.\\\u0007\u0016P\u0006\u00167tiV\u001e.>^\u001b\u0017F[\u000fG\u000bצGx0%}tsIP\u00131;\u001bŽkc+\u0004C#D{xw:~4LPJ\u0015K}l3\u0000ҽy\u000f;󯏪,߾ڇ\u000b\u0017h}W߮4e\u001bds?WwLM_x5y}\nYnX+E\r!Ϸ' Ƚ\u000bkˋHD\\XItlڶ6Cmyqu{1+\u001e\u0014ץCZRtb\u001306T˳k^<tG/W\t]t>_\u001a_ү~~v[}\\+b^\u0018#R?V\u0007K\u0017\u0006a\u0002\bqӣ˯6ǋ\u000f^{\u001e<[;,>\u000b\fQǟ\u000fJ+DxG\u0013T\u0010{~qs;]l:\u001aÕwە\u0007\u000fn΋lͮ3k\u0017\u000e\fQtȬ{\rۼL{)hʃZV/kǛ\u0016\u0007:OWŤ>7JN\u001et\\,ewnG\u0017V6\u001fnM\u001fi\"./:\u0007\u000bk]E+\u0006ѿJ\u0001}xօEｅs'F\u0017X\u001a&;vYz:3y\u0007B\u00127+\u001a]{'@\u0017wՉlm,\u0013/߃`qPs:2;T7\u0005Yݷw\t_>\u001f\u0007\u001bk\u0017~aQ}Ӆ+s?\fvzmv =MB7:sK?\u000bW\u001a \u001b~.\u0015\u0006lhom\"<d'o/Ѿh*`S )-;ʒ(/ƓǛ[TawDlkfK~}8],\u0001<~)ý\u000b\u0014y1]\u0019ܛ=\u0017Vۿtxb\u001d\u0005ǝG/餻߾Yp\u001a+\u0005C@xo$r?r\u001cᥗk\u0017:Kx4\u001dҴ\u0003\u001cDAV{K>m.=\u0019ܟY\u001bt]F!F?\u001f4\u0014^7&IV\u001d^\u0003][|r\u0003q8$7k\u0004\u001c^\u001d\u0002\u0012L\u001dҭR@qe\u001fo9Yٿxt!\u001d?\u0018ZЛ}Nct%\u0016AW\\'$\u0010tiP/N^\u0011}\u0002!flC\u0012\b3\u0001\u0012\b)\t$LH0?ٯ`\u001bۘak\u0001(U$JB(.f\u000b\u00146\u0000\nmy34B\u001a^u\u0005:\u001b\u000b[\u0014KJNF\rqe^\u0017@5|T\u001eQ$\t6\fʰ5\u0004>EfǗt1H}p/\bҒZ-I\u001aŁ Wxf\u001a/'J QJRޯP_bmzM\fڛq1\u0010\"_H\u0016-\u000beR8>|\u0000\u0015He;?\u001f=U`z\u0000\u0001W]>\u000e\u001b4\\u`MpL\b IG\n+IyFr\u00198*\u0004<ubd\u0005\u0018y^sX\u0001n沭\u001b\u001bfqV~k\u0010=b@D\u0017\u0012xHk(^ zkA\b88(7\u000f\u0015*O\u0019H\u0014_{-!(\n\u0011Uߛ@c\u00198>iH\u0012\t\u0011y\u001f\u0013/<y\u0010\u0000WvRy\f3e_1=Qm~ޒ\u001f\u0019\u0017:\u0016\u0015Ct0<;JW&?\nH[_aF?{qe\u001d,\u0002\u0003a\u000f>\u001b'=\u0000E\u00114Չ\u0016\u0015kW\nOw[\u0004Ǥ\nV\u0000,P\u001bć^\u0018w]K\bG*h`WnB@^\u0007_W0a*86\u001c)H8u}\u0013&\u0002xе?\u001a3\u0018k\u000eړ_ĳ\u000bH{`wHz)\t~zY9uPF7yn4*梄h\u0017)|1N\u00100НV۰}6HC\u0013\u001exG\\K5\u001e\u0017\u001euxtGrd(U5[,?ø\u001c? p9x%Z(\nrL1NTlE f\rp\nX7W\u001fZ~\b\"\bJ\u0010\u0010b\u001f@!-\u0005\u001f3\u0015L\u000f|p<\u001fM\fx<O<_o<z&\u00182ƏO\b_\u00033\u000fn+*.\u001a}M$\nً\u001aY+@9\f|ߣ_Ay\fx\u001cH\u001c>\u0004(\u0016\u001fZC_\u0003\u001b}0?{3\u0015%\f#{P!~2\u001df`\t2ŘI\u0002ܑI'4Ngle\nKQ Q\bm'e9Bթ?8\u000e[F}8_hj󎞤\u0019fExkxi\n\u001dx<ZF^me;Z\u0001SK\u001a\u0013 M* LC6\u0016\u001dRu9iz\u0017-1\f7P\u000f#OXf2%/Qg.K\u0015)%\u0013|bg?F\u0002l\u0016<*6c8ߗh\u0010B\u0002h\u000f\u0004V9Cw\u001f+>S5h.o\u0012\b%<;/\u0011\b?<N\u0017r%\u001c=Ehe\u0007\t\rG%{6N\u0002(ʳVN^T.^Ri-4\u000faP\u0001\u0016\u0012A R\r\u0016hv$X~i]۶\u0012\u001fፄB\u0015Ǻ\u001b`\u0013o\u0004~|$~U\u00006$vS\b\u0000.q@\b%ܱgN\bo2H@!N\b`/!B\u001f_\u0004[~ 0$\u0018N0\u001aOpΫ<m\u001dB^gxs\u0010\f#\"5C\\Bĵ!\u0010hD\u001f͘\u00117E$mD9\u0013\rsL_F\u0014`#]+q\u001fy%\u001ez/z{\u00125Y#o+ќ5\u0018OK&\u0010\u0017\u0013zJ\fS;>\u0016IwAdI)%?bsVⶻڦ;3asZݟ͚՗f%ﺗV8w$o\u0015]nedbW֛YϚTN޶oŗ\\Z\u001aܱZ[\u001f-\u0012yXU\u0005\u0006\u001dڦm,\u0002۬ՙdc6Wa\u000bTbZs2>۝ۮ.m7'[>_dVlm\u0007}\u001dl\u001e\u001dZmrwf\u001b~TmtⰍ+O\u0019[Kw˟:O;yYsD\u001e~yG\u000bSLQ.{\u0007w\u0006gF0e{7b{\u0015>7ǧlA\\.AMs6\u000e\u0005}w\u0017q\u0019u$#+\\{\u001cU!xhY\u0017MGg\u0018|׷cu\u0012.t\u0006\u000fΠwd\u00053R7_q9\u001a;\u001fkC_c=;ǩFй\fx\u001a.\u0011p\u0005ˇ\u0017W0a]U~\\/Y~޹[}u-F715\u000en>G\\6w \u0015ݏ\u0007i y\"Qz\\a\u0013J\u001eXzbyГK=hi\rۄ(x\u0000#r^G\r:m^rțcCs&Î}|}8y]=_|S?]sZ\u000e\u0018-\u0015_m\t?_\u0005&</6]f7&\u001a\u0001q\u0014\b8\u0010\t\u0003F>\tԹ\u0017&Ҹ\u000b\f\u0012wA\t|N\u0001JPw7=-r'd3W@\u000b\u0003\u001b\u0017J.sP)`BO|'\u0004ȅʝ\u001evǯHf\u001b1!󋲍\u001ad1\u001cn0)\u0013OKQ@S=*9ƹrv}i壣\u000f]HvZt\u001b҃aU6\u0017IU\fzޘ$VcB\"ϴ\u001b!F8\"c\u0004'olk_Ö}\u0019\u000b.\u0010\\6tpP\u0003\u001f$\nכ\"3PT_ޏ\u000b兰g,)4z\u001e\t+\u0007ho+5ī\\n*\u0016\tV|^ދ_ﰭtCa\u001cN8C*6\u0003W\u0010d\u0004ȬX6\u001a~Zx8.텟%f.S)1.^\u000e\u001ayK6HI~]?W]sv\u001dQs}_icla\u0016N6t\u0007\u001f~M@ 9EgXiZ,Ǻ\u0019*6v7R6t\u0013\u0017\u0018M n\u0006iGq\u0015O\u000fZ\u001fG=~\r=N\u001f%:-1}`\u0005L2N\u0017bO\u001c</\u0005v3U!g+\u0010t텈=\\>Ùᨖ\u0016,\u0011\\gz\u0001Je|Y\f\u0017Ty65?ܯX=s?y\u001d%}\u000em|\u000f\u0005wy^~\u000ba7\fkQtVNX\u001cŪ+-~֟<\u0014Q~%w/;qI8~op߫T)x,:$]z.U?meY~]t\u0016\u000fD} f&ևR8\u001e}\u000eJ\u0016*u1\u0014YfC^SL\u001f\tQ|]=#WZ\u0010=Uo\u001ejQ\\S]ݙnx\u0012Uh?k'amޣ&k7K>ectoB+ծZgZ|\"_Ob\u001f<=g}}.0\u001fA\u0017}\\7viq/#vZlO\u001e\u000em\u0012\u0012`~uSk{˷\u001au\u0017ҍ\u001bݧr-?.+r>{3o\u0017\u0017u_SI;\u001f߃>9\u001b֟=C6OrSb3{\\o\u000ffn?JUh>!>g9[\u0019f_\u0016y\u001a\u0017A{q{=\n;\u0006z*.UAi-᯵\u001bvL~r]㴋z\u0019C/\u0004\u0017|iL>{ѫ)Mlrm:\u0011yO|rۮuF0&خ^Bvq\u0015\u0005,[\\kj|)9Oki6^ߩ؝/mjȦ8ٸ{\u0003=\u000fe%\u0001dW\u001a{iJ^\neͽ\u0007]%QfirYZg*kq~\u001fW\\E&'K5'(a\u0015]h|\u000f\u0002cPg\u0017 2AYf\u00116ޥQRoZoݘ/IJ\u000e'x\u001b\fR~Ր/w\u001dL*ʊ\u000f8\u0005gʟh|QM\u0010\u0019\u0005|\u0005>Cټx|/.\"z\u000fgG9[庛z'[[w]?\t\u000f&\u0002!W\u0005._tt\u0005\u0006S~w0 *k\u0000yG\u001b爤灝;\u0018\\jJoQ&!2\">-\u001c}K^Ic\u0006E/o\nyT]5\u0013[O^S_)o\\\u0018Ұbh2_$\u001b\u0017߈\\>\n1Rh8gV\r`N])\u0015TMc\\\u0007fȁZ8.ˏX ClUB\u0001]w+f\u001dM\u001fRc4\u0016˳v{\u0013d\u0017\u0012-0PvRv\u0000c\u0016\u0002\u001b睒@;SY\u000fh\u000b=m-+yn@\u001f]H9\u0005wgtr`{1N{lIfH&Pkfۅ^\u000b(yl@a]`y\\YSM\u001bh6p\u0005Z@a]^\nlR*s\u0019`@rU[6G@=k\u001a|f>\u0000N,\u001dR\\etr?%B\u000fhwq:Z@-\u000emϏ]<mF\u000fh<&@Kp0P|/\u0007;[Q\u000e;\u0002껺͔O\u0016P$a3)\\5\u0011l\u001d}A\u000b(|u:J,\u0006\nfzlkHf\u001flOګz \u001dP\n@\nܕ}]\u0015poɍrjEkeQ\u0000}0zwf\u001b\tl\"j\u0001%C\f\u0014IK\u0005X\fTKwzz@;dT\u0006Zp=\u0015L\u0005\u0014`;FК+\u0006Z̲\u0005V\u00073K>V=:@j1\ff\\K\u0017>\u0007w\\Q\u0015P\"-]u7q\u001f\u0004\bԝ@\u001bqM\u000f\u0017\u0006ɯ=75{;]ȏ+\u0002H`_bd\u0013g|֩\u0017Ļ&7\u0005jmu!#k fLyvDU\u001fF2iI+\u0017\u0003]\u0018߫;@aw\u0014\b}\"w91(}U\u0000\\=\u0004.b>(tWi\"W\u00072e\u0010 t\u0010[h\u0001\u0012\u0003]l+\nC\u00044F\u0015\u0002*$\u001eXX\u0003\u0017cN.\b(3:\u0002fj3u\u0005yB,[_[\u000e߾e۝]\u0017\u001aDsL_\r);\u0002Xy|5x;x뿽#~>6\u0007ߖoz8}1N2)龝-zS˶4dr&߿\u0019$o\u001b-bL}3{mܥ]ulSםP-lѨ\u0015(\u001e:^\b(31\u0018U\\꾍8Wݷӗo_g;\u0018#w}O-\bL*NU\u0016\u0018\u00123\u0011\\YIѩj\nn\u0012>Jb-\u001fX\u0007ԈJ&BF6WS1_Q\f\u0010%|ʖoB\u000bW2|\f\u001bt`smw1\u0001l\u000b}]<4HXE!fVu]\u000eH\u0017sd3\u0018\u0017Ţ\u00159->\u0016\u0013.K z\u0002\n\u0012=B\u0002v\u000ePfq K\u0005\u0000z\u0005\n\u0007\u001c\u0005%+\"Kc\r4#\u0007zEx@٪]2Gˀ\u000eN\u0016(X\u0016H߀e\u0014@Oh\u0003e=m}L7ǔ`\u0003\u0014At^u\\Y;;W\u0000\u0005\u0000t\u001e\u0016)\u0010|_\u0003E:)R!d\u001e7o$nn%-\u0017ȉJ\\0vnh8LҮ\u0018y¨\u001d^Q\u001a?ɀ71\u001fa\u0003zVr\u0013 \u00124\u0006B~4\u0012L\u0000VN\u00075\u0000I\t^\u0001윮To'\u0010zds8Sq1^>%h\u000e\u0003\u001a)zxȉ0@l\u001bx<s0\u0014յr\u001b\u0004[o\u000f\u001ar4XM\u0006\u0018Rfn8$\u001bQ~y|.dH\u0005ctU\u001f/hPP{~ϾsY\u000fb\u0005\u001166z<$Z+H\u000eCO\f0|י)bP<wPʺ\f\u001c\u0015e\u0018Sbuv\u001e!ߓ5%\u001f,IDJѓފ5oj3\u0005\u00027\u0003V \u0010~9蔔]ܥ5}+z4K\u0017;\u0006w\u0001+;iL\u0014\u0005&WJ8\u0005ZS=SE\u001e\f&ǉyh;\u0010l\u001b\u001e3U\\\u0006_R\u0001Մ9'\r\u001b*܉TV.w;em\u001d\u0018\u0015ZP\tlBKN\u001d\u0012OΖLw]k֧仌z:-G/.e\f'#\nXQ2\fպA\u001d҂ʼ;ّuo\u0016\u0019Yh\u0012lzGN29]ou-\fD\u0014\u0015Kݧ)D'k\n\u001fh>RwF[!(\u001ab\u0017\u001b\u000b0Rk[\u0002(\u001aU]dy\\LsPC^y\u0019!!Nw,U6\u0002`X۫˚#Oyb%!\u001e8\u001b1%\u0007[w\u00162\u001esb:\u001fsb9\rcmyEh]#G\u000e\\ݴUb1\u001dӉ@Srh)zrl\u0011#L+\\SZp\"f?P籚4h.\u001c`\u0007Ʃ\u001a>f\u001dr}4\u0015*syɦ\u00060vw(\u001a\u0003øh0\u0014ny@d:c\u001bv\u0016îk\u0013t\u00154V=ܩ\u0019sR6ca\u0016%\u001dFӭ\u00015M5\u0010\bsitx-{XH\u0002`c\u0014\u0000+ٖ\u0004\u000e^\u001f\u0013?Ir\u0012\u0001{wd5Pɣ\fw_\u0000M\u000eغ\u0015זbM\u0010$L61\u0000+bT~bq\u001e.\u001bi{KCW\u0011\u0004\u001equGcq\u001cbT.YmGKVK\u001aqSc۩)R5\u0010lEET~4)PQi^:CO\u001e\u001fX\u001c{\u0010\u001eq?\u0018k\u000e\u00031h\u0002AJvUi\u0001aLL\u0005J3϶_\u0013մ`p&w\u001bTx\u0014c\u0007\t&;2-=,k0\u0014\u0007efVFt^{\u001b\u001d5!'\u0000,\u000e}\u000f',\u0013<F;F\u0000\u0000Zx\u0004b벅NmftYtXx\u0019r4!!;\"d~K\u0003\u001a>\u001d*27/&2Y=BjMO\u001fI\u0017t?&9Pul'\u0015}o3rη,\u0019|6}-y*}\u0013=\u000b\u001asQBn\u0010}\u000f6B\u0019.*c-Tj\\\u00015hɮDg\u001a\u0012mCc\u0007h\u00127ԧx\u0012M:\u0013TqDKc\u00182#E8YSjNh[އu;DCJ4-\u001a\u0012m)9]^\u0012m㷔\u001f<lqu\u0001\u0019Y7L*ͺ\u0003X1W\u00143z\u001dE\u0000\u000bG2=\\@]KuY\u0019cV̬m9odJ8G?Jn/\u0016\u001c\u0018\u00022F;Hvk;;̑SƏw×\u0010\u001dlUk[|HN F=\u0016p4nصelCU\u000b\u000fP?F\rendstream\rendobj\r179 0 obj\r<</Length 12334>>stream\r\n]\f9A\u000b\rcLBS\u001e9\u001b6L{\u0013\rfÑt­:3\rqX&t&r\u0014'ɑeH=E\u00125-o[\u001c&\u001b:4-*@g#}/!bbp\u0015\u000e2._gtM\t1Cu}@d\u001e+aP\u0006*~US-m\tCE&#rb.Ion\u0004e.ɧK,3FBgǝh+F\u0015DPt\u0010ZL\u0005tT\f\u0014O@\u001a`\u0015\u0014}\\\u001a.Ex%1-B\u0014\u0005mB-'?\u000bLjq܄\u0016bzֹ~=%8Nu{9t\u0019t\t9t\u0019t8\f9t\u0019tls3,\u0019gd\u000b\u001eCgA\u0007,9t\u0019tق\u0019g)\bNȡ3ΠS$>\u001dC\u001c:U@~Ư^^\ndUCRb{\u0007\u001eR8Ȧ\u0010T' Zv\u0013\fݏ'\u001d6KS8L'3qYwC`4c\u0019)/\u000eK\u00119|J\u001d\u0001HW\rI+Oy2b\u001a{<WrHҜڬI;Ѷ:IP_'\u0012\u001aٵf[\u0001ٜe\u00182Jgj\u0016A zn{\u000e-&yMxzQɮjG\u0019E)\u001b\u001362\u0004˻`\u0015JD7&7%\u001e2*WCbC2bjٛdڣ$Sv\u00012\b\f08S\u001e2F&y\tUS-قi]7Oyu\u0015 uHMSF:b\u000fH.DC\u000eitSz0fس~ȃin?\u0007Y\u0018I<3[\u0010tҊOF\u0019߂pȸОr6\u0019f\u001c11hMR]DpL\"{&\u001c8j\"*K\u00182N\u0017T\u001dh-bwȻ(7)gtN4Sѣ>M0rg^\u0007Q\u0004\u0006+\u0016'\u0006ON\u0006yJFP~ߏ\u000eS&)*Knw&\u0003^zY-\"\rsz~>=cK{ҏ)Ύ\u0002}Ν\u000f\u000b=dA\u001ck/xZ\\i9fq\u001c9.38hPyd6CRxzW:#c0$*'ɔGFJRzd\u0018{x\u0014Rzd\u0007yd67Nk|YOu[e\u001195\nNs\u000b\u00139\b:rj[7G\u0006i:\u001e\u000eO)GFN<GF}\u000eJα8]9\u0007%砹D\u000bu\u001ej\u0013McFY\u0006]vzNbl$,Jj\u0016N7l#G\u001eܧaI\n<\u0010B\u0017vS\u001e9t0Q^NЬv7]+\t!T\nX\f\u001b\u0014%\f[wkVgl>ܞΔ\u000f'%3Ν\u000fw8\u001d\u000f\u00152Λ\u000fwJ|8!\u001cpJi٩p[5Lj\u001c\u000f\u0013\u0003|]K|oH\u0011p3M\u001d$w+>6_섘Hn\u0015\u0013Yۚѧ~}bV7\u00051;RP*\u0019x\u00058\u0003b\u0013r\u000bQ޻Hqr\tUi\u001d\u001eܚ!<S2V\u001496<$Ai~td\u0015r.6k&\u001f#|\u001fiF+`\u0017Ά\u0017\u0015\u0013\u001ecJ\u001c\bɅ9\u000b~?9^LU&\n\u0003KJ`UܣJ\u001cH};KF*esTʪ\u001bOHY#(#k\u001dH1V\u0017\u001agHm)#qY2R\u001bZ@,>\u0013k\u0005S]\u0003\bX\b2P5(\u0017f=o*4.vT#>\"\u0015nSRsa~T8MpZ^I{R5ܟ\ngN1^\"[}؍H's#m\u0006YbG^.ٙ\nO5tYtdP0udB\u0012=w\u0002^\u0013,Fo\u0019nzm\u000ehH2PFD\u001c\u0012^T3NW+ U\u001fD`J4\u00113\u001d\"\u000fQ9$\"ߏ\r\u0007?UI?fؾYNjO3+=s1s\"CґvٕiT..\u00180Ȱ]\u001f\u000f:@y6yKv{2Ȱ[3F\u0019vU]N*\u0003:Pfة\u0012U\u0019PUs\u0015\u0004w3Su\u001di\u0002\u0005\u0004_gؑ0y\u0003\u0014\u001d3\f9\u000f4o\u001bOz|A#E.Py-JΕi\u0007\u001e\u0015:\fO$\u00060[v=NYێ\\^t\u0012W#\u001c~$۝Ԕ\u001a\u0019sjߵ^\u001d+#\u001fE\u001e|@̕~jR\u0005\u001bsuJrZگ,L\u001au¥̇H\u001aàh^]K#ϸي\u0006Ooq){+O+>\u0019\u0015k35`~H!9H7\u0011Ji_.Qшh\u001c3fөG'av쀵eql:-\u0016Y\\\u001a7OM\u0015\u0000Q<=N+Nﮛ{Oɦ:\u0010l:\\:\u0018ci$9f^yl:\u00196bTl:\\:Vsgi?W6V.itZtX5Nk05ntl:tOxΦjMCΆ:!\u0018;.N\u0007cgΦʥ3ce:NK.ZΞMKg[l:sfi~ɬ3euLtZ+`ϖMgҮ<1tZ\\nx\u0007R\u001dBk=Y\u0019QI罠\u0000=&]+\t\u001e\u0013\u0007\b\u001cħ:qvvqD:-H8^v^Y<t$;K2&\t֯l?M)\fi#\nG!afYfѠi\u0000{00(oHEŤLEtP[D(jy97ieV\u00183.twJYnO\u0011=\u001fXNZݑI[\u0016>>>2w\u0006Bw')IeN(*sg1\u0015rjM,7N\u000eop\u00041D\u001e`\u0007Y0`\"Urk\u0015tC\u000f VD:}T5kg|G\u00163\u0001'+\u001bvxP\u0010\u0019Q\u0001\u0015\u0013u_]*CY1\u000e\u0007pA3FCAg犆*2N辚\ri\"srro\u0012gsx'C:G{~GFU'c:.UД4Xg\u0015\u0010:3ob1qhR.%*\u00152pҦ\fIDUr(4b|g=.3\u0005=s\u0017uTiYs\u0015\f#0VU\u001e\u001fx:\u001fY;.\f\u0004~\u000eLdЊh\u0017:\"\u001bT׀ؗʰ\rw*P&^r~1Ɇ*ܙ˯<:\u0014\u001c\\Xm\nwǳ\u0017[}~\u0013wZ>ѶR>\u001b^NS`m\u0011짊1ɱ\u0012k\u001bXQ\rcl痿Se>\u0006ΐX\u000bhy\u000e9؃\u001b9=\u0016z1\u0017vT.O z\u0015Z#ELcz!<ײ8L!Yк$&.\u0016q6D\u0012L.G_<;o[L\u001a3Snj]\u0012cyJXz\u0000RGp5\u000fJbZA1\u001c\u0017ˬ$\u0017h\u0002\u001cWEG)Jyqmien-Cs\\\u0013͑qЬf.9ꨍZs\u0005-Lhf&tVѕ̖{4\u0001U;KuF9r\\\n;\n-5cHVz$JT\"K\n'顴*\u001d<\u00128>W}W\f5Gj㹞[{S([p\u0017\u0013!ROe;}2ot:l2[Դ\u0017s.P2KZ@-\u000eݘ|K\u0018\u0000\u0012>lv֒yix?~f\u000f'>Td@7i1xSK>7\rT/\tO?\u000fA*v1u_;p\u001cP\u0007\u0005\u0014gc\u0004\u0011H?6]ċ׏2suV\u0015f\u0000ǟ)ˁv\u0016\\,نfz\t\u0013fבC?(yG\\.VmFS۩*\u001aղWu\u001e;=!\u001fjUV[1f}%6\u001d\u0014ZƝ{\u0002Lz\u0000Oe\u00004HHC<n0vXhA\u0002o_V\u0001t7\u001e\u0013ib~\u001c+\u0018Tpk\u000fI\u0011񡺱0\u00178iƪU?ީg1#|郜[Ƶ:[KٵV\u00136랩\u0019ec?OOkk_Rf\u000ewV,ˤ,.Us]وDiia̖Tܽ+.\n<6%aL6r<,b??Jӏ;\u0011Ѻ\n_^]΄Ny\r \u0018dn]PfUzM\u0011!\u000b>V{+O$۽#]M~ևg65\u0013ڸrP\ny'\u00150\u0011о?t*xO\u000e7n*S'Q\u000413>eeR\u00147\u000eTbt2}\u0018\u001c='Lr%΃H:YfY/Gg\u0001\u00014u^\u0017+m#\u001f\u0005x?,\r=9\nf\u0001\u00018N\u00024\u0003h9)\u000b,>|t\u0016\u001c@|X\u0016{f\u0005\u001aL\u0014SW\u0001w))yOE\u0014ſVO\u000bw|꼟(\u001f=Pg/ʧ;kQ>͜\u0017;KʽET\u001b\r@wFn\u0019W;C&_PN\fwC3\nc\u0019W;n(~2C\u0019W3CɦB\u0016\ri|D]S3\u0011:S\"^UW;oyB]?嚛pp]#T맕?\u0016к~(<u7:˞5uLd:Kl]i옺~ZyW3e=SKٮ񝣮qĺ~anڷ\u001c^Rۍ>6G{5W\u0018ۓ\u0019\u0007\\[v̔\u001dv\u0007uU?]~~i>YFI\u0018q@=3Ա\u001aXoۋֱJ:qU?Og+8SOإ~\u0019C\u00073>o֔cG;$~\bݪ~;Q=\u0013P\u000bb\u0013oo3m\u0017cD]n9A0'oi&ȭW.i~j\u000e<C]?~Ƿ/\u000bl=ӼYz|[{P̕F]?s#\u0019'KN맳sɱC\u0019WTl^\u0019W;oĘH\u0013i<$\u001e[OsH\u001b{mf*~\u0007XX(8t[8!V\u001d]O+\u0017m>6(\u001ePov9\u0019\u001f.9߆?5[\u001eZψ\"dQâW\u0010'ه~Vĸ\u000fTvI\rk ^[*\u0013\u00173(܇Q=R61Ē`^E\u000bʓ-FU(}ˉ\u0001¹L7\u0012\r\u0002U&lvM'vM8\u0002K\"dN\u000f\u0004\u001d.\"\t_zkO\u00172d&!3v\u0015($S΃dőX}\u0006d5$EꏬOv\u0011viT ۋ`|\r7oA]u<(>m~68ogyn&ރLQ\\2;?&(\"j\t\u0007-aVzǳPIjD>\u0001c>\\\ry&\u0011p/Pt~Ò2(-@̾!G뮂}\rgz~}P,q\u0015AU \u0002\u00160:`N`<Seߒ(yldȬmR\u0000gn2RYϣ:\u0014(RNb:\u001d_&MK\\e!S\u0018V/Z3KT\u001b)5;е\u0014<sJj@AhZ/f\u0018\rn+Fī\u0015\u0014BeƝ\u0005\u000b%y.\u0000O8qؑ\u0001\u0016,(2G_C+I\\O:C4A TV'~ad0\u00067?\ff\u000e慉էW7D(Τ;4g;L\u0017ݛ\"1C|\u0019E@#\f7/ڰ|J\u0016-XSrw&Ul/{ѵ'/n(9\u000b{!dy@~/EBQX<b1>|\b1\u000f\u0012]\b$k\n5\tH\u001fEyVxnQ\rAlϕ-f=\u0001\u0016ŗ=\u0010C{b7\b%\u0013{\\T\u0012?\u000fo/\nDu+6ٞIjP%%hO.su\u001eW=\u00147%\u0000ʢl\u001ffOG\u0006e<RU}\u0003esZVYS#+x*&lH\u0011\bS\u000fIto#dqɽ\u0001}V\u0006&\u0006&\u0013J]/<|ZϠ%y\u0013DW~;_<1\u0017=\u001f[剗E:ssIr\u001b[-Mhgm[SBHmßV\u0003\u001dʶ'ZEصn\u0018CJ|'IEdhˑ^G\u0014\u001adWWoH<\u0013ۺtK7&\"\t¶W\t-)_cU&4]>K:\t+d;oUlFZS\u0012\u00187\".+y!\u0018/f)\u001eh&?DAcLZn\u0004\u001c|\u0015fd8\u001bCװp\u0017\u001e,\u001bYNn\u00028\u001c)><ϰ\u0007\bW^<k)輲s^}>C*DOC\u0006$Ō:_MH\u0010 \u0016JG?\u001f8C\u0005췟kr`ڐDXh\rҩ\u000f\u000f\u001a㋌B~H\u001a\u00079\rp\nlDb*\u001a!,5Ar3RIx[;\u001cTe[?(q@Z\n=\u000f4*g_,4OXjR\u0017.Xo61N\u001e9UiLW\u0001:(\u000e!THQ]U\u0017}N\u0017\u000b*R\u001b\u0018$\u000bjP\u000b\u00118\u00152\u001cGX]?!UzښJc߆\u000b\u0017_Ys\u0003<o\u0005\u0014^4%j\tz]\tъ'X߄\u0017T\u0010\u000f\u0014c?\nMHk\b\u0006zIm;r/ݑкS\u001aY\u0007\u001b5I(-ݜ0K16׍\u00009Yi4r+b\u0014HeG\u0004a'9\u0012`4re$N(ad(p\\\u0011ok\u0014!\u0002|\u000f\u0013\u0004#C$bx\u0002C\u0006\u0005\u0012խ\u001a%1\u0004\\\u0002آ`N]:PDBJy\u0013\u0006\tv][#!\u0018Х\u0003zXPrEAJF]G\u001dZ0?ۯ\u0001>E2\u00188RNY\rxi\u001aeCZ4M\u000ef\u0017&QAHKit]0?(b$\n\n]]̭\\·v<cd?Ϫ]ڶs7\u0005I@cR4i4VdAah>ȱǬìD]L#A\u0011!@\u001aĮ\u0018c06-VN\u0017\u0000\u00053%)\bN#\u0011š\u0002'M#\u0017Ȩ9CiM\u001d>\u0006CEBY4Dmȱ`JA\u0003`G6އw\u0018\u0015{S4ۅi\u0012xC\u0000'Oc~6&+ȿ>\u0016 ǖ,(&-gS1k\u0013l\u0011k,U\u001c\u0000\u0015h+\u0018<gS<ݏZy-d;Ng]Y\u001cd\u001atLrgڶ`L\u0003c\u001bIn\t\u0018ر\u000e~\br\u001cE|\u001b?Ea+$%[nLX\u0013ttըƬ\u001b\u00117.\u0018C\n]P\u0002\u001e<?\u0015&AF\u001bE!\u0012W~\u001cN\u0006Duu\u001bj.R|ܗ?N|!V#v\fث?E\r;ѺD\u0005FA\u000bcxv=Zo,\u0019@#sЅ|VH4X&K\u0003\u0004F<R\u0004\u001d-HI>}0NDT\u001cMeW\u0002\u0012\r\u0015P$ǰ\u0002[\u0002\n8?Ll!a\u0007\u0016A\u0010\u000bA\f3\u0017g8+;>\u0017~˥%\u0014x0̆/Rw8^\\D.BjVRd0\tܛ sI]\u001d#\u0003g\u0014˒HrM5}Cϰ٣#e\u0007ә*kKa\u0001۵\u0013\u0019*\u001cJ`g<%f\u0007bq\u000f䮉@UAWcH\u0015Ȫkf=C\u001d\"X\u0007oȝXO2\u00196S2lg+M>9\u000f\u0006mTN7nSq\u001cԛ/k\u0010=\u001fr~o\t\u000eȧ|#elYxC[A\f\u0004ȿթΆ=W\u0005]O\u001b\r\u001d\u0010\u0014ٱ\u0011\"K\u001aS)\u00192%\u001ffB\u001b^'{u)s I4v\"!{1M~l^#Cнr\u0007\u0006mΎ\u0017\u001fFC\u0007CP!\u0003\u0016\u0018\u0018P:1Z+\u0012\n_S$j\u0004ؿHl\b)hQ$j)\u0012[5\u0002_/)\u0012\u0014\u001aQ\u0005Eb;\u001a}{ľI\u0011\u0017\u000eٷ\u0002,C\u0011JZ}{ĮX3\u001fo-\u000f%-\u00074ě\t<\u0004$u]\u0010\nHdܓ+\u0017?-MR\u0005\u0007\u000b\"1NyL)&Ý!zMm\"9\t\u0016B&C߾\t+9r!ű6C'\u001c\u000fCo\\<Vup\u000f\u001d|\u0015zӛ\u0001M~DU\u0007d֊\u0000|39@8*\n5\u0000BQBXx·>\u00057Bg.\u001fR\r`G\bt\u0007T&Yy,\u0016a|\u001bkT\u000fCOh\u0014Nd\\`l+CQ\u0010ꯐI>\r:k$\u0004\u0015=ؿ\r\u00128GP-nk\u0019U\u0000\u0000&@ݔwSa\u001eE6rj<\u0016r1X\u001c\u0007KVA\u0002'2ϥ*Rb1Q~\u001eNӊ`hU-̢<k\u0005|]).\"(\u0010ǠurE<hn sw\u001cTeC-+ҽ\u001bXu|2\r\u0017\u0004UA\u0007?4V\u001fLc)\u0017:ʹ:(0d4cQh곫a)c%\u00194\u001aOMߒ\u0014\u0000g8щ\u001a/7ANc\r-ΐx_o\u0014Kicxe\u0005V]z͎\u001aEo\u000f\u0013{)#)4h~\u001e\u001aC?5kFt[\u0012}UiL\u0005th(`\u0012F\u000b\n\u0004~\u0015\u0013H\u0004\u0012-agxiq\u0013IC\u000f;\u000609p#\u0017\u00118 ݉\\_\u0000+\u0015+Fׯִ܇\u0015-23[yR-59de\u001d9l0hŉ-95%\u0012$|`.QExA9CM3m`k#/+\u001b\\\fF\u0000\tlQv\u0000}mJ2qp噴\u0007=+r\u0016O~b*\u0005WPȈÎ=gJ\u001f&\rw\u001c\rԙhgk*!\u001ekGv\u001dIk˷P\u001f\u0006N\u0013^0\u0012z͍:/+n\u000f^Erͣj>\u001eSZ^\u0013*#ѵOL\u000eyZ\b\fZ-m:+\u001fՂ\u0002\u0014\nVMt\u0017㺀|ԥ7Aű~n<f.=&VˠK\u0012\u0005\u0014HWU\\o\u0015ۇe=ҟ\r@۫\u0000Wrj\\<\u000b\u0011\u001dJ/yI6\u0007ss~s?w⸹5xIp6\u0007A:d_\u000e'l3z\tq)8ұ\u0003{\u0007W׳\u001e\u001f<;ɇ\u0007\u000f\u000eb?́A\u0003`K\u0014\u001e\u000fǘ\u0016\u0003T\u00145^\u0013Ïq?Ù#?W\b_PxAs\u001c|bm/(Eq\f-P|H}\u0017_qw?\u0017\u0011yWݦ.\"\u0017\u000f^\u0007\u0017n\u0018\u0012\n\u0007\u001d0_-E\u001clDn\b|\f\u001fg:\\Pg214E1,O\"%Р\u0002\n]\u0004X\u0014<\t\u001c-\b_tX\fafn_\"'\u0017H]I\u001d͇y7mt1?l\u0018(N>&\u0006\u001d!\u001aco,+M\u0010\u0016`5=-̑Ay`\" RPepW\u0005`\u001e~q!\u001dXj3a2|\\4\u001b&\u0010I\u0003\b,\u0015\u0019jH\u0000\u0013Fx\u0007LX`i`\"\u0017x8H\u0000DnNE\u001a>\f|ڋȋİ{ \"71H\u0005Bȋ\u0014d!\u0002GdX$E\rd\fB\u0017ibYOH\u001a,@\u0019,IgI:̅E%|\u0001v-<|Gȋ6y1@]43bgH\"@\fP.#\\K1\n\u0014\u000fTȐ\u0002Em_\u001f/\u00174\u00069NM(\u0013\t#\u0004q\u0013\nƫl\u0012f\u0010\b:\u001c\f\u0003sl-F<jD\u0007YV.䃁eFP|Ez5\u0018B>\u0019\u000em PLpG|ʉ\u00122pA\u0003{2\u0002\u0003t&\u001c\u0019\u0004\u0019d\u000fGD`\\D\u0000ɚq\u001b6,%lo.}˻6i \u0005\u0013\u000f3Pu1\u001a\\\u0013x\u001fdle袦2\u0005.\b\u0018\u0010\u001c\t$ab0PxXQ\u0011\u0005tP\u0000\"\f\u0003HZ\u00148bPHhF\u0010x:(\u0002e!ì\tH8hqA\u0011&6Y#񌅠ZU?\u0002\u001dFM\u0000\u0018ڎf;+vm\u0013<+\u0000\u000bA%h&EU\u001b\u000b<͒a\u0001P\u001c\u001c\f\u0013y\u0013XL^9)\u0004A6bx\u0019eY\u0019\fV\\\u000ex4_ \n\u0003b\u000b\u0000\u0007iV\u0018D\u0014F\u00031\u0014\u000b#M# CR\u0002\b\u00019h \u0014K+h\nEf\u0010Hʳ\u001c\u0016}F\u0002_0$p(aa\u0001r0\u0002|Q4\u0001M\u0016Y#\u00163\u001c\u0006jM#hXGD\u0011f<\u000bшY!h&@\u0007ҷȁq\nF\u001892\f\u000b4\u001c\u000bu&x>(P[\\D|\\X\r-p\u0002\u0010gbIu#\u0011P\"\tE8\u00158PP\u0013\u001e!K\u0004&\u0014\t\u001b\u0004!Oֆ\u0001c%d\u0019mcA)7 \u001dlN\f,\t\u0013@A\u001a\u0019\u0004{\u001blĲ\u001c\u0001F)ظ)LXT\u000e\u0006\u0018>h\u0017ٜp\u0013\u0004jۈ\rcA!\u001f\r\t\u0012hԹhb;^@4h\u0011_az5oP\u0015&xPY\u0000)0b\u0006Ige#\u0013\u0015\u0000#R\u0012b6#\u0006]ODp/$\u001fDI_NH\u0001\u0018\u0001]zB>\u0018@1/\u001c`d@S\"l^)\u000bA0j\u0004Z\u0005\f\"\u0003b\u001cE\u0006\u0003K\"(&\u00144Az\u0011#\b*FA\u000eT]X3\u0011\u0005KCw\tWʂ&\u0001Q/0$EUy \bs$a\u0012x\u0005y\"\u001d\u0011\"O\u0000QɃ\u0004\u000b|#&\fXL##1!M\tO\u0002\u0002DM`\u001caIȳX\u0012\"\u0000+\u0005\u001a1\u0018K\"\u000bD\u0012/@\fH\u0006phE\u001bI\u0018h\u0006\u0000\u0015F²\u0003\u00114\"%b0\u0016o\u0014V\u0004\u00143Xl,\u000fˆU\u0007\u0005)\\0< \u0013Ѷ\u0007\u0004Cms\u000bh\n\u000f\ni\u0002dXq\u0002\f',Jm\u0000\u0010\"<Uc4\"!\u0012\u0002\\\u001a\u0004\u000eJ\u001ex\u0017\u0001 \u0013$BI\u001e1a8\u0007 <ToPe%\u0014\u000e\u0000Z\f2)\"[\u0018 \u0007Ja\u00023\u0006\u001c.r.LW\u001d-\u001e\t\r: P\u0005&\u0002GI0A$P)ȁax\u0001lAiF\u0014##Q%+-!\u0006t*J \t\\X>@ \u0006\u00056c\u00130\t\u001ek9Z\u001b\u001e\u001eإEv\u0000\u0011\th$\"\u0019\u0006\u0000(n\b\r\u0005\b\u001f5C\u001e\u0003TO\txFh(A\u0006a5\f\t\u0006\f`X\fR\u0012`\u0004\u001dȊ\u0011{#>Hq\u00020\u0005\u0007-C@\u001b\u0015Hi|h\u001d3E\u0002\td\u001ab\u0012&W\u0002A\bUh;\u000f֟2؆\u0019IVJb \u0019\u0013A\u000bЅ8$\u0014\u0005p\n\u0010!\u0017pN#Ah\u0001\u0012_\u0013\u0011%fA\u0004ڈRA\u0012vӉDE@#f\r0i\u0016\u0001\t6\n\b\u0010bb\u0000\u000b\u0011\u0005\t \u0003d7{E#ZDz\u0000$\r\u0000y\u0004\u0002\u0007\u00139JCZ-\u0005'\u0005sFå)\t\u0001\u0005XaB\u0001\u0007\u0011\u0003s\u0003+\u0011\u001e\u00023\u0003?\u0002\u000bb\u000fH\u001a7AD冎9E\u0013\u0011W\bNj\u0004@m\u001b\"%\u0002v\u0001}\b\" \u0003y4WN\u0005\u0011U<\u001a\u0011@4v]\u0001?\u001aaINK\u0015P0\n?4\r\u0002 @N\u0001b\u0004\u001b\u0011\r\u0003kIQp\u0000m\u0006֔pd+\u0001\u0000c(\u000eRΒ\"\u0002\n#\u000f\u0005\n,\u0018\u0005H'\u0004#\bd\u0010F*V\u0005\u001e\f0 sK\u0013\fZ@U\u0013\u0004\u000b{\r\u0010aV8\u0017Jm$\u0002q!\u0004\u0001LKl\u0007I\u0019\u00160\u0014\u001c=EoHdoT\u0018\u0018\u0017R\u001a\u0000!\u00067+\u0005ksH_^a\u0018WqsH$mX\u0017D\"I+\u0005]\u0000EA#\u0011\u0001\u001fO\u0018\u00114\u0016\u0001\u0002@y$`#\u001d\bf~\"*$A\u000b\fĬ R7\u0012>\u0006\u0003P$lَF~`ݎf@:\f܃E|j\u0001[\u0001MH@\f\u0006\u0012\u001b\u001d\u0005\u0007}\u0017į\u0005\u0016`\u0016XQQ\u0011\u0001\u0001\u0016F;̴\u0000ݵ;\u001c\\|̺/\t?RG\u0013\u001f\u0016\fw\u000fRr\"I\u0019r+^h\u0001T\u001b\u0016\u0010FG\u000104`b4r}%\u001a=%f\u0005Tʀ\u0001Y[=@MH\b iPH: Q\u000f-ږIjumZP)yZR4:\u0002\u0007@4i@FbO\u0001ų:#H\u0014IЅY\u0001$VGxj4\b(0\u0007\ts`A\u001c\r4Aj&̉Ʈ.~hcAeA&:\u0011,CU>8Ё8A\u0001u\u001c\u0002\u0010\u0015\"y-2J\"#a\u0005]\u0002\ru\u001dDB(J->_He_t\u001f$T\u001b(A_5~vH$\u001d\u000f~{`3Iw;@\r 8Y\u0007\u0002\u001fD\u00187ӿNNfL-uoi;`uΤmk<\tޡt%Rgpqi\t6^jZ\u0001Ѻ\u001d1B2\u0018\u001bZ]n񹐚S\u0017dϤ?й*\u0017<d\u0002\u0007fE\u0016 u\u000efZrKYwv\u0005\u000fHϜqԔB[\u001dް\u000b\u0011\u0019%\u001f7!A\u0007LŁ<\u0007Ƃ#yv58==bb\u0013|z\u001f\b\u0000rc8\u0002cEw<F\u001bN\rh b2\u001b^?'AO'\u000eG?Wh\rendstream\rendobj\r143 0 obj\r[/ICCBased 148 0 R]\rendobj\r5 0 obj\r<</Intent 20 0 R/Name(Layer 1)/Type/OCG/Usage 21 0 R>>\rendobj\r31 0 obj\r<</Intent 59 0 R/Name(Layer 1)/Type/OCG/Usage 60 0 R>>\rendobj\r81 0 obj\r<</Intent 109 0 R/Name(Layer 1)/Type/OCG/Usage 110 0 R>>\rendobj\r109 0 obj\r[/View/Design]\rendobj\r110 0 obj\r<</CreatorInfo<</Creator(Adobe Illustrator 19.0)/Subtype/Artwork>>>>\rendobj\r59 0 obj\r[/View/Design]\rendobj\r60 0 obj\r<</CreatorInfo<</Creator(Adobe Illustrator 19.0)/Subtype/Artwork>>>>\rendobj\r20 0 obj\r[/View/Design]\rendobj\r21 0 obj\r<</CreatorInfo<</Creator(Adobe Illustrator 19.0)/Subtype/Artwork>>>>\rendobj\r132 0 obj\r[131 0 R]\rendobj\r180 0 obj\r<</CreationDate(D:20150720120636-05'00')/Creator(Adobe Illustrator CC 2015 \\(Macintosh\\))/ModDate(D:20150720142046-05'00')/Producer(Adobe PDF library 10.01)/Title(OLA Logo RGB CS6)>>\rendobj\rxref\r0 181\r0000000004 65535 f\r\n0000000016 00000 n\r\n0000000190 00000 n\r\n0000050376 00000 n\r\n0000000006 00000 f\r\n0000525013 00000 n\r\n0000000008 00000 f\r\n0000050427 00000 n\r\n0000000009 00000 f\r\n0000000010 00000 f\r\n0000000011 00000 f\r\n0000000012 00000 f\r\n0000000013 00000 f\r\n0000000014 00000 f\r\n0000000015 00000 f\r\n0000000016 00000 f\r\n0000000017 00000 f\r\n0000000018 00000 f\r\n0000000019 00000 f\r\n0000000022 00000 f\r\n0000525461 00000 n\r\n0000525492 00000 n\r\n0000000023 00000 f\r\n0000000024 00000 f\r\n0000000025 00000 f\r\n0000000026 00000 f\r\n0000000027 00000 f\r\n0000000028 00000 f\r\n0000000029 00000 f\r\n0000000030 00000 f\r\n0000000032 00000 f\r\n0000525083 00000 n\r\n0000000033 00000 f\r\n0000000034 00000 f\r\n0000000035 00000 f\r\n0000000036 00000 f\r\n0000000037 00000 f\r\n0000000038 00000 f\r\n0000000039 00000 f\r\n0000000040 00000 f\r\n0000000041 00000 f\r\n0000000042 00000 f\r\n0000000043 00000 f\r\n0000000044 00000 f\r\n0000000045 00000 f\r\n0000000046 00000 f\r\n0000000047 00000 f\r\n0000000048 00000 f\r\n0000000049 00000 f\r\n0000000050 00000 f\r\n0000000051 00000 f\r\n0000000052 00000 f\r\n0000000053 00000 f\r\n0000000054 00000 f\r\n0000000055 00000 f\r\n0000000056 00000 f\r\n0000000057 00000 f\r\n0000000058 00000 f\r\n0000000061 00000 f\r\n0000525345 00000 n\r\n0000525376 00000 n\r\n0000000062 00000 f\r\n0000000063 00000 f\r\n0000000064 00000 f\r\n0000000065 00000 f\r\n0000000066 00000 f\r\n0000000067 00000 f\r\n0000000068 00000 f\r\n0000000069 00000 f\r\n0000000070 00000 f\r\n0000000071 00000 f\r\n0000000072 00000 f\r\n0000000073 00000 f\r\n0000000074 00000 f\r\n0000000075 00000 f\r\n0000000076 00000 f\r\n0000000077 00000 f\r\n0000000078 00000 f\r\n0000000079 00000 f\r\n0000000080 00000 f\r\n0000000092 00000 f\r\n0000525154 00000 n\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000525227 00000 n\r\n0000525259 00000 n\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000000000 00000 f\r\n0000167008 00000 n\r\n0000525577 00000 n\r\n0000050940 00000 n\r\n0000051967 00000 n\r\n0000168684 00000 n\r\n0000140518 00000 n\r\n0000167200 00000 n\r\n0000167314 00000 n\r\n0000165523 00000 n\r\n0000053607 00000 n\r\n0000077650 00000 n\r\n0000052031 00000 n\r\n0000524976 00000 n\r\n0000053043 00000 n\r\n0000053093 00000 n\r\n0000156991 00000 n\r\n0000140555 00000 n\r\n0000154342 00000 n\r\n0000165669 00000 n\r\n0000165966 00000 n\r\n0000166089 00000 n\r\n0000166211 00000 n\r\n0000166332 00000 n\r\n0000166453 00000 n\r\n0000166574 00000 n\r\n0000166690 00000 n\r\n0000166801 00000 n\r\n0000166907 00000 n\r\n0000167082 00000 n\r\n0000167114 00000 n\r\n0000167431 00000 n\r\n0000167486 00000 n\r\n0000167785 00000 n\r\n0000167863 00000 n\r\n0000168012 00000 n\r\n0000168309 00000 n\r\n0000168384 00000 n\r\n0000168459 00000 n\r\n0000168534 00000 n\r\n0000168609 00000 n\r\n0000168760 00000 n\r\n0000169053 00000 n\r\n0000170576 00000 n\r\n0000184644 00000 n\r\n0000250233 00000 n\r\n0000315822 00000 n\r\n0000381411 00000 n\r\n0000447000 00000 n\r\n0000512589 00000 n\r\n0000525604 00000 n\r\ntrailer\r<</Size 181/Root 1 0 R/Info 180 0 R/ID[<D146E2BA72D74E1D82F78DD53C04E642><E5024EF2D906485989545A1241B9FD52>]>>\rstartxref\r525804\r%%EOF\r"
  },
  {
    "path": "doc/modules/ROOT/assets/source/OLA Logo.ai",
    "content": "%PDF-1.5\r%\r\n1 0 obj\r<</Metadata 2 0 R/OCProperties<</D<</ON[5 0 R]/Order 6 0 R/RBGroups[]>>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>>\rendobj\r2 0 obj\r<</Length 44174/Subtype/XML/Type/Metadata>>stream\r\n<?xpacket begin=\"﻿\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"Adobe XMP Core 5.3-c011 66.145661, 2012/02/06-14:56:27        \">\n   <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n      <rdf:Description rdf:about=\"\"\n            xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n         <dc:format>application/pdf</dc:format>\n         <dc:title>\n            <rdf:Alt>\n               <rdf:li xml:lang=\"x-default\">OLA Logo RGB CS6</rdf:li>\n            </rdf:Alt>\n         </dc:title>\n      </rdf:Description>\n      <rdf:Description rdf:about=\"\"\n            xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\"\n            xmlns:xmpGImg=\"http://ns.adobe.com/xap/1.0/g/img/\">\n         <xmp:MetadataDate>2012-08-26T15:57:41+10:00</xmp:MetadataDate>\n         <xmp:ModifyDate>2012-08-26T15:57:41+10:00</xmp:ModifyDate>\n         <xmp:CreateDate>2012-08-26T15:57:41+10:00</xmp:CreateDate>\n         <xmp:CreatorTool>Adobe Illustrator CS6 (Macintosh)</xmp:CreatorTool>\n         <xmp:Thumbnails>\n            <rdf:Alt>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <xmpGImg:width>256</xmpGImg:width>\n                  <xmpGImg:height>108</xmpGImg:height>\n                  <xmpGImg:format>JPEG</xmpGImg:format>\n                  <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAbAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq8o/Mz/nJT8u&#xA;/I8k1gJjreuxVVtNsSCI3Haec1SP3A5MP5cVfNvnD/nLb81tceSPS5oPL1k2yx2aB5uPg08wdq+6&#xA;BMVeW6v5z836yzNq+t3+oFtz9ZuZpR0p0dj22xVJsVR2na5remsG07ULmyYdGt5pIj/whXFXoPlj&#xA;/nJT84/L7pw16TU7dftW2pqLsN/rSP8Av/ukGKvevy8/5zJ8r6rJFY+cbJtDunov6QgLTWZY92Wn&#xA;qxVP+sPFhir6EsL+x1CzhvbC4ju7O4UPBcwOskbqejK6kqR8sVV8VdirsVfEmvf85Y/m9Za7qNnB&#xA;cWQgtrqaGIG1UnhHIyrU18Bir6E/5xs/MfzN5/8AI19rPmJ4pL231OWzjMEYiX0kt4JBVR35Stvi&#xA;r1fFXYq7FXYq7FXYq7FXYq7FXk//ADkX+b1z+XPlK2fSXj/xFqk4jsElUOqxRUaeVkNKgAqnzYeG&#xA;Kpn+Q35nP+YfkC31a7KDWbWR7TVo4xxX1koyuq9leNlPzqO2KvRcVdirsVdirsVdiqldXVtaW0t1&#xA;dSpBbQI0k88jBEREFWZmNAAAKknFXxt+ef8AzlHqvmGa58veSp5NP8vqWiuNTQlLm8HQ8Ds0UR8P&#xA;tMOtAeOKvnoAk0G5OKvYPy8/5xc/MvzdHFe3cK+X9JkoVudQDCZ0P7UdsP3h23HPiD2OKvc/L3/O&#xA;GP5cWKK2s39/rFwKcwHS1gNPBIw0g/5GYqypP+cWvyLVAp8tlyBQu19f1PuaTgfhiqT6z/zh/wDl&#xA;Bfo31KO/0lzXgba5Mig7kVFyJyR9P04q8h87/wDOGfnLS45LrytqMOvQJVhZyj6rdU8F5M0T0/11&#xA;+WKvA9W0fVdHv5dO1WzmsL+A8ZrW4RopFPurAHFWa/lP+dnnD8uNQDafKbvRZX5XujTMfRkB6tGd&#xA;/Skp+2o+YI2xV92/l7+Ynlnz75ej1vQZ+cRPC5tpKCa3lG5jlQE0Ph2I3GKsmxV2KvzA82f8pTrP&#xA;/Mdc/wDJ5sVfYH/OFX/krNV/7blx/wBQdpir3/FXYq7FXYq7FXYq7FXYq7FX58f85D/mJ/jj8yr+&#xA;6tpfU0fTP9x+lFTVWihY85R4+rIWYH+Wnhiqe/8AOKX5h/4X/MePSLqTjpXmULZSgmirdAk2r/Sz&#xA;GP8A2eKvurFXYq7FXYq7FXYq+Nf+cp/zwm13Vp/I2gXBXQ9Ok4arcRsQLq5Q7x1B3ihbb3cV6BTi&#xA;rwTQtC1fXtXtdH0e1e91K9cR21tGKszH8AANyTsBudsVfb/5K/8AONvlvyJDBq2srHq/mugY3Lry&#xA;gtW/ltkYfaH+/D8Xhx6Yq9mxV2KuxV2KuxViP5i/lZ5N8/6UbHzBZK8yKRaajGAl1AT3jkpWleqm&#xA;qnuMVfC35u/k95k/LXXRZ6gPrWl3JY6ZqsakRzIP2WH7Eij7SV+VRviqE/Kr8z9d/LvzTDrWmsZb&#xA;Z6R6lp5YiO5gruh8GHVGp8J8RUFV+h3lfzLo/mfy/Y69o84uNO1CISwSbVFdmRwK0dGBVh2Ipiqa&#xA;Yq/MDzZ/ylOs/wDMdc/8nmxV9gf84Vf+Ss1X/tuXH/UHaYq9/wAVdirsVdirsVdirsVdiryv/nJL&#xA;8xP8Gflnem2k4avrVdO0+hoy+qp9aUd/3cVaHsxXFX5/4qujkkikWSNikiEMjqSGDA1BBHQjFX6N&#xA;/kz5/j89/l3pevFlN/w+raoi/s3cFFkqO3PaQD+VhirN8VdirsVdiry7/nIz8zJPIn5d3E1jJ6eu&#xA;asTY6Ww+1GzqTLOP+MSV4n+Yrir8/SSTU7k4q+5/+cZfyYh8leWU1/VYP+dp1mJXl5je1tmoyQL4&#xA;M2zSe9F/ZxV7ZirsVdirsVdirsVdiqQeevJGhedfLN55e1qL1LS6X4JFp6kMo+xNET0dD0+47E4q&#xA;/Ojzz5N1byb5q1Dy5qq0u7CTiJAKLLGw5Ryp/kuhDD7uuKvdP+cOvzNfTtfuPIuoTf6DqvK50rkd&#xA;ku41rJGK9BLGtf8AWXbdsVfYWKvzA82f8pTrP/Mdc/8AJ5sVfYH/ADhV/wCSs1X/ALblx/1B2mKv&#xA;f8VdirsVdirsVdirsVdir4K/5yg/MT/F/wCZVxaWshbSPLwbT7QA/C0qt/pMo/1pBxr3VVOKof8A&#xA;5xq/LhPOv5k2pvYPW0TRQL/UVYVRyh/cQtXY+pJSqnqobFUj/Oz8vm8h/mLqeiRow012F1pTmvxW&#xA;k9WQVPX0zyjJ8VxV6N/zh9+Yf6E863HlS8lC6f5hUG25GgW9hBKU7D1U5L7kKMVfaeKuxV2KuxV8&#xA;O/8AOXvnB9a/ND9DRvWz8u26WyqDVfrE4E0zD3oyIf8AVxVIP+cbPIUXnD80tPiu4/U0zSVOp3yk&#xA;VVhAyiKM9vimZKjutcVfoDirsVdirsVdirsVdirsVdir5p/5zR8hxXWg6Z52tov9L06QWGoOo+1b&#xA;TEtEzf8AGOX4R/r4q+UNB1m90PW7DWbFuF5p1xFdW7ducLh1r7VG+Kv050XVbXV9HsdWszytNRt4&#xA;ru3bxjnQSIf+BbFX5mebP+Up1n/mOuf+TzYq+wP+cKv/ACVmq/8AbcuP+oO0xV7/AIq7FXYq7FXY&#xA;q7FXYq89/Pj8xF8iflxqOpwy+nq12v1LSKfa+szAgSD/AIxIGk+j3xV+dxJJJJqTuSetcVffH/OM&#xA;n5dDyd+WlrPcx8NX1/jqF9yFGRHX/R4jX+SM1I7MzYqkH/OXv5d/p/yLH5ns4+WpeW2LyhRUvZTE&#xA;CUbf77YLJv0Xl44q+LdPv7vT7+2v7OQw3dnKk9tMvVJImDow+TCuKv0m/LbzrZ+dfJGk+ZLYqDfQ&#xA;A3US/wC6rlPgnj33+GRTSvUUPfFWTYq7FXYq/Mnz7rD6z531/VnO99qN1OB4K8zFRv4DbFX0/wD8&#xA;4RaFHH5b8ya+VBkuryKwVtqhbaISsB8/rIr8sVfR+pajZaZp11qN/MtvY2UT3F1O/wBlIolLu5p2&#xA;CiuKvn2L/nNbyO2vC0fRb6PRjJw/ShZC4WtPUNsN+PfZ607V2xV9DWtzb3VtFdW0izW86LLDKhqr&#xA;o45KynuCDXFVTFXYq7FXYq8c/NT/AJyd8n+QdebQBZXGsarAEa9jgZI4oOYDBWkatX4HlxC/M4qz&#xA;f8s/zM8t/mH5cGt6G0iKkhgu7ScBZoJgAeLhSwIIIKsDQj3qAqs/N7Qo9d/K/wA0aY68jLp08kI/&#xA;4ugQzRf8lI1xV+bWKv0H/wCca9WbU/yU8tSuayW8U1ow32FtcSRIOg/3Wq4q+DfNn/KU6z/zHXP/&#xA;ACebFX2B/wA4Vf8AkrNV/wC25cf9Qdpir3/FXYq7FXYq7FXYq7FXw7/zlp+Yp8yfmD+gLObnpXlo&#xA;Nb0U/C949DcN/sKLH7FT44qxP8gvy7Pnr8ydP0+dOelWJ+v6rUVBt4GH7s16+q5VPkSe2Kv0OAAF&#xA;BsB0GKqV3aW15azWl1Gs1tcRtFPC4qrxuCrKw8CDTFX5t/ml5GufI3nvVvLcxZ4rSXlZTN/uy2lH&#xA;OF/CvBgGp+1UYq9s/wCcMvzEFlrV/wCRr2alvqYN7pQboLmJaTRj/jJEob/Ye+Kvr3FXYq7FX5V4&#xA;q+5v+cPoEj/J5HUkmbUbp2r4jgm30Jir1Hz35Z/xR5N1ry8Jvq76pZy20c+9Ed1IRjTcqGpUdxir&#xA;4Zg/5xo/OWXXxo7aA8X7wI2oO6fUwhP956wJBWm9AOX+TXbFX3h5W0RNB8s6RoSSGZNKsrexWYih&#xA;cW0SxBiPfhXFUzxV2KuxV2Kvi/8A5yD/ACF/MN/zE1PX9D0u41rStZl+spJaAzSRSMB6kUkYJcUY&#xA;fCacaU+WKvZf+cW/ys8x+RfKmozeYY/quo6zPHKLDkrNDFCpVOZWoDuXJIrsKd6jFXsGsANpN6CK&#xA;g28oIPQjgcVfltir7r/5xEZj+TVqCSQt9dhQew5g0H0nFXxT5s/5SnWf+Y65/wCTzYq+wP8AnCr/&#xA;AMlZqv8A23Lj/qDtMVe/4q7FXYq7FXYq7FWG/m95+i8ifl/qvmAlfrkUfo6bG1Pju5vhiFD1Cn42&#xA;H8qnFX5wzzzTzSTzOZJpWLySMaszMakk+JOKvuP/AJxP/Lo+WPy8XWryHhq3mUrdsWHxLaKKWyf7&#xA;IEyf7IeGKvbcVdir5x/5zJ/Lo6n5asvOtlFW70U/VtS4j4ms5nHBj/xilb7nJ7Yq+SvL2u6joGuW&#xA;Gt6bJ6V/p06XNu/bnG3KhHdT0I7jFX6WeUPM+n+afLGmeYdOP+ianbpPGp3KFh8cbf5SNVT7jFU3&#xA;xV2Kvy31jT307V77T3BD2dxLbsG61icoa7Dw8MVfYv8AzhXqkU/5carp1R69lqruVHX054IuBP8A&#xA;so3xV9B4q0zKqlmIVVFWY7AAdziq2GeCdPUhkWVOnJCGFR7jFV+KuxV2KuxVZDPBMpaGRZFBoWQh&#xA;hUdqjFV+Ksf/ADC1ZNH8h+YtUZuP1PTbuZSDQllhYqB03LUAxV+ZeKvvz/nFrTWsfyS0EuvGS7a6&#xA;uWFKGj3MgQnxqiqcVfDHmz/lKdZ/5jrn/k82KvsD/nCr/wAlZqv/AG3Lj/qDtMVe/wCKuxV2KuxV&#xA;2KuxV8X/APOYf5ijWfOFt5QspK2Hl8c7yh+F72dQSPA+lHRR4FmGKvB9Hk0yLVrOXVYpJ9Mjmja9&#xA;ghIWSSFWBdEY7KWXavbFX1jD/wA5s+UYYkhi8r3scUahI0WWEKqqKAAAdAMVX/8AQ73lb/qWr7/k&#xA;dDirv+h3vK3/AFLV9/yOhxVB6z/zmR5G1jSbzSdQ8q3s1jfwyW9zEZofijlUqw6eBxV8nS+n6j+l&#xA;y9LkfT5U5ca7VptWmKvqz/nC/wDMTnDqXkO9k+KLlqOkcj+wSFuIlr4MVkAHixxV9S4q7FX58/8A&#xA;OSPlaTy9+cOvR8ONvqco1S2b+Zbv45CPlN6i/RirMf8AnDfznHpH5g3nl65kCW/mG2pDU0BurWsk&#xA;Y32+KNpB86DFX2rir5k/5zZ17zDaaX5d0m1lkh0XUGuXvvTJCyyw+n6cchHUAOWCnqd+2KvM/wDn&#xA;EfXvMFp+bVnpNlNJ+idThuf0rbCpjKw27yRSMOgZZVVQ3+VTvir7nxV2KuxV8/f85leZPMmk+RtL&#xA;sdMlkttP1W7eHVJ4iVLKkfKOAsP2ZPiJHfjTpXFXgH/ONPmPzJpX5taJZ6RJI1tqk31bUrNSfTkt&#xA;yrF3delYgOYPXb3OKv0AxV4V/wA5gec49G/LRdBikAvvMVwsPCvxfVrciaZh/shGn+yxV8SW9vPc&#xA;3EVvAhknmdY4o1FWZ2NFUDxJOKv038l+Xo/LnlHRtBSlNMsoLVmXozxRhXb/AGTVOKvzZ82f8pTr&#xA;P/Mdc/8AJ5sVfYH/ADhV/wCSs1X/ALblx/1B2mKvf8VdirsVdirsVY1+Y/nWx8leStV8yXdCLGEm&#xA;3hJp6tw/wQxj/WkYV8BU9sVfmzqOoXmpahc6hfStPeXkrz3MzfaeSRizsfmxxVlej/kz+aWs6Zb6&#xA;ppnlq8utPu09S2uEQcXQ7BlqQaHFUZ/yoH85P+pTvv8AgV/5qxV3/Kgfzk/6lO+/4Ff+asVd/wAq&#xA;B/OT/qU77/gV/wCasVd/yoH85P8AqU77/gV/5qxVK/Mf5UfmN5a0xtU13QLvT9PV1ja5lUcAz7KC&#xA;QTSuKoDyP5sv/KPm3SvMljvPptwsxjrxEkf2ZYiR2kjLKfnir9K9F1ew1nSLLV9Pk9Wx1CCO5tpP&#xA;GOVQy1pXeh3xVGYq+d/+cxfy5fWPKtp5xsY+d7oNYr8KKs1lM32vH9zJv8mY9sVfHul6nfaVqdpq&#xA;dhKYL6xmS4tZl6pLEwdGHyIxV+jH5TfmTpf5g+TLPXbQql3QRanZg1MF0o+ND34n7SHupGKp35o8&#xA;peW/NWkvpPmHT4tR092D+jKD8LioDoylWRhU/EpBxVLfJP5XeQfJAn/wvo8WnSXIAnmDSTTMoNeJ&#xA;lnaSTjXfjypirKcVfn75s/5yP/NbWfMlzqdnrt1pVn6p+padasI4oog3wK6jaRqfaL1qfbbFX2L+&#xA;RvnvUvPH5aaXr+qIF1J/VgvHVeKSSQSGP1FAAHxgAkDYGoxVlfmPy1oPmXSJ9H12yj1DTbinq28o&#xA;JBINQwIoysD0ZSCMVY75H/Jv8t/I93Le+W9HS1vplKNdySSzyhCalEeZnKDx40r3rirL7y7tbK0m&#xA;vLuVYLW3RpZ55CFREQcmZiegAFcVfnl+ef5myfmF59u9VhZho9qPqmjxNsRboT8ZHZpWJc+FQO2K&#xA;sn/5xU/LqTzR+Y8OsXMXLR/LfG8nZh8LXW/1WMe4cep/sPfFX3Xir8wPNn/KU6z/AMx1z/yebFX2&#xA;B/zhV/5KzVf+25cf9Qdpir3/ABV2KuxV2KuxV8h/85mfmL9c1qw8i2M1bfTQL3VVU7G5lX9zG3/G&#xA;OJuX+zHhirxD8sfI935388aV5ctwwS7mBvJV/wB1W0fxzSV9kBp4mgxV+ktjZWlhZW9jZxLBaWsa&#xA;QW8KbKkcahUVfZVFMVVsVdirsVdiqTec/K2n+a/KuqeXb8f6Lqdu8DPSpRiKxyKD+1G4V19xir81&#xA;PMGh6hoGuX+i6jH6d9p08ltcJ25xsVJB7g0qD3GKvrX/AJw1/MT9JeWr3yVeyVu9FJudOBO7Wk7/&#xA;ALxR/wAYpm+5wO2Kvo/FVK8tLW9tJ7O7iWe1uY2huIXFVeORSrqw7gg0OKvz5/PT8ob78uPNr20a&#xA;vL5fvy02jXhqQUr8ULt/vyKtD4ijd8VS38pfzX1/8t/Mq6rp37+yn4x6pprmkdxCDXrvxdeqP29w&#xA;SCq++/Ivn7yx540GLWvL12Li3egmhPwzQSU3imTqrD7j1BI3xVkWKuxV4R5r/wCcQPy/13zHPrFt&#xA;fXmlRXcpmurC39Joubtyf0eakxhq9NwO222KvY/LHlrRvLGg2eg6Lbi202wj9O3iBJPUszMTuzMx&#xA;LMe5OKppiqldXVraW0t1dzJb20CmSaeVgkaIoqzMzEBQB1JxV8af85Gf85Gf4t9Xyn5TlZPLSNS/&#xA;vxVWvWU1CqDQiEEV33Y+3VV4b5c8vav5j1uz0TR7drrUb+QRW8K9yepJ7Ko3YnoN8Vfoj+U35b6b&#xA;+Xvky00C0Ky3I/faleAUM904HqP48RQKgPRQMVZjir8wPNn/AClOs/8AMdc/8nmxV9gf84Vf+Ss1&#xA;X/tuXH/UHaYq9/xV2KuxV2KpN5z806f5U8q6p5ivz/oumW7zslaF2ApHGpP7UjlUX3OKvzU8wa5q&#xA;Gva5f61qL+pfajPJc3DDYc5WLEAdgK0A8MVfWf8Azhr+XQ0/y9e+d72Kl5q5NpphYbrZxN+8df8A&#xA;jLMtP9gPHFX0jirsVdirsVdirsVfIn/OZv5crZ6xYeerGKkOpUstW4jYXES/uJD/AMZIlK/7AeOK&#xA;vEvys883Pkfz5pPmOKphtZQl7EP92WsvwTL8+BJX/KocVfpHaXdteWsN3ayLNbXEaywTIaq8bgMr&#xA;KfAg1xVVxVIfO/kjy7518u3Gg69bieznFUcUEkMgB4yxNQ8XWux+g1BIxV8D/m3+Tfmj8t9ZNvqE&#xA;ZudInY/o7V41PpTL2VuvpygfaQ/RUb4qx/yd5480+TdXTVvLmoSWF2Phk40aORP5JY2qjr7MPlvi&#xA;r6l8gf8AOZvlm+iitfOtjJpN2AA+oWitPase7NGKzR/IB/nir2zQfzM/L3X0VtH8x6feMwqIUuIx&#xA;KAf5omKyL9K4qyUEMAQag7gjoRiqVax5t8q6KjPrGsWOnKv2jdXEUO/h8bLiryXzr/zlx+WGhRyR&#xA;aM83mO/XZEtVMVvyp+1PKBt7or4q+XvzQ/PXz5+Ychh1S5Fnoytyi0e0qkFQdmkqS0re7Gg7AYqw&#xA;7y75b1zzJq9vo+h2cl/qNy3GK3iFT7sxNAqjuzGg74q+6fyI/IfS/wAttNa8u3S+81XsYW9vVB9O&#xA;JDQ+hBXfjUfE3Vj4CgxV6xirsVfmB5s/5SnWf+Y65/5PNir6E/5xm/O78u/InkO/0jzLfyWt9Pqk&#xA;t3HGlvNMDE9vbxg8o1YfaibbFXrn/Q2H5Jf9Xef/AKQ7n/mjFXf9DYfkl/1d5/8ApDuf+aMVd/0N&#xA;h+SX/V3n/wCkO5/5oxVk/kL85vIXnzULiw8s3U13PaRevcF7aaJEQsFFXkVVqSdh16+GKvDf+c0P&#xA;zE/45vkKyk6cdR1cqfmtvEaf7KQg/wCQcVfOXkfynf8Am7zbpXlux2n1K4WEyU5COP7UspA7Rxhm&#xA;PyxV+lWiaPYaLo9lpGnx+lY6fBHbW0fhHEoRa+JoNziqNxV2KuxV2KuxV2Ksd/MPybZec/JereW7&#xA;viF1CBkglYVEU6/FDLtv8Eiq34Yq/NfVNMvtK1O70y/iMF9YzPb3ULdUliYo6n5EYq+0v+cRfzE/&#xA;xB5Dfy1ey8tT8tsIogT8T2MlTCff025R7dAF8cVe8Yq7FUFrOiaRremz6Zq9nFf6fcrxmtp0Dow+&#xA;R7jqCNx2xV8u/mb/AM4a3Kyy6h+X10skJqx0S9k4uv8AkwXDbN7CSn+scVfOnmXyX5t8r3P1bzDp&#xA;F1pkteKm4iZEcj/fclODj3UnFUlxV2KuxVEWNhfX91HaWNtLd3UppFbwI0kjHwVFBY4q9p/Lv/nE&#xA;v8w/MckV1r6jy1pRIL/WRyvHWlfgtwRx8P3jLTwOKvrX8uvys8mfl/phsvL1nwlkA+t6hNR7qcj/&#xA;AH5JQbeCqAo7DFWXYq7FXYq/NTzT5W8zv5n1d00i9ZGvbkqwtpSCDK1CDxxVK/8ACfmn/qzX3/SN&#xA;N/zTirv8J+af+rNff9I03/NOKu/wn5p/6s19/wBI03/NOKu/wn5p/wCrNff9I03/ADTir7W/5x78&#xA;mRflt+UU2t6vA6alqMbatqUaoTOsKRkwW4QfEWEe/GlebkYq+QvOUfnnzV5p1TzFqGkX5utTuHnZ&#xA;TbzHgpNI4weP2Y0ARfYYq+if+cOvyuvNPXU/Ous2j21zLXT9KinQo6xijTy8WFfiPFFPs3jir6dx&#xA;V2KuxV2KuxV2KuxV2Kvj3/nLn8qb+DzfbebdFsprm31tfT1CO3jaQpdwKFDkIDQSx0+lT44qwH8j&#xA;dW82eRPzG03V5dKv00ydvqerD6tNQ2sxAZiOP+62Cyf7HFX6AYq7FXYq7FULqf6L+oy/pT0PqFP3&#xA;/wBa4ejx/wAvn8NPnirxDzd/0J76r/pb9A+pU+p+jOVa0Na/o7v/AB98VYFef9CPeuvpfWOFBX0f&#xA;0xwrU9fV+KvyxVkOg/8AQkn1gfUvqPOo/wB7/wBJ8K/9HvwUxV7j5L/5V19SP+Cv0T9Tp8X6I+rc&#xA;P9l9X/jirJMVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVf/9k=</xmpGImg:image>\n               </rdf:li>\n            </rdf:Alt>\n         </xmp:Thumbnails>\n      </rdf:Description>\n      <rdf:Description rdf:about=\"\"\n            xmlns:xmpMM=\"http://ns.adobe.com/xap/1.0/mm/\"\n            xmlns:stRef=\"http://ns.adobe.com/xap/1.0/sType/ResourceRef#\"\n            xmlns:stEvt=\"http://ns.adobe.com/xap/1.0/sType/ResourceEvent#\">\n         <xmpMM:InstanceID>uuid:4b8d80fb-79e0-e648-b7e5-561a697a3c5f</xmpMM:InstanceID>\n         <xmpMM:DocumentID>xmp.did:78407A0809206811822AB037A4F90ED9</xmpMM:DocumentID>\n         <xmpMM:OriginalDocumentID>uuid:5D20892493BFDB11914A8590D31508C8</xmpMM:OriginalDocumentID>\n         <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>\n         <xmpMM:DerivedFrom rdf:parseType=\"Resource\">\n            <stRef:instanceID>uuid:dd6f74e1-a7e7-604f-8b10-fa76c7b92231</stRef:instanceID>\n            <stRef:documentID>xmp.did:0380117407206811822AB037A4F90ED9</stRef:documentID>\n            <stRef:originalDocumentID>uuid:5D20892493BFDB11914A8590D31508C8</stRef:originalDocumentID>\n            <stRef:renditionClass>proof:pdf</stRef:renditionClass>\n         </xmpMM:DerivedFrom>\n         <xmpMM:History>\n            <rdf:Seq>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <stEvt:action>saved</stEvt:action>\n                  <stEvt:instanceID>xmp.iid:0180117407206811822AB037A4F90ED9</stEvt:instanceID>\n                  <stEvt:when>2012-08-26T15:46:21+10:00</stEvt:when>\n                  <stEvt:softwareAgent>Adobe Illustrator CS6 (Macintosh)</stEvt:softwareAgent>\n                  <stEvt:changed>/</stEvt:changed>\n               </rdf:li>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <stEvt:action>saved</stEvt:action>\n                  <stEvt:instanceID>xmp.iid:78407A0809206811822AB037A4F90ED9</stEvt:instanceID>\n                  <stEvt:when>2012-08-26T15:57:39+10:00</stEvt:when>\n                  <stEvt:softwareAgent>Adobe Illustrator CS6 (Macintosh)</stEvt:softwareAgent>\n                  <stEvt:changed>/</stEvt:changed>\n               </rdf:li>\n            </rdf:Seq>\n         </xmpMM:History>\n      </rdf:Description>\n      <rdf:Description rdf:about=\"\"\n            xmlns:illustrator=\"http://ns.adobe.com/illustrator/1.0/\">\n         <illustrator:Type>Document</illustrator:Type>\n         <illustrator:StartupProfile>Print</illustrator:StartupProfile>\n      </rdf:Description>\n      <rdf:Description rdf:about=\"\"\n            xmlns:xmpTPg=\"http://ns.adobe.com/xap/1.0/t/pg/\"\n            xmlns:stDim=\"http://ns.adobe.com/xap/1.0/sType/Dimensions#\"\n            xmlns:xmpG=\"http://ns.adobe.com/xap/1.0/g/\">\n         <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>\n         <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>\n         <xmpTPg:NPages>1</xmpTPg:NPages>\n         <xmpTPg:MaxPageSize rdf:parseType=\"Resource\">\n            <stDim:w>296.999959</stDim:w>\n            <stDim:h>210.001652</stDim:h>\n            <stDim:unit>Millimeters</stDim:unit>\n         </xmpTPg:MaxPageSize>\n         <xmpTPg:PlateNames>\n            <rdf:Seq>\n               <rdf:li>Cyan</rdf:li>\n               <rdf:li>Magenta</rdf:li>\n               <rdf:li>Yellow</rdf:li>\n               <rdf:li>Black</rdf:li>\n            </rdf:Seq>\n         </xmpTPg:PlateNames>\n         <xmpTPg:SwatchGroups>\n            <rdf:Seq>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <xmpG:groupName>Default Swatch Group</xmpG:groupName>\n                  <xmpG:groupType>0</xmpG:groupType>\n                  <xmpG:Colorants>\n                     <rdf:Seq>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>White</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>255</xmpG:red>\n                           <xmpG:green>255</xmpG:green>\n                           <xmpG:blue>255</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>Black</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>29</xmpG:red>\n                           <xmpG:green>29</xmpG:green>\n                           <xmpG:blue>27</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>CMYK Red</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>226</xmpG:red>\n                           <xmpG:green>6</xmpG:green>\n                           <xmpG:blue>19</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>CMYK Yellow</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>255</xmpG:red>\n                           <xmpG:green>236</xmpG:green>\n                           <xmpG:blue>0</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>CMYK Green</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>0</xmpG:red>\n                           <xmpG:green>149</xmpG:green>\n                           <xmpG:blue>64</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>CMYK Cyan</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>0</xmpG:red>\n                           <xmpG:green>158</xmpG:green>\n                           <xmpG:blue>226</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>CMYK Blue</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>49</xmpG:red>\n                           <xmpG:green>39</xmpG:green>\n                           <xmpG:blue>130</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>CMYK Magenta</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>229</xmpG:red>\n                           <xmpG:green>0</xmpG:green>\n                           <xmpG:blue>126</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=15 M=100 Y=90 K=10</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>189</xmpG:red>\n                           <xmpG:green>22</xmpG:green>\n                           <xmpG:blue>34</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=90 Y=85 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>229</xmpG:red>\n                           <xmpG:green>51</xmpG:green>\n                           <xmpG:blue>42</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=80 Y=95 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>232</xmpG:red>\n                           <xmpG:green>78</xmpG:green>\n                           <xmpG:blue>27</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=50 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>242</xmpG:red>\n                           <xmpG:green>145</xmpG:green>\n                           <xmpG:blue>0</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=35 Y=85 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>248</xmpG:red>\n                           <xmpG:green>177</xmpG:green>\n                           <xmpG:blue>51</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=5 M=0 Y=90 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>252</xmpG:red>\n                           <xmpG:green>234</xmpG:green>\n                           <xmpG:blue>13</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=20 M=0 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>221</xmpG:red>\n                           <xmpG:green>219</xmpG:green>\n                           <xmpG:blue>0</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=50 M=0 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>147</xmpG:red>\n                           <xmpG:green>192</xmpG:green>\n                           <xmpG:blue>31</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=75 M=0 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>57</xmpG:red>\n                           <xmpG:green>169</xmpG:green>\n                           <xmpG:blue>53</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=85 M=10 Y=100 K=10</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>0</xmpG:red>\n                           <xmpG:green>141</xmpG:green>\n                           <xmpG:blue>54</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=90 M=30 Y=95 K=30</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>0</xmpG:red>\n                           <xmpG:green>102</xmpG:green>\n                           <xmpG:blue>51</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=75 M=0 Y=75 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>45</xmpG:red>\n                           <xmpG:green>171</xmpG:green>\n                           <xmpG:blue>102</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=80 M=10 Y=45 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>0</xmpG:red>\n                           <xmpG:green>160</xmpG:green>\n                           <xmpG:blue>153</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=70 M=15 Y=0 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>53</xmpG:red>\n                           <xmpG:green>168</xmpG:green>\n                           <xmpG:blue>224</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=85 M=50 Y=0 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>29</xmpG:red>\n                           <xmpG:green>112</xmpG:green>\n                           <xmpG:blue>183</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=100 M=95 Y=5 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>45</xmpG:red>\n                           <xmpG:green>46</xmpG:green>\n                           <xmpG:blue>130</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=100 M=100 Y=25 K=25</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>41</xmpG:red>\n                           <xmpG:green>35</xmpG:green>\n                           <xmpG:blue>92</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=75 M=100 Y=0 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>102</xmpG:red>\n                           <xmpG:green>36</xmpG:green>\n                           <xmpG:blue>130</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=50 M=100 Y=0 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>148</xmpG:red>\n                           <xmpG:green>27</xmpG:green>\n                           <xmpG:blue>128</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=35 M=100 Y=35 K=10</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>162</xmpG:red>\n                           <xmpG:green>25</xmpG:green>\n                           <xmpG:blue>91</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=10 M=100 Y=50 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>214</xmpG:red>\n                           <xmpG:green>11</xmpG:green>\n                           <xmpG:blue>81</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=95 Y=20 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>230</xmpG:red>\n                           <xmpG:green>27</xmpG:green>\n                           <xmpG:blue>114</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=25 M=25 Y=40 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>202</xmpG:red>\n                           <xmpG:green>186</xmpG:green>\n                           <xmpG:blue>159</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=40 M=45 Y=50 K=5</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>163</xmpG:red>\n                           <xmpG:green>137</xmpG:green>\n                           <xmpG:blue>122</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=50 M=50 Y=60 K=25</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>122</xmpG:red>\n                           <xmpG:green>106</xmpG:green>\n                           <xmpG:blue>88</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=55 M=60 Y=65 K=40</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>99</xmpG:red>\n                           <xmpG:green>78</xmpG:green>\n                           <xmpG:blue>66</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=25 M=40 Y=65 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>201</xmpG:red>\n                           <xmpG:green>157</xmpG:green>\n                           <xmpG:blue>102</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=30 M=50 Y=75 K=10</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>177</xmpG:red>\n                           <xmpG:green>127</xmpG:green>\n                           <xmpG:blue>73</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=35 M=60 Y=80 K=25</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>146</xmpG:red>\n                           <xmpG:green>95</xmpG:green>\n                           <xmpG:blue>54</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=40 M=65 Y=90 K=35</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>126</xmpG:red>\n                           <xmpG:green>78</xmpG:green>\n                           <xmpG:blue>36</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=40 M=70 Y=100 K=50</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>104</xmpG:red>\n                           <xmpG:green>59</xmpG:green>\n                           <xmpG:blue>17</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=50 M=70 Y=80 K=70</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>66</xmpG:red>\n                           <xmpG:green>41</xmpG:green>\n                           <xmpG:blue>24</xmpG:blue>\n                        </rdf:li>\n                     </rdf:Seq>\n                  </xmpG:Colorants>\n               </rdf:li>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <xmpG:groupName>Grays</xmpG:groupName>\n                  <xmpG:groupType>1</xmpG:groupType>\n                  <xmpG:Colorants>\n                     <rdf:Seq>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=100</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>29</xmpG:red>\n                           <xmpG:green>29</xmpG:green>\n                           <xmpG:blue>27</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=90</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>60</xmpG:red>\n                           <xmpG:green>60</xmpG:green>\n                           <xmpG:blue>59</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=80</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>87</xmpG:red>\n                           <xmpG:green>87</xmpG:green>\n                           <xmpG:blue>86</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=70</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>111</xmpG:red>\n                           <xmpG:green>111</xmpG:green>\n                           <xmpG:blue>110</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=60</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>134</xmpG:red>\n                           <xmpG:green>134</xmpG:green>\n                           <xmpG:blue>134</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=50</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>156</xmpG:red>\n                           <xmpG:green>155</xmpG:green>\n                           <xmpG:blue>155</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=40</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>177</xmpG:red>\n                           <xmpG:green>177</xmpG:green>\n                           <xmpG:blue>177</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=30</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>198</xmpG:red>\n                           <xmpG:green>198</xmpG:green>\n                           <xmpG:blue>197</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=20</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>217</xmpG:red>\n                           <xmpG:green>217</xmpG:green>\n                           <xmpG:blue>217</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=10</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>236</xmpG:red>\n                           <xmpG:green>236</xmpG:green>\n                           <xmpG:blue>236</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=0 Y=0 K=5</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>245</xmpG:red>\n                           <xmpG:green>245</xmpG:green>\n                           <xmpG:blue>245</xmpG:blue>\n                        </rdf:li>\n                     </rdf:Seq>\n                  </xmpG:Colorants>\n               </rdf:li>\n               <rdf:li rdf:parseType=\"Resource\">\n                  <xmpG:groupName>Brights</xmpG:groupName>\n                  <xmpG:groupType>1</xmpG:groupType>\n                  <xmpG:Colorants>\n                     <rdf:Seq>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=100 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>226</xmpG:red>\n                           <xmpG:green>6</xmpG:green>\n                           <xmpG:blue>19</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=75 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>233</xmpG:red>\n                           <xmpG:green>90</xmpG:green>\n                           <xmpG:blue>12</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=0 M=10 Y=95 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>255</xmpG:red>\n                           <xmpG:green>221</xmpG:green>\n                           <xmpG:blue>0</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=85 M=10 Y=100 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>0</xmpG:red>\n                           <xmpG:green>151</xmpG:green>\n                           <xmpG:blue>58</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=100 M=90 Y=0 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>40</xmpG:red>\n                           <xmpG:green>52</xmpG:green>\n                           <xmpG:blue>138</xmpG:blue>\n                        </rdf:li>\n                        <rdf:li rdf:parseType=\"Resource\">\n                           <xmpG:swatchName>C=60 M=90 Y=0 K=0</xmpG:swatchName>\n                           <xmpG:mode>RGB</xmpG:mode>\n                           <xmpG:type>PROCESS</xmpG:type>\n                           <xmpG:red>129</xmpG:red>\n                           <xmpG:green>53</xmpG:green>\n                           <xmpG:blue>138</xmpG:blue>\n                        </rdf:li>\n                     </rdf:Seq>\n                  </xmpG:Colorants>\n               </rdf:li>\n            </rdf:Seq>\n         </xmpTPg:SwatchGroups>\n      </rdf:Description>\n      <rdf:Description rdf:about=\"\"\n            xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n         <pdf:Producer>Adobe PDF library 10.01</pdf:Producer>\n      </rdf:Description>\n   </rdf:RDF>\n</x:xmpmeta>\n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                                                                                                    \n                           \n<?xpacket end=\"w\"?>\rendstream\rendobj\r3 0 obj\r<</Count 1/Kids[7 0 R]/Type/Pages>>\rendobj\r7 0 obj\r<</ArtBox[78.7725 155.908 763.117 439.372]/BleedBox[0.0 0.0 841.89 595.28]/Contents 8 0 R/LastModified(D:20120826155741+10'00')/MediaBox[0.0 0.0 841.89 595.28]/Parent 3 0 R/PieceInfo<</Illustrator 9 0 R>>/Resources<</ColorSpace<</CS0 10 0 R>>/ExtGState<</GS0 11 0 R>>/Properties<</MC0 5 0 R>>>>/Thumb 12 0 R/TrimBox[0.0 0.0 841.89 595.28]/Type/Page>>\rendobj\r8 0 obj\r<</Filter/FlateDecode/Length 942>>stream\r\nHVˎ6\f+\u0003\u0014Ƕ \b\u0007\\b\u0012 \u0007z(ɲ6(fqM\u0014yx\u000ey5|z᧟_}PO߷·\u0018\u001e!#\\o\u0003w'\u0007H-\u001aD\u0013\u0019\u0012\u001e_7?,V<a\u0014}l#L\u001c9]\nq~|zl~d\u001dp#vyll/88g*Z\\%7\u001c펣\u0010\u0019٫m\u00076QAi\u0005\u001d3td= R,$)\t\"z Kl8\u0011L\u0013\u0000z\ri6\u0019:\u001bϋ\u0011vȥ3#a?qQH\nj\u0002e%e\ny`\u0016\u0015LM\u0010uIN2ڲo\u0014>!\r\rjl9$̈6\u001fI*\u001aIQ\u0019C\\z8F\u001e\u0010ri\u001a|ިuB\u000beR \u0004u`\u0014̐Mn!Kcj`̰kv\u0018F\u0015T\u001fvG$*+\u0004EE2.WWj^\u0010p\u0014\u000eR\u0004Xs F\u001ai[!\u0011S\u001agX)\u0012Z\u0002=\u0007\u00123io5Ů\u0015EA]P2E\u0015\u0015󈚳\u0007dS`gAյV\u0019\u0004\u000fg\u0007\bTds\u0014/*k\u0006j,bPEr\bjW\t\u0012!RC\u0013KrX\u00137T|&üI/S1;6/āq!Y\u001b\u0015AdCN?\u0017V\u000f\u0012N\u001da˝+d\bfD\bJ#Uᐱ\u0010 8\u0003I5!6NUG6W`dzE\nƜ~h7ڠ\bT\u0006;b,va\u0001$RsY{Jz\u0001Uie\u000e@^wx\u0000\u0012KE$\u0000>\b\u0004C4\r06m%H1 \u0007\fp=\u001fHܜ\nA\u00162b̍\nЈSt_u\u0005Vm.9#\u0014\n;^ܒZb2|\u000b\u0014\neA8\u0007>*D\u0006e\u00183\f@\f\u001bUVπ\u0002Ů\u001e\u001c\u0010\u001a6|\u001f\u0007E.QoX;g@\ti}\u0016`\u0000$pϳ\rendstream\rendobj\r12 0 obj\r<</BitsPerComponent 8/ColorSpace 13 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 74/Length 391/Width 105>>stream\r\n8;Z]!9+o,r#X`\\5$i2p?`$lCO7,$m!4(shr?p-lIcW[*kBJ^Wer_LScG:8SBfWBiJ\n;%8U\\!Z5]ZK,VFPnI?fSdR`<)pn?,-h`c:cfg,Y7OHRPK?M9]<i7NP]U80\"!$5GaE\nMj>IuP<ae#kFB@Njd`K*=Hn?3/P\\&,aPB8pU?eaDN`[5Pn-1cT.EL/BTTJ;>;M)dM\nk<Z7X_TfgN3p3Vsb.%N$*gBm%\"/pCsB5[Vg81;Smq-=@K+K#V$UZ\\l_@^\"%Sfi<lc\n+p6aQQXgBF]i[<<nqG$2D$N'k.`mi_U]k3LrTb(iPImWT\"IGYXDC(<c8W`#QP%\\Hm\nK#00>HG,)456>:)?QFQePXR)]\"p-2u)-t\\5D=iE*ctG6SNCK[Md:312gthT~>\rendstream\rendobj\r13 0 obj\r[/Indexed/DeviceRGB 255 14 0 R]\rendobj\r14 0 obj\r<</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream\r\n8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@\"pJ+EP(%0\nb]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\\Ulg9dhD*\"iC[;*=3`oP1[!S^)?1)IZ4dup`\nE1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\\.?d>Mn\n6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1\nVNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<\nPO7r\\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(\nl[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\\~>\rendstream\rendobj\r5 0 obj\r<</Intent 15 0 R/Name(Layer 1)/Type/OCG/Usage 16 0 R>>\rendobj\r15 0 obj\r[/View/Design]\rendobj\r16 0 obj\r<</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>>\rendobj\r11 0 obj\r<</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>>\rendobj\r10 0 obj\r[/ICCBased 17 0 R]\rendobj\r17 0 obj\r<</Filter/FlateDecode/Length 2574/N 3>>stream\r\nHyTSw\u0016oɞc\r[\u00065la\u001d\u0004Q\bI\b\u0001\u0012BH\u0005AD\u0005\u0014ED2mtFOE.c\u000e}\u000308\u0016׎\u00178GNg\u001f9w߽\u0000'0\u000b\u0000֠J\u0016\u0015\u0014b\t\u0000\u0003\n \u0002\u0011\u00002y.-;!\u0007KZ\t^\u0007i\"L0-\r\u0000@\u00198\u0007(r;q7L\u0019y&Q\u0013\u0004q4j|9\nV)gB0iW\u00198#8wթ8_٥ʨQ\u0014Qj\u0001@&A)/\u000fg>'K\u0002\u0000t;\\\u000e\u001b\r\u0006ӥ$պFZUn\u001e(4T%)뫔\u00060C&\u0015Zi\u001b\u00018bxEB\u001f;Pӓ̹A\u000bom?W=\nx\u0016-\u0000\u0004[\u00000\u001d}y)7\u0018ta>jT7\u000e@tܛ`q2ʀ&6ZLĄ?\u001d_\u001dyxg)˔z\u0016çLU*\u0006u\u0016SkS\u0013eO4?׸c\u0001\u0007.\u0000\u000b\u0000\u0000R\r߁-\u000725\tS>ӣVd`rn~Y\u0002\u0002\u0002&\u0001+`\u000f;\u0010\u0002\u0010\u0002A4\u0007 \u001d\u0002\u0014A9\u0000=\u0007-\u001dt\u001e\u001el\u0002`;\u0018\u0003~p\u0010\tGp\u001e|\t[`\u0012L`\u0006<\u0005 \b\"A\f\u000bYA\u000e+\u0005Cb(\u0012R,\u0000*T\u00162B-\n\u0007ꇆ\u001dnQ\u0004t\u000e\u0004}\u0005MA\u000f0\u0002a\u001el\u0007\u0018S\u001cx\tk&\u0013^\u0007\u000f>0|\u0002>\u000f_',\u0002\u0010\u001aG\u001c\u0011!\"F$H:R!z\u0015F\u0006Qd?r\f9\\A&G\u000brQ\f\u0015h\u0012\u001a\u0015E]a4z\u0005Bg\u0004\u0006E\b#H\t\b*B=0HIpp0MxJ$\u0012D\u00011D, V\u0010ĭ\u0003KĻY\u0012dE\"EI2EBGt4MzN\u001d\u0004r!YK \u000f?%_&#(0J:EAiQ((\u0017)ӔWT6U@P+!~\u0019m\u0013\u001aD\u000beԴ!hӦh/\u001c']B/\u001b\u001fҏӿ?a0\u0018nhF!X8܌kc&5S\u001d6lIa2cKMA!E#\u0016ƒdV\b(\u0006kel\r}}Cq9\nN'\u0003)].uJr\n\u0018\fwG\txR^\u0005[\u0004oƜc\u001ehg`>b$\u001f*~\u001f :Eb~\u0016,m,-ݖ\u0007,Y¬*6X[ݱF=3뭷Y~dó\tt\u001ci\u000bzf6~`{v.Ng#{}}\u000f\u001c\u000e\u000ej\u0001\u001cc1X\u00156f\u001cm\u001d\u001c;\u001c'\u001c_9\tr:\u000e8q:˜\u0007O:ϸ8uJq\u0015nv=MmR \u00154\t\nn3ܣkGݯz\u0010=\u001e\u001e[==<=G</z^^j^\tޡZQ\u001bB0FX'+t<u-{__ߘ-\u0011G,\u0010\u001d\u0013}/\u001f\u001a\bH\bh\u000b8\u0012mW2p[AiAN\u0006#8$X\u001f?AKHI{!7<qWy(!46-\u0017aaa\u000f\u0017W\t@@`l\b\bYĎH,$((Yh7ъb<b*b<~\u0014L\u0012&Y&9\u001e%uMssNpJP%MI\fJlN<DHJIڐtCj'KwKgC%Nd\f|ꙪO=\u0006%mLuvx:HoL!ȨC&13#s$/Y=Osbsrn\u001asO1v=ˏϟ\\h٢\u0005\u0005#¼\u0017oZ<]\u0014TUt}`IÒsKV-Y,+>TB(/S,]6*-W:#7\u001f*\u0015\u0003\u0007\be^YDY}UjAyT`#D=\"b{ų\u000f+ʯ:!kJ4G\u001cmt}uC%K7Y\u0013VfFY\u000b.=b?S\u0017ƕƩȺy\u001a\rچ\u000bk\u001a5%4\u0019m7lqlioZ\u0016lG+Zz͹mzy]?uuw|\"űNwW&e֥ﺱ*|j5\u0001kyݭǯg^y\u0017kEklD_p߶7Dmo꿻1m\u0001l{Mś\r\u0006\u000enLl<9O\u0000\u0001[$h՛B\u001cdҞ@\u001diءG&\u0006vVǥ8\u001anRĩ7\u001c\u0002u\\ЭD-\u0016\u0000u`ֲK³8%\u0013\u0001yhYѹJº;.!\u0015\nzpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\\dlvۀ\u0005܊\u0010ݖ\u001cޢ)߯6DScs\r\u001f2F[p\u0011(@Xr\u00194Pm\u00198Ww\u0007)Km\u0002\f\u0000\rendstream\rendobj\r9 0 obj\r<</LastModified(D:20120826155741+10'00')/Private 18 0 R>>\rendobj\r18 0 obj\r<</AIMetaData 19 0 R/AIPrivateData1 20 0 R/AIPrivateData2 21 0 R/AIPrivateData3 22 0 R/AIPrivateData4 23 0 R/ContainerVersion 11/CreatorVersion 16/NumBlock 4/RoundtripStreamType 1/RoundtripVersion 16>>\rendobj\r19 0 obj\r<</Length 993>>stream\r\n%!PS-Adobe-3.0 \r%%Creator: Adobe Illustrator(R) 16.0\r%%AI8_CreatorVersion: 16.0.0\r%%For: (Douglas Heriot) ()\r%%Title: (OLA Logo RGB.ai)\r%%CreationDate: 26/08/12 3:57 PM\r%%Canvassize: 16383\r%%BoundingBox: 78 -440 764 -155\r%%HiResBoundingBox: 78.7725 -439.3721 763.1172 -155.9082\r%%DocumentProcessColors: Cyan Magenta Yellow Black\r%AI5_FileFormat 12.0\r%AI12_BuildNumber: 682\r%AI3_ColorUsage: Color\r%AI7_ImageSettings: 0\r%%RGBProcessColor: 0 0 0 ([Registration])\r%AI3_Cropmarks: 0 -595.2803 841.8896 0\r%AI3_TemplateBox: 421.5 -298.5 421.5 -298.5\r%AI3_TileBox: 141.4448 -677.6406 700.4453 105.3599\r%AI3_DocumentPreview: None\r%AI5_ArtSize: 14400 14400\r%AI5_RulerUnits: 1\r%AI9_ColorModel: 1\r%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0\r%AI5_TargetResolution: 800\r%AI5_NumLayers: 1\r%AI9_OpenToView: -299 153 1.5 2307 1480 18 0 0 78 133 0 0 0 1 1 0 1 1 0 1\r%AI5_OpenViewLayers: 7\r%%PageOrigin:115 -694\r%AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9\r%AI9_Flatten: 1\r%AI12_CMSettings: 00.MS\r%%EndComments\r\rendstream\rendobj\r20 0 obj\r<</Length 6388>>stream\r\n%%BoundingBox: 78 -440 764 -155\r%%HiResBoundingBox: 78.7725 -439.3721 763.1172 -155.9082\r%AI7_Thumbnail: 128 56 8\r%%BeginData: 6236 Hex Bytes\r%0000330000660000990000CC0033000033330033660033990033CC0033FF\r%0066000066330066660066990066CC0066FF009900009933009966009999\r%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66\r%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333\r%3333663333993333CC3333FF3366003366333366663366993366CC3366FF\r%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99\r%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033\r%6600666600996600CC6600FF6633006633336633666633996633CC6633FF\r%6666006666336666666666996666CC6666FF669900669933669966669999\r%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33\r%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF\r%9933009933339933669933999933CC9933FF996600996633996666996699\r%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33\r%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF\r%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399\r%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933\r%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF\r%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC\r%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699\r%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33\r%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100\r%000011111111220000002200000022222222440000004400000044444444\r%550000005500000055555555770000007700000077777777880000008800\r%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB\r%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF\r%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF\r%524C45FD13FFA87D5227FD07F827527DA8FD6EFFA852FD11F8527DFD13FF\r%52272752277DFD28FFA85252FD25FFA827FD15F8277DFD11FF27FD04F852\r%FD28FF7DF8F8A8FD22FFA852FD19F8277DFD0FFF27FD04F87DFD28FFF8F8\r%F852FD21FF7DFD1DF852FD0EFF52FD04F852FD27FF7DFD04F8FD20FF27FD\r%0AF827527D7DFD04A87D5252FD0AF827FD0DFF27FD04F87DFD27FF27FD04\r%F852FD1EFF27FD08F8277DFD0DFF7D27FD09F8A8FD0BFF52FD04F852FD26\r%FFA8FD05F827FD1DFFFD09F8A8FD11FFA827FD08F8A8FD0AFF27FD04F87D\r%FD26FF27FD06F87DFD1BFF27FD07F87DFD15FF7D27FD07F8A8FD09FF52FD\r%04F852FD25FFA8FD07F827FD1AFF27FD06F827A8FD17FFA852FD07F8FD09\r%FF27FD04F87DFD25FF52FD08F87DFD18FF52FD06F852FD1BFF7DFD06F827\r%FD08FF52FD04F852FD25FFFD09F852FD17FF7DFD06F852FD1DFF7DFD06F8\r%52FD07FF27FD04F87DFD24FF52FD0AF8A8FD16FF27FD05F852FD1FFF7DFD\r%06F8A8FD06FF52FD04F852FD24FF27FD0AF852FD15FF7DFD05F827A8FD20\r%FF52FD05F827FD06FF27FD04F87DFD23FF7DFD05F87D27FD05F8A8FD14FF\r%FD06F8A8FD22FF27FD05F8A8FD05FF52FD04F852FD23FF27FD04F827FFA8\r%FD05F87DFD13FF52FD05F852FD23FF7DFD05F827FD05FF27FD04F87DFD22\r%FF7DFD05F852FFFF27FD05F8FD13FF27FD05F8FD25FF27FD05F87DFD04FF\r%52FD04F852FD22FF52FD05F8FFFFFF7DFD05F87DFD11FFA8FD05F87DFD25\r%FFA8FD05F852FD04FF27FD04F87DFD21FFA8FD05F852FD04FFFD05F827FD\r%11FF52FD04F827A8FD26FF52FD05F8FD04FF52FD04F852FD21FF27FD05F8\r%A8FD04FF7DFD05F8A8FD0FFFA8FD05F827FD27FF52FD05F87DFFFFFF27FD\r%04F87DFD20FFA8FD05F827FD05FFA8FD05F827FD0FFFA8FD05F8A8FD28FF\r%FD05F87DFFFFFF52FD04F852FD20FF52FD05F8A8FD06FF52FD05F8A8FD0E\r%FF52FD05F8A8FD28FF27FD04F827FFFFFF27FD04F87DFD20FFFD05F827FD\r%07FFA8FD05F852FD0EFF52FD04F827FD07FFA8FD19FFA8FD07FF52FD04F8\r%27FFFFFF52FD04F852FD1FFF52FD05F87DFD08FF52FD05F8FD0EFF27FD04\r%F852FD06FF27F8F852FD15FFA8F8F827FD06FF7DFD05F8FFFFFF27FD04F8\r%7DFD1EFFA827FD04F827FD09FF7DFD05F852FD0DFF27FD04F87DFD05FF7D\r%FD04F8A8FD14FFFD04F852FD05FF7DFD04F827A8FFFF52FD04F852FD1EFF\r%7DFD05F87DFD0AFF27FD04F827FD0DFFFD05F87DFD05FF27FD04F852FD13\r%FF7DFD04F827FD05FFA8FD05F8A8FFFF27FD04F87DFD1EFFFD05F827A8FD\r%0AFFA8FD05F87DFD0CFFFD05F87DFD05FF52FD04F87DFD13FFA8FD04F827\r%FD05FFA8FD05F87DFFFF52FD04F852FD1DFF7DFD05F852FD0CFF27FD04F8\r%27FD0CFFFD05F8A8FD06FF27F8F852FD15FF52F8F8F8A8FD05FFA8FD05F8\r%A8FFFF27FD04F87DFD1DFF27FD05F8FD0DFF52FD05F87DFD0BFFFD05F87D\r%FD07FF7DA8FD17FFA87DFD07FFA8FD05F87DFFFF52FD04F852FD1CFFA8FD\r%05F87DFD0EFFFD05F827FD0BFFFD05F87DFD29FFA8FD05F8A8FFFF27FD04\r%F87DFD1CFF27FD05F8A8FD0EFF7DFD05F8A8FD0AFF27FD04F87DFD29FF7D\r%FD05F8A8FFFF52FD04F852FD1BFFA8FD05F852FD10FF27FD04F852FD0AFF\r%FD05F852FD29FF7DFD05F8FFFFFF27FD04F87DFD1BFF52FD05F827FD0452\r%275252522752525227525252FD06F8A8FD09FF52FD04F827FD29FF52FD04\r%F827FFFFFF52FD04F852FD1BFFFD1DF852FD09FF52FD04F827A8FD07FFA8\r%27F827A8FD10FF52F8277DFD08FF27FD04F827FFFFFF27FD04F87DFD1AFF\r%52FD1EF8FD09FFA8FD05F8A8FD07FF27F8F8F827FD0FFF7DF8F8F827A8FD\r%07FFFD05F87DFFFFFF52FD04F852FD1AFF27FD1EF87DFD08FFA8FD05F852\r%FD06FFA8FD05F8FD0FFFFD05F87DFD06FF52FD05F87DFFFFFF27FD04F87D\r%FD19FF7DFD1FF827A8FD08FF27FD04F827FD06FFA827F8F8F827FD0FFF52\r%FD04F8A8FD06FF52FD04F827FD04FF52FD04F852FD19FF27FD04F827527D\r%527D527D527D527D527D527D527D527D527D5252FD05F87DFD08FF7DFD05\r%F87DFD06FF52F8F8F87DFD07FFA8FD07FF7DF8F8F827FD06FFA8FD05F852\r%FD04FF27FD04F87DFD18FF7DFD05F852FD15FFA827FD04F827FD08FFA8FD\r%05F827FD07FF7D7DA8FD07FF27F8F8A8FD06FFA87D7DFD07FF27FD05F8A8\r%FD04FF52FD04F852FD18FF27FD05F8FD17FF52FD05F8A8FD08FF52FD05F8\r%52FD0FFF27FD04F8FD0FFF7DFD05F827FD05FF27FD04F87DFD17FFA8FD05\r%F852FD17FFA8FD05F852FD09FFFD06F8A8FD0EFF27FD04F8A8FD0EFF27FD\r%05F8A8FD05FF52FD04F852FD17FF27FD05F8A8FD18FF52FD05F8A8FD08FF\r%52FD05F827FD0EFFFD05F8FD0EFF52FD05F852FD06FF27FD04F87DFD16FF\r%A8FD05F827FD19FFA8FD05F852FD09FF27FD05F852FD0DFFA8F8F8F87DFD\r%0DFF7DFD06F8A8FD06FF52FD04F852FD16FF52FD05F8A8FD1AFF27FD04F8\r%27A8FD08FF7DFD06F852FD0DFFA87DA8FD0DFF7DFD06F852FD07FF27FD04\r%F87DFD15FFA8FD05F852FD1BFFA8FD05F852FD09FF52FD06F852FD1BFF7D\r%FD06F852FD08FF52FD04F852FD15FF52FD05F87DFD1CFF52FD05F8FD0AFF\r%27FD06F827A8FD17FFA852FD07F8FD09FF27FD04F87DFD14FFA827FD04F8\r%27FD1DFF7DFD05F87DFD0AFF27FD06F8277DFD15FFA827FD07F8FD0AFF52\r%FD04F852FD14FF7DFD05F8A8FD1EFF27FD04F827FD0BFFFD08F827A8FD11\r%FFA827FD08F8A8FD0AFF27FD04F87DFD14FFFD05F827A8FD1EFF7DFD05F8\r%7DFD0BFF27FD08F8527DFD0DFF7D52FD09F8FD0CFF52FD04F827A8FD0F7D\r%A8FFFF7DFD05F87DFD20FF27FD04F827FD0CFF52FD0AF827527D7DA87DA8\r%7D7D5227FD0AF827FD0DFF27FD15F87DFFFF27FD05F8FD21FF52FD05F87D\r%FD0CFF7D27FD1CF852FD0EFF52FD14F827FFFFA8FD05F87DFD22FFFD05F8\r%52FD0DFFA852FD19F827A8FD0FFF27FD14F8A8FFFF27FD05F8A8FD22FF52\r%FD05F8A8FD0EFFA827FD15F827A8FD11FF27FD13F827FFFFA8FD05F852FD\r%23FFA8FD05F852FD10FFA87DFD11F8527DFD13FF52522752275227522752\r%275227522752275227527DFFFF7D2752275227A8FD24FF525227522752FD\r%13FFA87D52522727F8F8F8272727527DA8FD76FFA8FFA8A8A8FD62FFFF\r%%EndData\r\rendstream\rendobj\r21 0 obj\r<</Length 65536>>stream\r\n%AI12_CompressedDatax\u001dɕ&\u0004\u000ew~\u0014 5!773_4\u0006\u0016\u001ahRHPP]L2dZs_\u0011J00\u0018ׯ-gwׯx^ś~\u001d?޽Ow|twG\u001co~\u000bMO'6'~xS?:}wo?|G?~ӻ;W?~\u000f\u001f}Ot0\u0012]iv\u0005Nxw{9ұÇׇ\u000fi޽JMcڽ\n9o[t3MC3r\u0013!&ikn~\u001eӇ7sӯ?~xsw\u000f>|^ݿ޽{?vw{GC}ןvaX\u0016/\u000f߿}/ww4.#,~]w\u0017uqxgБ/>}\u0007\u001bb<iǠ~o-\r\rv÷߼v*/fSero\u001d4I\u001a\rȰ_Aϥ\u0002uRa\u001efL\u000e\u000b}yY2|w|{\u001f?;\u0019O_\u001c\\[>\u0003\u000e-2H;=߾{c-ro_\u0013w9\u001dh\u0012~Ow\u001f\r~~'~Fze\u0017.4\u0000C'z\u000eB~P~K\t\r&_\\ۯ߾i\b4dۯ$ڛ\u0017\\[</Owiq\u001dQ-\u0017_m:~\u0006\u001d\b}Z\u001bo\u00154U=~_?|?{\u000fݏ8\u001b\u00004_~E\u001fh\u00027\u0001}sh{x/Jh?|rw>|[uG^jϯ?~p׿~;>=\u001f4Rr\u00112\u0006/SV7G?\u0010{w޷|l\u001f\\=\u0017o\u0006?\u000e\u001f\u000f~λm0\u001f\u001d5_We.'D\u0014.t;Зͽ\u001f_{돯7[7$}7wߔT\u001d돟޾ywştͣ'ww-\u0011+sןoǷw>L߾\u0017߿tW\u00067B}k|-w$_\u0013WC;zK\fd\u0010v_~\u001fu\rWݿuĹaZ\u0006#gGH_f#a\u0019\u0003A\u0012ԏ]ݗU\u0007;٢t\u000ev:ݸēI\u0019~,}\u001d{3=\u0013\u001cN>69}*Ҝ\u000ePwYQD\rgjZZUǮZ\u001ep8\u001e·c\f\u0018阏q:Ԗx8\u001e?pJ|\u001aOix:Χs\u000e;s6R3߃Ζ6uSFn\u001etJ)[{qM6ZnZZh?\u0006i|\u000f[蔏1ycΙ<@|K1\u001d>-iJcʤ\u00074xK=1\u001e>.q\u0014ǘc1\u000e1=bZ݆vj\u001d:FPAӂ\u0005\u0019}qgT%\u0016vZV4^g8O3)Ty]%,\u0012˴˲rZ\u000fO\u001f~q\u001eC8\f\u001d!\u001ft\u000fa/KxnTʷleMkO-\u001e|[TCU\u001b\f[D3q4'3Hs8\u000fsi:Ni?-<SD\u0014R\u000e:0eǩ\u001b1i0Qރs\u001e\u0019m\u0013YC\u001f\r\u0002\u0006\u0007l\u001fo;l\u0017<.>[<%\u0013=\u0013[\u0002\u0003QDa\"\u001a'jq$qKc\u0014i3\u001dh Ow4\u0003r\u001fi\u000esO32dp\u000f/c0(\u000eբ0\nItS7\u0010k@빏\u0013\u0003iK,\u0013x+\u001d\u001d-fmQ[֖u+j3z\u0019\u0012_\u001d&\u0003۞ny8\u0012\u0017\u0013D}!\u0012)\n\u001eLHdjDF\"\\\bذ\u000f~h\u001d-D&xyID\u0006|k#\u001cx%\u0013\t:D#}?C\u0018h駐\u00180%-!\u001cÉk\u0018\u0006-i0\u000e0\u000f˰\u001f9#pK9n15\u001bޒn\u001bD(\u000b*@S$i\u0015uqc[ǿ\u0018xFz==<F\b3D\u001aIG\u0006rqi\\\u0012ƅDaӠ\u001c;戴@\\'kM;[ǿ#A2ѫMX2cT\u0019\fM\u0016!Ɣlt.noLLQ{퟇l>[\u000e\u0004\u001dM*\u0019\u00153\u001dI\f\u0016^odRjzZ\u001f\u001d=\u0018\u0019Z\\'?\u0007m{niӺu\u000bJ-~\u001ch_Lgt#X΅v0|˙-V.F{\u001ce\u001f7''mNwC;fnu&ą\u0014@\u0007bX\t\u0010*h\u0013~It1AÚg.|-C*@\nW4\u0015~ o7,i\u0012i0ʝ\u001eҋ3\u0014!Wyΐ\u0001B\u0014{$?kO=\u0002'!?kb\u00020\u001efq\u001eY'InC\u0010\"TC؄L3`B;\u0019曞dٞؑ<\rKA4q\u0011\u0005u\\C\u0005?\u0001\u0007[I\u001f~IXzO~\u001d+\u001a39#\f|g$5y\u0002F\u001f4qL}gۣEyuNv:Y';&mò\u0013l\\swK⩝p3}M4g|ukL}B_sk=\u000b7\u000eI) ?Cf\u0019[bN*K4\ry\u001am\u0006:dMuGu`wB6l\b\u0007n\u0010\u0017\u0017!tCN,t\u0007&t\u0004\u0016D\u0014?1\u0013\u0017q|a\\Ģ9sj̾8\u0011_Bn'ghН9|by&\rn$]e֖EWEO+'pd((jtP(\u0001-\"M\u0005H\u0011p\"DP\u0003i-'\u001a=ɰ\b\u0018\u0003\u000b\u0017'\u001a,,L\f4\u0010\u001f\u000e$/@NH&=[~rk0Ψȍ7/*l̬\u0014,u}J\u0007UY*\bs䣇yNg\u001dVU1;\u001cS\r\u0006m&'o3j:oֶh{;h;zS DW;E>FDi-i\u0007P|O|p\u001c'F\t\u0013\u00140P\u0010\u0019*\u0018i\f\u0016\u001c\u0004.n\u001d0H\u0002u\u0019y;9\u0016I\u0003C\u0006+\u0004\f\f\u0013\u0010\u0018>QjE3=#3v4\u0016\u0000w%Iwҡt)\u001edA@q\u000b\u000e>1\u000e~`Ē<\u0010q\u0007\u0012\"㇎\u0001r\u0014$\u000f%DC[j\u0015\u0003(\u0003\"Y\u0007\u0015U[y\u0002\u001b:\u0002\u001b\u0001 q\\5\u0012h\"M)\ne/\"_4|\u0011)BH\u000b\u001f@(9V\u000bs\u0016(=\"ȁ(\u0017KVqT\tAn\u001arbw\u0010%fobHcaaԟWZ,\u0013E$m;ЉZ@\u001fq UrpCbh-\u0001<Go\\`^]_n\u0006cͥ\u000f:w\u001b\u0003]9M\u0013=\u001f1\u0011'`\u0018E\fFު\u000f$.rt\u00143i<#\u000eq6=OO\u0013AM\u0019o\u0010\u0016s&o'QOu:FJMKM\u0013hdm:X^OOߖƟmW\u001d<7Դ70=3jkuUjZ\u0005Nְv\u0005@b|@\u0005\u0013),q2H\u0006(\u0007v=Km\u0019%``\u001b\u0006Kc\u0012O*Ls\bh \u001a\t9g\u0016k\u000fulX\u000fes$f\u0003/\bpxfg\u0016\u000e,I44Y\u0018xl\"e\u0005f#\u001b\r!3&cavI`l-\u001d\u001ev\bpaHrrtn1\u0010c\u00079`@3\u0018\u0002(\u0004\u0019i,Y<3Hu`pyajf23̋`U\u000e\f4\u001eyq\u0018(\u0005l\u0002\u0013#\\[h^\u0012$q\u00033kA\u0004\u000b \u0001\u0011\u0017\r;no\u001a5P#+\u0013\u001b}RmԞWbk?\u0005@\u000f\u0000\u000bdϺ\u0000-\u001e\u0003ڤ32:my\u0005$\u0007\u0003M˳\u001b\u00078fZfò\fI\u0003/\u000e3QIm\u0013\u000f\nb̬dY&rRFTPY`bu>B5.鈷\u0017?]\u0002Z\u001f\u001bٮ^\u000b\u0005[VBkAlʩ[\\\u0018ܴin\u0014e۱iGV\nռiElZjZ[HiS-Mۯ>;شPz/\u0011i`02\u0004߄g|taz`M|ֳ̏\b:ر(\nJA\u0013O-+N\u000e\f$7D*Nuó놦\u001di!xv\u001dD(\u001dk'\u0016VST]QL[\u0017Icؚt`Vg}?荺pejMW+[C/\u0011Y\u000e662[{a%>25sa]\u0018\u0002\u0018:b$Y=\u0019\u0010ܛad|dQe$6fPb\u0013pb\u001b`\u000b]*Zwb^\\\u00071\f&NILYN:Y\u000f[ يxbn}R}d/\u0000\u0013ĺ8\u0011\u0018v^8\u0018tPu-̵#\"ЗBw<4\u0015y]\u0001\f Z\u000fus^j\u0017\u001br00Q\u0010;y\u000e`@>)砗ѓ{\u0017<GvپCVJMxW^=m&\u0016׳ꭐJ{\u001e\u001ex-Y\u0001eU@&h\u0005r\u0014\u0016r\\d']l\u0017ru\u0007\u001e5uS+\u0000\u0014'*fWZE\b\\u_Aݧzu>U';!\u001b\bSn!uWi匷rk=S:!knl#[^7^\rtX|g\u0019xi\tlÞ]y@ob@N\u001dB_\r_e ~^9@\u001f\u0018[\t,S\u001eg\u0001X\r8\u0014\u0001\u0001W\u0019O\u0016 w9eLD\u0004˛\u001dc\u0000;ӳ\u0005Z0\bsu4P0m\tFw\u0007\u0005Y\t]'u{6=\u0019f\u0013:{\u0015\u0004+\u0010f\u000fHV*W\r\\UKV'V)UW&`$PXQMSZ\u0016\u000ejk:+\u0003+2NpɅhφQJ\"\u0019e6\u001bG\rv)k\u001bg̼Z`\u0006؁\u0019ّ4QnM}\u0007FX\u00136a\u001emQ}#[)G\u0013li-\u001d\u0003\u0016\u0002u\u0006i3\u001b\u0015πM\u0001q\b\u000b~caꜣ\u001a_\u00159;\\xHa\u0007D<o_KnYY|\u0003p\u001e\u001b\u001d\u0013hM[WB7\u0007\u001bI}\u001ejv֕?c3OU]Зe:zhATo\u0016/3v:K~E\u001aU&j\u000f83ީ1z\u0000\u001aʾ<6ߛUG5*U&Gk@}#\u0017hzw\u0005`\u0002`>\fKמ\\:,\u001fczf|\u0001nA&0Soʩ\u0017ex8NMR@N\u001d\u0015zc5^YQND=\u0011\u0005%~wǏC\u001d?\u0010[}oޝ>C\\>\u00127uQ C٩rvɝ?}e͜I꟩iD;F]{QgkS-:{\u001cyk\bH!\u001f\u0016dN+󅸺ծru8\u0012m=ik?ڹgAG\u0005Do.D о;\u0014ݺ[\u0011pvZ_eֺ''}^i\u000fE(\u0013\b\rQ؈P\u0018* @x\u0012\u0018+Amdf\u001c-j=s6Ѻ\u0015\\Z\u001bޭ>Vp)\u0001UZ4\u0002oZT\u001b\u0000KVjmX-mmƑ\u0000M\u00025n\u0005M\u000e,kpv\u001d8[A\u0001CN\u000eC\u0012Ƞ\u000f2Bs\u000f\"\u0012ȴ\"՞Y4GcVf\u0016k\u000fO&VWr-TiIp晃&Vfb\u0005]9*H\u000b#,\u0010OO\u001a5\u0005Spn&e:Aݠ\"$M[{\r1\u0015ᠿn(?Vd&O\\~m~B&U\b\u0010Ao帟gV|7v+p_r\u001aYn췿\u0013x\u001a9 e*B<\u0010\u001b\u0006$.\u0003אDYѳCqYt\u001e7,\u0016Q0\u00167ub~f\u0014I\u00016\u0005U\u001a\u0014V\u0004y\u001a\u0015g\r\"\u0014ԃjx\u001e]<\u0011W\u0003Ye\u001a\u001760as\u0010gC:2a\u001c(\u0015fЩ'̛ri-VKk\u000b_Pa\u0012S$\u0012S\"@\u0014A\"&\u0014Q=ΰqU6\"̨1X\u0016\u0013\u001b$W(vھ8\rF\n\u001afgM(\u0006K0E\u001d\u0007*?\u0007\u0006zPIf5\u001cݼ=1{y\bd(\u000bCC/`c'ƈG\nLʞ9S\u0013\u0013'G0[BOUf|\u0015X:\u0007f`\u0003;M0D!0K\u0019\u0016;2S8Be&ɉ+֙\r.`E\u0018QCHXxa\u000f`Pj\u0014ṅ\u000eL\\\u001e\u0007\u0005)/s3vn+A_6adX\u0019\bGW\u0018NNZoK뤪ƁОgiV]k+P<uK\u000e̩̭̅k\u0005o%\u001aEgE|cV\u000e]wZy$\u0005\rDh\u0003Vaz=\u0013\u001av\u0010\u001f㍄]݇\u00180\u001c)\u0004F#--*w?x\u001a\u0002v)T_Ȗ\u001bZ9;~\u0016ڵ\u0003#Գ\u0005$srB2nL7\u0006+t9:=)\nˍp\u0000qH^^op\u000fݴê&y}\u001a?n\u0002#~c\u0005\u0007\u0006\u0014!2f\u0013#b蝘E&x wg}>\u001d|x\u0013f2\"y\u001bD\u00191\u0006\u0000̋J٠J~>t\u001fˆ\u001bCqd*G\u0006pг+\bX8K\fhQ%Ee(H@,u\u0004S\r&o͋\u001c\u00135.cA\u0005y\u0007CMO@ӶW]{]Iskպ+naZ~u\u000fyoÒ!#`aU\u001b\u001d\u0019t\u000e\f\u0015@b\u001bR]dPc4-\u000bxѦn\u001a!V;:\u0015D\u0013թGV\"V.NivL\u0004A슃uGFX\u0007J\u0001\u0011A[eQ\rUX4\u001eTꎪ،V[\u001d\u0014O]׻{\u001d\u001a;Eu6j+\u0010T\t5\u0000\\cNB:ǫwxфDUU\u001fy\u001bk_7Z6N{|2K3V\u0016Z8VhX\f:GN׭f\tl\u0002hn\u001d\u000b\t__\rթ\u0012wd&\u0016?'H߉2P]\u001b>-%va451iя\u0015MEݝ\u001dN\u0005iO5UaU_|h\u0017\u0015eu\u000e\u001fj]zdXO$.\u0013x\u001bH(;\u0011kYH$\u001d\u0006\u0012\u001e\u0001\u001cI\u001c%G`eF`;1\u000e4wĸ̟Ĉ`>lsQ*+\\̦4ls,T?\u0018p;\u0018PGUCáA\u001d\u0004w(ȃ`\u000fIc\u0006G \u0014P\u001cNu*ZZWjS蝻\u0011\u001efm\u0018zr*\u0001`w\u0011Qj\u0006\u0014eʶYS>MvhFf\u0013;\u001c'nM~M>v\u00006?6O\u0000\u0019?vu[I+\u0016\u00194aGnA:ȶr_֛dۍ[\"E/#j!q\u0018\u00105\bi(\u001a\u0014\u001crD:]U}!\u0010L$:\u0013F)\nHUnT[u5\u0004!,m+_\ntՇKA~\u001dk_7\"V\u001ewd_\t/ym)\u000eb\u00186|,Ʒ*ӌ\u001b_YH3ti6-&l[\u0012\rթ̞G?]qhV^칣\u0006|'?\u0014ݏ27{]d#:9\u001dUm\u000ek3Wm(\u0001yUK\u0017-n/k>\u0007#{\f:<{;,v^[V%Y>dNiT\u001f\u0013/\u0002qA\u001c!@l1^Io\u000euR`h܅Kni\u000fVgՁ\fͱ*MS\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012\u0012п\"\"\"\"Ntu$.m\u0010\u000fTf\u001d<aաIP&\tηV1?j2QPD V;.C\u001c\u000eY8\u00046x24tlyj\u0019e'ae10;\u000eX/\n'k̬[̰Leտ[\u001fGN(H`QQ\u0011\u0005\u0010\u001aI\u0010RjJR:b\tf5\u001c\n\u001cOY\rNh\u0019\u0003vf\rQ&Md\u0010Sjh){y5\u0005\f:\"jtY@\u0015Z\u0007\u001a{gut\u000eV+k\nB/b)2z2y Y% \tCsы)w\u0012\u0003v!\u0013_=d\u0017\u001a\u001b+\u0013WC]\u001ex\u0003\"\u0003≥\u000fr\u001ap\u001e,OkTe\u001dR#+eOj&u\rR\u0010\u0016(A\"J^\u0003FL\u0011Q\u0000\u0012$Y.^\u0001^d2Z%\f\u001f9_XnvۭБ&o\u00118pEH\u00153Re\u00016o\u000b07\u000bȑ=$r\u000e8u,\u0018և_\u001eRɭuE:U\u0019U\t\u001e>Sr,\\CZWf\nvf\u0015뢝=9e74Xg\u001a2M\u0011\u0001D3H%%\u0014Su\\ۡ.G˦h1/\u001f\u001fU(P[]R\u0005\u0000)_mYɚ\u0011wmmy'[ֹylڤ^\u0019d\u0005\\0;\\%ٴejmmV\u0018tu\u0012Ojf+\u001b*ei\u0016hY\u0017\u0000bZaJ6\u0015\u0010iJ\n%ة\u0000\u0016\u0011X46\u001fzYf⫩Ia[\u001c-5~r:zin%\u00141\fDfO\u001d'==d\u0007ʒ9ґ8\u0015BFQ\u0001\u0011@@MH7(\u0018jk\u0016\u0013\u000efT4\nCG+\u0000]ҼQ,]6缮:OiyVG*+zP1\u001b[\u0014\\\u001d2H˝zT\u0002J[m3mj\u0012^\u000fC+zZiijQZ/5Ki\u0017+n:o>6`k\u000b*݋&p^xS\fwUe\f?*pgyϩk\u000bRt\fbO`$^\u0013R9tCt2I\u001d\u000fsj\u0004\u000eHL|tV\u001co\u0010/!BɓYn\bM\u001b]rNc1Gz%\nA\u0014J\u0015⮶Wgtg`l\u0010\nVfG?Kb\u001dhvK%^;i=Ӝ\u000b\u000bsrL[sʶu\u001b.inig\u0011z\u0019ltO;^o}_3Zq)8<\u001f4Q7:k=N;\u0016& ar\u0007\u000b`?K\n${\\\u0019۠͢l\"\u0017\u001bU\u000en<D\u001f\u0004/IxF9Ԣzf\rtB$֧Qc/JiQKRZjd4\u000f#&j\u0014I\u0012`{fly1^i*\u0004U4p\u00184JzEk9JŐ6\u001bgl\b\"\u001fgٞ?$EM\u0001p*JJ0\u0015\u0007HX]\u0018\u0002\bf7ء\u0015g(\u0006\u001d\u001430\b8KgƧzEFM>\u0001\\\u0015T3>z\t&ЪFZit\u001dtZoW\u001f#ݺkߪ¸;\u0006o5\u001e~ֶѡJ\u000f^ũ\u0015/\u00179 s64\u0015<NlPN}\u000f뒚YQiY.2xP;%vػLl.񧕧bv\raj<\u0016u{%\u0012e!3D莎mQ[\u0017m\u001c򪔥㪋l[`*\u000bB`F,\u0010?T\u0005U\u00147\u001bo*7m7\u0001^`C!/Ep\u0016?h؁4v_! ?\u00032G\\ V$\"'O\\uKq\u001a\u0003ݶ&Rs}m(~W\u0007;lK\u0018.dk\u0001\u0005Ɍkn_+gle\u0013ZKݺGۃ3\u0007'ouTݯ2.8+⬅Ce\\jpN\u000eVET\u001fXby`\u0001TҼjONdkFcm0G\u0016.ys;5E\u00064L\"K`V0{\u000e\u001cc\u001d<\u00135G\"8\u0002XT\r|Wݢ&p4\u0010oa[11<GoZb8ibH3ԓF6\naK`%78K=1׉\u001a\u001e\u0010\u0010\u0017:J\u001dݣXo+>ڱ[_bȝ^hq]O͒\u0005m\u001668\u0007m]\u0015\u0010*\u001b*\u0015hU\u0002eGW\u00122\u0001T\u0013u]F6yHKX\u001bbYdBM3d\u001aoh#TE7mCJl&:pn\u0000#b\\H친6RA+aI<i\u0017l\u0016IWŎWbǮE\u00014`Qc뺀\ruIM[\u0015HkevEҤ(`\u00155q=IG2\u0016Db]\u0015ur_[sUxw'UVA.\"\u001cj/Z6Y\u0016w*\u001a\u001bf\u001d\nr$b5\u0002&zdUzmiw\u0019{>{8*ɣ\u0017'SG\u0011CWWQsw*\u0015S\u000e\u00154E)!-fn;\u0007[u7r>ۊ8\u000e\u0018\bs\u0015Cu芹boJM똛\u0012oS|c/V}b*8\r/\u0001\u0007ZBդQ-Ǵ%9`\u001bͲdiX*x\nZ骈6Ne\u001d҆X*cF\u001eQA^\"\u0004\nOip\nGG\u001fG\fi.IIsD凛r;O\u0015x֙k9K\"P-\u0017RUwU WNe֜pLvH\u0004*{\"<oƶyC\u000ewۺ߽Crۚo1֑tt\u001ax=.\tbgLSu\u0014axA\u0001ZΟvk\u0007hr%\u0003I.Dfd\bx*6u{WY\"W\u001aҊ\u000b8\u0007=]$k\u0017v:\u0017\u001bR\f\u0017.UfKIӣ'\u0010k,}W:m-o_Ck3\"\u0001A*\">\u0001ENo(NE-xn˹^t.k唲x%&H&KHZo<ء\u001a\u0011o^HJݦ\u000eU3Yji\u00061\"v\u0012*#l\f\u0005l⯦sETn+16}]n\bt*_~%ˊ\u0013=\u00187UFY|5\u0000/Ĭ\u000b\u0010?sB\u0003CgiסKRɆӳ\r\b\u0013\u0010\u0004hp603vkxI\u0010\u0012-\u0012a\u0005qs\u0014E3n jԟ<\u001b\u001f#˖DK\u0001Ū\bG\u0010+ѓ8&_2\u0001d\u0002z\u0004\t%\u0013K&L@/^2\u0001d\u0002z\u0004\t%\u0013P\t%\u0013K&L@/^2\u0001d\u0002z\u0004\t%\u0013K&yfJa|&\u001d%\u0017b.C\u0013.zOjR9_eJC#/}נG5\u0016%_%j<r\nrLD\u0015\u0016U+\u0007mP\u0002Q4;F\u0002k u\u000b\u001eǰ=}\u000bqkwڊN\u0014G\u000fѫhm*p\u0007/A\tOVt\u0012\u0016IS\u0013ѩ^CW6k&2b\fBZ,\u000b:\u000b,:{eGH̤Ά\u0004@i$2,\u0017\u0015TFh\u0018<T\u00003CD=/\u0012\u0011A\u0010:iԲ\u0019T\u0005R\u001c\u0017hY(keH\u001eugRa\u000bQ&cY /JJ5YP\u001c8\u0006\u000f\fH/4ĲU.&Ϟy'c6\u0015bp$\u00066\u0013t^\u001dc,{\u0007\u0015\fʼ\u001d\bL\u0005\u0005\rdYZ٭wf!¢7\f9H\u000eY+m*\u0004\u0014tQ\u0006Z5B.kh\u0012;\u000b8ۭ&\u0015\b\\\u0002kb\fٳᡶ6Fl%MDm0?Tքse\u001b;\u001bl\u0001j3٢\u0011\u0005\u001a\u001dڴ\feƵvo{JS:%0yH%g.+s8~5C\u0003+.>~n챙'm\u0018A\u001f\u0007C7GנsքU\u0005pfT\u001duKܘCv=)Je6\fӕ\u0005ri{\b誉o}=ng[oG\u001ct\u0003/Wgwv~m|[Cm9\u001b_Ds\u0015'y̬9L\u001eh (p\u0012\u0003!W^KSCș]\u001f9f78E\\\u0017!^\u0014I;S<=M/\fS>\u001ahNc=}f>ZtB>DHO[g{Odbgh4Ь&7\u0000N\u0013mZ輑#\u0017gP%Դ<9(\u000f*k-RMOXZ+\u0016F_iZZ\u0017S\u0016[^*yycŴgt͕jzM==WkItSR2Y\u0013X:eYiu=u\u0016j\u0018MAuvֺ΍Zij\n\u0015}\\WP+}8a5\u0011cX\u0017%\u001e\ni~(\u0018xV`/fEMc\u0007͘u2#\u0019[K\u00065Vs5YI6GgU{\u0014zlh֥YҤ-kU&qN)k\u0017\u0013sBRi:Yq1K1\u001a҃Z\u001d~&tPT,\u001eЂJ8\u0010\u00075V\u000bZ\u0017*nMr׶ZE cpsMݶmzGufRSf}~\u0001l\u001e{\u0005x\u0000|1Uw\u001bب\u0016lO{HbWB\u00056Jlі\u001fԎת5Y\u0010A>C'\u0012w\"\u001f?g=W\rc;\u0000\u001boZ=!)<\u001c'%s%ssb\b\u0004I\tU QF?[OWCz>5ڻ{\u001a=oi3܄\u0007r)OWBKՇMQˮlw5\\\\v\u0019Go}nºkZ\tWەGhp?'\u000e\u001f{CbELh,0+\u0007QmZ\u000b# l\u001aL}\u0014I\u001fD6Q\u0005z8yzwH1^\u0012b\n^v{j%L\u0014TJ̭e\\e\\W⠅qsɜ&v{;_D\u0006ktpפݶb>[\u0019jqM.6e\u0016l[y/<?Ʊ˄ßѺß]ު\u0017Ok\u0005:\r\u001f8x\u0018[&\fR/wx\u0002\u001f0ad\u0002\u001e:w13([މ\u0012\u0018W$M)\u0014,Q*O\u0004)\u001av4=1i#KgMl\u001e4FĩL斿8ˋ\u0010\t;O'\u001eW>5m\u001d?k,\u001bX\u001c5MJ/I؎[\rr+Z\u000e\u0014W^>VKr\u0014yӠNVr\u001d/\u000fiD]Z\u0007#\u0015?mDv\u000fL~n/>|K/\u001d>\u0012_\u0007!m:`p\u0011..o\u001bGRv\u001e߶@KZ|نm\u001d]u=t綶+i?uK\u000eymVKX}Voe6yh\u0003S\u00130\u001eG|\u0011E,nUԡ7&R&\u0012\u001fK6Rh.1YTѶF\u0005n\bP[\u0006\u0018Vyɒp,2y{KMn\u00153\u001f޺\\_C'Hti\u0007'n\u000bmaOg-\t\u001b\u0018wlƜ;ڑ؋W<pIb/2[Q\n\u0017u{t:DWZ|EX\u000e5%u3UhԃC_&DW'\u0011ު1Q~ةoBcY99f\u00167kMy m\u0019.Zh-]i[کmgV\u000f_b6\u0005n}PJ\u000b[Fs8\fwl\u0010%aNL#N.p\u000b\u0011A=\u001a7c\u0013.1䴾huuDa\rM\u001ci}:ksi6ڸiM\tJ0v34\u001b\u0016ʑi\\?\u0003\u0014sV[MTI{%T\t)%\u0003䶴br+]y~V5O?Uֲs%Tח[%o\u00144\u001c\u0014ڼ\u0002*jUִ*e,;x\n\u0005kY\u001bUSO1cQ\u0014̚X+TU$Gu\u0003iMK4?Ow C\u0002v˒{\u0013\u000b<AlϾ^\u0001|?tûou3ᢦHnjX&XYbW5ElYm\u000bHU.V[\"8[Q\u0001e\\Tʽȃ#gVQ\u0000e\u000fY\u0016э\u001a\u00055b/\u0014\u0003Q]CTɮj\\3\u0018%/+u_J6abgu츒ݺvK<[-}\t\u001fQ%XTWYݶ]n\u0004~#dݺz\u001f,IeJے$-\u0017K\u001en[\".s])|\u0011.y\u0001+f,\u000bt)ĭ9-@m\u0004*(W5\nѧ&[eZɺ\u0000zɯ^Gdvu.\u0001ߚσzR\\l\u0012^#`,ٖ~pwU\u0010L].r[j?},toVڪͭ8\u00176\u0000YE\u0001Ky^\u001b$CsoW<\"\u000e7\u0002\u000bKiK-\u0007%\r\\,#\u0019LyL`0g.\u0018\u001d>$\nR8yi\u0013g}\u0004t)v]/VïT\u001b\u001eUq_w/\u0007'\u0014mY'9:IQC2˜>{GwF93f{,\u000fOB\u0004.\u000fEލ\"\u001es\u0000uH\u0012\u001a\u0013]\u0000\u001f߾ׯ^UaEoMo~ӧIcHYv!N../\u0011\u0001.N\rq\u000f\u001fg?_t?ww_%\u0001e7>wы;~^\u001f\u0007y'No|zA\u001c>|xg:\u001e_z/\u000f/Ә}۷ݛO?=]?_ii4q\u000e0\"hCD\u0016=Υ\u000eAkԀ\\cޅyAD\btl#1V\u0013\u001d\u0012}Ck\u0011GH,waL\u001aMr\u001d5F\u0007SSO\r\u0003n\u0006z04ϑ'\u001ekZ~\u0013\u0017o\u0004N=N\rA\u0018\u0001w\u0017\u000b\u0003P\u0014q\u0019fz\u001c\u001d\u0004Q:2H2+\u001dI\f#\u000efi@6dy@_wQxCJ(Uʌf8V\u0005\u001dGDt\n=\tC=Ǜa{b\u001aͫM\u001f\u0016U\u0006˜\u0012xM\u0002tӏz`/OO=hqX\u0006x(S3,\u0019(f(\u0006WA\u0007($$\u000b\rHODn\rQ`H#!\u000bK{:paO\u0003\u001fgLң,Z?a5Ъ#49\u0013\trK8}\t\u001a4>Bfg\u0016\u0000Ml\u001ey&ԢONsO=M3\f9%YF%\u0011Y9#\u0000b/0}gX@l\u0016\u001a\u0019\u001eksH3\u001dI5CGhh\u0016}\u000f\u0007,uz9ڇt\u001e\u0011\nօqט':aM+ʴ\f@\u00027fz6|W7c\u0017Χ?4\u0011Zr%}iw\u001bZn9-\u0017R<E/\u00031&\u0013mGpc>@7}6\u0010\u000b#f\"qi\u0016t\u00130&\f\u000b.\u0017\u001cIX\u0016=7ȑ\u001f[bXh.\u00036\u0007\u0016H^x7cqN\u0003\u001aY#\u001eϟu$\"\u00149\u0012~z\u0000:lAP4\u001f\u0017\u0000\u0017\u001e~Ҭ\u0010w0%\u0001\u000e\u0012\u0012O@#'7#<U\u0011\tAq-H\u000f_S߯HOD\u0015p$)v\u0004M\u0003*3U\u0019蛁B[oG\u0012\u000e\u0012l\u000bHЂ\"t\u001fZ _e\u0007P$v>y\u0013\u0001k.{E3OX\u001bV^nOLR\u0019\u0005fb\u000ehIKw=a/?|\"W4\r{'{\u0017?}|ݏ|ܐ\u0018W\u001f~wg˗ _|\u0013qrgB:lm\fOX\u001b\u0017øяw_\fP\u0003Vj?AcM\u0004\u0014Hdk@G$ݤ|\u0013+{$:~n==\b\u0001L\rSJli2΃\u0005?8.\u000b]F{$HX\ngb|{ȭ;+\u001be1R_c\u0007tN\f\u0000\u0000oHb1ER%BCF\u0014C\u001ewX$\u0011@f\u001ah|i=\u0004\u001e\u0017%\tDL8/7q\u0004e\u000b(xI\u0003BT\u0015W\u0013͈'ʭ(\u0003t\u00121-(\u001a;\"\u0019УҚ'(nLX$=[/|\u00124\u00190h\u0013\u0013!{\u0003(IFƝ/\u001f\u0010JOA&1%\u0003hfZHz\u0015N#\u001c@Ji\u0011i~\u0006oX\f\u001ed\u0004Lv\u0019mՔ'u\u000f9ZD\u0016J\u0000#q\u0004>\u0006\u0007'~C&`*[@\"#%N!'Q87\r'\u0017Zg`K~d\u00169ϚUNb\u0018\u0001\"A2;(\u001b\u000e\t`\\>ӽ\"k9p'\u0015^FZ\u00064 *\u001c\u0018jg~\u0010\u0014\u001d\u001eO\t(s\u0006pH)\"I΃\u000ebD\u0002\u0017\b\u0015Rp9\u0013x>>#Y&:࿣\u0015G\b'򆸐!gb凨#\u001f\r\u0012vIƐ\u0005\u000f$\\5ZU\b}E,ӷrih\u0005X\u0018\u0017Ti^\u0004\u001c]x#Hv}7K\u0002*i\fiR,P\u001e\u0014Q\u000eg[\b\u000e\u0010wѫh+c\t\u0013k&eg!\u0010\tJ,\u001b \u0006@\u00032ehP^$<!ۗhdOK\"ĆӴ\u001e\u0012ŰWNFE\u0016y\u0002La\nOϑslbFTzQ\u0012\u001a!'\"j\u0005\">\u0011-O{1K/qg;@\u0012S\u001fZ~#&n{9H\u000f}^ P\u0012@\u0001\u0010ƉM\f!NO\u0017\u001b\u000f(=v/ck2<8Ѝ\u001e6zC8e\u0015\u0005,}\u00068\u000eLr][Vذ0\u0000\u001e(;dvP-A5^o\u0012\u0014xw\u001f'\u0010I\u001dG\u0010A\u000fִ̉0\feT\u000eKȑ6S\u00077CT\u0001\u001d{t|\u001eEh\u001c4\u0013i'n\u0016\u0003=v\u0000%CbLS2f\b<Y\u000b]\u0002{^8V $\u0000B:\u0014~i\u0014?\u00026\u001e\fZn[\u0013\u001d '\u0006^P.'F\u0014\u0007%\u0003\u0019#tTdbX3\u0014!'9d\t\u000e5]ʴاS/ \u0001=qroP:N\r\u0011Y$\u0000\u000fF)31o#x/\u0016Cj\u0001\u0002=l\u0011n(,\u001buQ)\u000b$W,\u0013d!\u0013侓h\u0003M0sƲR~#wƆ)a\u001egZ}ƹ\b\u001e6,~dR\u0018`\u001e\u0019\u0010b@Ac\u0010`r\rX\b\u0011\\\u0005\u0000Ǹ!\t\u001aX?\u0006\u0017E\u0003܍\u001bMs΢=\u00031'Cni#$\u0017E\u0002Z3dRVƬ`XkY\f\u000fŢIl\u0018\u001ee:XԢ\u001f=C5\u0001\u0011 \u000e$H\\e|I<\u0006\u0006\u0014FqV$*bY1hڬ\u0000H\b&\u001b\u0001k6n-@硗M\u0006|¯j8\u0010\n\u0000򍸞\u0001؁b\u000fJQ\u001eV\r3ܤ\u00034\u0003\t`\bF\r\u0001_UY\u0001X3 \u0012S\u0000\u0005Q2\b)OXU,?\u00141P\u0010\"/jx5\u0010ZÛ(\u0000!BVбd\\M\u0002D\u0000W?\u0002\u0001\u0017X#-`\u0013f?^F2\u0003.E]3dCkb\u0001\"\u0011\u0011\u0012-IR{\rY\u0010~\u0014Nh6]0#X74\f-'34Hle\u0006E \rAQ>S2J,BQ\u00018!I\u0000:\u0005p\u001f\u0015hE4\u0001\\ݑH6#o'AP\u0006#.Wf;\u0016've(pe?C{lF@\u0003\u0010E\u001d@|y4tp$b\u000543;l|I]\u0005=-jX\u0013x\n\u0003@!2\fDd&\u0010H'^!\u0003ؠ\u0019P[\"U=p\u001ee\u001f\u0002\bH&m\u0006 &-\u000by\u001b\u0016KTu N'gCFI0@&\u000f>~)D$@\"\u001e\bҚ@T'Q`:\n\u000b\t]c1↣3}\u0001d\u0013\u0014Ĩ$\u0000\u0011nx#`FlhθO$F,\u00138q\u0007&ˊ@L-3\u0004\u0016Cy;%\f\u0012\u0017x\u000e4O\u000332\u000byaǙy8<\u0003+eG5\u001c0+\u00040\r[\u0006% TYUZQbͱ9/P7WٗT\u001c\u0000\u001e\u0010\u0003V\u0011\u001a\u0000Gh.x#&`a1\u0006At\u0002$GF\u001b1\u0012\u0011\u0005/R\u001726A23\t\f˕5d\u0013\u0002dgj\u0010(\u0013pD,-&a\"T\u0015\u0005C\u001e,dG\u0018.\tk\u001c\u000f\u0010iaaC\u0011Wq%%1T}\u001aɽh#/g\u0017q\u0004OJtU\u000e\u000b֝KtffqXzN] \u0016q_.H?\u001ck:\u0002B7]\u000e+\u001bA\u001dM#\tI\u0018,(\r\r&\u0019\u0002D2e0\u0015\tf4VC]£Rp\r=<豦\u0011\u0010CnlIpc\u0012(\u0005itE+4J\u0018b\u0004W73Cm)S}\u0010KSY\rY\ff$ׅA#\u0000\u0006\u0017UV]jp署7,\f*\u0010\n\u0000\u0001Vx)84U#kx\u0000ha#[~\u0004K7BGA\u001c\u0018h\u0019;r\bc\tty\u0005\u001fʑ?A/\rY'86\u0018\u000ex\u0019\u0014\fE6\n&8L\u0003Se\r%\u0010j(\u0012f+̡2_5Ձ7_ԎW\u0000\u001e6r з͖tXѷnA\u001euw\u0017|&\u0002\u00054bQN'\u000edF\u001cWu\nkC\u001cuh8L\u0007{\u001bꐰ`GH;ܐrG\u001bFmLl\u001d\u001a6\u0016㠸s?r;2tݙc\rsޙH\u001do\u0018\u00061w9R3rԄ\u0001V6Fpˇ\u001fn\u001b:R2Qx\u0018Bl\u001aM;< VD&$\u0013rۣ\u001aV.GeeM7U\u0012[\\puC\u000bnokd`7˹;\u000e[\nMw{b#\u00017L`Fp#k f\u0006u%ō2&Uyjf+\rb07\u00057[]si~nzn\u0014r)nvemݍR&q]b^\u0011\u0005c2?\u0005s\u001dSAje(j{H1幨1nh-E^Xt\rb\u0014\n,4_q\u000eFb1\u001cb<\u0016(b9d4q81\fOя2H\fJ)=\u0019Rh̛\f)o`0\u000f'M\u0005\u000b*Ca`Q\u0019\u001aT*Ck\u000fS>K5iXWo..pCq]3FAb\fzEwDG\u0011QD\u0001\u0003\u001eڋ3w;E~A:r\u001e<@+VG`Cl槜Du\u0005!r?;\"c\u00158|ݩ\u0019lf\u0005i-M{4U\\iK\f`yQ@\u001f?{c+\u001f^ޢ\"\u001a\r%\u0007xA\u001bAd2Tγg/}M;\u0006Cj\u0016\u00008\u000eH-/H6S3#4\u00150\u0002Dp\"L}r7O1iPJW-5W\u001eǷ[zmg\u0011\u000fFs5q\u0014:\u0007`S\u0019䗳tK?6\u0011z7ZâcnR8FR~4kGY vz7u\u0003\u0003\u001ff\t Kl\"\u0006\b\"p\u0014Y:{2\u0004\u0014<\n&U\n\u001cT\b\\\tMz\bb5C\u00128\u0006?QuDy\u0012B\r\b6D`4\u000b\u0002^J\u001c#\u000eOo,\u00063\u0012\u001e\f\u0015*\rpPV@f%4\u0004D\u0010͗ŷ(\u0003 <\"x+u\to8Agqٟ\u001e\u0018<U8\u0019DQ{\u0017b#Y3w>y6?v#[e\u0004\u0003\r<COaօ?D|\u0018pd\u0018[fp\u00168PWbfkr_@u볼\u0000K^^\u001a1/\nc<\u001f\u001dF\u0019@bͭP\u0010%po;\r+0y\u0018kJ}\u0010\"R?˴\u0004Al\",0\\\r\r\u0016+,\tZb3C{_K%\t@M@\t\u0015\u0004oRN\u0015_7=o2{lۊ\rkCP6\rSh\u0016\"a^\bL!8f\u0010/[\r)US-KzXmkqE?tnRB\u001e\rY\u001cU\"j4#\u0015Y|+߮r3[N̗#yr\b\u0016X\u0014\t\u000b\u0000p\u001ai#(%\b\u0016\u000e\u0019TjLAOy\u000b8\n[)\u0007\u0011q\u00001v U%,N[ 3\u0000\u001a\u0001:\u0015Q\u0013v2gCe( 1\u0001\u0016\u0001\"F8ʀ\u0006ߒt0jXB \u0004$_I\u0012bl\u0010I0\"j\u0018W¼\u001d\u000ea,\u000f\fi\u00031Dt=\u001cƊ\u000bc6HT\"*\u001a_\u0007`\u0006AQ|\u001a{CK\r\u0000r1\u0011\u0010\u0003ksnAN\u0018Dr.\u0011\\W;s\"~\t9U߇+\u0018?{br\u0016~7$pe3\u00038\bBㅘ<\u0005sO\u000feH\u0003G\"\u0007\bo-\u000f? :k\u0011\u001ehZ\u0019\"!\u001e\u001a係P\u0018c<\u0014\u0019D\u0014i=\u0005<D\u0004N\bRL\b|݉,ˊhOmC)8\"jo??IP\u001f4~1E\u0004qQw1\b[#\u0013\u0003\r}ʅϢ\u001bK<$sde,\u0016,LId\\&#G\ty2\u0011=8z{G*`e\">\u0018@t\u000eщ\u001fzC@\u000e\n2\u0010dcۻ\u000f\u0016 W\u000f*ܙ\u0018G\u0000\u0019bez@%\u0006R9fnJG$h0X<\u0018\u000b$\b`T\u001d\\ޑ\u00044Ǩ\u0005\u0016ѢÕQ\r\nS~0na3\u0003R\fsɄlQl%V͖ay~[{c;\u001e۲l\u000eޑ\u0006 \\6ݗ@\u001ab8@0\u0000If\u0004\n\u0004e6A\u001c\u001eωX~xN\u001c\u0015s/\u001eInSs\u000bfꥫ\u0012}%ѫx!M\u0002ex<琲x_Y8Xu4'#3\u0002hќCb`\u0001\u0018>L\u001d9^6\u00169yfvhN\u0001B9INWׂ9q\u001d桄n\u000e\u0000:\u0013߳iւ9qZR4s%?k\u001d9d]\u001e!9Y4?J\u001eHI9GeJ!CBE6j8gU\u0012ń\u0015IfQ֍\u001eH-$v/\tw\u000e\u0005\t\f\u001aϙO\u0002<s\u001d>\u0013اT\u0003:\f1i\u0011Oɱ\u0000c*\u0002<\u0005Ԓ,\f\u0010S,\tIɱ\u0000$^$\u000b3$\u000bp`Vd<jI\u0016pC\u0015$\u000b\u0006ɖd-\u00026*$Ybƚ'Y\u0018 $\u0000$\u000b9Cda`ǦK^ZK\u0000<\u001fI\n\u0011y\u0005v\u0013ଡN;U\u0005\u0007\fcu,^ed\u0001#\u0002~ڨTM]s,R,sՉ&\u0002\fX\b\rJ\u0010\b2VX͕iX\u0000Hp\u0006\u0014\u000bX\u000b\t$I:\u0019\u0016VnJ˩4\u000eT\u0000Dg\n6\u0000̥{c\u0003x\tu)\u00003;488\u00001\u0006\u000eڨHd\u0000s]P\u0017\u0007\u0007(\u0013\u0019jpw`\r\n\u000eB\u0006\u001c\u001c\r\u0006\u001c\b\u001c\u001c\u0010\u000f\r\u0003\u0007\u0002\u0000!-8ft\u0001<\u000e\u000eJ(jp@|I\u0000\u000e@ra\u001fJ\u0003\u0007\n\u001cY7p\u0000\u0004T`p\u0019\u0012.\u0001ѬCY\"+lA+\"S\u0016=p\u001c\u0016=\u001fiT}%I\u0005:\u0003g>|_\u0007\u0006.\u0012$\rU\u0004&1W0\u0003[`X\u0019f\u0015\u0011\u001al0L\u000b\u0001c=,\u0007\u0004\"\u001d?B|ĉNzQ\n2\r\u0016\u0003\u0015-S4\u000b9bJ\u000fm\u000eL\u0002\u0004W%\u001936\rob~$R%\u0006Y\u0012>X\u0014\u0004+Z,\u0015\u0004b*\u0004\u0015\u0006\u0012\fYs-4\t#\u001b\u0006&(Ν\u0016%\u0006?\u001e&yC\u0012o\r81\u001b\u0016\u0006o\u0001q*qkb6\u0010B\\mo%sj䜈Z,\u001d%>\u0016m\u0017441y\u0004\u0003ag`}5\u0010@hX|f\u0005P%\u0010=h\u001dq`9>^v;P7\"wW}3|l0J\u001e\u0011,V\u000b3\u001a\u0016Ec:dӎY\\'K|@#?qku|(ޕ֢H͹4i)96\u0019*Вm'ИVL\u0019N!p8ix,\u0018*c,u\u0004\u0018{Z-?AD\u0012\u000b\u000fI(RE%\u0003\u0005\u0001I\u00005w\u0000\"\u001d\\G\u00073AГ\u0010cK!\u000b1R\"D\u001dX\u0006B!I~{\u0003@9gx/ΡVGXcdC!}pa+@m,L\u0010:\u001ba\"\u0016󍮙XT`q!rc\bsv\u0017Š\u0002Tgl\u0003\u000bK!˯Ż3bv**\u001eh\u0004d,v>4`7zh,1%PbaK#5\u001aɢYb\u0005\"g\u0019\u0001\\<\u0001![*@`\u0014(gK? N4Q\u000fY\fܟA\u0017\u0018\u0011\"\u0005Q3%\u0000~aN\u0003\u0004`\\o\u001f{A\u0012b&$L<\u001c4ݼ.8k,W|\\!\u001dy\u0002\u0001\u0000k4DWc%\r6\u0007n8A\u0010$.,2pjj\u00106y[L3K\u000fa=qzQ6\u0003_¨\"Rʦ1VXtk2w\u001a6ɢUKB):\t`J<6T\u0002\u001bD\u0014pBÈQ^%l.Y\\\f<\u000b\b7ݤI\rCZ*$\u0017:\u001bd.ߦY8ip09©48ʇ\u0000I\u0015|#\u0000`^CXf\tT2a^[Sh\u0002Gp+\"D\r7\u000e\u0011}\u0018\u0014 pZ\u001fcvvЙ/8\rsg+\u0016\u001a\u001e\u000e\u0000#Ts-,A\u0017)`A\u0012:?\"\u0016M(\u0005s|R\";~+\b\rI`\u0002q2܅\u0001ե3\u0007Z`>b*҈y!4\by\u0005/k\"DM\u0011HI#:k\u0006J!_ˮ&?\u000b?\u0005B*\u0001\u001aUK$r\u0004aW\u001c\bIE-^3=\u0003$<O{\u0006lyhe1wO\u001b\u0005S2\u0017T\u0017!Sb\u001bqK\u0012>V+3$b\u001a\u000fB\u0003UJD,<r\u001e)%\u001c(_\u000esj3ѓZ\u001c\u0004Oy \u0011\u0002j֞ۀB\u001cq\u0014K\u0003$U\u0003s\u001d\u001bqRg\u00166\u00016~Lzzÿq:\u0001P}1\u0004Z\u0003{pmR\u001c\u0004R{\u0016,At+oll%6=ݥNkb\u0004uR\u0003}^B\u0017|h\u0006:~%Θg3Ih\"*t<gB3ʄ!\u001c.<C\u0017N\t\u0006ƌ\u0012\u0012[\u001e}븉Q4Bu\rӄ\u0019t\u001e[\u001b[ttk{\u0018n6s\b\t2\"R\u0016(i\u0016(9\u0010$W\u0016d4\te2g\u0001OF\u0017=$:thGX)\r\u0018,M\u0011srrQ_-Ta<<9\u001bjќ[yؚ34lsW\u00079s 9\u001eHl\tsn\\\fۃ#U_uT\u0001M<\u000e\u0010\u0015.xb9R2\u0016hGEDO,Q.my$dMm\u001eir\u0007~פ*p\u0019H]lR\u0015iQ*zԪʬMlɵ\u001e\u0000+RoUѸ\rU۪È\fF튘^\u0013\u0018*7Aª\fx$)\u000b\u0016l\u001aE\u001djF.^ͮ4AЮxA\u001eOmR\u0013v\nfۮ5Qޮy4w\u0016/:`\u0013VnG.\u0011r6쮘z{]-&\u0015&r`\u000fwUb]n\u0002][9R'\u0007(GA\u001c\bj\u00144\t\t\u001cP(9\f}~ԟ\u0010\u0006ܐl8\fQ)#fK;\f\u0018~Sf`v6\r\r*nQY\u0019+\u000b'_gOh0Vb\r퀘/~͚-$G|\u0019NIC5Oww\u0001\u0005k\u001aPC#\u0015\u0005]4j\u0018dMr\u001c4P.G<\u001b\u0002ANP:ڐSa:Td܆v;\u0014ޑac\u0001\u001f7\t\u001cevbXt!\fv\u0016w\u001c\"w~(z\u00060\u0015/\\\u000e4\u000e:7\u000bA\u000b̐\u000ffn(r\u0019$\"K9jY@cVL2{J9L.ErL#\u0005\u00058\u0014\u0019LA,h\u0016\"3Qȕn|OP6\"Ȫ\u0011w\u001eR[\\n.Zv\u0003n3A\ry8>\u0013\"j\u001b\u000e\u001b틮d\t\u0010T63M1k=n\u0016T#Uװ\nanuuйշQi\u001cG727Zۢ]\u0019-jW]VkY'8\u000f|4d&<\u0012\u001e=pd\u001e=0|\u00032c\u001a\u0000F\"+\u001d\u0014LEV\u0004\u0000U\nԙ\t0q\f\u001e\u0018n3KJ\u0011$\u0011!\u0015D\f\u0018XB.I\u0019\u0007hN2S\u0001\u001c~\u001f\u001fHvuR\u0002([ʳ9\t\u001d\u0005)`N\u0019\u001a)j0\u000fH>?5hTi.=\u001dpuN\u0002&x,1(o\u000b\u000fp\by)h\u001e%5\u001fhī4rteu\u0014|y4?\u001f\"/޲\f\u0005;h&+A9\u0004+\u0006s,\u001eXG\u0004\u0001%\u0012\u0000,Yw\u0000|h-<}\u00054\u000f9Z\u0006NM\"-ì\u0019<\u0003\u0010\u0018\u001c\u0001\u0005\u0019\tF\to5$\u000b?n<ݬ̀d\u0007mݮl=6U>\u0002?hy\u0004|-Ӏ\u001f\u0011l%c^9\u00031M\"PMƪd\u0004°=Ջ|C*\u001cl\u0010ߨ(*R\u001e\f\u001c8\u0012$\u000endy\u000e&p\u0016X\u0004s0S5.\u001d2T\u0018Vk(\u0006k&{\u0019x,\u0013aY\r/\u000fbR\u0012X\br(}7֩\bt9\u0003\u0011 \u0010R\u0018\u0000G\u0005\u0001̆mv$\u001bOS\u0000G%h9/RQ\nR'!\u001c\b׌\u0016kÁ\u0012wr\u0007\u001b2rfhqA&\u0000%X8I\u001a\u001f-#O&=8\u0007\u00079\u001bHY?\\n\u0019GB\u001c\u0000\u0007\tHTy_\u001dYxa\u001dW^\u001e[zyɚOw\u001b./ZGϗ(2A\u0016\u0013Y\u0007|[TY\u0012\u0016_N \u0011Uh\u0006|V\b|II\u001b\u001c|\u0013S>ؼoZ\u001f\u0004>PN\u0000\u0001uB\u0003ħhN3N||jhVC_]\u0017\u0014sEVJ\b.\u0001xxIF\u000e\u001b\u0002Q-\u001b\u001d{MY#P?%'J@!S*5p\u001adPP(Ѳ\u001c5_\u0015T!wHa+a@JҪ\u0010^*Z\u0010'4\u0003\u0017vVE\rC6 ho]%q\u0014Y2*\u0007\u000b1ڟ\u001c!_\u0010*\u0001qpJLՐ\u0002\u001e\rL\u001e\b\u000eGtr\u0010QQ`XѨ#X-7#[˃Y\u0004lyx-XGӖ2ZC\u0018mT\b2\u0016[fȢDQey(J_x{\nGEkyM[>\u001a}|w4#g3v4)\u00114\\\u0012_Q6Ŀ.U\u000e\u0013N\u001aG\u0004(\u0016IL&\u001aL\u0004$$&K=ޒp\u001c\u001c&cOd\\;Z\u0012\u0013\u0003%ɔ%1AFvNILr*x\u0012WZ\u0012\u0013N$&#\u0018%$&`#l\u0004a.\u0001ɓ L$&p9b\u0002/)-\t̠=1yy4&l\t,]{Z\u001a\u0013\u000e\u0000c\u0011\"S#>\n,&\u0017IL3ZaD.@\u0013\u0018R~{&D@\u0014&\f&Wn>$$0yz0ix%\u0006e\u001f\u0005ɖ$U\u000b׻\u001f\u001d\u000e7o7\u001f><'P~=BHԋZ=2Uw_eJ\u0011cRO\u0013\u0017LDJ\u0006\u0001/\u001e!s\"+\u001e\u0011.&m\nGy^e\u0005<`[8\\*\u0018rQ\u001b\\2c\u0014>\u0016\u0001U\"\u0002;\u0010\u0010\u0015;X5\u001c+\u000eՌrf^\u001d\u0011H&F_ӌ8zMJud_\u001f\u00140\u000ew0JQkZyuZ@\f/\u001e<\u0018\u0013r6N#\u0011_Gr\u0001\u0019Z:\u0000-:\u0012\\y)\u000e\u000e%.8BD\u0005ntq1ΑD\u0017<sIfe\u00102eƕMGsYq\u0016\u0016멫#J\u000edƢ\u000f\"LCp\\1f\u001fQ;\u0012b,vD|o?,q4?JO\u001daȡx\u001c{Ԋ@s\u0006\u001e{]4|X\u0011rh'e\u001f=ʖ<\u0006\u0007'%3\u001bP\u0013G\u0006s,y#3GO9X\tm(l#xRɕgBX^w2ss\u001e1$>.D\u0018\u0001\u0013!d9-1}\r^A\u0012\u001c؃e\u0010|\u001a-\u000b>\u001b\u0014R\u00049\u000e'\u0019\b\u000feޯ>I\u001c}\u0010&IҏB-\u0004lHh\b1Zm-0ENzX*\u0013Dr\bÅߏY=`VZV\u001e!\"VF!\u000f\bWR\u000bY\ficp\u000e\u0000\u00129˷\u0015wp\u0015-\u0002\u0001I\u0016nK#G\u0014VS\u0002W.K\u000eMual^\"\"W\u0003WG\"\u001687R\u0017G\")\n\u0011no\\\u0004f\u0000/\u000b!8u?l\u000bFdA:\u001d82[\u0016R\u0003\tp\u0017ҭ4D\u001b\u001b&\u001aJ̰ ˌp$AR.y\u0016[U-\f[\u000f^\u0004\u0016A\u0015PWJhTJ&c{Y\u0015p)c^\u0005gP9x\u000bwρ9V{Q\u0018\fx\u001cH^\ffݿVW\u0006tgD8qu\bQ\u0013Q\u001b_[-\u001b\u0010ʩS*aU+L\rl\u000e'6\u001dV]gșT\u0019O+R'\"\u001fwZ> ,z?\u000bE\u0003GT\u0015\u0019\u0018Ɛk#\u001d%fK5Fku/?R߳\u001cgZJ^si4}<|\rWyǵT/\u0015lT3^ʧ۫TjVұWļ0VYV@Y^h˗\u0017_v[ċ{F*\u0005tyfKzbuK1U\fx\u00053\u0016șQR\u000b<fQRWͨ_kisܜro5pNx\u0013k/2\u0010u/F9vGdh\u001b/|)K9|\r+\u0012~2̟U/\u0007ذ_/\u001bh\\+\u000b:#/Gj_`\f]x𪇍\u0011]\u0016\u0002\u001b\u0007*\u000f\u001a]@򺎍 \u001fyV#҅2%\bo^r҅</KRlE/sR^.yzFBʚ.ZMuFg#\u0013{-Oާ^\u0017í|I^_\u0005zC\b^\u0015\u0004/ij:W>mT\r\u001aWQuūֺdu\u0015붺]\u001buʫbU1zugMʴ\bz\u0005Fa,Zp]񴒹~ju]ڻz^W~Z7NA\fH\u0000\u0000\u0005Ƃ@\b*ތC\nC\u001c\u0011\t\u001dK\u0011cr<O,2R\u00179K\u0000V\u0018\u000f2ɑ3QU9e~MP3Qp^92_F4\u0015p\u0013j\u0017\u0004F<!lBN(.\u0017\u000e<ҫீjFː\nΑ]Б\u0003?[\u00196rP2@|\n\u00121巙J\u00181sjȓ:\tXR@W\u0007\u001b.\b`\u0000.4z9-\u0004׍ڪM\"K\"q8V?!9g9\rb\bS\u00042;.𕇂L?\rU\u00014*o\u0016Oxd<#\u0005\tnb\u0003\u0004؅%\u0011*1o\u0017Od%>WJA\u000fc&\u0017}I#w8*U=Hi+ʙH\bd74\nWBrP/A#;Fldj$\u001db-gd?\u0005H(m!=@\u0004\u0012 \\{ThR?Hh&\f\u0018\u0017\u0016:_i\r?s\u0015cxEژeb7sfP\u0013\u0002Q2\bx\u00178=AK1\u0012kL<'<\u0015fG(er\u0003F]ˁQ\u0000ZH\u0010\u00079)刉3\u0019Dib\u000f\u0016H&\u001a%\u000e^DJ\u0007?p^Z\u0011\nK40\u0005t\r7\b2ܜB\u00182I8I\t\u000e0/\u001eU`2\u0001G)\u0005\u0013:\u0013\t4L]8M0\u001f\u0007\u0013LM\u0012f!քوi5E\u0013Tz\u0016Mp/iC\\NGB\f!*(oj\u0017SNjMO#X'Q,n\u001e\bgp5\u0002G W`{df*IEQS]hQщ?\b\u0014jA\t\u0013%YYJ#va:\t\u0016L&\u0010x15\u00144~%|\u0012,(xa\u001eƙ(h\u001e!8aƒ2咻VK\u001aJ(eb\\Y\u0005-#K\u0015\u0004t\u001e\u001dS|C96d\u0015d0\u001ft%:E,0l<H\u0006\u000e\u0013Y)OHzj{\u001f\u0014i*u\u0001\u0012CRx)N\u0003B\u0002-U%^\u0003'\u0018$X\u001c{\u001a\u0010\u001f\u0001L\u0015<%^\f\\!Ts\u0010*G{l\u00067yK\u0006|$\u001ce2,\u0019R\u0005|\u0015qثBT\u001bղQHΗv\u0004\u001dkÀ\u001d*eb9\u001cvMȤ3\u000700oYB}[;dlVL8aچ8!_^\u000e\r7T!d2;t0\"\u000eY;uX\t\r!w\t!\u0013\u001cpwqy1\u000e;/j8;2[q5\u00184-\u000b$ԭ\u0014\ruc3f7x8.Gj&_0`6\u0016\u0017\u0014\u0015nq:\u001bGjQ:\u0012\\(rS#<ig+\u0017Ċ\u0016\u0016R\u001b\\sZ#!%b3ixP>\u0017^$\u0002\u000e\u001b9M./\u0019ebeojO\u0017BڈnIu9I/rZv]Mq\u0003pθ\u001e7&jFFr㴫Zn6m̭܍pW`\n\u001b\u001bE[]tK~5\u0015`Jn\u001eaJu+\u00047\n\u0017\u0012vE݋\r2E\u001bߋ\u0017;8Ս\u001d@*\u000e4{jd\u0007$\u0016M\u0019g7@C ^ǹJy\u0006\fv)4xMh\u0006W0)P\u0019\u000eʰ\u0010S\u0019^|\n\u001cQ-Q\u0007ʬ\u001b@v[[^֔sƠ\u0001;&G,`0!l\u0007\be#Z)fI\ba =\u0006w#2CP~^yE\u000504Ŝ!Di=J9{iՒGF>4YO\u000f\rߘ\u0010G'd^ТW\\)\u0001D\"\u0004\u0016uhK_|ӭ97\u000b!8zd\u001fk̉`^9f9O\u0016KJWScʃYu6~/x<H\u0014sUq\u001fQYudSٯNBޓs\n_\u000e\"+0Vi\u0014ae\fU\u0001V\\\u0017VhsG۽oEJ\u001723XJSL2S\u001bV\u0018\u0015\\dSX\u0015\u001a-Z8*\u000eV\u0015G$u\u0005ar 0\u0000j5b#\u0014QhhVI\u0016oS^o6\u0011YI\u001bu-ʵLN-D3\u0016\u0010\u0006nS8f<-[\u00024\u001d~=\u0015-Onu7z>\u0010VR+\u000f7c\u0015}콊ϏW;nѫ\"t{d_\u0011\f2̾R/B/G\u00048T8굧,-ɘF\u000f\u000fP\u0002[߱e,8kLNsڻc5\ns\u0010<f\u0012|a\tf\u0001)qŊ`+\u0007*X.9ח`\f^>\"[YmIW鲯7>Xg\u001dW,ֆl\u001bB\u0001Q-FP\u0013Bu\u001aˉNx_&CkC[b\u001b4by)XES҇sg4//v\tVcX\u001cG)\u0019<ISRLapD<E\u0005\u0011d\u0006<\u0007\u0010r8\u0018v\u001c֛cgK$\r\\Cd\u0000.\"lM\u0000CAZQԀzϙk\u0006[I\tYP\u0017\u001d \u0011\u0000\u001cg$\u0018\u001bX&$y͹+dMK+:x3\u0001&̐O9)\rHT\u0002\u000fd\u001d\u0016\u001b_\u0000\u0013d\u0013a\u0014_\u0006qe;X\u0014G(2F}#NZ*rd5I>A>\rm{}ir\u001f\u00044f?0.\u0016{R1E[n6!\u0005D\u00032\u0013R$Z R\u0010l\u0016h\u0004v2\u0002@$M;HI4\u00134$Db\",\u0007ƚ_ђE!O\\F\u0011s\r\u0010k]\u001a\u0004\u001e)\u0003\u0016orO5]\u000e?iH\n\u0004j=]\u001bֿROObЭLo\u0015jqT@qb\u000bAA\u0010v\u000b5s\u001bC\u00179H\u0015΍V\u000bB/\u0017j!^؅Ί;r\u0016<tΖ\r(z\u0007\u0006\"\",\bW\u0005iuW<t幬\bryv+ܾ\u0015U.ca}>s;Vǹz\u0019ЍZ7iPL\u0018\u0000W{\u0019\by4\u0007'\f|$'M\u0012FQ\u0003\u000e;Me2OS\u0019ZQU2I\u0002+\u0018gլ2~-ғ-ʓB,Oo\u000byK_>\u001a}\u001eF%j,]lK!\u001c1H\u0006W@\u0003\u001eE@}.E\fV@\u0002=TA\u0006jc(\u0015\u001e\u0017\u0019[G\u00006bF$\ra0g\u0014+-\u0011}5rRY\n%rd#ދQI[r\u0011eNw\u0000#\u001df.kL\"'<x\u0011sGĩUwp\u001eS\u0014\r\u0003`Y<C.#la\u0015!f+m:{\u0002C\u0018h\u001b(:3\u000ey]sC0dF\u0017\u0016\f\u0010dI\nZ~{!\"V\bݼ)?wZ2##f7m6y.Eh\u0004\u001d&&ΤPҮ٧ռ1L֐}B=MޤV9BMӃ<?sO7HI\u00043ٛ<2wS플?{߮;ңGi&\u0015g\u0012}C\u0014,sֹ2f\u001dq}:l3L;fkL;lҍ)0O;mvP\u0017+E\\iG\b1\\\u001d\u000el\u0018ym?iUNj9{Iavn9ivv\u0014=uQϮħ\u001db\u000eĬ,\u0006Ym)k\u000evcƬ~3t5\u00101|zV)dC[g\u001eqt\u0010Pf\u000f¼og?\u001fo7\u0015V\u0014-`CFN2Jt\u0010IPYyn:\u0002DubS\u000fmz.M\bXro)RqQWlTKlBwȩ\\>u_dS=A((j\u0017r0\u0014Z~S\u0015\u0011$8ю8q7jf%Ad\u0011<q\fZT\u0005Z]7b;\u001a5<wWM\u0005P\"\u0003\t)\u0011܂z8\u001arCkЭԘ1\u0011xة\u0018{.U;qz\\@S}>}U_x\u0019|'\u0014-X\u0001\"\t\u001el*\u001fK\u0002\u001f;|<-Eu(Ҝ\u0019\u0017&XU |Wh\u0013\u0006ʎ\fN;\u00037\u0014y*퇸'4I\u0005_w\u000f|w{>\u0002}\u001fc{\u001fqC^M6pyFbwt;sK̰ԞIoEjhg>iV_\u001avYI*Pe\u001d\u0015aLoVX7\n~3g70MhRU\u0005o\b\u001b_Q\t)u_wKx?'?3\u000eGN_\u0010\u001d/T\u0019ᯩ+X>fWC\u0017bWq\u001bFU)f*L&Z\u001eMoz\bW\u000fݥ*\u001e\u0012\bnj5-\f\u0000RB۲l.siXD\u001f8ӯ_W\u0014W\u00053xm.ٌJ\b\u001e=Y=?\u0011£l\u001aV+x?/U\u001e\u0018$c\u0015z\u0002\u0006\u000e1'>Xe_QKF΋1}Jb:~*\u0016c}]ڲ\u0018\u001e\u0015tb1Z/ƨDyY\nk\u0018K<X9nͼ\u001a#:\t-jAb5.[ϲ\u001aR՘3kQ$\u0000՘W\u00067W㢰\tWcR\u00189j\u001a\u0017\u0012^_OGɞ짥OV,+Y6z\u0018\u0016s\u0001g\u0005hE\u001fPn5*=ofN9\u0014\u0016ac$\u0006}1nE=/Sm\b?b&GDk'r\\U\u0000޼\u00167֖'i\u001ec-d=ͺ\u00167\u0006\n\u000bZ\u0000@䜯ŴX\u0016.;_ny-ni-~X\u001ay-;A\u00167\u0011}jD\n:/t\u000f$\u0017Hc=iǮn^>\u0016cX\u001b?Y]pkZ\u0018κ\u001cQ\\\u001d^2-|p_y\f.qqƣGXҺ7\u001cFTJ,,\u001cYrLTGjW\u001cL J.D\\kZ[*{j~\u001ag '\u0012S@^\u0001\u0011S^V$(\u001eaxtdTN\u0011z\u001e2*\u001b\u0007\u0001dPNUA2ruj\u001aA9\u001beFP\u000eI\b\u00058\bʑ9W\u0014eP+x\u0019n&\u001c%(ǐjp*PHΠ\u001c_\u001d[<(wZ\u0007L`r+\u0011󠜎C\u001cG~bTw.\u0019\u00173.7C[\u0014\u0015\u0014ܳ=㦗56\u0004)\u001eĉ\u0019#4C\u0017@쏸\u0000\u0004B\u001f\u0007⿆u_C5wTسnˡҹ\u0005\u0014mT.[\u001dw2v,\u0005bw\u000bM}\u0016\f/vlZ6T\u0018\u0005-,TeǗ-\t\tUX\u000fr\u001b\u0001-orqss\u0017k/[\u0012ͭ0tViӿ26a:\u0004F6K^ 7\\ss+\u0015Ehn-j\u0015R\u0005ooE\u0019Hn(ZGnѨr|wz;!w贻0nIIiz[6A0\u001f\u001fv#`h\u001dl0g\b\fj\bu\u00165Q\u0015C/|:\r$\u001c3jv)\u0019\u000fq{Y\r4cg\u0016]y\u000fU.f~\u0014kSmUQe:pw`\u0013_)x*\u000b_!@s\u0017x$mt6\b#=\u001cOP\u0012^]?n=+!\u0004~\u0015\u0004l!\u000fU\"\u0012_W\u000f4\u0006wIA\u0016`\"\u0005\u0004q)u[qy;P\u000f\u0018iZb\u001eEǻ,a\u0016\u0015_8\bKb(\b\u0000Vz`\t\u0004`\u0005qy,\u0014r\u001c*i>?7*{T$e\tz\u001aI\u0010>0C\\\u0001Q݉e\u0003i$'\u00079n]\thqaٜICϹyw9 r9=6N\u0014/E\u001c\u0004&iӤ;c\u000b +$NO.6Sv\u000bjݶ\t%.6m\bl\u000e뾜x\u0018y^ݯ3\"hQm\f\u0012$KЌ%ota\u0019z#j:w\u001aň\rq!\u0017@S\u00043iG`7\u0012l1TzZ[<\u0014NKe[i\u0012\\<\u0012q!:bv6f\u0010\u0019iԬ;$H\u0010#jQm|Dc]6be1E{adj\u00196n-\u0007S\u0010\u0003\u0017D,\n\u0011\"\u001e5H\u0010H\u0005p:hldա#))D圾w֌Ϣ@+!\u001b\u001ax\u0003j)9(s\u0010U\u0015\u0010%N)\u001e\n{\u001eRԦ\u0002t\u00115` h֔k,\u0007A߰\u001fgʂBAW氵\"m`\u0013<K1+Fi8붫R8'}HQo%ے\u0006C\b\u0007qcJj?ZQv-\f\u001dy\\Q3\u00124\u0012'e´u\u0011\u0018ntr\u000bY/Z\u0013w\r[v6rS׳q\u001d7Ve< m\u000f`n\u0003'޲9\u0000\u0006\u0005rRs\u001c(0q\u0018#aH]\nxes-cT)G\u0005{Y\u00102\u001fŋDh\u0011pP_R:t啮'\nD@]s\u0017\b**s\n,sOQ{y9\\\u001ey\f)&<ߑQPw΋8ɹ8Osc9.*b\rZ­lY\u001d\u001dIy9pqrm\u0014G.$vkA\u0005gu_\u0005+GՃ/^UR\u0016>4\u0012κ.<ac\u001fbILcAUӺK`L<3x\u0013c\u0005\u001fyOk\u0003D\u000e\u0001ted+^Z#\u000b\u001bKh|23iM\"\"VoF*\u0014{Bt\u001cGLbD5Y\\v:#]\u000b؆G\u001awzq\u0013yô\u001f\u000eo2\u000b[>Le\u0015cZo\u0018\u000e,ߤ\u0011N.s\u0014\u0016g4\"\u0019\u0005t\u0019uZ\u0016\u0007:t\u0014әg\u000brk@R\u0000}(\u0017s^\u0019\u001anD8‹cUx\nZ\u001b \u0016)M͔l\u0002\u0014%\u0013qI9\u001flM*Zc'\u001disn\u00037\u0003~Oq\\l+Kz2)*lQ%\u0018[Y<$\u001d]j<Ŷخ `\u0001>w?\u0007nګc+[e,Y-\"0\u001aXq\u001b\fl5y\u0019\u001aKY\u0004UWɟ3\u00191b\u0005z;`R{l\n~'\u0011xqI5\u001cͰR{/rY-\u0014/6tqE6S(\u0011hYݛGw>_k\u0003shoPmA[n*\u0007\u000f\u0001\u001a\u001b=\\p<\u0003\u0005wgE\u001dⵋgzpx\u0019o\u000f\u0012Y\u000b\u0010~}ge2A[\u0005Pw.6v>=@J,uz\u000fN;q\u000b!;#`Xo(WNR73nޘ\u0011hW4 g!V]YHŪ$]11Q&\u0010\u001eA#3#\u000b\u0006^N\u0016WD<lka9\u0018$}ɹz\u001b\u0000*ApuB8tvf'5%'J0M\u001bB߹+u\u0018:Hb\u000fg4K.k\u0016%+er\n]|cW\u0012\\őq>-'W0\u001d\u0017\u0004\f\u001a\u0016Z^=\f^[\"\fKx5l\u0015x\u001aPArc8HT]\u0017?-JT\u001eeuxyLLj)!ؐ]x\nٛ\u001bXՈ.ꚻ\u001a}jn%aex\u0002jO*WCV@L\rq\u0017?ӷr;eA4(슨NoW^ꭹ'JWsx+;Z\\1w\u0012X\u000es\r\u0007ܺn1ߔȶn=x[TlԦ-l\u0018JEC}\u0015f{)ȎK{4;b/qV =%Mu8<@[7/c\u0013\u000eOr\tج2L-kl{\u0011m\u0006ZEfecݐW\u001f\u0018,uZYZ4N^PG\u0017\u0000\u0002~\u001c\u0001\u0005F߸\u001ew0O{h|\u0001\u0000&\u000b0B2\u001c{\u000fTUJ\u001e䱗1aX-yQ\u0011\u0019\u0017\u001e!e@\u0007\u0003[\u0015AFj\bh\u00131Fl<\bX2p2&+v9\u000637\f\u0003xPa\f).F\u001e\u0015dd\u0019\\^ƌvK\u0011|#p\u0019_i\"C9dvq23S}s<e\u001494|\u0011e^uN\u0019):CT3>\u0016e\"A\\v@.Y\ne-S\u0006򗩅\\&30R,Knf3ri΄G.#S2/Ú@Xe\\Zd&\\y[fwf\u0013\":P\u001a\u000eT\u0019\u0014e*,.sodf7q$ҝ\u0004]xǛ\u001dӑ;~{5\\\u001c]\fGyd Ù\u001e\u001e\tpG3̍.n~Ps;y2d>vYd67 ڍ-J$\u0013ǆgcS4ridc܇e{ٯe6<u#c\u001e[YJ,}l7G6ޖl_Ge@lqG\u0005\u0015nA[f]VkսM86S\u0017\u0017\u001f1\u001e2dd\u001fPBF\u000fX΋ CV\u001a\b\u0014fD\u0004\u0005\\F*\u0002 `\u0006T\u0004Jq\u0011P\u0019\u0015A\u0011\\[\u0004q'DG\u0011\u0013\u001aw#FyҸ\u0011\u001a?BU9!<#5y%|秀+B\u001bgZ^U\u0016\u000e\u001c\nO+\u0013KXl\u0000mV}9@\t.ӄ<!q1ns4g=d!Z23,v3qŵ޿r܋ݎ|\u0013_j2\nҡ\"c7qWwף\u0014j}a/ެY[֪\u0018}.I\u000638\u0014w<,=?\u001b\u0000}<pH`ٕBbˢ\f{ɸ,\u0019-H֔<N|\rB5q\u000fY1wo\\[\u001e7Gw~x\b\u0001\"jkf\u0019#hb:n yE6}?\u0012_u\u001e|\u00195[C(\u0019\u001f{dI\fqEQ\u0018c[e>x\u0012iGGƆ8tcB\u000bAS-3Em\b\u001eA;ayYQdQ\u0012E\u001a\rrr[Tm7 .\u0004Ē\u0014Њ#\u0015J7v)\u001ay\u0016\u0013SfXm%RQ\u001c\u00063\u001cKAz\u0018\u0003\"\u0003Q1B\u00199JdvTsFp~\u0010Rb\u0004/_~\rϸ0'KAݮi=zNȗ\u0017:|݋^*;\u0010\u0013I\u0012\nP\u001bv>q\u001f\u000eĠȋX3خǘ/i jXRZ\"q\\~VsLN\u001fƼ,h^>\u0011\u000bQgΫ\u001d]nP2\u000e7oC[+TƕPQ {JOx \fECW`́i-#9\b\u001eWVyE\r!y3G.6\u001cQ,_\u0019R^YmyV.2޼\u001b\rˉ`9aI%QN>˳I*yc9.\"bc\u0019^qgD\u000fq\u000fԌ6kQ:a(\u0017q?{+Ҹٸٸ0Z\u0001ƅl\u0005ƅl\u0005ƅl\u0005\\\u001a\u0017\u00150\u001b\u0017\u0015pn\\Nh\\xW#ҸٸٸKB6\u0002fB4\u0002fBv\u0002.\u000b\t\u000b\t=\t\t.d't\\/EBv\u0002.\u000b\t\u000b\t\u000b\t.d+]Vѻ\u0010KB\u0002fB\u0002fB\u0002.\u000b\n\u000b\n\u0018\u000b\u0007ezĦR#\u000eݹ'C'8\u0001\\'ZBmg:9\u001d'\u001cyB'g\u0010ݗL:9;\u0019*WC'!\u0011\blż//\\K\u001c>[/h:9T\f\u001c>&͗\u0004;P\u0007\bhP\u000e\u001d.Ha\u0010/w\nN\u0017\u001dB9{0\u0000S)',vfH^?\u0019R9>KE(rզV\u000e}j9\u0014^{/?1r\u0016!q\n|J尒\u001d6G~*|K\u001b:9?ǂգNr\bLI&G%[Er<$2Qߺ\u0005\u000fi}C+bRHHC)$fT\nYfT\n\u0019)BrBre:JR)$!\u00142OG\u0014\u0012Q*tJ!tJ!9\u001f\r\u0010T<\u001f\rTHGC*dTHGC*$f\u00152GC,$!\u0016\u0012P\u000b磡\u0016\u0012\u000b=\u0006\u000fP[?4\u001d\u001dXǧVT4\u001f\u001d*\u0016\u001aR\u001dx}K\u00108ݔm!6<K6\u001fo}tB=f\\uB~wJ3\u0004|6j/zk2BgwHH䡑\u0010C#!\u0004W\u0010L\u001eU\u0016^ʖ\u0012\tY1K$\\H\b!\u0010rɫDB%\u000fK\u001e\u0012\t!J$\\Hh)h\u0015\u0012\t!J$\\H\b)uyDB%DB%FB%/\u001a\t)\u001a\t\u001a\tsߢ4\u0000\bK\\`\u000e\b.ZO١=oǿ8֜\fj&)C\u00170#\u0017O\u0011? \u0002\u000b$\u0006\n6=+e+ɻ6\u000e\u0011\u0001T\u0006E\u000e1>\u000ey\u001b!;+<R3V+%Gq\u0012VX\u0015j2R}MMxm=؉Q=Ì\u0014?qF\u0016r$9k6<\u0015\u000eISlF\u001bQye\u0002v*\u0000\u0017Ooi\u001eŶ{Ӣʼ_0u\u00072*}\u0018ٚ:'sj:j\"DY'\u001ci5d@إ\u0011b`^>jDʟIYD3n\u0010TN1\u0006;\u0018lkF;x}N/gD\u001f#V\u0014Ib\u0013rTGY1GY^Y\u000eļ\u001c˯́w#\u0007ޱL76^mGz+#B|ue/c\u0015\txKTqf;\u0018KL\u001fAy@r\u0014wP\f0+V]&ќS<NjU]<C%J积lp$8\u0005Q-e\u001eӻ4ŕ\u0017ϼap7]=\u0007\\T\u0006V; 8KxH\ro\u0012,-[lzá;\u001eq%*L8\u001dUesl\u0012W{uW8!zZgS/ٽ\u001fUIRvh9>\u0003\u0007OzJϊKe{>N|_wT^۔˟\"Z|^WE\bO9^4UC.+\u0004j\u000fgאJ\\\u001a\u0006֞yoZX9&p\u001a\u0018UcDN(TE7Rul5\tV}7t^h4$\n\u0011hnz٣̀yάbYJ6$\u001b{\u0007~iPG2\u001f(ܮxF[%b\"nʹ\tY^W\ts\u001co1\u001e=\u001b9G$6=7K\u0018>sOtChֱ%Ut0\u001cJ~S4g[;*\u0010#U^k87&{]\u0016&\u001e[o\nK'\t?\u000bϲ>J Q'>R\tn]Vel\u0015+\u000bX\u0013\u001f<V\u001c4ޟl$\u001ed\u0003rYͺݭ;,\n^[<8˻(\u0005\u000e\u0006e_q\u0011Iqڪ~\u000e\t*U/o/oA\f|\u001aw\\~)=gʑ\"rj].`evL[\r=^\u0006I\u0019Ta[b\u0000>\u0003\u000e-\u001fp:iqb]Fj]ILU\u0012L-يۣW(MV^rZ:3O9;77k~R=\u0019varejjN\u0010\fu\u0000\u0002pһVsj\u0001\u0012?%׀o\u0011Vbm\u001eT׋Ԝ X:nIk6Aض\u0000ڭV?\u0011Z_\u0007(k>\u001c\u001fCW\nlڼ\u0018E\u0010.\u0007+μ,H|VTk#Rȍ+MjH-x\"{6{8'\u0015R_aP$A)N\u0001~կyۍՙ\u0016eg³g7\f\u001d\bs\u0005skvM\nh?m)0~X􎊌\u00055!&]lZBV3|v/\u001eLoH`[w|VZLk^\u001b\u001b\u0013^>gм\u001fT靖9n\u0019\u000192EYG'\u0013\u001eO\u001cZ-Oǯ|ԫ9\u00063gկ\u0003y}`?2vZ_2fn},91߬za\\;Ό\rm;\u0017Z^J\u001b.=-U].f\u0004A\u00147\nj4\u0010\u0018ǤʲI[}L^\b\u000f]}=fB6~\r,q/xYks=\u001b-fgd|۵7}LS3VtX5t\u001f5Ț\u000bM\u001d\u0002?*D'\u0001^%EP_ԎOEWp~zl\u0014\u0019[i\u0005-\u0011^V5|c=Ɖ2`s,iYV\u0003jL\u001f9/Q\\k4]\nM\u0014\u001b}Ik9(H?5]!Ly\u0015*Tth\u0007\"ᥕ4hSK\n:3m&Jz+.ID\\\u0017ot')sDw_\fc){iGFմݍ7Xf)\u000f\u0014:g\u001e><6\u0001\u0018-ol\u0013{Y=@K\u001dTx9\u001aŶDUeݼ\u001cPq{ZF ̀U:;*>)Y\u001d\u0017U8]Ӷ޺ؼ!\u001bۻ˳Y6y\u0014|ክ$*j7HP1RtHcb im\u000f]b|Za\u0001e\u0006U#z^I*Ȟ\\\u001cWqc\u0019u:36eW3oX8b\u000bTɵ~\u0011nU\"GĻ:H]XȬ)\u001eIb*\u0007]`+' B`~e<Zz^U\u000f8nv\u0016\u000fG8=\u0014\u001eBe,\rt&x\u0012*\u0011B?4ퟤy^ZCc 踐x-\u000f\tkcy9\u00184U\u001e\u0000cr\u001aX>iO\u001c5gZx+TXwG]QZ\u00177Xh Sz\u000e\u0016\u0011=^ujۼ\u0004\u0007|3&ƬAWVB6\u0017sOӁ^x\u0011\u0013\u0014Y\u000ec\u0006P#*9ug6o:PMh\u0015t-\u00135y̪HDyL<g\f7\u0003/p12Z@\u0003\u001fǚAgg\bWAlg\rcZ\u0006ݿXm592Z|ͣtw4\u0015T?iwnMN@\u001a/Z|en\u0014~m\u0001X{߅31\u0019hT\u0017\u001b\tڼ_\u001cN\u0016\u001cW?G\u0015ƴD!ӱbn;`%\u001fK'\rK's\u001c-\u0004SfCH&\u001b,<pq¿Y}釪/E/_<V[)h!oRuҶU\u0017\n\u0018p\u001c\u0018.*`pԭ\u000eqܛ̔ܜ\u0012Pz84}w\u0017ʑG\u0003W6/2Rw\u0018[\u0019t5\u0007n*]\"ŮHNoڏK\u0015(%-\u0018\u001fs\u0015~|Az~@lɬݹ\u0000`7/-}\u0010~\u001c;LMц\u0015\u001bQU#d{U\u001aNv\u001f{Z5=t}i1;GSԛn74!ĎucN|7\u0005mD\u0006UʰPڹ\n22@mqad|\u0011\u001b88.b\u001dҲ|gZ\"2?0˯h͸\u0017\u0011\u0015qF|h!'\u0014IFLj<[Q\u0011uD\u001cl\fq\u00181uF-urg\u001coyA2ޗQ\u0004M6Ftq\u001e:̜۟$2HF&B9'e5.[Fms\nnΒ\u0019\u0001Ҍ\u0013|䜒3\u0019=׹\u0002d;W/s<|(\u00117ϕ_<ܫX\"\u0006\u001fkXꗕ.C\u001ef\u001eX\"5\u0013\rc\u000eò1k\f \u001f\u0010ygD.\u001be\u0019pm\"3ܟnRq3\u001a.W\u0016,rPÃ<\"z\u001a^cҳ\u001cz-\u001d\rg֓v˛3\u0013.v\u0013\u0015ϔcz뙚\\LaY\u001dd2tCd7\u001aV͝Hf_\rKfis_\u0013dw e^8Q9V&XsӖeN{|\u0018Df\n}kf=#\u001d\u001f֑77Slu\rZ|b\u0019W7bM\u0017U26ݔY]qi\u001c7ٞy.\b\u0011b_{\u00030Ś.PD\u000bb\nWP b\nJ\u0003\u000f\u0012e<X'\u0004\u001b\b`\u00106P\u001c\"\u000e2>)B%}\u0011P:_U]GtF##3nDy\rAF(o~!|\u0019\u001a;Xr\u000eS\f1-c*@[V\u0012v%\t\u0019F\u001emQE\u001bt]Ni?\"oYrX[aϓOgJ90,qo\u001cwB/t:ϳ9ս\fc\u0015q8]Z\u000e\u001d\u0005\u001b&F?>)\r}_ݑ5+\u0005F:Dn\u0012ß8g\b7q~>~\u0006Jy\f<Lk}t\u000f(^=?\u0010ڄ$\u0019F*ȥ\u001c\u001d!1=q\u0018\u001fH]h\u000br۸b\u001fO\u0011bK͕9l:dyav\u0007m_QF\u0017\u001eTϚ$vW1\u001d&?SITqMh$m֏!ٲjCFsC8|7\u0011B`G3\u0004^{²QPOo!éҖ*\u0010z]Ee\\\u0007\tT9l<gm5h)cg6K)ѫ\rjfО\u0012\u001f혩Z&Zy,\u0002!`vJǃ:<1}1>kwA;[PS]Q^xʒx<f\u001f\u000b1\fiP.\u0015\u001d>J\u0003*[x5(\u001dcD%,#\u0007\u000f\b\u0003{jB9'\npK>Ϣ>\u0016L-Rym\u001d/\u0015\u0013M_9nD/7\n%\fҊ7\u0013B:O\r$Y\u00153kOz\t>\rۤgCǇ\u0018\tH%^s\u0018\u0012a\u000eWHzǰ\u001e\u001f\"ťū\u0017\u001fo#͛owް\u0005\u001bE>Q\u0011ĳ<ɜ\fc\"a\u0019;9#\u0018{Ϛ+ϫrIi׮y}da\u000b˟Kml1ˇfO׶@TG|\u0014(Ām0*RQ7;ԍBtۨ.6/\u0014x\u001b\u0006'n*cr4\u000bPҷ\u000b]VLo1a/HDmq5}\u0007^ů<t\u000bd50\u0002.¤\u0013V>\u001eF\f\t.\n@\u0000F\u0014c;ś~\u000f\u0015&]G]\u000e%sE[/\u0012\u0019aaM5D:Us\u0006fM)f\u0012bO]WV&uo.`fEإ\u001bb\u0005A\u0016A6ʪTވ)bU\u001au\u0019\nSWhh}pЩsP1\u0017\u00199~\u000eڵ\t?#h,\u001c*.]I9A\u001a\u001b0\byݶ}%x?Ą꺴{1ր\u0004UoG9:j\u0006'Y\u0000^?S@n\u001dDE\u0001Wï(L\u0004Tw=-x5Z}Ið\u001b096S%\u001bS%[vWt9M݌GSIuߣaK5CWGp?\t\u001eG:.r\u0016eK\u001aMY\u0000A@&\u0016Y{]$uJE^Mw\u000e\u0016A\u000eJFG'z.!I#I}Ww9/3\u00190k,\u001fRa<&|=\u000fJ ׋u\u0001$E\u0005wg\u001e\u0011ձi\u0010lki2\u0019\u0005گmBZ\bە˔UUL=U?)C ՆF\u0015$(sZ]b_Bv<^k\u0001\u00106ǱYuN&WF\u0010YyX_\u0018\u001fD*^W}k1k7!q\bv<[6\u0004 rOQy<P0\u000f˔9d3\u001dwڊ=>lV<}Mc\u000fmPJ)VҚ?\u0013fg8]on2~8nڳ8n=#^!\u001d\u001aLd\u0010\u0018\u0014bc,/,a^|\u000eGƨ{>x?Q3zrco~?S_/;eZ\u001a]?y\u001fO\u0017O_\u001f~\u001fʞp\f\u0017\u000f\f&ESڿ\u0013)1g?=>ݾ}SCxg7}ٚW\u0013m]>׿c?~b,Mwg\u0010$6r*-IP3\"y'SФtV¿_\u0019?1\u0003Hc3܇ܶ?1ͅ\u0012GȑbU\u0013LbEPxZZgR@ND\u0006,6);F\u00013\"~\u001eYt]H+뉲d(SO\u0016d\u0000(e_0#wQ5a\u0004\u0013@'؃\u0001A\u000189|\u0014\"\u0014nS}ܶ&dR\u0002\u0011uٜx\",9wD\nŕJ\u001bMT\bQ_XIE~uigރPME\u0016ULU;=ϴ$w}>u)vީ\u000en:\u000b\b#\"\u0018J6\u0007\u0018\u000fKD\u001bwv51}X\u001bo6\u0013ڎfpΖpeee\u000f\u001a]g2L5.jjj\u0015pę$`'U'v&.\u0015,.*@gD\u000e-\u0012\u001d\"ę\u0016\r\u001c2\\V,`Q`鵲q%\b ]hLnX쾢W8^m3ZM`X'V\u0006vMH\u001d$cҮhwmm$Pܭ\nr\u0003!\u0015Ԥ@U{~^\"FME~c6;yl-bɓnN\u0005cmKYD%\u000e~w[.\u0002`hA'\nT&+5\u0007ϦVjz-B/6a\u001c)ͰL8RXҤ\u001aWlTY51C6ӣ讉(w{[Wm\t\u000b-S9 \u0004,i\u0018ObK\u0015z_qwdhU$eT\u001c\u0002KTt[nPg`޸~SE1\u0012qV?UM\u001c\u0014Kno̚JN\u001a^m\u0011a!1Yl\u0003¾1\\\bA/5{˱<w\r<\u0012son\u001a\u0016Rֵ&IAؙԾ11{\\\u0001\u0014c8hE&\u0011\u0002hWn|\u0018L^]Q]^s'r\u0019ߔ\\^(s7\u0003\u0015Z\u0004mUo\bS}ޭhɻ&[\u0002AgȦ$RfX:\t\u0013+Ȫtbo^w5\u001d!R59ʹ7\u0004\u0002wO\u0014_ዘn\u001d1ܧ\u0019H}\u001emly&gC0x{Һ=\u0016\u00004\u0000˼]H,D\u001a\u0017jG贀bc2طT<\"vys4\u000eæ|6\u000bt2 \bIØ6[uDh7ġ\f\u0015ȇ\u0003i\\\u0014#O`ZQkmO\"*Y(nmK:|Tq`@\f\u0003|fnFLKڳ<gꌘ6\fm0ۮqT!\u0010VRP\r{>n\"pԂT-,|Y]}ӈwᗷ\nBXY><mWs>hhj\riح\u000f\u000e\u0017(Ov;&\t\n\\\\K&H3\u001e:\u0014\u0000\tA\u0007zLA#\u0010ݩ@UvxYVK\u0015XA,\u0019(8L\u0012r>+U_~Muu\u0002[:U\u0000\u0010W\u0004Yy\u001c\u0010\\4)Y\u0019Vc`݌]N\u00049\b\tV\u0017U\u001ev(C\u0015K\u0007jsҎE%\u000e\n\\w7isg\b2m`;*&h\fN+rP\u001a\u001eo$\f3zd(\u0007ʯ<\t?97Y\u0006*r/ڬ\u00066nvqP<Ǐ*Rqd#B\u001fEo\u0002v\rQ9m/72aщtZy6\u0005kt:n:CgV=;9bt#ǫ\\Drf3?{<\u0004ʏ˰\u000b\u0003.:B84%Ln\b󔥡S1[AkM5]P23nio\u000fV8Fg\u001e\u00135\u0019OK\u0016F\u001a\u001b\u000b\u0000A\u001a\n\u0019n\u001e,(^sv蚇SpQ\u0019\u0018\u0018\u0016\u0000\f系-LQw\u0012n+Y;\f{c|\u0014rMq5v\u0001\u0006O%\u000e*bi\n]A}:\t\u001aҀ\u000e\u0003\u001e\u0016z9ΠgRɉooBAgўGolx@%Flx|^P><1襗r\u0010O\u001b!l8=\n/\u001946\u00173tW<m|i\u000b$\u00017\u0019y\u001dl$Wɹ:<2,d\u0014usK0\u001cM*3mޅ$ަ귆17Ml̹\u0011)x*qgθ, t\u001dyنq\u001ct\u0003\u0014Ǟfz9S|Y\u001bb\r;QS\u0014 \n`\u0012vZ|,Ce3\u000fTg7엱l]ԺRv\u000b>Oٝ\u00066\f~UԼ\u0019Bͦg\u0007_f4KB\u0004i\u0007p<\u0000.RZ1obQ\u000f\bs\u0017$IPN\u0016/v?~y''_\rRy\\\u0018\u0005(aE\u0010\u001d5-\fkFMă\u0017ٵ\u0019yKcL뽆?E$\u000b#\n<;s\u001b=Urh\u000f~\rKN'\u0011\u001e\u0001hn-cOp%\u0011G\r\u000b⡪/\u001bol\td`Z\f\r^~^vF_zoj)#IP;;zP+Azgq\u001bPp\u0002]ET\u00106\u0015\u0017N:\u0004\u0013\u0005\u0012\u000b#.?s^ya\u0014Iܷ{\u0002N\u0010\fm\u0019\u0004^:$igi\u0017\u001d\u0018V\tDP\u0011[ߟU[<tH \u001e4{qclƝoq\u0015o\u0005osA(\u0006\u0010$2\u0013ي\u0004\u0013\u00197J1\u0014\u000bHm;j?*SY\u0017\u001aZȹqf\u0013L{zju1\\g\u00147UV\u0000|\u001f*7%3/@t/^˹mA&IJVjYl~\u001bY13}VRn&FP]ԶW\fVb؃I\u001a\tfb\u000e\u00167\u0018\u0016{\u0011M+㷶,Qש\u001ea\u001df<\nȳ|2L,l\u0013g~I\u000bE#6N4\u0004\u0017;bwl\tqqv\u0015Z4--L=5ktQuE0LM\u0019\u0019\u0013/\u0002xւyo\u000b\u0005b,Y\"\u000e\u0007yCW\u0014qs,x\u00126\u0011qNIsih\u001a\u0006\u001bp>\u0019QJS\u0013kk7\rvk\",VV;?w\u0005^D\u000e)\u001e嫇a#\u001cq{A\u0019\tƎ~sB\u0003\u0001C$o#)x>s;:\rL-j$\bY\u0019*K-:\u0019FYDU-Z\nJŬ[\u0019Ujo/쩎3} q'\u0003\u001aܕ\u0014ҙdp\u0016|Ryxq43[!\u0013B\u001fqK\u0015ֳ\u0019MU:F\u0018>wZ_Aeհ\u001d͒\u0002\nkc6W\u0018}^S0c\b׎\u00139}&)EߺYՖ Bgs\"L{cNw\u001c,\u001fٍ\u00143\n4ZX,ގkgU\u000e}Cumq\u0019O\u0011حvv\u00055&ue2V^yy2l\u0016\u0013(\r=\u001f%d8̦V0&{\u0002L\u000b\u001c\u001e<tac\u0011\u001bVV\u0012cS`XRZn˻ؙa\u0015I-\u0004=\u000f\u001c\u0004ޞ\u0011\\)%f-1m~DL\u0014]s/e\u001aѤH\u0004Os+.2G\u001b\u0004Oܯ[Jj1T3MĪ\u0014?u6\u000eK\u0013(Rr>~s\u0013\u0018iQ??,\\1]$H\u0005,\u0012\u000b\u0015\u001d\u0015\u0014Q\"Hׁ\nv\u0012k+*\u0010\u001fuO%f\u0010[\u001d\u001d|4=ͻh7V\u00112[\u001e3*EqC\tQ6a6ӗ\u0002$'\u0005yPjNnvp)IvI#\u000f{\u000b,cj\u000fJL\u000b#\u0016\u0018F$b$XG(!\u0018=:\u001ab\u0016 ,/8.ť-#\u001fc{W8\"\n\u0019ln\\\u001em[?ʽHFP'#d-3v\u0007/}Z\u001cN3lwR\u001e7;շ9\u0011Ū$;g\u0016\u0015dȯ蘿V<izP|\u000efχ&gE,~ZnN?w+\u0016@K(#5\u0001L\u0014^H\u001946HP[\u001a}\u0012]#\u0001H\t>\u0012\bz\u0003O\u0016(\u0016n\n<y>\u0017rjn\u001df9K\u001blqn\u0007Jl,SbCVp'\n\\I7SX\u0017\u000e\u0017\u0018*h\u0005\u001bOI)$\u0015bD_}\u0011Q}YE\u00078%=\r]Qk\\a&\u001eIԙ\u000fɂ\u0000Bri\u001e\u001c{Z(zE1T*f!]nj9\u0011%訉\"!-!?T,ǓŞ'nw^\u0018e,[E\tRc\u0004똴xoy\u001d\nк#/Pa,WNƟtF\u001dM떈 \"+0Lx\u0005\u001a\\Z\u0003a!H\u0005i#Q\u0014V\r`Zf6axN.Iw}fA6\n(-\u0015~łq*tG>\u0011l%/mؼ1P\u0014v96\u001dsj+8(5@lW\f+\u0013Ô\u0004\u000bn\u0014bRR*B\u00065\tZ=5}\t=\u001eVAc\u0002=1N\u0005\u000eUrwt%UEoï8\"{\u001bJC\u0007[\u0004LPL\u0011Lm\u00038\u0013.V\fCT*i\u0012eK)+#^A_(?if\u001fs%N\u000b?sg^WP-Ь\u0007\u0011쉩2_y0,&^YUe\u000et\u001a\u0001\u000b5z\tnJ'H\u0017^\\3Ӗxf_~az\u0010'Rzhޝ\u000b.\u0007I2Y\u0004˳7YK᏾J?,\u0004(}P*\t\u001e>\u0003ΰ\u0002%լ\u0011\"ӎ\u0015]a~DCx-\u0018\u001csMո|5\u0018VTsºk*i\ndn͋8F|f\r\u0005y\u0016~A\u0011\"\u0017hu%Pg\u0012\u001a7\u0014ol09ܽUL t\u000by*458\u000f߹=\u0012\u0011TU~\u0011&!xX*8Y%\u0017Y\u0018I^#\u000bA\u0015V\u00126)ܩyZXTSU{Ġ&Bp\u001f^\u0010'\u001c#f;\u0007,*QAd3\u000fD-\u0019\u0010I\b+_,\u0016tbQ+Nv37l_L\u000fUHY^װGX\u000eZ\f8X\\\fhEZ\u0004$գwyMi<Cjav\u001f#)'?u׈lVT#?\u00143(KCELa\u0000W>\u0001u\u0006F^!l5>})\u001ci5s*ϣijcڹ}Ԓ\u0017\t*4wfH\n\u0005?J6*)u1BT\u0018\u0015\u001a\u0019ma6\u0014sǱv\f?H.Ϯ~g2b'r^_{\u0014I\u0016Opa&\u000fY\\U*T|g)1ʶG\u001dڛR\u0018\u001cм\n/c26dԪ\u000b<\t\u001a]0\u001ceBd}\u0019õv9ztg͟*\\u\u001ay$V\u000fAiq0\u0002--kɶP\"jίDl\f\u0019\u001a[O\u0016e[\u0018D A2\u00186\u001aˊZTa\u0014\u00031ԦjXi.d6i[C\u0018.\b\u001cƴ+E6&\t\u0012QH\u0017vVvGFrtE<~o\u0014.6k8E̱7{^ym6BDSkG(\u001eVIIq\u0002aJ$hL١Oe5D.\u001aYӟ}i\u000fyڇĶEmL[H?7_ש8LjL{\u001fw+\u000b\fGT0\n&sփ,p\u0014\u0011a +j\u0019\u001clI\u0011}&ʆp\u001d\u001e[5K\u0019\u0016:LPk1O\u0018yϨ<]Qe8\u0012E6\u0011(Mn\u001bɣ\u001aNTN:,\u000eRjJ~5&v\u0017z4z/ԔEtj\u001fJR\u0017O1$fLT5N\f|.Qi>\u0007\u0012\"J\u0011Wg*M\\Z\u00190TfFѓ\u0003\u0018V\u0010F\u0005Qp1\u000746\u0011ີsR?:2SLϷQyqk!dj%@TUJ*_#5֒͑Ze\u000e\u001b\fI\u0011YF\u00028m$-\u0005\u001f\u0013+1A\u001d0Z26J\ffuxdȠ+,)\u0017WUo\u001a@\fu\u0015Ȳſ41e9h\u0018\re\u001fdzH\u0010j#\\{Ul{$!ۚ?\u000bqzX\u001bж#Ok\u0016<L(Xٜڬ\t2]q\u001b'LM,&GwZXC?\u0018V|U*\u0003UʞJ\u0011U\":g\u000e\u001a\u000eBwDgA\"AU\u0019Mlj\u0016;\u0013}7&-|[HYNTKۊUTR!^,2\u001e\u000b\u0001@^?$>}6gBonӑ$U/0M2\u0004؟'L>b,\u0012%*\u001fmlڣZhV/h6W\u0011&DeC*e\u0016.\u0018$!UYf\u0018QiE\u0015zs_)-\u0014\u0017\u001b_y\u00135sU8\u0013c\u0000n*8}+.\u000b3~\u0005h4zD:U\u000bs%xY'\u0014KZ{=\u0012\u00169\n(P\"\n3ϳj`o\u001b.\u0014Q~kUh>2)Q)2I8$Z)*\u0005sܕ!ccL\u001bxӖfh7ֽv=)OpW\ffE\u0000\u0013jEdaάT>\u0003%(e\u0001j-z߽\u0011d\u0000J\u0014\u0002u\nMq{Yvfؐ\u0017RL\u000eTQ*UO {~\u0016\u0002T=+o\u0001\bq\u0006bF\u0012;D\u0014\u001c^h\t\u0016dޘq&*J\u0004@\bd1HQmP\u000bk{Wnwfc^h\"Hg=-\u0012\u0014TG^g(C%uȖj\u000b))U;\u0002QY=\u0010/\u000e>}g\u0014*v\u000f7 \u00151_\u001d1UhqE\u001e ҈\u0001C\u0000}\u0011Bg\u0019\u001bƆ\t'.\u001352>ݶ\u0010\u0018fb\u0007\u0010)NT\u00157[c\u00170b,\f+<\u001e#\u0016\u0014-\u0005t[\u0015q(}\u0016iPhR)fRl5U(\u0016V?\u00188,L\r^\u001a]\f[\u001d9(*2ڨV\\/5\u000bϩȤ\u0019vD:jN>/\u000b@hxa0j}]3N\t\u0016Z<gh][u+ƌ\u001c#j\u001d\u001cc\u0010./ir#z]Q7Yv2\u000eer,lI{\u001f\u0010`\u0010#1\u000ey;\u000e#\\~4W][jэ\u0002^%9q\u0015({\u0019OgPЏE\u001141/NC\u001dQ6X\u001dTH][]\u001c5\u001cw5a\u0006\u0000O^7\tK4ONV֚<\u0014Q*/kUF\u000bʗX\u0005ug\u0006NQh2|\u001b.LM'F[L\u0000gU_Frn^?ۢ@%T$%&B3!T\u0010\u0016BuU\u000e\u0015n}P__\u0003\u001e\u001e!J'k\u0012\\\u0004\\Q!zS-[\u0019\u000fG3UlBSѺʗ$W\u000eI:8\u0012\u00016\u000fd\\rU7\u0014+?\u000eiRֹe`@Aj|>j@\u001a\u000e]=w\u0014mWqi\u00169UR$\u000b.W\u000f%\u001c\r-zzub\u0003uc*6XA\u0018/P+\b\u0010GA^@3̯01|\u001c\u001c4yn\t3N*j6\u0006bu5>jvlp|d9:Nľ yzŸz$b\t\u0019ͻx\f\u0013wn\u0019mv.k[\u0005\u0011*\u0017h><s&T5>姾RfImDZCʉٖ^%\b%yD\noP\u0000Eט\u000ft۠\"}E/[!7%諩-&\u0018\u000b\\zd MGE+m\u000fPR'oU/ah\u001bW\fG>\u001fA.\u000f]݄v>TT P6W[\t\u0001\u000b}Z&6utjfgU'\u000bH\u001bvWsЩhs\u0016{)\u0011^\u0004HbТ\u00166\u001dqZISYՀ6Hw\u0016\u000bv\n1ܾg#\rN&#igRYS\bhn'$0_Ϋb?\u000eLu[g\u0014+n$P%\\-hk\u0019W\u001c\u001eLI1m\u001dgY_&\tT\"0Ѿl5\u001cB[B\bLoj=48\r/tW2,\u001aUm\u0018\u0004ȷF\u0019DN\u000b33\u0001=\u0000A^:g\u0005)\u001e'9}\u0006\u0013Ge\u001a6ԡٔ[3qW\fZ\u0015r\nӕ]N\"=*dA\u0019M\u001bQ)V\u0012\u000b,NwZ)xvwu)\bk)㎞qf\u0006l79\u00107\u001er׊\u00129ڲai$?BT(ZU`F\u0015ns\u0017OaW8\u0002;MYN<Q)ѭʁ\u0004\r+Ei.zo\nb۵;LGז\u00181l׳\u001absb<&\nj(`&F6`n\u0019Qx\u0005jv<\n/9eVjN~q\u001e-M\u0005\u0014\t'ߺ(@\u001f\u000f*\u001fRk¯*\u0013 I\u001aVY\u0002g\n±Юm\u0017TZ4\u001e^*tJ8`ҸBOfA[^\u0002uZ\u0001OPM\u0019\t~x_kq\u0016*\u0019]C Z3M5\u0016&\fY\u0011Ҫ5\u0011RRW\u0010e\u0017Yg'\u001ei8\n\b\\9BZ2*eH`\u0013GR|\u000f2+\u0019\u0014z\u0012U ub\u000bD}\u0011\u00072ϱY\u0003-؜sqz\u0016`ٵm:=f\u001a\u0001]%@g\baV\u000fuZ刲w,[\fϐ\u00132`*S=|_\u0017c;eI߈V\u0016XS/;/+\u0002b'D&U;=\u0004VL!}\u00114!Qv݌\u0017J#eI\u0003V\u000fy4hڐ8\u000eiYeu\b!*%NjLRQv`5\u0001]`G\u001d9Y\";\u0019\u0001s VLYil\u0015$\u0015R4f-_}yn&~y^[\u000b#CĬl&\u0011j3r^9y9r\"G}kIBW\u0010\u0001^ψya+\u0000QOd皢۽FY\\荕&oqP\u000e\u000f$,rbXIʏ\u0004fADnՔƫ˼\bz]j=>\fQZ\u0006*\u001dvT\u001a)UC:)j-^.\u000f˙VE\u000f\u00114\rμc\u0014ik^\u0016\f,1Fy7GSK팉\nj|WJZsض\u0016{t\u001e!\u0007\u0014\u0017r5J\u0012C\u0016κiN۲ѲJ3H-Ю͛e\rUխa@AsI\\c.$x\u0012*!n!~jnWh1_*3|N\u0014\u0016)*=I\t\u0007$=љ\u001bluz83g89٫\u0019$\u0011ﻭ\u001aS&d5pTP\u001b\u0017<\u001eC\t=@k\u0015F(w9P}]+F\u0014ZE1\u0013B7\u0006.e79\"ʪ>\u001f\u0004N5\u0011\u0013w\u0002}hEboے͙\u0013<j19\u000eKE*y25R.I\u0018Q\u0001KqG\u0010aƛRJIZR%\r.\"\r\"\u0016|\u00176\u0011P\u001a1\f$\b#=.\n)햁[6I2*E5UTuo[b^M\r]\u0002kX3=s5tAEx\u0011\u0002n\u001brq\u001cRD#y\u0002\\\u0016\u0007\u00187Ge\u0010U!@\u0017\u0010J];'\u0002H\u001e6q@zRs5muaT\u001cک([wo \u001f\u0016e\u0015\u001cm*I([L{^>\u000f5,v\u0014\u0019\rj\tʍ\fmwS<HjǏV%@uq)OLmda>\u0016\u0010dXbn\u0000WEŮu\u000f8.\u001a\u0002lR\rҶv)ӕ͋^-j\\6HT\u000f[\u0013\u0003S\u0001\r1xZnu-Um\u000e\u0015+S&i4C;ćU2*N\t\feYjL+0*24Ϗ|UҪwH\u0015kNW\t\u0004o\b)We#~JK3-(d;8\t\u0004o_ygݛ:UlGQ$,XVeX* r\u0004節Sm>rDy̮T.wvfq5oN\u000e!Ÿp+U6UBl/X\u001dӷQz\u0010y\u001c\u000b*uN2\u0019U2<\u0012(0C&k*v[\u001bH\u0006aD\u0011OT\u000eNwivUr8t\\fAZ\u001fNÿSjoSX)ةU_\tk+Bd\b>N?Wa9rE}KqY\u001df\t)v\u001fXمƙjOtB4+Kxq7\u0015\u0012]Y{\u000bU˸Ml(=\u0000ݰǼm\u0014gq\f\u0016Uq-\r2\"8\u001c@oﳥY\rqj.lyDQ\u001aI\rBʘ\u0018\u0015 Mi1IdiضP\u001dlٜ\u001e;(\rޱ\u000f\\\u0001f\u0016b\u001d&Р*9(N[Sҍ/1\"wh\u0014\r\n\u001c\t{\u001d`ʧa\u001bZ>\n׆\t=B\f\u0012V_i<\u0013JU\u0012b5(dX/_&đz>\u0019\u001d(&:\u001dф|>ωN\u0019MT\u0006gQ\u0016\n\\\u001c\u0017\u000b\u00153t\u001d.\u0003\u000b=U\u0018QP9V2k4s\rnۺ߶/;\u000eϏ! rP\u0003D\u0016\u001aB],\u0016\u0007%[x2\u001cQTQ \u0012k(\u0010Hy\u001bO˶XOل\u001c\u001fXi\u0012WNoMS\u001d4.Zբp'>lĵdu%kwhv\u0003#O\u001c\u0006bz9ŞOy\u0018\u000fTaT\u0012ɳ\u000fnHJ\u0011\u0001Ł\u0015k\u0003\u00192$E)*R\u00000\u0016r%d7\u0014ܱd\u0010֨<r\u0013Z`h\t\n\bH?][\blVΣ2 P]\u0000\u000epGi4Km O\u0007-\tb`V~Le|kc)(5U\r+\u0014s\"\u0002&\u0012ͷn_h{LrVlsQ58LL6E@J\u0003\"$:B8ZgzSҰjj7_,#En\u001d}\u0015=Ҩ;=̨\rm7\r,\u001f\u0011,m2ՃB\u001b\u0000!\u0015S\u0000>:So\u0016jds\u0001؆$j5J\u00116*2/d%tDk&JSKj\u0001y?\t-+\f\u0017r0%Gi^l;\u0000|\u0012\u001ed$ZNd8GZp\u001eռSɐ\u000eC2\r;-՚\\T\u0007C9Ns\u0011}z\u001e`\u001e[WT\u0012_fKˠn}rc.s{1\u000eV9\"t+8E\u0011\ne\u0016=U\f];DN.\fgD|\u001a/\u001c\u0012~,m]cN+6펣6+\u0004 %U8?j+0z4~%}o\u0005-;v2\u001e~Ͷ;79\u0005ɖ(M~G\u000f\"\fxmF$`dG\u0014Zag{\u001e7嫽yf\u0001\u0014OnR;\u000e3̥ ):#*E沙PJ7x\u000e`NVK\\Exg\u0018\"$)m􄘢\"9aQmb-PB\u001e\u000e,R\u0001ݪW>oB\u00185j\u001a\t7j#?fY5C?X7\u0007~&\u000e/\f\u0004y.rqo_|?_\u0010{\u0001۫ǁ}D\u0001}0.,2\f\u000bHxwe\u0015EV,o5*YdPdW\u0016,\u000b̎YYdEeeay\nԐEV<Yd~\nU]Ȟe\u0015e>Yd%5EV\u001a_XdHYdXW\u0016\u0019E\r\u001f,2Y\u0017\u0016,M,2}V+\u000bY@F?\u001bd3d׹\b,2&P$zEF\"{\u000f\u0016\u0019׵\u001b`ɺE&\"fa]Xd\u0018V\u0016\u0019g=`Y~f!7Ȇab1XdEF\"3ʙEqf\rDj,2B}+gf!gȤ\\q(2\u0016\u0014,\u000bL\u0001M*m\u0013LPdXV\u0014U)|iYQdb3\u000bEV\t+@\u0005ELB80<7l^n,V\t\u0005h\"4/(Z\"\\Pd5j\u0013E&˂\"*$DUW\u0016\u0014\u0019\u0015E\"\u000b\u0003EV\"\u0013x}FU(Z\u000bE&ۂ\"eAayȪ:&f\u0014\u0019\u0015E\"ྡྷȪ&\u00149~\\)ADa\\Pd:jFax0.(2\f\u000b왭(\"@\u0015\"N(\"\u000f\u0014\u00198\u0005Eƚ\ntXQd\u0018\u001a(2\u0019f\u0014Y\u001bEٴ\r\u0014\u0019\u0005E&'L\u0004\u001c(BpF\u0015ju>Pd\u0005\u000f\u0014Y1܁\"KÌ\"\u001bFύ\t\u0005dLo'dA\u0015j\"\u001b\"K;f\u0014Y\u0013EVj_Qd2>Pd:\u0013EV\u0007?ȊH!\u0003E/\u0014YeE\u0015UjN(aPdi\f\u0014\u0019\u001f^(Ќ\"+Ĭg\u0014Y\u001af\u0014Y\u001a\u0003EV$6J?(\b\"+T\u0015(\u0006\u0013EV\b(g(r7\f\"+,\u00173n\u001bEqAaXPdU\u001f(2\u000bL\u0019E&\u0007(0ȘV\u0016\u0014k\"\u0017\"RgA!\u0003Ba\\PdR\u000fQd\u0018D8tڌ\"\u0007'/(2\u000b\u000bEOYPdȴDi=lC(2\"qF0]\u001f(2~\"\u0017\u0014Y\u001a&\u0014Y\u0002EF`EU$F^(rFU\u0013g\u0014Y\u001bEQ\u000bLT\u0005E&\u000bE&\".,(4(4\u0006L)3\"^Qd\"KÌ\"\u001bFGU3\f@\u000bE%,(\u0015E&eO\u00143L\u0019EV{y0.(2\f\u000bZ\u0003E5-(21g\u0014\r\u000f\u0014Ym}E\u0019\"yB\r,\u001aF{W5:\u000e\u0014\u0019B1v\u0016\u00143,\r3,\"jȘPd\"Dx3\f~\u0019E@\u0019\u000b\f\u000bEV(2^\u0005Ef8\u000bL93\fÂ\"gy\u0014\\Qd\u0018\u0016\u0014@\u0011\\PdU\u0013\fmO\u0014\u0019K\u000byA\rÄ\"\u001bFG1-(2\"\u0015(2\f3L;(23N(25}XG\u0016\u0014\u0019\"\u001b\tE@Ug\u0014$\u0000_(2=\u0005E&\u0019E\u000bE&\u0019E˿*\u0011O\u00146H3ʂ\"KZ1Pd:\u0019EVF\\Qdu+\u0006[wFu(Ê\"{6\u0003\u000bW\u0014\u0019'L\u0019Ef\tEf\u000f\u0014\u0019\u0005E&Ì\"\u0013E,+\fÌ\"O\u0014YaQd\u0005\r\u0019E>\"+!\u0014(2\f\u000bL۟O\u0014\u0019\u0005Ef\tEӈ(p\"+\u0012\u000bPd\u0004|_(2\u000e3x\"KÌ\"Kcȸo+\u001bEV;\n\u000b친oȰ(2,+K\u0013EuAaQd:\"+jQdE\u00023GBa]QdXV\u0014ٳ\u0003E&\"ә3L\u001fB\u0013\u0016\u0014Ya.(aQdi\r\u0014Y\u00125(r\u0015EƤҰȆ5PdE\u0018\t<V\u001ax\n%\b\u000b\"\u001b\u0019E6Y\u001dEVQd1/\u0014\u000b\fˊ\"Fa]Qd,(2Y^(2\u000bK]Pdjo\u0014YNy\u0014\u0013ӌ\"KÂ\"\u001b@(2o\u0014\u0019a\u0015EX\"#\u0012B\u00110Qd\n4(4,(a5\u0014Y\u0005;\b&QdXW\u0014\u0019\u0015EVRjFa]Qd,(2B|ȸ+lXf\u0014ٰ\u0006waE|lQdhV\u0014dI\u0014ٰ\u0005H}F1\rQd\u001aq\u000blA\u0015(2+L\u0005E3_(2Y\u0017\u0014Y\"Fqi+M[PdeB\rky|\bvQd\u001f(2\u000b_Ȋt\u001bg\u0014\u0019Ɗ\"#\bBv|Jk\u001f(3\u0003EFJwEM\tE6\"+\u001a(2\"S\u000eyAa9mBBɺY\u000bL\"#ؾ\b\u001f6&@MFC\u0015%_\u0006d'PqJW\u0014Y7PdX(be].(2Ȇ5Pd\"cRyXW\u0014\u0019\u001b\u0015E6,3lX\u0003E|ȈPdV\u0014\u0019ѣ\u0005EF\"#\u00188\"#P]QdҾQdjy\\Pd+42(2u\u0003M(2\u00148hE\\PdqD'Fo\"{@\u0005EVU}\"4/(2+FɺȰ(2,o\u0014\"ò\u0014-{\u0018>\u000bXPdD[(2bv+\u001e\u0003EV\u001b(2\u00023H͊\"#Fa]Pd:lFaxd]Pd\n,(2,o\u0014\n\u000b&\u0014Y_^(2\u0013f\u0014\u0019a\u0015EfO\u0014D\u0017\u0014\u0019\u000b*#\"yE\u0017(2n\u000bEqAaXQdR1\u0014^[Pd,(2Y^(2+L\u000bF\u0011ZPd\u00020,(2o\u0014\u0019]+L\u0005E}}Ȉ(2\u0017\u0014\u0019\u001bEV/>\bQdXW\u0014\u0019oъ\";Da]Qd,(2Y^(2)f\u0014\u0019\u00178\"{f\u000f\u0014YU\u0015\"cJ|lPdJ\u0017\u0014{\u0012CY\u0003E<6j1\u0002EVBa[Pd\u0018\u0016\u0014\f(2\u0019'\u0014\u001d4PdBi\u0012QdU\tEV%\"c\u001e_PdZf\u0014\u0019\u000bE~FU\u0001O(2\u0019>Qd\u0018\u0017\u0014\f3L}pS\u0016\u0014YmuEٗ\u001fqX฾QdXO(29M(2,:?Pd+\r\u0014,\u000e\r\u0014>8\u0015E&gxAQAȈ_QdEi\u0019E.gAQ\"\u0005Euo\"Ŝ\"1[_Qd\\\u001f(2}vM(2,u?Pd\u0014o(2۸(2o\u0014\u0019\u0018+h\"+RiD\u0011_Qd%\u0012\":(2;\u0017\u0014\u0002/\u0014\u0019\u0011\u0015EV\u0012b\u001c(\"\u0002'Lq\u0005EeEBa]QdL(2O\u0014\u0019Wȸc\u000bLq\u0017Xϊ\"S\u0014qF\u0015!U>Pdx\u001e+\u0010\u001bEFXaEiP(2\u0012o\u0014Y!\b(2>\"c(2>kE\u0015r/\u0014\u0019W\u0014ZQd|\u001bE&\"aAayQW\u0014ݮ\u0019E\"JW\u0014YƄ\"{ϒ?ҌB\u0015\u0011@(2\u000exdQd\u0018T\u001e(2\f\u0007\u0019EB\u0006/Pd2(2\fv\u000b\u0001>Ȋ\bM-Qd\u0005WW\u0014ʇg\u0014\u0019U\u0013\u00035\u0014\u0019a\u0017\f\"+\u0012Pd2^Pd\u0018j\u0019(2\f\u0012\r\u0014\fR(27{D8-(2]/\u0014\u0019ނ\"vtAQ\"#ݱ\b\u0017/(\u0007fF{_Qd>Qd$M\u0016\u0014Rk\u0013\u000bE\bԌ\"+#Qd<\u0017L\u0019EVT\u001c;\bPPdBPdM\u0017\u0014\u0019\u000b\u000bEY\u000biiA)\"øȸ\u0005E&' M\tE\u0007Pd%ց\"+\n\"'\u000f\u0003EuF\u0015'\u0014Y\u0011X\u0003E$Vy\u0003ErgN\u0014\u0019\t|B)F9Ȋ\u0004@q/\u0014\u0019\"#HPd\u000eQd^(2{A\u0015[@1~.(2M3\"qFp\u0003EVTW\u0014\u0019\u0005E5.(2\f\u0015\u001b\u001dڤ\u0016\u0014.-Qd1DÜQda@\u0011yȴ[Qd\u0017\u0014\u0019;\u0015E&y\u000f\u0014\u0019B>Pd\u0018(\"\"\u0006\f+L'{Ȋ@ZuԢ\u0015EF,dF]\u0003E+MȈ,(Z\tE\u0010'z\u0006Ȋ2\u001f(2E66Jʓ\u0006\f\"SZF\u0015I3Hc\u0003E\u0012Ȕd[Pd\tJp\u0012E\u001fFq\"^Qd弿\"[zhwq\u0014Y\u0005E&\"eAayȰ(\n\u0019E\"c\u0001]Qd/(2\u00167L\u0005EeAax0(2g\u0014\u00197\fbEaYQd8$o\u0014Y\u0011eBYPdԌPdZPd$W\u0014Y\u001b(2R3+lJ\u000f8b7\n>3dYPd:\"úȰL(2|(V]Qd,(JC\u000bEuEUA}f\u0014\u0019\u0017\f\"M\\Pd|Ȫ\u0013dڊ\"b(2\u0011.(2FɊ\"S\u0019\u000bEV\u0014QdȪm?Pdԣ\u0006ֻ\u0015EV\u001b(Z\u000f\u0014\u0019g(\nR\"(x-(2~\"~\"ø2Ȗ\u0012E&\"òȰQd5ԙ\u0012EV\u0004W\"S)\"U,(*\u0000'L3L\u000bO\u0014\u0019s\"cYPdPdڗ(\u0012\r/\".\u000564L(2\u0019E\u0017L\u0005EeEUp~`,<dyȨ_Pd\u0014/(2\u000e?Qd\u0016.PdjQd(2i6.(!(2a_(2y+\"3'p3L\u0019EWQd*/_PdjYPd8D)dYPd:\"C\u000frAzF`(\u0007̚Kf\u0014\u0019ٔ7Lg.(P݄\"(Fq\u001d+MQdJ'PdU\u0019EF\u0003Ǌ\"\"S\"\"V\u0014\u0019\r\bo\u0014Y\u0015\u001beFqg\u0014ڭ^(2ܚPd\u0018V\u0014\u00197\f\"SC҂\"\"SzAYkF\u0013E^Qd\r\u000bt\u001bE\u0010DQ\u000bKx̺H(2\"S\u000bEFvxEIwA\u0018\"#]dg\u0014\u0019\"mXPdUCoB1gPdPdԈ.(2O\u0014\u0019\u0015E\u000bjN@j,(2\u000b#^(2\u001c\u0005EVPd\u0014J~JW\u0014\u0019A\u0005E^\u000f\u0014\u0019\u0005E\u0010Ä\"{Ep\u001eL\u0005\u0002/\u0014\n\u0004\u0016\u0014\u0001f\u0014\f/\u0014YU3\"c0.(2\u001a\b_(2\u000bL\u0019EfG|Y3\fÂ\"Bv\u0007kE1PdL\u000bWAQ\u0007B/(2JI\u0016\u0014\u0019o\u000bE\tE\u0019E\"qF09(2d\u0017\u0014\u0019%n3[\":D (\t\"\u001b5\"\u0014<[ZǌIp\u0018wmF\u0014`5$\"mF00Pd\u0018\u0017\u0014YCDiF59+\fu\u0019E\"\u001bO(4\u0006\ft\u0003E»B\t3L*\u0016~0#\nL\u0007,\rˍ\u000fcL$\u001bz\tE&\u001d}*{EȽ<E&#-\u0001#\u0001gadueɶ\t#\u0013x-q0ȅad\u0016Es\u0002FZ`db3|X\u0017\u0018\u0019F\u0017L\u0005Feߺ,Q02>adEi\tFFli)5dad:\u0013Fq)9Ԟ\t#S\u001cpQ˰(xȐX`dj1adj\n8dad*$`dj`dʡ|(\u001ead\u0005Fzb_~A\u000bFFg\n#q\u000b\f\u001bF&\u0002#S\u0010s\u001502B$+\u0012\u0019Y`d/adj]`dU\u0019F^\r#uU)!02,o\u0018\u0017\u00186\u000b\u0000\u0002#\u0006}\u0019XadlI0*\u001d\u0019FF\u0019\u0002#K\f#\u001bF׫#\u0003\u0013*'2T7\u000f\u0018Y\u001a\u0003Ff?g1iad.02Y\u0016\u0018\u00197L[\u0005FVsI'\u0005#zcg\u0018\u0019{\u0015F6Yډa\r\u0018\u0019_ȸo\u0018!\u0016\u0018^3l\u0018f\u0018ٰ\u0006L\u000bPtad\u0014C[`dUшO\u0018\u0019!\u0005FFxv\u0011}\u0014]`dځ-02e%^02Y\u0017\u0018\u0019\u0015F\r#S\buɲO\u0018\u0019\u0015FFu\u001fsy&uQ~~hzȰ0\"iR\u0001#u\u0005F\u000f,>Ȋg\u0018Y\u0011\u0013Fnx[_ad%\u00013Le+\u000bL\u0005Ff-02Y\u0017\u0018,3L_Q9x$+lXf\u0018Yg\u0018Y1;Pc~T3`dad\u0014\u001aadDX`d`d`dJG\u0003Ff\u0015F.eQY\f#éZad2&\u0011 \u0001\u0019\r#+\u0016\u000f\u0018*>ad2.02Y\u0016\u0018\u0019\u0017(\u0002:Ȋb3\f\u001bF\f#(\u0002#\t#+үad܌\u0015F6Y&du\u0018*R\u0017\u0018\u0019so\u0018\\\u0017\u0018\u0002g\u0018Y\u001af\u0018Y\u001a\u0003F/02F\u001bF\u0010Xad\u0010V\u0018ٰ0202J\u001fV\u0018YQ'Z\u0015FV% ad{|$8Ȥԓa]adXV\u0018yJm\u001f02U/0R7`dLq+L\u0005Z\u000blL0*\u0018\u00197LױȰ02Y^0202Y\u0016\u0018O\u0018Y\\\f#c]ade\rkȊ\t3}\t#3Y`d&;({xMV\u0018\u0014K\u0017\u0018\u0019\u001bF\u0002#:d\r2\u00195`d?]adN\t#3i\u0019F|\f##\f#\f\u0002#)]adU\u0002\u000e3^7̬3,3,02\u001c\u0015F&\u0002#\u0005#S*z\n#=Qj??`d9{Ȱ02,+L[O\u0018T\u0004\u0017\u0018bQN|Ȉ/02Zg\u0018\u0019QO\u0018\u0019\u0015Fe\r\f#3\u0004#.02|T3jm+\fQ\u0017\f\u0002#t\f#[\u0013FmaX`d:\u0013F&ɕ\u0019FFlQ0a\\`d\u0018\u0016\u0018\u0019\u0017L\tFf\u0018>\u0013FVm`d4-02\u0019>adyTȪV\u0004Is\u0003FVO02\u0015F\u0019Fƀ[`dR/QHtf\u0018Y\u001af\u00180:\u0002#A`d0o\u000b\u001d\u0007\f\u0002#aO\u0018\u0019\u001fȸ\u0015FV\u001b0|0\u0012\u0016\u0018YZf\u0018Y\u001a\u0003Ff\u001f?`dU\u001e+\u0005Ff!\u0001##J\u0011\u0006^ad\n.0023N02Us0z0.02\f3L0.02\u0019f\u0018Y\u0015`\u0003FƓadu\u000b,`da\n\u00183}ȴ~02UIN0\u0004#Kct\u0002UɱM02\u0017Lj/02\u0002/\u0018\u0019\u0005F&\u0004#Y02\u0019g\u0018\u0019\u0005F\u0005#\u0006L\u0013l=8T9\u0014aQO1$$;ȪZ\u0003?`drad8\u0007\u000b\u000bFV\u0014adM\u0011^`dh\n,040at\u0018*af\u0018\u0003F\f#ðd89\u0013,f\u0018\u0019\u0005F\u0019F6\f\u0013l\u0018\u001dFV#\u00141/\u0018f\u0018\u0019a\u0005FVUY\u0001#\u0013Fg-02y}\u0013,`da\u000b\u0018YU\f#cr`dR\u0015\f?\u0003FƀIo3xy02Jq\u0016\u0018z>ad\u0004\u0006\u0016\u0018J?`d6-02B_3\u0002\u0017\f#+da\rk$|94Ȟ\u0007\u001d!1`dgEF\u0001\u0013dب\u0013]^͔\u0018E\u0016\n\u0019dq\u0002B&2N]0tDg\u0004٭~\u0001 \u0019'ctkŏ]{[B\u001eH\b\u0015\u0005伒V\u0004w_c\u0014sA\u001fU\u0007|y5\u001e3M:c\"| \u0014Xc0c8A\u001dea,g\u001d1\f\u00039Ǵc\t\u001c#)EYb\bL\u0010ޙpclJX7u0Ҙ1JA\u0010|pk\u0018<yea]p+b\f\u001bI\u0018\u0013]\u00030\u0006ݴsQ\u001f$\u0011\u0017cc_bŕ\u0012.#ɠ\u001e\t.ƀn+\u0019\"`\u000bZ\fO\u0004m Ŷo\t\u0011]:X\u0011bB\u0003 F?\bbD\u0007@\u00130(\u000fz\u0018M.`jA\u000e&Խn+JrX\t\\\u0010j\u0005\u001c<<\b%6\u001csVk\fhTp3ac,jV-\u0005\u0019\u001b\u001f0%%2L#\"͉\u0019&\u001b!dx+`H.me1U0{/5a/n\\aMf\u0018e*J%3LSiid)\u001b>a\u001aѽ\u0003\u001aFL35LF}nPdia6Cð$4\f\u001a\t\rSyN\u000fT\u0015IrZ\u0013\u001aKէA\r{?/qb坨a\u0018-,0\u001dų\nj\u0018\u0006\u0013\n\u001e0\t+؉\u001a\nh[mK}]$\t\u001ad%\r\f/Oo\f#JD\u0013Li܉a@n\u0002!\\*s$dVqa\b\u000b\u0002\u000b#Kʔ\u00180\u00059*L -0\u0013R~4p\u0003\u0014FZLp3\"A\u0019B\u0016PM&N\t\nV\u0013όy0?-_۬\u00063 츍I\u00106\u0004г\u000e<X=`ar8\u0018\u0017\u0006H \fv|\u001bh9\\\u0005;I4Wk\u0004\u0015>\u0011\u0019\n\u0017Zg!G \b\u0016\u0000UTcޛ$˒J[\u0015\u00144ڍcZ{\u0003@\u00040IEY\u001aE<vUfH0\t\u00072u&q\u0002\u0006\u0016,\u0002\u00056dʐ\u0004IR8`\u0014\u001a\u00180\u0015\u000eؿ=&!`Ķe\u00164 `\u0018zj\u001002\nZ\u0004\u0004yN\u0001\u0001,c\u0004\u0001\u001d\r7\t,\bXv.\f0i49\u0005\u0003\fAn0\u0010'F`\\\u000b\u0002q(g@>#W^*\u001e*2C\u0014ă\" `!\u0012\u00100\u0019Ќ!`\u0012\u0003\u0002o\u000f\u001d\u000e\u0001ǜf6\u0004\f\u0006:kY݆F<\\\r\u0001)\u0000V*\u001c\u0001d\u0012\u0003ӕx/\u0004\u0018\u001e2B]M\u00172\u0002]v\u0000CP\" `\b:?C\u0010\u0017\u0001Q\u00040\u0004\u0012\u0001LS\u0010A\u0000[B\"--\b`ڕ?x쥬(2\u0001L\u0019d}2Q\u0007\r\u0000STW8-#t\u0018mÁ\u0000\u0006\f\u001ch/7ݕ\t\u0001֢Is\f<ہ\u0000[BF-1\u0010`XЪp*>;Z/4_c\u0011\u0019\u00004Q4\u0018Χ\t\u0017\u001ek*\u000bl@m\u001c\u0017\u000b_\u0000_i^_\u0012ٙ\u0007K\u0002A$0>g\u0017~ݨ\u00061\u000f=\u0011,/'O:\b(.\u0016\u0012&h\u001ehfA&^e\u001b)\u0000\u0002Zb \u0012h)\u0018d/V%J/j\u0016 \u0007-__\u0019Č^`\u0007q[ḵ_\\aVӬa7nw:K\u0002KL\"\u0012 I9_\u001cA<\u0019\u001dlp%\u001e\\\u0002%;\u0019\u0019:Ag,Fݐo\tEi仭;a}\u0019i~\\\u0006'\u0004w\rf\u0006o:\tPwi2I/\u001fL7Ҵ$_[H%\u0006{UW\u001a=v\u0017\u0017_ץDၯ!^Ad\u0017DZ\u0005K/>Cy@Ğ3]\u0016\u0010(\u0019u<b\u0019ByC\f\u0017{Z\u0006K&Yˌ@5\\l͚eve{\u0005Et@W±^}\u001ce\u0017\u0007zEQt\u000bſgq^Gte2J\u0005%Co\u001a,\u0013\u000b\u0017֫\u001d/S{/{L2;\u0017*P_ɤ3\u0001<\u0010/'/cn\u000f\u0006Kӝ\u0001woȌ\u001dNm ߙ\u0015\u0002|`\u0007\u000b\u0011\u0011\fҍg_\u0000_Zb\u0011 o],/6\u001b\u0006\u000bӫuZ\u0012oT\u0003)\u0005_\t_\u001c\u0011ӲLRaP/.7!E)+ф^\u0012,\u000e\u0014|/).|/\u001fgW,+͢1\u0003l\u001cvn\u0017*\bwnL9W.8]zV`^x(~Ŀ\u000bk\u0001j@ȝ8gYe\u001eqh;NW\u0000UI^Iu|n/iS&\u00176%ŢoA2W\u0017\bA?P-$/ZW\u0004\u000b\\\u001dըx\u0002ZC:J\u000eAP\u001c䵄\u0002j㯄C\u000e;=\u001fpW\u0015c{M\u001b\u0014S9^T\u0017\u001c%\u0014VeqA0IK3bxQA\n\u0017v_w\u001c\u001d4+^9^y\u001c/20:\u0012K\u001arMJxm58^z\u0013Ƙϥ\u001aYSG{Sֿ\u0017+糖q$\\$\u000b':Nl\u0001[\u0004/^G['Tߐ9\u000bt\u0017\u0012<|#\b^z_s\u0013\u0010Z\u0004/,ޠ|\u0005Kό![qSIAJJ\"xm5\b^2,\\G_\n=\fIgJ໴&]%\u0018;\u001e\u0016f\u0019\u0005ug=ڵy\\8M.\f\bϱpBYЮ-$f\u0012\u0003٥́\u000b٥{Y_MA(\u001a.jñx][b\u0015\\D.RкN\u001cb\u0015zY.υ:I-lP֌ӥ8\u0010\\XYf\u0015a\u0003\u0012A;gPq\u001d/颢h\u0015鞀tm!1\u0018cw\u001f\u0000ûI]~\u0010Иf\u0019u܌|\u0010\t][\rB\u001e\u001a\u0017Kϕ_M\"\u0005L\u0004+\b]\n-\u0010]8\u001b!!\u0018D\u0018\u0003ѥ3/.9^.Z-pA[\t]=v0vX\u0006y)еD't\"\t]\u001beB\u0017\u001d*\fB(\u000bB'\u001b%ݛVԅfq9'tg\b\t]<}7MXN8۶\b]V\t]m@\u0017M,@\u0014\u0005]d\f@\u0014rE\u0001\"ҳ\u001as\u0001h|韂R<BsBsC){As)Bk\u0001HCs)B\u001cp\u0014 S\\Rz\\\u001c8\u0019\u0003+L\u0015$h.T\u0012ߚ%n!s\u0011gt\r2Պ]\"s{\u001e\u000b\u000b\u0000z\u0014aû\\Ғ\\)\u000e2x)\f2W'y̥^+E\b2\u0017ȂeFfsIo\u0010L^p.|Yg8\u0017/\u0005Bı\\(-2K*\u0005碿\u0005ctylp.E!\\0\tn\u0010dN\u0012\u0012\u0017BR\u001b os\u0001.ht.][RȊsu9*v<nAj2Kq|\u0002ϥyd<T3\u000e<9\u000be&\u0016S\\VJ\u000f<\u0017\u001cυr]E\u0006\u0001vk%\u0018Υ*\"ӹo\u0003ӹ`:\f:\u0017c\u0006Ar@jCp\u001e\u0002G+|.=Nx8Ms3jÜ6\\\u0012\bW\u0004\u000bA1B{\u0018.;<\u0017KZ\u0019P<\u0000]-\u0004*fV\u0000]\u001a\u0019\u0003\u001c(z\u0000\u001a\u001eLෞy\u0007\u0003\u001aϳ\u0000]\bJf@\u0017YX|.\u001fY\nCd>(8{\u0005K_Y@>?c;*KΤ7n,Gu\u000e^R\\S?./\u0017^d.\tx7{V.־\u0002˥I;\u0002[zEvr)Wbr\\%#.\u001aJ5\u001bȥwq\u0016i<)uqÏgø.y]-\u000bu:*K\u000e\u0003fP\u0014\u0012(gpaZw\f\nWpiEOP0f\b\n\u0017!IvcA\"Il2S>]^bٌ6K\u0005ސB\">ϦpIYPP\u000f.\u0001B!j\u0010.N\u0010.\\ʹs\b\u0006E\u001aEO\f.\n_GzA-l's11f\t\bnծ\u0005Kq:2%C?\u000b:(\b\\w\u0016\u0000\u0017ka\u001blvoW\u0014\u0001&U,)QI!\u0007\u001e\t^\u001bW\u000eJ\u00053x덀so\r|\u000bE\u0005[[Q\u0019-.\u0013H_kM1|u=<Y\u0015E~GsUG3Jm\u0018\u001ecTHY[*\u0003Z\u0015FEpT>\u0000m/KAْlaERHKl\u0014\u0005\u0017c\u000b\n\rz!lV{hьw\u000bf3&R))8e{Eҿ>\u000b\\Ҳ\u0019>SKf\u0010|g\u000buwǨ:WD-Lpֲ%\u000f\u0016-\u0000r\u001dx\u0002-.@\u0001ԢX0\u0000\u0019x`\u001au2\u0003\u0017\u0016/\u001cE\"ˠ\u0003+LKa/\u0006 9C8I\u000bb#'嫫h\u001a\u0018-m\u0014\u0014-5S(\u0010->\u0006CqRLE\u0003@\u0010aư\u0001\u0002\u0005=RQ+4\fkz\fzQ0ó?e.vmޜAΒw\u001e\fz\u001cw\u0014,5\u0006Sci,\u0016\\جk\u0011\u0005\u00164\u000b\u0002\"%\u0010@fTRk}Xk6_}nIei\u0003\u0014,%A\"t\u0005E>鋕,שּׁ粼^FeP,HYEdM&L֌Qd\u0005* Y}:%_v\fgM\fUiR\u001cMcsgcM\u0016\u001bKfІ<FX2?8͌5\u001bʿ;\u001a֜X\u000b\u0001ҘeD04%\fT-$4*.3dr\u0005\u001a-?3\u000fZ1a,M,8,ӟ{ѰT:`XJj7\u000bK3\u0007\u000ĕ\u0014p&\u0010\re\u0010p\u001feRkS\u0002C,\u0014\u0015\u0014,ڗsQT\u0007I6 X\f 3Ct\u0002\u0016a*{^{\u000bq/\u0015k\u0004=ub{W$A\t\b\u0004\fF5+#\u001b~\u0005c_\u0007'\u0019+V\u000bUk>\u0015UUkoW-\n\ndЯP\u0014~:b~ŲOo٢_5j{߱WR0ӯ4኷Wdٌ\u0004\u000f~JW\u0012(\t\u0004Sb_^jI``g_I&\b qWR,~\u0013\u0019\u001d\u001btC_Gh=~\u0006\"Õ+ \u0001W\u0001X+\\鬂W,\u0015\u001b\u0015\"Jwg_\ne2A;f_̶Wxޕ|%\u0003\u000eTo+\"\"\u0019|8m\u0002|Ev\u0011eWӃ\u0013JyO~ \u001d\r$\u000bzО\u0014+\b\u0016M+vQdOQ!Wˡ.Wd\"(\u000e\u0015{LjĸۻW8#|\u0005EL&_z~ \u0010\b\u0015DA2\nK[]\u0010y|a\u0006_a3i5\u001eֶzAr`U{\u001b|%r\u0011[4t7*'.\u0015*hp޲WR,ˑW\r+  ZNzrc~ge\u0015\fA[\u0004ʚ+bŖ54\u0015uVF)KZ\"_i\u00004WR$+\"o|\u0016Bm\u0015Aj\u0011䫆}\u0016\u0015\rK`g_ģ0Wt\fP\u000fW\u0003~%'mDl\"yMB^7\nRN\u000e\":\u0007Ԝh&_Y \u0019|E _)\u001deyL )W+\u0017\nJ5/L&_)Yf=nk)#a\bA\"Bt'z|E\\khПh&_QZ{\u0017+L|eHW\u0015Y!nr,Ot<|ř\\LRV>~fԗS\u001afȏQW\u001cXhH;WSXF&_q&OdwGw)+}\r[\u0004@\r\"Y\u001be:Rf^ed\u000f\u0015BpI+J\u000f(\f-\u0001RNnv\u0006_u\u0006{n3\u0015r\u000eȚu\u0013l;iH\u001a8C'%T\u000b\u001a>\u001c\rendstream\rendobj\r22 0 obj\r<</Length 65536>>stream\r\n1:\nW-\u000b|EJxo,yd\u0000\u0004\\`K+l^\u0018&+\u0019YTdzQ5=\u0014I\u0006J_\u0006B\u00007*-\rr6\u0004\u001b\u0004R╕Qp0e\n\u0015xrsX@ê6WVzEBL2^+Z~\u0004J5sz)T\f֠Q\u0016A|N)D^iAD~q>ނ8G^^54UW\u0018\\+A Q AUmQ;!G^\u0001L΂VAR̀\u0013~fD\u001c{w\u0002^r\u001d9\u001e(\u000e\u0015'IZ-vk\u0019+*Z٧\u001e0\fڕ\u0019Ϣ]\u0011]hW|&]I`\u001aF+/U{Q^uF\u0004J-{ʌҠ!pWzቴEafܕ&}*Rq\u0006:pWzO_.o\u0005ٍvE\u0015e$R\u0012(˴+D<.pJЮ\u001chmMo.U^\u0014\u001cN|\u000b\nL\u0003\u0012j\u000b\tE]5hW8Ю4DfU\u001a+\\\u0015eN+4\u0018RNBЌ\u0019+\t3cy~\u00050*8`W\u0012kdU\nΚ\\aqW\tw]u6\u001bw%\u000f\u000f\n\u001f񌻒w]-\\\u0010\u0003we\u001e\u001bw΢pjϸ+٨pW\u0019wpW/\n-᮰ϸ+\t\u001fܕ\u001e\r#c\u0013 +\u0019Fz \u000e:|s\u0012+Z\u001e$Y~I]I!|\u0014?\u0012`WDh'\u0015K|\u0001>[#\u0015:ͤX܌ź`uY\u0012JE\u0011uE\u001cMwP .I\u0004/,jF\u0016]9\u001eǋ;Q՟ºƛ\u001dVR+ڣe\u0015k\u0010\u0011,sx>5îы+i$\u000f\u0015I8\u001fj\u0007fqWq|,YR6\"\u0004]q\u001c7^N\u0018*+-zmWCh\b\u001cʝhW9Y\\7hWZ^\u0014+9!B\u001dE':A\u000eE2\n_Ю-ڕ\u0014*p\nni\u00164Abu\tU7^iWl)\r\u0015係v\b\u001bBj\u0002\u0017J5i\u001easV2*?%U\u0018}»󾃷!8\u000b\u001bʄ\u001eF@^#6ׁGvd\u0015*EہBa\t\u0014\u0019yvOSh#p\u0000dB^uS\u0000\u0016+WII\f[\rBYRW!Z)ī-dVxE\u0016pՎl\u0002xe5\f̘Jq3ϸ^ڭYY\u0006^500]0l=\u0017\r\u000b,F\u0001bE7Wd\"\u0010\u0012\n9\u0000\u0003uU\u0013cY,aϗӮ숣ShW\u0000XNҿ4\u0001<&1fDuuXNwA*ӽs\u00175u8Wgf\u0015 >,k\u0016t׾\"yl'\u0012?\r% V%QPx+u!E9\u0019u-\u0006\u0014v䄂m%vd\u0015!'l%\u0006\u0000[\u0011\u000ek\u001fVzYH\b\"Z-!\u0003\u0010RYkCcU\u0011\\0+(6j\n%\rw[(:\fR?9pr \bUQ$c>\bBX]a\u0010 VK\u000bJEH\u0005y\u00004m)}\u0013\u0012\tV2*Nz\u0010t0.5'~%W=t)'\u0002\u0001z\u0014$UӨUZhUʱ\u0014 %UO$l\u001d[\\!wF\u0015\u000f't\u0016J\u0015owf\u0003d\u0005\u0001KH-z:Pis\rl߂ֱ:\u0016oo[%dZ\u0012V̢Pn\"_`UD\u001fo[E\u0002\u0010dX\fjQGUCd`iĪﰺt1\u0017Z\tTu\r^\u001dSA[U\u0006d\"\u001f^\u001e*~\u0002Qu_\u0012rS]nַT^&e:~!K<\u0006j\u000b\tMETA-0\u001cdB\\*}תiV}W\u0002r93\u0010\u001fs\u0010etFv?TfU\u000bHE\re׃iqFXT\u0005\u000e>*C*\u0002TW> Z\u001cxB\nXbPTq\u00108\u001f\u0006K>6Y\u0010U#ƪW{\u0012\u0011৬\u0017=+\u0016~mU\u0000Ta*\u0001O\u001d\u0002l{\u001fyB\"yER.̆1S\f2:o?mJ@By\u0016\nOXCO\u000fflw\u0000\u0015\b\u00013˓\u0011T\u001b,\u001e\u0003AE\u0003 g\u0006\n-3I\bG[U+zo!mg'\u0002\u0015&v[L!P\u0015\u001e\u0006-\u000b@^\u0003@N{v\u0013M\u0005J҂@L2o)}{\t\u0004\n[j3\u0017\u001aq\u0003A.)\r\u0004\u0015i~>\u0010T\u0018\u0001\u001b\u001a˩0H\b*Ϙ@ۦ]E\u00108@6\u0013\n&\bT{\u00111e\u000e\u0004*ǂ@iz@E[&LBԺ+\u0010T֞eQg^<i\u0016{?\u0002@\u001eb\u0011=M\u0012\u0019@Z\u0000<6l{Mllp~J#\u0016>6>d\u0002\u0012@e\u0004`Kѝ߮\u0002A\u0017m\u001d^\bgҜ>pAj\u0011O)])[oX($4w5&ABP$1ӧɼA7VJ0J=î!\fR2}jA\u0001b\u00179ӧS@.DTNR6m>\u0005t'&SAGm\u0011\u0014JO8ƢOQNeoЧ,<>Es\u0013>\u0006/?G=fAV*ӧp\u0018sfOѵ\u001ajtإ;|J׍w5SKH\u0005ʂp}Jğb$\u0006\u0018GXѐ6گ'\u0012QF!\u001d*,\u00173'Ke*(R\u0000uTsϻ2µS{/\u00166mDO!vKQ8@2原2^X9\t?odž\f\u0013~đ\\A\u0004\\BK\u0011\u00197oNG={\u0002@6\fLT\u0001F6\u0016J@f\u0019@\u0018\u0016\u001d@Em,E\\2JAdn:yAe𧖐S[t\u0014%)R\u0004kz3\u0001\rS5̤X)\u0000*D]\u0000P9:?\bT)\u00130\f薍bUG Pm!\u0011\u0004\u001e`K)[\u0004[&=688 P7Z\u0012\nQ5\u0013Y\u001a\u0018\u0003@Ś\u000f̗\u0013\u0010TK\f\u0006v7,\u000b;D+5G\u000f\u0016w\u001e#.\u0010%\u0006\n:[%_\f\u0019BE\u0002V\u0001R>\u001d1\u001dVƕ\u0011T6\bT\rg\u0002}/\u0002@xmքfIS\n!,rMNb[S\\\u0006M氩߅5>V \u0000M}fLřT)\u0015y>HSR\u0001-U߻\u001b.FRz7GP%{wةH\"eNuI\u001er\u001d\u001b95\n%6Qk\no;FE~^3b4z&8\u001dbhr'-ԮO \u001eQ\tC5\u001dzZӟsm,\u0007\u0018d͛}Pk\u0000v\u0002.PJ>DeU/!\u0017h৚\u0017߈ϵS4<\u001aJvM9\u001dAՌ'%1\u0011\u0000x\u001aJS\r 3(T*\u001d7\u0003=\u0013Ճ|('bj\u001b\u000fCc,\u0011vH1ڙ:/N)ɘHI\u000e\u0003VbE_Vy+xe_|m XlI\u000270.цWa9'HR\tK\fanRJ\u0017r\u0016%lU*e$\f\u0004#:r\u0006\u0018\u000bMv/\r2XP/M3BT\u0017\u0004\u0010\"v\u00071T\u0012x(v]b-\u001d\u0000zV\u001dY6]tSmoP\u0004B)u8`04c8\u0006\n1(\\\u0006BW\u0006\u000fXbw\u0007[2\u000e\u0015\u0001\u00049;^tjPZ %z\u0006\"\u0000V\u00168ܓ:Eɘ^N(\u000b5\u0016:O\u0006UxULynI51oZ5Tts!\u001d\u0015S<~x\u0003 #ЉI]`I\u0012;{\u0016dfr5Z{9)-|.Rm9*3vڙ$\fA+93HVm\bY>b\u0006]~1\u000e\u0011aۃa\u0016g\u0012ހs؈Ժ0\u001b\u001c+6fL\u0014\bOz4>\u0007J\u0010~U\u0000e­R`ϢeV.QOΌ|\u000exfK\u000ettX}>OUeb+@VR&\u001aQԆ㞨\u0006\\\n e_~f{oQ6~b+p7Wq3#\u0007:_pn)1Sz\u000f݌\u0013pb\u0016% q\u001dsH\\J`9bf\u0002TZ1@`!\u0002K5ⶰ\u001dR_Qhb2eT1\u0010(ZMe!\u0019VƦFz_ה;MRw\\\u000e>`\u0005{\u0013%S\u0013i\\\f\u0004kbS^I#n,ݭc!ēd\u000f?I\u000f\u000byʝOm>_z\u001eT-\u0002YC\u0019\u001dG39\u001dT\u0018\u0010\u0015\u0014\u001d\u0014\u0016ptE>+<xTԥvs\u0014FPs7حXI}E\nN\u0006{O\u0001\u000f\u0015gR\u0003ySRڳ\tYI=5q\u0007w\"\u0007\u0001B돹7(Kg\u001dkxv\u0014\u0003/\u00050pYS=R¯\u0010N*P#R0e5YRYQej\u0011D^W\u0012)ǉwSfIX*MR\u0016V|o\riJ>;R>\u0000\u001dӊ}\u0002+Z\"\u0015yïr\u001e\u000bp\u0019\u0013iVoY\u0002\u0003D;\n˼ꌓ˔l)%ɴbH\u0011l^\u0010-\u0018^YpfA\u0019+<>}\u000e\u001fÉ D\u0004!®Pn?ͨ\"u_Od3_Tp\fK\u0019jzt7@yG\u0002j\u001eGD\u0019_?\u0012\u0014\u000bc_X$bMox\fsn{F\u0013OY8U\bJLYL{ra\n3G>Nho\u000fXR?l\u000e[<(8\u0003٩B\u001eV$8\u0014L?I\u001d\\XLK\u0019kmU\u0016/ATe)t~\u0007p\"M)1e dEaUm\u0002M?՘>4\u001aBK{iNǩ,Q\u0001\u0013L\u0017m\u000b&a\u00110\u0014\u001e}R,\u0006n=kVKSQ])AJq_\u0015:n?R\u00196Œ{|bgv46'Q\u0017䂱U\u0015k\u0013~30{ZF5}ճ\u0015N\u0004tB\u000fj䷾\u000bּ}T3i5\f.=\b,UBbN\rjMD\u001c\u0014\t\u001b'X\u0002\u0013472zqL\u000e\u000b\u0007A2bAR-\u0013ZFǄ|%>)vC/іIK4ȁRҀd2-\u000bV6\u001dڝ5g=\u0012K\t\n`\u0007:D'8-V'es\"2)g\u0006\u0016\u0003a~\r2:aN\u0014WH\u0007YM\u0000\u0014\u001d\u0004+NOvy\u001cb/eȥ\u001c5(/FF-@`3Sh<?Q\u001b_L,O+Wl{[f؋2V/%\u000f\u0003[U\u001d@)קL\u0015]iUk\u0016\u001b+\u001b\u00042SpLb1\fqzXi\\M]DKƵw)2AV+տuP\u0006\u000b\u0014Q\u0001\u000e\u0014\bLkTzԺBd\u0000)ҵUg(5Zz\u0004S2ϢR`\\\u001cUi=\u0017\u0007\u000e6\u0006'\by\u0019r\u000fߤl\u0004\u000fEc\u0011)w\u000b\u0000٧)^Rme\u001c˼L^eT7\"$\u001aݙmf+SӬ⯝E:+b?W# _t͌jaft>\u0005:c')φ\u0003l.\u0019ǻxlr8☶WNěD\u0001I%ڨ/\nK\u0019:h?\u001eX\f3#B\u001ay4\u000e)\u0006r<\b\u001fjj5\u0015E@C}9,ԗԿXK5\u0005{a\t\u001b(.TЋf@z\u0010/\u0004\u001dM\u000b\u001b[Qgv\u0004\u001ae\t\u0006`<&\u0006\u0012ڡb\u001bÂ\u000b&ɳbq\\ƀmQmn\u0011TMQhK|\u001f˨<Uu)sc*qSݶ,\u001fAhx\u0016Ngu>ڍNfݐB۲b\\1H>\u0006\r\u0007QG,.PX,^Rm}\u001d&U\u000fÛ\fJuC'/Fu\u001c~D/g/\u000b\u0014ޥ>\u000e=1ڇ7Ǘٜ\u0014D%M8m{)_pP(&OL\fb\rr\bUt^8'h\u001d\u0003jECYԏ^ݓY\n\u000em+\u001eCH7\"\u0018CpXҋ3AYN jR\u001dj;\u0011\u0011LW2ͽfҟmUw(WbhrQ\u0004rN#e\bcl\u0010\u000e\u0002W\u0019[\u0019wd,\\\u001aXtٵN<vʎЬo\u001e\fML]\u001aOS1C!\u001e^bIp\u0005C՛\\\u0001u)i:o/?o.<80t!ɼq\u0019\u0017l+jGk\u0010\t]f>2QYO\\_\u0011XZ]Z9|\\%i=B\u0005d\b-\u0000+\u0011m,\u000f|[>o6')\u0007g<=Z\u0007*#\u001ax\t\u0015=9\u0011@\u0018M\u0012|\u001b+7̭Xt\u0013s\rK\b\u0012k{-l{Ӱ4ɯh^l+\u0012ϖt9\u000e^\tQ}cEOg&9h\u0000P.\u000b+\u00130,qhaJ\u001d2B\u0012\u0000-ےr,C-6+J\u001c$\u0012\u0014*xms(\fG[`D\u001e%E\u00186ise\u0019#hº+4\u001cQR[=r*7AXe$ҁĤm9u\u0013\u0015\u00165\\Vb\u0004\t\"TZR\u000b&B\u00043`iMbqwqÔR\u001d!/;/=`Z\u001a+ߢ=\rS AcG0jeUX\u0011ذ\u001a|IWifߞCf{Zb\u0019\u000b8.\\<\\ﭜ\u0006mv^$K\u0010o^\u0004'VOZrkФzRp`7\u001d%>ͤ#\u0019cVJ\u0014\u0010Ba\u0014\u0012z(kZu\u0006']Zوٲ1d]~xt\u0011\u0017>\fU;#\u001c=zCa\u001c+FkEDP0iI-\u0004P`n\"*ei\u001dr.Lz\u00141E\b[o6P\u000fw*K3e?QN\u0001B_sS\u0014\u001ezjGa\u001f{:Ɇ\"vb9Kv\"a?ُKJyn\u0018AiuD`\u001e$0bR_D\u0007#t\u001f\u0015\u0002^m\u0001\\~\u001e(Y9TpZߺ9\u0010=\u001d\u001aU/Z\reTxYvU\u0010!٬j\u001b#vpװJe\"՝`JGuv\u0001\u00118t5'؉Ց\u001fF\tGO?뼉i.,\u0002C\f\u001a\u0003ނ!&R+OdN\u0012j$֭\u0010;kT\u0010;3\u0001!v^X9?7-\u000epҙ7u\u0019[꺪mO!hJPq\u000b\u0016\u001bC\f\fA.\u0006I ۩#Ĭ[SVp@qTj_\u0006o-z\u0015E\u0011AL-tf\u0010Ĥj \u00025-\u0017C\u0013e\u0005\u0005ȒI_j\u0003^-\u0010b~\u0011\u000f/*]'\u0010n_#qh\u0012\u00041\u001b''-OC\u000eS5w\u0010\u0003Yj\tb\u001anxZ-pG#CJT& b'nZ\u0012KyUh#ʈ^6\u001ew̬\u000e\u0003 &%b\fzI##\u0010\u0004z}~[-\u0006uC;ۇ),\u0018\u0012\u001dJV\"\u001c\u000bɤZ\u000bİM)Et%\t6\u0002Zo[7rL\u001aJl\u0003mF\u00165\u0019\u0015\u0003i{yV\u000eFk\u0016\u001bYjVX\u0000Mu2R#/ԧo\u0018V)흥(j.Ĉ$\t\u0016˄\u001b}C\u00015vu\t-\u000eI1Ո*K]\u0010K\u000bUt}4,Θt,\u001e\u0003\u0012L\u0017\u0013\u0018\u0010\u0016ilX-\fk;QI\u0019\u0004mL(ͨ?yɯn<OZ\u0007qlⰯ\u0003ypμS;&#X}YR\u0014AVUlt\u0011v[,昶փ)F\u0003c\u0004G٩cE<s\b{y1 =nܝ\"\u0018SO!\u0010x_[`;ғŐ\u0014*!)=̃\u0000/nM4-\u000e+H\\б\t\u000fI](13\u001bמ8}c\u0005RU\u0000#RbLs^)c:bm\u0019:C0P6\u001c\u001d(\u000er\u001b\u0018\u000f\u0005fX\t\u0013\\\u001b<6A\nP^\u001b.Ջ\u000fM*=gLb\u001a\fUKKĲNnIn-IIc'f#*<\u0012Iuw\rXh\u000fT\u000bHs\u000er\u0019ow'\u0007\u0014^\u000f+KÌ\u0004b\u001d\ff5ojiǛTDeFsBΠ\u0017\r\u0011\njukf̆uȌr\u0015Dޚ\"Pi?Р+NJk{$J\u00145Md\u0019J\u001c׀\u00006')/\u0005\f2*<:I-5\u000f2\u001aZj5r4\u001b\u0005|Q\u0013#1yY\u0000Q&a4|F9\u001drz߯zX1T\u0014Iw\u000e*CU*X!LC1V?\u0019[H\u001cBL/]LQq\u00037Ry\u001f\u0015\u0006B~wŚq\u0012i'\u000bdM\nK4\n\u0004(\u001b'pE-Jw_\bW:/mů\u0007wU\u000b\u001f\u001cn<dbr3wo$;\u0012=\u0010(\u001b\u001dѮ.<hxcءFV;'Lhu@ɯ\u000br\u0013m\u0019nEQB\u0005,l\u0005ks8;F~\u000enY:aϤ/R\nKo<-\r0ș\u001aOB\t=lL;\u0004\u001f\u0018+4sǮE}~;S:\tL,uw\u0006\b4\u001aI92Wv\u001e~\u0012c.\u000e\u001a1P>Ё\u00105oײcN\u0018\b&\u001fnj=,݉\u0013'mEbǽm5\n#M\u0015[\u000eY$0ПlaF-\u0000Y%Jk\u0019)S\f\u0017\u0013_\u0016pxTKe\u000fFP\u001dd\r\u001f\n\u001bhP\"OYYiR\u000fBzde-)E3R\u000bU.F-6\u0001ir\u0002!\u000btCzF*\u00154Vj\u0013\u0006L$i\n/\u001cWDoc+\u001dlOQI\u0019B\rްgCԤi$+MЛs5FY(5\u0001<tj,5ĨGASCF_85ΣqU(K'ة'윉!\u001b]j96pHb-\u001f\u000b\r[j\n\u0007I\u001dįKC\u0012\u0012 lگ\fX#K[n51֚Y4_5B,dܷ(ÏTB\u001dQQ^\u0018~\u001bu*G)Nr\u001biɆ2.'9\u0017&0m4\u001a$hkx\u001e-:\u0006nMg!ƃRv\u001c+u\u0000OX\u0019zqkU\u0003~Fs4ڌ2S\u0007I*[Fw0ψ\u0002QU4\u0012RV\u001a4@(lCJXq<(='6hkDFk%n3\u0010 /\u00023\u0012y=J\nKb\u001b\u001b$bd\u001f ߄N:N4jLd.: :\u0007\nɏ8biܐRQ<T\u0012o:\u001bfݫ\u0004&i\u0004dv5\u0007oMɢ\u0019K)Sq*_\u000bq\u001bj`Τ݉\bp\u0002 V<\u0012Tp@\u001e.V\u001dR~QܛRfe`q\f}\"%\u001a,kR~jEB\u0014^^KC|F\nM^\u0012\u0002&HIWx]D\"_2\bi^#{?vP B\u001c^TZ=\u0019-jor~PBXQN\u0014FP\u001e#3 M\u0001\u001a\u001egL?P\u0000\tL@\u001a\\k#צDڰ\u0017L2AϤ\u0010V*R\u000f]TNͻv+9#\u0017\u0019!Y@?`\nJ_>}oR1Q\rB1[\u0014q9P&U\b\u0016s\r%\u000e@4\th̕b-\rR6\u0001~PBty\u0015k\u0017n3wz΍3\u0016o'-\u0016[ UkF'\u0019ǜ]Bj+0t[S@4\fXt\u001d\u0001=@4Gʮ\u0005wN׌ \u0016[dieA|-cxjXTY\u001es1-\rn,\u001a*\u0011{ő9Q,)\bㄔyLZ\u0002]!\u000fr<\u001eߓ\rn\r3%\u0015AH9Mn96\u0002\u0015\u001a\u0003G\u0014}iJYlS3\u001a\u001eC?\u0001I5\u001e5c2A`Sњ^\u000bV66NZ\u0002kݠ2oV|:\u0017T}c(~\u000e\u0005\u0010j\u001b>^\u0010б\u0011l[x8\u0019Rmt[\u0004Jxc\u0015۸,x0ڈT9gA`;\rfÂg6Ԫ~ (lg?b\nZnᑕ\u0011e9W3a$\u0002N\u0012g|F\u0016\u00186}\u0011[hو4Kb4\u0019SKSpؔ\u001f\u0014\b\"sQ\u0011l\u0001Э6j\u0012|~JN)\u0012/hC\tVZ`bA0:V\u0000xjX5\u000b\u001a'<\"˭#b!aڪ0\u001e<\u0019ARdUy\u0014Y\u001d4\u0015)\u000bFJ\u0010x{yo/\u0010\u0014es}`mIZ\u0012иu4+[ZCHl'6\u000eJ4\u0007EpY!vZ&@\u0002jZ`ؔ!l\u0017ؓnL\u000eE>/A7{aؔf2k\u0003\\q;a Kl$\"\\{p>Ҳ1\u0003Şp ;y,5|KX)H\u0004?i%\b|齣mH6U@|3m7\u0019\u000f\u0017M+\u0011\n\u001dK$C\u001c\u0014=O@`=b\u0017.E\b\u0016T\f$\u0013h\tԉcg\u001a\u0005Q\n6\beZ=\u0006Yil\u0011\u0000Nl7gs6\n\u001b\u001cߴ7\tN\u001b\rlCL\u0015\u00190I9}T\u000f3#Jy\u001eQ\u001b\b\u0015l/C̮+\u0018g2q\r5\u0011Hjƈ-\u0013\u0014-Rv6L޽˪\u000fL3G|ݡiwy\u0018v\\6\u00150]*7dպNk\u001dw\u001d l{\u000b`hjubrZmRSgZ8Nq}\u0016q'4\n\u0010hj-\u000f\u0007[jW|Q^F}JRO\u0016/oEJ8jQ`6 \u000b\u000fϓα-}-y0\u000ebQu'Z<0\rt䬑V\u000eRVG\u0007\u0019~l4k\n\u0007vvb\u0014\u001a\u001c\u0015a#wl\u000e\u0019n\u0001xiTcl[۩΁l\n\r\t\u001a]w\fHݸz햊f\u001cJ\u001b[n\u001cD܁Zut7\u0017v>i/\f<4\u001aծ\rx;\rEhܭ\u0017SW\u001dy1%^@!6\u0001re9(\u0012RGsQ\u001b&u\n\\\rC\u0012TUb~ǍcQ^l\u0017i[dx&\u0002\u001aW\u0015}y\u000bF\u001e{&yi@[\u001b^̼/^yVrnf`FSc]kZ\u0004$9oRe\u001e֫CZ\u0000\fz\u0012@\t\u001bGi\u0016QFFfqc\u0015|\u001dd]E#2\u001bwZ:H<o,d}@\t\n9\u001e\u0014\f;qߔ!ԉTYCB07\u001d\r1w(n١%\u001e\u000f[kbϝϿEK`$d7ae5BJz\f%\u0018p/\u0015G\u0001jxB>Wt\u0004\u001c*2G h4L|\u0002YVlJ-TMf\\7ݝ[\u000frJ\u0011-\b\u001c*bW7\b\u0014\u001e:<\u001bJ\f)Ԇ\u000e\u0001p^~q)z\u0016\u0001\u00005gTN\u0018d\u000b\u0013cOIU-HjBƀ[\u00029\u0018͖\t(P)}n\u0004IzfH/\u0018m\u001ap9jѣ\u001cEvT$\u0007U0\u0002VA\u0003\u0010G\u000f\u001b>M5\u0016\tLQcx۪\"b{k\u0019^T*U\u0015\u000fP!\u000f<&\u001e\u0004\u001c8\u0018i7\u0000\u0006%1\u0002ei\u001bh\u000f\u0019c\u0019\u00048il=͉p+F\u0000۞z\u0011\u0014]\rknR\u0012\u0000<EYS\u0015\u00048b~YjU<\u0012didW\u000b,\u0004\u001c*\u0004\f')q#Rk^oәm5BG\n<\u0019V|\nS؁Lneqke@{6;Vۗh|\tK>M(_w@pRR*ZG0\u0015y\u001c\u0013Z8s\rZqc:48>|Fm僩\u0014h6kȞ`^G`5sFV)h\u0013\u001ejn_8\u000f(JnoQEⱲ+\u000fԼ\u0016bf.k\nX\u0006;7}\u0018!H?I\u0001`é\u0018 AOش\u001a(\rr5.J\u00166*ΰ\u0015MC{Jaٿy2{\b\u001f__hH>ZZs;}=|!\u001es#*22z\u0015euL^ \u0014r\bU]۽oƙry~\u0006nzJadЍP\"&My+ٜֆ\u0004AK,sK[\u0015Y\u0007d\bgXA.\u001eb\u0018\u001b)0-\u001aݳr\n;R*\u0006w\u0010)ӐJ@1q\u0014,J%Dz\u0012{%x'\u0004QUR\u00158!܎I\f|%\u001c\u001e\u0001\u001efRGNGU\nB\u0017ÓχA\u001e7l*Ská*e[}Y`\u001cw62\u001a[\u0002AU\u001bf\"ֶ{#=t_J<\u0002uʘs)l*0N\u0018\f\\rnm\u0011mžk\u000b8.\"ll֏k\u000fGj\u0007sOa\u00178yi,\u0000zvW\u001amCbSM\u00005oidSQ6WN՞+>{벙f\b\tMCR)+c?Дr[\u0015\u0010\n(m\u00018﨎\u0001V&=xbym\u000bd\u000e\u001aޢ\u000e9Z\u0014澌3gY\u0002\ry@(sq\u001cT|\u0012Pe4K]\u0003\u0002;\u001eoBO\n>uep\"ް9GszMz\u0002Zv\u0019!C\bݾ\u0013ު\\\u000eN/\f\u0006ba}b\u0005w\b9\u001b [xo4\u000b3\f='K\u0005s\u001f+C\u001e9r#\nr^𵩽M\u0018\\\u0007MSڦޫi\u0002ϙ:B\u001fw\u000eWPPq39,}zbޯ\bM#\u001bYA\"͎\"\"\u0001V]S);\"\".)B\u0004Lی\u0011\u00054Ċ\u0014E@M}\"oDsE\u0019#7Lhn\u0012\u0004xp(I*%\u001b&#kE߭4幃;\u0010L\u000f\tRj[27wl?tSc @Qf4#\u0011Y1LF6r.*lzGm\u0006wd94uHx\u0001K\u0006ۘMR\u0005a]fTV\r3@Z?@Ln\u0015Ͷj冨\u001d7)v!aL}V\u0014\"$:NlϹ\r=+25ý,\u000e\u0001(!T8S\tpւV\rmmަ~H\u001eJ>r\r۪\u000b\u0001R\u0005W6yT\u0013\u0015ESï:N׊*s0',U\u0006R\np8O\\}sK4cn^r\u000e#\u0011V|舨 \u0018J( \u0010To+J18T\u0001}n>$\u0011}/&Zq2l\u0001µY\u0016`2DkM\u00144wT\feP-^ET\u001fwPM\u0014J]\"ԾR87\"50Qؿ\u001aF8vT3P,~{j!kq\u001c\u0014\u001c}\u0013o0è0f\u001d\n^.(>6NZ\u0013B\u0016^&c.l]hd_*^\u001bJbpP0|\u0006ڂ\u0016[j:Ӏ\u0014(15󞘙^;M#:Ngň+lLk3TO{N嵮n\t\u0014q\"Ʒm\u001dŝZ\u0007fQ{\u0014\u0015\u000f&|8_T\u000f\u000ef\u000b\u0006֖\nu&]Qu4VJnG_~X\u0013\u000bCItKc\u001a0=I\u0004<,\u000ftV|Z|\u0005J7\u0004!X\u000e4WG\u0015=9(\u000e\fQJE`Ki&%^ |(=兿ZKWqjb1F%>܎\u001e\u001eIqy~8%m[lf\u001azx3$uQOĵ\u00077.\f\u0016\\׊bgv\u001fq3K\u0006\\J$\u001ek:\\;h\u001f\\;}\u001e&@\fٵҼ,\u001e6\u0004\u0001[㼬Mn5i׽i\u001fB\u00109\u0006S`aʛ\u0006\rښ2ʟ80Fڗ%ЙwsF-\fHQyy*_H\u001bj9 y\u000eShml\u0005^Hfߩ7\fSV\u0016\n^g\u0015<;\u001f\u0000-\\T;a\u000e[J\u0017\u000eo\u001aWIjh\u0005oMm\r.8tXtFx\u000b/\u001aZƣ:~?h<\t\u0015n׊ӒSP\n\u001aώh<>T4-xZW4^ŊKiGi(hN\u0017׷%,x>h<\u0015ǚτƣ>x\u0005r΄f/h\u001eFt\u000boxP?~x\u000b\u001aO{Em%ؒh<k\t\u0007ccTx\u00174^SuP[Oh<ƓEI-h<\t\u0015'oA*h<z\u0019[b+\u001aO\u0017\u0000f4ͮ\u0019|Gjh<*j\u000b\u001aOk*h&o\n\u0019\u000f\u0003d<Md<)מ!㩜\u001a\u0001L\u0012C!uHމGZxv$2wiJ4T|xܪB#x<x7X|d<{xzE*\u0019^L#!!Yx˩d<>d<ҿ_xJ\u0011\n\u0019\u000f|xR+\u0019OJ%Q!(\u0006MLCƓZx\u001cWxRd<<\u000b\u0019ό2\u0019\u000f\u0019KdN%e&i=%\u0011*d<Mio~xR$2\u001eJ!\u000f!I%2^'qx(\u001f2LԎd<\n\u0019O5\u001f2JO;\u0013\u0019\u0005~!%%\u001ad\u0018UAc 4T2ZDJ\"%xBƃ\t!Rx(Ld<V2^\u0007%x\u0012d<j\u000b\u0019\u000f߼BJ&%x\u000b5ݗGC`!u9\u00172V2\u0019/NS-F%a!u\u00022\u0019k!i\u001a\u0014d<zm\u000b\u0019\u000f\u000f\u0019\u001cM!1\u00162/\u0019Oj%Id/\u0019Oj%\u00142\u001e/\u0019+d<\rI\u001d.cTΗk%\u0010d%Id<\f\n\u0019\u000f\u000f\u0019\u000f8\u000f\u0019OJnW\u0006\u0015j!G\u00172m7\u0019xRx_2~z%W2V\u0012\u0019oAS\u001c񔼯d<\u00152Ծd<\u001dVx\u000b\u0019\u000fh7;7t1*\u0019o+ mSx#~\u000b\u0019O\u0016}ҺJJ&m5x\u0014\u00142j\u000fd<}J\u001bg!\u0018!\u00162\u001eJ!㍳7d<'|x\u000f\u00172\u001e0BƳ嗌J3\\x&%%!\u001a!{ۙ/%d<`ޅDj@j\u00142\u001e+\u000f\u0019O\u000fB!dLj9Gχ\u0001u!\r,x2\u0019܌*\u0019\u000fۣBƓRxRd<'8旌i%\u0000I!R]x\u001a+\u0019o+T'id</\u0019/RxR\n\u0019\u000f\u000f\u0019LBƳ_KTx|+\u0019o+T'\rv뉌s/\u0019;xxy\u00152ޠ0U!id<QVd<6rT%m\f\u0003K\r2\u001e7ߐ(`/dq\u001f2XL#&x8d<M\u0007闌Xxd2)d<J\f\n\u0019\u000fP>d<D\n\u0019OJ!Ilɐx\u0000\n\u0019\u001b!\u0015d<\u001a\u0019\u000b\u0019}ڇGQ@!㙒xIH(0\u0002(d<\u001aV2y)d<+\u0019/) uL3\u0019\u000f /\u0019O\u000fK%iSx2/V2\u001e~l%I-d<Q\u0012\u0019\u0003>d<JQ\n\u0019\u000fBƣxCƓZxR*\u0019O%k_2\u001ej!qf&\u001f2~B!\u0002x[\r2^gd<\\>d<\n\u0019OJ%m%\u001ad<m\n\u0007O?KӳUxv\u00193\u0019/) ,\u000e2\u001eCC-d<)'K#-Tx(d<\u000f\u0019Oj%a,]x\r\u0019o8Y[\u00152V2\u0019oAƳxz\u0011d<\n\u0019 j!a!)\u0014ZxP\u000b\u0019o+U#Y59.d<\n\u0019Y!FWxfxf}KWx+\u00172V2\u0019oAKQxz>d<3\u0019OJ&%͹VJV2藌cWxTf2\u001e燌'P\n\u00193?d<{3\u0019OJ%a!U2j+\u0019o+ ɔ~xz+\u0019O/B!iV2&JSC!\u0011,dL3\u0019g=Dj\u0014j-d<\u000f\u0019\u001cy!az\u001c!\u00162]2\u0019_!,d<j+ۑxId-:\u0019X;^~xl\n\u0019p*McYxIId\u0006\u0019OJCWx4\u00162V2\u0019oAsTxz>d<􅌧U!\u0001\u0018c\n\u0019O'~x\nT2ړ*\u0019\u000f<ׇ7l3LJ&mx4_e2\u001e\u001e\u001f2\u001eM\u001eJF#$,d\u001f2\u001e\u00152\u001e\u001f2\u001ea!id<]/\u0019\u000fb(d<)_2\u001e\u00142\u001e\u000f\u0019OOQ!\t1SxLd\u001f2\"'ǆJ\u0013\u0006KS0:\u0014d<EHd<a'KC-d<\"0'K#QxV\txC\u001b\u000f\u0019\u000fZG&)@Uxy&\u00142\u000b\u0019ol%㩍E!I,d<\tGP\n\u0019\u000fCƓZx\u00172.ΗW!\u0001(d<`d<uV2\u001e Bu\u0014Md\u000e)td<\u0014ۗ'+\u0019R~x\u00142\u001eJ!|xdI2\u0019O_t◌Jƣ\u00185~x6N&2\u001eCi!}\u0007\u0018=2&~xz\n\u0019ol\u00134%\rscNd<)!f2\u001dx\u0012d<Bd<Y%iPd<B\u001b\u0018̖\"\u0006\rߙ!QKWx(Ǚ\u001f20_x{y!D!I3X\u0000ϙx[\u001f[P\r2\u001euo%X.d<:\u000b\u0019\u000fr·Ie2vA\u0001B\u0011QTh\u0004*d<{JC,d<$2\u001f2K*\u00196vQ懌]%)Sx}x\u00172^\"i7%ay_x\u0004G\u000b\u00190뇌Gbn\u0007\u0019O\u0011/\u0019F!Id<\u000f\u0019\u001eBCId<_2\u001eV|+Vx!>d<J\u000b\u0019pc&(pd<ݏJ#&!)Px<\u0014ƗYd2@G4C3Vx4S\u00172\u001e\u000f\u0019Oߤ\b=e2\u001e\u001f2\u001ej&!\u00142Zd<\\'K7d<\u0015\u00152w7l\\P?d<*Αxe2\u001e\u0015y\u001f2\u001ej!QwDƃOb!aBOa̖4h;;޻:Lƣ2hMƣ3m?d<j\u000b\u0019IT\u0014`\be2\u001eՅGip\u00006XϦ<\u000f\u0019OSr;ۻx*\u0019OI/\u0019\u000fKB3LuᗌI%)\\xԜxC2\u0019퇌g_2\u001eB#WxJ\u001c~x\n\u0019O\u0015!qm2\u0019\b \u001629\u0017d2B_2\u001e\r;\u0018l%QZ!JV2\u001e\u000f\u0019lk!U2\u001eʇQhLӧx=틌G#|\"\u0001Vu*d\u000e闌\u0011p0\u0012\u0004\u0019r'2\u001eMYo2\u001e1B.Dw@\u00152xGCƣXtf%iM%a]x\u001d*qOd<ix3\u001622\u0019\u000f\u0019\u000fPxR\u001aLƣ\b\u001d\u00162'N\\Ch\u0014\u000e2\u001ee\u001f2Jƣg!Kƣڰ\u0018\u000b\u0019Yl\u001f2\u001e*<AƓҕ&Xd<),\u000b\u0019ϦDƓ\u0012\u0019ϔ\u001f2\u001e7\u00166h\u0004;\u001f2\u001eN^g\u0017TxTxKƳƼDƣ3ln%uG\"]d<d<\u000e2\u0019%P!1\u00172\u001eiBƳ/\u0019/b@U}x\u001b\u00142JߐʋGsz\u00152\u001ej!\u00142\u001e\u000f\u00195n!uJ3\u0019Oʗ\tE(d<o>d<BƓRx\u0012>d<`qG;$|xZT2J:Kƣu6Hg2\u001e\u0016d<$2\u001e..CcVx)Sd<Uvx\u0003Q&\u00142\u001eg~xR+\u0019OJ\"_2bG4%Id\u0001S*0%I,d<.b!1d2gyJƣ\u0012H\u00142\u001e\u0011\u001f2^'\u001dxx\u00152\u001eЧ\u000f\u0019\u000f#BƃkTx~xM\u00172Y&2/\u0019\u000f\u000bB/d<e>d<gJ\"\u0016\u0019\u000fp+d<)_2X>\\AƣǾ~xԢ\u00162\u001eߢGp=B(d<u~x\u001a\u0006*\u0019\u000fB# !)d\u001eA7\u001d\\\"1d2BƣCC-d<)'Kƣ,\u0005x(\u001f2uV%,x4K\u00152Ry_2\u001e\u0016\f㗌<c%)\u001bPxF^%\u00199.\u00142旌G\r}!ђTx|\u000f\u0019Z!Y-8CSZW(d0?7CƳLSKBü5<C\u0017d-vx\u000fV2\u001eyB#Kƣ\"%*\u0019O/\u0019o0Vd2u&ї!Y[\"Id<)_2Lƣ_P>d<RꅌgLƣe嗌]x3\u0019O/\u0019oA\u0017\u0019O\u001fUx\n_2\u00142ްDӓ^xt+~xJ^W2\u001e\u0006υ7ߐήd<m!\u0012m2\u001eB\u0018%Qx\u00106\n\u0019OMH%]|*d<7\u0007%\u0001<(d<-\b+\u0019OKc\u0012,d<]Jƣ9V%\u0011do<ߌ#Q!QPx1d2\u001e7\u001bd<=GЇ\u0007P\n\u0019ώ%y'\u0006.d1Eƣ44x#*\u0019O\u0003D%㩜KZT\u0012Sx\u001a\nd<*e2\u0019\u0002BƓ%\u00162\u001eJ!Y\u001f2\u00067ޫ&!_2\u001en<\u00178\u0016W\"%%ض\u001ad<\u0002\u00062\u001d+\t\u0017\u000f76\u0002d<<xRxRdَ\u001f2Tg!I&&#6\u0007NB&%5|lzM\u0013<0E!A\u0010tT9[<x[)wcA3BBdi./\u0007az\u0006A\u001c\u0005Jd4\u001e*\u000bCƓsf!6ps\u0005Ƈދ'Iaa bt\u001b+\u001b\u000f\u0010ȇXr\u00146\u001e=\u001f6\u001ejaIl\b?Yx>l<6\u001aMpe1~xf\tx(Ǚ\u001f6#ZxDH?l<Kxg6⫕)e)\u0002Px}\u000b\u001b\u000f\u001b\u000fP\n\u001b_6\u001e}RG'Uf\u0014\u0010(l<ݏO\u000b\u000f\u001bOU\u0011q'C-l<'֭l<_l<z\u000b\u001b\u0006C-l<)'ƣO\u00166\b#2PxT{\u00166A_65TOXxKl-zq\u00026\nǐai[x4&6Eglq\r\u001b\u000fP\n\u001bOʗ>uW6\u001e6\u001f6l<\u0005\u0000*\u001b/)Xdӟl<]/\u001b\u000fk#x[l:\u000bBƃ\raYA|f\u0011+l<m\u0010l<$\n\u001bh@a\rwl<ą>H|xGcaI\u00166\u001eJa1l<8MGNa}s֔eiVxfxaLaa\u0018Sx|xf[xXx|g\u0002G\u0011Dau\u0000dl<3\u0005l<\u0000T6^_<#\u0002Qx(gQ_6\u001ejad6\u001e tK*\u001bo)gjf:Ol>#Rx)%6Uyd6_6\u001e\u0012G`fi-em3u\\\u000f\u0012|L\n\u001b/ƣh/h3\bN\u00176V2\u001bo;\u00176\u001e3If)Tx\u0014S\u0010\u000b\u001b\u000f|xƓRxRl<\\gɍƳ䗍JŨl$\u001cVRGMna㩪ƣ\r0l%d6^/l<=_6\u001e\u0019ӾRxf62\u001b\u000fs\u000f\u001bOף1b(rl<<\u000b\u001b)l<)Gm]aq̇aPxc}xwl<\n\n\u001b/)Uc*\u001bc\u0004{\u00146\u001eUsa㙚x(gǎ\u00146V2\u001boD\u001c2\u001b\u000f?\u000f\u001b{Rxfx`>l<&KmaA\u0005G\u00166\u0019*\u001bo+e0\bufU6\u0019\u000ȩ)(}ꛍ+gP\u0017#_Vx*)l<5N}xf6)g/\u001bOC)l<\u000f\u001b|xbяRx?xc\n\u001bZ\u001bXd6cⱰB/>'~x\u00166ƉƣGJaIl$6\u0015GaaaQhxc\u001f6\u001e'.l<N\u001f6+l<)l\t'p/l<\f#>l<?l<cTx(\u001f6>.x\u0019\u0005Ζ\t=@j\u00146V2\u001bob~\u0011)l<87\u001b/)`\rj3\u001bo\fEb!\u00166-,\u0013\u001b\u000f\u001bOZed6\u001eOl<Kg6Vw_6*'Z;x[\r6cƣ\u001b,^xyx \n\u001bmam%Ll<Q\u000b\u001b\"_l<\u001a\n\u001bOJa!|x\u00146\u001eJaaV\u00166ba-!B[l<\u001cf6\u001e \u000f\u001b鷰l-d6RW\u0003Q獱we\u00156\u001ee(7gPCl<NP\u000b\u001b\u000fO3/\u001bO_-hl%\u00146G=jf\u0011'I퇍Coa㙱@f)e#\u0004Zx\\}x\nW6޸\u001f6V2\u001b/ƣ̧l<\u0012'P>l<2\u001boU\u00156\u001e\u0016GeTa%%l2XSƣର\u0014l<y(|x\u001f6>Xif6^\b`i{Ux2\u001b񴤬l<S~x[\r6\u001e\u000e\u0007ƣc4SW6\u001ey\u001f6\u00162Gs/\u001by\u0014+l<U+}x4Ue6\u0012j\u0005GcчGUfnW67bo? \u001e^w*g%\u001f\"eNf\";\u001ak\u001a\u0012N\"sXuܝ*Z\u000b\u0005ve8pٶ;\u0012M{i2gqZ\u001e̝\u001cWϔ;\u001fR\u0011WQ Q*|n@.\f\r;\u0017\u0018w9*#p\bwQf\u0000w\u0015Qvo>\r&EQfIh;\t7َZ2n%sdr5k\">cQDp\u001bi\u0017B\u0001-q\u0011TnP҉\u0007g/>[:XbىrYng*-mc\u0011c\u0017t\u001aesvlG(vj\u001fWۭ[6mxGJ0>#j\u000fu\ba`u\u00166\u0013B\u001d˲ؑxlrQOxpB,18uz_@gP]7cͩ\u0004N\u0007R{f\u0018)\u0015\u001bQ7V\u0010^+Z:e͸[\u0017bӝ\u0001\b^l\u001b23\u001el:<Q\u0013h(\u0019\u0015N&5usLoNkי&4\u001d\u0012\"\nI\u001a5}V4]SMsu餌\u0015M״\u0002g\u001bhv5K\u000b.4i-\u001c\u0005M׮\u001ev_ΦkWU-6]b;u.tLwL`5\b%z)M'tRȟ,6\u0014klv.w\u0019]\u0001ĭ\u001eTWtRI\u0000,8\u001dYG#\nN\"iŦtڰ\u0002k˷!tJƹsM\u0005\u0000\u0019M:\u001cC\u0006]O]ntXɿ#t{ʤSzVBipc\u0013$>+N\u000br(\u000e\u001e:\u000bGwy.d;N \u00113[bn7_9xg\u000e\u001aebmy<(tKH\u0010\u0019NJcUnX\u0013\u0003XI.{Z\u001cLHjZN\u0017vh]Dy\u0016qj\u001a,'-!9m(-N8\u000e^_\tj[NZ\u0019\u001f̹%d\u00168\b\u0000νQ\u00102n\u001dۢVmw\t6\nkQ'm}S\u0013\u0013\u0019`͵~{Af5`!\u0018Mt/t_i8,\u0012kN\u0006âp|[Q\n\u000fj?$\bPs(Cw?\u001aa\u0001>\u001a\u001eW8k;\u0014M\u000375\u0003ŚSa\u000f\u0011Ś#0QYsR[kcXM_9\u001c\nk\u000eՇK@ЉX\u0012p\r\u00055\tK#Xt{x\t)9\u001d%^\u001e{;Hsl_9\u0014w5\u0012\u0017`PY9{@s(fAsNdVW2\u0000m%\u00189m\u001f\u0016U\u0001\u0013MK\u0001-z>NF:4_#\u0013iE7\"A6D\"\br6iw%A-\u0010s\\_dV4W\f2Ak\u0018窌*zD\u001dc斐9sK\f̜O\b|\\&̜\u0006\u0011}\u001c\u001cDbJs\u001e̡\f甹\u0016&\r2\u001eo.9\u0016\u0012\b\u001c\u0018+^5:_;fy\u0014髙SPbW\u00108{RỎ[u>0ۗ?R[ط\fM\u001e/Ac2h:Nn\u001f\u0014\u0007e.)2ՠ5A\u0004\u0006>\u000e\u0004\u0013\u00192p\u000e3\u001a\u0010fV2\u000fB/z:@[мxv̱\u0019s˦.Cp\u0010j\\[Ӝ[\u0017dt69S|I{A8O~T҂)X\ti%](sa/\u00032\fKC\u0018\u0013<\\a&1pf\u0004\u0019s8\u0011i\u0014̈9\u0013E`\u000f\u001c\u000bĜFTB̑cV\fĜ^\u0014B\u000b1K#:myTu3bo${\u0013*gS\bsxH=\u0016?\u0019qjѵ΄9vcZcEJ\u0019\u0003\u001aR\u001aAk*e\bW\bsm\u001e^O\u001c˱3\rX7ͷ-\\\u00124'4\rp`0\u000eJ^GtD\u0010j\u00190v@8\u0016^\u000ea\\\u0005-p\u0011\f\u001ckz(\f`\t-'\u0003ojޅ\u001b1jz\u001dys\u0017\bA\u0001uʙ\u0013?\u000b)\u0018MeAӎU\u0006]~\n\u001ca\u000291F\u0014'\u0014\u0013%`rK\u0001\u0007KNL\rƚ{|-PrIy˃$\u0004[bp(\u001a\u0018#`k8r/u-Y\u0016Tc\u0006GNզ\u0005G\u001dA}\u001c9\u0007GN\u0002f8\"aV\u001a?y[\u0005䚂)%\\c+|n\u0004\u000b#[C\u001dqv\u0015[ؠ9Ff1rq/nVtnh\\c¢apݶ̸/sM^GsR'C.d`\u0012\u0017ȍ9\u000e݇\u0000㚪\u0016\u001e7\u0018ti\u0014s[$`V\u0003\u0018״xHFuf\u0002ơ\u000f`\u0014\"\u000b\u0018'er20E\u0002ơ\u0004K\u0011`\u001c\nK\fB9xqu%8\u0007Q\u0012pu\u001aqS\u0010d^V\u0017g6\u0007Np\u0011Rv85⬰m\u0012ن'%O\tkܸd\\V\r\u0017צ\u000fIS\u001c\u00072.NC$8pqR;NF=~Iqq(p88Skk0\"\u001eQƂ%V2.n+1dp\f\\k^\\pq6\\!TQaq[cTiC]J4V8q<n\u0000q*F\u00138f\u001d9@qR͠!@q(\bp\u0005C5\u0016/[\u000b\u0000I1N\u0006\u000ekJÑ,\u000bPV2(n\u0001kZ\u0001{=(T8q\u0011`\u00179N{VaZĩ\u0012Έ=\u0010q\u001a7M8.?\u000flv\u0003\"<)Dx>]</\t6\u0016\u0012\u001anASV\u0004 1^Wnml.J'\nw'͂]\u001e\\L8Ig-$50h\u0011\u000b7~\u0012*[<9\u000eNc\u0019%Az\u001fUa\u0012g\u001e\u001d錃h\n\rNd7\fNE+v\u0016\u0016\u0012\nnAA}vSE\u000bcfɘ>nFAඒAp[\r\u0010Fb\u0017\bNaT2\t\u0004̚\u0003\u0004aW\u0004\b\u0011I\u0004@K\u0005\tNg:!A}കd\borf'詴V\u001c5\u0012e\u001e_J\u0006mApVz[\u0000r5l2\bk\u0006݊le'@pߐs\u0004 8|x+\bM\u000f&.\u0010\u001cQ?\u0018 8)\n\b\t)ApMٺAp 86\u0007\rپ\u001e\u0003ī?8pRH|\u0005\u0007ЙL\u0016\u0006N\u0003H\u000etC\u0012\bhy\bpDܧ3g \u0011ڼ\u0010(\u0012\u0002B2\u0010\u00048*wV\u0002 \bp\u001c8g\"\u0002d\u0002\u001cqo\u0000\u001c\u0011ˆ;\u0000` \u000ba\u000e^cn׵\u0000pzV(\u00008LP\u0001\u00048ܵZ\u000f\u0002\u001c̰\u0012\u0001\u000e8\u00000/\u0007QYke\u0016dtϷ\u0002p#\u0000p\"\u0000\u0010_*#p* \u0018p\u00064<,\u0006\u001c\u0003{2\u0003H\u001aЩ`wl\u0006E\u0014\u0006\u001c\\`\u001d<^\u0012#fؤf\u0006\u001c\u0011j;\u0002\u0002/w\b\u000e8L\u0017\b=v\u0007\u0004\u000e\u0005\u0015\u0010\u0001é\b<V\t)(pt\u0000X9\u0005N\u0003&\n§Q\u0017\u0005\u000e\u0005LJ\u0000fQȤQ_\u001f\u00148j\bXGd\n\u001cRA[\u0004\u0002r]\u0015\u0002G\u0002\r|P%\b\"\u0004\u0004\\\u001c\u001f\u0019\u0002'V\"\u0003\u0002(^mC\u001a J;\u0013\u0005\u0006qn\f\u001c\u0003)E`Cp\u001e\u0006r\u0007G\u00188f\u0004\u0006\r\f2\u00188\u001e\u000ffq[ caP,0pFNS-\u00009p\fࣂ\u0003\u0007\u0007N\u0003:&n\u0003A.cF\"P\u001f\u001c8()\u001c8N/q\u000e\\\u000bŁCQp\u001avf\u001e\u001f?\t\u0006\u0013Ud\f\u00160x-\f>\u000bϋ,hQ!p2I\u0000\u0012\f8*ƻ\u0011p\u001a\u0000'q\u001c\u0006Iƻo<ݳߴ6&H\u00187\u0011\u0006뮨$\u0011ԅ~cpRo*:[o76]W\u0001A}<|Qoc\u001cE|hE\u0005l\u0000Ȍ{-?;E\u0019UޚK!e؛\u001d\u0003\"}`oZq5H\u001dn*\r\u0000&\u0011\u000b5\u000bdѢ\u001c~ޚaۆ){R`oD%h\f؛\u0014\u0004\r\u001bJaI~`X'07NȬ7}1z\"\u00137\"\t\t(qr\u001c\u001b\u000b\u0005l騷(;˄zy\u0006\f֛n9Mm,r2M\u0015\u0018XB\u0007M\u00034\u0007=a9om,;5(o\u000f+\u0005v̷UV\u0014R\b41|&b\u0000X7\u0015\u001eSn\nn\u001aMf\u000b*kϷav88$:e^uzH\u0004MtP\u001d;31)!L7\u0018z\u0003&М\u001d6U\u0010$B\u000e\u001bIa-e9\u0017V\u0017Ģӧux=BHnzy+ME\u001e\u0010ytør\u0018ۢ]\u0000(n\u0015sC$}VڀglڭN\u0015\u0000n?mn~V\u000b4\r\\6b\bmrMN+wK*)vLmkl?\u0005ۦq}E`ۚ#\u0016V5mdƬEҨm\"?6Śmڤ\u001cjuypN+\u0016eklH*\u0013&ɰ6PGꬶ7\u001djS+则Ԧ\b\rE\u0014>n8m˧є\u0016Ml\u001d8Be\r9ǀIGfflc\u000bZ^PNH<3\u001eO,<g\nr؊{ٞ(\f8\u001b2tc\f+&4`AfS}.\u0001aE&#0JZh+wj ac(\u000bm/O:LeS;/ܸ)\u0003kOD@ٔ%ll툺@=W$\u0013\u0013M\u0000\u00057pl\rkMcal\u001a{\r,ӿb&\u000b\u0019 6\t\u001fE[9,#W&\f2&\u001c\u001bSu㾭V-\u0015\b\u0011UzGh2\u0003dVq\u0013=U[0}\u0010,kc\u001a\r\\\u0002\u001cE^h^\fաU8wm<-صͽ\u000bO+6c|\u001b\\~\u0015u\fT JfuP&\"\u0002\u0018i?cRB\u0019FeA\u0016˨M.\u0006km\\Iku\u0002ݩ-\u001fY#)\u000f(kMڇ|\u0012eM\rHAY#g\u0018\u00165[\nY{)\u0018kZ1[f:3\u001a&\u000e*\u0012+`\u0017c5F\u000bct+%㐵\u0016\u0005V\u0005J4 k(\u0004W\u0003֨ٿKoA֤\u001a& kװk8J\fYky k-Y.)-5Գoƚ\u0004j&ae\u0002:\u0011kdgfI]fᩜX$\u0018iIɌ2,XSG*\u0018k\u001af\u0019kkAfsĚRZ\u000fĚJ\f\u0011kb6\u0010k)\u000754\u001b8#\u001aa~o\u001alƉ]\u0001k\u0012- e\u0012l\u0000_M$\u000eSjQ\u001b|54T\u0006_M8\rpI5jAqy\t\u000f)֨jR\u000f\u0006\u0000%扰\t֢#\u0000kJY|\u0000\u001algتg\u0001\u001a\u0016Km\u001a\u0004ԓdZnM\u0000k:{\u0000k>㩀\u0002a\u0002\u0011Ϝ`2`Akc\u0003t<ӄӗ|,\u001b\u0005=W\u000f_[EoU\u0001I\u0003B櫵/X|5S`p3X9q\u0001PY\u0004`M\nd\u000b&*3`aMm,#IO\fX\u0014\u0006o_\u000e-ȅ\u0004`A\u0004\u0002h_$5\u001a\u000fe\u0000k0\n\u0006\u001dtl*ʀ56&BRn\u0014\u0000k\rO1ˉƸchGE5g`Kq\u0014M5TX\u0013aM\u0006f\u0001k4\\~Xd߶\u0001k(˟H\u0017`Mufh\u001b5R\fX36`Gc\u0002)Sf\u0019\u000f$\rD\u0001Xs\u0017\u0000kt0d\u001aK˭\u0004T\u0015L,\u0019\u0002F\u0013\u0007E\u0019f݀5g\u0003:'B1\tFG(׺\u0007`͈o5jt\u0004`̀\u0005ǳ\u0001k.\u0003p1!\u00145jyf\u0003g\u001a0\u0005\u001b᢭@\u0005\u0006`=^IR\u0000k|Wk\u0015\b\u0001XkdWeJ:|5rQL\u0014x5E6)j\tx5\u00033]gQ.\"@)\u0006_M\u0002nx᫁{[<\n=̓@\u0012ޫ^ \u0012\f\u0006C\b\"\u0013\u0002RLbY>[\u001b5\u000b4\u000f\u0016]UcSo}jo2\u001aW֜jf\u001cy\u001e\u001e!+eT\u000b\u000b\u001b`6%\"\u0001XC䫑nal\u0000Cb^x55Nx5}ms\u001e\u0007JAWS\u0016aa՜\u001b\f\u0001$\u0015>:9]M\u001fQP|5E娄|5V\u001b\u0014|5ZHg\u001a-\u001a\u001e<Wzx\u0006\\\u001f\u0006}v)\u000eo+p5=\rԟOz.\tFoK6<Vop5\u0015p5Mȑj*+\"C0j\r(tFa0&\u0002o\u0001W!^\u0005ŰM\u0006\\M-Ո\u001b23%=6=W\u0006<*YMg\u0002\u0003K\u0000bʿ2`U#ڝ6j\n\u0004$\u001cc\\5O\\Ӹ\u0006\u0005UVπ\u0002\u0002\u0019&x3\u0001UC8jv$9Y0Hhl@դPU\\j\u000e\u0017\u0003\u0012\u001fo,T5\r#jrö{\buL^jz,\u001fT5\"d\\\u0011\u0013񙽌\u000b6M:T[d^\u001e2T\r$4j\u0003\u00165chҎ\u0019|b\u0014\u001erRdO\u001a`\u0005NdZR\u0012k\u0001UÎ>Cip-P5}09T\ri\tHa[@P\nȡjĚNT\u0016,ڃ\u0018&/\u0019g[@fe︳\u000e\u00102U-*'BUSMU{P6\u0016R1ՠ~\u0014.T5/\u001ajd\u001aT5LU\u000eQjx㾨j*UM?\u0019\u0005-ͬQPO8t\u001a\\̀хx{StB=\u001c\u0006T͚bG?9jDLL\u0006g\u001bbsS\u000b\u001aS.}虩Fl\u000bDqV\u0005&e Ո^ǽj4\u0011:H5gj#<\u0013\n2\u0005&\f\u0005R^43\u001e5\u0012c܁\u0019\u0012*j(k\u0016p\"jXxɡj4\u0011\u000e\u001ai\u0011ܵȐ)_VYAU{E9:C2Us\u0003l9|뽒\u0001EM\u001a)#y@8C\u0014\u0000s@\bdrd\u0018e5\u001f\u0019*o\u000e@9\u0016TM\u000er\u00053V@դpM\u0014LP5ҍP5c\u0002ͧW\u001a\u00002R\u0001U\u0001cP5f\u0006j\fT6\u0005TMy^\rTdZR{=u\u0006/=\u001euX5\\Qu͜qLݺj\u0002zE\u0019'YMcd\u001a*AVC3jRg\u001a{>͝ɨ$Z=<\u0017aa\u0000\u0005Y-)tcAV[\u001elׂbKݳ[M\u0001ՖjI\f&W⪩@s\u000eUӉV5\u0016\\5vܟq7VUkx7i\u0010Rt0__q`VFtR઱ţ/jDhMX54m\u0010\u000bX{a[\u0011!+1\u0011[P5\u000bB/\n{r̂T\u001b#юT;J.jY\u0015qza\u0018ik\u000eo-4\b\u0006LMg\u001e,\r\u001b3IL\u0013F~x\u0016G\rV\u0015u\t6\u001et\u000fڱ{|) j}?\nCM\u0017\u001d8BMd4\"lA`fSO~\u00040w{\u001c\u00184ELr\tN\u000bp\u0010EMdc.@\u0000Ѯ\b~.f\u001d40\u0014f\u0012ĴK{-oVjd\\\u0004f2-mZ\u0015xn\tV\u0016\u0016dJ(M{t*\u0019G_4- @iKɠ\u0006(gx\u0016\t\u00172P\u0014EkA(+Ȑ䓑v~+|-V!)oaA\u0007ҍAFXA\u0010R\u0019F\b?vGFи\u001bh|Nl4U\u000f4 \u000e\b#BZsn;Nܙ2f*\u001aT߽-\u00113\u001b\u0001pŚB8hw\u0004LMa4\u001ed&~m\tU\u000b&&\u0013m*fj\u001b\tv֙m?H4QF\u0016E`\u0002NP*<sY#һQ)|jYo'JMj$s\u0004B;g:0hJr]g0>\u001fn_ hLQ\u00119@-!\u0011Цh\u0000#v\u001fJ\u0003<m4\u0011^$j3{,>\u0013|\u0017kr0==\u001bHг;#B\u000b\u0019Y\r^>\\]yڪv&^f7{,΄ޮ\u0005:#݋_+^6ca\u001d\nFM\u0005\u001fNY,׀rfn1)g\u0015D)g\\45%㪜3'r\u000f\u0005GδX,J;\u0004\u00143qV+3S{!\u0006(g(wXĜ!xX\u001d1\u0012挤4cs$ИsTҙZ,\u001e\u00183l\r\u0019\u0006gfHgR-\u00193)n\f\u0019q\u0017\u0019\u000eͻo\u0001\u0015izr̕&L-\u00053ĭHdδ=\u0000I1\u0000%%LUH\u0013[3Cn/*3*~(\nBo3<[\u000bj&I5'\u00063\u0006hLD:zM\"t\t:\u0010.s\u0006aB& @gʢSTTcO\u0019t&ժ\u0002t&z\t:b\f:Ceu\u00163lrcr45)\u001dF\u0005v.\u0019\nI9[\u00051E;}[\u00025IU1*[X\u0001\bcJ\u0006-5@gڔ\u0011@\u00003\rY9g\u000b8\u000fӥ\u001et\u0012\u0012l\u00019S\bτ1H3Y6o:\u0018gZeIH$\u0018g\b͏]P\b@fș^\u001eလ5<Ͼeڑs2l\u0015#\u00019[J-5 g\u0006\u0019x\u001a\u00029SI.B%j\u0001qU@\tr\u0005Z\u0003rF\u0004y\nɦ!g\t9\u001eY@Κ\"h(͐3f\r\u00113)3\u0004b\u0019r&278C \u0015\u0006qiq_Қ.qht@Ζ(gS3A\u0002_ִNkO3f_lqo\u0003s9/RpL\u0002_QЃ^\ts]\u0015<NeR\u00039S L9sAZ\u001eL\u0019qwd\u0019j\u000f\u0019\u000f݌A9BPLQ̚\u0011/gMPLݳ+!X2Bi0g*Ұzyj\u001f7_Q d\u0011/Zpδ0Dp%l͗9g:U\u0011t?\u0013)w*3W2kQ<\u001adYR\u001dsF,\b=-8gi\u0011\f\u0019^+CͱZA1V|\u0015rw4fu\u000b,*3\u001dgX?R\u0004h4@gII:ϼR\u0000k6+*U\u0012p\u0001:\t:C\"\"h9s\u0015\u0006L\u000e:J!-5Pg3[U/:jN\r+4&̔;\u001c4`a.Ƞ\u001c\u001bNdYۢ6XgOX*PgZ|IgZ`3t\u0007L},\u00013LźP\u000bsvG\u0019r\u0000lE\u000bL&\u0016s$\u0003hHh3\u0019\u000e5ۧonc\u0013\nLK@\u0016=t\u0014N+Z+C?Ǚ`o\rlPv\u0002\u000f\u001c{&\u0015\\T|\u0006\u000b왔sk\u0004l( zxq\u001e>{FφZ2\u000fEhRGl,QH1{KWj\u0019\u001ag\u0007\u001ey}s+M\bP@#-\u0003\\\fΛ\u0015\u000e%_?_苂6\u001bz;g\u001eNP\u0017\u0007M;T+\u0005\u0005ߴO>$fuDCBk6XhMD\u0003ihͨR\u0012\u000e\u0019PTvt\u0014\u0007p\fh\u000eMWg\u001c\u001fA\u0000=,%:S\u0012{a*t-UIôO\u001f\u001f\u0005\u001eKw|KK>\u0017H}rs:1\u001c#paE\u0015X*qς\u001cv_J&\u001fT$\u0000ysDs\u0017\u00124K\u001fR/r8\u0007hJ}VäkbҦxg=\u001cܩGP[g\u0014|\u0014A)&\u0001\u0012P_dp-ڳx9G\u0005PF\u001f?Jeb\u0019ʁPCT݀\u001e\u001dBw\u0003ebP4. \"V{[4Q\u0007ɱ\u001d\u0006\"\u000ee\r\u0013o=\u0003%7\u0005XЩE2f\u0017M}\u0006i)uyʦ4V<voETP\u0019\u0012\u0003G\u0013X?<[\u001e%;9$&A)9{H@5=#\\uWY:L\u000fbrf\u0000D\u0003>6\\\u001e\u0013>̬gUE\u0005t\u001ev2Z\u0019\u0018]\u001cZ*v\u001bf\u0003ƠOC\u001eo\u0018cV@z\u0007P2\u001a6Дbo8uV\bbY]ǙD\u001b\u000fęOJU\u000f.ޠ;\u0010dT\u000fShG!G;z)С\tϒT\u001d e;\u0018\u0006昏\u0019X=\u00184jw8(y<lЖg`\u0018\u0004\r\u0015~Ȉw\u001dg햤Br\u0017Ls0%VL\n[Urgwۇ!o]wgqY\u001f\u0003O)̯($٤\u0018\b))*\u0015\u001bv\u00181h:fm(/EM@\u000fs59\u001aݗ|l\u0000֒z[ydqz\u0015\u0006\u00025ST\u001a_e\u001eG@^q7)cb֒:YdU<Ƀl\u000fTR|(i\u0011ZL>=\u000b\u0018ߝ\u000f\u0004\u0006Eo\u0006#\u0005ܦ^|Ƽwk>Jfۍ{,Re͍ށrm>b\fZԵ\u0006g)S\u0010l8Eӵ܁\fiJ̩v#\rTYpyg:TCVM\u00136_h\u0017HEܠiԴ4_\u001bJ4\f\u0019\u000e\u000b9hE\b%\f9iNS\u0004M*4\u001d\u0004)\u0003\u001e_m5}ƃ0kRJ\u001e\u0018OF\u000fS\u0002&\u001e=R\u0018 \u001ew/GQ\u0006+Z7z\u0019fޱ\u0018X!֐-H\u001f62&\u0003j\u0006g\u000e\n\u0018\u00075q\u00012CK\bp-\u001eZsUOdp0=k12\u000eV\faxияE焃@akEB\u0011\u001aO\u0007\u001a\u0002}s>\u0018\tvLhst:\u0014幽E`;S\\P\u0010\"kyӪ\u001f}Z#(\u001cE\u001b!\u001e_\u0014\u000bWJ $\u0014O\u0019;\u001c\u001dS\u0019\nsCĆ\u001drSa\u0014\ng5qZ@y\n\\\u001c>H\"ϲP\u0006\u0002h\u0015GPm<\u0014RƬj'\\ǍޞOR\u0014Z\u000fGUDsJ3ߖ\u0017lB\rg'\u001d[8ox-U@m\u000f5DpHzi\n%.ɄStQ\u0001\u0003{[^k[\u00146T\u00047p<+IaJ|\u0002kBC\u0014&\u000f*6;f\u0012鳍~C{)\"\u0000Yg)vBj\\iĽlNN1)\u001e$Â,Y\u000f4\u001b!>k{)؉4?8\u0005\u001b`!'YOuDJm,dE޵\u000e%n\u0004!\u0018\n!{yD\u001c\u0014*\u000f'G.\u0005,\u0007DHת<gU\u000f|U!E#g2}^,Y\u0007I96ߩwYeR㱇\u001fǺ2%\u001c\u000e<\n4=d/I\u0003,5E&۟S@\u0013=зmeaxrXʽ0lK=xF\u000eWofx:9l|\u0010\u001e3|R\r\u001f\u001d,\tD'N>Wqmghߒ5\u0016M\u0013>\u0007\u000b`M2brgE}\u0010\u0001b[ъb\u001fY[)Tb\u0019!_=b\u0017}:C̳|syP\u00193u5\\l\u000f\nBx(\rycL\u0011{٣u)y\u0018\u00161h_s{\u0014\u000eP|\u0014WdK7HhˬU\u0014\u0013\u0017\u0017`\u0012\u0013a4қh%\u0017#͟8\\H\u001e\u0006\u0015&ZT?S`g\u0016(6D\u001bL'֔swe2BqT'er0?VҴx\u0005d^D%I&崁ު$vqd%\u0003\u0011aٓN3\u0018<~ؤKD]\u0001_ڌH>L9\u001fI-\u001d\u000b&T*<ML!ǙT\u0016~DCn㰱MWI]QH\u0000ڴ\u001f[)\u0000>\\fۤ\u001c\u000bº\u0016W\u00116\u0003\u001btOFUNĲD\u0001N\u0017}(dI%&@BERvP:`{\u0014#\\\u001e\ni5\u000eӌJdC\u000b-70\u001a*K\u001aNw[\u0018\u000eS*\u0012%i7e2ڤ~vF\u001d_\nql\u001e\u0005k\u0005\rDsμ4rh3o=\u001e_J\bH\u0002g]@ O\u001b덥Y$\u0002K\t\u0006\u0013ܭ2<E.١N6`\u0007q'{PSQM.u\f[yj3wmqxbG8\u001b&\u000b\u0010.-tRw\u0019is`\u0016\u001b7Pn3V).Q\u0014k2bu&\u0003%w;\u001cģe\u000b&M*k}4[W\u0011R7a<\u0015|^ǩL\u001c9n[h(hZ<<\u001d(XP\u001eƃ\u0013\u001f=t\u001d Ų\u0015d{P(ԂX<y\f?@\te\u0005o[\n\u001e\u000f\u000fzpW!x0V67ԭqԏ㷔B2|r!6h\rt\nJҋ3Aompg)ϱLm%Uz(vM.U\u0015\u0007\u0012cl;\u001d尖1Uh\n\u0018\u0013ʫbg()ٷ}%ȎT\u0006rX\u00012&^\b7of*n(zHb35RJ\b7{O\u0015\\\u001fXkB:R/,>yWPY<C@Me?\u0007PU_|\u000ezʜf\b,M.ʥ[>L4ޙ\u0005v\u001aXd\u0007\u001e\u001b-I\u0005)hiMۀ\u000b/\u001dup\u000f4\b#@K2bq\u0011w;-<Zw))\rE\u0005\u0016ǻ0Z<3\rgKZ\u0019AlgKl_[\u0004e\u0015LbR\u0019\u0005\u0015F-q>n0 լ?\u001dK|\u0012q'ĕX}:\u00005\u0010X\u000e\u0014\u000f۠Q{_β\u00114aف;I}*\\ORl\u0014*S\u001e}\u0006m\u000e\u0003CI:\n\u000bmAjMe 6AM%t\u001f\rg0\b/!\u001cF8n\u0004+f\u0006,gQ 10uH72\u0001F\u0010\u0014ٻ\u0016ڤu3x2^䚨XmBG,⸰\u001fLR\u0014\u000bR \\=j5\u001d\u0017<\u0017#ϕ\u001a4mhR=\u000f\u001aI:vĻQ\u001bF\u0006t,ěTV>sq\nK0eP8\u000eAԓ.j'mY.xCeU _6J]Y1BkL\u0005BDLj&0g\u0002mAt\u0017RF\u0005\u000b\u001dd*\u0014XLdV\f\u0016M\u0011֛6\u001dX(u\u0002⊧贴%o\u0014ԜCa\u001fZ)<IoRI\u000fJ՞,-o\u0012\tT*H7ԍ\u0017\u0013@I!~\u0012\u0016\u0012\u001emYG\u0002^Z\u0019R/@@>=V\u0002?PT\u0006\u0005k뒰Q\u0001\u001b>>iQ+\u001e=>\u001eV]mB7$\u0003{ގ\u0013\u0018T8;̬K\rЛ]?\u0010\u0006ʊ*bmt:܆8;\u0014ӞsMLUI}Խۃ\f\fKCv\u0012\u0016m\u0014Sir\u000e\u000e-p\u000e0\u0005Plv3Nqm\u001fx7;.c\u0017H\u0007\u0005J46\u0015\u0007=DOo+M90(9\nwy+u(=[SVPƤIp\u0000#º(U̠Ie E\u0011)PN\u000fDΠ\u0000Y\u0012VCP\u001b\u001a\u0013\u001cE\u0019}\u001a#n\u001eTڟ!ڢA\u001aZz (o6NZM-O5PqX{\u0010A,5\nZ7MEq''\f0ǈThpQKb)\u000f(D9Gge/\u001bf=\u000evi{\u0017d\u000eJT\u0019N/bTVL\u0016\u001a`fO5\u0019o\u001aԉ\u000e\u0002j(֔D\u0016q$\rFD94\u001e^:G& ZȢt\u0006>{ʴjuޢq\u000e3aJbPa%-@\u000en\u0015i_x\u0010\"U\u000eFkyiԤq^ ,\u0013V\"Aq j+\u001f챨\u0014\u0013\u001a\u00012#bߚ#Ǝ_=\fV\u0014H#b#Si\u0017Ēa@|\u001ea>\u0005:@\nKjB\u0013aR\u0010$jKa[1)ߤJ\u0004M%\u0006\u001e\nt\u001cn\u0016\u0002\u0001{_\"\u0013\u0016Q\u001b#\\ں\fm\u0014̷\u000fM\u0012LqVFb$oߴޙcs\u0017sZb\u0015gU\u001bk\tu^\rH߫>m-n\u0006\u0003\u0014Ͱ\u0011x\u001e \u001e4]!}Z)J\u001c\n\u000bb\u001b%\u001diSxj\u0000?!\u0000pd5AX\u0018>\u0000z\tDK\u001f\u0000G\u0011YI%\u0017'u\u0005r!۰\u0003'\u0001N\u0001\u0006ئ\u0005')4M Z$\"\u001d\u000e\"\u001c}\u00057q{j\u0017\u000508 pvPtq<X\u001c8cf\u0010`<kbZʝ\u0007z\u0000*\u0019(8}\b6:ؓ7~;\u001ey=A%^:\f\u0018`c\u0003<~97^B{\"joq4LϨm\b\u0001Q>w\r\\K\u0019!\u0002虤2LI[X6!}(\u0001;\u001b=@U)s)ɋz\u0019D\u001dzˍ)SN۝J\fR\t;LעDBW2\u0003׺mjNh*\rA>GVdl (VRͿ,\u0005U\u000f8C)\u0019QLLԃnkN5\u0014HRl\u0015sz)t\u0007\u000fVU]NE:\u0013dzUR\u0012A\u0016k]6\bl\u0019\u0012aa8\u0014n\u00028ڭ~/\u0007\u0017?J\fudn,a}V^9qz\u0018٥FBڼ\u0013\u001a(&U\r\u0004\f4:C\f\u0004Ϊ_Ii\u0017r\u0005?y\u000bo\u0017\\i\u0010Ke\r\b4E|\u0004\u000fPE^dd-ITV\u0010h\u00138Zvh\u00000nY\u0006w\u0006\u0001b8*,6\u0011r:\n\u001e7^Z%hN|\"GU̩\u000eC\r\nAP)\u001bA5\u001e9¨ˬ\u0019vC=ׂ۱3\u0013IݨwZhH\u0017ݙ\u0012u\u001eodR$\u00132\u0012`wRlW*I/2[L9a\nt\n,NS$\fHZJx,ZSIm\u0012.\u0015tߍ0ҙVG?{\u0018)bh9}\u00036)\u0011\u0006\u001bIi3j\u0011D\u000bHZjk\u0019éS\u0010\u0017{?,L]*\u0014D5I\u0002P\n5nR\u000e\u000bgn\u0010VP\u0014;dÛSZ;d5\\\u0005@ԢY\u0015JfKpXs\u0018\u00137+Nة\u0015>l\u00160ڜ\u000bʎKYӃ+\u001a\f8\\i&f\u001esŬ'Ta\u0007\u0004R\f:wu[ZL\u001cӊ\nFٞ^\n\u001cJGX9o\u001blY-`\u0007s\u0014;Q~\u0019\\\u0017N\u0018w\u001277ϩ򈭓\u001e\u0012kLP%5m\u000f\u0005?\u001fYϞsjͳ|\u0019ũ5CK\u0007\u000ek(m nPY+}Qi(\u0011{\u0014j\u001ddψrpJ1.\u0013Zy\u0007uy,#\u001e0t$5\f\u0019 \u000f/E.CJVÛ\u0012g\u0017*@t\u0014\u001c\"[C-NAr5[٧\u0002UU\u000f)\u000bZ*G})ф$qVM،C(BiIT,\u001aW\u0003\u0004\u0012Ԁ{\u0005S]){\u001d\u001b\u001c:McDg\"#93lì(!z\u000bDT-\u0003lk$>T$r[+u\u000f\u000e\u000b\u0012\u001e~|\u0012,TOs\u000e\u001b\u00077#]:\u00073\u000bɗ\u0004ȣ\u001d\fзòTOjCUgtwE/\u0016lT.F\u001a\bPL&-Z.\u0010T<}\u0018j\r\u0002lM֠\u00119<tx\u0017\u0017N*\"T\"E\u0012\u001fVu\u0005SP:`<\u001fA8#r\u0012jaˢM{R(ժz1\r\u0001\u001a)m&w$n\u00047\u000b)\u0010,<֬Hw*S\u0012ma˻}\u0012'GMa\u0011ֵ\u0019\u0017\rU8\n\u001dee\u001b,A>@ݸ|w6%Z\u0007-zE\fKa.aŖ\u0005g\u0018n\u000e&5@k;=ŢӞٶ#Rh\u001e\u0011EU0\u000f\u0012\u0019sRg\u0017\u000b\u0013)!\u0012p\u0016\f4/\u0011M\u0016\u001d*K\u001c*\u0012T01W4\u0004lV\u001aN_Z\t\tu\u0018\u0003>AfY;[{舮r=\b6\u0004\u00005\u000ekTg4\fP/l4ԆG\u0005)~z2\u001bc\u001f,:v;4+ݨ׈\u0006!\u0016[wґ\u0006bm{[XYnwVl@WgPO2qq$Bب\u0004Ć֓dҲ\u001c\n\u0010di#hŌn7dҷD}[,:&86Vc*G\u0012?4ctY!/\u001fS\u000f\u0016\u0012t\u0016Y9d7X7R\u0006RP\u0014\u0005%!/\u001e>\u0005%I\fO\u000ekyϓ\u0010ւEG\u0011=O,Q'LYe%\u0013(FZ2tK1\\V̙q-\u0016j\u0016{>~\u0006bu\u0012y\u0006Nam\u001fᢹ\u001bJImdվu<TLI#}N\u0018>UT05Kۂt\u0019U\u0001T\u000e(aT}\fst%Q\u0002@sH\u000e3-|Se\"\u00106<-R5~qe\"\u0012|0VxnX& \b8д67yǥC\u0011dg/tUV@*γ\u0015ެ\u000e\t#ԅ0@P\u0015&B}\u0000\u001dHS\u0017q[YZ[k(vO'\u0011u:9\u0015Xܛ\u0011l \u0010\u00197pt\u00160J{OT|tۦBǁB?1A;ƀ){m\u000b&H]\u000f\\\u001aE;.1?f(x~\u000f I`\u0016l\u0000\u001a6!v\u001bYk\f>װRtG\u0018ړt\u000f:\u0003GMȵ\u001dmxpt>lOKQF`5\u0015v\u000fm=SF\b\r\u0017 J^?@]4h\tV&A1e0-|GwcS^20\u0012$\\D\u0012>(\u001d\r]\u0003&Q=\u001f*u\f<\u001a#/Kو'Ԝi\u001c,Y!E>T~K\f\f\u0015dZ/aux̢x&S\u001f\\Q\u0013\u0019^o\u0016\u0011G@½z\u000f]GK\u0002@\tXNws\\\rV$O`4GغC\f\u001a l}\u0007ݚ&'Nk\u0005d\b\u001d_51\\|ijǵQ\u0007\bLԨ\u0018NBD)KJxh\u0015kiA;8\u0015ZPI/\u000f\u0007l\u001f\u0011\\z ${/TD\f\\NR\u000f\u001fm\u0012i1\u0006=h\u001d;\u00148OI-\rX?\b\u000b0P3$\u0001v\u0001c %\u0001\u0001f?2Ts\u0015a'Fa;=\u0005\u00032OZP.a\u0005Eo\u0007Y8f\u0012]\\w\u001fR7JS?p9>)X\u0019P-w^\u0003\u0017/\u0004Nb\u001bàLSm_THV`3y[\\\u001f\u000eʃ\r5\u0005\u000e\u000e\b˕-aGݚc\u0004Ng?xlfL7\u00164\fC2\u0013Ta2\u001clOc\u001d\u000f_\u001f\u000bSfsriLjӨtR,qU'\u0012`ݜcafa@mmͨt\f83/Gqڭ\u001c\u001b\nv3\u001e)fER&N*LTOO[Zp+\u0010⣤\u0004\u0004x8Nfзō\u0007\u0015v=Kƥ#K\u0015fv5IbY\\:ޭ\u000b@\tI@F\fBv;qbh\"$\u0010DJ\u0006\u0017ݕ\u001d١pa!\t[ki\u001chK\u000b\u0016\u00122\u0016N5\u0011\u000f%!\u001bs~m\u000bj+c(\u0001C}(9\u001c\u001eV,u|No\t@\u0014+l\u000b5\rq+\nNǄo\u0007\u001ck_M鏇RBhwzdꟴhVy,*\u001d*b*\u0004OvmuP/*e:R\u000f\u0002=53s%(ʶ .@\u0011t\u0012\u0001\u0014!lJ\u0000]Ӹq\u0010{\u0005UNHO০/&\u0014//MEhuzXts1Ju\u0017.V\r\u00018RӾf^j6`ѸD\u001a<C٭\u0002\u0007X\t\"|\u000bH.\u000fS͡]<\bo\u0010nv/ s{-8 zTrHR7/qT\u001c\n]hl:\u0013\u0002g\u000er\u00048(\u001b4tKPęT\u000f#>PgI.Qեi3tV\u000f]\u001f;_1\b{\u0013I\u0004;H*%-)z&\u0018~]\u001eR/n*9\u0016jL:T\t:FY<Dj\u001dt\u001a!3F}<~9\u0000v\u0002\u0005vvi@iYJgt`kx6=Vy[S\u0015\\:l83n5=\u0017[~\u00067\u0004{Fw\u000fg\u000eoc>\u0016\"Μ3\u0007;rkflCo\u000fR٬\u0001Ni\u0007Z\u001fTsZmy'LTÓJ?(u\u0014\u001cs.L\u001dv[Nx\u001e\n\u001aŋ`Y\u0011hf8TܧP\u000e;\u0011T\u001doI\u000eOJ1cn:$\u0005\u0002O,L㢩uڛÜf\"cÝ͝\"%\"~\f5\u001e\u0005\u0001)(l4\u001e0ݎx\n\u0004&w\u001f`IPx\u0010*n\u0019F5\f_g󇆝a\u0007e\u001e\u0014\\:odsxsx\u0012\u001e7.[ӃTzU1v9\u0019|ff\f\u0011R=kZ)\u0014;J\u0018EC$Į\u001fe\u0003͝k4=Xݎ\f\u0002-%\u0010\".\u0019S\u0013~\u00109m8v5J\"5#M$zPK\u000eoӡagA\u0019MʳWK%˹[M~\u000f\u001f\u000e?.*#b\u001f\u0016R9ns\u000bǜƖ\u0017n\u001cf\f[Hv\u0007O%nɥ<vr^u-J1ʕO/sJ\u001bVxE=T67E_\u001armܫ3\u0015wOǼ/\fX\u0001P;j>\u0005z&n.}۬16c݋p767\u0012\u000f\u0000Z\u0019.ڷvi\u0014G3Ż\u001bmRV\b\u001d\u0013\u0014\u0002aT=|yX\u0000\u001emDu\fTW9\u001e-\u0003\bP3\u0017NPXjnJ?Z\\>v\n'\u001d!bkƼ#&r]jV\u0015p\u001ccImv\u0005x\u001d\u0006e\u0010hd\u001ewZVσzYhs\u001cKt덼I-f}.C3z(tyD驔`*;Bg\u001ek\u00053<\u0016Qɉ^P,[nN\u0004\u0019C\u0013\u0005lHSO?ԞPUP\u001a_`)V}S5\"LC\u001d\u001fw\\\\Qos}mկ(v=o3A\f\u0017\u0003lf\u0005Ջ4;$\u0004\u0010xx?إ\u0000<\u00183\u0006\u0006cK\u0010\u0001yF \u0018,R㴿wɨ6׉R\bxEHn\u000f7\u0010x\tre#\u0010Đ5laE3\\7\u0011\u0007uݡ\u001b0w\\J[\u0004<S/3|\u0016V\u00152VD\u001f\u0015s\f\u0017\u00012ݼ=;\u0015ddcdO\u0000Ia\u000ewd94lf\u0012Cp\u0018\f\u001a\u001d1\u001fE\rx\u0015 \twԗ_fn[c\u0011Z!a\rdzHu\"6ZQ6\u00008rsȀs\\\u0017\u0012nn\u0011BENO8P\fg=xnn;[۶m1#{8*\u0000Hm\u0011w7\u0002\u0012EFA2Z_Q4\u0015Ǚ֔ʑy\nM\n`\u001e󻲕J'XoKW\u0003>maT7c\u0006\u00169,Ec\\1:J<ݿ\u0005\f@\u0002\u0002c=tZ)Cn;!\u001c>Vw\u000e~}\u001faj\u000e\riµ\u001e\rHԝ5\u0011\u00192sZ1)޾T;(x*\u0019dxn-os4p΍H\u00016ONŨܱ!EZKř{{2\nnqm!3K71\u0001\u0007#Ǝ0x(]+\riݬZ\u0018<:԰MeXS\u0010%\u001dYlZ0rݝoCgxwP<qʤ>\tZ\u0007\u0003/\u0011T\u001a=Ūbb[\u000e\u001fyP6ϊ\u0011i\u001ffx\u0017:NT\u001eoVܳ@@ʄj*\u0015c\u000e,}6bV\u0000}]}ƙϟ{W=Gb=\tWK[*ԑ|vF}l(GzbYG\u000ekz*\u0010=e|\u0018\u0006\u0002\u000f^\u001a+nr@ei+>,]\u0002㬾6\u000f@B*\"\u001d\u0015Wt\\+,nEyQa)b-U=\u0002QZ#\u0012=\u001fk9N\u001dtQUz\u001f=\n*%gr~?_@\u00126gDʭ_y ga\to.,v\u001eʳ\bxKՅŐdevmR*vf;\u001dY=\u001b\tB#ECI\u000b<\u0012Y:NK/\u00037,mXz-&\u0017Ln#\nAf\u0005\u0016<iа}N;z\u0019eh\u001c\u001c#=\\\u0012z\b\u001dG\b%\u0017b9K9iC-\u001f\u0007\u0000<-d\u0018!b\f\"j-0۽\bx#0\u0015y>>N\u0012\u0001R[\u0004[a\u000e'ME7U\rCP0\u0016T\r-4O.\u001eV\u0000\b\nwW+\u001b?\u0015\u001b'\t\u001bOjeu3\u001bc\u0013\n\u000b\u001bO7\u001bP\n\u001bώl<^T6xTW6h'7\u001bO\u000fl<q3\u000b\u001baflN}~f\u001f~V6\u001e`>Ɠ\fWe\u00166\u001e1bZӉ.xB~\u0001\u001f\u0010x\u000e\\\u001fC\u0017df%%ؖ\u001al\u0015Ц&w\"x\u0000\u000b\u001bO\b-eisںw5k\u0010_x\r\u001c\u0013IJl<)I\\`v\u0003xxSl%:\u001bOߺ\u001a(o6hҕgt[JEjlvF\u001al5ba5-\\\u001f\u0005Vx(\u0005侰\u0011Lh<3\r~o_hvo?A5v\u0019\b0g4/4^oa\u0013j\u000bx\u001a\nh<ԂƓd}oLV\u000bTB/h\u0015Zx{\u0014O4\u001eJAPv\u0015\u00144ƓF\t[x{x{?q1:Lv\n\u001ao\u000bVx(\u0005cƓZxR*\u001aO\u001b\u000b5Bw޷'h<\u0015q\u0005oOxR+\u001aOJE\u00134^6\":\u0019'\u001b'sEihO!\u0014\u0017\u001aOj{C)h.\u0017\u001aOgחxR*\u001a\u000fخ\u0013h>h.3v$4\u001e[JF%ճx}B\u0002y@Bih<}~\tKJ\u0005UBIh<Hhn=q_h<\u0015a$4^-\u001b\u0013axK\r4ޡ{+\u0005׵+hd4^R\u001d\u0015)h<!hNW@Fu\u00154^\u001bשkhOd4^mx]&&\u0005oOxR+\u001aoǐ9v쮿xR+\u001a\u000fPx\\IFuH2\u001a=\\Ƅ\u000b\u0007TTxD>^h<\u0015!TA\u0011yP\u000b\u001a3\u000b\u001aWtOU4\u001eѭxh*h<u\u0005\u001ecs_x1xB\u00164\u001eJAh<{݌Ӈhd4\u0012\u00038DE㉰F9o*\u001f'dFixѾx\u000b\u001ao4\u001eŨhd4T'\u001a\u000fo鷠v\u0015\"\u00174.LJA-%\u001ah<Q*\u001aO]uo4>IEGB\u0018B\u00164\u001eJAG\t\u001aOjE*h<)o4>[EA.h<YxmU43\u001a/)T\u000f\u000b\u0004^x\u0010o4nƃ]xKhN4N\u0017KF\u0001Nt#\u00144v\u0016\t7,h\u0006\u001aOSx\nxJT4\u001eZA㙛QEa{TxR*\u001aI#YxR*\u001acxwE)]x\u001ak_h<\u0006ȂϩxK\r4\u001eCwA-h<>HA4x'xf4\u001e'\u00164}o4\u001eiĂӣRxKh\u0006\u001aogxx\"\u0019G*h<\u001a\u000b\u001aOo4\u001e\u001bfRP'\u001aoW\u0011PA\t\u001ao߮/4޾_h=\u0005שNhN\u000b?HhJC,h<S2\u001aϔo4ԊC)h<\u0017\u001a[QxR\n\u001aO\u000b׏\u000berUxmx}y\u0005\u001aOJEO{V4)\u0019Ǚ2\u001akRx]lA)|FicSxW4^R\u0012\u001aoT|e4^\u001b>\u000b/4\u0013\u0004'T4^\u0017\u001b'$d4\u001e\u0007x\u001dþeQEu\u0005h^h6:T4g\u0015\u00134\u001ejAqfF/4^g˓x\u0017\u001ao)\u0019@u&\t\u001a?\u0017\u001aOJE-%\u001ahN\u001e0M/4^WFAeh$4R\u0003ף8x|\u0017\u001a\u000fT47\u001a?\u0017\u001a\u000fP^h<\u0015\u000f[x\nƛ#:N\u0007\u0005[j\u001d2\u001aO7\u001aO#Zx\nqx\n\u00164\u001e1Ԃ[JF-xx\u0019\u001b'T4^Ff\u0019'P\n\u001a3_h/4bE-%:xz(*\u001a_\u001bg\u0013rF)TxKYhMR\u0015A+h<=o\u0005`\u001b'P\n\u001a3_h<Ԃ\u0017e47\u001aO\u001f񺲅\u00057[ju~\u0014{\u0014h<\u000b\u001a+TBIh>\"\u0014h<\u0005-_h>/4\u001e͂d?zxJYW4R2\u001a/S̵:\u0017\u001a\u001cyAI-P^h<Ԃ\n\u001aoB)uPxJ\u0000mKh,4^\u0012\rI,;\u0005Ͽx]\u0015W\u0005T<FI}r\u0003g\b,h\u00144R\u0003e)Wx~Ӥ]xT4T\n\u001aox]xԾxU4bV\u0005\u001b@\\E7\u001aO\u001b\u001eLFfZx\u0015xKh:\u001a*x\u0013\u001a\u000f\u000f\u0017\u001a&ӂQwh}vtf4ގ/4\u001e\u001547\u001ao/@AUxo4\u001ejAf̚xcFs\u00164#0B.*h<^*\u001aog-DB\u0011i)h<b\u0005Gƣ\u00042\u0014h<|<^h<v$4\u001ee4\u001e\u0017\u001a\u000f\u00144\u001eA\u0017\u001aGAY%`B\u0006|񌾑x\u00174\u001e}h<\t\u0005GqF$x\u00174\u001e(0XFax$ \n\u001aϲh<bu\u0005RxBa(_xfx8o4\u001eaÓ\u0014x\u0014Ih<@ \u0005}7\u001akA6h<\ro4\u0015\u0007ƓZx\n\u001a҆\u0017\u001aƳCyȒd4>DE{\u00040h\u0001)}lLh<҂{\u000f1~:4&x\u001a\n\u001aoܕ@XEIh<)\u0015Bf4\u001dx\u0007^h<ӂS24x\u001a+\u001a)4̿x\f\u0005x(/4ގ\u0001bF\u00144\u001egxZT4>E\u001b'c\u0001<FBI,lxZ\u0003Bulxz*\u001arAJ\u0014|:I\f\u0014\u0019\u0012\u001f\n\u001aOj\u001bOBQ\nTx\u001c\u001d\u0015Xxv'4=_h<T42\u001a\u001fOx**hNWBue^h<\u0005+\u001aG~\u001dx:\\#:ZxY_hN@FI\u000e4B\u0018o4\u001eƓRx(/4ԊCIh<{o4>YE\u00154\u001e\u0017\u001aS\u0005x\u001b3\u001a++y\u0005ߣ\u0014}\u0014wh<nSVʩ\u00164@\u0015'h<c\u0015תh\\\u000bORxĞ2\u001aOoFsh<ƓBI,h<\\\u0019ש\bFV4\n\u001a=LI\"e4\u000eyP\u000b\u001a\u001f\t'弮/4^y\tRx\u001ds(h\u000e>: x]Ӿx\u0014S\u00174/t\u001e\u0006YcxR\u000b\u001ac\u0001x(Ow%bRͤ4xR/ө(\u0014f4>:\u001aOVE)kFi<h<V4*^h<%M*\u001aOlx\u001a\n\u001a?\u000bpBu,2\u001ad]F)F\u0011*hv.4~7\u001a\bbA)Uxuxtd4\u0015\u001b\u0013+\u001aOXE\u0011}V4>ZE㡼x=,&\u001ah<\u001b\u0003>x]˫ Yx\u0005!g4^\u0007\b\t4\u001ewOh<x\u0004A\u000b\u001aC8\u0013\u001aOӼRx\u001aW4o4\u001e\n\u00053+\u001aOk7\u001aOߠ\u0018\u0013\u001aO\u000bέc\f/hOx\u0005rƓҴ.h<\u0015\u000f[xR8qַo\u0017\u001am\u0016\u001aޭ\u0017\u001aI\u001a#s\u0004y/4^WJAu\u000bz=\t'+O0xRXZ\u00174^=$|>YB$4^WVn\u0013\u001aNB㩠tGB5\u0012_h<uU4ޱ4׿x֙x\u0015Ch\u000e2~Kh\u001e\u001e\u0013u\u001bGAFu\f\u0005iFiZh<~\u0005gko4^\u000f\u0000DiFu3\u001aOCAE+H\u0019WU\u001e+\u001cףP\u000b\u001a\u000f\u0004':5\u0019'Ux\u0014#\u00144V\u0005o4\u001ejAI)h<\t/4^7ϻ#ŝx\u0012h\u0005IFIh<shq$*h<\u0015x\u00154\u0006*\u001aOo4E\u0015R\u0015Si\u001b\u0013Ih<\u0017\u001aOjEIIh<FQYXx\n\u001aO$7\u001aOjEAL)h<)/4Ă\"\u00164\u001e7\u001ao'\u0011xU4\u000eշ(,h=VFQ\u0019Bu\u0001\u00193+\u001ao\u001bScE㩇ә\u0015\u000brB\u0007\u00164yE\b۷\u000bgJB&\u001a\u000fT47\u001aoF\\۷&\u0005\u001aO\u000f\u001bG1jA)\n\u001aoƣ3hC(h<x\u001a\u0006*\u001aONE㩨cSx=\u001a&\u001ao~p\tȓxzJ\u000b\u001a\u0017\u001a\u000fT47\u001a֓Ƴ\u001cxF㡼xj8h<UW4\u001eI\u0017\u001a\"\u0019[OnB)FYx\u0001:xt\u000fx,\n\u001aO˰37\u001a0\u0019g\u0004av}(/h<z\n\u001aOB+h<Md4\u001egx8\u00144\u001e\r\u000b\u0005\u0007秠\u0000a\u00144d4~8v\u0002\tEFT4-Hwx^U4\u001e\u0012\u0005gP/4\u001e%\u0005\u000fQx?xK\n\u001a\u000ffQBјBY[B\u0011!*h<^h<\u0019GVA㡼x\u000b\u001a\u0012p\u0019G7\u001aO߻D\u00144ҵo4ޤ~O4^\u0011h<S\u00144\"\u0015;hW|(/h<\u001c\u000b\u001a\u001axY#'4\u001emA\u0011z{DT4\u0016|\u00151ƣ\")TZx_h<@U4JhSt\u001b5qEiUx*|TXx\nT4\u001eh<*\u001apEFٿ2Zχ#TBQPx|Cxv\u001a3\u001a\u000fS\u001b'P\n\u001aώFz\u0005'xx&\u001a\u000f\u000bĂFTfg4\u0006#Bh<j\u0005G\u0019h<*`\n\u001aB\u00164\u001eJAZ/4*\u001a\u000f ZF1Zx\u00187h\u001cLhd\u0018[R\u001d\u0007V]\u0006p&qs`U\u001cD\u001bXx(\u0005G\b#([x\nW4\u0017\u001aO@AY:xK\r4\f-4\nus&4\u001e\b`Be\u0007I4;xIɿT\u0003gxḀ\tR^`\u001cgőx\u0016\u001c\u000f耿9x-8\u001e\u000f\u0001★If b3V89~(p<\u001c\u0005GS\u000bZxyx\u0011O,$8\u001e\u0017\u001cZp<\u0005*\u001c\u0005#=Wx(\u0005Ǚ/8\u0002#ZxmxD \u000b\u001cp<|x2\u0016p<:\n\u001c\u0017\u001c\u000fP\n\u001co8:\u0019GOayuV8~\n{»\u000b\nf8\u001e\u001587\u001c[0\u001687\u001cO\n\\d8|p<z\u0005A\u0001yP\u000b\u001cOJIyh/p<\u0005z\u0011\u0019(pݠ:\t\rcD/p<\u0015\u0014\u00168\u0012\u0012\u001co\u0001GsF\u0013\u001c\u000fo\u0002ǣ1/8\u0012\u001dg_'4x\u0005RxRp<\u0005W\u0013<\u0019v-%\u0017$xz\ncwQxD2\u001co\t\u0019TAPiYx\b@\n#Wx x;F\t(q)\u001e\u0011%.p<y\u0005Gz\u0005C-p<)\u0015cp\r#[x(\u0005g|\u0014p<+\u001c=Vy[\t7\u001cxpޮ/8p<\u0015\u0019o2\u001cO\u001bxXx\u000bg\u0002\t\n\u0010ȾxjW8J\u0000*\u001cOgQSx(\u0005g:p<\u0002Cp<\u0005S9P'pd8\u0019\fS7\u001c2\u0004]Tga)Qx\bf8hp0\u0017\u001cϔ\nǛZ()p<1xVxZbU8R2\u001co\u0001Ǔru\\\u001dx\u0015)p<x\u0005RxR^p<~uo2\u001cO\u001bG++p<Ix#p<]\nKJa-5x\u00168\u0004p<\u000b\u001c\u000fW\f[BM1xz\u0002\r\u0016p<\u001b*\u001co)\u0019gj\u0014t]p<UW8^Έ\t\u000530,p<v_p<\u0015'8\u0005Px\u001f?ip<\n\n\u001co)\u0019Txz\n;x|\u0002ǓRx(/8\u0019Rx-x\u001d\fӜ[xKp:\u001c\u0013qpOx&\u0005g^\u0019\"7\u001cOIaS[x!p<\u0005j\n[J\u0019\f\u001ap\u001c^x8\r3\fǓefxf\rx.p<M+\u001cO%%\u0015|\u001bgj㙒x|np<\u0002Cyȇ'8p<ҿx*p<m*\u001c\u000fo\u0017\u001cOjIp<vxp<<\u001e\u000b\u001c(4s\u000bgΠ\t.\fS\u001bPIp$8\u0019kZx8x\u0014\u001ae8޾/8p<\u0015w㩣\u0005ǓXxR*\u001cc^p<Lj\n\u001cO\nS1\u001b'T87\u001c\u000f58x\u0017\u001cO_vJ\u000f2\u001c\u000f\u0005[\u0005\u001cog;ؿx\txK\r86\u0015\u000b\nZ\u00158^R\u0012\u001co\u0001SPd8\u001ebmp<mx*\u001c\u000f%\u0010^p<zm)\nQz\u001e֯/8R2\u001co\u0001ǳ7Hp<_p<CU8k\u0013\u001cO17\u001cO\n#b[xKp<S3\u001cr\u0002Ip<)\u0005Ip<\u0002\u0001~S\u00168bM!\u0016p<r\u0005k1\u00168\u001eU\u0019\fKj(U]]x\u001a\u0007p<n\u00028Qx\n\u001bxR+\u001c\u000f%8\u0005C-p<)\u0015'\rGKp<3\u001co\t\u0019gjQx^p<\u00148\u001e>\u0005G+\u000bEoiQx\no8+p<B\u0005G\u000bG]~PxIIp\u0006\u001c2\u0002=x$\u000b\u001c\u000f7\u0002CyP\u000b\u001cpYYVxt^\u00148\u001eQ\u0005\u0004[jr\u0019~(8+p<r}\u0005\u000b?Wx43\u001co\n\u00197ŀޯ4\u00148\u001e\u000e\u000eL-5xX4\u00168%o8^/8*\u001cּ\u0017\u001cO\nǣ\u001b\nS\u0004T)@Zx꘩pd8R\u0003F\nSK\u001bGUu\u00158;b+\u0015\nw\u001dIaY$^\u0015YO2jmTHxZEQ\u0012\\<:\t,z=\u0015%-T<\u0011YP<\u0000/\u0011x\u000f(\u000b\u0007m܁t\u00178[*sEE,$()Vb^B;q>>\u0017\r8\u001e>`x$\u001c4Yx恸/\u0014p#IX\u0005_6JN\u000e\u001a\u0018\u000e\n?+\u0004Ob\u0003$_\u000b\u0019\u0004\tSKZ+ww\tB&w~\u0016N{'s*0qm1\t\u0013*NZ'\u000ej\u0017Nޯʻ>\u0001OG`<qwjᗙR\tz\u001f}\u001cM=\f[\u0014ط̰̭T\u001f-V6v?KSl\u0017+&N͇E栿v=\u001e٩l}v5\u0004-TXv\u000e:(J&Ɏ` ݺ\u0015\u000bȎ4n\u0010+\u001ccH\u001a\u001c\bEx\u000bbWu-k\nV1v$]SG>\u0017?\u0010v8\u0010\u0017\byd\u001dڸŰC\u0018vZ>*îEdIa;\u0019vR_a\u000eo\fv6K\u001fNgV°k؍\u001dǂ5~-]Ӣ;.(v'\u0016\u001e\u0017E\u0019mA$p\nN*?ʄI!2!vR\u0012+\u0010vzÄ5cQ?SfLJ`R8XP,7\u000fH$=!vRl\u001b\u0010#@آ0\u001a\fkݚ'P bfةNAS\"؝\u001aŏ\u0002d9'gɯÃ\u0019\u000b_wZfQ\\]m\u0006@םG*:98uJ=ZSsT6!adH\u001bNP#\u0018X)df\u0012=fc.G~\u0015`\u00198\u0010\u00151t\\\u0012\u0016ni\u0006x\"YyӃ\u0011T\u0007e7v\u001a\u0012\u001b\u0016=GΘ:\tNZ-\u001cvz?)]\u00012CxttF+\u0013QDb\u0000xsօ*x:Mؗ(9\u001a\u0002N7̦[鴾!v\u0015dF\u001fKGEau\\0ydG\f$CROC\u0000yfvBZ<ΗtRY;M(]STҵ=\u0019J'պZ˯\t(]hQt\u0012i\u0018L:\u0014`ҡ\u0010iPFb@ E\u001acN({)P1\rd\tJ1o}AT\u0000dPۛ\u0012ce\u0005Êɚ$\u001dJe\u0013l\fCҬ\u0012tb1\u0016GE^\u001ct\\fi׋divΤS:-7\u0013N_v\u0017\r^W'v\u0003\u00050s{\u0019H:Ը>\u0006\u000e,L@P7ta: ACy\u001eO\b\"\u0019V\u0006N\u001f>tSD%\u0006NEU\"lZ2^c\u000b˵kT(t:퉤\u0003\u0014\u001f9`\u0017\u0003o\u0014a@-%#:tx \u001cîj3]6<\u0013d?&n\n\u0019H75>A\u0005g1t\u001e£ǰH<\u000e`KqVǥ+Pms\u001c\u001d\u0010ǱuZ\u0005G'I1|c\u001a\u001d308:\u0000x>\u0007fc,Ů+it\u0018\u001fII\u0018z\\mkt\u0003\u001cR޶4Z=qtK8N\u001c]oD*8t\u0017\u0002z\u001ev֨`8g-5ptz!Ё\u0013s^\u0017\u001a]Sa$Qy\u0004|p\u001aj\u001e\u0016A렡\u0013\u0014e<htR4:Zd\u0015'\u001b.楠s\t\re37\u000f\"\u000eaFD[j4p^ޱbfm3\u0002t\u0013=ѡ\u0010\u0003p\u0018\u001dE;\u0013\u0017\u0007ξ#\u001f*4!R(Xtsm-\u0014,d\u0016REo;V\u001b\u000b#\u0002=\u0016\"Y3cK\u0015*2f\u0014\u001d^St~\u0007NC3J\u001d1.w,(:vcT\u0004!dx*e\f\buJn\b\u0005,lc6QtW\u001fo\u0018_OEiX;d\u0011\u0017u8v\u0014G\u001a\u00150>\u0001IthWh\u0004q\u001c:=\u0004\u00070\u0006MI{LgB$D\f:\rmT\u0004Nu6\u001bN\u001f.\u0002\u0003u?w=wk36י>gY=YBi]N_?M\\\u000f;ӈd):mAn(9a9sN3u\u001b:rn\t87\u0000Ω@z暦\u000b\f-|\u0002#mF'y/\u0014j&p[^*\u0001\u00199\u0012g\\S8RIk[eM\\k/FpI`;ysaM͡rv\u0015u6%Yfޜ\u0000CwgLYtƄ\u0018~PZ^r\u0016ǞG\u0016?Sd)\u0006XN\u001b2\n&1\u001aA7u!5U7Dn(6rIId\u0006Yu\n\u001c_\u0011\u0016Md9Tm'YN\n\u0011I2Z,'qoP-\u001c҅,'Z\u001d,J\u00045j`o:n\u0004-%\u001a`9{3a䴙\u0011\u001av)}\f;I,\u001c\nO\u0012t\u001ca\u000b;\u001d-%sj\\\u0012vlΕSz3WN\u0016\\9)\u0015K6)\\96R\u0004W\u000e從ŕLY\nW\\+h-%s:rz$T\u000b0yqd'U.^L9W&\u000f\nC,\u0001ӘG\u0000/\u001b7OBÅ('{o\u0012P\u000eg\u0011+Q\u000e<\"I!\u000e7rR\u0016>D4N\u0013RrK\r\\\u001eׂ\u0014xP\u0000\u0016qS\u0004NN~&%R\u001d&wER'Xrra\u001dPrLNv[;\u0017\u001f\u000eCz6\u0013FtQ\u0006X\u0004Dn\n!DG)ĥDis\u0010Wf\r*d/~\u0004B\u0019\u001f'\u00148\u000eP(v(dǝ\n&:N̿p'\u0005[q4XH8|L*k9D\u0019\u001cw5a27\u000eî8\u0019U۵q\u001a:`\u000e\u000b0\u00188Ey|B\u0005%P\u001dC1YuIJ!-5q\u001a18Q$b2k\u0016>\u000bbBJf\"\u00158E06H8\u0005l|\u000ed΄Pq\nP\u0013?qre6Qpr%)q^R+\u000eB2\u000f'-%\u00138:\u0012\u00058ڙBL ē\u0018\u000e9G0\u001f%Ʊ2\u0010ڈ`b\u0010ZMb\u0014g\u0018הƾh|sbv˝\u0018%.\u0018:\u0002IH\u0000\u001a^q\u0001B+q|e2yqXsN`\\Zvm\u0015\u0015蝙\u0004*Nڤ&*˗@kSx\u0012TB2\u001e'*N\u0001\fB\u0005\u0015ף3 Pq\u001cv;\u0005;TE\u0016PAx;\u0011ˆ;)N\naB#\u000bAv,<')k滐W0\u0007*/YzVd3\b(Hqj5HqTRzINR\u001cHD2ۊ#b8aqR\beOX\u001c\u000e'\u0004#tP4LX\u001c\u001a\u0005\u0016'Hۄڭu0~\u0015XSd&-\u000e7wZ8Q\u0017ZZ/y'-\u000e6\u0006\u0015\u0010Aӵn+8\u0005*L\\\\\u000fi$_Wpq\u0017.NQ1b\n.N*\u0001ӓkIa\u001dQpqR\u0019&.\u000eE{C9J#q!4FMZ\\\u0003*g0\u00001iq\"\u0016-N!1Ar?\u0016/\u000bŽ\u0018\u001d/r\u0007[8f\u0004/=\r^\\\"͗xq\u0012=\u001fl@š(Uxqp+\u0003\u0018g\u001d·|3\u0002cPvK鐝S\tӀ[\u0001ƵL`\u001c3\u0012\u0000)FO\u0001I~h\u0002\u0019\u0000ơ`qRaq\u0006/\u000e\u0017ǉAg^\u00160xM^>-\u0002-j:Q{\u0006T&a\u00138U&\u000b\u0017TDVAp\u0002Qtʉژ a`4G\u0018L<TH>V\u0011'+&\"NsџJ\u0002a<c\u0001NN>\u0017\u001fl\fx8v/8zA۳W6y\u001b0hQ;i\u0019w2}Lp;:O,\u001c{T\n}ƠµȟO*_\u000b\u0015NcJE&\u0015\bk\nG0{)\u000ehR\u0001ۢ)\u0000Rp%^T8)D&\u0015\u000eAZ4~N(\u001c\u000e*\u0014N\u001fLɄ\"\u0013L8B\tʉ\t@\u000eO\t\u001b`5r1t\u0003\n\n\u0002\no\t'{0@0\"\u001cn?\u0001ᨩŃ<Ee\u0018W2\rN\u0013~<\u000b\u0006'KF\u0012X\rGs\u0017\t5$b\f{\"\u001c8M2\"0p\u0002`\u001dO=_4gqy0G\u0016&B#\u0012\u00008\fJ>oޯא\u0016\u001b,\u0006OZ`\t\u0019U{3(\u0011r\u0014>v=cѩ\u0016}\u000f\\\u0017(o\u0003\u0003>^p/i\u0015\u0013m\u00117\u0012ꢦ!)Ǌ#5\u001d*~t\u0019g\u0019¢\u0010\u001bW=ft\u0017\"\u0010zj\ts[\u0018\u000e\\E=]I\u0016Ho\u0002E\u001ejDگ\u001c_7mW\rLݾ\to*s\u0003P\u0000oJ^ؚ*\u0000o4\u0001o]՚n\u001aWX\u0004߭I\u0019Y\u001a\\5P{nʂX]HY/d!w}.39h7dmg\u0001*\\7\"TSqBuS\tM\u0007\u000euSM\u00053\u00141bHk''؁n@·a&M\u0010\u001e!*j\u0015=Nsp8H/]s\u0015-\u000f(Ado\u0007\u0014N$R\u0014k\u001c7\u0019ci_0ncN\u001b,\\\u00107Bz2M7pS\r=xmG!]Ni\u0000wvO\ta\u0004)\u0005kn\u0007AoStb'U6g\u0007nO&ftInl/nrƶ+Jڦ\u001d\u0011\u000b\u0018^p\u00106\t\u001fEBqW^*T\b\u0005\u0015%V06p1Ymf@uM\u0016R\\-\u000el~t\b\tC)m\u00075&mtd)Ӹ;0m\"$Z5vI\u0001\u0002-o\u000b\u0018\u0003\u000fxӛݣpgiIemς)z\\ƫl6 &;M\u0011v0\u0017Be08}e۽dbnBeYL鋠\u0013)}Bv+\rRvAdv\u0002oc#+qlM#\u001f\u0002\u0006{űi\u0012a@86f\u0003\u000f;Ǳ٪wT\u001a!\u0005cӊR\u0019Ʀs-\u001a06=ڶ:\f\u0018[k>\u0016\u0018[U,BZTX\u0015\u001a\u001b*ePM\u001a\u0014K3f\u001aT'Q&2M'戓F\u0002߲Un):BcCU.`l\u0012(&\n\u0018Ѧ[<6g\u0016\u001e\u0019ֈS\u001aXW_06)\u001eK򔑖$\u00056$ؚF\u000bR,\u000ecSn)k7&݂ѰE1ؔkz\u001a\u000eNe\u00160,f'm%\u0001֨bka^=Yl(-\u0014\u001b'\u001eW%I$\"\u0011 6\t\u0016\fĦ?\t\u0014\u0010JRٜM\u0010\u001bq\u001aV\u0003hb8ؤR]\u0015\u001c㕗\u0010<Q@lR7fZ#NE3$6($\u0006Dv?3J@z&M\u0015\u0007Z\u0002rֈgtU>\u0004ES!ߓĦ=֓؉i\u001fIl\r\u0017Mgڼ\u001f$&>D\u00065Jt\u0003Ħ/>46PkZw&\u0010D\n\f&\u0014`]n!VN$6T,Ab{$\u0000\u0015\u0012[\u0012$kIb\u0013jIlb$6>A{\u001a\u0017n\"ѿH*Il\u0013W\f\u0012\u0019e\u0012\u0000<8MނĦr3\u001b3\t]Abk\u00153Ilmw+bcܱUV[6\"G\u001c\b\fcC>`lRzB+O\u0019\u0016\u0005TlO{TNW$3$6\"\"tsB2rĆa$Y p$6`)ĦD\u001eIbSm$A%IlF\u0005>Eb#l\u00061Hl9( 1\f\u0012\u001b8LcAb3+O=Il(6x.g5C\"ɍ\"KAbQq;IlͰ2{%pT$63DJ\\i\u0014+%$6=Ħ4\u0012%\bAb\u0013~٦\u0004beJ:Y 6QM\u0014\u001c6eވmM\u000e7l\u000f\u000e\u001dl%Al\u0014?\u0013\u001d૖\f6\u0001bS\u0019A\u000f\u0010.\u0019+R\u0019f\u000e*X$]\u0017MR\"IK#ѧdN'JfHYӮ\u001f 6l݋F\u0006`k[9c8Xcؔ\u0006e)l\u000e~\u0016M/DMİ\u0003(1lXnd\u0010rN\u0010ntL\u0004\u001e=j3MaVKaLlHwZ\u0015\f\u0012Ř \u0004\u001f\u0016`bi\u0000}RشԳuIP\u001aXU*\u001f+7\n*@YO\nzj6\nMuEd\b&}l\u001b71lZPF01lʽ-\u0017\u0014CP;+Mak\f\n6[\u0016\f\n\u001bnv%\b=lH\fˇ`w\u001e\u0015vz~f\u0012\u0014:\u001c\u0004WLW\u0006\u0000l\nt\u0007M\u0000\u001b\u0002R\u0019S\u00006O\\Ӹ򯋾[)\u0016C\u000f\b\fT4?cN$\u00115)\u0016\r\u0014ʊ\u000b}Mi9*įi@£_`iX 7;U\u001cF\b״@\u0018Te¥5\r\u0001qi2kT\"&B_C-k(,\u001adW>\u0005_S\u0005\u0002NU\u001eƙ3}dWR\bL_\u0003\u0010M_,\u0013}M\u001f̢yA_å\u001a\u0017D_C\u000e\"k(\u0007kRZ(5V\u0010\u000e\u0001_m=_\u0013\u001dAגkK\r<\u000b~Mo\u001a&\u0005&S_KJ9\u001a53O5\u001c/\u001a0_U\u001bZk(\u0019&_C50\u0012\u0005&_Tk!\u000fs#}A\n~Me30-5X\u0004}6ۻj%\u0016d5kR\bZ\u0006|=Y\u0004_#fg)ƉIƄ9\t_c5\u000b<5[/\u001a\u0002~^D\b\u000b{M*`\u0011?<k45\u00115a|j1k*0ӛ^y\u0006{f4\u000e,5T<72f\u0001-2\u0019f1wa\u0007=kmF\u0000\"C\u0004p~\u0011[e\u0005~[+\u0017%N5$TJ7įq~_CjפHN\u001a)`$]kx\u001f\u00114\u0016\u0014T59FyGژ׻gJ[4\u001cmG6kXc\u0005}MqTcјNy~}_n޽׈\u0006PY\u001c\u001e9I_4gD_kx\u0002)r\u001c2kII\u0006\r\u0000\u0001VcX:_nj\u0017CD3\rf~T\u0002[R\fo\u000f\u0004T{\b6T*\u0003B \u0010lRg\u0004\u001b{>\u0002u:Zr\u0004\u001bnf\u0013\u0010l\u0018\u000b\u0005.\u0002\\TG-\u000fkVӥ)(\u0013ذ 50\u000fS\rK'-!\u0013ؒ\u0001j\u0017\u0004`kT\u0000l:\u0004\u0011#i\u001cK{C\u00006\u0005(\u000f9\bl\u000e+9\u0001l\u0003r/\u00006Vj\u00006xlI\u0003FJ\u0004!\u0010ըbI!Pkok\bJ\f&v*}Mak\u0002\u0004|=Ry{D=ffi\u001fL}\u000e&zpCB^S\u0000:];W`$ưDgе\u0016\u0005FI\\#p<\u000bFm\u001au6\u001en\u0007nMNkQIGՎ\u0001\"{)Xk\u0012.G\u0011~f{*i\bq$cnO5I,ڱYv\u0012֦\u0001k«Ul ]\u0011\\p\\R̚Xt4\u0019/ZXLN:\r\tʌU^\u0005!4\u0006T\f\u0004UZ@TB.jwl\u001e\u0017QM\u000b's\u0004\bR2QmAT{htP\u0006T\u0012OMs\bŅ!b9կESS!\u0013X\u0011'\u000fm+\u0013yTB\t\u0004IM[\u0001RÛv{*G\u0010v&FLnf!C\bwh\u000f\u0001\u0013#\u0004Mb\u0000\u0014\u00187XiIXƧ\u0012%\u001b\u0013>XKH)\u0006=v;IE\u0013uFKצH}yĄ-%Z\u0018OxJ'.:hT֡\"##0igx(epi)a`NxrPiliull͕ؑi\u001eL\"f4=yi*΀#\u0015Z+Sf9XiSȨ%BJ;ܛk\u0014\fC+s\u0001(iǽbI`՜\u0019iX4\t\u0005\bi|+ \r'Z|au\u001d\u0016g6ԜF,@\u000b谕>ڹ\u0011ʱh[L*ڵYff\tN]\u0006p|\u0017LMWl桱*\u0018R\u0013-%?K\r\u001eZ,\u0000f1qhf\u0016Dۇdh\u0001Dk\n\u0010\fDL\u0017\u0017\"\u0016El#&\u0010MAX\u0015 =qqn\u0011my\u00033;^\u0018j\u0010(3\u000b\u001e\u001a\n\u0018FR݁h\u0012HhL V\u0014\u0016$Z,\u001fH4l\u000f$\u001a\u000eg榓hRhRH7N$ZsLDby-Dp3pwMO Zz\u001d+R\u000f67R\u0010\u0014\u0013\"ED~ IZ\u0010ђh*$\u0016wEFŏ\u0015%00ۉD3OqAI5Ga\u00074\u0006hLl2#Ѥ{\u0000ִHѰn.ND\u0010 [\n)hQ\u0016IDSQ\b\u000eoVD4)N\"Z\u001bt{*\u0011\rX 8R\u0017\u000fɵԤ&hjh{F4&\u0003q\u0001Dk_\u0011V߶\\D:~$-%\u0013і\u001aD4m\fb\u00103\r(|O@4U\u0005\u001dֳ5yhKH8)\u0006\rM\u0001'\"<\"cih۳`hmxtдeih\u0012\u0019\u0019\u0003(\u0005\u001cn\u0011\u000e\u001a>(\u0013s\u001d9W*\b=\u000f;7/.\u000b\u001aR2\rmAC7\u0018\u00131\u0001BCSI\u0005B%J@ih\nBV/\u00145,EZXZ]R2\r}_44A\u0018\t\u001aZ(f\u001d&ս!&ʼ@V,Фڰ04\u0004l\u0003\u0000C:WmK\u001aah<ӓC[bH\u000fY!Ccŵu\u001e_٣-!В\u001a!CZ4\u001a\u0007Ls?\u0012\u000f\u000e;yJMI\r\u0004\u000fM\\ٌCs\u0010v\u0014qCC:A\u0019CbC'3olތ9\u001b\u000em\t\u0019fꞭ^\t1Ǐ\t:#fΉ֮)>\n-h*`jVhbP\u001d@4-96ß9\u0010MF|\u0005h\u0004$\u001fk&L֯\u001f@\u0017N\u001eZR\u0012\u000fmCfx6/ \u001avp`\u0001D8;8m7j\u0005)\u0002Pj\u0001D`\u0005\u0011mx\u0015\"fa\u0019D4j=\u0005\u0011-) W:Eb\u0006*N$&\u0007\u0013\u0011\rLDaB\u001e@4֙Fs\"R2\u0012mDk~z\u0018-f)\fma\u0015\u001a\u0001E3N#\u0007'M5h\u000b2(\u0007\u001e\tEk\u0017N(Z\u0018PO&\u0016԰e$Luh@\u0000Y_f\"|g\u0000\u0004\u00102 Cc4=Qԙ:\t@c=\u0002~6Pg^>6s\u0013WWK\u0003//>_j\u0005?3_\u0004\u0017^/x/\u001f%_|R\u001f?>\u0018?\u001f+\u001dH[e\u0002Me袉\u000f?Oϔ8\u000f??|7EC>ò,>w^DeDReǶ+\u001d;a?eQy\r09DLє\u001b\u001fyPϸz[YYc[V*s_Sq\u001b*x!|\u001bP8!yכ\u0005[\u001b_o\u001a6\u001bW_zۿ-\u001eAa:96u,:\u000f\u0012+w}eӋwBo~Me7pލ0_־f,fI-O]K?Kίev~j5,Ɋ\u0004!~\u0001R\u0002țv.͏%j\"?/p)z\u000fK(ۯ͎\b[b`\u001di=Гa\"\boFD7!'^d>r샿YH!v|*oGc\u001fK\u0017/vWb\"LHEJc\nz؏YNt\u0013agp'и/6>X\u0013Yqk_A鼀\"\n^bɃHо\u0002\u001f6^\u001fG\u0014Y.\u0001G4~#\u0013)CW$\u001a\u0012C,G,Q\u0011~G>\u0017G*q8cI_/ݿS\u0015`\u0019\fW>p\u000fm\"y>*Axk.!u%\u0011AH}D\u0007 ~\u000eY_db?UX~\u0017o;?헥ۨɊw\u001f\u0012Qb/h#eY\fdJ$\u001eҵG9/\u0017f\u0019\t\u000en?tX(^\u0017m!\u000f\u001fd\u001c=\rJb]\n\u001cqָ%~ZCg\u0017^|5 Vl29|\u00021\u0013?q[Q\fbwg\u001f JO>ӵ;\u0015O\u000e|]\u0019kB͞V-\u0015-cznӽBg`ߛ\u000fD{\u000b\u001a\u0017\\͖\u001178|\u0010\u0007Ӟ~gٗƀy])\f\\\u0002Vg}\ttm>[ˑ\u001cG\u0013\u001d̨\u0003(e\u000452-J2RH6g\u0006$FXMQO%2+Ql\u0002U`&\u0012pD{d\u0015\u0001y\u00139v٫fץ\\/C\u0004y؈>*t,(۔M$Zn*8I09D?]Q)\u0018\u001aL\u001a+\u001d'nwW\u0006ZA;xw\u001eA\u0007꠳UX,N\u0006\u001d+NT\u0001^\u0019t޷\f\n&bʠ\u0003xw7ׁW\u0006Z!N\u0007I\u000f:W\u0007ryPye\u0001;\u001c\u001f]\u0004_\u0007^\u0019td%1ŋEZ!$ې\u0012_=@&`>W}aU\u0018%yZRv\u001dL\u0014f\u0001׉=~-WO\u0002\u00187\ft\u0014a`U_5 \u001e\u0000>m@\"\u001dThGs\u0016O2\r* \u001aŵ\u001dNopĭ\u0011\\\t!d\u0019(@,!HDG\u0019\u0002=Nh#\u001b陼\\2L4\u000f=LIK!)\f.8VpME.IX];SY\b*Td4m\u0005}y,\u0004JG\u0002.N@J\u000e\u0010#w*\u001d\u0007[m\u001b\u0002G\u001d\u001d8o`낶u\u0010d\u0018X]U`Rd\t&=_\u0015\n^6,ؓM\u0015-\r18 7\u00126xDmp\u0017UiL\u000e)p^f쬯2\u000f*%O\u001a}iq\u0003t\u0010Eu\b\u001eY*8\u0005k\u001eyy2Ftp\"!\u001f\u001a\u0003㹂b|۽v\u0017!e/B\rr\t\u0011o\u0010Y*:\u000eM&68\fH\tNɛɊY\u0019\u0017!\u0015<\u0012ÀC,\u0002萠7MY4bv\u0006\u0006٪\u0017J)\r3M(@+r(\u001a²KtBjy \u000fn\u0017kyѥ\fmGe\u001e+|3\"\"v@Bl\u000e\nLVX\u001be\u0002\bnB\u001a\u000bI\u0010<{]\u0002W\u0012抵\u0013\u001bf<\u0019Pg\u001clT^!\"\u0005\u001dY`A{vu[\u0016uM#QI\u0007xTO(6lc[׉R\u001d-_Ad\u0000v-`\u001fl\t}5T[v5fߡ>d\\\u0004vUMMe`\nuA=#A\u0016\u000ejtҶ* T\u0007\u0010]J=W\u0005+:\u0003dI6Y%I%豔\u001f\bi\u0005L\t,\u0002\f\bMxVhE1{u2~\u0016ů\u001a\nY8V83qGWCjr?|aOmV.Mkn련\u0014\u0016\u0006\u0014|x(](v#HB3mV/b\ns:@\u0002\u0007N_U\u0012@U#\u0006N$6*3bwB[\u00063.u\nӫ:/}@\u001aȦ\u000b:eU\u001e\"B\u001a\u0019\r_)r.JKcB]mU\u0002NXF\u0000ۉיQ\u0012Ml\u0016T9\u0018R&p\u000b0heƳ Lp;KPe\u001e\u0001@rr]\u0015s%u&ϰT}\u0007*\u0005Լ:c\u0004UbZF75NRT|o\u001a\fpCkx#]'b.\u0018\u000bH2[LSk\u0014\\\u0005!if SC\u0006T[(O\r`W\u00110p\u0000\u000e}\u0000<A\rNɯ\u0003U?i@&\u000f\u0006S%\u0002PJQ$M\u0014Ry\u0018\u0000}\u001b\u000b*cO8\u001aQSnxms'\\vd\u0005\u0003;]\\\"yKa5ExTurHU\u0018#W[}{G?W*eSg\u0018zc\u00183|g\u001d{\u0010ء\n\u001c&{\u0006\u0013}S\u001aBV\u001fvڬkV;K5YNfl\u0005H\u0015^^hJF\be.M*ﻘ]#{\u0013޻4<\u0013e\u000e\u0011B^P&.>!8:O\foYiH~\bʊם\u0004Dt!ߓLcp\u0014m3\u000e\n8<\t\u0018l5\u0003\u0010Q\u000b\u0003)2L:SѶ1f %\u001f\u0014E\u000eCuP\u0019T\u001dXHLr^6@2s\u001123X*\"\u0001;eDwTt*2ΤAfk\u0001\u0007gd5v$BE\u0019Ų\u0002X\u0003\u001apiQFea֗\u000e\u0011i*M\u001bOku\u0011Nಏ]?T\riʌSE\u0005%9\u001f\u0018V^mepO8QET\u0002\u0019l :l\u0017\u001b\u001a8rXzYh\u0006%wsKUDdJ(h\n\u0017Ge'\u0016ElMq\u0007j\u00066޲V;H;X-`kEW\u0015;\u0007\u00067\\'E1N\b8\u0014V\u001a\u000e:j\u000b`+z.\u000f\u001bmۅ2%\u000e<lvؚ&Lᄁצ\u0017b8wL@`A\f#eM\u0001޵C[\u0004*05ǲdI<\\_\u0000I\f4Y)\nk;2`q\u00043?zX\u0014\u0000ېx\u000ezX\u001b(\tЕ9M&0^\":\f&1/L&3\u0005\fT]=\r\u00148\u0013\u0006[V-F`XS?R0߱Fd\u0019\u001d\u001aً+%!Iˢ\fJ\u001b>=_#'3p/]\rvH[o\u0012y0΁\u001ffe7!Nv,)_'qY%\re%n'a\u001d\\\u0010\u0014l\u0017\u001fxH\u001c\n8G嬛H)\u0005fZ\u0000\u001ae\u0003.\\ۅ06kuT'\u000e^}\t\u0019\u0001eK\u0001]\u0013fL\u0003H\bJL+W\u0016pޑVdQ\u0001(\u0000_ۯ\u0014XYXV\u0017%Gz)`\u0015\"RO\fݍR綦_\u0019\u0010ŤB7Mk\u0001x \r*3L\u0001L݌?NR\\gzmgJ\u000f1u}\ni|\u0003e\u000by\u0007F1)5l\u00145)0h^:\u0000\u0016k\u0000\u0004Ƞmn\buJY\u000e4\f\u001ddb1>\u0018\u001a\u0002'K\u0018֦Q<\u0016BwP\u0016\u001c>Uke\u0019\u0005A\\\u000b[y2\u001ebJ.!ffE}r\u001d\u0004\u0018SbCt:L\u001d\u0011{6?6M*%Ct2\u000b~\r`nP)r>(<9\bs\u00101=Ʈ%vh+m|I\r;~U5\f\u0001W.⍚393r3Rk\u0001u6\u0000\u0002MVK,SY\u0004&߾w׫ȗd0+2#\nc\u0004\u0005NV KCE2W\u000eR2C鄔\b\u00003QX(\u001d(k\u001aݧځM\u0010\u0000&m|\u000625JW3\u0018\u0014klσcZ\u0005h\u0017\u0001M\u0014}\u001eUBut\rI\\j\t1\u0014\u0006$(@\u0012#*']\u0015?*`ϡ\u0018[ȫ,6\u001a\u0000qC|P܁{IND'IƦXe\u001bH\u0012L{l\b@\u0015V;R\u000enh\u0001j\u0007w \u001b\u0001ͼ\fN\t\r*NdNGb@5\u0017g\u001ev-#d,_z`\u0001#XXR;cLVZYTTDѺ~5((Y:#٠xyg0L-\b\u001a\u0013:0P$u|H\u001a\u0005޹ks[1\r\u001ev^\u0005}7rov\u0010z\u0004K#:\u0012\u0004Y3Z^B)@\u0000hY)}jz(ЪNC/$\u0011\u0000I\u001f\u0013X\nc\u0019\u0000(oSRԽ#\u00046QL\u0000\u0014\u0012\u0002U;P25VCS\t*v\n \u000fJC\u0007\u0012Qu&*\"R|I$\u001fV?(M1Z\u0018[3\u0017(\\\u001f\u000e7!O\u0015(\u0010\u0005\nhE\u0001+\u0011e\u0014hEլ0*£[0)dtP\u0000\u0002rHL\u0007h\u0014\u0011!U})l\u0002sG6\u0013-]cDA\rpj(a{(zm\u0010\u000f_\u0019&\u00165-&tXj\u0019(\\lx$ST\u001eJ\u00033_\"ӔX\u0006t\u0002$Z^\u0012r;t1#O5\u0000Fʽ\u000e\u0002L\u0012UȣnF\u0018m\u0019|r\u0016hːk\u001dW\u00140l\u0015`\u001b\u000b\r\u0003cE6W?tٹ\f\rUzn(\u001c\t |6.h\u0005jDdE<r/,\u0005,\u0000\u0012\u0019Y\u00103XQ\\\u0006_GUH\u0010}Z=F_R*&\u0012,s?\u0006B@JN@=Ө\n\u0004'\u0015\u0005RC\u0006\t&\u0000?u'\u00183ZCD\u0000y\u0013lek\u001c\u0003c2\r]@X\u0005XOG\nDÿS\u0011Pbk\\\r\u0012 \n#\t:ʷvS\nT->B1VX%\u0006\u0003mz\u0003\u0014Z^9\u001e]8P\u000e\"H`<ƨ\u0013Db.\u0001\u0018T\u001eN\u0001\u0015lmȀ;,ݫ\u0019\u0000®Yad\u0014\u0012\u00195ʛְ/{]vR/\u0000V9r53<\u001d\u0014$wz$[a;ސJl\u00112e\u0019\u0004Z\u0001\u0015\u001a'݀w!\u0004f\u001e8zkuv\u000f\u0006.G\tdQɧ\u0013\r\u0011I\u0010Lt\u000f\u0018A\u001f-\u0005\u0000#UH\u0013\u0011(\u0004\u0006\u001d/Z\u001dYԦ\u0012z8\u000b\u0015Rò?\u0002\u001b\u0018U--_Vz\u0015#sݢ=v0\u001e\u0005}\u001ei)@6ur4ھߝȨ\u001d\u0014t2W;&mPv\u000fKHbiF\u0007UDhQ\u00069؍^JQW7E! \u001d@ޥg(b\u001bUeK\u001eg\u001b\tιF1=>_E瑀'\u001aSDi\u0000Mg_\u0012UӍd oȣ\t\u0000\n'D;k=\u001bGB\u0000\u0003D+I w\u0011K0_\u0001\n*l!g`H1Fg\u0010_.\u0015հ%8\f:(<;Z\u0005\u0016\u000b)]\u0019e\rHUv\u00040\u0006[P\u0011ziTuNAֵd\u0014-\u0014#\u001dd5k(/=6@\r#fע;\u00193\n\u0019\u0005;\u0002\f.\nZ\u000e侉Hzk4W\u0002\u0015JAyP2\"_!68E#[W\u0006jT\u0014\u001e;T\u0017d\u0017K6GU\u000bh\u0000~pL\nUIAQj\t>\u000e\\YA\b\u001cRT\u0012\u001eW8E\u001fp1\bM\u0007n\u001b#|{L+L\u0014<\u001ctva\u00032ƣ`'3چ|\nx$Iڠq6z\u0015Xww8#וR\"\".mY\u001dLK\b['Fҭxv\u001a\u0004\u0014j)\u001ee$\u000b2j,&vPʛn\u0017LU`RtAe(NmxS%vthHwU1{$\\\u001c\u0007\u0011:\u0004z##1wP:j.<\u0018&O\u0012t\u001b\\킄Tg@cV!\r00B\u0006o(\u001fj\u001e{JO=\u000ev\u001d?\b\u001aA5\ngCG+A\u0006U\t\u001ef\u001d&{\u0018@Ծ\\_Eʸ6fY\u001a~w*duAR\u001e|rID\u0001F\u0015UK6M$̡JCRY9݀\u00147ïܯXhP\u0019$]{\u0007@V\u0016\u0003BPb\u000f\u0001D\u0018c7qa\u0006cKe^\u001dĬd]#\u001b\u0015_5ܗ̞\u0015<\u0018\u001f4\u0004\u00187\u0017{>ސ*oAEpE%\rgУ\u0015Y\u0015F.^G&~OSUЊ3\u000bc9\u0002P9[y9;y:?\u000fmV)(ւ\u001b\u0016(zI\u001c\u0012\u0012\u001fd\u00165LYQ\u0010v\u0010z\u00075\u0005hP-\b\u0007V1H'j$A)`s\u0007;Q\"5\rw3*\u001bb{ĉ\u0000hT,u\u0010^\u000eH\u001c\u000eIerwSڮB\rW7p]SDZʪ(KbTW.u7Q#\u0006TJ+0ɆZUۑ.F$,\r\f4^\u0012.j\u0007QbrgAn=\u000e%6tHbV_\u0007\u000eͪArޚ\bnp\u0001\u001e$Dj\u0013\"\u0019V5\bk몗O1qJ5@mxk\u0010Ad4-ACiJp\u0000gzjxڴkҪǬ\u0001eK\fVo#bX+1Y\f\u0018DS;=kd\u0014N-\u0017BXjuŜ\r4\u0011{kb#5:&Z\n\u0018\u000et(A/5\u0015F\u000b?1:\u0003!;;\u00189((A\u0005\u000e}\u0014J\u0001_cܑ'Nբگ`c\u000e9grP6:_.&\u001e\u001f{\u000f>d\u0014H\u0019R\u0010T\u0003/~\u0005dg\u000fd\bb1*EUj(eS\u00057-\u0005\u001c&T\u0011\u001bT9}\njXJHJh\u0002\u0010|\u001b\u001dm\u0018\u000e\u00030@$\u001d\u0005%t7ejF(/WerOTYj>CO\u0002,\u0006oPj}IltJ^\u001fratOab \u0017\u000es\u001a\u000ep\rMv\u001dMꉣ_\\j`nC;P6\u000e\u0014\u0013_Fh{n#\bسE\u001c%$ \u001e\f%d`\u001a8\u0003\u001b\u000e\u001bO1{~\u0005=2L`!:=\\\u0014EK\u000e\u0011\u0010%kI\u0015\u0011\u001dTMͣg@#\n\u000e\u001aDD*;M}\n/˳\u0014= *\u0011sω*\f\fC\r%=\u0010\u000fk(AL\u000e+o\nڳGbb\u0019k\u001eP8-BऱtK橳=\u0012\u000b7wz#\u001d\u0015{\"sV\u0016\u0017G6C=+A%i\u0001\u0015\u0014uvg77th\u0019\u0002sf\u0004\u0011ώ,J*(y\u0016UN>\u000e1\u001d8F~<j\u001a+M5Q\u000f\"BO\u0014o<PJsJW4>\f5ZE7=7:*{͡ SD8üQ\\\u001e\u001c|W\u001aR2R[5T\u0010QVUܳ#κZ52\u0015/,z\u0013\u0006Θ\u0016r5/X΍\u0000k\u001c\u001bIO+V0\u000324\rK\f\u001ahF-]&\u000fN.\u0013\u00063X`izjT\r]\u0004T{$=دxX!\u0004-\u000fYw=!Υ*w\u000f9gݰ\u0002QHf0,\u0001ߝ̆A/辤Mh۳|>\u0017J\u0004\nS09MIzov*/`\u001eOu0J\tYc[\u00108\u0018\";\u0007Ӕx\u0015\u0010:\u0001V4\u0017ўb(84\u0014(\u001ei\fTpz\u0001Aj%^\n\\\rj\u000e]PMJ\u0001\u001354VJ,l\u001d1\u001a\u0006+\nX'k{*{\u0007+{\u000et\u0000\u000ekg* n\u0017_S\"ށ*bkt{l\u0011\u0005e8F&bk}wz`ԓLJY@Z}jȔ\u000bk4D\u0005m\u0018ji9΃wP\u0003M\u0004[?\u0015jRzz<\u001b¨ԟ/0\fY2WYl+\u0019U2燗zI\u000e\u001a.Q\u0019\u0002]\u001cv3\u001eŌYU\"/g\bC%dAkH?48U\\F;\u0010̅Tr(\u0005\b5\\*X\u0006\u0018mZ]\n\u001ay!0΍\u000eތa\u0005Q\u0018\u0002\u001e4&;\u0004wd,\u0001\u0003=ϨT\u0015q\u001cY&f{NԹIFQ<|\u0015y\u001d)%\".\u0014`X;\u0016\u001c[5(\fU}\u001cM\u0018\reE\u001c0.\u0017(7S M.z헂w\u0003m\u0018\r=GN \u0019eIR UN\u0017\u0006:iZ\u0016\u0002:j\u0010:zWd\u0004Oس^}\r끃J*ފ؍;\u0012ǻ{<\\?OU\u0006\u001b0~m}\nӒ\u0011~P\u0018]-!7č@4\u0003#\u000eQ\u001f\u0014,W^`\u001b\u001cjяȋ8\u000edO\u00037A\u001d$[q\u001aKQi%ƑNT(\u0015FdU874mRKq@\u00155\u001d uĐZvc&`RXG\u0016st\u0001YiUp)*tjf2#Z\u00031T \u0017f\u0017px;ŝDmWōԋ{j|Ϝ)\u001ey8E|jV\u0014A]ZX*v(=\u001b<؜Bws̕ڥ0㒣m\"\u001e\u0007\u000bc\u000f.'đ\u0003m\u000fҝ\u001a\u0017\u001ds\f#$l]T%+P*zT-īL\u001c\rV U\u001dzmS\u0005?lJ\u0017\u0004\\pw\u0010PU\u0019\u001e(x\"x(F\t\u0010:tM/ Zpv#\u0015*\u0006t\u0015ޕ\u000ejO\u001d% DА`\u0012\u000ee(4?og~:EQ-\u001b\u0007cKh2@U\riy챮]\u0006):%u\u0014#C\u001d\u001e\rmP=\u0013U\u0017RZ\u000fj\u00024H\b\u001eBzU\u0015\fwE\\nk[{Z'\t-;Qٳ\fY1\u0006Ёb\u0014ƨZ{\u0007׵\tj{GkG#v[A\u0019n%OGK7D,aC|\u0016\u0000kpd*5ә\u001a-`\u000b B\u0019r#ǃ\u0000hD?\u0003{lj\u00037\u0019Du\u00187qZmǊűX~\u0002%HE\u0001fU5!!\u0016@׹\b\u0014Dރ}\"ڮ7m\u001c*\u001e\u0014?%\u0001C\u0013{}\u0003\u0000\u0018T7\u000bѶζD\u0014/P?\u000e=\rɱFʖztp\n\u0001Z+5u;\u0015?Eˬ\u001e\u0014\u000b\u0003qI6:¥sA|^r1^J\u000e<\u0005%\u0001'\u001b)eZh64Ug\\:\bpu9 K\bkiW\u0017j\u000bfL+\u0018.KӞߕ\u0019F\"`6vl\u0000h5\u000e`~\u001eJ'B(\u001enU\r-5Cۊ_\u0018\u000fuMJ2p\u001cE\u0006\u000eVzd|CNI\u0015k\u0001qA\b\u0003*K_[OvPm\u0006\u0007NuS=\u0004I[e\u000f\u001dG\\z\u001c@\rF\rt\u0001#J$\u000f&u0\f\u0015\u001d8\u0015ڻFY\u0004Iu~-R\u001f*^\u0012t01_'\u001c{A`@#\u000f/:kFb7kx\u0006=\bځX\u0016~\u0012/\u0010QAA\fTEVm\u0019Iy\bjH\"\u0005\u0003ד\u00162\fK\u0001\u0003{\u0010\rendstream\rendobj\r23 0 obj\r<</Length 64295>>stream\r\nìTXL\n*\bZTQG\u0010,O0atg;zTex}~( D[u˫\u001c\u0004\u0011=q\u000f/i\u0007[\u0004-\u000e+\u001a.Kը*{\u001e⻙\u0011ApV\u0015\u0014)F9Y\u0019B;%ȸ#:\u001dJ\u0016A\u0013\u001d٥\b]\u0013h!\n\u0007\u000eGDՒpV\u0003\u0016o5t}6<Egy1=;/EEBRI\u0004\u0010\u000b`\u0018\u000b\b\u001chB\u001a\u00022ސ\u001av\u0003q\u0007\u001bkkUɹ{}pŌq50<HTrg f$C\u000e4'!\"Hɪ\\\u0004 s\r#\u0010ql%&P5H_#\u00178nr)Rp(b\u0002*n(;\u00145%d8\u0010\u0017!10N\u00112\u0006ڎ)\u0018ѽәJ<\bP9,eTS;\u001f=TL,/rk *Utce[\u0011ܒ\u0005\u0005q\u0016E\u0015)c)x}7M%j4&N\b\u0004\u001e:\u0004\u001d֨U1\u001eݸw}p%u\u0002iV\nj'<\"fqNrK(}\u0005=\u0005\nfS^F.{{5&\u0002S\u00166f-\u0005q1ӥ\u0016t,tt\u00199s\u001ax(;B\u0019jK\u0001Ǩ\\,II\u0003+1\u0014'n;_\"x\f()·V=\u001fB\u0010J)2;ç+AY^\u0013J#2D g3\u000eF[Kz\u0012^E;Py4xtH3]VڭC|t0Lr=\n?.~\u0013\u0015A)T&\u0001\u00121qM\u0016\u0011%Mj\u0016G;lL\u0015jp*\u001d&R:k-+J,w=řƅ'\f]6mҺ\u001au?FR\u000e\u0006YjȥkE\u0010\u0016\r&+pJL{ѐުDO{\u0002R88>Hܚ׏'\u0018mVEdqz\"\"xֱLY&$\u000eԫbwV\u0004!X\u001aT{\u0000 6B\f\u000eO#1k\u0010(\u001eY\u001e\u0012\u0003i7l@ym3\u0012b\u000ft\u001daI5\rd\u001cy\u0000\u00170˰k)=К\u001b\u0011,\u0016O_\f9\r*\u001a(\u0012[\u000b\u0012#*\u0014!^jN\rvR,\u001fI/v\u001b%CM!<xc*tpc*P<&C~dX=\u00013\u000bJYU\u000fVw@Q\u0007AeB4\u0011\u001etEux.zF\u001d(0tL$U;='ݩdH!+\u0003]VsRuC&^\u0017*pR\u00045i-h.ې4,)~@g/%!Ýf>RXV[,^w\"\fnĢ4s=&+3_\u000bHb!\t\u00133rκÙgj@\u0015gȸDK;\u0016QBT(ոQ\u0004=W_\u0017X\u000f\u00177N{\u0010j:OI[l/\u0002\u0004k\u0005\u0010M$zL\u0000\u001eI򂫧LK=п/=փ\\SpU\u0003g+\u0018a,T\u001e;_\u0002&iX`T@\u0016&\u0013RdHw;zmE]7/T[E@M\u001bD5İt:\u0001{F~U\u0015&\u0013\u0018\u0015\u0015a(|)\"OQK}OCdL^Wr@D\u00028p0\u0015\u0015=\u0000=EP=yh')J|tPԞ\f^;N\n`F\u000b\btȺ\u0000Z\r\u0012e\u0004\u000e\u001a VsF/LiAĆzjLzV>9d\u0002nrg\tD4<l\u0007k:i+߇ܫu0CA~*\u00029ذǮxIr\u001a#k}\f4V qHI=VC\u000b=p/ȣ\u001a\u0000v7g\u0014\u0010dU$ۏ\u0012Kz\u0018$uYGvhd(F\u0014\t.\u0003)=\b\u0017=]ÂjV{,Hp[7P\u0018\\\u0017{?}\u0010z][\ti@\u0016O\u000e03Vz\u000eE\u0005B<ӄr\u0003Ԧ8\u001d@\u0004-z(\"ب)XF/P<,\u001d]\u0017|r\u001ajƓ\u0016J+@ۓ55Џ\u0012k('iD5MAKv^C\tЕu#U]^dΗ\u000e\u001c^=wT\u00117\n%XN\u0014{a{\"xzN\u0005:R`*;\\߉S5bULP\n\u0006na5'k=\u0018j%zQ=Ez\"?K#wNjX\\\u000b8|\u001f\u0019o\u0000\u0005\u0006j\u001eUuᆍln0\u001b5S\"QUPjE$\u000fݡRJM<\nC\fN;USa\u0007*/Eϴt\nR\u00009$;ʔ\u0006M\fZ+SY\u001fh\r\u001aC0둪\u0010\u0007{V\u001dZtseνzZ\"\u000b\u0007BU=&&7tP\\/\u0014g{\fzwe3(&K\u0018Ozֵq0\u0012+\u0018`\u0010dn(V\b]*i_H\u0002V\u001fݩ|xcaͻ\u0019ZJz\u0001o9,\u0003\u0004Y\u001dlDlv6 6FҢV=Pr\teUNX*/d \u001eիٓ*\u0018\u0018aTg\u0010JQ0y%8J,\u0013\u0019\u0004R^r}'{պT'\\\u001f\u0014o`d\u0002,_\u001dXkŃ.\u0010#7Ձ\u000ef\fp\u00009O~~_͋޼Og\u0017w7\f˛\u0015'9x 袁\u0017Mm\fO@ۅc?\u000f@?,Y|1\u0017h1$Hv_!㪌U0L\"\f]\u0005\u000e\u001dܴ1:BP+QF<<\bAM6V@1p\u0019ϚVm)\u0000Mk+\n/1\u001aުla\u0012H\u0017{sF\u0012m\u0016AE<=2fy4u8c4WM<b1\f\u001b<\u000f\u000bf\u0007J B&\u0019*yr%Љ\u00116?fg* s_&GX\u0006\tLU\u0006AFqM4ɡ'k\u0013!\u000et\u0006\u0002\u000epAj\u0003pe\u0006cpʺ&{prP\u0014El\u0014\u000e,v&\u000e\u0007\u0003A}\u0003/f__x\u0016\u0001\u001c\u001bں\u00012\u0018g::Zl$JDA^\u001c{o>\u0015#77bL Z\u0019?\b\u001cΕse7dʰS7C51d*ǌF\b31\u001aYX%\u001c(\u0016\t\u00100\u00135/\u001ej\u0017p9\fV\t\u0000\"geV#g`<\u00032O\u0018Ltؔ1)vB3`\u0017yDy3\tLeo\u0001\r\u0011\u0007MR\u0019\u001a\bش\u0000j\bL7߄B=\u0013:\"\u0014mQy{yX<fv{r%\u00119^RaQ\u0004|uI8\u0012*T$Kr\u001b/\tvk\u0005E\u0001\u00112^Ԛn|\u001f-5D\u0000͟.o/o;>f0\t\u0013?\u001c\u0015b\r?.Z7G?.7r\u0017\u0017ۛ\u001fO\u0017M7\u0017?Gl˫\u0017w\u00177[7\u001f_]oXc~orsy_~o[m\ro\f)\nmT\u0015}q\u001b/I?>7]\u001b._\u000f,\u0007m\u001e})\u001fΏ\u001bˏ;n>:nߋoܼhS\u000ezI5\u0002W?\u001bhWo\\]ܜ_l=<ܦys\u0017\u001fǿ'&no^_{Nws3Wxs\u0003xXkj˫-pG_!ܦxjs>7@}3\u0011d{fS}uqwv{\f\u001f4]<@82\u0016>j}sw~񻻳W_o-V-1\u000f\u0012e6ox\u0002ފN\u0005\f\u0007\u0015pB\u000e*A\u0005ywYgp{Y)\u001bӓS\u00027\u001dt\u000e\u000f:A\u0007<\u0007\u001d9[ht/^\\}ً\u001f3=\u0017]pl\r,\u0014?\u001bU/.^aB[H\u001e}q^y{x7__|\u001awQ\u0018^lNL^<milN_<\u0005:Q}7co\u001fiw7\u0016^8suvwz{f\u0004mWU\u000e\u001f>*$ PAmu,LxXZ?\n7\u000eyg۬j\u0003\tkm\u0007nϣ\u0010]M]ktC^)TOZv\\[,?(˛6\u0006Vyĥ0წ&}ؒ\u001c8蓪K\u001fN\u00151\u0003ykE\u001b/o\u0010\u0004\u000bD\u001eXx!vOdsj gw__o\u0007'5u8G7!\u0013΁nv\u0002}$Kɗ\u0017w]`'O$=#q\b<82=\u0004\u001eEw\u0017\u0017؉QG[ЮK7^!\u0005eSP6\u000f؜?\r'\u001b\u001e;{qf揾\u0017Wg;xI~Q}\u001b/dߴ/o^}{u|kwԖs/\u000e@\u001e8M{r{MӶav|\"y͍\u0018ks\u0011\u0002ͮ-\bonv5>m݆žq}\u0003CC?|\u0017W\u0017h\u000f\u001f}_mlE?|EnK\u001ey\u0005\u000fCz>o\u0017_]_\\_yjxYjco^J\u0015ha.k\u0016b]q\u0015O\u000b|\tΓqH)j܀|\"vc}׉\u0016nǯXec\u0005d*6EWOp77\u001bU?y]^|\u0007O\u0014qsqq|iϿ<y'lL#G'~v\u0007ّctJT!~8q4v\u0015lof\u0004n]^^o΄\u0013i&g7[֟)Geߝ?r\b1=os7!l]iL&lf\u000b\u00177sxru\u0017897޴ρ3C̎\u0005lWG\u0016\u0007<\u001fais·o\u00108{\r-$]'}]${&pf\u000brWY\u0007lpF\u0007>h!޼':=.VE$0\u00187ó)\u0019|Yv#!p榙C!+=ӧ?<ρmD/m\u0003};з\u0003}+ۻ\u00068oϊ]L\u000f@\u000eԍAx;P\u0003u;PFno\u000bxfDn\u0014^y\t\u000fhKɗh\u001f.\u0012^?]OWg?~].F\u0003E\u001bG\u0003)~E@G_mͪ\\>Tdj\\޼xyy\bW\u0017g_lQ&c\u0013d\u001dja͝ׯPugӕS͝\r¾\u0017ܱWs9T9THH:,?m?~ٳ8DmٺͮRn\u001cg\t<\u0017\u001fWa'\f<:rpM\nV$|M\r\u0007.S]хnx3:\u000f44<\u0010{4^\na<BN\u001fOA.￿ߜ\u001f\u000fRu\u000e!\\g8-1Y?>h&\f鐅E;e\u001e>\u000f||9\u000f)y<?|\u0006\u000f3n%\u001d|λ8\u000f>y#~_\\|f7Mv0lisz+HOoohsM}KMyu(\u00172=1s!G;Mw%oI\u001b\u0001\u0012\u001fLp\u0007\u0013\u0004w0mε\u000ewxy`{\u001a!..n>mŧ]~w۫O.^|z{wv`{D\u001b[L//[F_<>\u0015,\u001b/_o\u001fx=qLY$ey\tı3_\u0014\u0006\u0017`O_8oR6O \u0014lU?`ÇO ?`);\u0016\u0007y0<!Gn\n=\u0018s\u000eƜ1`9\u0018s\u000eƜ1g79bacXvȦs0.{A`*\u000eeLkѿ4Ks<\u000fP\u000f'<x\u001c/dsl^bsl~\"\u001cOG\ry\u001e8O<Jvˇh\u0007\u0016z`\nW\nW\u0007\u0016*m9ξpCegUjc=Ty<\u001cSU?{q3xRP\u0017q5Cn\t\bs/\u001eD>\u0001mե;}Wvݾ|\u001e7Vzߨ\u001fi(\u001d\u000f\u0019+\u000br8\u00128\u001b̯6\u001f._l\u0011w%\u001f7_\u0017d揾A6n|>ˌO!2n\u000f_#\u001d\u001f<\u0017\u000b9?@C7*p0\u001c\u001fD\u000f揃c\u001fP϶Ym\u001fn/7\u000f\u00127\u0019\u001du]hCj\u0014x|>l\u00117lhvl'\u001f|qo^_{sqs\n4\u0017xs\u0003u\u0004|y\t|\u0004Pi0\u000f>=_Pi\u001e_ڂ{C-xSU_:\u0015͕\u00166_^oΙTSY,I~s훫Fx\u00037w[\u0018'\u0014\u0001i\u00073{M%.\nm\u0015Q\u00141y m~\u000fL曟nǡmC\u001407\u0014ˁq X~r\\\u001d0\u001ft\u000e:6W\u0005n5\u0016x\u0002\u001fqMZƲA\u000bܙu\u001c\u0002k $O\u000fxi\u00075\u0006n?\u001axP\u0003\u000fjA\r50>;5p\u0015\u001a_/;ۜ\u000exl\u0016J\u000ez[mxϳ|bcPac4qAe\fr[ȡ^Ǹ+z!KͶz|׉˫7;?>]0W\u0007os|v\u0003gW5Փ<}N\u0017yځJ]7\u0007oG\u000fbĎ=~p\u0007Bwmg[\u000b+HOoo^ߟ=Xo~K-\n4\\~\u0001\u001cr٣/r\bo^_l\u001f\u001d#0twMeq=Vv\u0017($_op\u0018O&j}qIiSg\u0016\u0005Ӈ06(\tܭEO\u0010r*W7\u0017\u001fÃt~\u0007<K\u000eAx:\bO//\u0016\u0012?(\u000fG\u0007\u0016{M\u001f\u000fxG灦B\u001e(4^\nB\u001eh9^\u0013ٜ*)\u0017[5O|t[g\u0019|uyˇL=\u0007\u0016z`yvn~\";B7?\u0003\u000b}B\u0016AZۮm9΁>\u001f\u000e?ã;,\u0019$ds\f_/\u001dNVU6|2>v>k]m\\a\u001f]\u0018gO\u001d6߃k\\w\u000f\\/ݠ/7H8\u0018K\u0012qоe8\u001edk/&v_q<P\u000fǻwl-:\u0002Gg\\y\u0019>xv\u001d\u000f\u0011\u0000>>s^J\u0004,^^.XQvϾ\u0016\u001b{hΨ\u0015\u0002{ss\u0011gl'ya\u0016\ft\u0001ݞ\u001e/}ā*\u000fn^i9\\]7|t\u000f\u00127\u001f׎\u0007\u0001Q4gWW;p4%\u001f0\u000fCg޼OY\u0001\u0014\u0001\u000f7j]P\u0011c\u0006~\u000fGxE}\u0004?^{{u.mGfY~8zs4\u001f~Xŗ\u001fx_\u001d\u001d;wR\r\u000bOLu~q}J\u001d\r%4Pn\u001dl#sb.I9T~H6\u000fXJXJӿO.Fb\u001d\u001dxm8yi\u0013=v\\\u0016$\u0014R=q8nBXZ%8bknIʥAI6%6@9\u0014\u0000Lɥ.Nۀb\u0012}}kO\t\u0019&h\u001bĞh\u001d \u0018ߵM)/\u0003p\u0012|4\u00029=z9=9儣0'!`mpmaI|Oruף6\u001ckxۼ]Xt\u0000o\u000bkNl\n\r\u0019j\u0016amI@\r>\rփ1aM^\u0013ck\u0018\u000eט6q\u0017NÆK1lXQmÎ5ق\u00136XM\u001f:SU D-g\u0013=\u0006,bHTM\u001b.\u0010\u0001ޅ\u0006(5׀X)h&\u0010\u0016Ծ\r#Minc_\u001bZ\u001daM}\fKȹ}\u0014S\bXVD\u0000\u0016r&KX\u0000D(\u00195\u001cnp%\u0001o?8\u001cEd\u00036n]C0FWq\nI$BͶh\u0001\"._.{oP*DOcv`\u0004{NJ\f֟\u0004g+/85'\\r1<pev J\u0004\u0010G;6d\r\u0018-n8\u0018\u000f@[1m\u000eo[\u0000l\n\u001d\u0001\n\u001c6\"F}\u0001w]M\u0016Ж\u000f,\u0006-^\u00103]l\u001a\n\u0015l\u001f\tm)hq\u0000053[};i)P#:9zG\bV-\nK1\u0015ɷ\r]c쿵\u0011%m\u001ff5l̵`f9^f;@C25`\u001a~V:jպu\ro.7t\u000e\u0017R#]s0(D1>/PGjA\\q4[[Ml'cnw\u0010lXƘx|kVr\u00043@5Ǹ2\r]n\u0014&mk\u0000\u0001\u0016imlDۈ\rHho\u0005\u001ae`!\u0015m)\u00127\rTDv\fI\n\u0018\u000ek\u0000g\u001aݔFA\u001aƝly\u0013\u001d7A6d%n\rۆ$b\u0005`1:b&\u001b\u0003M\u0011LccMՖ\u001a!rЭdn/W$\u0003\u00110+7&yz\r<]>g<+M:?Z\u001cJݗd=c`8Ԙ\u0003i44o\u001d_R\t%MJ̳m\u001enIw\u000fL0WILw\u0018_7K8F\u001c&$\n\u001b̰Qdx1A1,E5*A\trW\u001d7O&!%јA Xy\u0010\u0012o5\u0001X>ǔ\nd\u0016:A\u0018!ZJ\u000b:R\u001a~nϖq@`ɖiS]Áb\u0006+~wvEt#aK۵+ʄ\u0005}\u001bj.:RIج5}Zkʹ9Pr9M{\u000fru\\@3\u0000H\nQ\u00133%\u0002\\\t\u0016\b A,[qdc\u0012'*:Ad\u00165\u001aeVid\u0002&a>\u00151Iyv\u0010И5OQIG\u0011֮l6t\bA^\u001a\u0000[6ui;9N\u000f\u001b( D\u000eR`,ZGgK\"(bn4oc\u0013h҉-\u0006V0\u001ee)\u000e\\NdeSF$C&Aiz-Y\r\u0014\u0010\u000e\u0003\t\u0001)\u0000ݶ,\u00182M\u0012F\u001f8M\u001aMcKXjDb>@,Ж7dj\"kD<ɯ\u001a.\u0011\u0014\u0003\u0012\u000e1_y\f .@&\n&<\u0015\u0006h\u0017DW/4\u001a,fL'bM\u001f(LidLV\f|u\u0005hQS@\u0004q7І\u000b\u000bIv0\u0016x\u0012I\u0004o\u0014\u0013B+D\u0004+\u001b]E?%esF\u0014R\u0014Ym\u001f6!\u0011\u0003j\u0019j6\u001cT\rL\u0015I\u0010M\u0001F\t\u000b%oW!AԐ\u000f\rФxBSD\u0001\nTpk\u0012\u001am֔u\u001baf\u000bi\" H$c\u0018X\u0006\u0010ޓr`o\u0002\u0018@Փ\u00141و\u0014km\\TMښ\u0018\n_q\u0007\n̮lA%O0u(\rF\u0018\u0005hֱSB%H[\u001c[KD'4R\u0010.4M\u0010~}q\u000e'#:\u001e\r\u001bLW\"FԶxg2\u0006mWO\u0003\tLW^6\u0005)`jxm&DH\u0017d7މ[\t12:,\u0012jD\fO\r4\u0016#[\n$VS\\\u001d0*\u001a\b7M~X\u001dhFb1àЩ\u0011H\\b\u0001|n{WR&V729B6k`vLXĘtɧk\n湶n\u0000lF\rQS6,ѩL~\u000f$\fX9#\u0005&\u0001\u0016hܺT\u00001MM7h6e{eaɢ֧m\u0002W\"r\u0003R!Z5FH#\u0016hNXi\u0002JX\u0012B&\u000b(\u001cb@2G\f\u0005O\u000b:0\u001b+\u0011\u0013\u0004^;];\fZoA>\t\u001d6\u0011&v\u0012\u000eVҶf\n'D\u00147\u00181\u0007æP;Y\u0014\u000b\n9\u0001\u0002\u0019y\bbe#E\u0019\u0004\u001d\u0004$\u0005\f\u0007C\r\u001cZIr\u0011']\t\u001dS.#A{hC3K\u0006\u0017h\u0011U!\u0016evv%fMq\u0015\u0015fu-v\\{\u000e\u0003nCf4ـ&MD'M\u001bbtjb-K#F_\u0012N\nc\b#D\u0018\"mxMhRV]Myk\u0011\u001c\u0017̨\u001cSԑ\nְ\u001fwߒY,v\u001b\u0002Y#\tK\"q\u001eO\u0001f(\u001b\u001dJI\u0011-q7\t\u0007\u0002;?\u0015 i\\ αp\u0010.5#$w@\rp̀uN]fG3%0w\u001bT1\u0019\"=Dsfu&G\u00135\u0001B o\tYǸ\u0000\u0017,w\u001a[H\u0015WRSam8<\u0018ߓ\u0002\u0003\u0011lb\u0003km\u0011D\u0006,@Ub-h\u0019m[38|Ώ\u0014vsic\u0013Ct\u000f`|\f!\u00042O\fo&\u0006~j\u0017\u0000\u0006قH+l\u0010k&TY\u001bL$\u001amH8[\u0014,vO[&\b\u001ȁ\u0000v\u0000.\u000bL\"ʓ>\u0010$\txK6&M\u001eN4a\f\u000fqu\u0011oΐdRSdղa\u0007r 0˪jp\n)ZDava{=qL\u001d&3\n=Ge'aIImd\u0011\u0004Q\u0002\u0019a\r2\u0019\u0000`N6ƭ?u^e;y\u000byAv<J)ajhٴ»CB5\u0002P3\u0018\u00004\u0019\u0010\u0016\u0012\u0004\t\u001aࡀ\u001dD\u0016(Aqx\rm@&\u000f^NV\u0004G>T\u0011\t|\u0015`B<l\u0011V&G \tц.ib-`FkČmso\u0018h\tb#q\u0005CFt}\u001dc77:\u0013\u001b\u001dl\u0003\u0004c5\u0019\u0002Z\u0003\u0004Tصk0D\n$J\u0005S71XɅ\u0010H\u0012<Y!gQ(^FML%e\u0010XJ\u0004rʓ\u000e$z1\u0001@P\u0017VTl\b)L\u0016@|\u0013q>q\u000e$\u0019\u001e\u0019LU#+r\u001fͼM=31yȖ\u001f\u0013P\u001a뜔_F.|6\u00182\tf+\u0006oIlN\u001f\u001b2S:F($h\u001dr-\u0012O:ԅ\u0015c;=\"\u0000.ؑ\b=ZH}:'AډHHL\u000f'׷G뜴s?ez̎Fc\\^i48$?S\u0003\tBj\fX0($t,aG\u00141B\u001f'fN\u000eh<\t#AL\u000ey\u00115sВsƝzˉ-\\­\n({Cc̕)؍mU\u001b1Z\u0018y&k\u0014\f>yzeK,ݠ9ɓVFvP]4t@\u0019ءPd'B·Fi#I5\u000f0\u00025Q=A^7@ޑ_8 L>{v]\u0013]\b\u0012i{i5ܤ*b`v\u0016MN̷o8A<B(d/:Kb\u0012\u001c4L\u0011ьYb%\n;\u001cg Wh%evg\u0005\u0005vZ'\"mI;9\u0000Wj`2A\b]mcq^[\u001f평c5Y\u0014:\u0010a}\u0003A(\u0019OY;\u0004Yld'|1J\b\u001c:,\u001c\u0010\u0003\u0007F\u0000\u0005ɝEx,\u001d1\u0003l\u001f;=;s\u0005'\u0018QG!RBHj\u0011\u0006flg=dq>iۣ5q\bX˟P%4-<?czο\u0006}Ux ? \u001ff\u000bCz2l\u0018PYɰbfgMx`\u0011c=֬\u0019:L\u000fQ\u001acbI\u0012$TȔYȌ!ua\u0019Gk7f\u001d\u0010sɶ\u0018\u0012e\u0006!kcr\u0014\u0002?cX12d\u0005қ\u0006\u0002i\u001e\u000bN\u0003,ΏքaC5\u0004t<1\n\u0016̰d<|dM4\u000etm44\bY4\u0014we\u0012/1X\u0013xQD\u0002i W\u001fm\u0010\u0007\u0019!\u0014)\bI\u0003čv20ג a\u0002d'I%cpds\u001f)ނ\r`V,N2.~ :_+Y[\u001dtBۉ\b_\u0015\u0001~t\n\u000epN\u001d\u0011G$39\t\u0002A\u0002I\u00106\u0017ήa\u001c\u0011\u0015\t^\u000b@m-`\u0017#\u001b<;\u0016s\"D\u00186?)\u0002\u001f\rϙ\"?LC\u0011$0\u0013'B.\u0007$-1s҆b\u0011#\u00100؆\u0000\r\u0018\noA\f\u000ev4M\"\u0013\u0019)\bEfs]\u0016ȱə]i\b(\u0002Hw\u0001k461P\u0005\u0010\u0001'w!lv\u0003\u0002@v-ȋ\r#q\u0003I\u001cN\u0002\u0005\u0018exbQ)/\u0004jX\u000f>\"\\2AD\u0004!ꞕf&N0K1.6KM\bj\u001cg͑r\u0010 \u0011KC\u0005s;{StT7 lę\u0006\u00131;Z7\u0005$Mx\u0004\"\u0010IPM!\u0010\u000f49jC7\u0006{\"16;5\rE\u001baݞ`ķ-mU\u001a`i\u0005\u0010ypn$byLk\u0010\u0014ifhzks.\u0014'\"\u0014Ķi\u0010\u00140Y\u0018$>i$h\u0016e4D:H(i-N\u0007O!-(x1\u0006,%1'n\u001f\u0019f0b)\u000e\\hr\u000ee@!I1\u0004=(\u001d@\u0007rNx)~|$i]T,`h\u0012h\u001a3\"\u0003\u0001bM\bWd}\n(/q0m1d\u0002\u0010i$KH{|Lv\u0010LU(J\u0015\fzpQT1.A\u0014I8N\u0002[6L\u001fɫ`X\u0018)3S\u001e\u00041\u0018i\u0015'KSH*ƛqljD,dmr\u001f\u001d5l+YH5.EP8\u0006]2b\u000bX=yNϜ\u0010%Y\u0006\u00077He\u001euE\u0014l\u00125ݚwy.\b'Ȫ*\u001a0\u0015 -S=ZpRr\u0004-4\u0000P\u00112z!SIΤ\u0003DXU\u0004\u0018r\u001c\u0001J\f\u001dOعDR4\fM\t\r/TV6MV\"\u0005}~\u0007(4l\ru݉\u0015\n9J >BA^h/\u001bϑfŔ6'#\u000b$l\u0016>pMȉjl(Å!9ݩAYVXds;Dqp\nP-\rHFEClo4U#nhl&+unxY4|f\u0003klI\u0010e!\u0003\u001c*\u0001\f߄L8\u0010\u0002q[\b%+4t\u00145\u0000\u0011&\u00018j\u0016guBD\u0005\u001c\u0002$\u0015Q*le85D4yvVff??Z\u0016L\tNC\u0011R,*(xUᐉ2\u0018ꐾT)/P\u001bAHN\u0006'=Z\u0013\u0012$;\u0002\u0015t9; \u0005\u0017vvQl\b\u0002R)2\"z`^\u000fQJؠ;\u001b\r\b>ּ\u0018䈄6FUN.qm\u001dN3C\u001e\tq:$T8\u0012x~.q\u001a8<PNwG\u001amd3uwǾ\u0019܍rmHG6=TSql%\u001fT\u0014e\u001aL2ϏI9BNK$\u0001L`_\n\fFNݵr\u0004N\u0004N\u001c,Ē¨V0A0N:u\u0018\u001aH/0J\u0002@\u001eP\"F\\܈F\u0007݈{0c#8OQq@\u0002\u0017?T;\b\u001c\b\u0019@\u0007/5*V\u0006B*D '|\u0012)\u0016:ل.S$\u0014BQ:\r6,EPZ\u0001}ɘ\u0000*\t+\u0012PͷG`PI(l>J0\b\u000eۼ0^#\u001a]\rd\u001bG4\bE:\u000fִ&f\u001ac3\u000b\u0005ꜷ[,aa\u0016zPaHd\nM U\u000e)@&\n1(\u0018@XR&Q&`=(H5,\u0017H\u0015d\nkL}\u00027Gv\u0005xFF23dBB\u001a\u0006l؂\u0014ƕ\u001fXYi\u0014֜Wh4!宔yt<u]$R\u0011M\u0019g񎳘s۱!֋}\u0012\u0011gE\u001a5\tAG0Y $X\"V\u0003f!g3āNvՓ\u00137\u00029PRCC \u0015NI|,\u0002k]ֺ`y4>hM\u0018<g\u001a\u000eDQD[\u0011\u0010\ny\u000b%w\u0016\u0019BMG1&\u0007\u0019\u001bI\"\"|4Y\u0002|Xy,*Q*4\u001d6,:WI>wO\u001cW׹`W}Cd\u000f:z&(1b r\"\u000b\u001fC\u00113\bF3o\u0016Hs\u0004:9\f~j珦AO\u001f5Y:S)%!\"\u001fF\u0000S\u000b4JƎjˤPF_3P$|\u0014sjO&ob\"XشVm,t8ObaW<т,sÂ\u0004\u0018\u001f։\u0001\u0003֨Yrj,hj\u0012:Zk6\u0016f\u0007H\u0013 K\fS4\u0011`Ug&VO\t=VdnFT+\u0010tV\u00153I\u0006\u001e\u0016\u0016\u001a\u0019\u00176\u0015Ϗ\u0002T^\u001dITXIF&+Kg&<M\u0013VS(\u0013\bCA\t\u0012j\u0014Ю00ŵY\u0001iUa\t!#\bc:2$Y|\u001956\u0012\u0003&!ش\u0019$&s*v\u0019t\u0012Xa\u0004H&h=Eol\\\u00025p\u0019s\u0013[B7)B(}\u0011FdQ,`D\f\u0004zkG\u0016\u0018%(}P*\u000eE2Έ1T\u0001i?\u0015B,\rK\nud=\u0014\u0012zͤ$d\u0012\u0013S\u0018\f\u0002\u0000O[\u0004PMrCh=\u00020Hr^K\u0002\u0015B\u001aYr\rRcKnET\u0010>0Oc+.FHXY32pZ\u001f&I<\u0016ȕ$\u001cY\u0002D\f\u001f\"jS!~$X:as2Xl$ *ήq_\u0011t5&\u0012e\u0004\"b%[\u0013|\u001b%V8\u0010\u001c^2g%\u000e1\u0014v\u000bO<\u0007-g\n/GTQZ|K&6^j(\u0011t\u001a\u000ePTE\u0012i\u0012ј(\u0004Gab\u001eAˮ\u000e\u0000\u0014\u000fB\u0007J86lBHl!QC?jtC\\!@$\u0005j'%3@y>\u001d\u0013~&+J\u001a*2\u0014$\u0010ƊiLCg\u0014\u001dDd8uKI\u0001^(\u0019ʩI}\n![o\u001byI\u0007\f\u0010en)g>)\bl&!:ᡣɚh~\u0004 !\u0014xc1r)؈#v94_\u0001._\\bAI\u0004чUfL\u001aO\u0006S\bL\u0004{Tʲ~\u0004*\u0018\t5@+m=/gc15*t\"QA\u001c{pj4\u0000$(&C\u0011cH\u001c}׎0\u0001h3P\u0010$A\u000bl\u0010\ne\u0011\u001b1c.a+z>\u001eQkǦ99\u0014\u001b\u001ciF(\fK\u000e\u0017u&vEf3x 6?f:rͨK\u000e\u0012x!\b\nLc;vN\\Ģs,w`ibuNX\u0019Wf)I-MF\u0013,.V(='RAHl?\u0006yчJ_GiTJ\u000bW\f\t5-@\bHʷ\u001cZY1\u0011\b%;\u0006\u0005\u0011W>Vr>\"M\u0003\u000e&6rZ\u0015\u0007TZ \u0001h#\u0018\u00063qT*(Uy\u0005DgF^·9Xag@c%F6n2~\f1G|\u001bixLE \u0019\u0003Y5rM\u0004\u0011ˡ1YM\u0005ZvV!k]R@\u0019([rf\u0000\u001c%ۂ[#4w\fi䄴\u0011JhX<ǆZѥ@+lˡ\u0013\u0003\u0014Nr\u0007PF-nao_\u0019E*_~o>_)\u001fo>mm\\{M_]9xw\u0017+\u00156w\u0017fz0p~\u0018\u001b5ir_Vjo\u0013\u0007TQ\t\u0005\u001dO>\u000fA/\fLZUN;?Q'ui\u0006\n}nϿm_nPD⻻\u0017\u00177~M\u001bSGKϿ;\u000e,\u0015(E^\u0001p\u0016R\f\u0015XZziӈR\r>?\u001f}r\u001c5\u0013\u0000O*\u0012;O\tJqN=I\"T'[)\u0015\rR\u0002\u0011͚gh0rT\u0014C\u001c@!<-0\u000eg0Ю0\u001d?vǊw8q\u0005\u000b_\u0003hJ+xw\u001eĦ)1dEq]р?BJ\u0006J\u0013\u0004Z\r\u0004~\u0004]xGh>4bC|پ\fת\u001bxY\u0016\u000fVy9=&O^\u0001e$\u0003:P\u0011{q8y8Mx6JN\u0002\\\u001f˚+5\u0015G9>=^Fcz{ed5NDWvA{\u0015\u0004,Aq\n)(\u0012\u001eg)F^W\u00036\u0004\u00021|<\u000e\u0002L\u0014_\rV9wf\u0007&K7\u001fv7\u001f\u0001\u0006l\u001b<n,~Uk{tvqw\u001b<7/%_}\u000fU\u001b呣u?ݞ_~i0WS\u0015lPe8s\u0010͡he μJ\\HX++if\u0002\u001c3d\ni\u001fEBm?\u001aCNNv5\u000e%j\u0019}G]Kl?u=\u0006|\u0014\u0019N\u000b.u:~:ߗ;%\r\u0005UI!\u000bDb\u0011\u000f\ba^5渦ǪJ>H\u000ea\":#pTՈ|@ST\u0013.(yM5MV\u001c\u001fA5<u/*\u001c&~ jIqD_\u000f\r.i4@`8'2P5#\u0011-L|׫3|/m+\u000b\u00059^wBgE(rI\u001fQ(\\\u0012e6DŢ6\u001bqÆHJqSAOLpS\u0015v\u000e\u0004l\u001bP\rD.J<t\u001c*LA%\u0012Brfz\u0018\u000e;)\u0002G3c)Z\u0018LWd\u000f\u0014;դ\u0010zR(Sٷ1_$''NԊ\u0015?Z\u0003\u0001Nˌ\u001c\u001bD\u001f!5\u000b£z6t\u0000]{MtA#U/\\mT^j^\u0010v|\u0001b,Ns\u0004:\u001e`\u0013\u001c?\u0010ǝԁۦU|ɹ\u0005WP)e\tO-\u0002\"b\u0014*o\u000b\u00102\b\u0010*'QCphR@H`\t^JN\\\rʪ,\u0016.\u0018HZ9#Rƕ\n&D,\u001a\bQ\u0000 $\nTܕD\u0001H2(\u000b*\u0014e)$ #$(\u0017=E\\\u0000/ 7LIo\u0015Niasl%\u0014У\t!/P\u001f6$p\u0010r5|)j\u0000!f\u0015sw\u0010\u000b/T&9*)*\u0017\u0007\u0001ľEcXᲠ\u0007K\u0017Oe?(\u0001\u0010}\t.I,R\u0012\u0011`[\u0011 z+s9\u001dRt\u00177\u0017<\u001fq\u001cWɎY*tA\u0002\fz\n\u001brf~;x-\u001c\r2>Xp^O\u0010\u001ev~34gߟŗg󋗷wrq?ֶlv;\u001b\u0011\u0001'\u001c\u0018PP5QGm\u000b\u00157eDRsՒ4@WC))ڥz6MBCk{Oא,D7Iߋ˨N$t\u0010[[(\u0007\u0014#!TjEb\u001e^C6E\u001e\u0012):^\u001cR񾰋^\u001fAV4^\u000b\"Ga2H}\u001d*A[~pz\u0017.mi}{K\u0014\u0005CU|g!IC*G\u001f\\*RdwGMPD\u0001Q\u001aH5j\u0004Um4z§R<\u0017\u001b\u0011\u00169DFq \u0005HC9ZC@>\u001cXB\u0002B~W)\u000by\u000b22?T\u001d/AR3W/\u001dǇcj#5ʙDV7|-\\\u0001bxD7DJ)\u0004Q\u0010\u0005R\u0017\u0005ya\u0017}\u0007Dr\u001a\rm\u0000\\ב\u0010h\u0011<P?\u0007W\u0012QVF\u001a-C\u0012\r\u00196fD\u0015q6\u0015oD\u0012#\tA<\u0011ߎȷ\u000ft~G\u000fƂ0\u000fNDo)\n%\u0015+p\u0006riGF}؂tx<~FR\u0015䜠^GAD G\u0004\u001c\"$r\u0006\u00054\u0006*\u001b\feh2%\u0003\u00155_1\u0005w\u000f\u0011{ӶͶ\u000ff\"4֥D\u001c\u0015OeӴxot>\u0010x\nFQ\u0007\u000e^szY\rR\u001cү+)yJm[v7`|->\u0015\u000bW .f\u0007|ĳ\u0002.3\u0005Jwye*H\u0015,%'y\u0005\u0002\u0015\u001d<B&L݁:RYqN\u0006%;niXOG\u0019PeHH\u0002q\u0019%)ҖpPIVA7(\u001dP\u0007X*4\u000bh\u0019+Ts\u0012Q6rqB|\t}LT)\u001bU\u000fZX3$x\u0007u$]\u0018H68\\1}OFx~\u0016?\u001a\u001fPi{i<]F3\u001d\u0000yOah\u001e%\u000bM\u0011\b&8\"+^\u0017V򜁆c]D\nPL\u001eVT2#i\u0013R?b.9}d;AG5\nݠ2'FP\u00059\"\u001e\u0011:\u0018*ƯI!O\u0006\u0005\u0002\nb`yސ@\u001cc_\u0000Ӑ#\u001aN\trP\u001fK亟!\u000b}\u001eIv0>6\u0015~C\u0002^>D,\u0011kn,qx\u0003e>3?E\u0011\u0006၊\u0017\u0014\u0016B\u0013 \u000bzMC\u0007u8\u0019\u0015$\u0006Í#^z\u000e\u0001l\u001aG>p+XDA.\u0000\u0015\nx*\u001f5Q\tMU3|8N\u0014ոLBHKB(nRy\u0005mS#Z\\\u0001x\u00161I\u000b\u00048i1\br\u0000i)\u0018(C\u0011T3e!\u0000\u001bs\u0003\u001090\\'\"\u0010\u000fH+\u0019F\bL@E\u0006\u000bs\u0005r$'\b\u001dN\n\u00164\u0014cuJKԮ7\u0006RO\u0014qM2gL\u0012镙8W7H\u000fd.0\fd\u001c\ne1`n \u0014/2\u001eWO\u0010 3q!̨Z\u001a`\u0005J[|C}\u001d\u00148:X\u0018dL\u0003!t\u0014<,9QQB>A\u001ax\u0002\u0019\u001f\u0014\u000er\n^O\u0014z+Y\u0012PJ_.RFr,\u0018Ģ\u001aY&x\"\"&1i\u0006/z$w@mea~E<3ǢʾLj\u0003HlW\u001dCoHʐj)c\u0003\u001aB+0Q=\u0012Ki\u0016:oIoC\u0015V7ߛΖ\u0005C\t!b\bz\u0012\u0018#1\u001boHx%dA\u0015\th\u0018 eD\b,*9Z6N@,Z)*4\u0013?Ir=,tH\\.`\fX<Fd\n'_\u000bX$SkFEb1\u001c\u0005(\r\u0003E'!E/AMGko^\b\\\u000f\u0017I\bT1\"o\u0004\u0019c*`(;\u0004UPņ˔̥y,.W{baK?,@/z-\u0017\u0002\u0012(̉YN$Tƥd^Rـ`艏<:\u0019Éi3K.+6\u001eǲr,}\u0003\u001aBT~z(hĲ\u001e+X\u001c*pyHK)u$'*\t{\u0013\u0013 ^\"XoȢ( !2N\u001a04\\ٱ\u0012bWeMϤ#nÓ\u001fmm\f\u0015\re,\u0014_Y˭J$C\u0015UR>*)pfhҬ\u0007\u0002\u001d\u0004D\nY1@\\@1q&>\u0007X$\u0019$RBaIeFH\u000eϖ\be_^5\u0003TIKӶ\u001c2p\ndfe\u0011b6zV\u001f\u000e\\l0EJ\u0019d\nC\u0013qfEuP\u0013\u0003r@VF\u00163#l\f\u0013ace\u000eF{S@ȇ$l\u0017\u0011\rTJCqz\fcQGK\"L̾'8PC?4S\u0013}\u0015! s(T\u0001\u001b6rYĘ\u0019\u000e&{\u0004\u0012\nQ\u0015ȅs8.H+\u0004\u001dY!ѝ*Hy:\u0018Xj\\\n}W!\u001e[9-Nb\u001eEʲG~<\n6\u001b\u0003_\u000eZP0VU2dE\fbB,\tT\u001e+_4\tlUӲRo}PoXH\u001bb{\u000e鬰szL\u0006\u0012\f\u0002T5*?ʙ\u000f\u000bHm\u000f`|v59 XJ9M>bC}\u001a;L\u001c\\F:I\u0006\tl\"<D^2\u001e\u0001P\u000eխ\u00112j(basL\u0016|əYFq \u0004REd/灪l\u000fdzsTUEX\u0013?\f)\u0019U\u0011,\u0017zU$\u0007:\u001fYIj'}Ë;&:J\u0017qx*@W\f+\u0019&[\u001cf\u000f4R^f!1-((\u0016|sA=[j\u0018e6l+lׅ|UH\u001d,2;\"S'\tLW[r|ힵiǦ{5Gm;ӓ\u000e\u0001\u000fv{ҳ/nk=Ǧj663֫J⇹Glz?^/'?\\__]__8\u0000%wӴ-c\u0016r\r5d\u001c~]ǡэ\u0014\bM\\n\u000fȏ)=C|_U__GǤ[Q1tWP\u0013\u0006?5h,6ِ+3ᅑ˰K!O\fί`c\u001f<URk5.L\fN\u0007׾WG\u0006\u001fQŔ;\u0000a\u0010\u0010腒&w\u000eep\u0012yp{uDj0\u000f\u0019LJpUT̡茄\u001cw\u000e\u001edpoޮ\u0007o\u000bG&h\u0012MMD\u001bյ\u0019<v@8? hD[W\u001c\u0006\u00144ڟp\u001b\nuyIm\u0007|\u001b\rW~#7fJP\u000eSΑ3<ڀj}8\u000f\rmH\u0005\u000e6iZj\u000f\b\u0004}\u0013$\u001c1\u0001\u001dﳿ*In\u0003af};\u000bZgnUA1$֠\u000f)_xA#\u001aZ\u0014C0\u001dŗÞbdU#p1\r2d\u0018\u001e~2\u0003RF\n\u0007J\u0007;\t\u0003\u001b\u0014\u0005\r\u0010^E/Q\tfxX&\u001fc_Yclߢ)V\u0017СGB߁l3\u0004Mg*\u0006ñO@R\u0000$\u0000\n\u0010\f4^_bD\u0000\u0006(qʳG ,\u0005\u0006 YTbJt;0MQo$t=\u000f%j8]Kmdw\u0011E#\bi)-\u0002\u0004\bw\u0002_\u0000(g#( \u0010E38ٛ\u0004Hj9E\u0000Q]Xݐ\u0001sɢN\u0015A\u0001\u0007RV\u0004Bё\u0015|h9\u0011\u0019L;LGCP\u00062*&!dDJ\u0000(B\u00032\u0014\u0014s+n\n׊\u0005\u0004ő\u001e5\u001aИ?*T\u00042{\u000e)1\u0000$bA)$vt8DAJݣe6qHP|\u0001}\u0002sa\u0013\u0007\u0004ɚ\u0003\u0005}\u0007;\u0003<\u0012\u001ap\u0000\u0012&\u0014S\rQ@m%I'Nd\tH2v\u0010f\tXUT\u0012\u0007l0\u0015`\u0004 9\u0000\u000ego\u0015&\u0002r\u0011\u0010`\u0015\u0018-D\u0014Ro>G\u0004\\A2J\u0010\u0000bG\u000b\u0004\r\n|,\u000bmV\u0003\u0019,arYu/\u0002\u000b4\u0012;\u0003BK\u0016%aof)*-00\r:VA2K\u0002,S\u001fR7XWE=\u000fto2U\u0001\u0013D\\\u0000qS\u0004\u0017i=e@\u0006\u000f\u0012N\u0018\u001dG{@t\n\u0015&Jӗ\u001c\n$cTO]\u0010\u0005\u001a(QR|Js\f̨\\NFX\u0007\\tO `\u0006F ^\u001c_\u0013a*?acՐ&\u0017\u001ar\u0018Ψ.r\u000fCy\n1_z2.\u001eڄP\u001c\u0012`8ÏPjIVN\tc+#hi\u0000\u000b؄V0p~4\t¿\u0014YU-HSU]\u0003O[M\u0000Bs\u001baQM\u0010O\u0012^Y\u0011(\fmP%\t$E\u0001Yr\tPOE`\u0019\u0014!\f\u0018\u0000JB.!Q1\u000b\t\u001b-, mL\u0003aT\u0017\u0015@xq\"\u001e\u0013}rUpN R \u0000D\u0001mH|(\u0001\u0019c?\u0001\r@N\r\u0006\u00180\u0000iʔ\u0018*{I\u0001h\u0007e>\u0015\t\u0003 \u0006\u0019\u0013\b\u0019ؘ@\u001c\u0002\u0000\u0000\nK|\u0002@ҷ\u001c9\u001c\u0000\u001b\u0011g\u0000qC1g\u0005\u0019$\u0013AY4y>8\f4\u0011\u0016%Ғ\u0001\u0006aPYz\\v\u000br\u0000\u0003#RИiT\b\u0011bF\u0003ps\u00108-,\u001fcI\b}r5F\\\r9\u0011y\u0003d\u001a}d(\rKC;(3 Gg\u0013mYh)4t\u0001q*\u0018\u000e êȏj@SEuS8i\r+֎E,3sC^<8+5\u0012\u0013=\u0002ѥ\u0007JtQ\u0012Fn3\u0000\u0005z摫*\r(\u0000\rAg^BP\u0018\f\"\u001bAxkh:\u0002dعdVko68+v\b*-B#\u00110\u000fƅC w\u0003\u0012&=B;\u0004JPHp\tvRgY{Drf\u0010\u0000|\t2\u0014S\u001e`ļ4HV\u0011\u0018\u0019\u0002bLX'\u0005Y6\u00025;42L\u000fF\r.ӋA\naUz\r\t\u0017\u00023g>\u0005H\u0013QeD\u0006A\u001fh!(>\u0015@\u0004ـHm%E1X˅\u001c9L\u001aD4D'tJ\u0016\u0010Wie1 1៞\u000f0aaiש\u0000l\u001bѐD9\u0003$\u0010\u0000Č\\\u0014ĘK1 ӄ\tb]\u0004YV\u001c\u0002=\u001di;5(*t֢'s\bQ\u0001%2L\u0016ˤ\u0018AmgP-\t\u0014}2CTD$3\u0016Zww倘s/\u0013&37]`p\u0004VAM\u001d\u0016\u0006X\u0000\u0003d\u001f\u001e\u0001<\u0015\u0002uC\u0016\u0018a[\r$r&\f)B\u0010\u0016$T\rV\u0000+(\u0005:8>\u0003r8`\u0002\f$Φ@TC!\u0000jt\f\u0018DOώ\r\u0013\u0004S\u001e,\u0002nX\u000f@\u0010C\u0005\u0007=\u000418fvu\u0018}{jMo\tٕ\u0004hw\u000fX{L\u001993g9\u0013#&uyA[\u001e\t\u0018(\f0kd¶4ji\u0016\u001805AvbOdVSE9w\u0000\nԞ W9@K\u0005\u00001bȯ\u0002Fr\u0010OY9\u0010(Z\u0007\f{\u0001y4#7JKZ4bTP\u0016\u0002\\Ҷ\u001crAή$@{dYٙ\u0013\u0013qN\u0014(g.FapQ`P\u0002\u0013jeqVTG?:XMA0\b=d&3Yv\u0011TWeXƷ\u0011:\u00009O\u00070}\u001dW\u0000\u001bʥ\u0015&B\u0018A+\fRzc\u0012غ \u001av3Q+2 \fIg&g\u0015\u000b=y\u0018ʅO\u0002pܺ;8\rja.:\u001c\u0019OOLлe\u0000%>1\u0000 7c*'DL qI\tP`\u0004'&N\u000fD&\t]\u0001O\fͣ}M\u0018\u0003G\u0013ǙvtH0\tmUY\u0018d\u001bt^'\u0006fg|bT\u0013\u0018ӅV\u00133\u0018OL\u0014(=\u001cQ(\u0002FF:͞\u001b_S\u0019\u0010~*)7ݎJ\u0010\u0006\tq:񉁻ԏ\u0006\u0010\u001a:s'fAQ\u0013s`'I\u0004\u0019\u0018z\u0004\u0012~\u0001@\u0013C$f|]fEi\r\u001a{vQ]&\u0002Y^\u0014\u000f@'&4\u0005o\f\u001c!\n28\u0011߀PT\u0004\u0019\u0001JD'&\u001a\u0000 n\u0018h\u0003@2\u0011H\u0003\tzʃۤ}]\u0001K@\u0016(ӎSͪ޸'&QG'\u0006ꩠ-1>1\u0017d}b\u000eDA\r>1\u0006'~\"5l\u0001!^\u0000b\t\n\u0000>1MꛈO\f\u0018\u0011>\tJ@\u0013LS\".I\u0016d\rSt9BR;SkVzOLxd\u00052>1\u0007,0>1p\u000bOLj\r/pl'L\u001b ZƖڮ\b rh\u0013N;E\bdzg'&\u00189_1\u0018+\u0010\u000b\u0012c8)M\"\u0014Hzv\n\u0003r<;6;v<;\n\u0017m@(#N G\\R+gC\u0014NЏ>\u0006hbu\u001cDc. ñx@s\",\t1\u000b\u0016#\u0017MkTTw2qGfa\u0004\u0010hi1)\u0010\u0000f?F\u0003ҟkf\u0003PAF7&G|G\u001e\u0000ɥm\u0004lC\u001cI1B\u0010F\u0005\u0003wƷuM5о\u001d\u0005\u0007\b_^*\bfbn\u001aQʷC\u0000\r\u001a\u0013\u000e>s\u001d/M%QU83w\f[Id=İuh\u0013\u0003\u00183\u00047\u0019\t\u0003{\u0017c>\u0001U!)G\u0018 P\u0014\u0011w\u0007twǧz\b\u001e\u0014?\u0011\u0011\u0012\tȬG.֧a6>M@F3t=i\u000bкa\b\u001a'gFIfGql\u0006U\u001c\"fHaP:a\u001eEh5r\r\u0015\u0013'\r\u001eX>ƿ\u001c\u0004PgP\u0019,Q>l/\u0006\u0005TnкAV\tzE~,b;\u001a>}\u0016\u001d>n̅03 ׿\u0000\u001aF\u0011[\u000eQ0C\u0004woj3\u0004$wUapZ\n\u0001Py,Ϲ@4\u0007C\u0014\u0001re\u001b\u0016n|w\u0012ް@kcY%\u001dJWb\u0004@X9\fWJqk{T\u001c\u0006Dv?ƼIQF \u0019Aѡ8#`C\u0018\u0012rP;q\u0018i&(*\u001cF+`\u001c|J)lN))X\u0019H*\"`JYk1h\beղ6\u0012G\u0018͟w7٘6~ȎF&CGv2@B\u0000Z_\u000f\u001d]\tm\u0000y\u001dt;\nP\u0000\u0018[\u000b\n\u0013>\rSF*-\u0018_!\u0010\u0006uް0u1|t|\u0005¤'0k\u0017\u0006O-^[\n\u0001\u0014)\"ӫ!\u0016:=B\u0014r\u001bUSHf\u0003P-UW\u0000\u0001B\n\u0004H t\u0002ȒQV.5!˨\u0003(!\u0016\u0012y\u00034#ƨ7#;\n]\u0002@\u000ek\u000f\u0002\u0005)YF\u00055\u0013A31@Ǒ\u001b\fA88\u0015ǝv\u000e\u0000\u000b\u0007Nx\u0005\u0018,\"Te\u0001dx\u0014\u0010۞\"\u001e\"e5 #`\u0000YW0\u0015\u0005C)Y \u0015\u0019D\u0015Ȏ7\u00103?\u0001deGx#)t;-I\u0010\u0004AFaBx\u0016?皙v7N\b\u001cQ\u0016tB\u000ewv̬A[\u000e82 Vc_7#M/`\u0015^ zv\u0013XUQЦ\u0002盘EH\u001cG<\u0013Ȏ.\"\u00034'ST\u0007EaP?ʠ2L)G\u0004L]\fxYVAE:WMbnqr[\u00101q/\u0002r6ha`eG\u0007n@\u0002Gj\u000fCBP,2L\u0001(N*c)Jfh=OSDY,Zwȼ\u001a\u00179\u0000yk4\u0006f\u001amOX\u000b\u0005j&[a|\u0019^\u001d=(WH\u000e\u0003rحR)^m˫~g\u00138\u0000'\rNb~\u001c\u00022bij\u0010ـXQJ\u0000s}\u0006_':pp\u0006s3\u0005\u00135\u0019J,!\u001a%\u00019F\u0016\u000b4~\u00147,v\u001e\u00152\u0003kP˱0aV$\u000fvV\u0011O\ra;\u0015t!c9T\b\u0005Hc[\u0012\u001c=y\u001cy:\u00101:.\u0003D\u0006G\u0004n&`\u0011\t]\u0016&\n\u0003D\u0010c\u001a5E`$(J?}<\u0000#\u0001V Ȃd\u0012\u001e\u0000#\u0013\u001eK~J%e5#\n3J̺:+XcMwv\u0011k\u000fF(1Us\u0013\u00073PZ\u0013kT2@f\u0010^9{l^OfǑ9Y?\u0011\u0010dU\u0006) ,Bs\u000fLby)L6NR\\ FMF&W^j~5\u000e&֋ӻKj\u0019\n\"2\u0005\u00155$\u0018Kq\u000e)\b\u00011\u001e\u0012o!`y+G\u0016cvp\u0005]qz\u001e;&gΜ\u0019X3Ԃ\u001by)g\u0003\\\u001a\u0003\nYKҬZPP1%RC@4\u000f\u0004W\u0007f\u0007\"=0qk;W~%O\u001f\u001fOᇅpL\u000b=.\\f]|&܅˞p\u0017.{]|&%3˄p\u001beO\u000b=.\\>\u0013eO\u000b=.ű\u0013p\u001bk`&܅l\u000bτp\u0013eO\u000bjs\u0010\fw'܅˞p\u0017.\twIC'\u0005-\u001d]\tw'܅g]\tw'܅g]\tw'܅g]R(܅˞p\u0017.\tw'܅˞p\u0017.z]\tw'܅g]\tw'ŀ\u0006{vڙp\u0017.z]\u0004܄p\u0013EO\u000b\u0017τp\u0013EO\u000b\u0017τp\u0013EO\u0001Y\u000fL;\nw!rzz]\tw'܅g]\tw'܅ES\u000b\u0017=. S\u000b\u0017τp\u0013EO\u000b\u0017τp\u0013p\u0017?\u0013jGnQ.z]Rk5.\\p\u00133.\\p\u00133.\\p\u00133.\\p\rwp\u0017.{]\twp\u0017O<\u001bT UN)*`\u0014n.zwT;\u0017Ϩ$\u0005HU߹xF}\u0007`F}GL\u0006R\r0>&=5\u0004L٨\u001cPl[V}OmQߝ1{\u0010I}7n\f\u0010'\u001b\u0003SJ}\u0002CF3;ޔnlX)\u001d\u0019\u001dXF}G3YV}\u0007`F}kV\u0001ԣ4Vrw\u0003*gvW}\u0002\u000b\u001e\u001dM8Hڴ\u0015\u0017Qߝ=6{,Qߝ5\u00019{\n)\u000edG}ϴ$)0\u000b\f03\u0016MdY\u0007qzI-OJ\u0002Qq;EZ}7zJJ}O]CV}\u0014)1k\u0006HӣQq\"˪%jS.G}wv-]V}wN'W}Ϡ\u0005iF\u0002{w\u0003{\u0010qJ\"*\u0012R\tĘ\u0003PI\u0012\u0013P>C\u0014AlY%9I<$*Ct?9\u001f\u0010\u0004!r\u0003a j@BNh,\"\r\u001aԤVȍ}zEI i\u0014R(\u001c\u0000{3.<\u0018'}ݝॖ!;yl\\q\tj\u000ehF,Z56T\u001f\u001aQŰ$v\u0012T0Bl\u0002MJZ%1jRga\u001b\u0011\u0006O\u0005\u0003\td\u001dB$\b\u00184T;J|K\u001d\u0002\u001a<\u0000))୙ŷ\u001az,\b\u001aX̊뵒\u0010\u000bDƙ\u0016\u0007[Kp\u0015QcF3\u0007_M' Mv\u0005\b5x\u001bLj!U\u0003\u0019vNk\u0016\u0013\rށ\u0019\r>Ϗ\u0014\u0003L\u0010r([\r>:fx$V5\u0011\u0003\u001dmxʭ\u001bO\u0000d\u0010D\u0001d5xj\u0012\u001f\u001a\u0019ۨ؋\u0001yVO0}`0GpKp\u001b@2q\u001c\u0003@C(\u0002iV3\u0007\u0004dt>FT368L\u001c\u0000_\u001e1P ;@Cof\u0006\u000f꩹ZDƭ\u0006/\u000bȨRGbY(i\tZS̐U߮2껤z8\b;\u0016\u001a]!_3yf\u0004Pd\u0010|ߪS\u0016\nI5\u0018=(D\u0012\u0002}\u0007T\u0001WPPu\"4섅зܨ\u0016\u0000r@$\u00134: T#\"\u0017X\u000b0̪R۸owirV}ϲՔ.t\t㩈C]\\OE\u001czq\fDhc\u0002IE-1JR=7XLOy(_\u0001\u001a=\b\u0001\nCF\t]Y:\u000f\u0019%ten\u001e2yw\tȉM6\u000f\u0019<&n\u0005 ,afBqaTCF\u0006d6 g!\u000b1\u0000$ↄ:@17\u0015\u0016 lT}bU\u001d\u0001D\\m\u0000Ld%\u0002ϣ\t\u0002f>qZ\u0004tӉ\u0019J*Г\u0006kvD\u001cb\u0002w\bt\n'zLTO\t,ȍ8L6T7ƝC\nQg<\u0015q\fM\"\u000e\u0019+Ua<e5*0\u000b,wvt.2T\\d<8 \u0007n.2]u\u001fFEcLx\u0003\u0006m\tNP\u001fd\u001bedldVIfG7f#3ሩld\u0011]\\$,wJL\u0018\u0011DhiF)F:\u001bQ\u0013Z`P\u0005^\u00059He\t\u0019AQCS\u001cHgP>l/\u0006~S*\"\u000e'D\u001c&F\u001cҢcS\u0012qhAna\u0002:\u0018Yp\u001c\"\u0005)\u000byU*ӷ\ndsSF\u0000\b\u0015q,˄ϥtI!ca\u0007tm@8^Na\u0002rC,\u001c2Y$A/\"a*LM\u001bsőVmؠ\u0017X;|\u000bFF0!\u001b\\=y ~>U\u0018Z\"`гԔ\u0018BS\u001b\u0015lR1\u0011ӂk\u000f\\\u0003r\u0006$o\"ӂ\u0007\"Ha!\u001ak\u0012E\u0002r\u0016\u00168-lox\n\u0019\u0002ν:1jR\u001bFR\u001bF%g\bxMI봠fΔ},^Z\u0003re\u0004he\n[\"y?$\u0014&DV\u0007)y3,}IqԩK\u0000]\u0005y\u0012QwL#p\nH\u001cw\f\u0014\u000eL>]\u00043*Y3A10[KRb`N@9\u0001F&\u0015K\t\u0002\u001fea]6\u0017+ΦDk2XR@3\":ן\u001b]ѽ\u001cWj9\u00019\u0006\u0004h\ȓ{b`&WX,\u001406º>3ݩrwiAZ\fRCuĨe3xX\u0007H1;;\nҫ\u0015*RԞ$ g\u0012&-DdzJuYƳ'kא?eJa\u0014H^(\u0019\u0017qp6;\f;\u000e\u000bFh\u0015$61\rv\u0005=qzޒ\u001d'aW\"\u0011Sed-S\nx\u0017%+\u001cKLκ+BC\u0019r(t\u00171\u0019!PT\u0007j%!?S\u001bĝ<I\nu+\b\u001ea\u0004_~Pο6\u001f\u0010H}cJ!SZ\u000b)\u000b%\u0018[Ƅ\u00197ddV/\r$խ׵\u0011Q\u0004\u000e\naD*\u000b\\C\u0012Mē\u0014\u000bl\u001c\u001fp=\"$~*&Ll\u0014jSX\u001flLH\u0007f9WY}\u0013d\b\u001fԥǡ\u001e*\u0013I\u001cR!ƦX\u0017 /\u000eL\u0014\u0003J:f:twr\u001bd!\u0019˞X\u0018f'Kp-l\u0006j.Y,/@!۞쟤d\n5@&&ӄ\u001c\r\u0006\u001b\u000b0)Y0\f]̂\"\u0003BGF(\u001b\b7:@YJO1?\t$0\u0015\u001d1 ##\u0019Z(!ݘя{E\u001c`I\n\u000br7\u0002\u0000\u0013 s0\u001bn!ySZ\f\fAed\u0010(Fm#b6#,\u0010cU3@]8\u0011ؚ(5o_Xy#y\u0005J'ZGd)Hk.T\u000b8)M.\u00133G\u001bI49r0/#7aJ32x\u0017|\u0013~L/Q\u001d\u0007EpiE\rgN\u0003J6\u0001&\u001a\u0000UfLx\u0006lsp9\b)x=T \u0015=\u0015\tYm\u000e\rr\u001c\"&(\u001d`cK{\u0010#\u001d\u0015y\u000fkJ]p%d]\u000b;\u0006C\u0015hV\u001eZtT\u0004\u0013;[\u0014\u00100$PrC/Ns&mm0لۙ>.Wu}\u001e\u0007Y qcn\u001b\u0000a\u001e|vl< #Pt'\u001c0r\u000bk#\nXZv'(\u0015@zk=-1#\u000b={…#UvNA`\b\u00184(hkP'\u001dJl-\u001e\u0002\u0018Fj\u0001\"\t_6g\u0013\b{F>­5'r;}g\u0012y؇@\u0004ِ\u001d,VUL\u001eR?LR\fjC\u0016Π1!S#\u0007̎\u0019g4SE=a'Lu]5\u0018180\u0012\u0011E6I7(\u001b\u0001d=QsNB=yδMq?gwf\u0002KP䜑1*QVg:\u000fP[!CשI/\u0013!NM$;G\u001a!׉?'O\u0011z8W\u001dПr㔿\u000eoCUo\"\u0001\u0016/hΒ==VF\u001aDړ}KE\u001ai\u001ctJ#Z\u001a\u000bC3\u0007% R\u001aRgg\u0006Xd\u0011\u0007\u0019$sP(AΆO/Ρ!+vK{nCu;\bi,s\u001c\u001b% _\u000e\u001d9[-M_|}A\"xfNύQWbsي\u0004\u000f8\u00128\u001f\u0006\u0012\u0002d\u0011o.q0\u000fw\rۤV\u0010n)4UTM\u0010\u0011\u0006MBo(]'5ؙE\u0007\u0004;iԡb?S#\bv\u0012I\u0013Cw ?\u0019R\u0018\u0002Uw\u001bz΄3ᮦpG\u0014c\u0006a{Q:)\\\"~i\u0011\u0017\u00113ڋ)dOBd\u0007G3[B^ɠU/\u00103u<\u0018-:K\u0006zQ.yo'f|oI\u0000$ֳ\u0011$ԪX\u001d\r]M/˵2_jQ /7]l6\r&kUM=Y_iՇcI՚!\u0011f<y\b\u000fNۮb~ۭ\u001baV\u001eKZv]l\u001eenzM5vVU\u000fLԴ٭=*ՎmnVM:UscӾ!лZiTh*\u001944dDmFS~3[T;s}X_\u00139]~W 4*>_x޳\u0003\rJ\u0014P3\u0007&Ӗ:sD\u0004\u0005t\u001fwK\n\u001bQXR2*O8nTkR\u0019\u0002Og8Z\b%P\u0007X\u0011C\u0003\u0002\u0003\f)(N jJ!>sc؊GXH@\u00003\bB\u0001Oǣ\u0005_fx\u0010\\\u0001f{w`Gf0F\u0004VP`Y\u0002H\u0000Rԥ]L\u001dXգy`v\u0019^\r8\u0007O\",\u0016̨,R_\u0000,X+WR\u0002puRQ\u00002ED9xˈλ0FmtcB5\bMq\u000evQ\u0005/ /+\u001d8JL\u001d#U\u0018c\u0011Lb\u0019xjsbJG\b\u0017f\u00071n\u0015rSI'GƂp\b\u001d\u001b\u0011T,j\u0018 4̲R\u0016\u00060Z\u0001o\u0007\u0003J\u001b\u0011\n.!Z\u0006R\u001c0xz\u0001Py\u0010l\r\u000b\"\u0000צ\"͔\"\u0014kbo\u0001X7T,\u0002r(.ޡE,*\u0013\u001enDgP\b\t˙Gj\bu\u0006)4Qpڏ+w\n&M\u0016\u000bcSq{\u0018 dІцP Nҳ)\u0003Q%D\u0000L\u0015\u0000\u0002\u0001}TK8e\u0000\u0003#|/tD\u0014\u0003,Q\u0006w#B\u0010Z\u0001cD ui\n\u001av\u0002x\n\nX.?:,t .P\u0015)\u0015|\u00128'\u0002\r\u0012\fEF:m\u0000FJ\u0017]\u00010Kր\u0001<ja9\u0012\u0005V\u0014yנJqV#뚄>Hp\u0004\u0002\u0007@\u00120?$\u001a\n1U?\fGq\u000by~\u0013\u0000q\u001f\u0001T7\u001e=1&\f IH\f^WX\u001cD\u0001x\u0011XH\u0002VB\u001cv\u001b3ˉ\u001fQԮ(ZJJOpv>M<$z\u001f* A1\u001e\tQ\u0007\u0002\u001d\f1j\u0004\u0010y\tbu7\u001dcJmO\u000fj`%2&Q\u0001Ww\u0011E\u000f\u0006\u000b\u0011\u0002ALVUz\b!7sIH\u0001=],FP\nhMْ\u0019=\u0005J,<e8 .&\u001e\u000f/l}*\u001aw=FЛJx;\u001b)4D\u0000&L,P ڂX`'P\u0003G\u0003\u0010\u000fO\u000e\u0010NK\u0007X\rt\u0010C@'J0\u001d\u0005@o;\u0012\u0002C#\u0018@>1=~jC-\u000bu$e\u001coה=lKe<_9|\u0001d\u0011x\u001eVq$\u0001Q犋@\u00112\u001fat`TX\u000f\u0016\f!=֊Bᣐ\u00022\u001a\u0010Z\"T&&!)\bމ\u000bx\tB\u0002L\u000b\u001d\u0004HI&[H՛-~)Lj3\u0014\u0003\u000f\u0001\u0013\b4`\u001a^\r\u0018U܆\"[ \"A\u0000<\u000f\u0010ݘF@D\u0017ڏP@M\"!Rh X?\u000ft2E \f\n\u0012p\b|*\u001d\b\u0000z\u0001TSP\u0012\u0000L\u000e2G<)D!\u001d\f\u00108 &\u0010'\u0010\u0002I.^\u000e0(/\u000fhQ/|\u0004H /.t\u0002\u001f!\u0003\u0005$\u000e\u001e\u0001\u0012eN\r@R\u0011V{n\u0005=s`\u000b\u0005Oӭ\r1k\u001f\u0001H) @40B\u00068#O\u0007_hu6mV\u0019\tp\u0018\u0010a A\u001aj\u0006\rW#\n9#iz\\}\u0003}\f$\u001aB.)ۘ\u0002\u0001De'\u0015i.@)WvD@mH_v|Ï\u001a\u0017\u001b9%\u0011DX@],`\u0014\u0019T\u0016\u00017KK<\u00014\u00035W\u0000%\u001a\u0010 \u0011qh>\"\u0004d\u0003\t\u0002|{*isC/=h|\u0003Z8#@0kM@%ڠE(\bSo\u0004~+CMj\bX\u0001 C_\"i\u0004\u0006RgdJD\u000f\u0010A\f\u0013Ҹ\u0000\u0005\u0005|a/@U\u0002C\f\u0002%i\u0001n\u0005˄\u000e4\u0003\f\u0014̎ޮ\u0000ކ\u0018u)\u0000\u0018L@\u0006\u0012:S\u001ccbl\n\"ΰlQV$PÀ\u0000\u0012!\u000f̌\u0003ûE~jx8\u001a\u001c'(f۠\r\u0001I\b\bbJ\u0011yB\u0019>Ō \rC|\u001crM=C\n:\u0002\bŪԌ\u0002\u0000K\u0000u#\u0010\"\u0014q_yPO-@r\u0001E! \bqrH\u0001\u0006~1Ģ\u00106؆\u0002R\u001aAD.\bd7\u0001\u0011\" \u001el\f`,$Ո ?RGR\u000b\u0007T\u0007\t/w\u001a\u0004(9\u0013B\u00101Ԏ*L\f!w!\u001d\u0003ƅ\u00023H|wDX\bf\u001ba\u0002b\u0011`\u001bE#]k\u000bF\u0002x\u001d\u0002}\u0002\ta\u001a >̏\u000eA\t\r*N@t\u0013V'*CɈo]R?( ڇoՕ5@h\u001bN\u0001\f.\u0012S7\u0005*jǃ$\u000fVZd\u0004\u0000\u0016&+b\u0000\u0005sC\u000b\u0005\u001b1\"\u0005BO9Bʽ\u0007\u0015\u0001A\u0017Q5\u0002s,1@ xPg0z=ʙ~eib\u001aB!b:Nz\u0015D\u0012\u0000!\"S\n\u0002@c\u001fbCU\u001b\u0001s0j`TO\u0019\u0018n\u000e\u0001\u0012U\u0003|\u0003Ib0\u0003P\u0000\\b\fDAcTc]Ώ)0\u0006\u0006cNQIm4@\u0011Ȟ\u0016\u0000\u0001a/@dy\u0001ً`\u000e\u001a3\bQ\f\tn#U^d\u00023ujj,Ҩ\b#,tfH&ȅ\u0012w9٭@eO\u0001;9\u00024L|\u0007\u0011(e-*̀\u0014 ɼt7Pq/sG\u000fz\u0015F),BcIyn\u0004#!lA)Fccc\u0006\u001eK|3xy\rl\u0001\u0002ce\u0005k\u0005@#QHS~\u00105t\u0012@m?\u001fs'F:ي@Z\u00060*\u0005+\f\u0016peulڜ@YE\u001d99F\f\u000bNBg\t(8\n.\u0006e̷ߡ0Ā\n\u0002#6[~\u001d\u0016S\u0007T?\u0014_.]1I<9X?||g\u000e\u001a%b\u001ck\nB\"J\u0011h\"e\u0012:@b\u001bL\u0004r\fF:'-d\u0014\u0019a&G#V{\u0019i&)\u0018dc\u000eEZ2ԉ|\u0002mR\u0010\u001d\u0017njX\u001blta܄\u0003US6s\u001d\u0017\nEʔ\u000b\nI:_oQ,(i*H\u0013x$$Ya2\tRYH\u0010Eu%\u0012CIx\u0012\t\u0018\u0016\u001b\u0001z9ఙhP*\u0001I\t#4\u001d}\n\fmP\u0002!)\u001c!tp~j\f\u001fz%P^/\u0007}\u0010o\f\f eYE\u0006Ew1\fD\tb4d\u0012٣\u0019\u0005j8\u0001߅J\u0001F)\u0001怺`G\u000fx@\"\u0016ӱ`%\u0001\bBp\u0006\u001c:S\u0010.C'\bD'\\W|l:w\fw\u0019ʅ޹\u000fa\u0005\u0006 \r\u000b\u0014,✦ؽ\u0011\u001c^cJk(yjS4v<pDzdB\u0006t:\u0005|w\u0001W-y\u000fsиK\u0010tx86Am\f}\u001e\u0014Pp1\u000f+\u0015'A)>\u0000+*ft\tTL\u0012\"w\u0001\u0007\u0004\u0001b o@z2\u0007\u0017H]\n\u0010T0޸\u0004Pr\u0019P\u0017vh\u0006t\u001e)0jD5Ҕ(\u0012c^tcP\u000bB+4\u0018V1Fq#DPN#iGo|}Q<yB+9\n]MS#\u0004;\u0014y@CB7L\b\u0013\u001b\u0016=~(R\u0002\b3C@\"$j.;\u0011\u0019N-t\u000eJ蚚Є\u0013G+\u001eeu0\u0002`\u0005\u000f<\tL{\u0004c8\u001f!1'4\u0016\u0018\"2\u0016\u0013(\f\b\u001e8jIf^\u0003\u0000l\u0006\u0018\t\u0018<UBhQ\u0011/R\u001fbV\u0003*#\u001a}}\u0002\t\u0001KA\u0018^ǁZ\tp@tj9$TCSIS5d\u0006pPL\u0006\u0012_\"\"nCHH\u0006|?L@\u000fB@\u0019n\u000f\u0013\u0007׮T\u0013w#Je\u0006>PZ\u001eRdL`!0\u001c\u000f\u0001H [\r\u0007uqg# W\u0003\"&1\u00114 StF:\u0012gО\u0010JX\u0013@.R\u0000x\u00118^u%<t(ס\u001d\u001e\u00046應;\u0007\rZ\u0002\u0003\tMEu|a\u001d\u0000Dd\u0007\u0002K\u0019M>H RtQ^Qp(12\u001a\u000b\u0018(\r}:5%j$\u000f *\u001ctL&O!>\u0016\u0011\"<J%\n\\|\u0017<e^V\u000b\u001c\u0007\u0010\u0019\"Ր\u001c\u0000D\u001e\u0017'\u000e6Oi\u000e\u0015?e0x!ϦB7a*\u001c^{\u0000:ic\f\n?C\u0019?\u000bHs +\"F\u0018\u0014\"b\u0010:0^$G\u0000S\u0005\u0006\u0015\r8q+\u0000K\f0$\u0004\u000ex\\)#P b\t\r¼8\u000bX P$2-\u0000'U\u001eC\u0007\\@ԷO󐐙\u0011\u00062B\u000b,\\31x+\u0016 7>G\u0007 :\u0005~\u0007f\u001d?\u00070\t슐 \u0015AvP2'\u001cƔ\u001fS\u000f\te\n\u0000\u000f\u000bu)@g*\u0015KX>J\u0004J\u000baԲA\u0003\u0013@ Y?Rc\u000f\f\n`n5c#;\u001aH!A\u0012ZG#\u0017@g:\u0018\u0003\f *%\u0006\fc/@\u0005;z\u0010\u0001\u0001\u0006\u0007\u001485\u000ejq\u001a^\f2\u00148\u0011\u0004'sr\u0001\u0004s\u00120!%F\r\t$\u000e\u0001oH\t\u0002\u0001fBW]\u0003\u0019r-B2\r-\u00011!ն\u0003,\u0014}\u0005\u0011`\u0015H9`7\u0003\u001e@\\\u0006D<X53v\u0011\b(\"\u000e:;p>2\u0006|P0\u0003\u0011L\u0018x\u0005\u0013X\u0002Ȫ\u000b$\f{\u000e\u0007\u001d\u001f+\nl}A\u001a>x\u0005mA\u0001.\u001d\\\u0002m%\u0013\u0000\u0016C$ I/1Pa\u0001Mɤ\u0005*h NҗOS#󥶇s.n\tN1P<ᥭ1P\u0019&a\u0000[\u0001_Vj\u0001\buW.\"WS.dps`\bi8\u0006q\n|ʈ\rD\u0007\u001fp!G[p0ph\u0017\u0005</V+\u0005s\u000fɅ\u0004TT}\u0019߭*<\u0007\u000507xY\u000b(ء\b5/hb\u0005\u0018\u0003dtoh7:\u001aU\u0012\u0016\u0014ӊ1\u0003]&\u000b\u000b1\b A\u0004\u0012kHE\u00032\u0004,g\u0010@\u0006\"?;k`\b8\u0014\u0014߁ǀW>D(\u0003\u0014\u0002\bv\u001d]\u0007Ǖ\u000bb\u0013&T\u001d3,p\t\fQC=D\n\u0000Df@H0\u0007\u0006z0FG\u0007C\u001c\u0019߽\b\u001dB#C\"J;Y1m!`nL\u0018\u0001Bi\u0014R\u001e\u00173\u0011ӪeL\u0006^P\u0018\u0014ZjgR\u0002\u0000Ђ:*c\u0004\u0018\u0001z,50I&hp\u001aL\u0012ox\u0004\u0018\u0010\u0006fZu#pt,xjrZH\u0007ڂ\u000e\\\u0003а:\u0011Ipe\u000bڊCF\u0003\u0002e[PC\u0015F\u0000b,eDB)3\u0001qi&!B\u0019Rz!*\u0010\u0010U+C\u000brOt8R:gF\u0003\u0001*\u0002\u001a!a\u0010\u0014i\u00022GIB#\u0016^{\u001a3Px0\u0006A\u0012a\bXP>\u0014:\u0019J>J4\u000f{\u001a\u0002Q\u001b\u0001j\u0019ˊδ\u0005!HRcdX!-sJ+ʥ-\u00042U9\\X;1GfN,\"{\"f\u0000PhÏ\u000ej\t%\r.@\u0000\u0002O\u0004<\u0007y\u001b\u001d+eOQB\u000fT\u0014ɥ\u0015eIc\u001fX \u0004\u0017ab\f\t\u0018\\\u0013$TT<<9S\u00079\u0004-P\u000e~Ҷ{uܔ@\u0017(J\bYQ\u0007,\u0003\t$kL\u0005\ff\u00016ό\u0001\u001ea5*^\fцp\f\u001egtJi8\u001aW*@@T)D\u0013\u001a(\u000eQ01F\"0VxDq3\u0005\u001891+v\u0013O\u000eP%\u0001\bq0%<cّ(\u0003KQ&\f˕SܕZcFbt`%\f1)\u001e\u001ay\u0006d\u001f\u001f\u0002%zlk\u00141lCn\u000b\u0012_O{j\u0017F\u0017+j~vJmkW?.mԺu#̵\u0001\u001cto۱Th\u0003\u0017~]\u000f~)տٞ6.^iZ/uM{{\ruRwvK]]n깩jU_hB\u0004\b8\u0010Oz]\u001e\u0015\u0014ձ;\u000b=\"\u0015\f\u000bE<z/\r\u0003ā`\u0010T\u001f^|a\u0013<a悫\u001f4]+\fp\u0000}\\پa\u0013\u000f<j^K=M\u0001yn:wh\u001e\\03NMpX.yO^ۙ)Q\u0013:ǒ÷\b\u0010[i)9ODH\u0014̿AD04qݭjZDWz#p\u0017uNVk\u0003Qrb\u0018MSxzQ$T_$Z@{F\u001a\u0010tVL*!q֩)1\u0000:[*?\u001eNL٨<պot/7_jwn>T>\u000bGW~S\u001b\u001eTM%3TLcvy\u001es<L>\u0018#O\u001eۀp9\u000eI=(\u0010\tpo8䬲o<xs\u0007*j՛l/7L\u0006\u0004\u001c=n?\u0006Ӆһwsөvp/|'I-\u000bz\tUFTm\u001b\u0010UZ\u001cFS\u0003\u0001\u001dLݛlV;:i:\u0017Qz?\u001e\u00113O/zU)\u001fo?W1\u0019;K08]f\u0017C\u0011\u0011p;Ux;Օ_J\u0005\u0003HvhǱ=wޕBQBRU\u0014L?\u0017\u0005nl?#\u0010\t\u0010P\u001c9a\u0019)w[\u0004\u000f7nğ\u0001}+UO0\u0007\u0003~@c \u001fZEl\u0001>\u0004@\b\u0000f\u0011#kA\u0004-<\u001f\u001ens\u0002\u000eS(M:$\u001cZ1$|_S$\u000e\u0018x<co\u0016#AsS\u001cpKU\u001d{\u001277-uQ%G^!hh01\f+|L\u00051Qߙڴ\u001fvJu&lG\nЋ*qx%\nҫtCn@OX\tZ\u0003\u0007@\r݋m\u001b\u0011}ht\u000b\u0000\u001e1\u0014\u0018q9\u0014Z\u0010x\u0001ex\u0013\\\\E2o)\u0002Y%b|Hq'\u0005\u000eF\u001f(ڥF~|Cf/2\b\u0007]R@\t/[tʥzj.\u001dnIOW%\u0012y4o]+V9sî/O۵F33&An[\u0002aDk\u0013jf%<$r]fUjT?I\u0013o<=.5[K\u0012O\u0010ݢ4(9$?Ѐ->\u0016\n9\u0019#TQ\u0011ZO\u000ed?\u0011\u0014c/\u000f1\u0004d G>8c/FI\u0011@(4я$?I\u000f)\u0010y.OmMu}y\b\u0014\u0011\u0012\u0004_MP~\u0006K\u0003\u0004E$\u0014?XOȾ\u0007\u0019=S`o܂?\u0010\u001bN?\tkS[3%j^+V\u000e:.͎\u001aT\u001aWճ|F\u001b5Y`uS\u000fxADg!\u0004E\u0017\u000f\u0005\u0003Fݞb1}\u0019\n҄Y$oߑ[\u0003bsg?IO\u0012ׯ_ݠq'+\u001fSD\u001f:E\u001f$t*ͧO)_NM\rrEg%Y4\u0015Y\rgICL)äQ\bZ\f-a\u0019\u0004`3z!}0S$\u001e喚F\\><zVJMu\n(Pe:~~=\u001c5\b-c\u0010zV\u000f=\u001f:I(|b֠gtPK~G z¡QVҨ\u0017\u000e?t6v`zF%In\fyJQ\u001a\u001e.i\u000flT\u001cjxX\u001b'\u0018\u0015$T\u00161n\u000e܋1܍?rvպUܵ\u0012 \"3\u000b\"P;L:?\u0003˛ķ>PNuq+wP\u0004n`̌b\u000ev~\u0004!z*؇3\u00107Nm\u0010i\u000b\u000b\u0012D\u000e,\t mWkJlPQ\u000bsޱ\u001b\u000fHEZK̷qua0\u0013^,B\u0003̂Ca\u000e(ř\u001fL=\u001avX?sP\u001e惒 ZDP0\u0011~\u0014',httE}೐vc\u001d@?jfP\u0017 jSgsLv\u001aq.r[G{1iP\u0001k2(N1ɦ\u0002ԟUǹHޒ\u0004\u001d\u0016\u00152^W.(3\f1m\u0013dG4L#u\u001c4\u001dG\u001e>ڦ\u001e\u001c\f\u0002@$\u0015<L@@=C\t\u001d\u001ee\u0018\u0010\u00192uca/A\u0002\u0010K\u000b\u0001\u001d\bl@қ\nuK\u0001Empˢ\u0018c/(\u0012Z\u000b^sp 8LGP#cA4%Ǟ4\u0002@aowd\u0016=Sz\u000bD@\u001b<8gx`BH^Yၞ]\u0012>\"= H*BF\rI\bu\u001e @I2v\u0019I\u000ee\u0000bmJhJ@4\u00032,2+\u0004PT\f\u000fE\u0018\nAA+\u00069\u0019Z|,h8b\"^\u0010\u0002bU.z@\u0015%A$Xݠ\u0010̭#)7'Dԫ*E3E\u0007X\u0003\u001a7)>\u0003\u001cP\u0007-Ѽ/3O.\u0016MPsم!s\u0006x\u001e2K\u0014zX<\t\u001f\u0011Y1*<C2,w\u0018>t\u0011!\u001e\u0002TG\bk`HB(A3]\u0012)\t{}\u001c\tB\u001c\u0005\u0002;\u00100CUS3\r\u0013bq\u0011]XĂ\u001b\u000b\",\u0019ڧv\u001eo9׮_XEp#\u0014\u0007<P\u0014\u0019ca\f9\u000fM\f\u000e'3eGH\u0012B|,P\u000by2\t\u0019E\u0004LZ:&\u0005eWƞGv\u0004/\u001diF\b\\dr\u0017@\u0004\u0007%\t F\u000e;Rw\u0001;\u0016>4l94\u0002KV>pY=+i\u0002Sm0\u00199&Hh½_\u0002f,\u0003eA\u0012x =R<[\u0005<\u0007*\\6aW\b,x\u0014\" T\u0015P`\u0004vG\u001fi9\u0011\u00073E=\u0003J\b\u0019p2xʡ\u0007JȤ;x.bKhz\u000e̜vj\u000e\u0014a}!dEZ\u0018h\u001c\u0006$ZoC_\u0010\"IWh\u0019\u0016-X\u0004Er%݅(>\bh>Q\u0007_$B!\u001b0SN$\u0019\"\u0017\u000eN\u0004Ұx\u001c\u0010q!B-['\u0014!LfqHK;=\tf7d{PEI-\f\u000bX\u001cphHoݏ\bzLHip\u0014\u0002ҍ>ڥƭk[d'*o4\u001b\u000eZJ熴>4I\u00017{~K\u0018(mܶ\u000fYiM\u001cst]\u001dmuCI$zlB9mJ\u001eB\u001cA\u001b)\u0019qÕ\u001f\u0010{-\u0017\u0005\u0011xx@8\"\u001a8or\u0003~#ۯe\u001f(wL>N9\u000eLCSbRؐPHMxg`\"^\u0002K$\\L(]3¸DŜ+oZ+C\u0015_<@#\u000f%\u001fz,Cm=I\u000f,\neG}A\b\u000b\"dKU9\u001f^\u0007+\u0010\u0001p\u0000_ƜT\u0010\u00162D 'O$t\u0017/`zZe'.5s,<u!zJ\u0010ņfx-kw]\\\"e_%ߠJ\u0012\n\u000bڹz\u0017\u001b\"\u001bJg\u0012\u001cabh\u0003bD}MM,G~\b\u0000 \u0017\u0005c;SYu0\u001c\"3\u00046M`$\u001e#RzZ2odEꉣ\u0000+؃P<\u0000Q.e-s/S\u001d\u0007_FcS3u8kk~}o\u0013ߕJgb\\3\u0006=\u0016R\u001c\u0011a\u001erA7\u001a,W;\u001d5rW:\u0014G9BHn]{_7ZԭVr$\u0017AN1Sj?tr磿ֺwx\nˑFԮ\rZ}]mƲ%hWzY~z6˥n\tJ߱Z<RƯ\u000e[Rlmj/\nG|p\u001deU^%|<ܨj\u0005\"fMY]n\u001d:j[ڤ\u000b\\Ŭ,?4vjZYWg\u0006N\u001fj\u001cZ%:ǧ:ں\u0002ŹR{,+2\u001d; V]mWsUTof\t\u000bE_K]k̾-ֶ]Շ\u0017Hܒ9\u0013fSg\u0002lk'\u0002?mKK/Ρ':vSm+\u0012qT[ԺZy^l+)\u0013TtXjfT\u0007O\u0007}^t|\u0004`T(*-xNōէz,D:5AW}\u0013x\u0006m¾[\u000esOxu\u0000lv-ZvgO٦\u0007\u0004\rs{^T[kmWK\"Roޮ4^IeE\u0000Kn\u001f\u0018mQNʠ1x6a`\u001f}s+l#\u0012r\u00038\nE\u0006ׇ\u0012Sn\u001bN/\u0005r7VQ\u0006EhF5U؋ϵ\u000bm4.)S(u\u0004%-)ԹJ/\u001e\n[RX\u0018ME*\u001c]mWf\u0014x\u001d\u0000+R\u0006H¡m(20\u0016JOc╖E{y$w]`lm͖\\O^+6u'e֭s})^bKQξy 6%zZz`Kfk]-QP\u000f]~F+3\u0019-_\u0002q0rJs=xW{Jeȫ.+\u0001&\u001cW]m@YII'#h\u0003M\u0004TܔR=w\u0012\u0007Q&@,fNޛ?a;\u0019I\\/\u001d*~Ԩb<\u0007rT ?S|L1orh_ bm>:!3AoIQܩ#wz޷ni%ku~Pm=;VL_\u0011;Um鳝]\u0012\n=\u001bSjS n.CN]^i\u001b\u0012hX+kpsKݙu2/F\"Bz&oi4\u001b7lL]Vɾ3wB̿\u001a*v\rkSqX<s[;^݉7\u0006z[\u0010\u000f_SG\u001fuMTl7/\u000e\u001d\u001c\u001etJ\u0010\t\u0006,uފ?^\u001c\u0002_3[ڹ\u001bנ\u0003)\u0007\u0011#_k\u0015\u0013\rY\"#\u001fkYkUw<e9n]S!}kaeM\t#t~k1ӋJK˸F\r\u0017-hښU~_\u001d6e?5*8W\\꟞c[(q#\u00180`\u0018c\u000fJIԛ\u001cץzbɲRZr\u0013rꭺ\u001aAG?T+AӬ?G+Yk\u001d:_T\tSO-cWwsLz%\u0018\u0004;ΝuEC\u0019\u0017{OS\u001b߰\u0017;Rt[7[OsJz޷V\u0007U[REsH`\t~.|Y\rRhW\u0003[\u0017HIW=f(\bL-v\u001b\u001d\u001bmoĜѨT;ʟf\u0018f\u000f\u001b\u0013\n;Oꊬ6\u001b\u0001`V4\u0013K>͛Zj[ڻj\ncK\u000eW\u001eu\n}I\u001e\u0015N1\f>j|8Ԇ\u00167^0i/ ;o\u00116*%\u0012P%M\u0005\u000f\\*tO\u001e\u000f_r=Z\u001dYWK\ti\u001dR\u0010Tӽۻr+o&h}\u001e߶Q;nVQ/Y\rAi4\u0013\u0017B@\u0007.btz3Do^\u0017ZPlRjR=`RzCu&6fZI\nk޲ܬ-\u0018e&O|\ftx\tlfzq%a\u001d$\u0003ΫW&\u000b\u000bbG)aL;zB=͆}c/3>\u0011M\\oyRʛ;'{3oںˣC\u001b=:5\u001cSA$K\\͛E/=RWoز2\f[#ޖ5\n\u0014\u0001-\u0015+o~\bK%\u00033r>zj:A\u001ftis\n^'\u0018jvpkZ떯\rQxCR},LRѻz\u0000\u0016JSG߅0W\u0002--\u0007'1/mW\n6Rvv75hdUK'\t8mUm~M0~y}r^eDmʍk(tD>uJR۽2CAikT\u0017ZuLFo-6'*\\|\u0010\u000bYtL\ny\rM\u0015\u0007*M5hSn7[h\u0002PMo4k;)/5(^ڝW1Y\u000esyC㮳ou8LbGJOO\r4֙s-T\u0013<jj4\u001bQ;hQ\n\u001e:j6YISAw\nm)Q{Q9ӾN1}Y\u0019\u001e3S]箤\u0004+\u0004]5F<[U\u001cUHLv;k/Ͷ|恩\u0000WQ-WHj\u0000ѹBf\nU\u0006WN\u001c\u001bTm3BҖ:\u0011Q~\u0005KV\r|17F<\u0011y^SVR\fʏ4z\\8,NJ\u00178磇{c_\ttj;\u0002s\u0012j\u0003ʕ\u001b\\\u001b\u0013W~5i+iؤlə$`>s-\u0003\\\rm,qLuԩ.7hI{V^4\u001f:kQ{[_mC!'Qʾiru(V\u0014eVo:]\u0013=\u0010+c';ך)=RjTo5o\u0000}\u0004\u0019ss\b_\u0003R#\u000eE_a?z.֌\u0015dpic#US|>\u0014o\u0016\u001fxv4Ԟ+\u001e\fl|\u000fn\\[9#t:?/H>?7\u0014핽?Q|a\u001f\u0006bxq[W?\f}P֊\u000b5\u001d].\\|\u001dS?+_\u001b,Z\u001e5>T_bo\u001fFwil\u000e~=\u001bZ\u001b),NǡQî~܅Wji\u0015'*\u000b\u0007S\u001d\u0014ÿ.U_cujQ\u0015\"n㯸X,Wn.\b>\u0005#b~?\u0017\u0017vVW\\囑'\u0012\f7\u001b͟X\u001c\r/\u000f~񾜰?\u0018n\r\u0017`v\u001b\u001cM}WS\ts\u001e}Co<b8\u001b}x\u000f\buf\u001fy\nk\u0005T\u001cٺTi?\u0003wq6Dl)~8|\u001f\u0005V`~2= `>ۯ\u0013\u000fs+ͳy0S\\VtP)uO\u0019,2uynuc/\b'Km}9X^\r\u001fL?ln'PPcsfprTtr>\\tZ\\ٽ޺\u0010gvFg}oڛ|Z8pN~8\u0015Q\u0018\u001b*\u0017~.ps/\u001bl!aS\\<|M\u0014W\"kOM,,\\/FS囩s3=R:?\u0010\u000fT}>|*\u0014ζ]g>L<8Z\u001b;z\u0001\r6#t>\u0019OS|L~`ry7?'Cs{RȌ\u001f}_\u001f[9lǷf\u000b\u000fI~|>_\u001aO<ռ?\u001dOA^\u000e\u0007\u0003]Wz~8-\tO^m~&ř火p{0u!>:o\u0006[SOU~X~8^\u000f7vD;;Ο<Ϛ+OWswj0~r$''\u0007Yk0S)%0\u001fg>~7\nkӯ$_o\u0007Zŝpq{3)lo_lG#3һǯKw\u0007[b޿}׿W\u0011\u0007\u000fQGOsX:__?of7xXu8кoG\u001bjq0\u001e\u001c\u0018\u0016\u0006jק\u0003S\u0000?F\u0003r؟\u0018\u001eKw_fo\u0006\u0016\u000e?\r,n\r\u001fz\u0003ۧ\u000fs\u0003\u001fǁ?P/\u0007\u0003|ohqt7\u0019^\u001d{382t;8qv7n\u000f`|~up~\u001f\\Zf#ĩ\u001c<\r\u0016f\u0006ϧO\u0007K3\u0003\u0007ov\u0006\u001ft\u0006[ݵP~iohhlw{hi|\u001aCAwqbPѻ9\u001cZp7576t\u0018\u0016\u0016>wφ.\u000f_*`P8Cpa5,}yx874\u0016l\r=4'?}X\u001e.y51|[\u001b˧᧩ӑTulD\\\u0014Ff?̞\u0014bdc2>~6\u001a|\u0019\t>N<no\\t\u001f\u0016+72?\u001f-gA\u001čGѕٳ\u001dE\u0015G\u001aãhe=Z/zh?6RǦ&~2vt:\u001a\u001fQƾ#9>ub0y`<X:~]<\u000ffr^:\u001f]|\u001e6>O^Ly51=Ż؝\\O'J0?\b&G\u0006|ucwTJg6W\fL~'_өT838tj~Ӝ:ԗӝ'0QS\b녅\u001au2zZ8~7X(m\u001d\u0017ꛍtnzz:\f饧齙?xrZ!y퍎.\u0007,z\u0001vԻKeC\u001b}CMñ;Qvq3-5Yc}\u000f}-r>72+ut\u0017ָXBu{`\u001f[>l\u0018//~X/\u0005~6\u0012{^ߐ.Mw8/\u0007q#:`GN<we|\u001a˵!y<7&S:9\u001e\u0006Aľ\u0007*փp\\\u0004a<VYUlr,<\u000fa\u001c\u000f;\u0015-;{ѻVT\u0014ѧݨp\u001f\u000f-WI+r.R\u001dT=z793^aff?hջLhnohvpޜ\u0015Kk#٣l䝾F\u0007仅ڻƻRt>ͧ/sS?.͏WvKw幫֦'׶s\u0017[\u001bWvϷjSSK\u000fw\u0017ZKۭR06\u0018#\u000bCCk1y>\u0016W*\u001fo\u0017OoOo\u0016GJwőw\u000fcq嵋ŵb]\u001bZ*K|{~\\^;Y\u001e<{,{ͽBanqepezxRV+Ǐ#xupzgTt1FY\u0018*}\u0018k{~ane~q~1y586vqq\u001f7Ǟ|u`bb:55dK\u0014h=wŋ}Cۇ#w'wXdgV\\9:l~w\"]\fV>ʁw{ٽK}0J\u0003\u001bϟ\u000f\u000fj^<:7f\"\u0018;\u0018\u000eI4qxp:||6}p}x7:O\u001cEG\u001dό\u001dvo'\u0003[3ǟ\u000e\u0017>\u001cf\u001fN\u001c;ٹ9\u0019^?\u001d+\u001eۛOPif~,X?ۛ\u0018=})2\u0018~\\8xGͧ&g\u001eWƶ?-sz|l?_\u001a}:?n_/\n}C\u00173\u0017\u001f\u000e/GR˽Z8~|U8>^\u0018eUn˘x`\u000f_.?w˥ҧكu{\u001cvOʇ\u001d(Uʇ׮<|\u001eMOV>\u0015ك\u001bkffqw8|ui\u000fٻǓC]\u0013c\u000f3km%}\u0007C<\\<,/\u000fVnCTĪg\u000b\u000e\u001f\u001f/fcd4\u001eiFyڛkNnss?m]Ͽkqoox՜o\r}˯\u001bv/T\u000bx\u0019\u001b߼6pǊ@&2FLf\r_;OnU.?g5\u001en7C\u000e28F\u000f]`yUWR<J:^hyۣ?9\u00010a\u0018{nM;\u0017?O;\u001b-Mn{SŅm#\u001c\u001dY\nx}%\u0018Y8^\u0011gGv\u0016OpuDCL\u0001,/Nz\u000bwBgO\r-nۦfxa{ᝨ\u001e*i\\(\f]\u000bWfOk45:|0,\u0006OӾ\u001bo\u0006&<|hpnw\u000f\u0017\u000b3Zo\b7ki\bJMt\u0017~b2\\f_\u0017)QS,]^6O_Ao\u0017é\u0006Ty\u001bG'+eatN\\;[\u001c'_@a;^]>ϟl\u000e)-\u0000?&VnhdMvmLrR\u000f\u001fjO?-n\u001f\u000e-n)\r?=XXlG\u001e'vf::WK3X^율m\u000bGUfjK%ulgntjZC\u000bK\u001b\u0006NW&ct|ԼxwR<ï\u0007.ƐZ|0>\u0000G98\r>4`\u000fcF͓ʶ.\u0006vKW\u00130J\u0000^Iߐwݿ!ww+[|ir\u000bu?\rg$_~;9{7[߽ē\u0013V\u0015\u001eE5*n\t\\$\u0013`s\u0007Ш*\u0010&+jPE)//\u001e-O,Lo}])F\u0006wWGw`ygq@}Sr\"\u0014^>$EB{\u001cJ\u0005Su[\u001a\u001f=\u0013VIQm.wbf=P$k@\u001dD\u0019_f2pw>BWJZ{\u001a]])gԿּ\u001a3\u001f\\7\u0017fGݧޭ̜y\u001d):P[A\\]\u001d\u001dn-\u0005\u0007Vwv{S<oNn&Cl{7e\u0015nVay>,ݧ\u0003\u000e>n-]\u0016wVn6#m]WV*\u001fx>s\u0006kz0w\u001dt\u0015]?\u001a̡oH͢0TUC}xf\u001df;li꿎Yٍّݗ'^\u0001P<gbl\u0001\n\u001dh-\u001dPD\u000bak?\u0013\u0012'd\u0004?Y.$-K$[J m\u0019yf\u0002zM\u001e8\u0005I\t \be\u001f7H?A\fVWo\u001cy\u0001(/f\u001fv}WR\u00074DU%r+%{\u0013\u0007u6n\u0010`\u0001\u0019\bkz\n7? ^kP\u00037hѽ\u0015-~^mZd\u0004X\u0003nx\u001fp~aΝACSqb!\u000e\"ZU,Pu\u000f\u000e\t\u0016?\u0015C_\u0011\u001a\u0013.7\u001a\bZ\u0007S4Tx}\u0014Ω('Y> \u001bSC5\u0015gT\u001a :Gw6\u000f9h\u001b6\u0003lu\u001b́aQ|\r\u0002k\r\u0002&\r.\u000b\u0011\u0016z^!^\"`,e5\b\u0017QY%9abO6\u0011\u0018\u001e\u0015ƂVH6)\r!ΈWWR\fy*\u0014^7T<m\u0011$\u0010@\u0015(&`jmLj\u001aX`\rO\r\u0014\u0010ޓ\u0014\u0005s\u000e¬\u0003\u001e4ʱX\u0012<\u0002fTSO\u0018fllYeg\u0011\u0016]b\tƔؐ\u00183zY71\r'k\fSF'P\u0016\u000f)@\u0001R</\u00129\u0004,Y\u0015h \n}\u0004JhHw\u0019\u0012\u0000I\u0019m\u001a`?0'o\u0011\u0013\u001bbRI \u0003/< 4\fa Ӎټ\u0005\n\u0015׽taZyhY٘\u0016B14=qxj\u001f̒?A&\tu\fU\u001ej,&\t*P{I{\u000e\u000fv\f\u0004\u0005\u0010ipX\u001ań\u000fL7<yl\u0005v>~r@! 8<9D\\qǑXqfz)ܮ꿕P3W>i|T\u0004dK@Pj\u0015JkdÈկ0\"+L9RHun\n\"\u0005\u0010\u000b\u0016b:Iuy5^_3Qe9*\u000eQcs@w@˸Q~o-oc_O`o3\n9<3$s(\u001aa?\u0014}z>\r@k2y3EdH4co^dP\"<DP\u0007\u001f^P>CR+͈s\u0017\u0000Gy\u0011\u0006\rCu\r\u001f.\u0014<h\n</2'\u0011=\u0013\\\u0016\u000fx\u0016'F\t\u00064\n\\\\&\u001d0\u0014S.`[I\u0011xA*wBUj<L`T\u0011$\u0010{t_J\u000bwU\u0004]|e~e<ߔ8aw)|k\u0017[y\u0018KRt]Ouy{Ǘ\u0003\u0003g^*9Y\u000ffc8}dúy>Po8%\n3\u0018m\u0014'\u0017!0e͠HK8aN\u0014\b2\u001f\nD~\u001di>4f7;Bgw\rv2\u001eT¾*VG0/\u00058x\u000e\fdkfX\u001d?\u0000=v\\IN@\u0002\u0000@\u001eO:(\u0011$c?'B3\u0002\u000f?YM-\"igu\u0000Iw=7\u001b%Y^(\u001a/$\n\u001bߚJ/\u0011$\u001f|/\u001fP\u0012܆h'6\t-60/\u001c\u0019E1\u0013ij'iI\f\r\u0002Er$o\u001c\u001c^\u0011=b嬨Aq3߫\u001cb\n+^G Ͳ\u0012\n&މ\u0015K;J\t/}׆\u001f\u0003O\u00124໧\u000e\u000f^OD\r&nM\u000f~\r<_59p59\u0017jcʍű>ylBwK]~wx*ź\u0010\u0017*o?\u0001$F&?<\u0013P2vyWh7H\fӑΟHz]dzw \u000ba\bQ6\u0006\u001c\f'15R&\u000bD\u0007\u00034WBj8ҵ\u0006S\fX\u0017t@\u001e6\fBZ_Q/#ş_\u001deey\u001e\u001e\u0017x3j͂/W2oHJ?81)\u0003r(&\\~\u0011\u001afD\t|Qiyõ,}e/\f\u0019$\u0012\u000feL\u000e\u0013<z{*n=ښ\t\u0007gt_F8Q`F.?\\/\\23\u001c\nʠՇgN\u0003nO\u001fqie\u0018{+-og}][\u0018_^\u00186=ʰ\u0018;<\u0010ThN\u0005%M1J%ESP?u\u0018K\u00170\u0011\u0007cp;.\fަ'JL|/\fH龂\u0016\u0001r\u0002i-gY\u0016I47GܦW\u0003ĸ8΋\\S>s>K#\u0015<\u0005\u0014\u0019a/HKgh5<\u0007&A~Y\u0017\bi\u0019DN9/@zUht\u00114۸\u001cG0g\u0001=󃖿|WP³8!pC{<\f~y)_\u001ep_`V^\u0014{.7\u001a1TcZ\u0011BLx3~X\"\u0017rńg\u001e/\u0007?-s\u001d\u0000ڼ ]\u001a-7%ЖJ\u0001:\r|ZaΧC\u0019\fv7i\u0006$}\u00051<K\u0011`٠? 8vٻ{o\"\u0011Nx|t[3@܏?leQ4l`=BU*i$\u001aĂ^VQ\u0019^2\u00148S//HjbQ#\u0001\u0010HW\u0017m\u0004ۚ h\b̍*HzNF~\u00192\u0014|»\u0000h\\T_R/5ɿ\u0014{NN/ѫSks\u000f\u0006\t08\u000f\u0012\u001fx2N݉[p\u000e9R2\u0004q'cف1rٞy&'\u0019jم\u001e\u0014nw[d\u0012\u001f7a)kT\u000brϞ\u000e'l/(Ee\u000b=I\u0017\u0005p9\u0001].\u0014,V\u0019j\u0011~\\\ry\u0005zcqv\u00003E۫\u0011r5Ra\u0012k?0뗛\u0015\u0019\".\u00036W~)РO:_ZϣmкoT\u0019bӨ֝\u001bkƷצ\u0005+\u000b\b]\na|Iu|^QJ\u001eı\\k\"\u001ecG\"\u000btP'X\u001c\u001ewܕX5VY\u0013)|\u001f0\u001b`2\u000bݢz^\u0005\u001b\u00148o\u001bB\\c\u0003`\u0007\u000fe8+O{a%}\u000e9\fVFߦ%}r3.\u0005E0\u001b\u001a|3\u0005c\\\u0019\u000b司K$ŵY*-)qJ*x.\u001c\u001e\u0005Y|:\u000byb)C\u001f)\u0006r+<e+{\"'+ <Z\u0006OU0Ů\u001fZ/\u000bx[\u0005\u0016/R槅\u000bX?ہ4\"\u001a(*\u001fn|pCІ\"q1\u001ecF\u0007-mHevͬ\u0005&ˌh\\6+\"\tW\u000ebb\u0005\u0014\u0005Ç\rH[VXGJCyir8a\u0016\u0014xw%\u0016\u0019>g\u001bEܥMtiWN\u0013Q\f$\u0013=\u001fM||\u0011\b/{\u0001/\t̨`K/Q.Ǵ>{\tБfZT\u0014\u000eWh<\u0006R#\u00004\u001b>?Ọj,\u0012veZp^K\u001f\u000fz\u0014]\u0000\u0013o\u0019C;/_]\u0017[-+B\u001en{\u001e+E ݻ+NbY+o\b\"gc/>N\u0015d\u0017Y\u0017ڥd\u001f\u0011xرȠ0+ys\u0002\u0014_8ɟtiM_>^\u0018o\r0\u0017#S\u0018\u0014\\\"8RMm\u000fMG\u0003w~\u0001}t\u0003y\t\u0005ʔ;2{Y\n\u0013\u001e\u0019VQCQ8=P\u001b-v$\u0015u{\u0000StxHQ\no\u001f0Dg\tѧ.[yp7v\u001d]\bS\u00186Io;b[X3[Lڛ}W\"[l8X5\u0007\u001do3\f>MgokL\\Bg<JT\rVF!0\u0015v΍|Sy-ͦ#|I}\u0004I鷵\u001b-\tL <E70\nZV+4\u001fZN3\u0001CIFSI\u001b#C\u000e]'uw~n\u0016\r2ٍ'Z%\u0006yjZ|Ԅ\u000e#YEr+\u0005ӌEԩ\u001b(u\u001b\u0013\"<'zl>l/~Q:|pયb\u0001;y\\\u0016\u0011_^n{o{ixn\u0010Yt:\u001f\u0018U3R^*$#f\u001a?׿v\u0014Fk\u0013%<\r?,ǘ\bm'&n6\u001ex{LTӼ?e|*~՚\fk18ThݛjUhXeO9v\u001dU&/\u00153\u0000,̅&j9\u0011װɻL6I*\u001e\u0000HtX\t2\u0002j'H\t\u0011s|$^x\u0004\u000e/9\u001e-\u0007\u0014`zD8fDr>\u0011H\b\u0002\t*w>GDb\u0004\b\u0000c5E\u0012GLt\n?Z\u0010\u0017,up3/\u0006<Ak\nrW2\u0018\u0001\u0014He_ˣt2\u0005!ZVoE~<DNͧUUbY.`I,wJ\u0016|ls9L\u0003b\u0018K#vwE.WWٺ]\"\"ppi0\u0017\u0013q\u0013F.I\u0012\u00072T7\u0007͕e,xd\"VMO\u0013@X8\u001aPD\u001c]\u0013yc$[43Bk2tv7QE$tb/;meXAK\u001fgUNjNusS&I|:\u0003l-|7\u000e3:\u0003ig\u000b\u001eGu\u0019x(;#\u0005CŲ]?F\u001fw\u0002-n,/s\twvc)6xL>l\u000f|Q~JóXBx~yoT>\u001e*?6-d`!9\u0015V\u0014\t\u0000fBol3F\u000eꗚd\u0006$:\u0015na=[\u001dӛMKcW2\u000b<\u0005ةu(Wuz'2UR'g\u0007H\u0017/\u0017-md/H{˦ãB+#M|5\u001emNbI{\u0016Hg\u0004e\u000ev\u000b_Dt?\u0003_\u000b<N\u000f\u001e=qu?MR|Ap@V\u0007iG2R):OyZcںe\u001esW\u0014xqXQ=p:Dh\u0003۳O?t\u0000r-VjRE\u0011ϧB\u001a2R\u0005紭4?H$y7wzYɳXO/KF\u001bi\u0014ZHC'?\u0014EJ6Rۥ4uHo~+-\u000e\u000fſ:cM<EI\u000f逪_ﴑVoOv1RGM+|&\"F*\u0002]rY\t@xJ5\u0011\u001a!\r:<x\u0019D\u0018@8Ap%'#L]\u0004_\u0018)ޥU/.o4ޞX]-Ki!E{PXǍ1Dz~\"l\u000e1Rg{OU1?Fd=\u001d>F:??B\n:\u0019WW:\u0004~\u001aem\u0017JzyDr5ch}\u001ew7>u>OD\u001b*bUH\u0001\u000bFۯG\u0004^xnCN\u001d\u000eU=D\u001c;/\u0011c6\u0016u?\u0017\u000eـJh\u0002A\u0010#e|9M9&\u001a\u0014\u0010Ұ\u0014 \u0000o\u000b5̛\u0015B:\u0007O\u0001\u0001iKו0XvrN\u0002hZ\u001ec\u0005Ֆ*\u001d'\u0004gt#R9w)4;Sj`\bֽX\fSR!],\nنϝ*wF\\i2ǳk!\u000fA?T2O-N'U{[\u001fTo٫5́7T{T=M~[|21<~z.(zYi\t޼?\u001c|\u0012Ŷ\u0017\u0018fhz?\u001d^OU\u0014K߆5S5o\u0014Ҫo;qN\u001fg(\u0019N\u000bZ\u001c,t{1r&WO/}tNbK~E\t}\r]ju3\\Ab?\u0007uV\n\u0017ñs֧Xɸ\u0003\u0019\u001aU\u00067cOTOCL|Z~\u0006\u000bsnɅo\u001eX\u001aJys\u001dqA\u0014gKB1+70Ky\u000b\u001ew\u001b\u0013Em3\\)&yo\u0010\rn\u001bͷ8f|눨Qc9\u0017\u000fl OEj\u0003?a\r\u000bO%|Wv\u0018\u0000t\\Y_\u0011]\u001c;<2Z M󤍔>\"EVcX\u0014-yozHG$R\u0016|d\u0002mxK \u001dy.\u0019)%FZQ \rtJU\u00108\"ֿ\u000eR\u0007Ha,\"\u0005\u0002/9}E S{Ψ\u0011ҦO\u0017))dH\u0015hMV8A\u0013\u0011(=~[NIy3U\u001eLߋ|'j\" j-}\"\u0010\u0001\u001c^{WI|˕\tQ[t֑N\u0012<p: 1\\ƽȥOeP\\\nʪIDx\u00173\u0011\u000167\b$\u0012\u0003΅T'P{!-f1fv%\\FXp_Ę\u0012ts\r\r^dЮ\u001b\bv\u0011\\{\u0004\"na<\u0010C+$NMuU.>`݋0;8*\u001cI\u000ee]l\u0011\u001d#v^p5sGѝ\u001eϟK\u001a_P1\u0011\"c@,7)x\u0016\u0016e\u0000\u000e\u0016y]P\u000e+!I\u0016g|X\u0005Ϊ>٧&y\u00149yo31\u001dRUU=\u000e3֭<\u0017$\u0001.+\b\u0015T6z\u0015dÈ\u0004O\u0012\u0016\u0011iGOi׍8uնTxкFbxp]ՆWMH9\u001a\u0015\u0011\u001a_Go\n`\u001a\u0001\u0001w$$\u0006й4>\bq\u001d\tCҟPv9\u0004'㠎60*0-P.Op[\u0006U3:X+\u0007\u000fkùt\u000e\u001dF<M-\u00004\u0013(FN(\u0007&T\u000eDo\u0006O҂ۼqՒD\u000beUY:\\\r2OWؖ\u0015=%w\u0011ڞQ\nz&ã0Y\u0019yZ.K\u000e\"[OZ?*\u0006.fkХٹZyu#ǊI\u0007]76SXA\r\r\u000b3_1Saac׿2(\u0000v;/JK\u000b~mvxE`]c' Ino\u0017\u0007R\\\u0019yM.\u001cUnuԴA=Vsf\u000fN\u0013=F\u0018R:;>T\u0016\u001f\u001cea?vk&khˤ)\u0006y=Zu>$RMRZM\bچaM\u00144|rKc\u0017O\u0011b\u0005,uDe[F\u0013\u0013':\"!%꣆BO6|raSRyH:ü,Q\"\r+6\u0010\u00045\u0012t\u001a0CG@fcS\u001d\u0015R[\"{Yye\n.+\u0000|\u0016HFt`\u001eP[rﻎ6\u000fT\u0015]yYVe͠8\u000bU\u0014we]u\u001e%\u0001lX/Xwz\u0012S\n9\u001aR5n\u0012p\bQ,\\\u001dU($+-x\u001d<$\u000bC#\u0004I}ast.jxC]9_+\u001d\u001b\u0007\f\u001e\u0010>5[J}\u001c\u001e(9\u0015Ad1TN\u0006Q'a\t4\u0015t~6\u000f􃉢N`L#*7Ԧ\u001d\t\u0018Ǹ?V\u000bY'Sq\u0004Z\b\u001b*Kx7yɴ\u0002C3I\u000eyC\r1t\u001d墷\u00028x\u000e9FIޡZlYj3[H[V\u0018\u000bԡ*\u001fy~\u0003\nڬ0\u0011\\Dżp)wE-oA\u00020xVU,\b\r@h\u001c7)\u0019/y\u000epވ{\u0002}%P\"y2N\u0003'\u001a\u0014;\u0016Q\u000f[\u0017a,c\u0007a(ç\u000e\u0018ZXn\u00100&j{Oǈ@g9HI?*hI`K-'\r<\u000b\u001aM3BR\u0002h\u001dYmW;\u0016\u001aFsXABvhTVf\u0007h0kZ\u001aͶ\u0003\u001c\u001am+v!_!(b8\u0006A_ŉ9<Zրb\u0011\u0019y֡o-ي}7`7˻O_\rYJ W+-a\u0016\",\u0000sR\u000eR/w1P`T49\u001ck.\u0014\u001c\u00018\u001fPt\u001cjλ9\u001c妻n\u0002\u0006vX\u0016BȺP\u001aǾ'tp|{\u001a\"b\u0017-8\u0006o?ivW14kCZ۫\u0018}O@W1\fGþׂ\"y:pk!0{'X Ǒ<%S1\f][0\u0012a\u000bo\u000f\u000fĪUq~\u0000t\u0013Ґm\u0006\u0014dnf\u0012a`.`\u0004\u0019D,\u001cSuI#\u001eSR/LhdkY*EcJ\u000b\u000b\u0013S|\u0018\u001e?C\u0018k \\N\u00020ݽ\u001b)c@=\u0000c'!\"$@=\u0013C\f\"~R\fV\u0000#]÷\u0002G86{K\u0011[%ȂY.~1,9r\u000fgd;w3R`{(oA'ܲ\u000e\u001dmgЩ2vΡ3Π:\u00009tHq\u0006n\u001c:\f:2[p\u001c:\f:շG\u000eq\u0006\"[p\u001c:\f:lA[9t\u0019t8[\u00009t{m\t\"N,̡3Πy\u000e@Aٵײg\u0002\u000eXfl~p;h-_W;\u001f-_HSYۛ:b>3N\nvUJkJ2{|g\u0016DQ\u0019\u00013>em|8g9gy|նX'z~t2\u001fM\"WF]JCc4gITTGA=\u0012V\b4\u000f\u000f\u001b\u0005`{ǫ\u0011\u001c\u0016ݔ'!\u0006\u00061'Ü\u001b1\u0016m^Yj@hˊa\u0010kjTT\fLakG\u001d!ghMg\rx[N/J=w\u001fbs.,f\u001d@,l\u001e\u000e\u0005\u000e'*L\u0002v4\u000fcU5t\bKI\u0007fjvY[74q)ViI0Ʀ\u0019x_ӥשV|`TUF05j\u001e_ja\u0013c\f\b2D\u0017·^f\u001d`\u001cob\u0000\u00143M\u0013>HYD1e)>t#ʃN5zL.kVw͒DF;ni/\u0002\u0003`r\\5@2=\u001aj(5\u000bΞ8{\u001f5Ξ\u001e\u0000\u0019\u001d@]\u0002,ݪa-Un\u0019SƤ\u0016\u000bf\u001edp\u0018QV\u0013F9r\u000e4g\u000b[x@W8+\u0003;2:/,\u0019ﺽ$XJ&\tr[ZG?#j`խJ,w^xG?N}hg:}D\u001a\u001c*WB\u0005lFd\u0014]R#C\u0018;\u000f.)|\u00153\u0013gKƧ͓⌺#\n)IȜ̞\u0012v[Ȉ{|&9LԻOD\u0000\u0000\u000e\u001bihDd\u0005Ƞ44UDF/#,?\u0015ь[HϱR@9=TR\u001a\rX?7nXf:!\u0005f0I7\u000es\u0001K;LP\u0007鵒\u0001vr}A\td%\u001bc[G\u00174\u0005l\u001f>,3̫#RG\r2̓\rK\b%lKãzw6\u000b&]`a\u0010C3·.pZ\u000f\u000fG|8\u0013ˇCQ=%B>ƍI\\)NCm\u001d:\u001fN}塚\u0011w|8[\u0002\u000e\u000fرpr|8/2ϬG\u000bD\u0002(H=ʙȻ3f\u0001%|@blt\f'l6\u0016X#х\"c\u0018\u00012N2\u00187h(N? }ޙes\u0017:3\b\u0010F{\u001e\u0011C9*+\u0000Z\u0019-=+ݹU14\u0011vۀ1\u001c{⣓\fp\u000e\bYY[L_\ts1+MoCSFU5\u00061,|f|C-eǻ\u001e\u0010!ƬwN\u0019㾅$R\u0019㡕IA2R\u000e\u001c\"#\u0015ퟑ\u001c\"#\u0015v\r%:ׇ\u0005DTۇ\u0002\u0011qb\u0018RءSy~\u0013=HӜ\u001eTRwW\nGAI*FT\u001fi,g]#ÐT\u0005FOgU\bJQ\u0013A/\u0004*n)h!lgӆٺd\u0002޵ct;/r%ObܬΫ{ֽ\u000eG8l\u001a˃,j\\X\u000b8\u0007es7]uO=c+\u001fh~}\"_%bT*\u001a\b|\u001cy~]\u0016#N\\,3%9JOygVd/e\u0005\u0019|&?SL/Î>\u0018%bH)]4ʰ\\}]\f\u001a F\u0004Ru.V&$pd7)U&T\u001d\n\u001eɯ^]Kݞ~3f.Ros9C:6zGZ|=eOzH[\f;< /3\u0016;zO*(䞛 rk=ql&4\fˍ?\u0005(vlȭ҂\rM(äPUGMXY\u0012/f)éf<\u0004ʎhܩb!dTIV\u0014lI6$\u0013ƹ>\"rI\u00119i}3+6bu|\u0006,\u0013ݬΈ.=YX\u0010qW\u0005#d\u0016M\u0007ljq\u001e.0{fi\u00046V.ݮtZxd)\"ʬc{ei2!dl\u001dWdtZ4Zyl:\\:?L6V.ų=6b\n˦Ӛ]\u001c=h6qC\u001d=L6V.m{dmwӥo)Me:<ΦӚ?P{fөA\u0014)N϶<l6uM\u0002\u0013?P6N\u0014Mgcul:Cgi\u0001\u0000,\u0007Φ-Q?@6zPzȦ3\u00199P6rl:-b2\u000eMK[o\u00070\";bnү]R]bӟ+j^nK+szuօ5:B>[t8\tr2M\r\u000b,HPz딪KVUrʍ(\u0006Uv٨K\u0007)t5\u0001\f.L)=3|XwznR82'U2*tw;+&.et5,*Y,se-\u0001\trڝ[2c\u0018T4\bw;ц1.tw;!ͤНͣy\u0000\\g\u001dx\u0012Y4\u000evDiސMsy`hـUA\u0005L\u001e'JCγa\u0004R\"\u0013\u000e\fCC\u001c\u000b\u0001C\u001b\u0010utCJNVa\u000b0||\"ti^إ8\r\u0005Ler\u001ei(\u0000ez~i(\u0000fDf\u000eV\b(hp\u001d8\u0016X\u00058u{\b\tP253s10Kz5 ԉn\u0005D\u000eR\u0018\u0018֊2#.]RHiZ\fup{K\u0017em6PdH7\u001f۷$A5ׇ`\b\u000f-~Vj7TxmosBbt\u0006\u0003\u0012 ٷZ\u0000e#Z7\u001c;ڱ`k7\u0010\u0010;\u000b\f\"{WWոA\f5\u000eWZ^;=phbT3'V)o|\"RbhPNd%?d\nwF^Q;\u0015jO}\u001c=rb-\u000037s\u001cV\f\u001d6n#_x\u000em+\fg\u0007uG\u0004s|\u000bʚ/f\nG?\u0017V0f\u0002˳߮D\"\u0005\u0011\u0012Ìd\",ĵ6u,1YIbe{jOXŬ1)\u0007i\u0012;AIƔ[P7t%H$&_v6w+\u001fl%1 B\u0013\rVZ{იûǭ*PćP\u0003\u00109b[VGLJ}{{x@9]ݫ0år&b;\u0012)\u001dðl\n]l*FD46\u001fxe\t]*ˮS>\u000bݶP\u0002~Uqv\u001f̏\u0018_,,<8KĎ_$˳\u001b\u0012\"\u001fYdJY-Sz\u0005\u0016\fɪ4<*p7\u0017$g]0c~ꎕ\u001e;H}aC\u000e[@F*er\u00043\u0004Rejҗu\u0004YUcA\u0004VלS\rԹ$y\u001b:H\u0013.\u000fwY~cꌸ\u0001Ҫ;r=j!uR5Ej\u001aQ\u001dƝ>J+Nv\u0001Z7z\u001e~I`6}\u0012\u001e_I\u00063\u0005\u000b\u0010C٪\"/0.6:\u001a1ڣ\\<K\u0006qbixl\u0012\u001a\u000f E\u00153\u0016fU'6FHSVv\tq~JVR\u0013̂\u0003&YFGtn2\u000b s\u0004(Nu\u001eYi&'4\u0005*9j5ʻ]eQK[bNi9<Fҏ\u0013\u0012hKsZbƪU9\u0017Tn^WkJ\u0000캅Mbʡ.oFn8d\u0018^ӫs\u0013ueNn[ֶUv,+oDY^BuWnײ}W\u0003\u001d\u001fS\u001e\u001ab\u001d\u001dk\u0018`>Wk]w;=9;V\u0014=SCv\u001enT:@0I-#:|\u0007A{d[,(fd+*m\u0003KQ(vlj+D\u001c\u0017w\t\n8q[H$2H\u00054+il2jc\u0019Tu5\u0000fVEǧή5\u0000ZUi.A*w.i=\u001d[\u0014kr:҅Cb;f\u0001Z\u0001|\u000f^\u001c@\u0016\u0000\u0000nǓd\u0001Z\u0001$o8\u0005h5\u0007\u0010Gw\u0002T>\u0007k/\u000bj\u000e Y2=2n\u0016\u001c@G)\u000bPK[9~ПQ_zE}\u0011cE\n(YE\u0014\u0013rF\r9<\u001aVmG\u0017E#\u001f(\u0014#\nS\tN$2K\r֯P燸\u001bb]?KwC]׏\u0018\u0001ҫgҮut7F]?㨐'n6\u0019\rC]?sN>D]?!RjϺ~f\\\u0007\n\u001aVsxl\u0005tu\u0019\u000fM\u0015ع#[Uv\u0000Yx@Z'Tw맙htuXΔռ\u000bz~7I{{3\\Jx\u0015;@]?㰰\u001b\f\u0019w맕&)~\u000en1\u0014\u0014?D]?\r\u0015e8$3Rwaj\u0012U\f\u001euTbH))첝BIuL^\u000fRϸ{3>pMdUOE=W;3& `\u000fP@֖\u0013@P,3)'g\u001e^u$(c7cAރi۱ݺ~Ɩ<\u0010u,D314g߬<E{]?%\u001dЯw\u0000_J\u0012\rg5SgWO\u0011ު'd\f_OJ2+w]?c3Gl3Mb]=c}\u0016Y{=@]?~픅ҖuvO'\u0011X\u001dJ&rf.*s]?Nu4慨g|/~-\u0014WQOV\\ZUv>=g\u0011D\u0005\u0019\u001b]?XqE޻r~[囬u 1b]?K6uș1ȮՑO~Ƌa\u0016\u0012bu?<<\u001ahW\u001d\u0013\u001f{>\u001b\u0015Uk%v\u000fޫ\u0016\u0015ܴ1y&yBlJDWљL\u0018*v5NHTx%}cNXVΝK7\u0015{$P>}G)\u0019{{s[?\u001b\u0015T[\u0017\u0013_yO<uR^\\&''\u0019ro\u000b!ڈ.f{-L:gۋg{|\u0019\u0000W>n4&Ӈ?'<4q鼿<Y5y\u0003O\u00137{\u001egDǹN\u0019\rN.t\u0014_l\u0014)휪&7kڿXKW/1\\ƇORe;El3}I{-3Tl.\u0012ru\"O\u0017ZsPK% Q=+\t\u0016s-babpW^4/۩;V\u001f׮v=]x/}]?#\beoCD.8'Ym\u000f\u001e=SsЮKDҜ\u001co%\u0006jM\u000evxʏ\u0001\u0017,To\u001e\u0012q>:=ǖ\u0013>\\Wl\u000f6U\u001e\u000bs\bp6`~:4ITn/t.\n3Ʌ}?T{_0(J\r\u000bn}.]`ω4B%hX<8v\f\u0014INd\u0010g©l\u0018k\u0018\u000fV\u00054\u000f\u0018_a.R\u0000FaϚu:MT,\fν\u0012}R\u001ahx\r\u0011\u000f\u0006R<*EGLsyP5H|\u0011wsC\u0000ل6\u0007R[H~ᡫ(B3\u0014jQBYFt-d\u001c\b{q>\u0007\u001eq\b\u00060R\u0010qQ\"-Bz.\u0005__\u0001b(=2\f\u0003sݡ7;?턅oۡPuBOC KźM,2W G1R\rNßVoU'Z\rZio%M\u001eNKZ\u001c\u001d!n1yNUo.GY\u000f4S<6#\u0006\u0013D.\u000e8i\u0003J\u001c1`f\u0017Yw؉>|a\u001e_OȮ\u001e:\u00035\u001c_#\u000e\u0010vr!F\t>į'OWz35\u0013{3\u0019T\u000eSyc&t\u0014:\u0019\u0002\u0004UIR(\u0014\u0006$#1\u0010쇨ԟ7YV=y?\u001aЛ_#F~\u000fL\u001b\u0018M|u\u0007\u0003]\u0002fFZde:0W/\tQ<P.\u00135*\f'pa,x\rkg\u0019U\u0007g|T3hѮ9Á3sFgg-F[\u0002\u0015b<e~d߹qPEn#s_d-9-%\u0005CGNN\u0013\u0016\u0001\u00050Ow\u0015\u000f;_#8Si=\nў0ia's\u001a\u000f^6T\u001et\u0000Kr\u0017r\"ҫXBE=3/s<p/9@Х]:)\u0000(s5\u0013\u0010<\u000bl\u0001ghLGмŅD\u0002\u001bVKX\u0001\u0006D:&G\u0000\u0016\"<*M\re\u0015Tقږ i=Ձ\u0015ڰ!^\u0011VF3-/\u00167/iק{Ψ1-O܆J\u001a_l\u0000z\u0000?\\7\u0016Ȝ\u00134nsf\n٠\u001d]\u0013%\u0004\u0010j\u0000l\u0017{\u0002[e޸\t}LෘD\u001fֽ\u000f\nY\u0001m\u0017\u0014&!\u001bqɎ\u0018)\u0011Da\rv>8\u0000\n \u001af\u0013j\u000fђMQC'?Kc/˃s\u0016\bfޢ}Xx`\u0018\u000e7|\\U]\u001a\u00062N)\u0010[>y\u0011F.7\u001f4B$A\r)nHDRτ&/n\u0010P^JDxJ\"L\u0002G\blD\u0018]m\u001fQG$\u0010:)&\u0001EE\u0004\u0005b!\u0011\u0012=X\u0003dɫt\u000f\tI\"]]O\\B7R.\u0000{\t\tzh΋0e0Hf1\fb'%1\fݓj6乐`\u0018~r6vi?^ AX\u0004\u0006!Rk\u0018\u001bN>L\u001b\u0010AUAvL\t>\u0018i'\"ŨZv(];3U\u0019\u0010S\u0012i\u0017ﾨ&G~og\u001e#<\u0006BtG\u0010\u0002iHM\u001e#)#\t\u0004):\f%\tbM\tq݅xn(\u0013%:\u0000\u00004: vԿ\u0004\u0000Ia,;F@\r] s>W\u0000@L'\f\u0002Q0d0\f\u0007Jq\u0005\u0014>XZsK\u0004,{J\u0010\u001dX2_R¸\u000fR[\u001aP\"HCiˠ\u00154Z\\iE[\u0006b\u00132;Sj\b[4Ǣ-Zt>\u0015`q\u0019\u00129` p-\u0001\u0001)G\u001ePU>mB\u0011~,B|n\\{uV4F6%S\n![\u0017B\"\u0004]\u001dR\u000b\n^;}\u001c\u0016!Y\"\u0016k1ɫy&\u001c痂\u00012x^IF|\fIaFD\u0011QTx2\u0017?\n\u001b|WrԨ'vY9#K\u0013\u000f\u0014QWL?<\u0004\u000fe\u000774\u001bԂC-w~\u0011Bi\ttɌ؄/I~di\u0013\tQϷ:N\u0016iu0XL\u000bq&\u0003\u0011\u000e\u0019\b\u0019;˟ ,'H\u0014\u001f{)7[9l.\u001d].)\u000fxbLƟjAԂ'$Al5\u0012b|u\u001eW_\u001eS\u001f۵8F\u00116-Gؙu//E:<\u001b.jsgIY#LUB\"w\u001f0=\u001e\u0004/zxj~/\u000e\u000b\u0002Q9M@ã\bƣ)y呒~\u0011A\u0016#K>(Oܛw\\\u001eˣ(T[O%\u000e'ԝ;D\u001c'{Y\u001f\\%J\u000b\r\\!?{ۿ/\"\u0004z/>8iſuKP*󕋻&\u0018\u001bLBسWw\u001eFL1AAL. n|~t\u0010Ad3>\u000e_ΑL&d*\u001en?kz\u0014v8b:Mw\u0019\u0018]gotu9\u0015nKz*^\u001eF㣰\"sED\u0018P$7\u0015FAYIu\u001dߩnC\n\u0016˼b5XRCoQXW':e\u0018\u00150BdSsk\u0015\u0004]񢸮.*M/v\u0015\u0016}q|-?Nccc+jWeqGSq~&G\u00198P\u000eE0\u0016w9\u0015s\u0003\u0018o\u001d_]\u0007gH\u001d9\u0017\u000f5gϵ@\"74LH`\u0012b\r]͠9\u001dPqWgr-Qh\f\u000e5_(~\u001e\u000fG\u0004S\u000679\u0011{'\u00125aNBB6̔2\u001d\u001eLކ#q\u001b\u001a\nOV&>63G0\u000ff\fO\fqLy+\u0013\u0016)oeۚ̔2a,l3S$V&2Bf)\u001b+R?̔\u0015-fZ\u0005=o63ec\u0005\u0004U\u00152=D!]F?k||~:\u0000\u0015%(OBcW;\f\b'DH\u0007YS\u00173Vè\n\u0007*R\u0005Rۇoʿ@\\o?\u0006QVr6ś\u0014\u001b\u000bbԟ҄)\u0006;\u0018\u0001\u001f4\u0015\u0003㍭WS\u0001b\u001cMߦ}]MC,8H%}\tA!ݯ\r@\r,\u0007JG/G%\u0007T:=P\u0014\u000bJ%\"H\u0012XHG\u0004\u001be$5\u000b\u0007*EM\u0003bd\u0011\b\"R\u001f\u0012\u000b$Ȯ\b>\\,쁒\u001bp!xt!)\u0012\u0000[-\u0010>\bGLAT\f\u0003\u001f߈\u0014at21[;R\u0019N4\u001d.yB*\u0000\"ŬR\u0002\u001d\u001b\rcpz)\u0003`~\u0014&C%Js\u0018\u0016I\u000eQ\u0018Z+b\u001e\u000eOi\u0011oV\u0001M\u000ei\u0010|c`&\u0017\u0001!^ڗ|x\u0006tx2f(l $\u0000<\b%}f\u0003lL\u000b\u0000U\u0010汹j\u0003\u0010\u000f\"ϲC/MJ\u0007|t64x>c~ZcRh\u0018\boO6h\u001aC6jg7I\u001f\u0016\u0018M5n\u0015\u0012 =~k#\u0014ڬȆ0Üg*U\u001fDW͝\u0011olT&%-MV\"\u0012D)}֖og3U)`g\u0001'.`R.WzxKςT/4l!\u0010\"Wq9\u0000'y\u0005\u000bυ\u0003cO\u0004+̩]ba\u0012aQ\u0018{\u00063\"n:`=\u001c\u000b>&\u001fߜp\u000e\bȑk(F<\u001f\u0011|Yq\u0014'4h1px$g(\u0011\u0003r\u000f\f L>#A|}'ka!B]\u0010\u0016Ƞ\u0014\"є`B+ *Z\u0011-p\u0003\u000bŶw(!(-\n]\u000b\b7`\u001eh1CRRp@\"#\u0011\u001d\u0015&\u0010[`:Ͱvl52DH\\PduBe\u0017:\u001fo\u0018\u001c={ً\tG\u0013<p,arGE}T|\u000b\u0013v\u0015\u0017t\u0018\u001fL%0苿\u000f\u0014j{(\u0018ŧkO\u0012oDد\u0007\u001eדѷvgX^%YX-?bֳKq ^É\u0005I\u0004-\u000f\r\u0017V|޻*_[\f#{Nb,o5O\bq;!\u000e8y.\u001b\n:K\u00148(Pї\r9a\u0007k*\u0014D=u_\u0019\b\u0005\fv|z\u0002m xt|\"Ɣ#O!\u0015&\u0005\u0013#\u0010\u0001N\fCy\u000fFp@-.sשM\u001d]ϰ\u0001\u001f@\u001d#?\u0019aIˇp<s\u0018\u0015\u001f6d&Fృ$;,\u0007&e6\bVwNcHe\u0002XDPagb!!OL\f5h7Wd\u000e&p9\u00070$ڣW#r@x\u0017k\u001cwpG(\u001f7>\u0011\u0013\u001fq\u001c:#:pԜ:<Xa*fG\u0019pG#>{rP}x\u001b\u001e\u0005Цh\u001fzwPG\u0005?5_\u0019rP4pI&S\u0004\u0003أ\t:b#\u0012ICj\u001f?74爦.^\u0011\u0002`\u00186H\u001dE8\u001dM&\u0012_\u0007CQ.&\u0018*\u0019e,jIFSqlIģl\u001cr[\u0012IHLEq>\"\u0010nC&\u0015L|x*A\u0002\br5\u0019a9\u001dt\"\u0011M,\u001f\\\n\f\u0015F:FiBM,\u0013Xy)\u001dMs\f\f%a0\u000e\u0002\u001a<ihn$\u0017e\u0018:I,H&\u0002+Ѹ\fM\u001aX$`R(ťS\u0004D#\u0015s1\u001aB\r\u00004A\u0000\tŁ'i|\u000f:\u001ag8NE4\u0018C1\u001d\tMB%X,EG\u0013\u001cM\u0013|*M~O\u0004m{hL2\u001eexJJ\"`O$]*M42\t\u0000\r$N&qL\u0012\u001eQnK\"!\u00056AAߡ\u0005d&2\u0005`\u0019.A\u0007LQ\u0004\thʍRdh\u0000\u0007/}&,Jh)\u001a\u0018J\u0011h\u0016SȖTMD#\u0010>\u0001\u0004\fMO:4iJ:\u0012,\u0005L%X\u0002\u001a$c%\u001bI\u0011l\u0014\u0011 \u0006^\u0006\u0007b A4b\u0018(E!!5ID\u0002N0Q$),\u0005\\H'bJ&\u0019e{И_q\u0000BT\u0006%\u0005\u001d@gW:\t\fsd4He2\u00007\u0004\u0007L3)\u0012-ix\u001cR\u001b\u0002T(̀1H\"ѪEE\u0014\u0016\u001fIX,I@#ǀ%ah2\u0002\u001a@,$V\u0004\u0003\"\u0010VE\u0003_\u0003q\u0000M\u0004F3\u0011\u000b_t\\@JI4c\\:)o$z-\u0001\u001dO1B8L Bi<r#\u0004\u0011\u0002\nEic)\"Fh\u0014\u0003d@\u001c\u0001'NR\b4b\ni58\u0001\tZY\u001fƪ<\u0001lN\u00024Rqtr@\"|\u001cE#5\u0000sh\u0000\n\u0013O`(t2.\u000fq\u0014\u0010\u0006a\f\u0007@I0\u0000rq4G\u0013MH㧁IR)\u0011#X\u0007=\u0006sĘ08ZXUaH'KR8\u0016l\u0002P\b4&=p\n\r-7!\u000eKr,\"\u0002ј)J\u00044(\u0014\u0010fcABi }I!\u0004H!G\u001d\u001a,R\f\r5ޓ\u001c\u0001)Z\u0018YQ\u0003m4\\\u001aiː$*\u0004P@\u0013\u0005и4GIj\u0002\u0002sd\u001b\u0003q:\u0015H`05@\u0014F\u0014M!O<h\b\u0014\u001dG\u0012?\u001c9E\u0019)\b\u0010h\"\u0001+ ˂RLID)6h\u0002XbЧFP]x'24\u0005\u000eJٹ̈́Xu\u001c\u0001\u0005\u0000&X\u0006XĞh\u0010\u001aD#Ll4\u000est=\u0000\\C\u0014m0\\\u001c\u0000\u0004xIl$H5\"\u0015L)z%8ؙQ\"β 6$RXA7\u001d4p\n\u0015I:Bku\u0012\u0010<rF\u001fǁU\u0012H \n샺\u000f\u001eG(d\u0001\u0010 ,^7Z7\u00198GýY\u0014\u000eAo\u0010Cr=\u0018\u0017\u001fA>\u0019\u001f\rj\u001ab\\\u0016?\u0005>ټ\u000e\u0015-C\rendstream\rendobj\r6 0 obj\r[5 0 R]\rendobj\r24 0 obj\r<</CreationDate(D:20120826155741+10'00')/Creator(Adobe Illustrator CS6 \\(Macintosh\\))/ModDate(D:20120826155741+10'00')/Producer(Adobe PDF library 10.01)/Title(OLA Logo RGB CS6)>>\rendobj\rxref\r0 25\r0000000000 65535 f\r\n0000000016 00000 n\r\n0000000144 00000 n\r\n0000044395 00000 n\r\n0000000000 00000 f\r\n0000046916 00000 n\r\n0000253194 00000 n\r\n0000044446 00000 n\r\n0000044812 00000 n\r\n0000049898 00000 n\r\n0000047215 00000 n\r\n0000047102 00000 n\r\n0000045822 00000 n\r\n0000046355 00000 n\r\n0000046403 00000 n\r\n0000046986 00000 n\r\n0000047017 00000 n\r\n0000047250 00000 n\r\n0000049971 00000 n\r\n0000050189 00000 n\r\n0000051232 00000 n\r\n0000057671 00000 n\r\n0000123259 00000 n\r\n0000188847 00000 n\r\n0000253217 00000 n\r\ntrailer\r<</Size 25/Root 1 0 R/Info 24 0 R/ID[<9EE612499ACB4E378F2092018ED56842><0A3F3EE61BD34EFE9E0E26C74DA50670>]>>\rstartxref\r253412\r%%EOF\r"
  },
  {
    "path": "doc/modules/ROOT/nav.adoc",
    "content": "* xref:README.adoc[Developer Guide]\n* xref:cues.adoc[Cues]\n* xref:effects.adoc[Effects]\n* xref:parameters.adoc[Dynamic Parameters]\n* xref:metronomes.adoc[Metronomes]\n* xref:oscillators.adoc[Oscillators]\n* xref:fixture_definitions.adoc[Fixture Definitions]\n* xref:show_space.adoc[Show Space]\n* xref:color.adoc[Working with Color]\n* xref:mapping_sync.adoc[Mapping and Sync]\n* xref:push2.adoc[Using Ableton Push 2]\n* xref:push.adoc[Using Ableton Push]\n* xref:launchpad.adoc[Using Novation Launchpad]\n* xref:rendering_loop.adoc[The Rendering Loop]\n* xref:videos.adoc[Videos]\n"
  },
  {
    "path": "doc/modules/ROOT/pages/README.adoc",
    "content": "= Afterglow Developer Guide\nJames Elliott <james@deepsymmetry.org>\n\n[[organization]] This section provides an\n<<introduction,introduction>> describing this guide and an\n<<overview,overview>> of the Afterglow environment. It then explains\nthe <<web-ui,built in web interface>>, and links to other sections\nthat go into more detail. It is worth reading through this whole page\nonce if you are new to Afterglow, because the orientation it provides\nwill be helpful, and it ends with a <<getting-started,walkthrough>> to\nhelp you get started on your way to creating your own light show. Once\nyou know what you are looking for, you can also dive right into it by\njumping to the section you want:\n\n****\n\n<<effects.adoc#,Effects>>::\nThe building blocks of a dynamic light show, which have a\n<<effects.adoc#the-effect-lifecycle,lifecyle>> worth understanding, and a few\n<<effects.adoc#effect-examples,examples>> to get you started.\n\n<<parameters.adoc#,Dynamic Parameters>>:: Provide inputs to your\neffects which change over time and space, enabling much more\ninteresting and complex appearance and behavior.\n\n<<cues.adoc#,Cues>>:: Provide a convenient way to organize and trigger\neffects. Allow you to build a user interface for your show, through a\ncolorful cue grid in the web UI, on a supported grid controller, a\nbasic MIDI controller, or a combination of several of these options.\n\n<<metronomes.adoc#,Metronomes>>:: Keep track of musical time, in terms\nof beats, bars, and phrases, and can be <<mapping_sync.adoc#,synced>>\nto DJ equipment and software.\n\n<<oscillators.adoc#,Oscillators>>:: Convert show timing\ninformation into waveforms that can drive your light show.\n\n<<fixture_definitions.adoc#,Fixture Definitions>>:: Tell\nAfterglow how to work with different lighting hardware.\n\n<<show_space.adoc#,Show Space>>:: Explores how to measure\nlocations and orientations when hanging your lights so that Afterglow\ncan properly calculate spatial and directional effects.\n\n<<color.adoc#,Working with Color>>:: Introduces tools for\nexpressing and manipulating color values when designing lighting\neffects.\n\n<<mapping_sync.adoc#,Mapping and Sync>>:: Looks at options for using\nMIDI controllers to run your show, and synchronizing its metronome\nwith DJ equipment.\n\n<<rendering_loop.adoc#,The Rendering Loop>>:: Explains in\ndetail how a frame of lighting control data is calculated and sent to\nthe lights in the show. This is advanced, low-level information for\npeople who are ready to create their own custom effect algorithms.\n\n{api-doc}index.html[API Documentation]:: Generated from Afterglow's\nClojure source code, to provide information about all the namespaces\nand functions that make it work. The rest of the documentation\nsometimes links to related sections of the API documentation, and vice\nversa.\n\n<<videos.adoc#,Videos>>:: Show examples of Afterglow in action.\n\n****\n\nimage::Afterglow-logo.png[Afterglow logo,128,127,style=\"vertical-align:middle\"]\n\n[[introduction]]\n== What is Afterglow?\n\nAfterglow is a lighting controller designed to support\nhttps://en.wikipedia.org/wiki/Live_coding[live coding], written in\nhttp://clojure.org[Clojure], intended to enable people to produce\nspectacular and highly customizable light shows using modern stage and\neffect lighting, and which are related in deep ways to the phrasing of\nmusic being played. (Its http://deepsymmetry.org[creator] is a DJ and\nproducer of light and laser shows by avocation.) Currently, the\n<<effects.adoc#,lighting effects>> and\n<<fixture_definitions.adoc#,fixture definitions>> are\nwritten and organized through Clojure code, so you will either need to\nlearn Clojure or work with a Clojure programmer to create new ones,\nbut they are controlled through MIDI control surfaces or Open Sound\nControl, so once they are set up, there is great flexibility in how\nyou can perform them.\n\nSomeday a user interface for building shows and fixture definitions\nmay be created, either within Afterglow, or as a companion project,\nbut that is not currently planned. For now the focus is on building\nrich user interfaces for controlling shows, such as the\n<<push2.adoc#,Ableton Push>> and\n<<launchpad.adoc#,Novation Launchpad\nfamily>> mappings and the <<web-ui,embedded web interface>>,\nwhile using the concise expressive power of Clojure for writing the\nfixture definitions, effects, and cues.\n\nAfterglow communicates with the lighting hardware using the\nhttps://www.openlighting.org/ola/[Open Lighting Architecture], so it\nsupports a wide variety of communication methods and interfaces.\nInformation about\nhttps://github.com/Deep-Symmetry/afterglow#installation[installing OLA] is\nincluded in the project\nhttps://github.com/Deep-Symmetry/afterglow[README].\n\n[[overview]]\n== How Afterglow Works\n\nThe fundamental task of Afterglow is to make light shows happen. It\ndoes this by controlling lights, communicating with them through the\nhttps://www.openlighting.org/ola/[Open Lighting Architecture], which\ncan work with several kinds of control protocols, most of which are\nderived from http://en.wikipedia.org/wiki/DMX512[DMX512], or a faster\nimplementation of its basic ideas over Ethernet. When a show is\nrunning, Afterglow runs a thread which periodically asks “what should\nall the lights be doing now?” (resulting in a single “frame” of\ncontrol values representing that moment in time), and sends the\nresults of that analysis to all of the OLA universes the show is\nconfigured to control. By default this happens 40 times each\nsecond, but the interval is configurable within the show, and should\nbe decided based on the fastest refresh rate of any physical\ninterfaces you have hooked up to Afterglow. This is described in more\ndetail in the\n<<rendering_loop.adoc#,Rendering Loop>> section.\n\nTIP: In principle you could have more than one show running at a time, each\ncontrolling a different set of OLA universes, but most people will not\nneed this capability.\n\nWhen you just create a show and call `(show/start!)`, Afterglow will\nsend a bunch of zero values to the show’s universes. To make\ninteresting things happen you add <<effects.adoc#,Effects>> to the\nshow. The default namespace you are put into when you launch the\nAfterglow project using `lein repl` has some\n<<effects.adoc#effect-examples,example effects>> that can help get a\nfeel for this concept. To get a full understanding of how to use (and\ncreate) effects, learn about the\n<<effects.adoc#the-effect-lifecycle,Effect Lifecycle>>.\n\nThe effects need to know what lights they are supposed to control,\nwhat capabilities they have, and how they are connected (what\nuniverse, what channels), as well as how they are arranged in space.\nThis is accomplished by patching\n<<fixture_definitions.adoc#,Fixture Definitions>> to the\nshow. To work with the actual lights you have available, you will need\nto create fixture definitions for them, unless they happen to be ones\nalready available in the Afterglow project. Since there are so many\nkinds of lights, with more being created every month, that seems\nunlikely unless the project really takes off… and, to that end, if you\n_do_ create definitions for your lights, please contribute them to the\nproject!\n\nTo learn how to install Afterglow and the Open Lighting Architecture,\nsee the project https://github.com/Deep-Symmetry/afterglow[README].\n\nSince Afterglow was developed to create light shows for electronic\nmusic events, it is deeply driven by the notion of musical time,\nthrough its <<metronomes.adoc#,Metronomes>>, so it is worth learning\nhow to configure and interact with them. It is also designed to work\nwith MIDI controllers, both to trigger effects, and to synchronize\nwith music, as described in <<mapping_sync.adoc#,MIDI Mapping and Beat\nSync>>.\n\nOf course, you are not going to want to have to type and evaluate\nClojure expressions to create your effects in the heat of the moment\nof running a light show, so Afterglow shows incorporate a grid of\n<<cues.adoc#,Cues>> that you can trigger and adjust quickly, both\nthrough the embedded web interface described below, and with dedicated\nphysical grid controllers or simpler MIDI controllers.\n\n[[web-ui]]\n== The Embedded Web Interface\n\nAlthough a physical grid controller (especially one as well-designed\nas the <<push2.adoc#,Ableton Push>> or <<launchpad.adoc#,Novation\nLaunchpad Pro>>) offers the ideal control surface for running a light\nshow, you can do a lot with just the web interface built in to\nAfterglow. And even when you have a Push or other grid controller, the\nweb interface makes it all the more powerful by adding at-a-glance\ndocumentation of cue names, as well as alternate ways of doing things,\nor the opportunity to interact with more than one section of the cue\ngrid at once.\n\nIf you have started Afterglow by running the jar file, it will have\nopened a browser window on the web interface by default. Otherwise,\nyou can bring it up by evaluating:\n\n[source,clojure]\n----\n(core/start-web-server 16000 true)\n----\n\nTIP: The `16000` specifies the port number on which the web interface\nwill run. You can use a different port number if you want: just pick an\nunused port and type it instead. The `true` requests the browser\nwindow; it will be opened on whatever port you told the web interface\nto use.\n\nimage::WebHome.png[Web interface,537,427]\n\nThe home page offers some buttons which can take you to this\ndocumentation, the Open Lighting Architecture console in case you want\nto monitor DMX values or configure the universe(s) that your show will\nbe using, and an embedded web REPL that can be used to evaluate\narbitrary expressions to configure and control Afterglow. The primary\ninterface, however, is the show page, which is reached by a link in\nthe Shows section. However, when you first start Afterglow on its own,\nthere will be no shows running. The Console can be used to change that:\n\nimage::Console.png[Web console,850,690]\n\nNOTE: As menioned in the main project\nhttps://github.com/Deep-Symmetry/afterglow#afterglow[Readme], the web\nconsole is there for quick hacks, and is no substitute for a rich\nClojure development environment. For any real work you will want to\neither start Afterglow from your development REPL in the first place,\nor to connect it via `nrepl` if you have launched Afterglow\nindependently, such as through a jar file. Afterglow can offer an\nembedded `nrepl` server, which can be brought up via either\nhttps://github.com/Deep-Symmetry/afterglow#usage[command-line arguments],\nor by using the web console to invoke\n{api-doc}afterglow.core.html#var-start-nrepl[`core/start-nrepl`].\n\n[[show-control]]\n=== Show Control\n\nOnce you have the web interface open, and a show running, you will\nspend most of your time on the show page. Here a look at the cue grid\nthat gets created for the sample show by\n{api-doc}afterglow.examples.html#var-make-cues[`afterglow.examples/make-cues`]:\n\nimage::ShowGrid.gif[Show control,998,912]\n\nThere are a number of different things you can control from this page.\nThe load indicator in the middle of the navigation bar gives you a\nsense of how much headroom your system has, by showing you what\nfraction of the time available for rendering the last few frames of\nlighting effects was used up. As you add more complex effects, the\nbar will fill in and turn red, warning you if Afterglow might not be\nable to keep up.\n\nThe red `Stop` button next to it can be used to temporarily shut down\nthe show, blacking out all universes that it controls. Clicking it\nagain restarts the show where it would have been had it not stopped.\nIf there is a problem communicating with the Open Lighting\nArchitecture daemon, the status indicator will show Error, and there\nwill be a `Details` button you can click to get more information about\nthe problem Afterglow is encountering.\n\n[[cues]]\n==== Cues\n\nThe majority of the page is taken up by an 8&times;8 window on to the\n<<cues.adoc#,Cue grid>> attached to the show. You can activate any cue\nshown by clicking on it; running cues will light up, and darken again\nwhen they end. To stop a running cue, click it again. Some cues will\nend immediately, others will continue to run until they reach what\nthey feel is an appropriate stopping point. While they are in the\nprocess of ending, the cue cell will blink. If you want the cue to end\nimmediately even though it would otherwise run for a while longer, you\ncan click the blinking cue cell and it will be killed right then.\n\nThe text labels within the cue cells are to help identify their\npurpose, and are established when the cues are created. Similarly, the\ncolors are intended to help identify related cues.\n\nSome cues (especially intense ones like strobes) are configured to run\nonly as long as they are held down. In that case, when you click on\nthe cue cell, a whitened version of its color is displayed as a hint\nthat this is happening, and as soon as you release the mouse, the cue\nwill end. If you want to override this behavior, you can hold down the\nkbd:[Shift] key as you click on the cue cell, and it will activate as\na normal cue, staying on until you click it a second time.\n\nCues may be mutually exclusive by nature, and if they were created to\nreflect this (by using the same keyword to register their effects with\nthe show, or specifying other effect keys in their `:end-keys` list),\nwhen you activate one, the other cues which use the same keyword are\ndarkened. This is a hint that when you activate one of them, it will\n_replace_ the others, rather than running at the same time. The\n<<cues.adoc#the-cue-grid,Cue Grid section>> of the Cues documentation goes\ninto more details about the relationships between cues illustrated in\nthe above animation.\n\n[[effect-control]]\n==== Effect Control\n\nWhen any effects are running, whether they were launched by a cue\nbutton or some other means, they are listed at the bottom of the show\ncontrol page, in descending order of priority. (Effects are run in the\nreverse order that they appear on the screen, so effects towards the\ntop of the list can override things done by those further down. Newly\nlaunched effects assigned a given priority appear above older ones\nwith the same priority.)\n\nimage::EffectList.png[The Effect List,872,263]\n\nThe name of the effect is shown, along with its prority (if it is\nanything other than the default of zero), when it was started, in\nterms of clock time (down to 1/100 of a second), and the show\nMetronome (phrase, bar, beat, and hundredths of a beat).\n\nIf an effect was launched by a cue with any cue variables, they appear\nafter the start time. Numeric cue variables can be adjusted by\ndragging the associated slider. As shown in the image above, the\ncurrent value appears as a popup above the slider thumb when the mouse\nis over the slider. Color cue variables can also be adjusted. The\ncurrent color value appears as a swatch; clicking on that swatch opens\na color picker interface which can be used to adjust the color\nparameter:\n\nimage::EffectColor.png[Effect Color Parameter Adjustment,872,299]\n\nClick anywhere outside the swatch and color picker to dismiss the\ncolor adjustment interface.\n\nIf cue variables are adjusted somewhere else, such as a mapped MIDI\ncontroller or from other code that is running, the web interface will\nupdate to show their changed values.\n\n===== Saving Cues\n\nIf you have made any adjustments to cue variable values, these are\nnormally discarded when you end the cue; the next time it begins, it\nstarts with the values that were configured in the show. You can\nchange that by saving the cue's variables. In the effect list, any cues whose variables you've adjusted will have a green kbd:[Save] button on the right, like the `Color snowball` cue in the photo below:\n\nimage::SavingCues.png[Saving Cues,1002,246]\n\nAfter clicking kbd:[Save] in this situation, whenever you click the\n`Color snowball` cue in the cue grid, it will start out blue rather\nthan its previous white color. To reflect this, the color of the cue\nin the cue grid is updated to be blue as well, both in the web\ninterface, and on any attached hardware grid controllers.\n\nOnce you have saved a cue's variables, while it is running, instead of\na green kbd:[Save] button, you will see a gray kbd:[Clear] button\n(like the one on the `All Dimmers` effect in the photo). Clicking that\nwill remove the saved values, so the cue goes back to its original\nconfiguration.\n\nFor the moment, saved cue variables last only for the duration of an\nAfterglow run. The next time you start up a show, all cues are back to\ntheir configured values. This may change in a future release.\n\n===== Creating Macros\n\nIn addition to saving the values of a single cue, you can also make an\nentirely new cue which, when you launch it, will start one or more\ncues that you currently have running, with whatever cue variable\nvalues they had when you created the macro. This is a great way to\nquickly build up a library of looks by combining a bunch of running\ncues that you like, so you can get back to them in an instant.\n\nTo do that, start by clicking the kbd:[Make Macro] button at the\nbottom of the effect list. Checkboxes will appear in front of all\nrunning effects that were created by cues. Check the ones that you\nwant the macro to include, type a name for it, then click on any empty\ncell in the cue grid. A new cue will appear there with the name you\nhave chosen.\n\nimage::MakeMacro.png[Creating a Macro,1002,383]\n\nWhenver you click that cue cell, it will start all of the cues that\nyou included in the macro, with the variable settings they had at the\ntime you created the macro.\n\nIf you decide you don't want to create a macro after all, you can\nclick the red kbd:[Cancel] button, and the effect list will return to\nits normal state.\n\n===== Deleting Cues\n\nIf you have created a macro and decide you don't want it any more, you\ncan right-click on the cue cell and choose the `Delete` option that\nappears.\n\nimage::DeletingCue.png[Deleting a Cue,313,284]\n\nWARNING: Be careful with this: You can delete any cue this way, and if\nit was not a macro, the only way to get it back is to re-run the code\nthat created it in the first place.\n\n===== Ending Effects\n\nA running effect can be asked to end by clicking its kbd:[End] button.\nIf the effect takes a while to end, its entire row will take on the\ncolor of the kbd:[End] button while it is in the process of ending,\nand the button becomes a kbd:[Kill] button which can be clicked to\ninstantly terminate the ending effect:\n\nimage::EffectEnding.png[An Ending Effect,1002,246]\n\n[[scrolling-and-linked-controllers]]\n==== Scrolling and Linked Controllers\n\nThe show may have many more cues than fit on the screen at once; the\ndiamond of blue arrows below the bottom right of the cue grid allow\nyou to page through the larger grid. If there are more cues available\nin a given direction, that arrow will be enabled, otherwise it is\ndimmed. Clicking an active arrow scrolls the view one page in that\ndirection. In this grid, it is currently possible to scroll up and to\nthe right.\n\n[.right]\nimage::CueScrollLink.png[Cue scroll arrows and link menu,365,167]\n\nIf you hold down kbd:[Shift] while clicking a scroll arrow, it will\nscroll you as far as possible in the direction you clicked.\n\nYou can also use the arrow keys on your keyboard to scroll in the\ncorresponding direction. (Again, holding kbd:[Shift] will scroll you\nas far as possible in that direction.)\n\nIf you have any compatible grid controllers, Afterglow started\nwatching for them to be connected as soon as you called\n`(use-sample-show)`. If you are defining your own show and want to\nlearn more about how that works, or lower-level ways of binding to a\nspecific controller, see the\n<<mapping_sync.adoc#rich-grid-controller-mappings,details>> in the\nMapping and Sync section.\n\nWith auto-binding active, whenever a compatible grid controller is\nconnected and powered on, you will see a link menu appear next to the\nscroll diamond, as shown in the above screen image. The link menu\nallows the web interface to be tied to a grid controller, so that each\nis always looking at the same page of cues. Using the scroll arrows on\neither the web interface, or on the controller itself if it has them\n(the Push and Launchpad family do), will cause both to scroll\nsimultaneously. This provides an excellent additional layer of\ninformation about the buttons on the physical controller.\n\nTIP: Of course, there may be times you want to break this link, for\nexample so you could have access to one set of cues on the physical\nbuttons of your controller, while simultaneously being able to control\nothers via the screen and mouse. To do that, simply use the link menu\nto turn off the link.\n\n[[brightness-control]]\n==== Brightness Control\n\nIn the center of the interface below the cue grid is a slider that\nlets you adjust the show's dimmer grand master. This can be used to\ncontrol the overall brightness of the show, because any dimmer cues\nthat are running will be affected by the value of this master. If it\nis set at 100% (all the way to the right), the dimmer cues can operate\nat full brightness. As you slide it to the left, it gradually reduces\nthe maximum brightness that any dimmer cue can achieve. In the middle,\nall dimmer cues will be reduced by 50%, and all the way to the left,\nall dimmer cues will be zeroed out.\n\nimage::GrandMaster.png[Dimmer Grand Master,319,172]\n\n[[metronome-control]]\n==== Metronome Control\n\nThe final section of the show control interface, left of the Dimmer\nGrand Master section, lets you view and adjust the Metronome that the\nshow is using to keep time with the music that is being played. Since\nAfterglow's effects are generally defined with respect to the\nmetronome, it is important to keep it synchronized with the music. The\nmetronome section shows the current speed, in Beats Per Minute, of the\nmetronome, and the `Tap Tempo` button label flashes yellow at each\nbeat. It also shows you the current phrase number, the bar within that\nphrase, and beat within that bar which has been reached.\n\nimage::Metronome.png[Metronome,361,175]\n\nThe most basic way of synchronizing the metronome is to click the `Tap\nTempo` button at each beat of the music. Tapping the button aligns the\nmetronome to a beat, and if you tap it three or more times within two\nseconds of each preceding tap, sets the metronome's BPM. Tap it as you\nhear each beat of the music, and after three or more taps, the speed\nof the metronome will be approximately synchronized with the music.\nYou can also adjust the BPM by dragging the slider along the bottom,\nor fine-tune it with the `+` and `-` buttons around the current BPM\nvalue.\n\nOnce the tempo is correct, you can tell Afterglow which beat is the\ndown beat by holding down kbd:[Shift] while pressing kbd:[Tap Tempo].\n(The label of the button will change to kbd:[Tap Bar] while\nkbd:[Shift] is down). This combination does not change the tempo, but\ntells Afterglow that the moment when you tapped the button is the down\nbeat (the first beat of a bar).\n\nIn order to make longer chases and effects line up properly with the\nmusic, you will also want to make sure the count is right, that the\nbeat number shows `1` on the down beat, and that the bar numbers are\nright as well, so that the start of a phrase is reflected as bar\nnumber `1`. In addition to using kbd:[Shift] with kbd:[Tap Tempo] to\nset the down beat, you can adjust the count using the `+` and `-`\nbuttons around the Bar and Beat numbers.\n\nA shortcut that you can use right as a phrase begins is to click the\nred `x` button above the phrase number, which resets the metronome to\nPhrase 1, Bar 1, Beat 1.\n\nTrying to keep up with tempo changes during dynamic shows can be\ntedious, so you will hopefully be able to take advantage of\nAfterglow's metronome synchronization features. If you can get the DJ\nto feed you <<mapping_sync.adoc#syncing-to-midi-clock,MIDI clock\npulses>> or <<mapping_sync.adoc#syncing-to-traktor-beat-phase,Traktor\nBeat Phase>>, or connect via a Local Area Network to Pioneer\nprofessional DJ gear to lock into the beat grid established by\n<<mapping_sync.adoc#syncing-to-pro-dj-link,Pro DJ Link>>, Afterglow\ncan keep the BPM (with MIDI) and even the beats (with Traktor Beat\nPhase or Pro DJ Link) synchronized for you. To configure that\nsynchronization, click the `Sync` button once you have the MIDI clock,\nbeat phase, or network Pro DJ Link signals reaching the machine\nrunning Afterglow, and choose the sync source you want to use.\n\nimage::MetronomeSync.png[Metronome sync,1040,800]\n\nTIP: When you are synchronizing with Pro DJ Link, you will almost\nalways want to sync to the mixer, rather than one of the CDJs, so you\nstay in sync as the DJs mix between tracks.\n\nThe actual list of choices you will see depends on what MIDI and DJ\nLink Pro traffic Afterglow has seen in the last few seconds, and will\nupdate as players and mixers start and stop sending clock or beat grid\ninformation.\n\nOnce your sync is established, the `Tap Tempo` button changes. If you\nare using MIDI clock to sync the BPM, it becomes a `Tap Beat` button,\nwhich simply establishes where the beat falls. If you are locked in to\na Pro DJ Link or Traktor Beat Phase beat grid, it becomes a `Tap Bar`\nbutton which, when pressed, indicates that the current beat is the\ndown beat (start) of a bar. Similarly, if you press the metronome\nReset button (the red x above the phrase counter) while synced to a\nPro DJ Link or Traktor Beat Phase beat grid, the beat itself will not\nmove, but the beat closest to when you pressed the pad will be\nidentified as Beat 1. In these sync modes you can also use the\nkbd:[Shift] key to align at the next bigger boundary: If tapping\nwould normally move the bar, shift-tapping will move the phrase.\n\nimage::MetronomeSynced.png[Metronome synced,355,156]\n\nThe Sync button also turns green to indicate that sync is in effect.\nIf something interrupts the sync process (such as the network link\nbeing broken, or the DJ software's MIDI clock generator being turned\noff), the button will turn red to warn you that it is not working.\nPressing the Sync button again will give you more information to\ntroubleshoot the problem.\n\n[[getting-started]]\n== Getting Started\n\nThere is a lot to Afterglow, and already a lot of documentation. In an\neffort to help you find your way through it, here is a guide to the\nsteps you'll want to take to get a basic light show up and running.\nOnce you are there, you can branch off and explore extending it in any\ndirection you like, and hopefully contribute back the fixture\ndefinitions and new effects and cues you come up with!\n\n. If you don't know any Clojure, you are going to want to learn at\nleast a little. Luckily, it is a fantastic, helpful community, and an\namazing language (the existence of Afterglow after a couple of months\nof spare time work is good proof of that)! The\nhttp://clojure.org/getting_started[Getting Started] page on\nclojure.org has links to some great resources.\nhttps://www.maria.cloud[Maria] is an interactive, online workbook for\nbeginners that provides progressive instruction in the language. And\ndon't miss http://www.braveclojure.com[Clojure for the Brave and\nTrue], a fun book under development which can be read in its entirety\nonline.\n\n. Install Afterglow. For now the best way to do that is following the\nsteps in the\nhttps://github.com/Deep-Symmetry/afterglow#installation[Installation]\nsection on the main project page, to install the Open Lighting\nArchitecture, then create a new Clojure project with Leiningen that\nincludes Afterglow as a dependency.\n\n. Set up your universe(s) in OLA. Their own\nhttps://www.openlighting.org/ola/getting-started/[Getting Started]\npage may be helpful. Until OLA is successfully communicating with your\nlights, whether over a USB DMX interface, Artnet over a LAN, or the\nlike, Afterglow will not be able to control them. Even though their\nexamples show using the command-line tools to configure your\ninterface, today you will likely find the web interface, especially\nthe beta new UI, much more convenient and easy to learn. With a\ndefault installation, once you have `olad` running, you can find that\nat http://localhost:9090/new/[http://localhost:9090/new/].\n\n. Find or create <<fixture_definitions.adoc#,fixture definitions>>.\nOnce you are able to get your lights to do things by manipulating the\nFaders section of the OLA web interface, it is time to get Afterglow\nready to talk to them. There are a vast number of fixture types out\nthere, and at this early stage almost none of them are built in to\nAfterglow, so you will probably need to create your own. The\n<<fixture_definitions.adoc#,documentation>> explains how, and links to\nexisting fixture definitions as examples. You can also ask for help on\nthe https://deep-symmetry.zulipchat.com/#narrow/stream/318697-afterglow[Zulip chat] or the\nhttps://github.com/Deep-Symmetry/afterglow/wiki/Questions[Wiki]. + At\nthis point you are almost certainly writing enough code that you want\nto save it for later reuse. The\nhttps://github.com/Deep-Symmetry/afterglow#usage[Usage] section of the\nproject page explains how you can have Afterglow load files when it\nstarts up when you are running it as a standalone jar, which makes it\neasier to use your own configuration files. + . Patch your actual\nfixture channels and locations. Once you have working definitions for\nyour fixtures, you will want to create a show that tells Afterglow\nwhat fixtures you have, and the DMX universes and channels you have\nthem connected to, and how you have them arranged in physical space.\nYou will want to create a namespace for your show along the lines of\n{api-doc}afterglow.examples.html[`afterglow.examples`], and a function\nlike\n{api-doc}afterglow.examples.html#var-use-sample-show[`use-sample-show`]\nwhich sets up your own show.\n\n. Create the cues you want. Much as the\n{api-doc}afterglow.examples.html#var-make-cues[`make-cues`]\nfunction in the examples namespace creates a bunch of cues that work\nwith the sample show's fixtures, you will want cues that create\neffects to make your lights do interesting things, and which are\narranged, labeled, and colored in a way that makes sense to you.\n\n. Map some cues to a controller, if you have one. If you have an\nAbleton Push, you are in luck because you will be able to take\nadvantage of the built in <<push2.adoc#,support>> Afterglow offers. Or\nperhaps a <<launchpad.adoc#,Novation Launchpad>>? But even if you just\nhave a simple MIDI controller with a few buttons and faders, or even a\nkeyboard, you can <<mapping_sync.adoc#,map>> keys, buttons, and faders\nto trigger cues and adjust variables used by the cues.\n\n. Run the show! With or without a physical controller, you can create\nyour show by calling the function you wrote modeled on\n`use-sample-show`, then bring up the <<web-ui,embedded web interface>>\nto trigger your cues and watch the results.\n\n. Create your own custom effects if you want to be fancy. Once you\nfeel constrained by the limits of the <<effects.adoc#,effects>> that\nare built in to the current release of Afterglow, the whole point of\nthe environment it offers is to enable people to imagine and create\nbrand new effects. You have the full power of the language used to\ncreate Afterglow at your fingertips at every moment to create and\nexplore new ideas; you are not constrained to the limited scripting\nenvironment that most lighting control software offers, if it offers\nany at all.\n\n. Don't forget to contribute your fixture definitions and effects to\nthe Afterglow community! If you are confident that you have fully\nmapped out the functions of a fixture, please make a pull request to\ninclude it in afterglow, either within the existing namespace for its\nmanufacturer, or creating a new namespace for a new manufacturer.\nSimilarly, if you have created an awesome new kind of effect, please\nconsider a pull request to add it somewhere within the effects\nnamespace hierarchy. And if you are just tinkering with something new\nand experimental, please post about it on the\nhttps://deep-symmetry.zulipchat.com/#narrow/stream/318697-afterglow[Zulip\nchat]!\n"
  },
  {
    "path": "doc/modules/ROOT/pages/color.adoc",
    "content": "= Working with Color\nJames Elliott <james@deepsymmetry.org>\n\nCues that assign color to lights are designed to leverage the\nhttps://github.com/jolby/colors[jolby/colors] library. In addition to\ncreating colors by name, as in the Usage examples, you can create them\nby hex string, RGB values, and, most usefully when thinking about how to\nmix and fade them, http://en.wikipedia.org/wiki/HSL_and_HSV[HSL] (Hue,\nSaturation, and Lightness). So, if you wanted a cue that shifts back and\nforth around yellow, and don't remember the hue value of yellow, you\ncould do something like this:\n\n[source,clojure]\n----\n(use 'com.evocomputing.colors)\n(def yellow (create-color \"yellow\"))\n(def hue-param (oscillators/build-oscillated-param\n  (oscillators/sine) :min (hue (adjust-hue yellow -5))\n                     :max (hue (adjust-hue yellow 5))))\n(show/add-effect! :color (global-color-effect\n  (params/build-color-param :s 100 :l 50 :h hue-param)))\n----\n\nYou can add lighten it up by changing to something like `:l 70` in the\n`build-color-param` call, darken it a bunch with `:l 20` or desaturate\nit a touch with `:s 80`... For more options and ideas, delve into the\ncolors library http://jolby.github.io/colors/[API documentation],\nand the various <<oscillators.adoc#,oscillators>> that Afterglow\nmakes available to you.\n\nSince working with colors is so fundamental to creating light shows,\nthe mechanism for creating <<parameters.adoc#color-parameters,dynamic color\nparameters>> is very well developed, and worth getting familiar with.\nYou can often avoid having to write your own function entirely by\nclever combinations of oscillated parameters for creating dynamic\ncolor parameters.\n\n[[thinking-in-hsl]]\n== Thinking in Hue, Saturation, and Lightness\n\nIf you are not accustomed to working with colors in the HSL space, it\nis definitely worth spending a little time becoming familiar with it,\nbecause it is a powerful way of expressing relationships between\ncolors in ways that are visually sensible and pleasing. The\nhttp://en.wikipedia.org/wiki/HSL_and_HSV[Wikipedia article] is a nice\nreference, with diagrams. Please spend a little time reading it. This\nis the way that Afterglow works with colors when it is fading\n(blending) between them, and many of the sample cues and effects use\nHSL relationships to achieve pretty and interesting results.\n\nIn a nutshell, a color in HSL is represented by three numbers:\n\nHue::\n\n  Identifies a specific pure color, as an angle in degrees around the\n  color wheel. Red is at 0, green is at 120, and blue at 240; values\n  in between these are a linear mixture between the colors, and as the\n  value increases towards 360 it returns to red.\n\nSaturation::\n\n  Specifies how pure the color is. A saturation of 100 means it is\n  fully pure, while a saturation of 0 is completely achromatic (gray).\n\nLightness::\n\n  Specifies how white the color is. A lightness value of 100 is pure\n  white, while 0 is pure black. At these extremes the saturation can't\n  affect the color, it is always achromatic anyway. A lightness of 50\n  lets the color \"be itself\" when fully saturated. Lightnesses above\n  fifty start to whiten it, while those below fifty blacken it.\n\n[[modifying-colors]]\n== Modifying Colors\n\nYou can also create a variety of layered looks by building effects\nthat work with each other, rather than having to create a separate\neffect for each combination. The discussion on\n<<effects.adoc#layering-effects,layering effects>> explains how to do\nthis and points at a sample implementation that ships with Afterglow.\n\n[[colors-and-cues]]\n== Colors and Cues\n\nWhen you create a cue that assigns a color to a group of lights, you\ncan take advantage of Afterglow's rich user interfaces for picking\ncolors to let the operator tweak that color during the show, simply by\nmaking the color a <<cues.adoc#cue-variables,cue variable>>.\n\nEven if you are creating a cue to simply assign a fixed color to a\ngroup of lights, it is worth setting that color up as a cue variable,\nbecause it will allow the show operator to adjust the color in a very\nconvenient way when running the show. The\n{api-doc}afterglow.examples.html#var-global-color-effect[`global-color-effect`]\nfunction in the `examples` namespace provides an example of how to do\nthis (click the kbd:[view source] link below the description to see\nhow it is done).\n\nYou may also want to have a group of cues which share a same basic\ncolor, like the strobe cues do in the sample show. In that case,\nrather than having a color variable that exists only within the cue,\nyou will want to set up a show variable to contain the color, and have\neach cue share the same show variable as a cue variable. The\n{api-doc}afterglow.examples.html#var-make-strobe-cue[`make-strobe-cue`]\nfunction in the `examples` namespace shows how to do this (again click\nthe kbd:[view source] link below the description to see how it is\ndone). All of the strobe cues in the sample show use the same color,\nand if you adjust that color while one is running, the cue cells\nwithin the web interface and on the Ableton Push and Novation\nLaunchpad Pro will update to show the new color you have chosen, and\nit will be used when you press any of them.\n\nIn order to let you adjust the strobe color even when no strobe cue is\nrunning, the sample show also sets up a &ldquo;Strobe Color&rdquo;\ncue. All it does is run a\n{api-doc}afterglow.effects.html#var-blank[`blank`] effect, while\nbinding a cue variable to the show variable that is being used to set\nstrobe colors, so that you can run the cue to adjust the color without\nfiring any strobes:\n\n[source,clojure]\n----\n(let [color-var {:key :strobe-color :type :color :name \"Strobe Color\"}]\n      (ct/set-cue! (:cue-grid *show*) 7 6\n                   (cues/cue :strobe-color (fn [_] (fx/blank \"Strobe Color\"))\n                             :color :purple\n                             :color-fn (cues/color-fn-from-cue-var color-var)\n                             :variables [color-var])))\n----\n\nThis example also shows how to use the cue `:color-fn` key to\nconfigure the cue grid to display the cue using the current value of\nthe color variable associated with it, as an additional aid to the\nshow operator.\n"
  },
  {
    "path": "doc/modules/ROOT/pages/cues.adoc",
    "content": "= Cues\nJames Elliott <james@deepsymmetry.org>\n\nCues are designed to support creating user interfaces for controlling\neffects. They provide a convenient way to organize, identify, trigger,\nadjust, and monitor effects. Each {api-doc}afterglow.show.html[`show`]\nin Afterglow maintains a cue grid, which can be viewed and interacted\nwith through the <<README.adoc#web-ui,embedded web interface>> and\nMIDI controller mapping implementations which can be\n{api-doc}afterglow.show.html#var-register-grid-controller[registered\nas grid controllers], like the <<push2.adoc#,Ableton Push>> and\n<<launchpad.adoc#,Novation Launchpad family>>.\n\n[[the-cue-grid]]\n== The Cue Grid\n\nThe cue grid is a two dimensional arrangement of cues, where the\nbottom left corner is assigned coordinates `(0, 0)`. X coordinates\nincrease from left to right, and Y coordinates increase from bottom to\ntop. The web interface and registered grid controllers display 64 cues\nat a time in an 8&times;8 grid, and can be scrolled around that grid.\nThe user can configue (&ldquo;link&rdquo;) the web interface to track\nthe scroll position of a registered grid controller. When that is\ndone, scrolling either interface will cause the other to scroll in the\nsame way, so the browser window can act as documentation to help the\nuser learn the cue names associated with each available cue pad on the\ncontroller.\n\nimage::ShowGrid.gif[Web interface,998,912]\n\nIn addition to names, cues can be assigned colors in the grid, and the\nweb interface will honor those colors, as will the physical grid\ncontrollers, within the limits of their capabilities. To provide\nfeedback about cue activation, a lightened version of the cue color is\ndisplayed for cues which are currently active. And to help inform the\nuser about cue compatibility, any cues which would cause a running\neffect to end (either because they are assigned the same effect\nkeyword, or they mention that keyword in their `:end-keys` list) will\nbe displayed in a darkened color.\n\nExamples of these features can be seen in the animation above, in\nwhich the first two rows of color cues are all mutually exclusive,\nwhile the four rows of dimmer cues above them have a more complex\ninterrelationship: The &ldquo;All Dimmers&rdquo; cues in the leftmost\ncolumn darken the entire rectangle of dimmer cues, while individual\nfixture dimmer cues to their right darken their just their own columns\nas well as the \"all\" cues. On the blue/green page of Torrent gobo\ncues, you can see how each gobo wheel cue dims other cues which\nuse the same fixture and gobo wheel while it is active.\n\nThis is a useful technique for building easy-to-learn cue grids. A\nslightly older version of the same cues are shown on the Ableton Push\nbelow, so you can see how the color relationships help with learning\nthe cue names.\n\nimage::AbletonInterface.jpg[Ableton Push interface,800,637]\n\nTo trigger a cue, simply press the corresponding pad on a physical\ninterface, or click within the grid cell in the web interface. The\neffect associated with the cue will be created and added to the show,\nand the grid cell will be lightened to indicate that the cue's\neffect is running. If the cue ends itself after a period, the grid\ninterface will be updated to reflect that as well.\n\nTo end a cue's effect before it would naturally end (or because\nit is open-ended and does not end until asked to), simply press the\npad corresponding to the running cue (or, again, click the grid cell\nin the web interface). The effect will be asked to end. Some effects\nend instantly, which will be refleced by the cue grid cell returning\nto its normal color. Some effects have a delayed ending, so they can\nfade out, or finish some musically relevant sequence. If this is\nhappening, the grid cell will blink while the effect ends, and then\nstay at its normal color once the effect finishes ending. If you want\nthe effect to end immediately you can press the pad one more time\nwhile the effect is performing its gradual ending, and it will be\nkilled at that point, regardless of how much longer it was planning to\nrun.\n\n[[held-flag]]Cues can also be created which run only as long as the\ncorresponding controller pad is held down (this is done by passing a\ntrue value with the `:held` optional keyword argument when creating\nthe cue). This is often done for intense effects like strobes.\n\nCues can also offer pressure sensitivity on controllers which support\nthis (like the Ableton Push and Novation Launchpad Pro). For such\ncues, one or more variable used by the cue can be updated by the\nstrike and aftertouch pressure exerted by the operator as they hold\ndown the pad. This can make for very expressive effects, as\nexemplified by the Sparkle cue set up early in the examples\nnamespace's\n{api-doc}afterglow.examples.html#var-make-cues[`make-cues`] function,\nand its {api-doc}afterglow.examples.html#var-make-strobe-cue[strobe]\ncues. Of course, this pressure sensitivity is not possible with the\nweb cue grid.\n\nThe interface for moving around the cue grid is the diamond of arrows\nat the bottom right of both the web interface and the Ableton Push. If\nthere are more cues available in a particular direction, that arrow is\nlit, otherwise it is dark. For the cues pictured above, the bottom\nleft corner of the cue grid is being displayed, and there are more\ncues above and to the right, so the up and right scroll arrows are\nlit. Pressing an arrow scrolls to the next set of eight rows or\ncolumns in that direction. (And if the web view is linked to a grid\ncontroller, pressing the arrow on either will scroll both. For\nphysical grid controllers which lack scroll buttons, linking them to\nthe web interface is the most practical way of scrolling them.)\n\nCues can also be triggered from simpler MIDI controllers (which\ndon't register as grid controllers) by explicitly mapping notes\nor control changes sent by the controller to cues within the grid\nusing\n{api-doc}afterglow.effects.cues.html#var-add-midi-to-cue-mapping[`afterglow.effects.cues/add-midi-to-cue-mapping`].\nRegardless of the mechanism by which a cue is triggered, the web\ninterface, a registered grid controller, or an explicitly mapped MIDI\nnote or control change, feedback will be sent to all interfaces so the\nstatus of the cue will be represented consistently on all of them. And\na cue triggered on one controller can be ended on any other controller\nby simply pressing the lit button or clicking the lit cell there.\n\nFor example, to be able to trigger the Sparkle cue, which the examples\nnamespace places at `(0, 7)` within the sample show cue grid, by\npressing the bottom leftmost button on my inexpensive Korg nanoKontrol\n2 MIDI controller, after using\n{api-doc}afterglow.midi.html#var-identify-mapping[`afterglow.midi/identify-mapping`]\nto determine that the button sends control-change messages for\ncontroller number `43`, I can simply evaluate:\n\n[source,clojure]\n----\n(cues/add-midi-to-cue-mapping \"nano\" 0 :control 43 0 7)\n----\n\nNow I can press the top-left pad on the Push, click the top left cell\nin the Web interface, or press that button on the nanoKontrol, and the\nSparkle cue lights up on all three interfaces, and the effect runs and\nsparkles the lights.\n\n[NOTE]\n====\n\nIn order to enable Afterglow to send feedback about cue status to the\nlights on the nanoKontrol I needed to use the Korg Kontrol Editor to\nset its LED Mode to _External_ (as shipped, they were in _Internal_\nmode, and lit themselves when held down). Most MIDI controllers are\nlikely to need similar configuration to work as feedback-capable cue\ncontrollers with Afterglow, but most I have seen do offer\nconfiguration tools to enable this kind of external control.\n\n====\n\n[[creating-cues]]\n== Creating Cues\n\nThe {api-doc}afterglow.effects.cues.html[`afterglow.effects.cues`]\nnamespace provides functions for creating cues. Unsurprisingly, the\n{api-doc}afterglow.effects.cues.html#var-cue[`cue`] function creates a\ncue. At its most basic, you pass in two parameters, `show-key` which\nis the keyword that will be used to add the cue's effect to the show\nwhen the cue is triggered, ending any other effect running under that\nsame keyword, and `effect-fn`, which is a function that will be called\nwhen the cue is triggered, and whose responsibility is to create and\nreturn the effect that the cue should add to the show. This is done so\nthat a fresh instance of the effect is used each time the cue is\ntriggered, in case the effect is complex and maintains its own state.\n`effect-fn` will be passed a map containing any\n<<cue-variables,cue-specific variable bindings>>.\n\nNOTE: For the very common case of wanting to create a cue to activate\na fixture-specific _function_ (capability), and perhaps adjust the\nfunction's activation level while it runs, you can instead call the\nspecial-purpose `function-cue` described\n<<creating-function-cues,below>>.\n\nThere are a number of optional keyword parameters which can be used to\nmodify the cue that is created. Remember that you can also consult the\n{api-doc}afterglow.effects.cues.html#var-cue[API\ndocumentation] for another explanation of these functions, and for\nlinks to examine the source code, which is the most authoritative\nexplanation of how they work, and can offer inspiration for variations\nthat you might want to create yourself.\n\n[cols=\"1a,1a,5a\", options=\"header\"]\n.Keyword parameters to `cue`\n|===\n|Parameter\n|Default\n|Purpose\n\n|`:short-name`\n|effect name\n\n|Sets the text to be displayed for the cue in the web cue grid, and in\nthe text display of the controller (if it has one) when the cue is\nrunning. If you don't supply a short name, the name of the\neffect created by the `effect-fn` function is used, but that may be too\nlong or not informative enough.\n\n|`:color`\n|white\n\n|Sets the color of the cue within the grid for hinting about its\npurpose and relatedness to other cues, to help operators learn and\nunderstand the interface. If not specified, white is used.\n\n|`:color-fn`\n|none\n\n|Specifies a function to call to obtain the current color to use for\nthe cue within the grid, so that an dynamic/animated color can provide\neven more intense hinting about its purpose and relatedness to other\ncues, to help operators learn and understand the interface. If not\nspecified, the static value specified by `:color` is used.\n\nThe function provided will be called whenever the grid interface is\nbeing updated, and will be called with four arguments: the `cue` whose\ncurrent color is desired; the map describing the currently active\n`effect` that was launched by that cue, if any; the `show` in which\nthe cue and effect exist; and the metronome `snapshot` representing\nthe moment in time at which the interface is being rendered. The\nfunction can use this information to calculate and return a color\nvalue, which will be used to draw the cue in the interface, or it can\nreturn `nil`, in which case the static `:color` value will be\ndisplayed instead.\n\nHelper functions exist to create cue color functions for commonly\nuseful situations.\n{api-doc}afterglow.effects.cues.html#var-color-fn-from-cue-var[`afterglow.effects.cues/color-fn-from-cue-var`]\nreturns a function that causes the cue to appear in the same color as\na cue color parameter, whenever the cue is running and that parameter\nhas a value. Similarly,\n{api-doc}afterglow.effects.cues.html#var-color-fn-from-param[`afterglow.effects.cues/color-fn-from-param`]\ncauses the cue to appear in whatever color is returned by evaluating\nthe specified dynamic parameter at that point within the show. The\nsource code of those helper functions are good examples of how to\ncreate dynamic cue color functions, and the source of the\n{api-doc}afterglow.examples.html#var-make-strobe-cue-2[`make-strobe-cue-2`]\nfunction in the examples namespace shows how the strobe cues are\nconfigured to flash between current color of the `:strobe-color` show\nvariable and white to emphasize their strobe nature.\n\nNOTE: When assigning a color to a cue in the user interface, the\nlightness of the color has no effect, because that is assigned by the\ncontroller to indicate the cue state, so you will need to use changes\nin hue and saturation for your animation.\n\n|`:end-keys`\n|none\n\n|A list of keywords that identify additional effects to be ended when\nlaunching this cue. See the dimmer cue section of\n{api-doc}afterglow.examples.html#var-make-cues[`make-cues`]\nfor an example of how this can be helpful: it sets up a couple of rows\nof dimmer cues where the leftmost affects all the dimmers in the\nlighting rig, and cancels all the cues that work on individual light\ngroups, while the individual light group dimmer cues cancel the\nall-dimmers cues, but leave the dimmer cues for other light groups\nalone.\n\n|`:priority`\n|`0`\n\n|Sets the effect priority used when adding the cue's effect to the\nshow. This can be used to make sure the effect runs before or after\nother effects in the <<rendering_loop.adoc#,rendering loop>>. Effects\nare run in order, and later effects can modify or override the results\nof earlier ones, like the way the Sparkle effect in\n{api-doc}afterglow.examples.html#var-make-cues[`make-cues`] is\nassigned a priority of 100 so it sorts after any chase which may be\nrunning, and its sparkles can lighten the color which would otherwise\nbe present in their fixtures.\n\n|`:held`\n|`false`\n\n|As described <<held-flag,above>>, causes the cue's effect to run only\nas long as the corresponding controller button or pad is held down, if\nthe controller supports that capability. All current controller\nimplementations, including the web interface, the\n<<push2.adoc#,Ableton Push mapping>>, and mappings to generic MIDI\ncontrollers created using\n{api-doc}afterglow.effects.cues.html#var-add-midi-to-cue-mapping[`afterglow.effects.cues/add-midi-to-cue-mapping`]\ndo honor this setting. The web interface and controllers like the\nPush, which can vary the color of cue grid cells, will provide\nfeedback that a cue will last only as long as it is held by displaying\na whitened version of the cue color while it is held down.\n\nShow operators can override the `:held` flag by holding down the\n`Shift` key when triggering the cue on interfaces which have `Shift`\nkeys (like the web interface and Ableton Push). This will cause the\ncue to run until the corresponding pad or grid cell is pressed again,\nand will not whiten the cue color while it is held down.\n\n|`:variables`\n|none\n\n|Specifies a sequence of show variable bindings that can be used by\nthe cue's effect. Each variable specification is a map, whose content\nis described in the following table. These specifications are used to\ncreate any necessary new variables, and a `var-map` describing any\ncue-local variables is passed to the `effect-fn` function when the cue\nis triggered, so they can be used as needed when creating the cue's\neffect. See <<cue-variables>> below for many more details.\n\n|`:visualizer`\n|none\n\n|A visualizer creation function that will be called by controllers\n with animated graphical displays like the Push 2. It will be passed\n two arguments, the cue's `var-map` and the `show` in which the cue is\n running. It must return another function which takes a metronome\n snapshot and returns a value between 0 and 1 representing a\n meaningful numerical summary of the cue state at that time.\n\nWhen supplied, this function will be used to create a moving strip\nchart of the cue's activity around the current moment on the display.\nThe example dimmer oscillator cues like\n{api-doc}afterglow.examples.html#var-make-sawtooth-dimmer-cue[make-sawtooth-dimmer-cue]\nshow how this can be used effectively.\n\nimage::blade-saw.gif[Visualizer function in action,240,160]\n\n|===\n\nThe ability to create animated cue colors in a grid controller\ninterface via the `:color-fn` key described above can come in handy\nwhen there are a lot of cues and you want some to stand out to the\noperator, but there are contexts in which it might be gratuitous or\ndistracting; the example strobe and rainbow-shifting cues provided\nwith Afterglow might tend toward that extreme. So you don't need to\nuse it, but you can if it makes sense.\n\nIt is hard to argue against the usefulness of a dynamic color that is\ntied to a show variable, however, like the `:strobe-color` example, or\neven a cue parameter, like the example global color cues, because this\napproach updates the grid controller interface to reflect a color\nchosen by the user, and so provides valuable information in a\nnon-distracting way.\n\n[[cue-variables]]\n=== Cue Variables\n\nAs noted above, a cue can contain a map under the key `:variables`\nwhich assigns variables to the cue. These variables allow the cue to\nbe adjusted by the show operator in convenient and powerful ways,\neither through the interfaces automatically presented by the Effect\nControl sections of the <<README.adoc#effect-control,embedded Web\ninterface>> or <<push2.adoc#effect-control,Ableton Push mapping>>,\nthrough velocity-sensitive grid controllers like the Push or\n<<launchpad.adoc#,Launchpad Pro>>, or a binding to\n<<mapping_sync.adoc#mapping-cues-to-a-controller,any\nvelocity-sensitive MIDI controller>>.\n\nCue Variables can either be numeric (adjusted by sliders in the web\nUI, or rotary encoders and faders on MIDI controllers), boolean (with\ncorresponding simple Web and Push interfaces) or they can store\ncolors, in which case both the web UI and\n<<push2.adoc#color-cue-variables,Push mapping>> provide a powerful\ninterface for picking and adjusting the color.\n\nThey can also be temporary, lasting only the duration of the cue, or\ntied to a {api-doc}afterglow.show.html#var-set-variable.21[show\nvariable], so they can be shared between cues, and have values which\nlast between activations of the cue. Color variables which are stored\nas show variables can be adjusted by\n<<mapping_sync.adoc#mapping-a-control-to-a-color-component,any MIDI\ncontroller>>.\n\n[cols=\"1a,1a,5a\", options=\"header\"]\n.Cue variable specification maps\n|===\n|Key\n|Default\n|Purpose\n\n|`:key`\n|_n/a_\n\n|Identifies the variable that is being bound to the cue. This can\n either be a keyword, and refer to an existing show variable (set\n using\n {api-doc}afterglow.show.html#var-set-variable.21[`afterglow.show/set-variable!`]),\n or a string, meaning that a new variable should be introduced for the\n cue. The actual name of this new variable will be assigned when the\n cue is activated. In order for the effect to be able to access the\n correct variable, a map is passed to the `effect-fn` function that\n creates the cue's effect. Within this map, the keys are keywords\n created from the strings passed as `:key` values in the cue's\n variable specification maps, and the corresponding values are the\n keyword of the variable that was created for the cue to go with that\n key. An example of using such cue-local variables can be found in the\n source of the\n {api-doc}afterglow.examples.html#var-make-strobe-cue[`make-strobe-cue`]\n example, for the variable `level`. That cue also makes use of the\n independent show variable `:strobe-color`, so that changing it in any\n strobe effect changes it for all of them. The color can also be set\n by a separate `:strobe-color` cue running a\n {api-doc}afterglow.effects.html#var-blank[`blank`] effect, so you can\n preconfigure the color while no strobes are running. These are\n intended to be a demonstration of interacting cues.\n\n|`:start`\n|`nil`\n\n|When not `nil`, specifies the value to assign to the variable when\n the cue starts. Most important when the value at `:key` is a string\n rather than a keyword, so a variable is being created just for the\n cue, because otherwise the variable will start out empty, and\n whatever effect parameter is using it will fall back to its default\n value. But you can also assign starting values to cue variables that\n are bound to regular show variables, and they will get set when the\n cue starts. You will probably not want to do that in cases where you\n are using a shared variable to adjust the appearance of many cues,\n unless you want the start of this cue to affect them all.\n\nIf the value of `:start` is a keyword, this cue variable will be\ninitialized with the value held in the show variable by that name when\nthe cue begins. If it is a function, that function will be called when\nthe cue starts to determine the starting value of the variable.\nOtherwise, the value is simply copied to the variable.\n\n|`:name`\n|variable name\n\n|Provides a name to identify the variable in the web interface and in\n the text area of physical controllers which provide a labeled\n interface for adjusting running effects, like the Ableton Push. If no\n name is supplied, the name of the value passed with `:key` is used;\n provide `:name` in cases where that would be insufficiently\n descriptive.\n\n|`:short-name`\n|none\n\n|If present, gives a shorter version of `:name` to be used in\n interfaces with limited space.\n\n|`:min`\n|`0`\n\n|Specifies the smallest value that the variable can be adjusted to, for\n interfaces which support adjustment of cue variables while the cue is\n running. If not supplied, the minimum value will be zero.\n\n|`:max`\n|`100`\n\n|Specifies the largest value that the variable can be adjusted to, for\n interfaces which support adjustment of cue variables while the cue is\n running. If not supplied, the maximum value will be one hundred.\n\n|`:type`\n|`:double`\n\n|Provides a hint for how the variable should be formatted in\n adjustment interfaces. Supported values are `:integer`, `:double`,\n `:boolean`, and `:color`. Others may be added in the future. If not\n provided (or an unrecognized value is provided), the variable is\n assumed to hold double-precision floating-point values.\n\n|`:centered`\n|`false`\n\n|Requests that variable adjustment interfaces which draw a graphical\n representation of the current value within its range display this\n variable as a deviation from a central value, rather than something\n growing from the left, if they have such options.\n\n|`:resolution`\n|_varies_\n\n|Specifies the smallest amount by which the variable should be\n adjusted when the user is turning a continuous encoder knob. If not\n specified, the controller implementation gets to decide what to do.\n The recommended default resolution is no larger then 1/256 of the\n range from `:min` to `:max`.\n\n|`:velocity`\n|`false`\n\n|If present, with a true value, requests that the variable value be\n adjusted by strike and aftertouch pressure while the operator is\n holding down the button or pad which launched the cue, on controllers\n which have pressure sensitivity.\n\n|`:velocity-min`\n|`:min`\n\n|If present (and `:velocity` is active), specifies the smallest value\n the variable should be set to by MIDI strike velocity and aftertouch\n pressure. If not specified, the standard `:min` value is used.\n\n|`:velocity-max`\n|`:max`\n\n|If present (and `:velocity` is active), specifies the largest value\n the variable should be set to by MIDI strike velocity and aftertouch\n pressure. If not specified, the standard `:max` value is used.\n\n|===\n\n==== Using Cue Variables\n\nThe purpose of cue variables is to define a user interface for the\nshow operator, either in the web interface, or on a rich MIDI\ncontroller like the Ableton Push. The web UI and controller\nimplementations look at the variable specifications as you have set\nthem up, and build interface elements accordingly when the cue is\nrunning. The running effect looks up the variable values when it needs\nthem, and adjusts itself appropriately.\n\nIf the cue is configured to use any temporary variables (which are\nindicated by using strings rather than keywords for their `:key`\nentry), the effect needs to know how to look them up. That's the\npurpose of the `var-map` argument which gets passed to `effect-fn`. It\ncontains a mapping from the keyword version of the temporary\nvariable's name to the actual keyword of the temporary variable that\nwas created to hold its value for the duration of the cue.\n\nFor example, a cue with a temporary variable named \"color\", defined by\nincluding `:key \"color\"` in the cue variable specification, might be\nassigned a temporary variable with the actual name\n`:cue-3-9-temp-color`. The `var-map` passed to `effect-fn` would have\nan entry `:color :cue-3-9-temp-color` to let it know about this\nassignment. So `effect-fn` can find the actual variable keyword to use\nfor its effects that want to access its `:color` variable by looking\nup that keyword in `var-map`\n\n[source,clojure]\n----\n(:color var-map)\n----\n\nThe above function call would return `:cue-3-9-temp-color` in this\nexample scenario.\n\nThere are many examples of cues using permanent and temporary\nvariables in the `afterglow.examples` namespace. Several of them take\nadvantage of the helper function\n{api-doc}afterglow.effects.cues.html#var-apply-merging-var-map[`apply-merging-var-map`]\nwhich provides a very convenient shortcut: If the effect that you want\nto call makes use of keyword arguments, name your temporary cue\nvariables the same as those keyword arguments, and you can then simply\nuse `apply-merging-var-map` to build the function call to the effect,\npassing in the cue variables (and their values) as the keyword\narguments and values that configure the effect.\n\n\n[[a-cue-example]]\n==== A Cue Example\n\nAs a simple illustration, here is how to wrap the blue and red scene\nfrom the <<effects.adoc#multiple-colors,Multiple Colors example>> into a\ncue, and add it to the show grid, so it can be started and stopped\nfrom a grid controller or the web interface. This cue has no\nvariables, so the effect-creation function ignores its argument (this\nis reflected by using the conventional Clojure “don't care” name for\nit, `_`, rather than `var-map`):\n\n[source,clojure]\n----\n(ct/set-cue! (:cue-grid *show*) 0 17\n  (cues/cue :color  (fn [_]\n                      (afterglow.effects/scene\n                        \"Blue and red 2\"\n                        (afterglow.effects.color/color-effect\n                          \"Plain red\" (create-color \"red\") (show/fixtures-named \"odd\"))\n                        (afterglow.effects.color/color-effect\n                          \"Plain Blue\" (create-color \"blue\") (show/fixtures-named \"even\"))))))\n----\n\n\n[[creating-function-cues]]\n== Creating Function Cues\n\nOften you want a cue to activate a specific feature of a fixture\n(often described as a _function_ in the fixture manual, and in the\nfixture definition within Afterglow, which can unfortunately get\nconfusing when we are talking about invoking Clojure functions). To\nmake it easy to work with such fixture capabilities, the\n`afterglow.effects.cues` namespace also offers the\n{api-doc}afterglow.effects.cues.html#var-function-cue[`function-cue`]\nfunction. It is quite similar to the `cue` function described\n<<cues.adoc#creating-cues,above>>, but it takes care of creating the effect\nfor you, given the function name you want to apply to a fixture or set\nof fixtures. You can even apply the function to fixtures from\ndifferent manufactures, regardless of whether they implement it on\ndifferent channels and with different value ranges. If it has been\nassigned the same function name (such as, for example, `:strobe`),\nAfterglow will find it in each fixture definition, and send the right\nvalues to each fixture.\n\nNOTE: Function cues are able to figure out how to do the right thing\nfor each fixture because they can scan the fixture definitions for\n<<fixture_definitions.adoc#function-specifications,Function\nSpecifications>> matching the keyword you gave when creating the cue.\nWhen you patch a fixture into a show, Afterglow indexes its function\nranges in order to make this efficient.\n\n`function-cue` also automatically creates a temporary cue-local\nvariable for <<push2.adoc#effect-control,adjusting>> the function\nlevel if the function is not fixed over its range. This makes it\nessentially a one-liner to create a button in your cue grid which\nactivates a function and then, via the web interface or if your\ncontroller supports it, lets you tweak that function while is running.\nExamples include the Torrent gobo, focus, and prism cues created by\n{api-doc}afterglow.examples.html#var-make-cues[`make-cues`].\n\nMinimally, `function-cue` requires three parameters: `show-key` which\nis the keyword that will be used to add the cue's effect to the show\nwhen the cue is triggered, ending any other effect running under that\nsame keyword, `function`, which is the keyword identifying the\nfixture-specific capability that you want the cue to activate and\ncontrol, as defined in the fixture definition, and `fixtures`, which\nis the list of fixtures or heads that you want the cue to affect.\n(Only fixtures and heads which actually support the specified function\nwill be affected by the cue.)\n\nThere are a number of optional keyword parameters which can be used to\nmodify the cue that is created, and are described below. See the\n{api-doc}afterglow.effects.cues.html#var-function-cue[API\ndocumentation] for more details.\n\n[cols=\"1a,1a,5a\", options=\"header\"]\n.Keyword parameters to `function-cue`\n|===\n|Parameter\n|Default\n|Purpose\n\n|`:effect-name`\n|function name\n\n|Sets the name to assign the effect created by the cue. If none is\n provided, the name of the `function` keyword is used.\n\n|`:short-name`\n|none\n\n|Can be used to provide a shorter name to be displayed for the cue in\nthe web cue grid, and in the text display of the controller (if it has\none) when the cue is running.\n\n|`:color`\n|white\n\n|Sets the color of the cue within the grid for hinting about its\npurpose and relatedness to other cues, to help operators learn and\nunderstand the interface. If not specified, white is used.\n\n|`:color-fn`\n|none\n\n|Specifies a function to call to obtain the current color to use for\nthe cue within the grid, so that an dynamic/animated color can provide\neven more intense hinting about its purpose and relatedness to other\ncues, to help operators learn and understand the interface. If not\nspecified, the static value specified by `:color` is used.\n\nThe function provided will be called whenever the grid interface is\nbeing updated, and will be called with four arguments: the `cue` whose\ncurrent color is desired; the map describing the currently active\n`effect` that was launched by that cue, if any; the `show` in which\nthe cue and effect exist; and the metronome `snapshot` representing\nthe moment in time at which the interface is being rendered. The\nfunction can use this information to calculate and return a color\nvalue, which will be used to draw the cue in the interface, or it can\nreturn `nil`, in which case the static `:color` value will be\ndisplayed instead.\n\nHelper functions exist to create cue color functions for commonly\nuseful situations.\n{api-doc}afterglow.effects.cues.html#var-color-fn-from-cue-var[`afterglow.effects.cues/color-fn-from-cue-var`]\nreturns a function that causes the cue to appear in the same color as\na cue color parameter, whenever the cue is running and that parameter\nhas a value. Similarly,\n{api-doc}afterglow.effects.cues.html#var-color-fn-from-param[`afterglow.effects.cues/color-fn-from-param`]\ncauses the cue to appear in whatever color is returned by evaluating\nthe specified dynamic parameter at that point within the show. The\nsource code of those helper functions are good examples of how to\ncreate dynamic cue color functions, and the source of the\n{api-doc}afterglow.examples.html#var-make-strobe-cue-2[`make-strobe-cue-2`]\nfunction in the examples namespace shows how the strobe cues are\nconfigured to flash between current color of the `:strobe-color` show\nvariable and white to emphasize their strobe nature.\n\nNOTE: When assigning a color to a cue in the user interface, the\nlightness of the color has no effect, because that is assigned by the\ncontroller to indicate the cue state, so you will need to use changes\nin hue and saturation for your animation.\n\n|`:level`\n|`0`\n\n|If provided, and the function supports a range of values with\n different meanings (such as a focus range, movement speed, or the\n like), sets the initial level to assign the function, and to the\n variable which will be introduced to allow the function value to be\n adjusted while the cue runs. Functions with no variable effect will\n ignore `:level`, and will have no cue-specific variables created for\n them. The level is treated as a percentage, where 0 is mapped to the\n lowest DMX value that activates the function, and 100 is mapped to\n the highest.\n\n|`:htp`\n|`false`\n\n|If supplied along with a true value, causes the effect that is\n created for this cue to operate with _highest-takes-precedence_ rules\n with respect to any other effect which has already assigned a value\n for this function. Otherwise, the effect will simply discard any\n previous assignments, replacing them with its own regardless of their\n value.\n\n|`:end-keys`\n|none\n\n|A list of keywords that identify additional effects to be ended when\nlaunching this cue. See the dimmer cue section of\n{api-doc}afterglow.examples.html#var-make-cues[`make-cues`]\nfor an example of how this can be helpful: it sets up a couple of rows\nof dimmer cues where the leftmost affects all the dimmers in the\nlighting rig, and cancels all the cues that work on individual light\ngroups, while the individual light group dimmer cues cancel the\nall-dimmers cues, but leave the dimmer cues for other light groups\nalone.\n\n|`:priority`\n|`0`\n\n|Sets the effect priority used when adding the cue's effect to the\nshow. This can be used to make sure the effect runs before or after\nother effects in the <<rendering_loop.adoc#,rendering loop>>. Effects\nare run in order, and later effects can modify or override the results\nof earlier ones, like the way the Sparkle effect in\n{api-doc}afterglow.examples.html#var-make-cues[`make-cues`] is\nassigned a priority of 100 so it sorts after any chase which may be\nrunning, and its sparkles can lighten the color which would otherwise\nbe present in their fixtures.\n\n|`:held`\n|`false`\n\n|As described <<cues.adoc#held-flag,above>>, causes the cue's effect\nto run only as long as the corresponding controller button or pad is\nheld down, if the controller supports that capability. All current\ncontroller implementations, including the web interface, the\n<<push2.adoc#,Ableton Push mapping>>, and mappings to\ngeneric MIDI controllers created using\n{api-doc}afterglow.effects.cues.html#var-add-midi-to-cue-mapping[`afterglow.effects.cues/add-midi-to-cue-mapping`]\ndo honor this setting. The web interface and controllers like the\nPush, which can vary the color of cue grid cells, will provide\nfeedback that a cue will last only as long as it is held by displaying\na whitened version of the cue color while it is held down.\n\nShow operators can override the `:held` flag by holding down the\n`Shift` key when triggering the cue on interfaces which have `Shift`\nkeys (like the web interface and Ableton Push). This will cause the\ncue to run until the corresponding pad or grid cell is pressed again,\nand will not whiten the cue color while it is held down.\n\n|`:velocity`\n|`false`\n\n|If present, with a true value, requests that the function value be\n adjusted by MIDI velocity and aftertouch pressure while the operator\n is holding down the button or pad which launched the cue, on\n controllers which have pressure sensitivity.\n\n|`:velocity-min`\n|`0`\n\n|If present (and `:velocity` is active), specifies the smallest value\n the function should be set to by MIDI velocity and aftertouch\n pressure. If not specified, `0` is used, which corresponds to the\n lowest legal DMX value the fixture definition identifies for the\n function.\n\n|`:velocity-max`\n|`100`\n\n|If present (and `:velocity` is active), specifies the largest value\n the variable should be set to by MIDI velocity and aftertouch\n pressure. If not specified, `100` is used, which corresponds to the\n highest legal DMX value the fixture definition identifies for the\n function.\n\n|===\n\n[[creating-code-cues]]\n== Creating Code Cues\n\nIt can be convenient to use a cue grid to trigger arbitrary actions\nwhich have nothing directly to do with lighting effects. For example,\nif your grid controller doesn't have a dedicated button for resetting\nthe show metronome, you might want to use one of the cue grid cells\nfor that purpose. The\n{api-doc}afterglow.effects.cues.html#var-code-cue[`code-cue`]\nfunction makes this easy. It creates a cue that does nothing other\nthan call the function you supply, one time, when the cue is launched.\nYour function must take two arguments, because it will be called with\nthe show and metronome snapshot when the cue starts. The function must\nalso return right away, since it's run as part of the effect rendering\npipeline. If you need to do something that could take a while, you\nwill need to do that on a different thread.\n\nYour function is passed as the first argument to `code-cue`, and you\nmust also supply a string as the second argument; this will be used to\nlabel the cue when it is assigned to a cue grid with text\ncapabilities, to identify its purpose.\n\nAs with other cues, you can also provide an optional keyword argument\n`:color` along with a color specification, to request that the cue\ngrid use that color for the cell holding this cue.\n\nThe cue will be configured to end when you let go of the cue pad,\nbecause it doesn't do anything after calling your function once when\nit is first launched.\n\nAs a concrete example, here is how to create a code cue that restarts\nthe show metronome when it is launched:\n\n```clojure\n(ct/set-cue! (:cue-grid *show*) 0 0\n             (cues/code-cue (fn [show snapshot]\n                              (rhythm/metro-start (:metronome show) 1))\n                            \"Reset\"))\n```\n\n[[controlling-cues]]\n== Controlling Cues\n\nThe {api-doc}afterglow.controllers.html[`afterglow.controllers`]\nnamespace defines some helpful functions for working with cues, and\ndefines a {api-doc}afterglow.controllers.html#var-IGridController[grid\ncontroller protocol] which rich controller mappings, like the ones for\nthe <<push2.adoc#,Ableton Push>> and <<launchpad.adoc#,Novation\nLaunchpad family>>, use to attach themselves to a running show, and\nsynchronize with the web interface.\n\nIf you are implementing a new grid controller mapping, you will want\nto study that protocol, and will likely find the Novation Launchpad\nfamily and Ableton Push mappings to be useful examples and starting\npoints for your own work. (And please, when you are done, submit a\npull request to add your implementation to Afterglow!)\n\nWhen you are setting up the cue grid for your show, you will use\n{api-doc}afterglow.controllers.html#var-set-cue.21[`set-cue!`]\nto arrange the cues you want it to contain. The\n{api-doc}afterglow.examples.html#var-make-cues[`make-cues`]\nfunction in the examples namespace contains a lot of examples of doing\nthis. As cues are added to the grid, its dimensions are updated, and\nthe web interfaces and any registered grid controllers will\nimmediately reflect the new cue and dimensions.\n\nYou can remove a cue from the grid with\n{api-doc}afterglow.controllers.html#var-clear-cue.21[`clear-cue`].\n\n=== Digging Deeper\n\nThe rest of the functions in the `afterglow.controllers` namespace are used by\ncontroller implementations and running shows to mediate their\ninteractions with the cue grid; dig into them if you are writing code\nin those spaces.\n"
  },
  {
    "path": "doc/modules/ROOT/pages/effects.adoc",
    "content": "= Effects\nJames Elliott <james@deepsymmetry.org>\n\nEffects determine what a light or group of lights are doing at a given\nmoment in time.\n\n== Overview\n\nThis section starts out by describing the basic effect types which act\nas building blocks for an Afterglow light show, then goes on to\nintroduce the <<scenes,scenes>> and <<chases,chases>> that you can use\nto group and sequence these building blocks into a show that evolves\nover time, driven by the show's metronome.\n\nWhen creating an effect, you assign one or more\n<<fixture_definitions.adoc#,Fixtures>> to it, and it will generate\ncontrol values for only those fixtures. The fixture channels that will\nbe manipulated by the effect depend on the kind of effect it is, and\nare grouped into several primary categories. The simplest kinds of\neffects apply to a single channel per fixture, or perhaps per head, if\nthe fixture has multiple independent light-emitting heads. A very\ncommon single-channel effect is the <<dimmer-effects,dimmer effect>>.\n\nMany effects assign <<color-effects,colors>> to lights, which often\ninvolves multiple channels. RGB fixtures will use three channels, one\neach for the red, green, and blue levels which make up the color. Some\nfixtures add other LED colors, such as amber, white, and even\nultraviolet. Other fixtures simply use a rotating color wheel to pick\nfrom a fixed set of colors, using a single channel. Regardless of how\nthe color is finally produced, at most stages of effect processing,\nAfterglow works in terms of the <<color.adoc#,color itself>>, allowing\nyou to blend, lighten, darken, shift hue, and the like so you can\nproduce interesting looks, without regard to details of fixture\nimplementation. It is only at the <<rendering_loop.adoc#,final\nrendering stage>> that the color is broken down into channel\nassignments.\n\nAnother important category of effects control the\n<<direction-effects,direction>> of moving-head fixtures. These work in\nterms of a desired 3D direction vector or <<aim-effects,target point>>\nwith respect to the <<show_space.adoc#,show frame of reference>>,\nand at the last stage of rendering, convert that to pan and tilt\nchannel values, with reference to the angle at which the fixture has\nactually been hung.\n\nYou can also conveniently use features which are shared by a number of\nfixtures, or completely unique to a single fixture, through\n<<function-effects,function effects>>, or drop right down to the\nlevel of individual DMX channel values with\n<<channel-effects,channel effects>>.\n\nAs mentioned above, there are a number of ways to combine these\neffects. If you have a group of effects that you want to start and\nstop at the same time, you can group them into a <<scenes,scene>>. To\nsmoothly transition from one effect to another you can use a\n<<fades,fade>>, and either side of the fade can be a scene. Or you can\nfade to or from a <<blank-effects,blank effect>>, or sequence a whole\nlist of effects or scenes using a <<chases,chase>>.\n\n<<conditional-effects,Conditional effects>> and\n<<variable-effects,variable effects>> are designed to make it easy for\neffects to influence and interact with each other by responding to and\nsetting show variables. Finally, Afterglow includes some examples of\nhow to build up <<complex-effects,special-purpose effects>>, which can\nbe fun in themselves, and also serve as templates and inspiration for\nwhole new kinds of effects you create on your own.\n\n[[basic-effect-types]]\n== Basic Effect Types\n\nEffects in afterglow are divided by the aspect of a light that they\ncontrol. Not all fixtures have features which allow them to\nparticipate in all kinds of effects. Afterglow effects will\nsimply ignore fixtures which are unable to reapond to them.\n\n[[dimmer-effects]]\n=== Dimmer Effects\n\nDimmer effects set the basic brightness level of a fixture. To create\nan effect that will set the dimmer level of a fixture, use:\n\n[source,clojure]\n----\n(afterglow.effects.dimmer/dimmer-effect level fixtures)\n----\n\nThis effect finds all the dimmer channels associated with the\nspecified fixtures (there may be multiple, if the fixture has more\nthan one light-emitting head), and assigns them a level. 0 is off, 255\nis maximum brightness. Dimmer effects can work with either fully\ndedicated dimmer channels (in which case the channel itself has a\n`:type` of `:dimmer`, and the entire DMX range is used for dimming),\nor multipurpose channels in which a subset of the DMX range is\nassigned to a function of type `:dimmer`, and the channel `:type` is\nsomething else.\n\nIf `htp?` is true, uses highest-takes-precedence rules when replacing\nany earlier or lower-priority effects which attempted to set this\nparticular dimmer in the current rendering cycle. In other words, if\nan earlier effect chose a higher value, let it win, otherwise use the\nvalue this effect wants.\n\nThe\n{api-doc}afterglow.effects.dimmer.html#var-dimmer-effect[API\ndocumentation] also identifies some optional keyword arguments you can\npass. If `:htp?` passed with a `false`, value this effect will simply\noverwrite any previous assignments it finds for the dimmers it is\ncontrolling. Omitting `:htp?` is the same as passing it with a `true`\nvalue. And you can change the\n{api-doc}afterglow.effects.dimmer.html#var-master[`master`]\nthat scales the dimmer value by passing one along with `:master`. If\nyou do not, the effect will be tied directly to the show's grand\nmaster.\n\nTIP: If you want your dimmer cue to affect only one head of a fixture, you\ncan pass it just that head, rather than the entire fixture.\n\nFor some fixtures, generally those with a single, white light source,\nthe dimmer is the only thing that determines the amount of light output.\nFor color-mixing fixtures like RGB LED lights, each color channel has\nits own separate brightness level, and then dimmer scales the actual\noutput of the light, so the final brightness will be a combination of\nboth. In other words, if the red channel is set to 50% brightness, and\nthe dimmer is also set to 50% brightness, the final red output will be\nat 25% brightness.\n\nIn addition to passing in a literal number for the `level` parameter,\nyou can pass a <<parameters.adoc#,Dynamic Parameter>> whose value\ndepends on a <<metronomes.adoc#,Metronome>>, the physical location or\norientation of the head, or a show variable, perhaps\n<<mapping_sync.adoc#mapping-a-control-to-a-variable,bound>> to a MIDI\ncontrol surface. It often makes sense to use\n<<parameters.adoc#oscillated-parameters,oscillated parameters>> with\ndimmer cues.\n\nTIP: If you have color effects running for a light and you aren’t\nseeing anything, make sure you have a dimmer effect setting the dimmer\nto some visible level. And if the fixture has a shutter (either\nphysical or electronic), you may need an effect running to open that\nas well.\n\n[[virtual-dimmers]]\n==== Virtual Dimmers\n\nAlthough most RGB color-mixing fixtures have a dimmer channel which is\nseparate from the color component intensity channels, we have\nencountered a few that lack this feature: they have only a red,\ngreen, and blue channel, with no overall dimmer. In order to\naccommodate fixtures like this, and enable them to participate in\ndimmer effects for more flexible show control, Afterglow now can\nprovide _virtual dimmers_ for them. To use this feature, pass the\noptional argument `:add-virtual-dimmers?` with a `true` value to\n`dimmer-effect`.\n\nNOTE: As explained below, when using virtual dimmers you must also\nturn off highest-takes-precedence dimmer mixing by passing `false`\nwith the `:htp?` optional keyword argument, and add your dimmer effect\nto the show with a higher priority than any color effects running on\nthe fixtures that lack real dimmers, so it can run after them and\nmanipulate their results.\n\nSince virtual dimmers do not have an actual separate dimmer channel to\nwork with, they are actually <<color-effects,color effects>> which\nwork by modifying the result of whatever other color effect you have\nestablished for the dimmer-lacking fixtures. When you tell\n`dimmer-effect` that `add-virtual-dimmers?` is `true`, it will scan\nthe list of fixtures whose dimmers it is supposed to control, and in\naddition to creating ordinary dimmer effects for fixures with dimmers,\nit will create special color effects for any fixtures that can mix RGB\ncolors but lack dimmers. These color effects will act as virtual\ndimmers: they will look at the color value that has been established\nfor the fixture, and darken it as needed in order to reflect the\ndimmer level of the dimmer effect that created them (scaled by the\ndimmer master chain, just like regular dimmer effects). This dimmed\nversion of the color will replace the one that came from the other\neffects, and the visible result will be the same as if the fixtures\nhad dimmer channels.\n\nIn order for the virtual dimmer effect to be able to modify the other\ncolor effects, it needs to run after them. So you need to be sure when\nyou are adding virtual dimmer effects to the show to assign them a\nhigher priority value than the color effects they will be working\nwith.\n\nBecause the virtual dimmer color adjustment is a destructive\noperation, and the color channels have no direct access to the dimmer\nlevel information once it is complete, virtual dimmers cannot be\ncombined with each other in a &ldquo;highest takes precedence&rdquo;\nstyle. So when you need to use virtual dimmers, you must set `:htp?`\nmode to `false` in `dimmer-effect`, or the function will throw an\nexception.\n\nYou should also not try to run more than one dimmer effect with\nvirtual dimmers on the same fixtures at the same time, because each\none will darken them, giving you different results than actual dimmers\ndo.\n\nEven with these restrictions, virtual dimmers can address most of the\nlimitations of fixtures that lack actual dimmer channels, and allow\nthem to participate as nearly first-class citizens of Afterglow's\ndimmer effects.\n\n[[color-effects]]\n=== Color Effects\n\nOne of the most common basic effects you will be using to create the\nlooks you want is the color effect. To create an effect that will\nassign a color to a fixture (which will assign colors to all of the\nfixture’s heads), or a single head of a fixture, pass the fixture or\nhead to\n{api-doc}afterglow.effects.color.html#var-color-effect[`color-effect`]:\n\n[source,clojure]\n----\n(afterglow.effects.color/color-effect name color fixtures)\n----\n\nThe `name` parameter is intended to help identify the purpose of the\neffect, and shows up when examining the created effect. Put something\ndescriptive in there, or use a helper function like\n{api-doc}afterglow.examples.html#var-global-color-effect[`afterglow.examples/global-color-effect`]\nwhich builds the effect for you, figuring out a reasonable name in\nmany cases.\n\nThe `color` parameter is where you specify the color to assign to the\nlights. It should be a color object returned by one of the factories\nin the https://github.com/jolby/colors[jolby/colors] library, as\ndescribed in <<color#,Working with Color>>.\n\nIn addition to passing in a color for the `color` parameter, you can\npass a <<parameters.adoc#,Dynamic Parameter>> whose value depends on a\n<<metronomes.adoc#,Metronome>>, the physical location or orientation\nof the head, or a show variable, perhaps\n<<mapping_sync.adoc#mapping-a-control-to-a-variable,bound>> to a MIDI\ncontrol surface. The flexibility offered by\n<<parameters.adoc#color-parameters,dynamic color parameters>> is huge,\nespecially when combined with\n<<parameters.adoc#oscillated-parameters,oscillated parameters>>.\nLearning how to effectively leverage these in combination with each\nother will enable you to create most of the basic lighting looks you\nneed.\n\nThe following code creates a effect that assigns a pure red color to\nall fixtures with RGB channels, then adds it to the current show under\nthe keyword `:color`:\n\n[source,clojure]\n----\n(show/add-effect! :color (afterglow.effects.color/color-effect\n                          \"Plain red\" (create-color \"red\") (show/all-fixtures)))\n----\n\nTIP: Remember that if aren’t seeing anything when you have assigned\ncolor effects to a fixture to make sure you also have a dimmer effect\nsetting that fixture’s dimmer to some visible level. And if the\nfixture has a shutter (either physical or electronic), you may need an\neffect running to open that as well.\n\nYou can also assign colors to lights that use color wheels instead of\nRGB mixing by passing a `true` value with the optional keyword\nargument `:include-color-wheels?` to `color-effect`. Afterglow will\ntry to find a color wheel position which is close enough to the\ndesired color, and if one can be found, tell the light to use it.\n\n[[multiple-colors]]\n==== Multiple Colors\n\nYou can assign different color effects to different sets of fixtures\neven just using simple single-color effects, by combining them into a\n<<scenes,scene>>, which is explained more fully below, but worth\nmentioning now. Here is an example of how to assign a red color to odd\nfixtures and blue to even fixtures (assuming you have named the\nfixtures even-_number_ and odd-_number_):\n\n[source,clojure]\n----\n(show/add-effect! :color (afterglow.effects/scene \"Different colors\"\n  (afterglow.effects.color/color-effect\n    \"Plain red\" (create-color \"red\") (show/fixtures-named \"odd\"))\n  (afterglow.effects.color/color-effect\n    \"Plain Blue\" (create-color \"blue\") (show/fixtures-named \"even\"))))\n----\n\nThe Cues documentation <<cues.adoc#a-cue-example,extends this example>> to\nshow how to wrap this scene into a cue, for easy control by a light\nshow operator.\n\nTIP: There are many other ways to achieve multi-colored effects,\nranging from <<spatial-effects,Spatial Effects>> up to writing\nyour own custom <<complex-effects,Complex Effects>>. You can\nalso group fixtures any way you want, independently of how you name\nthem, by storing sets of them in variables and passing those sets, or\ncombinations of those sets created using Clojure's rich\nhttp://clojure.github.io/clojure/clojure.set-api.html[set-manipulation\nAPI], to the effect-creation functions.\n\n[[direction-effects]]\n=== Direction Effects\n\nMoving-head fixtures can create particularly exciting and dynamic shows.\nTo create an effect that will tell a fixture or head what direction it\nshould be pointing, pass the fixture or head to:\n\n[source,clojure]\n----\n(afterglow.effects.movement/direction-effect name direction fixtures)\n----\n\nThe `name` parameter is intended to help identify the purpose of the\neffect, and shows up when examining the created effect.\n\nThe `direction` parameter is where you specify the direction the\nlights should be pointing. It is a `javax.vector.Vector3d` pointing in\nthe direction the lights should face, with respect to the show’s\n<<show_space.adoc#,frame of reference>>. An easy way to create one is\nto call\n{api-doc}afterglow.effects.params.html#var-build-direction-param[`afterglow.effects.params/build-direction-param`]\nor\n{api-doc}afterglow.effects.params.html#var-build-direction-param-from-pan-tilt[`afterglow.effects.params/build-direction-param-from-pan-tilt`].\nThese can create static vectors for you, but can also create\n<<parameters.adoc#,Dynamic Parameters>> whose value depends on a\n<<metronomes.adoc#,Metronome>>, the physical location or orientation\nof the head, or a show variable, perhaps\n<<mapping_sync.adoc#mapping-a-control-to-a-variable,bound>> to a MIDI\ncontrol surface. Building dynamic direction parameters with\n<<parameters.adoc#oscillated-parameters,oscillated parameters>> can\ncreate fascinating motions.\n\nIf a group of fixtures is assigned the same direction effect, they\nwill all face the same direction. If they are assigned the same aim\neffect (below), they will all face slightly different directions in\norder to aim at the same point in space.\n\nTIP: Because of the fact that the direction vector must be translated\ninto pan and tilt angles before sending it to control the light, fades\nbetween directions might not always work the way you expect them to.\nThis is especially true if the directions you are fading between are\nexact opposites of each other: In that case, the angle does not change\nat all during the fade until the midpoint, when it reaches the center\nof the light, and the light instantly flips around to face the\nopposite direction for the rest of the fade. You can also run into\nissues where one of the directions you are fading is close to a\ngeometric singularity (when one of the angles gets near 90&deg;), at\nthat point the other direction will suddenly dominate, and you can see\nunexpected jiggling or changes in direction. For such cases you may be\nbetter off using lower-level <<pan-tilt-effects,pan/tilt effects>>,\nwhich operate closer to the way the lights themselves do.\n\n[[aim-effects]]\n=== Aim Effects\n\nThese are very similar to <<direction-effects,direction effects>>,\nexcept they tell each fixture to aim at a particular point in space,\nsuch as an object or person in front of the lighting rig, or perhaps\nanother fixture. To create an effect that will tell a fixture or head\nwhat point it should be aiming at, pass the fixture or head to:\n\n[source,clojure]\n----\n(afterglow.effects.movement/aim-effect name target-point fixtures)\n----\n\nThe `name` parameter is intended to help identify the purpose of the\neffect, and shows up when examining the created effect.\n\nThe `target-point` parameter is where you specify the point at which\nthe lights should be aiming. It is a `javax.vector.Point3d`\nidentifying a point within the show’s <<show_space.adoc#,frame of\nreference>>. An easy way to create one is to call\n{api-doc}afterglow.effects.params.html#var-build-aim-param[`afterglow.effects.params/build-aim-param`].\nThis can create static points for you, but can also create\n<<parameters.adoc#,Dynamic Parameters>> whose value depends on a\n<<metronomes.adoc#,Metronome>>, the physical location or orientation\nof the head, or a show variable, perhaps\n<<mapping_sync.adoc#mapping-a-control-to-a-variable,bound>> to a MIDI\ncontrol surface. Using a tablet with an OSC or midi interface that\nlets you drag an aiming point around a map of the stage is one fun\npossibility.\n\nIf a group of fixtures is assigned the same direction effect, they\nwill all face the same direction. If they are assigned the same aim\neffect, they will all face slightly different directions in order to\naim at the same point in space.\n\n[[pan-tilt-effects]]\n=== Pan/Tilt Effects\n\nThese are essentially the same as <<direction-effects,direction\neffects>>, except they use a pan and tilt angle to tell the fixtures\nwhich way to face, so they are closer to the way the lights naturally\nwork, will be more familiar to light show designers, and can behave\nmore smoothly and predictably when fading into each other. To create\nan effect that will tell a fixture or head what direction it should be\npointing via pan and tilt angles, pass the fixture or head to:\n\n[source,clojure]\n----\n(afterglow.effects.movement/pan-tilt-effect name pan-tilt fixtures)\n----\n\nThe `name` parameter is intended to help identify the purpose of the\neffect, and shows up when examining the created effect.\n\nThe `pan-tilt` parameter is where you specify the angles in which the\nlights should be aiming. It is a `javax.vector.Vector2d` whose `x`\ncomponent contains the `pan` angle, and whose `y` component contains\nthe `tilt` angle. These angles tell the fixture how far, in radians,\nit should rotate away from pointing straight out at the audience\n(along the `z` axis of the show’s <<show_space.adoc#,frame of\nreference>>). An easy way to create the pan-tilt vector is to call\n{api-doc}afterglow.effects.params.html#var-build-pan-tilt-param[`afterglow.effects.params/build-pan-tilt-param`].\nThis function also allows you to work in degrees rather than radians,\nif that is more convenient. It can create static angle vectors for\nyou, but can also create <<parameters.adoc#,Dynamic Parameters>> whose\nvalue depends on a <<metronomes.adoc#,Metronome>>, the physical\nlocation or orientation of the head, or a show variable, perhaps\n<<mapping_sync.adoc#mapping-a-control-to-a-variable,bound>> to a MIDI\ncontrol surface.\n\nBecause when you fade between pan-tilt effects, the angles always\nchange smoothly, and correspond to the actual movements of the lights,\nthey can be easier building blocks for natural-looking movement\neffects when you aren't trying to track particular points in space.\n\nIf a group of fixtures is assigned the same pan-tilt or direction\neffect, they will all face the same direction. If they are assigned\nthe same aim effect, they will all face slightly different directions\nin order to aim at the same point in space.\n\n[[function-effects]]\n=== Function Effects\n\nFixtures have a wide variety of different capabilities, often more\nthan would be reasonable to assign a separate DMX channel for each,\nespecially when it does not make sense to activate or control some at\nthe same time. Afterglow can be told about these in the\n<<fixture_definitions.adoc#,fixture definition>>, and you can control\nthem using function effects, by specifying the name of the function\nyou want to activate, and a _percentage_ (a value between `0` and\n`100`) by which you want it activated. (The percentage will be\ntranslated to the corresponding value within that function’s valid DMX\nrange that Afterglow should send).\n\nFor example, many fixtures have a strobe function, which causes them to\nflash off and on at a particular speed. The following line shows how to\ncause them all to strobe at their fastest speed:\n\n[source,clojure]\n----\n(show/add-effect! :strobe (afterglow.effects.channel/function-effect\n  \"Fastest strobe\" :strobe 100 (show/all-fixtures)))\n----\n\nWith this effect active, any fixture with a `:strobe` function range\nwill be sent the highest value defined for that range, on the channel on\nwhich the function exists, causing it to strobe rapidly. Fixtures which\nlack such a function will be unaffected.\n\nFunction effects can be very specific to individual fixtures. For\nexample, the Blizzard Torrent F3 has a pair of gobo wheels; one of them\nhas a gobo that projects something that looks like a fat atom with\nelectrons orbiting it. This projection can be selected, and caused to\njiggle back and forth at the mid-range of possible shake speeds, by\nadding the following effect:\n\n[source,clojure]\n----\n(show/add-effect! :gobo-fixed\n  (afterglow.effects.channel/function-effect \"Brownian motion?\"\n    :gobo-fixed-atom-shake 50 (show/fixtures-named \"torrent\")))\n----\n\nDepending on how far away the projection is landing, it may be very\nblurry; focus can be adjusted like so:\n\n[source,clojure]\n----\n(show/add-effect! :focus\n  (afterglow.effects.channel/function-effect\n    \"focus\" :focus 95.5 (show/fixtures-named \"torrent\")))\n----\n\nThe functions available for a fixture, their names, channels, and\nranges, are specified by the <<fixture_definitions.adoc#,fixture\ndefinition>>, so reading over those can be helpful. (And carefully\ncrafting and testing them is important when defining a new fixture.)\nTrying to maintain consistency in function naming is valuable in\nallowing functions to be conveniently applied to groups of different\nfixtures.\n\nFunctions which do not vary in their effect for different DMX values\nwithin the legal range are described as `:range :fixed` in the fixture\ndefinition; this is currently only used for displaying the\ninterpretation of a fixture setting, you still need to provide a\npercentage within the range when setting up the function effect.\n\nFixture definitions can also supply a _scaling function_ for a function\nspecification, which maps input values to the final percentage within\nthe DMX range. This is helpful, for example, to allow strobe settings to\nbe interpreted as approximate Hz values, so fixtures from different\nmanufacturers can be asked to strobe at roughly the same rate for the\nsame function setting. You can view the source of the\n{api-doc}afterglow.fixtures.blizzard.html[Blizzard\nfixture definitions] for examples of how this is done, passing the\nminimum and maximum Hz strobe rates of the actual fixture to create a\npartial implementation of\n{api-doc}afterglow.effects.channel.html#var-function-value-scaler[`afterglow.effects.channel/function-value-scaler`]\nwhich is passed the value that the effect is trying to establish, and\nconverts it to a position in that fixture’s range which attempts to\napproximate that strobing rate.\n\n[[channel-effects]]\n=== Channel Effects\n\nWhen you just want to send a specific number to a particular DMX\nchannel, you can drop right down to the bottom level with channel\neffects. For example, to pin the dimmer channel of a group of fixtures\nto 55, regardless of the setting of the show’s master chain, you could\ndo something like this:\n\n[source,clojure]\n----\n(show/add-effect! :blade-dimmers\n  (afterglow.effects.channel/channel-effect \"Blade dimmers\" 55\n    (afterglow.channels/extract-channels\n      (show/fixtures-named :blade) #(= (:type %) :dimmer))))\n----\n\nOr to look at what actual pan values do to a Torrent, without fancy\ngeometric transformations, as you set values into the show variable\nnamed `:pan`:\n\n[source,clojure]\n----\n(show/add-effect! :pan-torrent\n  (afterglow.effects.channel/channel-effect\n    \"Pan Torrent\" (params/build-variable-param :pan)\n    (afterglow.channels/extract-channels\n      (show/fixtures-named :torrent) #(= (:type %) :pan))))\n----\n\nYou will most likely be wanting to do this sort of thing for channel\ntypes which Afterglow does not yet have a more sophisticated\nunderstanding, and then perhaps you will end up creating a whole new\ncategory of effects as your experimentation progresses.\n\n[[compound-effects]]\n== Compound Effects\n\nThe most straightforward way to create interesting shows is to combine\nmultiple simple effects in different ways. Compound effects are tools\nwhich enable that.\n\n[[scenes]]\n=== Scenes\n\nThe simplest way to build a compound effect is to combine a group of\neffects into one which can be started and stopped as a unit. That is\nthe purpose of the\n{api-doc}afterglow.effects.html#var-scene[`scene`]\nfunction in the `afterglow.effects` namespace. It takes a name for the\nscene to be created, followed by one or more effects to be grouped,\nand returns an effect which combines them all under that name:\n\n[source,clojure]\n----\n(show/add-effect! :color\n  (afterglow.effects/scene \"Blue Sparks\"\n    (afterglow.examples/global-color-effect :blue)\n    (fun/sparkle (show/all-fixtures) :chance 0.07 :fade-time 500)))\n----\n\nAssuming you are running the sample show and have the dimmers up,\nyou'll see all the lights turn blue, and a random pattern of white\n<<sparkle,sparkles>> twinkling across them. Ending the scene\neffect will end both underlying effects in a coordinated fashion (the\nblue color effect will linger as the last sparkles fade out).\n\n[[blank-effects]]\n=== Blank Effects\n\nA blank effect does nothing at all. Although this might not\nimmediately seem useful, assigning a blank effect to one side or the\nother of a <<fades,fade>> (below) lets you fade an effect in\nor out, from or to nothing. In such cases the fade also takes care\nthat as it fades towards the blank effect, whatever effects were being\nreplaced by the fade are restored.\n\nTo create a blank effect, simply call the\n{api-doc}afterglow.effects.html#var-blank[`blank`]\nfunction in the `afterglow.effects` namespace.\n\nYou might also want to create a blank effect as part of a cue whose\npurpose is simply to provide a way to adjust a show variable. The\n<<color.adoc#colors-and-cues,Colors and Cues>> discussion provides an\nexample of doing just that.\n\n[[fades]]\n=== Fades\n\nA fade effect lets you smoothly transition from one effect to another,\nblending a weighted combination of each. The\n{api-doc}afterglow.effects.html#var-fade[`fade`]\nfunction in the `afterglow.effects` namespace supports this. It takes\na name for the fade to be created, followed by `from-effect` and\n`to-effect`, the two effects to be faded between, and a `phase`\nparameter which controls how much of each effect is seen. It returns\nthe blended effect.\n\nTIP: For the common case of wanting to fade in an effect when you\nstart it, and then fade it back out when you tell it to end, see\n<<#fading-in-and-out,Fading In and Out>>.\n\nWhen the value of `phase` is `0` (or less), the fade acts as if it is\nsimply `from-effect`. When `phase` is `1` (or more), the fade behaves\nidentical to `to-effect`. When `phase` falls somewhere between `0` and\n`1`, a corresponding linear blend between `from-effect` and\n`to-effect` is created. At the value `0.5`, each effect contributes\nthe same amount.\n\nEither or both of the effects being faded between can be a\n<<scenes,scene>>, which groups many other effects, or one can\nbe a <<blank-effects,blank effect>>, which will simply fade\nthe other effect in or out of existence (allowing any earlier or\nlower-priority effects to show through). When fading between two\nnon-blank effects, if they include different groups of fixtures (or\naffect different aspects of the fixtures they do include), the same\nnotion of &ldquo;seeing what is underneath&rdquo; the fade applies, as\nthe side which is controlling a particular fixture or feature is faded\nout.\n\nThe `phase` parameter can (and usually will) be a dynamic parameter,\nprobably a <<parameters.adoc#variable-parameters,variable parameter>> or\n<<parameters.adoc#oscillated-parameters,oscillated parameter>>, so the fade\nwill take place over time, or under the control of an operator using a\ncontrol surface.\n\nHere is an example of a very simple fade cue from the sample show:\n\n[source,clojure]\n----\n(show/set-cue!\n 4 7\n (cues/cue :color-fade\n           (fn [var-map]\n               (fx/fade \"Color Fade\"\n                        (global-color-effect :red :include-color-wheels? true)\n                        (global-color-effect :green :include-color-wheels? true)\n                        (params/bind-keyword-param (:phase var-map 0) Number 0)))\n           :variables [{:key \"phase\" :min 0.0 :max 1.0 :start 0.0 :name \"Fade\"}]))\n----\n\nThis fades all the lights from red to green as the cue's encoder is\nturned. Switching either color effect to `(blank)` would insted fade\nto or from whatever color the fixtures were otherwise displaying at\nthe time.\n\n[[fading-in-and-out]]\n=== Fading In and Out\n\nSometimes you would like an open-ended effect to fade in when you\nlaunch it, and then fade out when you ask it to end. To facilitate\nthis, Afterglow includes a special compound effect you can wrap around\nany other effect to implement this behavior, building on the fade\nmechanism described <<#fades,above>>. This is built using the\n{api-doc}afterglow.effects.html#var-wrap-fade-in-out[`wrap-fade-in-out`]\nfunction in the `afterglow.effects` namespace.\n\nThis function takes a name for the wrapped effect, and the effect you\nwant to wrap with fade-in and fade-out behavior. By default it will\nfade in and out over a beat, but you can change that by passing\nkeyword arguments `:step-in` and/or `:step-out` to configure the\n<<parameters.adoc#step-parameters,Step Parameters>> that will be used\nto manage the two fades. The values you pass with these arguments are\nmaps that will be merged onto `{:fade-fraction 1.0}` and then passed to\n{api-doc}afterglow.effects.params.html#var-build-step-param[`afterglow.effects.params/build-step-param`]\nto build the step functions that control the fade in and fade out process.\nThe most likely arguments you would want to use to adjust these fades are\n`:interval` and `:interval-ratio`.\n\nHere is an example of how, in the sample show, you could wrap a dimmer\ncue so that it fades in over two beats, and fades out over half a\nbeat:\n\n[source,clojure]\n----\n(show/set-cue!\n 7 0\n (cues/cue :dimmer\n           (fn [var-map]\n             (fx/wrap-fade-in-out\n              \"Fade Test\"\n              (dimmer-effect\n               (params/bind-keyword-param (:level var-map 255) Number 255)\n               (show/fixtures-named :ws))\n              :step-in {:interval-ratio 2}\n              :step-out {:interval-ratio (/ 1 2)}))\n           :variables [{:key \"level\" :min 0 :max 255 :start 255}]))\n----\n\n> You can omit the `:step-in` and `:step-out` lines if the default of\n> fading over a single beat is what you want.\n\n\n[[chases]]\n=== Chases\n\nChase effects allow you to sequence a series of effects one after\nanother, with optional <<fades,fades>> between them. They are\nbuilt using the\n{api-doc}afterglow.effects.html#var-chase[`chase`]\nfunction in the `afterglow.effects` namespace. Of course each effect\nwithin the chase can itself be a <<scenes,scene>>, which\ngroups many other effects, or a <<blank-effects,blank\neffect>>, which will simply fade the chase temporarily out of\nexistence (allowing any earlier or lower-priority effects to show\nthrough). When fading between two non-blank effects, if they include\ndifferent groups of fixtures (or affect different aspects of the\nfixtures they do include), the same notion of &ldquo;seeing what is\nunderneath&rdquo; the fade applies, as the side which is controlling a\nparticular fixture or feature is faded out.\n\nIn addition to the list of effects which make up the chase, a\n`position` parameter is used to create it. When the effect is\nrendered, the current value of this parameter is an index into the\neffects that make up the chase, and it controls which one is currently\nvisible. When `position` is `1`, the first effect in `effects` is\nactive; `2` causes the second to be seen, and so on. Non-integer\nvalues are how fades are accomplished, they result in a linear blend\nbetween the corresponding effects. In order to make the chase evolve\nover time, `position` needs to be a dynamic variable parameter, and\n<<parameters.adoc#step-parameters,Step Parameters>>, created by the\nfunction\n{api-doc}afterglow.effects.params.html#var-build-step-param[`afterglow.effects.params/build-step-param`],\nare designed specifically to work with chases.\n\nWith no other arguments, the chase will end when `position` has a\nvalue less than zero, or greater than the number of elements in\n`effects` plus one. Values between `0` and `1` fade into the first\neffect from nothing, and as the value grows above the number of\nentries in `effects`, it begins to fade out the final effect.\n\nA chase can be made open-ended by supplying a value with the optional\nkeyword argument `:beyond`. The default value, `:blank`, causes the\nbehavior described in the previous paragraph. If `:beyond` is supplied\nwith the value `:loop`, the chase will act as if the `effects` list\ncontained an infinite number of copies of itself. So when `position`\ngrows past the final index, the last effect in the list fades back\ninto the first entry. Similarly, values of `position` below `1` fade\nback to the end of the list. In this configuration, the chase will\nonly end when either all of the underlying effects contained within\nthe `effects` list have ended on their own, or `position` resolves to\n`nil`, which always ends a chase immediately.\n\nAnother way to create an open-ended chase is to pass `:beyond` with\nthe value `:bounce`. This acts like `:loop`, except that whenever one\nend of the list of `effects` is reached, the chase changes direction\nand moves back through the list from that point. In other words, if\n`position` keeps growing steadily in value, and there are three\neffects in `effects`, with a `:beyond` value of `:loop` you will see\nthem in the order 1 &rarr; 2 &rarr; 3 &rarr; 1 &rarr; 2 &rarr; 3\n&rarr; 1&hellip; while a value of `:bounce` would give you 1 &rarr; 2\n&rarr; 3 &rarr; 2 &rarr; 1 &rarr; 2 &rarr; 3 &rarr; 2&hellip;.\n\n[[conditional-effects]]\n=== Conditional Effects\n\nThe\n{api-doc}afterglow.effects.html#var-conditional-effect[`conditional-effect`]\nfunction in the `afterglow.effects` namespace wraps another effect,\nallowing it to run only when the value of some dynamic parameter (most\nlikely a <<parameters.adoc#variable-parameters,variable parameter>> or\n<<parameters.adoc#oscillated-parameters,oscillated parameter>>) is not\nzero.\n{api-doc}afterglow.shows.sallie.html#var-global-color-effect[`afterglow.shows.sallie/global-color-effect`]\nshows an example of using it within a scene to optionally have the\ncolor effect apply to a laser show running simultaneously with the\nlight show, controlled by the show variable `:also-color-laser`. This\nvariable gets set when the &ldquo;Also color laser&rdquo; cue is\nrunning, by means of a Variable Effect, described in the next section.\n\n[source,clojure]\n----\n(ns afterglow.shows.sallie\n;; ...\n  (:require [afterglow.effects :as fx]\n;; ...\n)\n;; ...\n(fx/scene (str \"Color: \" desc)\n          (color-effect (str \"Color: \" desc) c lights)\n          (fx/conditional-effect \"Color Laser?\" (params/build-variable-param :also-color-laser)\n                                 (beyond/laser-color-effect laser-show c))))\n----\n\n[[variable-effects]]\n=== Variable Effects\n\nThe\n{api-doc}afterglow.effects.show-variable.html#var-create-for-show[`variable-effect`]\nfunction in the `afterglow.effects.show-variable` namespace creates an\neffect which does not set any DMX values. Instead, it makes use of the\nrendering loop <<rendering_loop.adoc#extensions,extension mechanism>> to\nset a show variable while the effect is active. This dovetails very\nnicely with Conditional Effects, described above.\n\nYou can see an example of how to use variable effects in\n{api-doc}afterglow.shows.sallie.html#var-use-sallie-show[`afterglow.shows.sallie/use-sallie-show`],\nwhich creates a binding to the show variables using\n{api-doc}afterglow.effects.show-variable.html#var-create-for-show[`afterglow.effects.show-variable/create-for-show`].\nThen\n{api-doc}afterglow.shows.sallie.html#var-make-cues[`afterglow.shows.sallie/make-cues`]\nuses that `var-binder` to create a `:color-laser` cue which sets the\nshow variable `:also-color-laser` while it runs:\n\n[source,clojure]\n----\n(ns afterglow.shows.sallie\n;; ...\n  (:require [afterglow.effects.show-variable :as var-fx]\n;; ...\n)\n;; ...\n(reset! var-binder (var-fx/create-for-show *show*))\n;; ...\n(ct/set-cue! (:cue-grid *show*) 5 7\n             (cues/cue :color-laser\n                       (fn [_] (var-fx/variable-effect @var-binder :also-color-laser 1))\n                       :color :red :short-name \"Also color laser\"))\n----\n\nThis variable setting causes the Conditional Effects in scenes created\nby `global-color-effect` (as described in the preceding section) to\nalso send commands to the laser show.\n\n[[complex-effects]]\n=== Complex Effects\n\nThese are effects which build on more than one of the capabilities\nlisted above to create an interesting or fun effect. They represent\nexamples of how Afterglow can be used to create new things, and we\nhope that people will contribute their own effects for inclusion in\nfuture releases.\n\n[[color-cycle-chases]]\n==== Color Cycle Chases\n\nThis family of related effects are an excellent illustration of why\nAfterglow was created, which was to enable the concise expression and\nimplementation of effects like them. They leverage many of the\nbuilding blocks within Afterglow, and provide a framework to combine\nthem in flexible ways using functional composition to acheive a\nvariety of different looks that change in space at appropriate musical\ntimes, with very little code required in each. They are useful in\nthemselves, and as examples of how to write similar effects.\n\nThe\n{api-doc}afterglow.effects.fun.html#var-iris-out-color-cycle-chase[Iris\nOut] color cycle chase changes the color of a group of fixtures to a\ndifferent color for each bar of a phrase of music. During the down\nbeat of each new bar, the color spreads over the participating\nfixtures starting at their geometric center in the x-y plane of\n<<show_space.adoc#,show space>>, and spreading in an expanding\ncircle until reaching the furthest heads at the end of the down beat.\n\n[source,clojure]\n----\n(show/add-effect! :color\n  (afterglow.effects.fun/iris-out-color-cycle-chase (show/all-fixtures)))\n----\n\nIf you look at the source code (which you can always get to by\nfollowing the &ldquo;view source&rdquo; link at the bottom of the\n{api-doc}afterglow.effects.fun.html#var-iris-out-color-cycle-chase[API\ndocumentation], or typing `(source\nafterglow.effects.fun/iris-out-color-cycle-chase)` in a REPL or the\nweb console), you will see that it is only a few lines, once you get\npast the documentation and parameters, most of which are given default\nvalues to pass along to\n{api-doc}afterglow.effects.fun.html#var-color-cycle-chase[`color-cycle-chase`],\nwhich is used to actually implement the chase.\n\nThose parameters can be used to change the set of colors in the cycle,\nas well as control when the color changes, and when and how quickly\nthe transition occurs. The documentation for `color-cycle-chase`\nexplains how.\n\nThe body of `iris-out-color-cycle-chase` simply sets up the measure\nfunction which causes the iris-out effect to behave as described,\nmeasuring a circular distance in the x-y plane (ignoring the z axis)\nfrom the center of the fixtures that have been assigned to participate\nin the effect. This is why it is easy to set up a family of similar\neffects which create different spatial transitions for the color cycle\nchase.\n\nFor example,\n{api-doc}afterglow.effects.fun.html#var-wipe-right-color-cycle-chase[Wipe\nRight], which transitions the lights from left to right, ignoring both\nthe y and z axes. The work of both of these chases is simplified with\nthe help of\n{api-doc}afterglow.transform.html#var-build-distance-measure[`afterglow.transform/build-distance-measure`],\na function for constructing distance measure functions for use in\neffects like this, and\n{api-doc}afterglow.transform.html#var-calculate-bounds[`afterglow.transform/calculate-bounds`],\nwhich calculates a bounding box and center for a group of fixtures and\nthe heads which make them up.\n\n[source,clojure]\n----\n(show/add-effect! :color\n  (afterglow.effects.fun/wipe-right-color-cycle-chase (show/all-fixtures)))\n----\n\n[[sparkle]]\n==== Sparkle\n\nCreates a random sparkling effect like a particle generator over the\nsupplied RGB fixture heads. See the\n{api-doc}afterglow.effects.fun.html#var-sparkle[API\ndocumentation] for details.\n\n[source,clojure]\n----\n(show/add-effect! :sparkle\n  (afterglow.effects.fun/sparkle (show/all-fixtures)))\n----\n\nYou can also create a\n{api-doc}afterglow.effects.fun.html#var-dimmer-sparkle[similar\neffect] with fixtures that have only dimmer channels, rather than RGB\ncapabilities.\n\n[source,clojure]\n----\n(show/add-effect! :sparkle\n  (afterglow.effects.fun/dimmer-sparkle (show/all-fixtures)))\n----\n\nAnd if you want to run a sparkle effect on both kinds of fixtures at\nthe same time, you can combine these two effects with a\n<<scenes,Scene>>.\n\n[source,clojure]\n----\n(show/add-effect! :sparkle\n  (afterglow.effects/scene \"Sparkle all\"\n    (afterglow.effects.fun/sparkle (show/all-fixtures))\n    (afterglow.effects.fun/dimmer-sparkle (show/all-fixtures))))\n----\n\n\n[[strobe]]\n==== Strobe\n\nA flexible strobe effect designed for intuitive tweaking via pressure-sensitive controllers like the Ableton Push.\nSee the\n{api-doc}afterglow.effects.fun.html#var-strobe[API\ndocumentation] for details.\n\n[source,clojure]\n----\n(show/add-effect! :strobe-all\n  (afterglow.effects.fun/strobe \"Strobe All\" (show/all-fixtures) 50))\n----\n\n[[metronome]]\n==== Metronome\n\nThe Metronome cue is a way to check the synchronization of the show\nmetronome with your DJ software or mixer if you don't have an Ableton\nPush or an easy way to pull up the web interface, and is mostly a nice\nexample of how to write a cue that is driven by a metronome. It was\none of the first clearly metronome-driven effects written, and was\nextremely useful when developing the metronome sync facilities\n(especially since at the time there was no web or Ableton Push\ninterface, with their metronome monitoring and adjustment sections).\nToday it is less interesting, especially compared to the color cycle\nchases described above.\n\n[source,clojure]\n----\n(show/add-effect! :color\n  (afterglow.effects.fun/metronome-effect (show/all-fixtures)))\n----\n\nCreates an effect which flashes the heads of the supplied fixtures one\ncolor on the down beat and another color on the other beats of the\nshow metronome. The default down beat color is a lightened red, and\nthe other beat color is a darkened yellow; these can be overridden by\noptional keyword parameters. See the\n{api-doc}afterglow.effects.fun.html#var-metronome-effect[API\ndocumentation] for details.\n\n[[the-effect-lifecycle]]\n== The Effect Lifecycle\n\nWhen an effect is added to a show via `(show/add-effect! :effect-key\neffect)` it immediately replaces any other effect which had been\npreviously added with the same keyword. The former effect does not get\na chance to gracefully finish its effects, it is simply gone. The new\neffect is added to the <<rendering_loop.adoc#,rendering loop>> in a\nposition determined by the priority value, if any, specified after the\noptional `:priority` keyword argument. If no priority argument is\nsupplied, a priority of zero is used. The new effect is added after\nany other existing effects of the same (or lower) priority, but before\nany existing effects with higher priority. Since later effects get a\nchance to override earlier effects, this means that higher-priority\neffects, and effects added later, win.\n\nAll effects implement the\n{api-doc}afterglow.effects.html#var-IEffect[`afterglow.effects/IEffect`]\nprotocol. As each frame of lighting control values is rendered, a\nsnapshot is created from the show metronome, so every effect shares the\nsame notion of the point in time at which effects are being rendered.\nThe priority-ordered list of effects is traversed, and each effect’s\n`(still-active? [this show snapshot])` function is invoked to determine\nif the effect has ended at this point. If this returns `true`, the\neffect is removed from the list of active effects, and is finished.\nLimited-time effects can use this mechanism to tell the show when they\nfinish. Ongoing effects will simply always return `true`, or if they\nwant to end gracefully, will return `true` until they have been asked to\nend, and their graceful ending has completed.\n\nAssuming the effect has not reported completion, its `(generate [this\nshow snapshot])` function will be called, as described in the\n<<rendering_loop.adoc#,rendering loop>> section, to create the effect\nit represents at this point in time.\n\nAt some point, the show operator may indicate a desire for the effect\nto end, by calling `(show/end-effect! :effect-key force)`. If `force`\nis `true`, the specified effect will simply be removed from the list\nof active effects. If `force` is omitted or `false`, the effect is\nasked to end gracefully by calling its `(end [this show snapshot])`\nfunction. If the effect is ready to end right away, it can return\n`true`, and will be removed at that point. Otherwise, if it wants to\ntake a little while to animate an ending effect, it should set an\ninternal flag so it knows it is ending and return `false`, and at some\npoint in the not-so-distant future, conclude its ending and return\n`false` from `still-active?`.\n\nWARNING: As implied by the preceding paragraph, your effect cannot rely\non its `end` function ever being called. If the effect is ended\nforcibly, if another effect is added under the same keyword, or if it\nis taking part in a fade, at some point it will simply be discarded.\nIt must therefore not retain any resources that will not be reclaimed\nby simple garbage collection.\n\nIf `end-effect!` is called a second time for an effect which was already\nasked to end, even if `force` is false, it will be removed forcibly at\nthat point.\n\n[[effect-examples]]\n== Effect Examples\n\nHere are a few ways in which effects can be used and combined.\n\nNOTE: These examples assume you are in a Clojure REPL with Afterglow loaded,\nin the namespace `afterglow.examples`. This is the default namespace you\nget if you check out the project and run `lein repl`.\n\n\n[[oscillator-effects]]\n=== Oscillator Effects\n\nOscillators in Afterglow are a flexible way of turning the timing\ninformation tracked by metronomes into waveforms that can be used to\nmake lights do interesting things. They can be related to the beats or\nbars of the metronome, or multiples or fractions thereof, and can be\nsawtooth, triangle, square, or sine waves.\nhttp://en.wikipedia.org/wiki/Sawtooth_wave[Wikipedia] has a nice\nintroduction to these waveforms. The namespace\n`afterglow.effects.oscillator` has <<oscillators.adoc#,functions>> for\ncreating lots of variations on them.\n\nHere is one way to create a basic oscillated hue effect which cycles\nthrough all colors over one bar of the show metronome:\n\n[source,clojure]\n----\n(def hue-param (oscillators/build-oscillated-param\n                 (oscillators/sawtooth :interval :bar) :max 360))\n(show/add-effect! :color (global-color-effect\n   (params/build-color-param :s 100 :l 50 :h hue-param)))\n----\n\nTIP: Remember that if you aren’t seeing anything when after assigning\ncolor effects to a fixture to make sure you also have a dimmer effect\nsetting that fixture’s dimmer to some visible level. And if the\nfixture has a shutter (either physical or electronic), you may need an\neffect running to open that as well.\n\nWe can set up separate metronomes as show variables, so that effect\ntiming can be separate from the main show, which is intended to track\nthe beat of the music. Here we will create a metronome running at 5\nbeats per minute in a show variable we will call `timer`.\n\n[source,clojure]\n----\n    (show/set-variable! :timer (metronome 50))\n----\n\nThen we can build an oscillated hue parameter based on that timer, for a\nnice, gradual color fade. We will use a sawtooth wave since it smoothly\ngoes from its minimum to its maximum value. Zero is the default minimum,\nwhich is perfect, since it is the lowest hue value. We will tell the\noscillated parameter to range from that to a maximum of 360, the largest\nhue. Since hues form a circle, we will fade smoothly around the circle\nfor each oscillation, with no jarring transition from one bar to the\nnext:\n\n[source,clojure]\n----\n(show/set-variable! :hue-param\n  (oscillators/build-oscillated-param (oscillators/sawtooth :interval :bar)\n    :metronome :timer :max 360))\n----\n\nNotice the use of the keyword `:timer` to tell `build-oscillated-param`\nto use the show variable with that name for its `:metronome` keyword\nparameter. We can do the same thing when building our color effect to\nuse this oscillated hue parameter variable:\n\n[source,clojure]\n----\n(show/add-effect! :color (global-color-effect\n  (params/build-color-param :s 100 :l 50 :h :hue-param)))\n----\n\nWe can change the speed of the fade by changing the BPM of the\nmetronome stored in the show variable:\n\n[source,clojure]\n----\n(metro-bpm (show/get-variable :timer) 500)\n----\n\nSuddenly it is crazy fast!\n\n[source,clojure]\n----\n(metro-bpm (show/get-variable :timer) 5)\n----\n\nBack to a sedate fade.\n\n[[spatial-effects]]\n=== Spatial Effects\n\nRather than spreading the rainbow out in time, how about if we spread it\nphysically across the lights in the show, in the form of a rainbow\ngradient along the X axis?\n\n[source,clojure]\n----\n(def hue-gradient (params/build-spatial-param (show/all-fixtures)\n  (fn [head] (- (:x head) (:min-x @(:dimensions *show*)))) :end 360))\n(show/add-effect! :color (global-color-effect\n  (params/build-color-param :s 100 :l 50 :h hue-gradient)\n                            :include-color-wheels true))\n----\n\nNOTE: Since this cue is not constantly changing over time, it makes\nsense to allow fixtures that use color wheels to participate.\n\nThat’s pretty! But now that we have both of these interesting concepts,\noscillators and spatial gradients, wouldn’t it be nice if we could\ncombine them? Oh, but we can!\n\n[source,clojure]\n----\n(def adjust-param\n  (oscillators/build-oscillated-param (oscillators/sawtooth :interval :bar) :max 360))\n(show/add-effect! :color (global-color-effect\n  (params/build-color-param :s 100 :l 50 :h hue-gradient\n                            :adjust-hue adjust-param)))\n----\n\nNOTE: Now the rainbow drifts across the whole lighting rig. We left out color\nwheels this time, since the color is continually shifting.\n\nThe <<basic-effect-types,Basic Effect Types>> section goes into more\ndetail about how these effects work.\n\nTIP: Looking at the source code of the <<complex-effects,complex\neffects>> is a great way to learn about how to create effects, and to\nget ideas for ways to vary or build on them.\n\n[[layering-effects]]\n=== Layering Effects\n\nRather than building separate effects for every combination of ideas,\nyou can get much more power by building effects that build on or\nmodify each other, which you can then compose in different ways. The\nmost straightforward way of doing this is by combining effects that\nwork on different facets of the lights, such as when you choose a\ndimmer oscillator, to make them pulse in a particular way with the\nbeat, along with a color effect, and perhaps an aim or direction\nchase. Varying these effects can give you quite a palette of looks.\n\nThe Afterglow <<rendering_loop.adoc#,rendering loop>> is designed to\nlet you be even more flexible than that, though: you can combine\nmultiple effects which work on the same channels of the same fixtures,\nbecause of the way that later (and higher priority) effects can see\nwhat earlier effects have done, and modify the results.\n\nThe\n{api-doc}afterglow.effects.color.html#var-transform-colors[`transform-colors`]\neffect is an example of how easy and flexible this can be. (As always\nwith the API documentation, you can click on the `viw source` button\nto see the actual implementation of the function.) This effect uses\nits own variable parameter to adjust the saturation of any color being\nsent to the fixtures it is assigned. (If there isn't currently a color\nbeing assigned to those fixtures, it does nothing.) Calling it with no\narguments uses a default transformation and oscillated parameter which\ncauses the saturation of the color to start each beat fully saturated,\nand to fade to gray by the end of the beat. This was inspired by the\nrainbow fade effect which was initially created while experimenting\nwith\nhttps://github.com/Deep-Symmetry/afterglow-max#afterglow-max[afterglow-max],\nbut this generalization can be combined with any other color effect.\n\nThe `transform-colors` function itself does all the work of creating\nassigners that will watch for colors being sent to the fixtures it is\nsupposed to affect, and whenever appropriate, transforming them. The\ntransformation itself is separated into another function, which can be\npassed in as an argument to achieve a totally different kind of\ntransformation. The default transformation if none is specified is\ncreated by calling\n{api-doc}afterglow.effects.color.html#var-build-saturation-transformation[`build-saturation-transformation`]\nwith no arguments. The source of this function shows how easy it is to\nwrite a transformation given the support provided by the Rendering\nLoop and `transform-colors`.\n\n[source,clojure]\n----\n(defn build-saturation-transformation\n  \"Creates a color transformation for use with [[transform-colors]]\n  which changes the saturation based on a variable parameter. If no\n  parameter is supplied, the default is to use an oscillated parameter\n  based on [[sawtooth]] with `:down?` set to `true` so the color\n  is fully saturated at the start of the beat, and fully desaturated\n  by the end. A different pattern can be created by supplying a\n  different parameter with the `:param` optional keyword argument.\"\n  {:doc/format :markdown}\n  [& {:keys [param] :or {param (oscillators/build-oscillated-param (osc/sawtooth :down? true)\n                                                                   :max 100)}}]\n  (fn [color show snapshot head]\n    (let [saturation (colors/clamp-percent-float\n                      (params/resolve-param param show snapshot head))]\n      (colors/create-color {:h (colors/hue color) :s saturation :l (colors/lightness color)}))))\n----\n\nThis particular function takes an optional variable\nparameter to control what the current saturation should be (if you\ndon't provide one, it creates an\n<<parameters.adoc#oscillated-parameters,oscillated parameter>> which\nimplements the desaturate-over-each-beat behavior described above:\n\n[source,clojure]\n----\n(oscillators/build-oscillated-param (oscillators/sawtooth :down? true) :max 100)\n----\n\nThe downwards-direction sawtooth wave from 100 to 0 each beat causes\nthe saturation pattern described; changing to a different wave form,\nor something which oscillates over a bar or phrase or fraction\nthereof, or with different `:min` and `:max` values would achieve a\ndifferent effect.\n\nThe function returned by `build-saturation-transformation` is called\nby `transform-colors` when Afterglow is calculating a frame of DMX\ndata to send to the lights, whenver one of the lights that the\n`transform-colors` effect has been applied to is being sent a color\nvalue. The function is called with the color that has so far been\nassigned to the light (in `color`), and the current `show`, metronome\n`snapshot` representing the current instant in musical time (and which\ncan be used with an oscillated variable parameter as seen here to\ngenerate smoothly changing, rhythmically-driven values), and the light\n`head` this is being sent to (which can be used to perform\n<<spatial-effects,spatial>> calculations as described above). The\nfunction returns a new color to replace the former assignment (or it\ncould return `nil` to suppress coloring the light entirely).\n\nHaving all this information at hand, and the flexible power of\n<<oscillators.adoc#,oscillators>> and\n<<parameters.adoc#,dynamic>>,\n<<parameters.adoc#oscillated-parameters,oscillated>>, and\n<<parameters.adoc#spatial-parameters,spatial>> variable parameters,\nmakes it possible to write straightforward, concise transformation\nfunctions like this one.\n\nAnd of course you can change things other than\nsaturation; take a look at the source and try writing your own\ntransformation functions which do different things. When you come up\nwith exciting looks, please contribute them back to Afterglow!\n\nRemember that when you create a cue for an effect like\n`transform-color`, you want it to run _after_ the other effects that\nit is going to transform, so give it a high effect priority. Here is\nhow the sample show configures it:\n\n[source,clojure]\n----\n(ct/set-cue! (:cue-grid *show*) 2 7\n             (cues/cue :transform-colors (fn [_] (color-fx/transform-colors\n                                                  (show/all-fixtures)))\n                       :priority 1000))\n----\n\nAnd here is a complete, concrete example of how you can try out\n`transform-colors` from the REPL:\n\n[source,clojure]\n----\n(show/add-effect! :color\n  (afterglow.effects/scene \"Blue Sparks\"\n    (global-color-effect :blue)\n    (color-fx/transform-colors (show/all-fixtures) :priority 1000)))\n----\n\n> This assigns a blue color to all the lights, and pulses them to\nwhite once per beat.\n"
  },
  {
    "path": "doc/modules/ROOT/pages/fixture_definitions.adoc",
    "content": "= Fixture Definitions\nJames Elliott <james@deepsymmetry.org>\n\n// TODO: Can the following be defived from Antora, or just eliminated?\n:branch-base: https://github.com/Deep-Symmetry/afterglow/blob/master/\n\nFixture definitions tell Afterglow what capabilities a given piece of\nlighting hardware has, and how to control it to get the effects that are\nbeing requested.\n\n== Overview\n\nThere are a vast number of fixture types out there, and at this early\nstage almost none of them are built in to Afterglow, so you will\nprobably need to create your own. You can study the existing fixture\ndefinitions for examples of how it is done. You can also ask for help\non the https://github.com/Deep-Symmetry/afterglow/wiki/Questions[wiki].\n\n[TIP]\n====\nWhen you first embark on the project of creating a fixture\ndefinition, it might seem overwhelming. This page is long, and\nincludes a great deal of complicated detail. But don't despair! First,\nremember that most fixtures only do a subset of the kinds of things\nthat the fixture definition mechanism needs to handle, so you do not\nneed to learn and understand all of it at once. And even more helpful\nto beginners, realize that you do not need to finish your fixture\ndefinition before you can start using and testing it. Your fixture may\nbe capable of many things, but start out by defining just a couple of\nchannels that will make it at least light up, and see if you can get\nthose working in a show. Once they are, you can already use the\nfixture at least at that level. And that success can be a foundation\nfor digging deeper into other types of channels, which you can add to\nyour definition one at a time, building on what you learn as you go\nalong.\n\nAlso, as of version 0.1.3, Afterglow can read fixture definitions from\nthe http://www.qlcplus.org[QLC+] lighting controller and use those to\n<<translating-qlc-fixture-definitions,create a starting point>> for\nyou. Since there are far more fixtures already defined for QLC+, that\ncan be a huge help.\n====\n\nThe namespace\n{api-doc}afterglow.fixtures.html[`afterglow.fixtures`]\nhas definitions for very basic one-channel generic dimmers and\nswitches. Looking at the source for those can illustrate the most\nbasic structure of a fixture definition. It also contains some helper\nfunctions Afterglow uses in processing fixture definitions.\n\nThe namespace\n{api-doc}afterglow.fixtures.american-dj.html[`afterglow.fixtures.american-dj`]\ncontains definitions for fixtures made by American DJ. Currently, only\nthe Hypnotic RGB laser is present.\n\nThe namespace\n{api-doc}afterglow.fixtures.blizzard.html[`afterglow.fixtures.blizzard`]\nis the most complete so far, mostly because the author lives close to\nBlizzard and mostly owns fixures made by them. It includes definitions\nfor a full-featured moving head spot (the Torrent F3), a moving head\ncolor-mixing LED fixture (the Blade RGBW), an LED five-color Par (the\nPuck Fab5), an eight-head RGB system (the Weather System), and an RGBW\nmoonflower effect (the Snowball). These might be useful examples for\nfixtures you want to create.\n\nThe namespace\n{api-doc}afterglow.fixtures.chauvet.html[`afterglow.fixtures.chauvet`]\nis for fixtures made by Chauvet.\n\n[[structure]]\n== Structure of a Fixture Definition\n\nOnce created, a fixture definition is simply a Clojure map with keys\nand values that tell Afterglow how to control it. The fixture\ndefinition functions linked to above simply create and return these\nmaps.\n\nFixtures may have multiple \"personalities\" or _modes_ which change the\nnumber and meaning of the control channels they use, and the features\nthat are available. For such fixtures, the mode is generally given as\nan argument to the fixture definition function, and tells it what\nversion of the map to return. For convenience, the function may let\nyou call it with no argument, and assume a default mode. Its\ndocumentation should reflect this, see for example the\n{api-doc}afterglow.fixtures.blizzard.html#var-blade-rgbw[`blade-rgbw`]\ndocumentation.\n\nWhen you are learning how to write fixture definitions, it can be\nhelpful to compare the fixture definition functions, which call helper\nfunctions described on this page, with the actual maps that they\nreturn. This can be facilitated by using `clojure.pprint/pprint` to\npretty-print the map that you get when calling the function. For\nexample:\n\n[source,clojure]\n----\n(clojure.pprint/pprint (afterglow.fixtures.blizzard/snowball))\n {:name \"Blizzard Snowball\",\n  :channels\n  [{:offset 1,\n    :type :dimmer,\n    :functions\n    [{:start 0,\n      :end 255,\n      :range :variable,\n      :type :dimmer,\n      :label \"Dimmer\"}]}\n   {:offset 2,\n    :type :color,\n    :functions\n    [{:start 0, :end 255, :range :variable, :type :red, :label \"Red\"}],\n    :color :red}\n; [...many channels omitted for brevity...]\n   {:offset 9,\n    :type :control,\n    :functions\n    [{:start 0,\n      :range :fixed,\n      :type :no-function,\n      :label \"No function\",\n      :end 127}\n     {:range :variable,\n      :label \"Sound-active\",\n      :type :sound-active,\n      :var-label \"Sensitivity\",\n      :start 128,\n      :end 255}]}]}\n; -> nil\n----\n\nEven though most of the channels were cut out to shorten that example,\nit is still pretty long. Still, it gives a sense of the shape of a\nfixture definition. You may have noticed that there were only two\ntop-level keys in the returned map, `:name` and `:channels`. Those\nare the only two that need to be there for a simple fixture. And\nalmost all of the information Afterglow needs is found in the\n`:channels` list, so that is where you will spend most of your work in\ncreating the fixture definition.\n\nIf you had already looked at the source for\n{api-doc}afterglow.fixtures.blizzard.html#var-snowball[`snowball`]\n(which you can get to by clicking the `view source` button at the\nbottom of all the API documentation entries), you might have noticed\nthat the source is a lot shorter than the resulting map. That's\nbecause it can take advantage of a bunch of helper functions described\non this page to help with the tedious and repetetive parts of\nconstructing the map. And when you patch a fixture into a show using\n{api-doc}afterglow.show.html#var-patch-fixture.21[`afterglow.show/patch-fixture!`]\nthe map gets much bigger again, as Afterglow annotates it with\ninformation you provided during the patching process, assigning the\nactual universes and DMX channels for each logical channel in the\nfixture definition, and figuring out the location in space and aiming\ndirection, potentially of several heads of a multi-head fixture.\n\nSo, let's look at the fixture definition map contents in detail.\n\n[cols=\"2l,5a\", options=\"header\"]\n|===\n|Key\n|Purpose\n\n|:name\n\n|A string which identifies the manufacturer and model of fixture.\n\n|:channels\n\n| A list of channel specifications which tell Afterglow about the DMX\nchannels that the fixture responds to, and how to make it do different\nthings. This is the meat of the fixture definition, and is described\nin detail <<channel-specifications,below>>.\n\n|:mode\n\n|If present, identifies the fixture mode in which this definition map\n was created. As desrcibed above, some fixtures can be configured to\n have different &ldquo;personalities&rdquo; which use a different\n number of DMX channels and provide a different set of features. Their\n fixture definition functions will use a `mode` argument to determine\n the mode in which the fixture is operating, and return an appropriate\n map. That map will include the chosen mode keyword as the value at\n this key.\n\n|:heads\n\n|If a fixture has multiple independent heads, which can be controlled\n individually, the channels which control the heads are grouped into a\n list under this key. Each entry in the list is a map which explains a\n single head. It will contain its own `:channels` key with the channel\n specifications controlling that specific head, and will also contain\n geometric information about the offset of that particular head from\n the geometric center of the fixture, so Afterglow can figure out\n where the head is in space when the fiture is patched into the show.\n This is described in more detail <<head-specifications,below>>.\n\n|:pan-center\n\n|If this fixture is a moving head capable of pan movements, this entry\n tells afterglow the DMX value to send the fixture to pan it directly\n at the audience when the fixture is hung at its standard orientation.\n (The documentation you create for your fixture definition needs to\n explain what this default orientation is, so that people patching\n your fixture can figure out the proper angle information to tell\n Afterglow if they hung it in a different orientation, as explained in\n <<show_space.adoc#,Show Space>>.) The `:pan-center` value should pan\n the light so it is aimed exactly along the show Z axis when also\n tilted to `:tilt-center`.\n\nMany fixtures can pan more than once around a full circle, so you may\nhave a choice of values to supply here, all of which pan the fixture\ndirectly towards the audience in your default hanging orientation. If\nso, pick one towards the middle of the DMX range, giving Afterglow\nroom to maneuver without having to flip to the opposite end of the pan\nrange regardless of how the fixture has been hung.\n\nIf the fixture cannot pan far enough to aim directly at the audience\nwhen it is hung in its default orientation, you may be better off\nchoosing a different default hanging orientation. But if you do not\nwant to do that, you can set this to the closest value outside the\nlegal DMX range which would cause the fixture to pan that far if it\nwere legal and possible, and Afterglow will still be able to figure\nout and use the legal movements that the fixture is capable of.\n\n|:pan-half-circle\n\n|If this fixture is a moving head capable of pan movements, this entry\n tells Afterglow the amount it needs to add to the DMX value sent on\n the fixture's Pan channel to pan it halfway around a circle in a\n counterclockwise direction. Afterglow uses this to figure out how to\n aim the head exactly where you want it. If your fixture is not\n capable of panning that far, this value may be larger than a legal\n DMX value. That is fine, Afterglow will figure that out. Simply\n always give it the value which, when added to some legal Pan channel\n value, would cause the fixture to rotate counterclockwise halfway\n around a circle if it could rotate that far. (This number could be\n negative if the fixture turns clockwise when the pan value is\n increased in its default hanging orientation.)\n\nThe <<show_space.adoc#,Show Space>> page explains how to figure out\nwhich rotations are clockwise or counterclockwise with respect to\ndifferent axes. Pan motions are rotations around the fixture Y axis.\n\n|:tilt-center\n\n|If this fixture is a moving head capable of tilt movements, this\n entry tells afterglow the DMX value to send the fixture to tilt it\n directly at the audience when the fixture is hung at its standard\n orientation. (The documentation you create for your fixture\n definition needs to explain what this default orientation is, so that\n people patching your fixture can figure out the proper angle\n information to tell Afterglow if they hung it in a different\n orientation, as explained in <<show_space.adoc#,Show Space>>.) The\n `:tilt-center` value should tilt the light so it is aimed exactly\n along the show Z axis when also panned to `:pan-center`.\n\nSome fixtures can tilt more than once around a full circle, so you may\nhave a choice of values to supply here, all of which tilt the fixture\ndirectly towards the audience in your default hanging orientation. If\nso, pick one towards the middle of the DMX range, giving Afterglow\nroom to maneuver without having to flip to the opposite end of the tilt\nrange regardless of how the fixture has been hung.\n\nIf the fixture cannot tilt far enough to aim directly at the audience\nwhen it is hung in its default orientation, you may be better off\nchoosing a different default hanging orientation. But if you do not\nwant to do that, you can set this to the closest value outside the\nlegal DMX range which would cause the fixture to tilt that far if it\nwere legal and possible, and Afterglow will still be able to figure\nout and use the legal movements that the fixture is capable of.\n\n|:tilt-half-circle\n\n|If this fixture is a moving head capable of tilt movements, this entry\n tells Afterglow the amount it needs to add to the DMX value sent on\n the fixture's Tilt channel to tilt it halfway around a circle in a\n counterclockwise direction. Afterglow uses this to figure out how to\n aim the head exactly where you want it. If your fixture is not\n capable of tilting that far, this value may be larger than a legal\n DMX value. That is fine, Afterglow will figure that out. Simply\n always give it the value which, when added to some legal Tilt channel\n value, would cause the fixture to rotate counterclockwise halfway\n around a circle if it could rotate that far. (This number could be\n negative if the fixture turns clockwise when the tilt value is\n increased in its default hanging orientation.)\n\nThe <<show_space.adoc#,Show Space>> page explains how to figure out\nwhich rotations are clockwise or counterclockwise with respect to\ndifferent axes. Tilt motions are rotations around the fixture X axis.\n\n|===\n\n[[channel-specifications]]\n=== Channel Specifications\n\nThe `:channels` entry for a fixture or head definition map tells\nAfterglow the control channels that can be used to make that fixture\nor head do things. It is a list of maps, each of which describes the\nnature and capabilities of a single channel that the fixture or head\nresponds to.\n\nTIP: Although there is a lot of detail in this table, you don't\nnecessarily need to understand it all to create fixture definitions,\nbecause Afterglow provides <<channel-creation-functions,channel\ncreation functions>> to create these maps for you.\n\nEach channel specification map has the following content:\n\n[cols=\"2l,5a\", options=\"header\"]\n|===\n|Key\n|Purpose\n\n|:offset\n|[[channel-offset]]The number that identifies the channel. Each\n fixture listens to one or more channels, and is itself configured to\n a partcular DMX channel number (DMX channels range from 1 to 512).\n That configuration defines the _first_ channel the fixture\n listens to. The `:offset` value tells Afterglow how the current\n channel specification relates to the fixture's configured (starting)\n channel number. An offset of `1` corresponds to the first channel the\n fixture is listening to, which would be the channel number configured\n on the fixture's front panel (or via its DIP switches or jumpers if\n it is really old-school). The second channel would have offset `2`,\n and would correspond to the channel one greater than the fixture is\n configured to listen to.\n\nAlthough it might seem more natural (at least to a programmer) to\nstart the offset with `0`, because then you could calculate the actual\nchannel number by simply adding the offset to the address at which the\nfixture is configured to listen, most lighting manuals describe their\nfixture channels with numbers that start with `1`, so Afterglow\nfollows that convention.\n\nThe offsets for all the channel specifications in a fixture definition\nshould form a continuous series of integers starting from 1 and going\nup to the number of channels the fixture supports. It is an error if\nmore than one channel specification in the fixture definition uses the\nsame offset value, and if there are any gaps it probably means that\nyou have missed a channel specification (except for multi-byte\nchannels, as described in the next row). You don't need to define the\nchannels in the same order as their offsets in your fixture\ndefinition, although that is a reasonable practice, making it easier\nto match them up with the manual.\n\n|:fine-offset\n|There is one circumstance in which there _will_ be gaps in the\n`:offset` values for your channel definitions. Sometimes a pair of\nchannels are used to express a single value, such as pan, tilt, or a\ndimmer level, because the normal DMX value range, from 0 to 255, does\nnot give enough precision to allow smooth movements or fades. In those\ncases, you specify the channel number containing the\nmost-significant byte (MSB) of the value as the `:offset`, and the\nchannel containing the least-significant byte (LSB) is specified in\nthe same channel specification using the key `:fine-offset`. The\nfunction\n{api-doc}afterglow.channels.html#var-fine-channel[`afterglow.channels/fine-channel`]\nhelps create such a channel specification map. (In fact, it has other\nhandy features which make it useful even when you are creating a\nchannel specification that does not need a `:fine-offset` value).\n\n|:type\n|Tells afterglow the kind of channel this is. Special values include\n `:color` for a channel that contains a color intensity, `:dimmer` for\n controlling brightness independent of color, and `:pan` and `:tilt`\n for controlling moving heads. Other channels may use keywords that\n Afterglow does not recognize. A common keyword used for a grab-bag\n channel which may do many things depending on the exact DMX value\n sent is `:control`.\n\n|:color\n|When the channel `:type` is `:color`, this key is also present to\n tell Afterglow what color the channel controls the intensity of.\n Afterglow uses this information to enable color mixing using multiple\n color channels. The value of this key will be a keyword. The values\n `:red`, `:green`, `:blue`, and `:white` are understood and supported\n for color mixing automatically. If your fixture has LEDs of other\n colors and you would like Afterglow to include them in its color\n mixing calculations, in addition to supplying a `:color` value for\n their channel, you will need to specify a `:hue` value (below), so\n Afterglow knows how to mix them in.\n\n|:hue\n|[[hue-mixing]]When the channel `:type` is `:color`, this key is optionally present\n to tell Afterglow the hue value of the LEDs controlled by the\n channel. This allows Afterglow to perform color mixing with\n non-standard LED colors. Its value is the numeric hue (expressed in\n terms of degrees around the color circle) of the LEDs. The best way\n to find that is with a colorimeter, but since most of us can't afford\n them, you can approximate it by working with graphic design software,\n or even entering the color name on\n https://www.wolframalpha.com[Wolfram Alpha].\n\nIf you don't want Afterglow to mix colors using this channel, leave\nout the `:hue` entry. The fixture definition function for the Chauvet\n{api-doc}afterglow.fixtures.chauvet.html#var-slimpar-hex3-irc[SlimPar\nHex3 IRC] uses optional keyword arguments to let the show creator\ndecide whether or not to include them for its amber and ultraviolet\nchannels.\n\n|:functions\n|A list of <<function-specifications,Function Specifications>> which\n identify ranges of DMX values that can be sent to the channel, and\n which perform particular functions. Fixture manufacturers often use a\n single DMX channel to achieve many different kinds of effects, in\n order to not use up the DMX address space, especially when it would\n not make sense to try to activate two or more of the functions at the\n same time. Afterglow effects and cues can work in terms of these\n function definitions, and it often makes sense to do so even for\n channels which implement only a single function, so you don't need to\n worry about how a function is implemented when designing your effect\n or cue. Because of that, the channel creation functions add a\n function map even when you are creating a single-function channel.\n\n|:inverted-from\n|[[inverted-channels]]If this key is present, the value established\nby the channel's <<rendering_loop.adoc#channel-assigners,assigners>> will\nbe\n{api-doc}afterglow.effects.channel.html#var-apply-channel-value[reversed]\nwhen it is sent to the fixture. This is necessary to support fixtures\nwhich have inverted dimmer channels, and can be configured when\n<<dimmer-channels,creating>> the dimmer channel\nspecification.\n\n|===\n\n[[head-specifications]]\n=== Head Specifications\n\nAs described above, the `:heads` entry in a fixture definition map is\na list that describes each individually controllable head within that\nfixture. It may be a separate moving head, or it may just be an\nindividually-addressable pixel. If a fixture has only one\nlight-emitting head, it does not need a head specification list at\nall; everthing Afterglow needs to know about it will be contained in\nthe main fixture definition. But if there is more than one place on\nthe fixture that can be controlled independently, you will want to\norganize them into heads, and tell Afterglow their spatial\nrelationships as well as which channels control which head, using a\nhead specifications list. Each element of the list is a map with the\nfollowing content:\n\n[cols=\"2l,5a\", options=\"header\"]\n|===\n|Key\n|Purpose\n\n|:channels\n| A list of channel specifications which tell Afterglow about the DMX\nchannels that this individual head responds to. These have exactly the\nsame structure as the channel specifications for the main fixture, as\ndescribed <<channel-specifications,above>>. A channel can only be\nlisted in one place or the other. If it affects the entire fixture, it\nshould be in the main list; if it affects only a single head, it\nshould be in that head's list.\n\n|:x\n|The offset along the fixture X axis, in meters, from the geometric\n center of the fixture (the point at which Afterglow is told the\n fixture is located when patching the fixture) and the geometric\n center of this head. If this head is centered along the fixture X\n axis, you can omit this value or you can supply it with a value of\n 0.0. The <<show_space.adoc#,Show Space>> page illustrates the\n axes and links to a function you can use for converting inches to\n meters.\n\n|:y\n|The offset along the fixture Y axis, in meters, from the geometric\n center of the fixture (the point at which Afterglow is told the\n fixture is located when patching the fixture) and the geometric\n center of this head. If this head is centered along the fixture Y\n axis, you can omit this value or you can supply it with a value of\n 0.0. The <<show_space.adoc#,Show Space>> page illustrates the\n axes and links to a function you can use for converting inches to\n meters.\n\n|:z\n|The offset along the fixture Z axis, in meters, from the geometric\n center of the fixture (the point at which Afterglow is told the\n fixture is located when patching the fixture) and the geometric\n center of this head. If this head is centered along the fixture X\n axis, you can omit this value or you can supply it with a value of\n 0.0. The <<show_space.adoc#,Show Space>> page illustrates the\n axes and links to a function you can use for converting inches to\n meters.\n\n|:x-rotation\n|If this head aims in a different direction than the fixture as a\n whole, this value tells afterglow the angle in radians it is rotated\n around the X axis. The <<show_space.adoc#,Show Space>> page\n illustrates the axes, explains how to calculate the sign of a\n rotation, and links to a function you can use for converting degrees\n to radians.\n\n|:y-rotation\n|If this head aims in a different direction than the fixture as a\n whole, this value tells afterglow the angle in radians it is rotated\n around the Y axis. The <<show_space.adoc#,Show Space>> page\n illustrates the axes, explains how to calculate the sign of a\n rotation, and links to a function you can use for converting degrees\n to radians.\n\n|:z-rotation\n|If this head aims in a different direction than the fixture as a\n whole, this value tells afterglow the angle in radians it is rotated\n around the Z axis. The <<show_space.adoc#,Show Space>> page\n illustrates the axes, explains how to calculate the sign of a\n rotation, and links to a function you can use for converting degrees\n to radians.\n\n|===\n\n[[function-specifications]]\n=== Function Specifications\n\nFunction specifications allow a single channel to be broken up into a\nseries of value ranges which accomplish different purposes. As noted\nabove, fixture manufacturers often do this so that they can provide a\nlot of functionality without taking up too much of the DMX address\nspace. And since fixtures often have functions which cannot be\nactivated at the same time, such as selecting a particular gobo on a\ngobo wheel, it makes great sense.\n\nThe `:functions` entry in a channel specification map lists all the\nfunctions that a given channel offers. In order to work well with\n<<effects.adoc#function-effects,Function Effects>> and\n<<cues.adoc#creating-function-cues,Function Cues>> it is best to\nprovide a function list even for channels which only perform a single\nfunction. A function list is a list of maps, each of which identifies\na range of values that do something when the channel is set to a value\nwithin that range. Each map has the following content:\n\n[cols=\"2l,5a\", options=\"header\"]\n|===\n|Key\n|Purpose\n\n|:start\n|The beginning of the function range: the lowest DMX value which\n activates this function on the channel. Must be a legal DMX value,\n from `0` to `255`, and less than or equal to `:end`. Ranges must not\n overlap, so this value must be greater than the `:end` value of any\n other function range defined for the channel.\n\n|:end\n|The end of the function range: the highest DMX value which activates\n this function on the channel. Must be a legal DMX value, from `0` to\n `255`, and greater than or equal to `:start`. Ranges must not\n overlap, so this value must be less than the `:start` value of any\n other function range defined for the channel.\n\n|:type\n|A keyword which identifies the nature of the function. This is how\n <<effects.adoc#function-effects,Function Effects>> and\n <<cues.adoc#creating-function-cues,Function Cues>> will find the effect,\n so it is important to be consistent when assigning function types.\n The list of <<standard-function-types,standard function types>> is a\n good starting point. If you feel there is a common kind of function\n which should be added to that list, please open an\n https://github.com/Deep-Symmetry/afterglow/issues[issue] requesting it.\n\n|:range\n|Tells Afterglow what kind of a function range this is. Some functions\n are simply either off or on, and even if multiple DMX values exist\n within the function range, the result of using any of them is no\n different from using another. Such functions are identified by a\n `:range` type of `:fixed`. Other functions, such as a rotation speed\n or focus, will have different effects for every value in the range,\n and are identified by a `:range` type of `:variable`. This helps\n Afterglow build an appropriate user interface for interacting with\n <<effects.adoc#function-effects,Function Effects>> in places like the\n <<push2.adoc#effect-control,Ableton Push Effect Control interface>>.\n\n|:label\n|Specifies a label that should be used when creating a user interface\n that refers to this function. <<cues.adoc#creating-function-cues,Function\n Cues>> will use this as the label text in the grid cell they create\n in the <<README.adoc#web-ui,web interface>>. If omitted, a capitalzed\n version of the value of the `:type` keyword (without its leading\n colon) is used as the label; this entry allows you to specify\n something more readable.\n\n|:var-label\n|Specifies a label that should be used when creating a user interface\n for adjusting the value associated with this function (so it makes\n sense to set this only when `:range` is `:variable`).\n <<cues.adoc#creating-function-cues,Function Cues>> will use this as the\n label for the cue-local variable they create, and it will appear in\n places like the <<push2.adoc#effect-control,Ableton Push Effect\n Control interface>>. If omitted, the generic label\n &ldquo;Level&rdquo; will be displayed under the encoder knob.\n\n|:scale-fn\n|A function that will be called to scale the function value being\n requested by an effect. For functions whose `:range` is `:variable`,\n Afterglow function effects can vary the value being sent to activate\n the function. They normally do this as a percentage, where 0 maps to\n the `:start` of the range, and 100 maps to the `:end`, and values in\n between are scaled appropriately.\n\nIf there is a reason to tweak the values on the way in, you can store\na function at this key in the function specification, and Afterglow\nwill call the function with the percentage value the effect requested,\nand expect the function to return a modified percentage value to use\nto actually pick the DMX value to send. A good example of a reason to\ndo this is with the `strobe` function, so that different fixtures can\nbe coaxed into strobing at roughly the same rate. The fixture\ndefinitions that ship with Afterglow use\n{api-doc}afterglow.effects.channel.html#var-function-value-scaler[`afterglow.effects.channel/function-value-scaler`]\nto build `:scale-fn` functions for their `:strobe` functions so that,\nrather than a percentage, the strobe function value is interpreted as\nan approximate tenth-Hz rate (flashes per ten seconds), normalized for\neach fixture. The example in the <<function-channels,Function\nChannels>> section below explains this further.\n\n|===\n\n[[channel-creation-functions]]\n=== Channel Creation Functions\n\nThe\n{api-doc}afterglow.channels.html[`afterglow.channels`]\nnamespace provides a number of functions to help you create channel\nspecifications in your fixture definitions. You will see these used\nall over the place in the fixture definitions which ship with\nAfterglow; here is an introduction to how they work.\n\n[[color-channels]]\n==== Color Channels\n\n{api-doc}afterglow.channels.html#var-color[`afterglow.channels/color`]\nreturns a channel specification for a channel that controls an\nindividual color intensity (such as with an RGB LED fixture). Its two\nmandatory arguments are the channel `offset` (the channel number\nreported in the fixture manual, assuming they are numbered starting\nwith `1` as described <<channel-offset,above>>), and the `color`, a\nkeyword naming the color. The standard colors `:red`, `:green`,\n`:blue`, and `:white` will automatically participate in Afterglow's\ncolor mixing for <<effects.adoc#color-effects,Color Effects>>. If your\nfixture has other color channels, and you would like them to\nparticipate in color mixing as well, pass the hue value of the color\nchannel with the optional keyword argument `:hue`. (See the discussion\n<<hue-mixing,above>> for ways to determine the hue value of your color\nchannel.)\n\nIf your fixture supports two-byte color values for more precise color\nmixing, use the most-significant byte as the `offset` value, and pass\nthe offset of least-significant byte using the optional keyword\nargument `:fine-offset`.\n\nIf you want to use a label which differs from the name of the `color`\nkeyword in the user interface when\n<<push2.adoc#effect-control,adjusting>>\n<<cues.adoc#creating-function-cues,Function Cues>> (for example, if the\nkeyword is hyphenated, and you want the label to use a space), specify\nyour desired label with the optional keyword argument\n`:function-label`.\n\n[[dimmer-channels]]\n==== Dimmer Channels\n\n{api-doc}afterglow.channels.html#var-dimmer[`afterglow.channels/dimmer`]\nreturns a specification for a channel that controls the dimmer of a\nfixture or head. It always takes at least one argument, the channel\n`offset` (as described <<channel-offset,above>>). If the fixture uses\ntwo-byte values for more precise dimmer control, use the\nmost-significant byte as the `offset` value, and pass the offset of\nthe least-significant byte using the optional keyword argument\n`:fine-offset`.\n\nNormal dimmers are dark at zero, and get brighter as the channel value\nincreases, to a maximum brightness at 255. However, some fixtures have\ninverted dimmers. If that is the case for the fixture you are\ndefining, pass the DMX value at which the inversion takes place with\n`:inverted-from`. For example, fixtures which are brightest at zero\nand darken as the value approaches 255 would be specified as\n`:inverted-from 0`, while fixtures which are dark at zero, jump to\nmaximum brightness at 1, then dim as the value grows towards 255 would\nbe specified as `:inverted-from 1`.\n\n[[focus-channels]]\n==== Focus Channels\n\n{api-doc}afterglow.channels.html#var-focus[`afterglow.channels/focus`]\nreturns a specification for a channel that controls the focal plane of\na fixture or head, usually a moving head spot which can project gobo\n(template) images. It always takes at least one argument, the channel\n`offset` (as described <<channel-offset,above>>). If the fixture uses\ntwo-byte values for more precise focus control, pass the offset of\nthe channel that controls the most-significant byte as the `offset`\nargument, and pass the offset of the channel that controls the\nleast-significant byte as the second argument, `fine-offset`.\n\n[[frost-channels]]\n==== Frost Channels\n\n{api-doc}afterglow.channels.html#var-frost[`afterglow.channels/frost`]\nreturns a specification for a channel that controls the frost effect\nof a fixture or head, softening the beam of light it emits. It always\ntakes at least one argument, the channel `offset` (as described\n<<channel-offset,above>>). If the fixture uses two-byte values for\nmore precise focus control, pass the offset of the channel that\ncontrols the most-significant byte as the `offset` argument, and pass\nthe offset of the channel that controls the least-significant byte as\nthe second argument, `fine-offset`.\n\n[[iris-channels]]\n==== Iris Channels\n\n{api-doc}afterglow.channels.html#var-iris[`afterglow.channels/iris`]\nreturns a specification for a channel that controls the iris\n(aperture) of a fixture or head, widening or narrowing the beam of\nlight it emits. It always takes at least one argument, the channel\n`offset` (as described <<channel-offset,above>>). If the fixture uses\ntwo-byte values for more precise iris control, pass the offset of the\nchannel that controls the most-significant byte as the `offset`\nargument, and pass the offset of the channel that controls the\nleast-significant byte as the second argument, `fine-offset`.\n\n[[pan-channels]]\n==== Pan Channels\n\n{api-doc}afterglow.channels.html#var-pan[`afterglow.channels/pan`]\nreturns a specification for a channel that controls the pan (rotation\naround the Y axis) of a fixture or head. It always takes at least one\nargument, the channel `offset` (as described\n<<channel-offset,above>>). If the fixture uses two-byte values for\nmore precise pan control, pass the offset of the channel that controls\nthe most-significant byte as the `offset` argument, and pass the\noffset of the channel that controls the least-significant byte as the\nsecond argument, `fine-offset`.\n\n[[tilt-channels]]\n==== Tilt Channels\n\n{api-doc}afterglow.channels.html#var-tilt[`afterglow.channels/tilt`]\nreturns a specification for a channel that controls the tilt (rotation\naround the X axis) of a fixture or head. It always takes at least one\nargument, the channel `offset` (as described\n<<channel-offset,above>>). If the fixture uses two-byte values for\nmore precise tilt control, pass the offset of the channel that controls\nthe most-significant byte as the `offset` argument, and pass the\noffset of the channel that controls the least-significant byte as the\nsecond argument, `fine-offset`.\n\n[[zoom-channels]]\n==== Zoom Channels\n\n{api-doc}afterglow.channels.html#var-zoom[`afterglow.channels/zoom`]\nreturns a specification for a channel that controls the zoom of a\nfixture or head, changing how much the beam spreads as it travels from\nthe fixture. It always takes at least one argument, the channel\n`offset` (as described <<channel-offset,above>>). If the fixture uses\ntwo-byte values for more precise zoom control, pass the offset of the\nchannel that controls the most-significant byte as the `offset`\nargument, and pass the offset of the channel that controls the\nleast-significant byte as the second argument, `fine-offset`.\n\n[[function-channels]]\n==== Function Channels\n\n{api-doc}afterglow.channels.html#var-functions[`afterglow.channels/functions`]\nreturns a specification for a channel that implements a list of\ndifferent functions for different ranges of DMX values. Its first two arguments are `chan-type`, the keyword which identifies the type of the channel (please see the list of\n<<standard-function-types,standard function types>> below and try to\nreuse one if it is appropriate, or at least create your keyword in a\nway that follows their conventions), and the channel `offset` (as\ndescribed <<channel-offset,above>>).\n\nThese are followed by a variable number of function range\nspecifications, which take the form of a number (which identifies the\nstarting DMX value for the function range) followed by the function\nspecification itself. This can either be a\n<<function-specifications,function specification map>> as described\nabove (without the `:start` and `:end` keys, which will be figured out\nfrom the starting ranges supplied to this function), or in many simple\ncases you can use the shorthand of passing a keyword, which will be\nexpanded into a variable-range function with the a type of the keyword\nyou supplied, or a string, which will be expanded into a fixed-range\nfunction with a type of a keyword made from the string you supplied.\nIf you pass a `nil` after the number, it tells Afterglow to not create\na function at all for that part of the range.\n\nThe range specifications need to be in order of increasing starting\nvalues, and the ending values for each will be figured out by context.\n\nThe best way to understand this is to look at an example, like the\nspecification for channel 9 of the Torrent F3:\n\n[source,clojure]\n----\n(chan/functions :shutter 9 0 \"shutter-closed\" 32 \"shutter-open\"\n                           64 {:type :strobe\n                               :scale-fn (partial function-value-scaler 14 100)\n                               :label \"Strobe (1.4Hz->10Hz)\"\n                               :range :variable}\n                           96 \"shutter-open-2\" 128 :pulse-strobe 160 \"shutter-open-3\"\n                           192 :random-strobe\n                           224 \"shutter-open-4\")\n----\n\nThis sets up a channel of type `:shutter` with offset `9`. The\nremaining arguments are pairs which define function ranges.\n\nThe first two pairs use the String shortcut to set up a fixed-ranged\nfunction of type `:shutter-closed` from `0`-`31`, and another fixed-range\nfunction of type `:shutter-open` from `32`-`63`.\n\nThen there is a more complex function specification, using the map\napproach to set up a variable-range function of type `:strobe` from\n`64`-`95`, assign it a function label of `Strobe (1.4Hz->10Hz)`, and\nassign it a scaling function, which maps the values from 14 to 100\nonto tenth-Hertz frequency values, to try to normalize the strobe\nspeed of the fixture, since `:strobe` is a very common function, and\nit is nice to try to get different models of fixtures to react\nsimilarly when a given value for that function is assigned to them.\n\n> The discussion of the `:strobe` standard function\n  <<strobe-function,below>> provides another example of this approach,\n  and explains it further.\n\nThis is followed by another fixed-range function of type\n`:shutter-open-2` from `96`-`127` set up using the String shortcut,\nand a simpler variable-range function of type `:pulse-strobe` from\n`128`-`159` set up using the keyword shortcut rather than a map. That\nline finishes with a fixed-range function of type `:shutter-open-3`\nfrom `160`-`191` created using the String shortcut. Since the\nTorrent's pulse strobe mode is not something any of the other fixtures\nsupport, there was no need to try to use a scaling function to make it\napproximate another fixture's speed.\n\nThe last two pairs should be easily understood by now, as we have seen\ntheir like before. The second-to-last line uses the keyword shortcut\nto create a variable-range function of type `:random-strobe` from\n`192`-`223`, and the last line uses the String shortcut to create a\nfixed-range function of type `:shutter-open-4` from `224` to the\nlargest legal DMX value of `255`. Again, random strobing is a function\nunique to the Torrent, so no effort was made to scale it.\n\nNOTE: The various shutter-open ranges all do the same thing, but need\nto be given different names, since function names must be unique; it\nis a quirk of this fixture that it has multiple ranges with the same\nfunction. Another valid approach for handling the redundant later\nranges would have been to pass `nil` after the number to tell\nAfterglow to not create a function for them.\n\n[[generic-channels]]\n==== Generic Channels\n\nIf none of the above functions match the channel you are creating, you\ncan use\n{api-doc}afterglow.channels.html#var-fine-channel[`afterglow.channels/fine-channel`]\nto create the definition.\n\nIt always takes at least two arguments: `chan-type`, a keyword\nidentfying the type of the channel (please see the list of\n<<standard-function-types,standard function types>> below and try to\nreuse one if it is appropriate, or at least create your keyword in a\nway that follows their conventions), and the channel `offset` (as\ndescribed <<channel-offset,above>>).\n\nIf the channel uses two-byte values for more precise control, use the\nmost-significant byte as the `offset` value, and pass the offset of\nthe least-significant byte using the optional keyword argument\n`:fine-offset`.\n\nIf for some reason the channel's function type should differ from the\nvalue you gave for `chan-type`, you can pass a different keyword to\nuse when creating the function range, using the optional keyword\nargument `:function-type`.\n\nIf you want to use a variable label which differs from the name of the\nchannel's function type keyword in the user interface when\n<<push2.adoc#effect-control,adjusting>>\n<<cues.adoc#creating-function-cues,Function Cues>> (for example, if the\nkeyword is hyphenated, and you want the label to use a space), specify\nyour desired label with the optional keyword argument\n`:var-label`.\n\n[[function-creation-functions]]\n=== Function Creation Functions\n\nThere are also functions to help you create function specifications in\nyour channel definitions.\n\n[[color-wheel-hue]]\n==== Color Wheel Hue\n\n{api-doc}afterglow.channels.html#var-color-wheel-hue[`afterglow.channels/color-wheel-hue`]\nreturns a function specification which ties a color wheel position to\na particular hue, so the color wheel can participate in Afterglow's\ncolor effects. See the\n{api-doc}afterglow.channels.html#var-color-wheel-hue[API\ndocumentation] for more details, and the\n{api-doc}afterglow.fixtures.blizzard.html#var-torrent-f3[Torrent\nF3] fixture definition source for an example of its use.\n\n[[standard-function-types]]\n== Standard Function Types\n\n<<effects.adoc#function-effects,Function Effects>> and\n<<cues.adoc#creating-function-cues,Function Cues>> trigger and control\nspecific functions, potentially across a range of different fixture\ntypes from different manufacturers. In order for that to work, the\n<<function-specifications,Function Specifications>> must be created\nwith consistent `:type` keywords. When you are creating a new fixture\ndefinition, check to see if any of the functions that it provides are\ncovered by this table, and if so, use the same keywords to identify\nthem, so your fixture can participate with other fixtures in effects\nusing that function.\n\nIf your function does not fit into this list, make up a keyword that\nmakes sense for it, following the style shown here. And also please\nconsider (if the function type is likely to be present on other\nfixtures and useful to other people) opening an\nhttps://github.com/Deep-Symmetry/afterglow/issues[issue] requesting that\nyour new function type be added to this list so that when other people\ncreate definitions for similar fixtures, they can interoperate with\nyours.\n\n[cols=\"2l,5a\", options=\"header\"]\n|===\n|Function Key\n|Description\n\n|:dimmer\n\n|Controls the overall brightness of the fixture or head, independent\n of any color intensity channels which might also affect it. This is\n also a fundamental channel type in Afterglow, and has a category of\n <<effects.adoc#dimmer-effects,Dimmer Effects>> to work with it. Dimmer\n effects can work with either fully dedicated dimmer channels (in\n which case the channel itself has a `:type` of `:dimmer`, and the\n entire DMX range is used for dimming), or multipurpose channels in\n which a subset of the DMX range is assigned to a function of type\n `:dimmer`, and the channel `:type` is something else (like\n `:control`, as suggested below).\n\n|:red\n:green\n:blue\n:white\n:amber\n:uv\n\n|These identify functions (usually entire channels) which control the\n intensity of a particular color, usually on LED fixtures. When you\n create a channel of type `:color`, it will have a `:color` key with\n this value, and a corresponding function range. If your fixture has\n LEDs of colors other than these, use the color name to identify the\n function. (This will happen automatically when you use the\n {api-doc}afterglow.channels.html#var-color[`color`]\n channel <<channel-creation-functions,creation function>> to create\n the channel.) Color channels are fundamental channel types in\n Afterglow, and the colors `:red`, `:green`, `:blue`, and `:white`\n will automatically participate in the color mixing Afterglow performs\n with <<effects.adoc#color-effects,Color Effects>>. The others can too if,\n as described <<hue-mixing,above>>, the `:color` channel has a `:hue`\n entry.\n\n|:pan\n:tilt\n\n|Rotates the fixture about its Y (in the case of `:pan`) or X (in the\n case of `:tilt`) axis. These are also fundamental channel types in\n Afterglow, and have categories of\n <<effects.adoc#direction-effects,Direction Effects>> and\n <<effects.adoc#aim-effects,Aim Effects>> to work with them.\n\n|:strobe\n\n|[[strobe-function]]Causes the fixture to flash on and off abruptly (and usually\n rapidly). This is typically a variable-range function, so different\n values within the function range cause the fixture to strobe at\n different speeds. If possible, use a `:scale-fn` function (with the\n help of\n {api-doc}afterglow.effects.channel.html#var-function-value-scaler[`afterglow.effects.channel/function-value-scaler`])\n when creating a strobe function so that the function level is\n interpreted as an approximate Hz rate for the strobe, and your new\n fixture will strobe in rough tandem with other fixtures being\n strobed.\n\nTake a look at the strobe function definitions for the\nexisting fixtures for examples how to do this. All you need to do is\nmeasure the slowest and fastest rates at which your fixture actually\nstrobes, as best you can, and use them like this:\n\n[source,clojure]\n----\n(chan/functions :strobe 7\n                0 nil\n                11 {:type :strobe\n                    :scale-fn (partial function-value-scaler 6.6 100)\n                    :label \"Strobe (0.66Hz->10Hz)\"\n                    :range :variable})\n----\n\nIn this example, the fixture's strobe channel is at offset `7`, and\nthe range from `0`-`10` does not strobe (the `nil` function\nspecification tells Afterglow to skip creating a function for that\nrange), while at `11` it begins to strobe approximately 0.66 times per\nsecond (or 6.6 times every ten seconds, which gives a more useful\nspread of strobe values across the normal function value assignment\nrange of 1-100), and strobes faster for higher values, finally\nreaching around ten times per second at the maximum function value of\n`100`.\n\n> Measuring the actual strobing rate of arbitrary fixtures is\n  difficult to get right, I am not yet quite satisfied with the\n  scaling function values for my lighting rig, but for all practical\n  purposes, the audience does not notice the difference when being\n  dazzled by strobes.\n\n|:focus\n\n|Adjusts the focal plane of the fixture, usually a moving-head spot\n with the ability to project gobos (templates).\n\n|:frost\n\n|Controls a frost effect, softening the beam of light.\n\n|:iris\n\n|Controls the iris size, widening or narrowing the beam of light.\n\n|:zoom\n\n|Adjusts the rate at which the beam spreads as it travels further from the fixture.\n\n|:sound-active\n\n|Puts the fixture in a mode where it decides what to do by listening\n to music in the environment, rather than being directly controlled by\n its DMX channels.\n\n|===\n\n[[translating-qlc-fixture-definitions]]\n== Translating QLC+ Fixture Definitions\n\nhttp://www.qlcplus.org[QLC+] is an established and powerful free and\nopen-source lighting control system aimed at more traditional\nworkflows than Afterglow. If you were not already aware of it, you\nshould definitely take a look. And since it has been around a while,\nused by an increasing variety of people, it has had time to accumulate\na bunch of fixture definitions for lights that you are likely to\nencounter or own.\n\nEven though QLC+ does not model fixtures in as much detail as\nAfterglow, so their definitions are incomplete from our perspective\n(lacking geometry information for aim and direction cues, and explicit\nlinks between channels that pair up to control a single fixture\nfunction, among other things), Afterglow can still use them as a\nstarting point to help you creating a fixture definition, and save a\nwhole lot of time reading fixture manuals, and trial and error...\nespecially when it comes to channels with a lot of functions, like\ngobo wheels. So when you decide to create an Afterglow fixture\ndefinition, start by looking to see if QLC+ already has one for that\nfixture.\n\nYou can find its current set of fixture definitions on\nhttps://github.com/mcallegari/qlcplus/tree/master/resources/fixtures[GitHub].\nIf you see one for the fixture you want, you can either click on it\nand download it individually (after choosing the `Raw` view for the\nfile in its header bar), or, if you are already using git, you can\nclone the entire project to get local copies of all the fixture\ndefinitions.\n\nOnce you have downloaded the QLC+ fixture definition file, you can\ninvoke Afterglow from the command line, as described in the\nhttps://github.com/Deep-Symmetry/afterglow#usage[Usage] section on the\nproject page, to translate it into an Afterglow fixture definition.\nFor example, translating the definition for the\nhttps://github.com/mcallegari/qlcplus/blob/master/resources/fixtures/American_DJ/American-DJ-ECO-UV-BAR-DMX.qxf[American\nDJ Eco UV Bar], like so:\n\n```\n% java -jar afterglow.jar -q American-DJ-ECO-UV-BAR-DMX.qxf\nTranslated fixture definition written to eco-uv-bar-dmx.clj\n```\n\nwould result in the following Afterglow fixture definition file:\n\n```clojure\n(ns afterglow.fixtures.american-dj\n  \"Translated definition for the fixture ECO UV BAR DMX\n  from American DJ.\n\n  This was created by Afterglow from the QLC+ Fixture Definintion\n  (.qxf) file, and will almost certainly need some manual adjustment\n  in order to enable full Afterglow capabilities.\n\n  If you have more than one fixture definition for this manufacturer,\n  you can consolidate them into a single file if you like, with a\n  single copy of this namespace definition, since it is the same for\n  all fixture definitions translated by Afterglow.\n\n  Once you have completed the fixture definition, and are happy with\n  the way everything is being controlled by Afterglow, please consider\n  submitting it for inclusion with Afterglow, either as a Pull Request\n  at https://github.com/Deep-Symmetry/afterglow/pulls if you are\n  comfortable putting that together, or just on the Wiki if that's\n  easier for you:\n  https://github.com/Deep-Symmetry/afterglow/wiki/Questions#defining-fixtures\n\n  The original fixture defintition was created by Rob G.\n  using Q Light Controller Plus version 5.0.0 GIT.\n  QLC+ Fixture Type: Other\"\n  (:require [afterglow.channels :as chan]\n            [afterglow.effects.channel :as chan-fx]))\n\n(defn eco-uv-bar-dmx\n  \"ECO UV BAR DMX.\n\n  Please flesh out this documentation if you are submitting this for\n  inclusion into Afterglow. See, for example, the Blizzard fixture\n  definitions:\n  http://deepsymmetry.org/afterglow/api-doc/afterglow.fixtures.blizzard.html\"\n  []\n  {:channels [(chan/color 1 :uv)  ; TODO: add :hue key if you want to color mix this\n              (chan/fine-channel :strobing 2\n                                 :function-name \"Strobing\"\n                                 :var-label \"Strobing (slow -> fast)\")\n              (chan/functions :dimmer-curve 3\n                              0 {:type :dimmer-curve-no-dimmer-curve\n                                 :label \"No dimmer curve\"\n                                 :range :variable}\n                              21 {:type :dimmer-curve-dimmer-curve-1\n                                  :label \"Dimmer curve 1\"\n                                  :range :variable}\n                              41 {:type :dimmer-curve-dimmer-curve-2\n                                  :label \"Dimmer curve 2\"\n                                  :range :variable}\n                              61 {:type :dimmer-curve-dimmer-curve-3\n                                  :label \"Dimmer curve 3\"\n                                  :range :variable}\n                              81 {:type :dimmer-curve-dimmer-curve-4\n                                  :label \"Dimmer curve 4\"\n                                  :range :variable}\n                              101 {:type :dimmer-curve-delay-mode-control\n                                   :label \"Delay mode control\"\n                                   :range :variable})]\n   :name \"ECO UV BAR DMX\"})\n```\n\n> Of course this is a very simple fixture, but I didn't want to waste\n> a ton of space on the example, and it shows the basic idea.\n\nThe new definition file will be written to the same directory as the\n`.qxf` file it was based on. It is not named in a way (nor placed in\nthe necessary directory hierarchy) that would enable it to be loaded\nusing a normal Clojure `require` form, because it is intended to be\nloaded individualy using Afterglow's init-file mechanism, also\ndescribed in https://github.com/Deep-Symmetry/afterglow#usage[Usage], and\nwithin\nhttps://github.com/Deep-Symmetry/afterglow-max#afterglow-max[afterglow-max],\nby the `load-init-file` function. If you are creating definitions for\nseveral fixtures from the same manufacturer, you are encouraged to\ncombine them into a single file, as described in the API documentation\nat the top of the example above, using your favorite text editor. The\n`ns` form places the fixture definition functions in a package named\nafter the manufacturer, and so needs to appear only once at the top of\nthe file, and all the fixture definition functions themselves can be\nlisted after it.\n\nUsing the fixture definition from this example, once the file is\nloaded, is as simple as calling\n`(afterglow.fixtures.american-dj/eco-uv-bar-dmx)` within\n{api-doc}afterglow.show.html#var-patch-fixture.21[`show/patch-fixture!`].\n\n[[lost-in-translation]]\n=== What's Missing from Translated Fixture Definitions\n\nAs mentioned in the introduction, there are some things that Afterglow\nsimply cannot guess from translated fixture definitions. Even in\nsimple cases like this example, you will find things that you can make\nbetter by hand-editing the results based on your understanding of the\nfixture, after reading its manual or working with it for a bit.\n\n[[no-function-specifications]]\n==== Function Specifications\n\nFirst off, all fixture function ranges are created as `:variable`,\nmeaning that they do slightly different things along the range of\nvalues that activate that function, because QLC+ does not distinguish\nbetween fixed and variable functions. In the event that the function\nactually has no adjustable behavior, you will want to change `:range\n:variable` in the corresponding function specification entry to\n`:range :fixed`, so that the user interface of a function cue created\nfor this fixture properly reflects the fixture's behavior. I am pretty\nsure that is something that should be done for all the ranges in this\nexample, but I don't have the actual fixture to test it and see.\nFunction specifications are explained in more depth\n<<function-specifications,above>>.\n\nThe types and labels assigned to the function ranges are derived from\nthe labels in the `.qxf` file, and uniqueness is enforced, but they\nare probably too long in many cases (especially if you want them to be\nreadable in the Web or Ableton Push interfaces), and in some cases\nshould be adjusted to match up with the\n<<standard-function-types,standard types>> so that they can\nautomatically work with cues. (This is especially likely to be the\ncase with strobe cues, for example. Compare the translated definitions\nwith some that ship with Afterglow as you are starting to get a feel\nfor these issues.)\n\n[[no-channel-types]]\n==== Channel Types\n\nAfterglow tries to guess what kinds of channels it finds, based on\ntheir name, and aspects of their structure. For simple cases it will\nget it right, and save you time, but it might be wrong. This is\nespecially important to double-check for dimmer channels, to make sure\nthey are properly detected, since only then will they participate in\n<<effects.adoc#dimmer-effects,Dimmer Effects>> and the Master chain. (And\nyou don't want inappropriate channels to be mapped as dimmer channels\nfor the opposite reason.)\n\n[[no-dimmer-channels]]\n==== Dimmer Channels\n\nIn addition to the possibility that a dimmer channel might be\nmisidentified, as described above, some fixtures have _inverted_\ndimmer channels, which do not get brighter as the DMX value increases.\nThe `.qxf` file does not record this information, so you will need to\nmanually add it to the <<dimmer-channels,specification>>.\n\n[[no-color-channels]]\n==== Color Channels\n\nColors are fairly well represented and identified in the QLC+ format,\nand if you have a channel controlling a red, green, blue, or white\nchannel, chances are good that it will be properly translated. If you\nhave an LED fixture with other colors, like amber, UV, or beyond, and\nwant these other channels to participate in Afterglow's automatic\ncolor mixing capabilities, as noted by the `TODO:` comment in the\ntranslation example above, you will need to add a `:hue` key to the\ncolor channel definition, containing the actual hue value of the LEDs\ncontrolled by that channel. The Chauvet SlimPar Hex IRC\n{branch-base}src/afterglow/fixtures/chauvet.clj[definition]\nthat ships with Afterglow contains a nice example of doing this for\nits amber and UV channels, and shows how to make this extended color\nmixing an optional feature when using the fixture definition.\n\n[[no-two-byte-channels]]\n==== Two-Byte Channels\n\nDMX parameter values are integers which only range from 0-255. That is\nnot enough to achieve precise pan and tilt movements, and some\nfixtures even want to allow more precise dimming values and color\nintensities. In order to achieve that, they use more than one channel\nto communicate a single parameter value. QLC+ fixture definition files\nreflect this to an extent, using their `Group` tags which have a\n`Byte` value of 0 or 1. But there is no explicit link in the `.qxf`\nfile between the channels that are controlling the same value.\nAfterglow is able to figure it out in simple cases, such as where\nthere are two channels controlling the intensity of the color red,\nusing bytes 0 and 1. But if there are more than two channels serving\nthe same purpose, it cannot figure out the relationships, and you will\nhave to sort that out using the fixture's manual. Once you do, get rid\nof the channel specification for the least-significant byte in the\nfixture definition, and specify that channel as the `fine-channel`\nvalue for the channel specification of the most-significant byte, as\ndocumented in the <<channel-creation-functions,Channel Creation\nFunctions>> section.\n\n[[no-geometric-information]]\n==== Geometric Information\n\nIf the fixture includes a Pan or Tilt channel, you will see additional\n`TODO:` comments telling you that you need to add information about\nhow the channel actually physically rotates the fixture, in order for\nAfterglow to be able to accurately calculate\n<<effects.adoc#direction-effects,Direction>> and\n<<effects.adoc#aim-effects,Aim>> effects with it. The\n<<structure,Structure section above>>\ndescribes the `:pan-center`, `:pan-half-circle`, `:tilt-center`, and\n`:tilt-half-circle` values that you will need to figure out\nexperimentally.\n\n> We hope to someday help automate part of this process, which will\n> make it easier for all of us!\n\nSimilarly, if the fixture has multiple heads, you will see `TODO:`\nentries where you need to fill in their\n<<head-specifications,locations>> relative to the origin of the\nfixture itself, so that <<parameters.adoc#spatial-parameters,Spatial\nParameters>> can work properly with them.\n\n[[dont-panic]]\n=== Don't Panic!\n\nEven though this sounds like a lot of things that can go wrong trying\nto build an Afterglow fixture definition, most of the problem areas\nare subtle, or relate to the more advanced capabilities of Afterglow.\nChances are very good that the automatically generated fixture\ndefinition will at least enable basic control of the fixture right\naway. So try that, and gain some confidence, as you gradually explore\nthe areas where it isn't quite doing what you want, and tackle those\none at a time. And, as you do, remember that you can get help:\n\n[[when-things-go-awry]]\n=== When Things Go Awry\n\nNot all definitions have been tested with the translator, and there\nmay be scenarios that it gets fundamentally wrong. If so, please raise\nan https://github.com/Deep-Symmetry/afterglow/issues[Issue], so we can see\nif it is something that can be fixed, or a fundamental limitation of\nthe translation approach that should be documented here.\n\nIf you are having trouble figuring out the details of how to finish or\nuse your fixture definition, please ask for help on the\nhttps://deep-symmetry.zulipchat.com/#narrow/stream/318697-afterglow[Zulip chat] or\nhttps://github.com/Deep-Symmetry/afterglow/wiki/Questions#defining-fixtures[Wiki].\nNot only will that hopefully get you going faster, but it might help\nothers in the future, especially if it leads to improvements in the\ndocumentation or Afterglow itself.\n"
  },
  {
    "path": "doc/modules/ROOT/pages/launchpad.adoc",
    "content": "= Using the Novation Launchpad Family\nJames Elliott <james@deepsymmetry.org>\n\nNovation makes an entire family of grid controllers which can all be\nused with Afterglow, with differing capabilities. The most powerful is\nthe Launchpad Pro, with pressure-sensitive RGB pads.\n\n[[binding-to-a-launchpad]]\n== Binding to a Launchpad\n\nAssuming you have a Launchpad family controller connected to the\nmachine running Afterglow, Afterglow will find and activate it as soon\nas you have set up the sample show. You will see a brief startup\nanimation, and Afterglow's appropriate Launchpad interface will start.\n\nTIP: For information about how to set up bindings without the sample\nshow, or more details about how it works, see\n<<mapping_sync.adoc#setting-up-grid-controller-bindings,Setting Up Grid\nController Bindings>>.\n\n[[using-launchpad-pro]]\n== Using Launchpad Pro\n\nWith its pressure-sensitive, RGB-capable 8&times;8 pad grid, the\nNovation Launchpad Pro makes an excellent grid controller for\nAfterglow, and has its own custom\n{api-doc}afterglow.controllers.launchpad-pro.html[mapping].\n\n> There are also mappings for the\n  <<using-launchpad-mk2,Launchpad Mk2>>,\n  <<using-launchpad-mini-and-launchpad-s,Launchpad Mini,\n  and Launchpad S>>\n\nHere is what the Launchpad Pro interface looks like:\n\nimage::LaunchpadPro.jpg[Launchpad Pro interface,1000,1011]\n\n[[show-control]]\n=== Show Control\n\nOnce you have the Launchpad linked to a show, it becomes a helpful way\nto monitor and control the cues and manage the musical synchronization\nof the show.\n\nThe red kbd:[Stop] button at the bottom can be used to stop a running\nshow, which will suspend the processing of its effects, and black out\nall universes assigned to the show. The button will be illuminated\nbrightly while the show is stopped. Pressing it again will restart the\nshow where it would have been had it not stopped, and dim the button\nagain.\n\nMost of the space on the interface is dedicated to an 8&times;8 grid\nof color coded cue trigger pads, which provide a window onto the\nshow's overall <<cues.adoc#,cue grid>>. The Launchpad can be\n<<README.adoc#scrolling-and-linked-controllers,linked>> to the\n<<README.adoc#web-ui,web interface>> so that both always display the same\nsection of the cue grid, and the web interface can remind you of the\nnames of the cues you are looking at, or it can be scrolled\nindependently, allowing you access to more cues at the same time.\n\nTIP: If you have more than one compatible grid controller, you can\nhave Afterglow using all of them at the same time; each can be\nscrolled to different areas of the cue grid, and each can even be\nlinked to a different browser window if you have that much screen\nspace.\n\nYou can activate any cue shown by pressing its pad; running cues will\nlight up, and darken again when they end. If the cues are configured\nto respond to velocity, you can adjust the corresponding variables by\nhow hard you are pressing on the pad while the cue is running.\n\nTo stop a running cue, press its pad again. Some cues will end\nimmediately, others will continue to run until they reach what they\nfeel is an appropriate stopping point. While they are in the process\nof ending, the cue pad will blink. If you want the cue to end\nimmediately even though it would otherwise run for a while longer, you\ncan press the blinking cue pad again and it will be killed right then.\n\nThe colors assigned to cue pads by the creator of the cue grid are\nintended to help identify related cues. Some cues (especially intense\nones like strobes) are configured to run only as long as they are held\ndown. In that case, when you press cue pad, it lights up with a\nwhitened version of the cue color as a hint that this is happening,\nand as soon as you release the pad, the cue will end. If you want to\noverride this behavior, you can hold down the kbd:[Shift] button\n(towards the top left of the Launchpad Pro) as you press the cue pad,\nand it will activate as a normal cue, staying on until you press it a\nsecond time.\n\nAs noted above, cues can also be configured to take advantage of the\npressure sensitivity of the Launchpad Pro cue pads, so that as you\nvary the pressure with which you are holding down the pad, some\nvisible variable of the cue is altered. The strobe and sparkle cues\nin created by\n{api-doc}afterglow.examples.html#var-make-cues[`afterglow.examples/make-cues`]\nfor the sample show work this way: the intensity and lightness of the\nstrobe are increased by pressure, and so is the chance that a sparkle\nwill be assigned to a light on each frame.\n\nNOTE: In order for aftertouch to work with your cues--in other words,\nfor you to be able to adjust cue variables by varing pressure on the\npad after you have launched it--you need to set your Launchpad Pro's\n*Aftertouch* mode to *Polyphonic*, as described in the *Setup Button*\nsection of the\nhttps://downloads.novationmusic.com/novation/launchpad-mk2/launchpad-pro[User\nGuide]. You might also want to set the *Aftertouch Threshold* to\n*Low*.\n\nCues may be mutually exclusive by nature, and if they were created to\nreflect this (by using the same keyword to register their effects with\nthe show, or specifying other effect keys in their `:end-keys` list),\nwhen you activate one, the other cues which use the same keyword are\ndimmed. This is a hint that when you activate one of them, it will\n_replace_ the others, rather than running at the same time. (There are\nphotos demonstrating this effect on the\n<<push2.adoc#numeric-cue-variables,Ableton Push page>>.)\n\n[[scrolling]]\n=== Scrolling\n\nThe show will likely have many more cues than fit on the pad grid; the\nrow of arrow buttons at the top left allow you to page through the\nlarger show grid. If there are more cues available in a given\ndirection, that arrow will be lit, otherwise it is dark. Pressing an\nactive arrow scrolls the view one &ldquo;page&rdquo; in that\ndirection. In the photo below, it is currently possible to scroll down\nand to the left:\n\nimage::LaunchpadPro-scroll.jpg[Launchpad Pro interface,800,539]\n\nIf you hold down the kbd:[Shift] button, the arrows will scroll you as\nfar as possible in the direction that you press.\n\n[[metronome-control]]\n=== Metronome Control\n\nThe kbd:[Click] button lets you monitor and adjust the Metronome that\nthe show is using to keep time with the music that is being played.\nSince Afterglow's effects are generally defined with respect to the\nmetronome, it is important to keep it synchronized with the music. The\nkbd:[Click] button label flashes at each beat, and the color of the\nbutton tells you whether the metronome is syncronized to an external\nsource. If it is blue, as in the first photo in this section, the\ntempo is being set manually. If green, as is shown right above, then\ntempo is being driven by an external source, such as MIDI or DJ Link\nPro. If the button is red, it means that Afterglow was configured to\nsync to some external source, but has lost contact with it.\n\nThe most basic way of synchronizing the metronome is to tap the\nkbd:[Click] button at each beat of the music. Tapping the button\naligns the metronome to a beat, and if you tap it three or more times\nwithin two seconds of each preceding tap, sets the metronome's BPM.\nTap it as you hear each beat of the music, and after three or more\ntaps, the speed of the metronome will be approximately synchronized\nwith the music.\n\nOnce the tempo is correct, you can tell Afterglow which beat is the\ndown beat by holding down the kbd:[Shift] button while pressing\nkbd:[Click]. This combination does not change the tempo, but tells\nAfterglow that the moment when you tapped the button is the down beat\n(the first beat of a bar).\n\nTrying to keep up with tempo changes during dynamic shows can be\ntedious, so you will hopefully be able to take advantage of\nAfterglow's metronome synchronization features. If the DJ can send you\n<<mapping_sync.adoc#syncing-to-midi-clock,MIDI clock pulses>>, or you can\nconnect via a Local Area Network to Pioneer professional DJ gear to\nlock into the beat grid established by\n<<mapping_sync.adoc#syncing-to-pro-dj-link,Pro DJ Link>>, Afterglow can\nkeep the BPM (with MIDI) and even the beats (with Pro DJ Link and the\nTraktor Afterglow Beat Phase\n<<mapping_sync.adoc#syncing-to-traktor-beat-phase,controller mapping>>)\nsynchronized for you. You can use the <<README.adoc#metronome-control,web\ninterface>> to configure metronome sync.\n\nOnce your sync is established, the meaning of the kbd:[Click] button\nchanges. If you are using MIDI clock to sync the BPM, it becomes a\nkbd:[Tap Beat] button, which simply establishes where the beat falls.\nIf you are locked in to a Pro DJ Link beat grid or using the Traktor\nbeat phase mapping, the beats are automatically aligned for you so, it\nbecomes a kbd:[Tap Bar] button which, when pressed, indicates that the\ncurrent beat is the down beat (start) of a bar. In these sync modes\nyou can also use the kbd:[Shift] button to align at the next bigger\nboundary: If tapping kbd:[Click] would normally move the bar,\nshift-tapping will move the phrase.\n\n[[sharing-the-launchpad-pro]]\n=== Sharing the Launchpad Pro\n\nIf you are using Afterglow at the same time as Ableton Live, you can\nswitch back and forth between which has control of the Launchpad Pro\nby pressing the kbd:[User] button. If Live is not running when you\npress kbd:[User], the Launchpad interface will simply go blank (except for\nthe kbd:[User] button itself), until you press it again, at which\npoint Afterglow will light it up.\n\nNOTE: Future releases may take advantage of more of the buttons on the\ncontroller.\n\n[[using-launchpad-mk2]]\n== Using Launchpad Mk2\n\nThe Launchpad Mk2 is very similar to the Pro, except that it lacks\nvelocity sensitivity and has fewer buttons outside the cue grid. For\nthe most part you can follow the\n<<using-launchpad-pro,Launchpad Pro>> instructions above\n(ignoring the discussion of velocity sensitivity and aftertouch\nconfiguration), but refer to the button mapping shown for the\nLaunchpad Mini and Launchpad S\n<<launchpad-mini-image,below>>, because the Launchpad Mk2\n{api-doc}afterglow.controllers.launchpad-mk2.html[mapping] uses the\nsame arrangement of round buttons as those controllers.\n\n[[using-launchpad-mini-and-launchpad-s]]\n== Using Launchpad Mini and Launchpad S\n\nThese two controllers share the same\n{api-doc}afterglow.controllers.launchpad-mini.html[mapping] because\nthey are functionally identical--the Mini is a highly compact version\nof the S. Neither supports velocity, and they have a very limited\ncolor palette, so the mapping does not attempt to reflect the\nAfterglow cue grid colors. Instead, colors are used to represent cue\nstate.\n\n> The mapping of these controllers was made possible thanks to the\n  kind loan of a Launchpad Mini for that purpose by Novation.\n\n[[cue-grid-colors]]\n=== Launchpad Mini and S Cue Grid Colors\n\nPads which have no cues associated with them are dark. If the pad has\na cue that is not running, it will be amber. If the pad's cue\nconflicts with another cue that is running, it will be a dim amber.\nCues which are running are bright green; cues which are ending blink\nred, as illustrated below.\n\nThe round buttons along the top are used to scroll around the grid,\nusing the same conventions as the decals which come with the Launchpad\nMini (and the arrows printed on the Launchpad S). The User 2 button\ncan be used suspend and resume the Afterglow mapping. The round\nbuttons on the right side are used to adjust the metronome, and start\nor stop the show, as shown:\n\n[[launchpad-mini-image]]\nimage::LaunchpadMini.jpg[Launchpad Mini interface,1186,1194]\n\n> The Tap Tempo button corresponds to the button labeled Volume on the\nLaunchpad S (and on the decal which comes with the Launchpad Mini),\nthe Stop button matches the decal and printed label, and the Shift\nbutton corresponds to the Arm button. Although the locations of these\nbuttons are different, they light up and respond as described in the\n<<using-launchpad-pro,Launchpad Pro>> instructions above.\n\nCues which run only while you hold them down will light up as bright\namber instead of green while you are holding them, to let you know\nthey will end as soon as you release the pad. As with other controller\nmappings, if you hold down the Shift button (the bottom right round\nbutton) while launching such a momentary cue, it will stay running\neven after you let it go, and in that case will be green.\n"
  },
  {
    "path": "doc/modules/ROOT/pages/mapping_sync.adoc",
    "content": "= MIDI Mapping and Beat Sync\nJames Elliott <james@deepsymmetry.org>\n\nAfterglow is designed to work with MIDI controllers and DJ equipment.\nYou can bind physical controller elements to trigger cues and adjust\nshow variables, and sync the BPM of the show master metronome to MIDI\nclock pulses from a DJ controller or mixer. (Although if you have\nprofessional Pioneer gear, you are better off syncing the metronome to\nthe Pro DJ Link via an Ethernet cable.)\n\nNOTE: These examples assume you are in a Clojure REPL with Afterglow loaded,\nin the namespace `afterglow.examples`. This is the default namespace you\nget if you check out the project and run `lein repl`. The sample show is\nassumed to be running; if not, `(show/start!)`\n\n[[mapping-cues-to-a-controller]]\n== Mapping Cues to a Controller\n\nAlthough the most convenient and powerful way of running cues with\nAfterglow is to use a large grid controller with color feedback (like\nthe Ableton Push or Novation Launchpad Pro, which can mirror the cue\ngrid of the web interface) you can still accomplish a great deal with\na simple controller with a few buttons. You will still want to start\nby creating the cues in the show cue grid, not only so you can see and\nmanipulate them with the web interface, but also because that is how\nthey can be mapped to MIDI controllers. (The rich <<push2.adoc#,Push>>\nand <<launchpad.adoc#,Launchpad family>> mappings are described in\ndetail on their own pages.)\n\nFirst you need to identify the MIDI messages that the controller sends\nwhen you press and release the interface element you want to assign\nthe cue. Afterglow can help with that too, as described\n<<finding-mapping-details,below>>. Once you have the cue created and\nthe control identified, you can create the mapping using\n{api-doc}afterglow.effects.cues.html#var-add-midi-to-cue-mapping[`afterglow.effects.cues/add-midi-to-cue-mapping`], like:\n\n[source,clojure]\n----\n(cues/add-midi-to-cue-mapping \"nano\" 0 :control 46 0 6)\n----\n\nThis would cause Afterglow to start or stop the cue at grid position\n(0, 6) when a pad on the device named \"nano\" is pressed and sends a\nMIDI control change message on control number 46. See the\n{api-doc}afterglow.effects.cues.html#var-add-midi-to-cue-mapping[documentation]\nfor details on all the arguments.\n\nTIP: If the controller has LEDs associated with the controls, and you\ncan configure it so that its LEDs are in external control mode,\nAfterglow will even give you feedback about when the cue is running,\nby lighting up the pad or button when the cue starts (whether or not\nyou started it using this controller), and darkening it when the cue\nends. If you are unable to configure your controller in this way, or\nthere is some other reason why you want to avoid having Afterglow send\nit MIDI messages about the cue status, pass the additional arguments\n`:feedback-on false` to `add-midi-to-cue-mapping`. See the\nfunction\n{api-doc}afterglow.effects.cues.html#var-add-midi-to-cue-mapping[documentation]\nfor full details.\n\nIf you want to be able to later remove this cue mapping, be sure to\nsave the value returned by `add-midi-to-cue-mapping` in a\nvariable, because you will need to pass it to\n{api-doc}afterglow.effects.cues.html#var-remove-midi-to-cue-mapping[`remove-midi-to-cue-mapping`].\nOr you can simply disconnect the controller from your system, and\nAfterglow will clean up any mappings that had been assigned to it.\n\nAlso be sure to see the section <<automatic-bindings,below>> that\nexplains how you can arrange to have afterglow automatically call the\nrelevant MIDI mapping functions to set up your device whenever it is\nconnected.\n\nNOTE: If you are mapping a cue that is set up with velocity sensitive\nvariables, and your controller is not actually velocity-sensitive, you\nmight find the cue being activated more intensely than you like,\nbecause the controller is always sending maximum velocity values when\npressed. You can work around this by passing the optional\n`:use-veolocity` argument along with an explicit velocity value from\n`0` to `127` to `add-midi-to-cue-mapping`. This will cause the\nmapping to act as if the button was pressed with the velocity you\nspecified here, allowing you to choose the values with which the cue\ngets activated.\n\n[[mapping-a-control-to-a-variable]]\n== Mapping a Control to a Variable\n\nYou can also tie an encoder or fader on a MIDI control surface to a\nshow variable, so that turning the encoder or sliding the fader\nchanges the value of the variable. If you have set up cues to look at\nthat variable, through <<cues.adoc#cue-variables,cue-specific variable\nbindings>>, the control surface can then vary the look of the effect\ncreated by the cue, both before the cue is launched, and while it is\nrunning.\n\nHere is a lower-level example of how I can use\n{api-doc}afterglow.show.html#var-add-midi-control-to-var-mapping[`add-midi-control-to-var-mapping`]\nhave a knob on one of my\nsimple MIDI controllers set the hue of all the lights. It shows up\nwith a MIDI port name of `SLIDER/KNOB`, and its first rotary\ncontroller is control 16 on channel 0. I can map that to set a show\nvariable `knob-1` to the values 0-360 (the legal hue values):\n\n[source,clojure]\n----\n(show/add-midi-control-to-var-mapping \"Slider\" 0 16 :knob-1 :max 360)\n----\n\nNOTE: See the\n{api-doc}afterglow.show.html#var-add-midi-control-to-var-mapping[documentation]\nfor details about all the arguments. Also, if you want to map a color\ncomponent like this, there is a\n<<mapping-a-control-to-a-color-component,better way>> to do it that\nmakes it easier to work with the color in the web interface.\n\nThen I can create a global color effect based on that variable:\n\n[source,clojure]\n----\n(show/add-effect! :color (global-color-effect\n  (params/build-color-param :s 100 :l 50 :h :knob-1)))\n----\n\nIt is also possible to perform arbitrary transformation of the MIDI\nvalue before storing it into the show variable, by passing\n`add-midi-control-to-var-mapping` a transformation function using the\noptional keyword argument `:transform-fn`. The function you supply\nwill called with the MIDI value (already scaled, if you passed a value\nwith `:min` or `:max`), and whatever it returns will be stored in the\nvariable. Your function can contain whatever logic it needs, and does\nnot even need to return a number. As a simple example, suppose you\nwant to set up a `:beat-ratio` variable for configuring oscillators,\nand you want it to have the value 1, 2, 4, or 8, depending on how far\na fader is raised. Since those are all powers of two, you could\nimplement the varible binding like this:\n\n[source,clojure]\n----\n(show/add-midi-control-to-var-mapping\n  \"SLIDER\" 0 1 :beat-ratio :max 3\n  :transform-fn (fn [v] (Math/pow 2 (Math/round v))))\n----\n\nNOTE: This intercepts any MIDI control-change messages for the device\nwhose name or description contains \"SLIDER\", on channel 0, controller\nnumber 1. It scales the incoming control value to the range 0 through\n3, then calls a custom function which rounds the scaled value to the\nnearest integer, and raises 2 to that power. The result gets stored\ninto the show variable `:beat-ratio`.\n\nIf you want to be able to later remove this variable mapping, be sure\nto save the value returned by `add-midi-control-to-var-mapping` in a\nvariable, because you will need to pass it to\n{api-doc}afterglow.midi.html#var-remove-control-mapping[`remove-control-mapping`].\nOr you can simply disconnect the controller from your system, and\nAfterglow will clean up any mappings that had been assigned to it.\n\nAlso be sure to see the section <<automatic-bindings,below>> that\nexplains how you can arrange to have afterglow automatically call the\nrelevant MIDI mapping functions to set up your device whenever it is\nconnected.\n\n[[finding-mapping-details]]\n== Finding Mapping Details\n\nIn the all-too likely event you don’t have all your MIDI port names and\ncontrol channel and note numbers memorized, Afterglow can help. Just\nrun...\n\n[source,clojure]\n----\n(afterglow.midi/identify-mapping)\n----\n\n...then twiddle the knob, slide the fader, or press the button you\nwish to map. Afterglow will report the first control-change or note\nmessage it receives:\n\n[source,clojure]\n----\n{:command :control-change, :channel 0, :note 32, :velocity 127,\n :device {:name \"SLIDER/KNOB\",\n          :description \"nanoKONTROL2 SLIDER/KNOB\"}}\n----\n\n____\nNotice that even for control changes, the controller number is\nidentified as `:note` (32 in this example).\n____\n\nIf nothing is received for ten seconds, it will give up:\n\n[source,clojure]\n----\nnil\n----\n\nIf this happens, and you are sure the device is connected, you will\nneed to troubleshoot your MIDI setup. If you are on a Mac, and the\ndevice was not connected when you started Afterglow, be sure that you\nhave installed\nhttps://github.com/DerekCook/CoreMidi4J/releases[CoreMIDI4J] as\ndiscussed on the\nhttps://github.com/Deep-Symmetry/afterglow/wiki/Questions#midi-from-java-on-the-mac[Afterglow\nWiki].\n\nNOTE: These examples show how to perform low-level MIDI mapping. Over\ntime, you might find that someone has written a rich user interface\nbinding for your controller, as has been done for the\n<<push2.adoc#,Ableton Push>>, which would let you jump right in\nwithout having to worry about such details. These examples can still\nhelp explain how your controller's binding works, or encourage you to\nwrite and share a binding for a new controller that you happen to\nhave.\n\n[[automatic-bindings]]\n== Automatically Creating Bindings When a Device Connects\n\nYou can tell Afterglow to watch for a particular device to be\nconnected and call a function whenever it is present. This function\ncan set up all of the MIDI bindings you want for that device. This is\nconvenient because if the device is not there, nothing will happen\n(and there will be no errors), but if it is, the bindings will be set\nup. Even more importantly, in a performance context, if the device is\naccidentally disconnected or powered down, the bindings will be\nreconfigured as soon as it is reconnected.\n\nTo do this, set up a function like `map-nano` in the example below\nwhich creates all the MIDI bindings you want for your device, and then\ncall\n{api-doc}afterglow.midi.html#var-watch-for[`afterglow.midi/watch-for`]\nto cause that function to be called whenever a device with a matching\nname or description is connected:\n\n[source,clojure]\n----\n(defn map-nano []\n  (cues/add-midi-to-cue-mapping \"nano\" 0 :control 46 0 6)\n  (show/add-midi-control-to-var-mapping \"nano\" 0 16 :knob-1 :max 360))\n\n(afterglow.midi/watch-for \"nano\" map-nano)\n----\n\nTIP: If you want to be able to cancel the watcher later, be sure to\nsave the value returned by `watch-for` in a variable. The return value\nis a function which cancels that watcher when you call it.\n\nSee the `watch-for`\n{api-doc}afterglow.midi.html#var-watch-for[documentation]\nfor details about other ways you can configure it, such as adjusting\nhow long it waits for the new device to stabilize before calling your\nfunction, and how to provide another function that gets called to\nclean up when the device is disconnected. You do not need to worry\nabout cleaning up ordinary MIDI bindings, since Afterglow\nautomatically does that whenever a device is disconnected, but if you\nhave set up any of your own state that you would like to remove, you\ncan use this mechanism to do so.\n\n[[mapping-a-control-to-a-color-component]]\n== Mapping a Control to a Color Component\n\nWhen you are working with colors for cues, Afterglow lets you put a\n<<color.adoc#,color object>> in a show variable or cue parameter,\nrather than simply storing individual numeric components like the hue.\nDoing this lets the web and Ableton Push interfaces give the user a\nrich color picker interface for adjusting that variable or parameter,\nso it is usually a better approach than just storing the numbers that\nmake up the color.\n\nWhen you do that, you can still use any MIDI controller to adjust\ncomponents of that color, using\n{api-doc}afterglow.controllers.color.html#var-add-midi-control-to-color-mapping[`afterglow.controllers.color/add-midi-control-to-color-mapping`].\n\nHere is an example of how to tie the left six faders on one of my\nsimple MIDI controllers to adjust all of the components that make up\nthe color used by the sample show's strobe effects. The controller\nshows up with a MIDI port name of `SLIDER/KNOB`, and its fader\ncontrollers are controls 0 through 7 on channel 0. Assigning the\nfirst six to adjust components of the strobe color looks like:\n\n[source,clojure]\n----\n(require '[afterglow.controllers.color :as color-ctl])\n(color-ctl/add-midi-control-to-color-mapping \"SLIDER\" 0 0 :strobe-color :red)\n(color-ctl/add-midi-control-to-color-mapping \"SLIDER\" 0 1 :strobe-color :green)\n(color-ctl/add-midi-control-to-color-mapping \"SLIDER\" 0 2 :strobe-color :blue)\n(color-ctl/add-midi-control-to-color-mapping \"SLIDER\" 0 3 :strobe-color :hue)\n(color-ctl/add-midi-control-to-color-mapping \"SLIDER\" 0 4 :strobe-color :saturation)\n(color-ctl/add-midi-control-to-color-mapping \"SLIDER\" 0 5 :strobe-color :lightness)\n----\n\nNOTE: See the\n{api-doc}afterglow.controllers.color.html#var-add-midi-control-to-color-mapping[documentation]\nfor details about all the arguments; this simple example assumes you\nwant to access the full range of each color component and that higher\nMIDI values should map to higher color values. Also, even though it is\nincluded here for completeness, there is no point in assigning a value\nto the `:strobe-color` variable's `:lightness` component, since that\nis under the control of the strobe cue.\n\nWith this done, as I move the sliders on this MIDI controller, I can\nsee the colors of the strobe cues in the web interface and on the\nAbleton Push and Novation Launchpad grids changing (and on the lights\nthemselves if any strobe cue is running at the time).\n\n[[mapping-dimmer-masters]]\n== Mapping a Control to a Dimmer Master\n\nThe web interface and Ableton Push mapping have dedicated interfaces\nfor controlling the show's dimmer grand master, but you can map any\nMIDI controller fader or rotary controller to it, or to any other\ndimmer master that you have created to control your cues, using\n{api-doc}afterglow.show.html#var-add-midi-control-to-master-mapping[`add-midi-control-to-master-mapping`].\n\nHere is an example of how to tie the leftmost fader on one of my\nsimple MIDI controllers to the show's dimmer grand master. The\ncontroller shows up with a MIDI port name of `SLIDER/KNOB`, and its\nfirst fader controller is control 0 on channel 0. I can map that to\nset the show grand master to the values 0-100 (the legal dimmer master\nvalues) by simply calling:\n\n[source,clojure]\n----\n(show/add-midi-control-to-master-mapping \"Slider\" 0 0)\n----\n\nNOTE: See the\n{api-doc}afterglow.show.html#var-add-midi-control-to-master-mapping[documentation]\nfor details about all the arguments; this simple call takes advantage\nof the fact that the show dimmer grand master is the default master if\nyou don't pass one in with `:master`.\n\n\n[[mapping-metronome-control]]\n== Mapping Metronome Control\n\nThe rich grid controller bindings created for the Ableton Push and\nNovation Launch Pad provide very convenient metronome control using\nTap Tempo buttons that flash on each beat of the show metronome, and\nrespond to taps appropriately for any metronome synchronization (as\ndescribed in the <<syncing-to-midi-clock,next sections>>) the show may\nhave established.\n\nEven if you don't have such a controller, you can set up a button or\npad on any MIDI controller you own to work the same way. Simply\n<<finding-mapping-details,identify the mapping>> you need to interact\nwith that button or pad as decribed above, then call\n{api-doc}afterglow.controllers.tempo.html#var-add-midi-control-to-tempo-mapping[`afterglow.controllers.tempo/add-midi-control-to-tempo-mapping`]\nto set it up.\n\nNOTE: As with cue mappings, these mappings work best if you can\nconfigure your controller so that its LEDs are in external control\nmode (instead of local control mode), so that Afterglow is completely\nin control of when they are lit. If you can't do that, of there is\nsome other reason why you want to avoid having Afterglow send MIDI\nmessages to try to control the LEDs, you can pass the additional\narguments `:feedback-on false` when setting up the mappings. Of course\nthis will mean that the Tap Tempo button can't blink on beat for you.\n\nFor example, to set this up for the kbd:[Record] button on a Korg\nnanoKONTROL2 controller, you can call:\n\n[source,clojure]\n----\n(def tempo-map\n  (afterglow.controllers.tempo/add-midi-control-to-tempo-mapping\n    \"nano\" 0 :control 45))\n----\n\n> See the\n{api-doc}afterglow.controllers.tempo.html#var-add-midi-control-to-tempo-mapping[documentation]\nfor details about all the arguments.\n\nFrom that point on, the kbd:[Record] button blinks on each beat of the\nshow metronome, and when you press the button, it adjusts the tempo of\nthe show. Assuming you have no metronone synchronization established\nfor the show, tapping the button aligns the metronome to a beat, and\nif you tap it three or more times within two seconds of each preceding\ntap, sets the metronome's BPM. Tap it as you hear each beat of the\nmusic, and after three or more taps, the speed of the metronome will be\napproximately synchronized with the music.\n\nNOTE: To synchronize bars, see the discussion about how to pair this\nmapping with a shift button, coming up shortly. Also, because of the\ntwo second threshold, you can't tap tempos that are 30 BPM or less.\n\nIf the metronome's BPM is already being synced automatically, via MIDI\nclock messages as described in the <<syncing-to-midi-clock,next\nsection>>, then tapping the button will not change the BPM. Instead,\nit acts as a Tap Beat button, always moving the start of the current\nbeat to match when you tapped the button.\n\nIf the metronome's BPM and beat positions are both being synced\nautomatically, either via the <<syncing-to-traktor-beat-phase,Traktor\nbeat phase mapping>> or <<syncing-to-pro-dj-link,Pioneer Pro DJ Link>>\n(as described further below) then tapping the button acts as a Tap Bar\nbutton, telling Afterglow that the moment when you tapped the button\nis the down beat (the first beat of the current bar).\n\nIn addition to Tap Tempo buttons, the grid controllers have Shift\nbuttons which modify the behavior of other buttons, including the Tap\nTempo button. That can be very convenient, especially when you are not\nsynced to a beat grid from Pioneer DJ Link Pro or Traktor, so you want\nto be able to set the tempo, the beat location, and the down beat. You\ncan set up another button on your controller to act this way and work\nwith your Tap Tempo button, but you need to map it before mapping the\nTap Tempo button, so you can make use of it in setting up the Tap\nTempo mapping.\n\nTo set up a Shift button on any MIDI controller you happen to have,\nstart by <<finding-mapping-details,identifying the mapping>> you need\nto interact with the button or pad you want to use, then call\n{api-doc}afterglow.controllers.tempo.html#var-add-midi-control-to-shift-mapping[`afterglow.controllers.tempo/add-midi-control-to-shift-mapping`]\nto set it up.\n\nFor example, to set this up for the kbd:[Play] button on a Korg\nnanoKONTROL2 controller, you can call:\n\n[source,clojure]\n----\n(def shift-map\n  (afterglow.controllers.tempo/add-midi-control-to-shift-mapping\n    \"nano\" 0 :control 41))\n----\n\n> See the\n{api-doc}afterglow.controllers.tempo.html#var-add-midi-control-to-shift-mapping[documentation]\nfor details about all the arguments.\n\nOnce you've done that, when you hold down that button Afterglow lights\nit up, and when you release it Afterglow darkens it. But more\nimportantly, you can use the value it returned to set up a\nrelationship between your Shift button and a Tap Tempo button:\n\n[source,clojure]\n----\n(def tempo-map\n  (afterglow.controllers.tempo/add-midi-control-to-tempo-mapping\n    \"nano\" 0 :control 45 :shift-fn (:state shift-map)))\n----\n\nThis tells Afterglow to check the state of your Shift button whenever\nyou it your Tap Tempo button. If the Shift button is not held down,\nthe Tap Tempo button acts as described above, but if your Shift button\n_is_ being held down, tempo taps act differently, synchronizing at one\nlevel higher.\n\nSo if your show metronome is unsynchronized, and the Tap Tempo button\nwould normally align the beat or set the BPM, or if it is synchronized\nto MIDI clock and the button always simply aligns the beat, then\ntapping it while holding down your Shift key makes it act as a Tap Bar\nbutton, telling Afterglow that the moment when you tapped the button\nis the down beat (the first beat of a bar).\n\nIf the BPM and beat positions are both already being synced\nautomatically, so the button would normally act as a Tap Bar button,\nthen with Shift down it acts as a Tap Phrase button, telling Afterglow\nthat the closest beat to when you tapped the button is the start of an\nentire phrase.\n\nIf you ever want to stop using the mapped buttons, there is a function\nto remove MIDI mappings. This would undo what we did above:\n\n[source,clojure]\n----\n(afterglow.midi/remove-control-mapping \"nano\" 0 :control 45 tempo-map)\n(afterglow.midi/remove-control-mapping \"nano\" 0 :control 41 shift-map)\n----\n\nSimply detaching the MIDI controller also automatically removes any\nmappings that were created for it.\n\n[[syncing-to-midi-clock]]\n== Syncing to MIDI Clock\n\nMany DJ mixers automatically send MIDI clock pulses to help synchronize\nto their BPM. Pioneer’s Nexus mixers send MIDI clock over both their\nphysical MIDI connection, and over USB if you are connected that way,\nconveniently. But they offer far more useful sync information over the\nEthernet port via Pro DJ Link packets, which Afterglow\n<<syncing-to-pro-dj-link,can also process>>.\n\nIf you are using a mixer or DJ software like Traktor which supports only\nMIDI clock sync, it is a lot better than nothing! Here is how to take\nadvantage of it.\n\nTIP: Native Instruments has an informative Knowledge Base article\nwhich\nhttps://support.native-instruments.com/hc/en-us/articles/209590629-How-to-Send-a-MIDI-Clock-Sync-Signal-in-TRAKTOR[explains]\nhow to configure Traktor to send the MIDI clock pulses that Afterglow\ncan sync to. Also see\n<<syncing-to-traktor-beat-phase,below>> for how to sync\nto the actual beat phase information when you are using Traktor.\n\nOnce you have your MIDI clock pulses reaching the system on which\nAfterglow is running, start Afterglow. Because of limitations inherent\nin the Java MIDI API, only MIDI devices which were connected when the\nprogram started are available to it. Then, assuming you have only one\ndevice sending MIDI clock, you can just execute:\n\n[source,clojure]\n----\n(show/sync-to-external-clock (afterglow.midi/sync-to-midi-clock))\n----\n\nIf there is ambiguity about which device’s MIDI clocks you want to\nprocess, Afterglow will complain. Resolve that by passing a device\nfilter which matches the device you want to use. The simplest kind of\nfilter you can pass is a string, which uniquely matches the name or\ndescription of the MIDI device that you want to sync to:\n\n[source,clojure]\n----\n(show/sync-to-external-clock\n  (afterglow.midi/sync-to-midi-clock \"traktor\"))\n----\n\nThe documentation for\n{api-doc}afterglow.midi.html#var-filter-devices[`afterglow.midi/filter-devices`]\nexplains the other kinds of device filter you can use.\n\nNOTE: This section describes the low-level mechanisms available for\nestablishing MIDI sync from code and the REPL. A much easier way is to\njust click the Sync button in the Metronome section at the bottom of\nthe <<README.adoc#web-ui,embedded Web interface>>.\n\nFrom then on, as the BPM of that device changes, Afterglow will track it\nautomatically. To check on the sync status, you can invoke:\n\n[source,clojure]\n----\n(show/sync-status)\n; -> {:type :midi, :status \"Running, clock pulse buffer is full.\"}\n----\n\nThe calculated BPM of the synced show can be displayed like this:\n\n[source,clojure]\n----\n(metro-bpm (:metronome sample-show))\n; -> 128.5046728971963\n----\n\nIt will bounce up and down near the actual BPM as clock pulses are\nreceived, but overall track the beat quite well. To get a rock-solid\nbeat lock you need to have equipment that can provide Pro DJ Link\nsyncing, as described below.\n\nTo shut down the syncing, just call `sync-to-external-clock` with no\nsync source:\n\n[source,clojure]\n----\n(show/sync-to-external-clock)\n(show/sync-status)\n; -> {:type :manual}\n----\n\n[[syncing-to-traktor-beat-phase]]\n== Syncing to Traktor Beat Phase\n\nIf you are using Traktor as your source of MIDI clock synchronization,\neven though you cannot quite attain the kind of smoothly precise BPM\nlock as you can with <<syncing-to-pro-dj-link,Pro DJ Link>>, you can\nconfigure Traktor to send its beat phase information in a way that\nAfterglow can detect and analyze, giving you the same kind of beat\ngrid synchronization.\n\nIn order to do that, download and unzip the Afterglow Traktor\nController Mapping,\nhttps://github.com/Deep-Symmetry/afterglow/raw/main/doc/modules/ROOT/assets/attachments/Afterglow.tsi.zip[Afterglow.tsi],\nand import it into Traktor.\n\nWARNING: Be sure to use the following steps to import the mapping,\nwhich will add it to any other mappings or settings you have already\nset up in Traktor. If you instead use the obvious and tempting\n`Import` button at the bottom of the Preferences window, you will\nreplace--rather than add to--your settings.\n\n1. Open the Traktor Preferences.\n\n2. Choose the `Controller Manager` section from the menu down the right.\n\n3. Click the `Add...` button in the `Device Setup` section at the top:\n+\nimage::TraktorAddMapping.png[Traktor Add Device Mapping,654,431]\n\n4. Choose `Import TSI` in the menu which pops up, and `Import\nOther...` at the bottom of the menu which that opens:\n+\nimage::TraktorImport.png[Traktor Import Other TSI,659,429]\n\n5. Navigate to the folder containing the `Afterglow.tsi` file you\ndownloaded, and open it.\n\nFollowing this procedure will create a Device named `Clock,\nAfterglow` within the Traktor Controller Manager:\n\nimage::TraktorMapping.png[Afterglow Traktor Device Mapping,996,774]\n\nSelect and use that rather than the Generic MIDI device you would\ncreate in the process described in the Traktor Knowledge Base article\nlinked above, and in addition to sending basic MIDI clock mesages,\nTraktor will send special MIDI messages that Afterglow will recognize\nand use to remain synchronized to the Traktor beat grid.\n\n[WARNING]\n====================================================================\nIn order to avoid extra MIDI clock pulses being sent, which will cause\nthe BPM calculations to be wildly incorrect, make sure not to create\nmore than one Generic MIDI device on the Traktor Virtual Output port.\nIf you created one following the directions in the Syncing to MIDI\nClock section above, be sure to delete it, and leave only the\nAfterglow Traktor controller mapping.\n\nYou must still follow the instructions in the Traktor\nhttps://support.native-instruments.com/hc/en-us/articles/209590629-How-to-Send-a-MIDI-Clock-Sync-Signal-in-TRAKTOR[Knowledge\nBase article], starting with step 3.2, to ensure that the `Clock,\nAfterglow` device is configured to send MIDI messages to the\nappropriate MIDI output port, and step 4, which configures Traktor to\nsend MIDI clock.\n====================================================================\n\nThe way the Afterglow mapping works is that it sends out Control\nChange messages for all currently playing decks. These messages\ncommunicate the current beat phase on that deck. (Deck A is sent as\ncontroller `1`, B as controller `2`, C as controller `3`, and D as\ncontroller `4`). In order for Afterglow to know which deck to pay\nattention to if more than one is playing at the same time, whenever a\ndifferent deck becomes the Tempo Master, a message identifying the new\nMaster deck is sent out as a Control Change message on controller `0`.\n(The same number to deck correspondence is used.) When no deck is\nTempo Master, a Control Change with value `0` is sent on controller\n`0`.\n\nWhenever Afterglow detects a coordinated stream of messages on\ncontrollers `0` through `4` which are consistent with beat-phase\ninformation from this Traktor mapping, it offers that MIDI input\ndevice as a source of Traktor beat-phase synchronization, and if it is\n<<syncing-to-midi-clock,synchronizing a metronome>> with the MIDI\nclock messages on that port, will also synchronize the beats.\n\n[[syncing-to-pro-dj-link]]\n== Syncing to Pro DJ Link\n\nIf you are working with Pioneer club gear, such as the Nexus line of\nCDJs and mixers, you can use Pro DJ Link to sync much more precisely.\nYou just need to be on the same LAN as the gear (most easily by\nconnecting an Ethernet cable between your laptop running Afterglow and\nthe mixer, or a hub or router connected to the mixer. You don’t need to\nbe connected to the Internet, the protocol works fine over self-assigned\nIP addresses. You just need to specify which device you want to use as\nthe source of beat information, and that will generally be the mixer,\nsince it will track whichever device is currently the tempo master (or\nperform BPM analysis if a non-DJ-Link, or even non-digital, source is\nbeing played). Like with MIDI sync, you can give a unique substring of\nthe device name in the sync call:\n\n[source,clojure]\n----\n(show/sync-to-external-clock\n  (afterglow.dj-link/sync-to-dj-link \"DJM-2000\"))\n----\n\nAs with MIDI, you can check on the sync status:\n\n[source,clojure]\n----\n(show/sync-status)\n; -> {:type :dj-link, :status \"Running, 5 beats received.\"}\n; -> {:type :dj-link,\n;     :status \"Network problems? No DJ Link packets received.\"}\n----\n\nTIP: If you are not getting any packets, you will need to put on your\nnetwork troubleshooting hat, and figure out why UDP broadcast packets\nto port 50001 from the mixer are not making it to the machine running\nAfterglow.\n\n[[midi-over-networks]]\n== Sending MIDI Over a Network\n\nYou can sync MIDI clock and respond to MIDI controller messages from\nhardware and software which is not directly attached to the machine\nrunning Afterglow. If you are on a Mac, this capability is built in,\nand can be configured using the\nhttps://help.apple.com/audiomidisetup/mac/10.10/index.html?localePath=en.lproj#/ams1012[Audio\nMIDI Setup] utility (in the `Utilities` subfolder of your\n`Applications` folder). For Windows, you can install the excellent,\nfree, and fully compatible\nhttp://www.tobias-erichsen.de/software/rtpmidi.html[rtpMIDI] driver.\nEither of these approaches allow you to communicate with the network\nMIDI capabilities built in to iOS devices and applications.\n\nIf you are interested in using Open Sound Control (OSC) control\nsurfaces with Afterglow, you should also check out the free\nhttp://hexler.net/software/touchosc[TouchOSC] package (also available\nfor http://hexler.net/software/touchosc-android[Android]). The TouchOSC\nsite also has a nice\nhttp://hexler.net/docs/touchosc-setup-coremidi-network[illustrated\nwalk-through] of setting up network MIDI communication.\n\n[[local-midi-ports]]\n== Connecting to MIDI Ports on the Same Machine\n\nTo achive MIDI routing on a single machine, you need to set up a\nvirtual MIDI bus. On the Mac you can use Core MIDI's built-in IAC bus,\nand on Windows you could use the MIDI Yoke utility. You can find\nhttps://help.ableton.com/hc/en-us/articles/209774225-Setting-up-a-virtual-MIDI-bus[a\ngood tutorial] about the needed steps on the Ableton Live website.\n\n[[checking-sync]]\n== Checking your Sync\n\nAn easy way to see how well your show is syncing the beat is to use the\n`metronome-effect`, which flashes a bright pink pulse on the down beat, and a\nless bright yellow pulse on all other beats of the show metronome. To\nset that up:\n\n[source,clojure]\n----\n(require 'afterglow.effects.fun)\n(show/add-effect! :color\n  (afterglow.effects.fun/metronome-effect (show/all-fixtures)))\n----\n\nThen you can reset the metronome by hitting kbd:[Return] on the following\ncommand, right on the down beat of a track playing through your\nsynchronized gear, and watch how Afterglow tracks tempo changes made by\nthe DJ from then on:\n\n[source,clojure]\n----\n(metro-start (:metronome sample-show) 1)\n----\n\nWhen running live light shows you will almost certainly want to map a\nbutton on a MIDI controller to perform this beat resynchronization\n(although it is not necessary when you are using Pro DJ Link to\nsynchronize with your mixer—but even then you will likely want the next\ntwo functions mapped, for realigning on bars and phrases). Here is how I\ndo it for one of the buttons on my Korg nanoKontrol 2:\n\n[source,clojure]\n----\n(show/add-midi-control-metronome-reset-mapping \"slider\" 0 45)\n----\n\nThen, whenever I press that button, the metronome is started at beat 1,\nbar 1, phrase 1.\n\nYou can add mappings to reset metronomes which are stored in show\nvariables by adding the variable name as an additional parameter at the\nend of this function call.\n\nAs noted above, even when you have a rock solid beat sync with your\nmixer, you sometimes want to adjust when bars or phrases begin,\nespecially when tricky mixing has been taking place. You can accomplish\nthis by mapping other buttons with\n`add-midi-control-metronome-align-bar-mapping` and\n`add-midi-control-metronome-align-phrase-mapping`. These cause the MIDI\ncontrol to call `metro-bar-start` and `metro-phrase-start` on the\nassociated metronome to restart the current bar or phrase on the nearest\nbeat, without moving the beat. This means you do not need to be as\nprecise in your timing with these functions, so you can stay beat-locked\nwith your synch mechanism, much like the “beat jump” feature in modern\nDJ software.\n\nIf the metronome flashes start driving you crazy, you can switch back to\na static cue,\n\n[source,clojure]\n----\n(show/add-effect! :color blue-effect)\n----\n\nor even black things out:\n\n[source,clojure]\n----\n(show/clear-effects!)\n----\n\n[[open-sound-control]]\n== Open Sound Control\n\nAfterglow also embeds https://github.com/rosejn/osc-clj[osc-clj] so\nyou can bind cues and variables to be controlled via Open Sound\nControl (OSC), using tools like hexler.net's\nhttp://hexler.net/software/touchosc[TouchOSC]. The sample show in the\n`afterglow.examples` namespace uses this capability to offer wireless\ngraphical X-Y-Z aiming of groups of moving heads:\n\nimage::TouchOSC.jpg[TouchOSC interface,1024,1366]\n\nThe functions\n{api-doc}afterglow.examples.html#var-add-osc-cue-binding[`add-osc-cue-binding`] and\n{api-doc}afterglow.examples.html#var-add-osc-var-binding[`add-osc-var-binding`], and\nthe ones near them in the namespace, show how this was done. They seem\nto work well enough that they will be fleshed out a bit and moved into\na new OSC-support namespace in a future release of Afterglow. But for\nnow, you can use them and tweak them as they are.\n\n[[rich-grid-controller-mappings]]\n== Rich Grid Controller Mappings\n\nAfterglow ships with built-in mappings that take advantage of several\nexcellent grid controllers. If you happen to own one, you are in luck!\nAnd if you don't, reading about these capabilities may tempt you to\nbuy one, or write a mapping for one that you own that is not yet\nsupported.\n\n[[using-ableton-push]]\n=== Using Ableton Push\n\nPerhaps the best way to control Afterglow is using the fluid, tactile\ninterface offered by the Ableton Push. There's enough to say about\nthat now that it has been moved to its own\n<<push2.adoc#,page>>.\n\n[[using-novation-launchpad]]\n=== Using the Novation Launchpad Family\n\nNovation also makes a great line of grid controllers, some of which\noffer touch-sensitivity as well. Even though they lack built-in text\nand graphical displays (at least so far), Afterglow uses them well\nenough that they get their own <<launchpad.adoc#,page>>.\n\n[[setting-up-grid-controller-bindings]]\n=== Setting Up Grid Controller Bindings\n\nWhen you set up the sample show by calling `(use-sample-show)` in the\n`afterglow.examples` namespace, it configures Afterglow to\nautomatically use any compatible grid controller as soon as it is\ndetected in the MIDI environment. Here is a closer look at how it\naccomplishes that. It uses the\n{api-doc}afterglow.controllers.html#var-auto-bind[`auto-bind`]\nfunction in the `afterglow.controllers` namespace:\n\n[source,clojure]\n----\n(require '[afterglow.controllers :as ct])\n(ct/auto-bind *show*)\n----\n\nWhen you want to shut down the bindings running on all connected\ncontrollers, you can call:\n\n[source,clojure]\n----\n(ct/deactivate-all)\n----\n\nYou can also undo the binding of any controller by simply\ndisconnecting it or powering it down; Afterglow will gracefully\nstop using it when that happens.\n\nBoth of the above approaches leave the auto-binding mechanism active,\nthough. So if you attach a new controller, or disconnect (or turn off)\none of the controllers that you just deactivated, then reconnect it\n(or turn it back on), it will get bound again. To stop that from\nhappening, you can call:\n\n[source,clojure]\n----\n(ct/cancel-auto-bind)\n----\n\nFrom that point on, controllers will be ignored as they come and go\nuntil you reactivate the auto-bind system. As described in the\n{api-doc}afterglow.controllers.html#var-auto-bind[API documentation],\nthere are optional parameters you can give to `auto-bind` to adjust\nthings like the refresh rate used by the controllers, or to only\nauto-bind to certain controllers. For example, if you only want to\nauto-bind to Push, you could call:\n\n[source,clojure]\n----\n(ct/auto-bind *show* :device-filter \"Ableton Push\")\n----\n\nSimilarly, to only bind to Launchpad Pro, you could use a\n`:device-filter` value of `\"Launchpad Pro\"` (or `\"Launchpad Mk2\"`,\n`\"Launchpad Mini\"`, or `\"Launchpad S\"`), or to bind to any member of\nthe Launchpad family, just `\"Launchpad\"`.\n\nWhenever you call `auto-bind` it cancels whatever previous auto-bind\nconfiguration had been set up, and applies your new arguments.\n\nIf you don't want to turn on auto-binding at all but simply want to\nset up a one-time binding to a controller that is already connected,\nyou can call\n{api-doc}afterglow.controllers.html#var-bind-to-show[`afterglow.controllers/bind-to-show`].\nThat function always expects you to pass a device filter as its second\nargument, and then accepts the same kinds of optional keyword\narguments that `auto-bind` does. It will try to bind to first device\nmatching the `device-filter` argument you supplied, so that needs to\nbe the correct port on a device like the Push or launchpad Pro which\nhas multiple MIDI ports. That means that to successfully bind to a\nPush or Launchpad Pro, you need calls like these:\n\n[source,clojure]\n----\n(def push (ct/bind-to-show *show* \"User Port\"))\n(def launchpad-pro (ct/bind-to-show *show* \"Standalone Port\"))\n----\n\nThat finds the User Port on the Push, and the Standalone Port on the\nLaunchpad Pro, which are the ports that Afterglow needs to use to\ncommunicate successfully with them. Simpler controllers like the\nLaunchpad Mk2, Mini, and S have only one port, so you can use the name\nof the device itself as your device filter.\n\nNOTE: If a compatible controller can't be immediately found at the\nfirst port that matches your device filter, `bind-to-show` will fail.\nThere are more sophisticated ways of building device filters than\nsimply using strings; see the\n{api-doc}afterglow.midi.html#var-filter-devices[`afterglow.midi/filter-devices`]\ndocumentation for details.\n\n\nThe example calls stored the results of calling `bind-to-show` in\nvariables, which is useful because you can later use those variables\nto individually shut down the resulting bindings:\n\n[source,clojure]\n----\n(ct/deactivate push)\n(ct/deactivate launchpad-pro)\n----\n\nOf course, if you don't care about that and simply want to deactivate\nall bindings, you can still use `(ct/deactivate-all)` as described\nabove. Or you can just turn off or unplug the controllers. Since\nauto-binding is not active, that will permanently remove them from\nAfterglow's control (at least until you explicitly re-bind them).\n"
  },
  {
    "path": "doc/modules/ROOT/pages/metronomes.adoc",
    "content": "= Metronomes\nJames Elliott <james@deepsymmetry.org>\n\nMetronomes play a fundamental role in coordinating the timing of\nAfterglow’s effects, and helping them relate to musical structure. They\nkeep track of musical time relative to some starting point, in terms of\nbeats, bars (by default four beats to a bar), and phrases (usually eight\nbars to a phrase). In addition to keeping track of the current beat,\nbar, and phrase, metronomes can also tell you the _phase_ of that beat,\nbar, or phrase, which is a measurement of progress through the beat,\nbar, or phrase. The phase starts out at 0.0 at the very beginning of the\ninterval, and grows towards, but never quite reaches, 1.0, because at\nthat point you have moved on to phase 0.0 of the following interval.\n\nMetronomes are generally combined with\n<<oscillators.adoc#,Oscillators>> to generate wave shapes which drive\nthe parameters sent to lights, creating color shifts, brightness\npulses, or movements.\n\nSince they are so important, there is always a metronome associated\nwith a show in Afterglow. It gets created when the show is created,\nand is used for the show’s timing unless you create a separate\nmetronome and explicitly tell an effect to use it (which you might\nwant to do if that effect is to run at a very different speed than the\nmusic). The main show metronome can be\n<<mapping_sync.adoc#,synchronized>> to external timing sources, such\nas DJ controllers and mixers, to keep the light show tightly in time\nwith the music being played. You can access the the main show’s\nmetronome through the `:metronome` keyword in the show map, for\nexample:\n\n[source,clojure]\n----\n(:metronome *show*)\n----\n\nTo create a separate metronome, you call:\n\n[source,clojure]\n----\n(afterglow.rhythm/metronome bpm)\n----\n\nThe `bpm` parameter tells the metronome what tempo to use, that is, how\nmany beats happen per minute. You can also adjust the number of beats\nwhich make up a bar (or measure), and how many bars make up a phrase:\n\n[cols=\"1,1,2\",options=\"header\",]\n|===================================================\n|Parameter |Default |Purpose\n|`:bpb` |`4` |How many beats make up a bar (measure)\n|`:bpp` |`8` |How many bars make up a phrase\n|===================================================\n\nThe metronome starts counting from the moment it was created, and you\ncan ask it for all the counts as a string by calling:\n\n[source,clojure]\n----\n(afterglow.rhythm/metro-marker (:metronome *show*))\n; -> \"15.1.4\"\n----\n\nTIP: This is used by the <<push2.adoc#metronome-control,Ableton\nPush controller mapping>> to display the metronome state and support\nbeat jumping.\n\nFor that metronome, the current count was phrase 15, bar 1, beat 4. You\ncan determine those values as individual numbers as well, but you might\nend up with confusing results because time is moving on while you are\ncalling the individual functions to ask for information, and you might\nbe on a different beat, bar, or phrase for a later call than an earlier\none. So the way to start is by asking the Metronome for a\n_{api-doc}afterglow.rhythm.html#var-ISnapshot[snapshot]_\nof its state at an instant in time, and then ask the snapshot for the\nindividual pieces of information you want. Afterglow does this when it\nstarts generating a frame of lighting effects, to make sure that all the\neffects share the same notion of the point at which they are being\nrendered, and create a consistent look:\n\n[source,clojure]\n----\n(afterglow.rhythm/metro-snapshot (:metronome *show*))\n; -> #afterglow.rhythm.MetronomeSnapshot{:start 1431727332206, :bpm 120, :bpb 4, :bpp 8,\n;    :instant 1431727683636, :beat 703, :bar 176, :phrase 22,\n;    :beat-phase 0.8600000000000136, :bar-phase 0.7150000000000034,\n;    :phrase-phase 0.9643750000000004}\n----\n\nAlthough this captures all of the information, it is not necessarily in\nthe format you want it, for example the beat number and bar number are\ncounted since the start of the metronome, and you usually want them\nsince the start of the bar or phrase. The snapshot has ways of providing\nthis information:\n\n[source,clojure]\n----\n(def snap (afterglow.rhythm/metro-snapshot (:metronome *show*)))\n; -> #'afterglow.examples/snap\n\nsnap\n; -> #afterglow.rhythm.MetronomeSnapshot{:start 1431727332206, :bpm 120, :bpb 4, :bpp 8,\n;    :instant 1431727967069, :beat 1270, :bar 318, :phrase 40, :beat-phase 0.7260000000001128,\n;    :bar-phase 0.4315000000000282, :phrase-phase 0.6789375000000035}\n\n(:beat snap)\n; -> 1270\n\n(afterglow.rhythm/snapshot-beat-within-bar snap)\n; -> 2\n----\n\nSince the notion of a “down beat” (the first beat in a bar) is important\nin music and thus potentially to lighting effects, there is a snapshot\nfunction for checking that, too:\n\n[source,clojure]\n----\n(afterglow.rhythm/snapshot-down-beat? snap)\n; -> false\n----\n\n____\nThe second beat is not the down beat.\n____\n\nThe metronome can be restarted at a particular beat by calling\n`metro-start` with a beat number. (Calling it with no argument returns\nthe time at which the metronome was started.) This can be useful to\nresynchronize the metronome to the music if it has drifted, either\nbecause there is no BPM synchronization in place, or if MIDI clock sync\nis being used, and it’s been a long time, since that can drift, unlike\nPro DJ Link sync:\n\n[source,clojure]\n----\n(afterglow.rhythm/metro-start (:metronome *show*) 1)\n; -> 1431727642086\n----\n\n____\nThe new metronome start timestamp is returned.\n____\n\nIf the beats are landing in the right place but the notion of the down\nbeat (bar start) or phrase start is wrong, you can reset those by\ncalling `metro-bar-start` or `metro-phrase-start` with the desired bar\nor phrase number (usually 1). These adjust the metronome so the larger\nintervals are resynchronized without changing the individual beats\nthemselves.\n\nThe metronome’s tempo (beats per minute) can be determined or changed by\ncalling `metro-bpm`. Without an argument it returns the current BPM, and\nan argument is used as the new BPM value. The same can be done with the\nbeats per bar (`metro-bpb`) and beats per phrase (`metro-bpp`).\n\nThere are a number of other functions which can be called on metronomes\nand snapshots. The\n{api-doc}afterglow.rhythm.html#var-IMetronome[`IMetronome`]\nand\n{api-doc}afterglow.rhythm.html#var-ISnapshot[`ISnapshot`]\nprotocols in\n{api-doc}afterglow.rhythm.html[`afterglow.rhythm`]\nspecify and describe them.\n\n[[watching-metronomes]]\n== Watching Metronomes\n\nTo help get a feeling for exactly what your metronome is doing, there is\nan effect that flashes one bright color on the down beat, and\nanother less-bright color on the rest of the beats. Running this while\nyou change the metronome BPM, sync, beats per bar, and such can help\ndrive a more visceral understanding. To run it for the main show\nmetronome, you can do this:\n\n[source,clojure]\n----\n(require 'afterglow.effects.fun)\n(show/add-effect! :color\n  (afterglow.effects.fun/metronome-effect *show*\n    (show/all-fixtures *show*)))\n----\n\nIf you want to watch a different metronome, the invocation looks like\nthis:\n\n[source,clojure]\n----\n(show/set-variable :my-metro (afterglow.rhythm/metronome 50))\n(require 'afterglow.effects.fun)\n(show/add-effect! :color\n  (afterglow.effects.fun/metronome-effect *show*\n    (show/all-fixtures) :metronome :my-metro))\n----\n\n____\nThe lights are pulsing sedately...\n____\n\n[source,clojure]\n----\n(metro-bpm (show/get-variable :my-metro) 400)\n----\n\n____\n...and now they are almost seizure-worthy!\n____\n"
  },
  {
    "path": "doc/modules/ROOT/pages/oscillators.adoc",
    "content": "= Oscillators\nJames Elliott <james@deepsymmetry.org>\n\nOscillators in Afterglow are a flexible way of turning the timing\ninformation tracked by <<metronomes.adoc#,metronomes>> into\nwaveforms that can be used to make lights do interesting things. They\ncan be related to the beats, bars, or phrases of the metronome, or\nmultiples or fractions thereof, and can create\n<<sawtooth-oscillators,sawtooth>>, <<triangle-oscillators,triangle>>,\n<<square-oscillators,square>>, or <<sine-oscillators,sine>> waves, or\nany <<custom-oscillators,custom shape>> you can dream up and code a\nshape function for.\n\nMetronomes keep track of musical time relative to some starting point,\nin terms of beats, bars (by default four beats to a bar), and phrases\n(usually eight bars to a phrase). In addition to keeping track of the\ncurrent beat, bar, and phrase, metronomes can also tell you the _phase_\nof that beat, bar, or phrase, which is a measurement of progress through\nthe beat, bar, or phrase. The phase starts out at 0.0 at the very\nbeginning of the interval, and grows towards, but never quite reaches,\n1.0, because at that point you will be on to phase 0.0 of the following\ninterval.\n\nSo, in a sense, by itself a metronome can give you a\n<<sawtooth-oscillators,sawtooth>> wave related to its intervals, just\nby looking at the interval phase. The sawtooth oscillators build on that\nby letting you change the direction of oscillation, so it starts at 1.0\nand slides downward, the speed of oscillation, so it ramps over\nmultiples or fractions of an interval, and also let you shift the phase\nof the wave so it does not coincide with the interval itself.\n\nSo that all of the lighting effects created for a given frame of control\noutput are synchronized and share the same notion of the current state\nof the metronome, Afterglow takes a _snapshot_ of the metronome at the\nstart of the frame, and the oscillators work from that.\n\n[[sawtooth-oscillators]]\n== Sawtooth Oscillators\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/sawtooth)\n----\n\nReturns an oscillator which generates a\nhttp://en.wikipedia.org/wiki/Sawtooth_wave[sawtooth wave] relative to\nthe phase of the current beat. At the start of the beat, the value will\nbe 0.0, and at the end of the beat, the value will have grown linearly\nto 1.0.\n\nimage::sawtooth-beat.png[Default Sawtooth Oscillator,500,378]\n\nYou can change the nature of the wave by using optional keyword\nparameters, and the values you use with them can be be\n<<parameters.adoc#,dynamic parameters>>:\n\n[cols=\"2,1,4\",options=\"header\",]\n|=======================================================================\n|Parameter |Default |Purpose\n|`:down?` |`false` |When `true` the wave starts at 1.0 and falls\nlinearly to 0.0.\n\n|`:interval` |`:beat` |Change whether the oscillator cycles over each\nbeat, bar, or phrase, by passing in the keyword `:beat`, `:bar`, or\n`:phrase`. There are graphs showing the other intervals below.\n\n|`:interval-ratio` |`1` |Runs the oscillator at the specified\n <<ratios,multiple or fraction>> of the interval (beat, bar, or\n phrase).\n\n|`:phase` |0.0 |<<phase-shifting,Offsets>> the oscillator from the\ninterval boundary by the specified amount (where 1.0 is an entire\ninterval, and so would have no visible effect).\n|=======================================================================\n\nAs noted in the table, the direction of the wave can be reversed:\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/sawtooth :down? true)\n----\n\nimage::sawtooth-beat-down.png[Downward Sawtooth Oscillator,500,378]\n\n[[ratios]]\n=== Ratios\n\nAll of the oscillators can be modified by supplying the\n`:interval-ratio` keyword argument. This argument specifies a fraction\nthat adjusts the speed of the oscillator with respect to the interval\nit is oscillating over. For example a beat-oriented oscillator\nnormally goes through its entire wave shape once per beat. If you\nsupply an `:interval-ratio` of `2`, it will run half as fast, taking\ntwo beats to go through its waveform.\n\nimage::sawtooth-beat-ratio-2.png[Sawtooth Beat Oscillator with Beat Ratio 2,500,378]\n\nAn `:interval-ratio` of `1/3` speeds it up so that it only takes\none-third of a beat to go through its oscillation, and will finish\nthree complete cycles each beat.\n\nimage::sawtooth-beat-ratio-1-3.png[Sawtooth Oscillator with Interval Ratio 1/3,500,378]\n\nThese can be combined, of course, so an `:interval-ratio` of `2/3`\nwould complete three cycles every two beats.\n\nimage::sawtooth-beat-ratio-2-3.png[Sawtooth Oscillator with Interval Ratio 2/3,500,378]\n\n[[phase-shifting]]\n=== Phase Shifting\n\nAll of the oscillators can be modified by supplying a `:phase` keyword\nargument, which offsets them from the actual phase of the interval that\nthey are tracking. For example, if you supply a `:phase` value of `0.5`,\nthe oscillator will be pushed exactly halfway out-of-phase with the\nmetronome interval, so that it will act as if a beat is starting halfway\nthrough the actual beat. A positive value shifts the oscillator ahead of\nthe underlying interval, and a negative value delays it. Only values\nbetween -1.0 and 1.0 make sense, since shifting multiple intervals has\nno functional difference from staying within the current interval. In\nother words, passing in exactly 1.0 (or 2.0, etc.) is the same as\npassing in 0.0, and will have no effect on the oscillator.\n\nimage::sawtooth-beat-phase.png[Sawtooth Oscillator with Phase 0.25,500,378]\n\nAs noted in the table above, to have the oscillator work with\nintervals other than beats, you use the optional keyword argument\n`:interval`. For example to have the sawtooth spread over each bar:\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/sawtooth :interval :bar)\n----\n\nimage::sawtooth-bar.png[Sawtooth Bar Oscillator,500,378]\n\nAnd to have it oscillate over each phrase:\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/sawtooth :interval :phrase)\n----\n\nimage::sawtooth-phrase.png[Sawtooth Phrase Oscillator,500,378]\n\n[[triangle-oscillators]]\n== Triangle Oscillators\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/triangle)\n----\n\nReturns an oscillator which generates a\nhttp://en.wikipedia.org/wiki/Triangle_wave[triangle wave] relative to\nthe phase of the current beat. At the start of the beat, the value will\nbe 0.0, at the midpoint, the value will have grown linearly to 1.0, and\nat the end of the beat it will have returned to 0.0.\n\nimage::triangle-beat.png[Default Triangle Oscillator,500,378]\n\nYou can change the nature of the wave by using optional keyword\nparameters, and the values you use with them can be be\n<<parameters.adoc#,dynamic parameters>>:\n\n[cols=\"2,1,4\",options=\"header\",]\n|=======================================================================\n|Parameter |Default |Purpose\n|`:interval` |`:beat` |Change whether the oscillator cycles over each\nbeat, bar, or phrase, by passing in the keyword `:beat`, `:bar`, or\n`:phrase`. There are graphs showing the other intervals below.\n\n|`:interval-ratio` |`1` |Runs the oscillator at the specified\n <<ratios,multiple or fraction>> of the interval (beat, bar, or\n phrase).\n\n|`:phase` |0.0 |<<phase-shifting,Offsets>> the oscillator from the\nbeat by the specified amount\n|=======================================================================\n\nNOTE: The effects of the `:interval-ratio` and `:phase` parameters are\ndiscussed in more depth, and illustrated with graphs, in the\ndocumentation for the Sawtooth oscillator. You can jump to those\nsections using the links in the _Purpose_ section of the table.\n\nAs noted in the table above, to have the oscillator work with\nintervals other than beats, you use the optional keyword argument\n`:interval`. For example to have the triangle spread over each bar:\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/triangle :interval :bar)\n----\n\nimage::triangle-bar.png[Triangle Bar Oscillator,500,378]\n\nAnd to have it oscillate over each phrase:\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/triangle :interval :phrase)\n----\n\nimage::triangle-phrase.png[Triangle Phrase Oscillator,500,378]\n\n[[sine-oscillators]]\n== Sine Oscillators\n\nJust like in musical synthesis, sine waves are the smoothest-feeling\nwaves of all, and are good for creating gentle, subtle effects which\nease in and out.\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/sine)\n----\n\nReturns an oscillator which generates a\nhttp://en.wikipedia.org/wiki/Sine_wave[sine wave] relative to the phase\nof the current beat. At the start of the beat, the value will be 0.0 and\nbeginning to rise slowly, picking up speed as it goes, and slowing down\nagain as it approaches the midpoint. At the midpoint, the value will\nreach 1.0 and begin falling slowly, again picking up speed, and at the\nend of the beat it will have returned to 0.0.\n\nimage::sine-beat.png[Default Sine Oscillator,500,378]\n\nYou can change the nature of the wave by using optional keyword\nparameters, and the values you use with them can be be\n<<parameters.adoc#,dynamic parameters>>:\n\n[cols=\"2,1,4\",options=\"header\",]\n|=======================================================================\n|Parameter |Default |Purpose\n|`:interval` |`:beat` |Change whether the oscillator cycles over each\nbeat, bar, or phrase, by passing in the keyword `:beat`, `:bar`, or\n`:phrase`. There are graphs showing the other intervals below.\n\n|`:interval-ratio` |`1` |Runs the oscillator at the specified\n <<ratios,multiple or fraction>> of the interval (beat, bar, or\n phrase).\n\n|`:phase` |0.0 |<<phase-shifting,Offsets>> the oscillator from the\nbeat by the specified amount\n|=======================================================================\n\nNOTE: The effects of the `:interval-ratio` and `:phase` parameters are\ndiscussed in more depth, and illustrated with graphs, in the\ndocumentation for the Sawtooth oscillator. You can jump to those\nsections using the links in the _Purpose_ section of the table.\n\nAs noted in the table above, to have the oscillator work with\nintervals other than beats, you use the optional keyword argument\n`:interval`. For example to have the sine wave spread over each bar:\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/sine :interval :bar)\n----\n\nimage::sine-bar.png[Sine Bar Oscillator,500,378]\n\nAnd to have it oscillate over each phrase:\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/sine :interval :phrase)\n----\n\nimage::sine-phrase.png[Sine Phrase Oscillator,500,378]\n\n[[square-oscillators]]\n== Square Oscillators\n\nSquare waves are good for abrupt transitions, like strobes, or switching\nbetween different effects.\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/square)\n----\n\nReturns an oscillator which generates a\nhttp://en.wikipedia.org/wiki/Square_wave[square wave] relative to the\nphase of the current beat. At the start of the beat, the value will be\n1.0. At the midpoint, it will instantly drop to 0.0, where it will stay\nuntil the end of the beat.\n\nimage::square-beat.png[Square Beat Oscillator,500,378]\n\nYou can change the nature of the wave by using optional keyword\nparameters, and the values you use with them can be be\n<<parameters.adoc#,dynamic parameters>>:\n\n[cols=\"2,1,4\",options=\"header\",]\n|=======================================================================\n|Parameter |Default |Purpose\n|`:width` |`0.5` |Determines the phase at which the value changes from\n1.0 to 0.0, and therefore the width of the 1.0 pulse\n\n|`:interval` |`:beat` |Change whether the oscillator cycles over each\nbeat, bar, or phrase, by passing in the keyword `:beat`, `:bar`, or\n`:phrase`. There are graphs showing the other intervals below.\n\n|`:interval-ratio` |`1` |Runs the oscillator at the specified\n <<ratios,multiple or fraction>> of the interval (beat, bar, or\n phrase).\n\n|`:phase` |0.0 |<<phase-shifting,Offsets>> the oscillator from the\nbeat by the specified amount\n|=======================================================================\n\nNOTE: The effects of the `:interval-ratio` and `:phase` parameters are\ndiscussed in more depth, and illustrated with graphs, in the\ndocumentation for the Sawtooth oscillator. You can jump to those\nsections using the links in the _Purpose_ section of the table.\n\n[[pulse-widths]]\n=== Pulse Widths\n\nAs shown in the above graph, the square oscillator normally spends\nhalf its time in the &ldquo;on&rdquo; state (at the value one), and\nhalf its time &ldquo;off&rdquo; (at zero). You can adjust that by\npassing a value between `0.0` and `1.0` with the optional keyword\nargument `:width`. This tells the oscillator what fraction of the time\nto be on. For example, with the value `0.8`, it is on 4/5 of the time:\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/square :width 0.8)\n----\n\nimage::square-beat-width-8.png[Square Oscillator with Width 0.8,500,378]\n\nAlternately, using a `:width` of `0.1` causes the oscillator to be on\nfor only one tenth of each beat:\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/square :width 0.1)\n----\n\nimage::square-beat-width-1.png[Square Oscillator with Width 0.1,500,378]\n\nYou can shift where within the beat the transitions take place using\nthe `:phase` argument, as with all oscillators, in the manner\ndescribed <<phase-shifting,above>>.\n\nNOTE: The `:width` value must be greater than `0` and less than `1`,\nor the oscillator does not oscillate at all. A value of `0` leaves it\npermanently off, and a value of `1` leaves it permanently on. Values\noutside that range are not accepted.\n\nAs noted in the table above, to have the oscillator work with\nintervals other than beats, you use the optional keyword argument\n`:interval`. For example to have the wave spread over each bar:\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/square :interval :bar)\n----\n\nimage::square-bar.png[Square Bar Oscillator,500,378]\n\nAnd to have it oscillate over each phrase:\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/square :interval :phrase)\n----\nimage::square-phrase.png[Square Phrase Oscillator,500,378]\n\n[[custom-oscillators]]\n== Custom Oscillators\n\nYou can build your own oscillator with any shape waveform that you\nlike by defining a _shape function_ for it, and let Afterglow do all\nthe hard work of hosting it within the oscillator framework by passing\nthat shape function to\n{api-doc}afterglow.effects.oscillators.html#var-build-oscillator[`afterglow.effects.oscillators/build-oscillator`].\nAll of the oscillators you have seen so far use this approach, and you\ncan see how simple they actually are by looking at the source of one,\nfor example\n{api-doc}afterglow.effects.oscillators.html#var-triangle[`triangle`],\nwhich defines a the triangle wave oscillator. (Click on the `view\nsource` button at the bottom of the linked documentation.)\n\nAs you will see, most of the function consists of its documentation,\nand its argument declaration, and those simply get passed on to\n`build-oscillator`, which supports the `:interval`, `:interval-ratio`,\nand `:phase` arguments you've seen in all the oscillator functions.\nThe core of `triangle` is setting up its shape function to create the\ntriangle wave which makes it a triangle oscillator.\n\n[[shape-functions]]\n=== Shape Functions\n\nThe shape function is the first argument to `build-oscillator`, and it\nis simply a function which is given the current phase of the\noscillator, ranging from 0.0 to 1.0, and must return the value of the\noscillator's wave form when it is at that phase of oscillation. In the\ncase of a triangle wave, it needs to ramp up from 0 to 1 during the\nfirst half of the oscillation (as the phase grows from 0 to 0.5), then\nback down to 0 during the second half. Here is how `triangle`\nimplements that:\n\n[source,clojure]\n----\n(fn [phase]\n  (if (< phase 0.5)\n    (* phase 2.0)\n    (- 2.0 (* phase 2.0))))\n----\n\nThe arguments to `triangle` are then passed along to\n`build-oscillator` after the phase function, and the result is the\ntriangle oscillator behavior you can use in your shows.\n\nHopefully examining this example, as well as the source of the other\noscillators, can inspire you to create your own interesting oscillator\nshapes.\n"
  },
  {
    "path": "doc/modules/ROOT/pages/parameters.adoc",
    "content": "= Dynamic Parameters\nJames Elliott <james@deepsymmetry.org>\n\nDynamic parameters provide a way to turn a simple cue into something\nwhich changes over time and space, or reacts to operator input. Most\ncues which take simple values can also take dynamic parameters which\nevaluate to those values.\n\n[[frame-dynamic-parameters]]\n== Frame Dynamic Parameters\n\nWhen creating a dynamic parameter, you can control _how_ dynamic it is.\nThe most dynamic, __frame dynamic__, are evaluated anew for every single\nframe of control values that are sent out to the lights. If, on the\nother hand, you want the value to be calculated when the effect is\nstarted, and then stay constant, you can create the parameter with a\n`false` value for `frame-dynamic?`\n\n[[variable-parameters]]\n== Variable Parameters\n\nParameters can get their values from a __show variable__. Any number of\nvalues can be stored in the show, by assigning them a keyword with the\nfunction:\n\n[source,clojure]\n----\n(afterglow.show/set-variable! :key value)\n----\n\nTIP: In addition to manually setting values in show variables, you can\nuse <<mapping_sync.adoc#mapping-a-control-to-a-variable,MIDI mappings>> to\nhave them set by turning a knob or sliding a fader on a MIDI control\nsurface. <<cues.adoc#,Cues>> can also set variables, and can bind\nthem to encoders or pressure sensitive pads on controllers like the\n<<push2.adoc#,Ableton Push>> and\n<<launchpad.adoc#,Novation Launchpad Pro>>.\n\nYou can then refer to that stored value whenever you are building a\ndynamic parameter (for example when you are passing in the `:hue`\nparameter for a <<color-parameters,Color Parameter>>\nas described below), by simply using the keyword (in this example,\n`:key`), and the current value stored in the show variable will be\nused.\n\nThis keyword shorthand is just a convenience mechanism provided by\nfunctions like\n{api-doc}afterglow.effects.params.html#var-build-color-param[`build-color-param`].\nYou can also explicitly build a reference to a show variable like\nthis:\n\n[source,clojure]\n----\n(afterglow.effects.params/build-variable-param :key)\n----\n\nThe most common reason you might want to use the explicit creation\nfunction is that you can control details about the binding by passing\nin optional keyword parameters:\n\n[cols=\"1,1,4\",options=\"header\",]\n|=======================================================================\n|Parameter |Default |Purpose\n|`:type` |`Number` |The type of value that is expected in the variable\n\n|`:default` |`0` |The value to assign the parameter if the variable is\nmissing or has the wrong type\n\n|`:transform-fn` |none |If supplied, is called with the value of the show\nvariable, and its return value is used as the value of the parameter\n\n|`:frame-dynamic` |`true` |Whether the variable value should be looked\nat at every frame, or just once\n|=======================================================================\n\nAs an example of using these parameters, consider:\n\n[source,clojure]\n----\n(afterglow.effects.params/build-variable-param\n  :key :type Number :default 0 :transform-fn #(* % 2))\n----\n\nThis would cause the dynamic parameter to have a numeric value which is\ntwice the value found in the show variable named `:key`.\n\nWhen you use the keyword shorthand to bind to a show variable in\nbuilding another dynamic parameter, the type and default are assumed\nfrom the context in which you are using the variable.\n\nTIP: Another time when you will need to use this explicit way of\nbuilding a dynamic parameter from a show variable is if the parameter\nholds keywords. In that case, clearly Afterglow can't assume that a\nkeyword is shorthand for a show variable. The `:interval` parameter\nfor Afterglow's built in oscillator-building functions, like\n{api-doc}afterglow.effects.oscillators.html#var-sine[`afterglow.effects.oscillators/sine`],\nis an example of such a parameter: It expects the value `:beat`,\n`:bar`, or `:phrase`. So to have an oscillator look up and use the\nvalue in the show variable `:my-interval` to control the interval over\nwhich it oscillates, you would write something like this:\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/sine\n  :interval (afterglow.effects.params/build-variable-param\n              :my-interval :type clojure.lang.Keyword :default :beat))\n----\n\n[[oscillated-parameters]]\n== Oscillated Parameters\n\nOscillated parameters vary over time, at a speed controlled by a\n<<metronomes.adoc#,Metronome>> (usually the main show metronome,\nsynced to DJ equipment) and so can make the lights appear to be\nreacting intelligently to the music being played. The timing\ninformation produced by the metronome is fed into an\n<<oscillators.adoc#,Oscillator>>, which determines the shape of\nthe wave that controls its value, and the frequency at which it\noscillates, related to beats, bars, or phrases of the underlying\nmetronome. The resulting value can then be scaled to meet the needs of\nwhatever is being generated (a dimmer level, color component, or light\nrotation). Oscillated parameters are created by calling\n{api-doc}afterglow.effects.oscillators.html#var-build-oscillated-param[`afterglow.effects.oscillators/build-oscillated-param`].\n\n\n[source,clojure]\n----\n(afterglow.effects.oscillators/build-oscillated-param oscillator)\n----\n\nThe `oscillator` parameter is an\n<<oscillators.adoc#,Oscillator>> created by one of the functions\nin\n{api-doc}afterglow.effects.oscillators.html[`afterglow.effects.oscillators`]\nwhich, as described above, determines how to react to the time\ninformation provided by the metronome. Additionally, you can supply\none of the following optional keyword parameters:\n\n[cols=\"1,1,4\",options=\"header\",]\n|=======================================================================\n|Parameter |Default |Purpose\n|`:min` |`0` |The smallest value that the oscillated parameter will be\nassigned\n\n|`:max` |`255` |The largest value that the oscillated parameter will be\nassigned\n\n|`:metronome` |none |If supplied, is used instead of the main show\nmetronome\n\n|`:frame-dynamic` |`true` |Whether the parameter should be calculated at\nevery frame, or just once\n|=======================================================================\n\nThe keyword parameters `:min`, `:max`, and `:metronome` can themselves\nbe bound to show variables by passing in the keyword with which the show\nvariable was created. The frame-dynamic setting of such variable\nbindings will be controlled by the frame-dynamic setting of the\noscillated parameter being created.\n\nNOTE: If `:min` ever evaluates greater than or equal to `:max`, the\noscillator will be pinned to the value of `:min`.\n\n[[step-parameters]]\n== Step Parameters\n\nLike oscillated parameters (above), step parameters vary over time, at\na speed controlled by a <<metronomes.adoc#,Metronome>> (usually\nthe main show metronome, synced to DJ equipment). But rather than\nmoving back and forth, step parameters increase steadily over time,\nbecause they are designed to control the progression of a\n<<effects.adoc#chases,chase>>. Step parameters are created by calling\n{api-doc}afterglow.effects.params.html#var-build-step-param[`afterglow.effects.params/build-step-param`].\n\n[source,clojure]\n----\n(afterglow.effects.params/build-step-param)\n----\n\nWith no arguments, this creates a step parameter that starts out with\nthe value `1` for the duration of the beat closest to when you created\nit, and the value will jump up by one as each subsequent beat occurs:\n\nimage::step-fade-0.png[Default Step Parameter,500,378]\n\nIf a less-abrupt transition between stages in the chase is desired, a\nfade can be added between them by passing a value with the optional\nkeyword argument `:fade-fraction`. When omitted, the default value is\n`0`, meaning no time is spent fading, which results in the kind of\nabrupt steps seen in the graph above. Passing a value of `0.2` would\ncause the parameter to spend 1/5 of its time fading: During the final\n0.1 of the beat, it would ramp up towards the midpoint of the next\nvalue, and then finish that ramp during the first 0.1 of the next\nbeat, as shown in the following graph:\n\n[source,clojure]\n----\n(afterglow.effects.params/build-step-param :fade-fraction 0.2)\n----\n\nimage::step-fade-0-2.png[Step Parameter with fade fraction 0.2,500,378]\n\nThe graph shows that most of each beat is spent with the step\nparameter steady at its expected value, but the first and last tenths\nare a linear fade from and to the next value. Changing the fade\nfraction to 0.5 causes half the time to be spent fading, and only half\nsitting at the beat's assigned value:\n\n[source,clojure]\n----\n(afterglow.effects.params/build-step-param :fade-fraction 0.5)\n----\n\nimage::step-fade-0-5.png[Step Parameter with fade fraction 0.5,500,378]\n\nThat trend continues until the maximum possible fade-fraction value of\n`1` is used, which causes all of each beat to be spent fading, so the\nstep parameter continuously fades through values, reaching the value\nassigned to a given beat at the midpoint of that beat:\n\n\n[source,clojure]\n----\n(afterglow.effects.params/build-step-param :fade-fraction 1)\n----\n\nimage::step-fade-1.png[Step Parameter with fade fraction 1,500,378]\n\nIn addition to linear fades, you can smooth out the start and end of\nthe fades by using a sine-shaped fade curve, by passing the optional\nkeyword argument `:fade-curve` with the value `:sine`. Here is what\nthat looks like with a continuous fade:\n\n[source,clojure]\n----\n(afterglow.effects.params/build-step-param :fade-curve :sine :fade-fraction 1)\n----\n\nimage::step-sine-fade-1.png[Step Parameter with sine curve and fade fraction 1,500,378]\n\nThe smoothing effect of the sine curve option becomes even more\nevident when you configure the step parameter to fade for only part of\nthe beat:\n\n[source,clojure]\n----\n(afterglow.effects.params/build-step-param :fade-curve :sine :fade-fraction 0.5)\n----\n\nimage::step-sine-fade-0-5.png[Step Parameter with sine curve and fade fraction 0.5,500,378]\n\nOf course, as the amount of time spent fading gets compressed, the\nsmoothing is less obvious, although it is still there. Dropping back\nto fading over just the first and last tenth of the beat looks like\nthis:\n\n[source,clojure]\n----\n(afterglow.effects.params/build-step-param :fade-curve :sine :fade-fraction 0.2)\n----\n\nimage::step-sine-fade-0-2.png[Step Parameter with sine curve and fade fraction 0.2,500,378]\n\nWhen the fade fraction is `0`, it does not matter what the fade curve\nis, because no fading takes place.\n\nYou can also have the step parameter increment for each bar or phrase,\nrather than each beat, by passing the optional keyword argument\n`:interval` with the value `:bar` or `:phrase`. And, as with\noscillators, you can use the optional keyword argument\n`:interval-ratio` to have the parameter run at the specified fraction\nor multiple of the chosen interval. The way that `:interval-ratio`\nworks is illustrated in the <<oscillators.adoc#ratios,Ratios>> section of\nthe oscillator documentation.\n\nAs one example of `:inteval-ratio` specifically applied to step\nparameters, here is what the preceding graph would look like if the\ninterval ratio was changed to a value of one half, meaning that the\nstep parameter increases every half of a beat:\n\n[source,clojure]\n----\n(afterglow.effects.params/build-step-param :interval-ratio (/ 1 2)\n                                           :fade-curve :sine :fade-fraction 0.2)\n----\n\nimage::step-sine-fade-0-2-half.png[alt=\"Step Parameter with sine curve, fade fraction 0.2, interval ratio 1/2\",width=500,height=378]\n\n\nFinally, if you would like the beat numbers to be counted from a time\nthat is different than when you created the step parameter, you can\npass a metronome snapshot along with the keyword argument `:starting`,\nand beats will be counted so that the first beat is the one that\noccured closest to that snapshot.\n\nFor maximum flexibility, any of the parameters to `build-step-param`\ncan themselves be dynamic parameters from the show. If none of them\nare, a more efficient version of the step parameter is built,\nprecalculating as much as possible.\n\n[[color-parameters]]\n== Color Parameters\n\nColor parameters are an extremely flexible way of dynamically assigning\ncolor. The basic way to create one is to call\n{api-doc}afterglow.effects.params.html#var-build-color-param[`afterglow.effects.params/build-color-param`].\n\n[source,clojure]\n----\n(afterglow.effects.params/build-color-param)\n----\n\nBy itself this call would simply return a non-dynamic black color.\nHowever, you will use one or more of the following optional keyword\nparameters to get the dynamic color you want:\n\n[cols=\"2,1,4\",options=\"header\",]\n|=======================================================================\n|Parameter |Default |Purpose\n|`:color` |black |The base, starting color of this dynamic color\n\n|`:r` |`0` |Red brightness, from 0 to 255\n\n|`:g` |`0` |Green brightness, from 0 to 255\n\n|`:b` |`0` |Blue brightness, from 0 to 255\n\n|`:h` |`0.0` |Hue value, from 0.0 to 360.0\n\n|`:s` |`0.0` |Saturaion value, from 0.0 to 100.0\n\n|`:l` |`0.0` |Lightness value, from 0.0 to 100.0\n\n|`:adjust-hue` |`0.0` |Hue shift value, from -360.0 to 360.0\n\n|`:adjust-saturation` |`0.0` |Saturation shift value, from -100.0 to\n100.0\n\n|`:adjust-lightness` |`0.0` |Lightness shift value, from -100.0 to 100.0\n\n|`:frame-dynamic` |`true` |Whether the parameter should be calculated at\nevery frame, or just once\n|=======================================================================\n\nAll of these parameters, except for `frame-dynamic`, can themselves be\ndynamic parameters, such as show <<variable-parameters,variables>>\n(with the convenience shorthand of just passing in the keyword by which\nthe show variable was stored) or <<oscillated-parameters,oscillated\nparameters>>.\n\nRefer to <<color.adoc#,Working with Color>> for a refresher on the\nmeaning of the basic color components. It would not make sense to pass\nall of these parameters, because some will override others, but here\nis how they are evaluated:\n\n. The base color is established by the `:color` parameter.\n\n. If any of `:r`, `:g`, or `:b` have been supplied, the color is\nreplaced by creating an RGB color with the values (or defaults)\nsupplied.\n\n. If any of `:h`, `:s`, or `:l` have been supplied, the color is\nreplaced by creating an HSL color with the values (or defaults)\nsupplied.\n\n. If `:adjust-hue` was supplied, the hue of the color obtained so far\nis shifted by adding that amount to it (and wrapping around the color\ncircle if needed).\n\n. If `adjust-saturation` was supplied, the saturation of the color is\nadjusted by adding that amount to it, maxing out at 100.0, and bottoming\nout at 0.0. Lower saturations yield less colorful (more gray) colors.\n\n. If `adjust-lightness` was supplied, the lightness of the color is\nadjusted by adding that amount to it, maxing out at 100.0, and bottoming\nout at 0.0. A lightness of 50.0 allows for a fully saturated color,\nlightnesses above that start getting whitened, and a lightness of 100.0\nis pure white; lightnesses below 50.0 start getting darkened, and a\nlightness of 0.0 is pure black.\n\nFinally, the result of all this is the color that is returned by the\ndynamic parameter. Afterglow tries to be as efficient about this as\npossible, and do as much calculation as it can when the parameter is\ncreated. If there are no frame dynamic parameters, it will return a\nfixed color. But you can easily use frame-dynamic oscillated\nparameters and get lovely shifting rainbow cues, as shown in the\n<<effects.adoc#oscillator-effects,effect examples>>.\n\n[[movement]]\n== Movement\n\nThere are three different kinds of parameters which tell fixtures how\nto move. They differ in the way that you express direction or aim.\n\n[[direction-parameters]]\n=== Direction Parameters\n\nDirection parameters are one way to tell a group of fixtures to point\nin a particular _direction_, or move in unison or in a coordinated\npattern. They are used with <<effects.adoc#direction-effects,Direction\nEffects>>. (<<pan-tilt-parameters,Pan Tilt Parameters>> and\n<<effects.adoc#pan-tilt-effects,Pan/Tilt Effects>> are the other way to\nachieve that result.) The basic way to create a direction parameter is\nto call\n{api-doc}afterglow.effects.params.html#var-build-direction-param[`afterglow.effects.params/build-direction-param`].\n\n\n[source,clojure]\n----\n(afterglow.effects.params/build-direction-param)\n----\n\nBy itself this call would simply return a non-dynamic direction telling\nfixtures to point directly at the audience. However, you will use one or\nmore of the following optional keyword parameters to get the dynamic\ndirection you want:\n\n[cols=\"2,1,4\",options=\"header\",]\n|=======================================================================\n|Parameter |Default |Purpose\n|`:x` |`0` |The amount the light should point towards audience’s right\n\n|`:y` |`0` |The amount the light should point up\n\n|`:z` |`1` |The amount the light should point towards the audience\n\n|`:frame-dynamic` |`true` |Whether the parameter should be calculated at\nevery frame, or just once\n|=======================================================================\n\nCollectively, `x`, `y`, and `z` specify a three-dimensional vector in\nthe light show’s <<show_space.adoc#,frame of reference>> telling\nthe lights which direction they should point. The absolute magnitudes\nof the values are not important, it is their relative sizes that\nmatter. The default of `[0, 0, 1]` means the lights point neither left\nnor right, neither up nor down, and straight towards the audience.\n`[1, 0, 0]` would be straight right, `[-1, 0, 0]` straight left, `[0,\n1, 0]` straight up, and `[0, 1, -1]` up and away from the audience at\na 45° angle. When this vector is supplied to a\n<<effects.adoc#direction-effects,Direction Effect>>, it causes the attached\nlights to make the specified movement, if they are capable.\n\nAll of these parameters, except for `frame-dynamic`, can themselves be\ndynamic parameters, such as show <<variable-parameters,variables>>\n(with the convenience shorthand of just passing in the keyword by which\nthe show variable was stored) or <<oscillated-parameters,oscillated\nparameters>>.\n\n[[aim-parameters]]\n=== Aim Parameters\n\nAim parameters are a way to tell a group of fixtures to aim at a\nparticular _point_ in space, or track something in unison or in a\ncoordinated pattern. They are used with <<effects.adoc#aim-effects,Aim\nEffects>>. The basic way to create one is to call:\n\n[source,clojure]\n----\n(afterglow.effects.params/build-aim-param)\n----\n\nBy itself this call would simply return a non-dynamic point telling\nfixtures to aim directly at a height of zero, centered on the X axis,\ntwo meters towards the audience. However, you will use one or more of\nthe following optional keyword parameters to get the dynamic target\npoint you want:\n\n[cols=\"2,1,4\",options=\"header\",]\n|=======================================================================\n|Parameter |Default |Purpose\n|`:x` |`0` |How many meters along the X axis the target point is found\n\n|`:y` |`0` |How high up or down the Y axis is the target point\n\n|`:z` |`2` |How far towards or away from the audience is the target\npoint\n\n|`:frame-dynamic` |`true` |Whether the parameter should be calculated at\nevery frame, or just once\n|=======================================================================\n\nCollectively, `x`, `y`, and `z` specify a three-dimensional point\nwithin the light show’s <<show_space.adoc#,frame of reference>> telling the\nlights where to aim. When this vector is supplied to an\n<<effects.adoc#aim-effects,Aim Effect>>, it causes the attached lights to\nmake the specified movement, if they are capable.\n\nIf you need to convert inches or feet to meters, which are the\nstandard distance units in Afterglow, you can use\n{api-doc}afterglow.transform.html#var-inches[`afterglow.transform/inches`]\nand\n{api-doc}afterglow.transform.html#var-feet[`afterglow.transform/feet`].\n\nAll of these parameters, except for `frame-dynamic`, can themselves be\ndynamic parameters, such as show <<variable-parameters,variables>>\n(with the convenience shorthand of just passing in the keyword by which\nthe show variable was stored) or <<oscillated-parameters,oscillated\nparameters>>.\n\n[[pan-tilt-parameters]]\n=== Pan/Tilt Parameters\n\nA more traditional way of aiming fixtures (in contrast to\n<<direction-parameters,Direction Parameters>>) involves\nsetting pan and tilt angles. Afterglow supports this approach as well,\nalthough even in this case you use angles expressed in the standard\nshow <<show_space.adoc#,frame of reference>> regardless of how\nthe individual fixtures are hung. Pan Tilt parameters work with\n<<effects.adoc#pan-tilt-effects,Pan/Tilt Effects>>. The basic way to\ncreate one is to call:\n\n[source,clojure]\n----\n(afterglow.effects.params/build-pan-tilt-param)\n----\n\nBy itself this call would simply return a non-dynamic pan-tilt\nparameter telling fixtures to point directly at the audience. However,\nyou will use one or more of the following optional keyword parameters\nto get the dynamic angles you want:\n\n[cols=\"2,1,5\",options=\"header\",]\n|=======================================================================\n|Parameter |Default |Purpose\n|`:pan` |`0` |How many degrees counter-clockwise should the light turn\naround the Y axis\n\n|`:tilt` |`0` |How many degrees counter-clockwise should the light turn\naround the X axis\n\n|`:radians`|`false` |Supply a `true` value with `:radians` if you\nwould rather work in radians than degrees for your `:pan` and `:tilt`\nvalues.\n\n|`:frame-dynamic` |`true` |Whether the parameter should be calculated at\nevery frame, or just once\n|=======================================================================\n\nThe rotations requested by `pan` and `tilt` jointly identify the\ndirection the light should turn away from the audience. The result of\nthe parameter is a pair of pan and tilt angles away from the `z` axis\nof the light show’s <<show_space#,frame of reference>>\ntelling the lights which direction they should point. When this parameter\nis supplied to a <<effects.adoc#pan-tilt-effects,Pan/Tilt Effect>>, it\ncauses the attached lights to make the specified movement, if they are\ncapable.\n\nNote that although internally Afterglow works with angles expressed in\nradians, the values of `pan` and `tilt` are assumed to be in degrees\nand will be converted to radians for the convenience of users who are\nmore accustomed to working with angles expressed in degrees. If you\nwould rather stick with radians, you can suppress this conversion by\npassing a `true` value with the `:radians` keyword.\n\nAll of these parameters, except for `frame-dynamic`, can themselves be\ndynamic parameters, such as show <<variable-parameters,variables>>\n(with the convenience shorthand of just passing in the keyword by which\nthe show variable was stored) or <<oscillated-parameters,oscillated\nparameters>>.\n\nNOTE: You can also create a direction parameter using pan and tilt\nangles if you want to work with <<effects.adoc#direction-effects,Direction\nEffects>> in those terms. This can be helpful, for example, when you\nwant to fade between a specific direction that is easiest to express\nas a spatial vector, and one that is easiest to express in terms of\nangles. Use\n{api-doc}afterglow.effects.params.html#var-build-direction-param-from-pan-tilt[`build-direction-from-pan-tilt`]\nto create a normal direction parameter starting from the same pan/tilt\nparameters described above.\n\n\n[[spatial-parameters]]\n== Spatial Parameters\n\nSpatial parameters allow you to base an effect parameter on the physical\narrangement or relationships between fixtures in your light show. The\nway to create one is to call\n{api-doc}afterglow.effects.params.html#var-build-spatial-param[`afterglow.effects.params/build-spatial-param`].\n\n[source,clojure]\n----\n(afterglow.effects.params/build-spatial-param fixtures-or-heads f)\n----\n\nThe required parameters are the fixtures and/or heads over which you\nwant this parameter to be calculated, and a function which, when invoked\nwith a fixture or head, returns a number or a dynamic `Number`\nparameter.\n\nIf desired, the results returned for all included heads can be scaled\nto fall within a standard range. Scaling is activated using the\noptional keyword parameters `:max` and `:min`. If neither is supplied,\nscaling is not performed. Passing a value for only `:max` activates\nscaling with a default minimum value of `0`, and passing a value for\nonly `:min` activates scaling with a default maximum value of `255`.\nThe maximum value must be larger than the minimum value.\n\n[cols=\"2,1,6\",options=\"header\",]\n|=======================================================================\n|Parameter |Default |Purpose\n|`:min` | n/a | If present, activates result scaling, and establishes\nthe smallest value this dynamic parameter will hold.\n|`:max` | n/a | If present, activates result scaling, and establishes\nthe largest value this dynamic parameter will hold.\n|`:frame-dynamic` |n/a | Whether the parameter should be calculated at\nevery frame, or just once.\n|=======================================================================\n\nAs noted above, the values returned by `f` can themselves be\ndynamic parameters, such as show <<variable-parameters,variables>>\n(with the convenience shorthand of just passing in the keyword by which\nthe show variable was stored) or <<oscillated-parameters,oscillated\nparameters>>. If `frame-dynamic` is not explicitly set, the spatial\nparameter will be frame dynamic if any value returned by `f` is\nframe-dynamic.\n\nUseful things that `f` can do include calculating the distance of the\nhead from some point, either in 3D or along an axis, its angle from\nsome line, and so on. These can allow the creation of lighting\ngradients across all or part of a show. Spatial parameters make\nexcellent building blocks for <<color-parameters,color>>,\n<<direction-parameters,direction>> and <<aim-parameters,aim>>\nparameters, as shown in the\n<<effects.adoc#spatial-effects,effect examples>>.\n\n[[combining-parameters]]\n== Combining Parameters\n\nSometimes you want to build a cue parameter by combining some other\nvalues using a simple expression. While you can certainly do this by\nimplementing the low-level\n{api-doc}afterglow.effects.params.html#var-IParam[`IParam`] protocol,\nAfterglow provides a helper function,\n{api-doc}afterglow.effects.params.html#var-build-param-formula[`build-param-formula`]\nto eliminate most of the boilerplate involved in that approach. You\ncan see an example of it being used in\n{api-doc}afterglow.examples.html#var-build-ratio-param[`build-ratio-param`]\nin the `examples` namespace, which takes the `beats` and `cycles` cue\nparameters chosen by a user, and divides them to create the ratio that\nan oscillated parameter needs:\n\n[source,clojure]\n----\n(params/build-param-formula Number #(/ %1 %2) beats-param cycles-param)\n----\n\nThe `build-param-formula` function takes the `param-type` of the\nparameter you want to create (in this case a `Number`), a function\n`calc-fn` that will be called to calculate the parameter value when\nneeded (in this case, an anonymous function that simply divides its\nfirst argument by its second), and then the list of other dynamic\nparameters that will be evaluated and fed as input to `calc-fn`. This\nis a very compact way to perform calculations to combine or transform\nother dynamic parameters.\n\nIf you want to perform geometric transformations on\n<<aim-parameters,Aim>> and <<direction-parameters,Direction>>\nparameters, there are some helper functions for that as well.\n{api-doc}afterglow.effects.params.html#var-build-direction-transformer[`build-direction-transformer`]\ntakes an incoming direction parameter and a Java3D\nhttps://docs.oracle.com/cd/E17802_01/j2se/javase/technologies/desktop/java3d/forDevelopers/J3D_1_3_API/j3dapi/javax/media/j3d/Transform3D.html[`Transform3D`]\nobject which will be used to transform it. Both can by dynamic\nparameters, including keywords that will be looked up as show\nvariables. Similarly,\n{api-doc}afterglow.effects.params.html#var-build-aim-transformer[`build-aim-transformer`]\napplies a transformation parameter to an aim parameter.\n\n\n[[debugging-dynamic-parameters]]\n== Debugging Dynamic Parameters\n\nSince dynamic parameters are such a source of flexibility, they can\nget complex quickly, especially when you are driving them from\nexternal systems via MIDI events. Here are a few tips on how you can\ncheck whether the parameter is doing what you expect, and how it is\nfeeding into the effects you are creating with it.\n\n[[checking-variable-parameters]]\n=== Checking Variable Parameters\n\nIf you are using a show variable to hold values as the basis of your\ndynamic parameter, perhaps by\n<<mapping_sync.adoc#mapping-a-control-to-a-variable,mapping>> incoming MIDI\nevents to it, can check the current value of the variable at any time\nlike this:\n\n[source,clojure]\n----\n(show/get-variable :key)\n----\n\nIf you want to be informed more proactively whenever the show variable\nvalue changes, you can register a\n{api-doc}afterglow.show.html#var-add-variable-set-fn.21[watch\nfunction] to be called whenever the variable changes. The following example\nprints the new values of the variable named `:key` each time it is changed.\n\n[source,clojure]\n----\n(show/set-variable! :key 0)\n; nothing special happens\n\n(defn println-on-change\n  \"Prints a variable every time it changes\"\n  [key value]\n  (println key \"set to\" value))\n\n(show/add-variable-set-fn! :key println-on-change)\n(show/set-variable! :key 10)\n; prints \":key set to 10\"\n----\n\n[[evaulating-other-parameters]]\n=== Evaluating Other Parameters\n\nFor all the other kinds of dynamic parameters, there isn't a place\nwhere their value is stored; instead, it is calculated for a\nparticular point in time (and perhaps space). But you can ask the\nparameter to evaluate itself by giving it the proper, context, in the\nsame way Afterglow itself does, using the\n{api-doc}afterglow.effects.params.html#var-evaluate[`evaluate`]\nfunction in the\n{api-doc}afterglow.effects.params.html#var-IParam[`IParam`]\nprotocol. All dynamic parameters implement this protocol. To call\n`evaluate`, you pass in the dynamic parameter, the show in which it is\nrunning, and a metronome snapshot to identify the instant in time you\nwant to ask about. If you are testing a spatial parameter, you will\nalso want pass in the fixture head that you are asking about.\nOtherwise, you can leave that last parameter `nil`.\n\nThe\nhttps://github.com/Deep-Symmetry/graphterglow#graphterglow[graphterglow]\nproject includes a bunch of examples of doing this, and graphing the\nresults. It is how the graphs of oscillators and step parameters in\nthis documentation were created. Its\nhttps://github.com/Deep-Symmetry/graphterglow/blob/master/src/graphterglow/core.clj#L21-L31[build-test-snapshot\nand build-beat snapshot] functions show how to create a snapshot for a\ncertain number of millseconds or beats since the start of the\nmetronome. Using them to evaluate a parameter looks like this:\n\n[source,clojure]\n----\n(afterglow.effects.params/evaluate\n  my-param *show* (build-beat-snapshot (:metronome *show*) 5) nil)\n----\n\nThat would determine the value of the dynamic parameter `my-param` at\nfive beats past the start of the show.\n\nIf you are working on a tricky oscillated or step parameter, or any\nother sort of numeric dynamic parameter, getting it set up for\ngraphing within graphterglow might help you get a visual insight for\nhow it is behaving.\n\n=== Digging Deeper\n\nFor more details, see the\n{api-doc}afterglow.effects.params.html[API\ndocumentation].\n"
  },
  {
    "path": "doc/modules/ROOT/pages/push.adoc",
    "content": "= Using Ableton Push\nJames Elliott <james@deepsymmetry.org>\n\nSome controllers have such rich capabilities that they deserve their\nown custom mapping implementations to exploit their capabilities as a\nshow control interface. The Ableton Push is one, and a powerful\n{api-doc}afterglow.controllers.ableton-push.html[mapping] is being\ncreated. You can already use it to do most of the things that you\nwould use the <<README.adoc#web-ui,web interface>> for, and often with\ndeeper control, since you can press multiple cue trigger pads at the\nsame time, and they respond to variations in pressure.\n\nNOTE: This page describes the mapping for the original Ableton Push.\nThere is also a <<push2.adoc#,Push 2 mapping>>.\n\n[[binding-to-the-push]]\n## Binding to the Push\n\nAssuming you have an Ableton Push connected to the machine running\nAfterglow, Afterglow will find and activate it as soon as you have set\nup the sample show. You will see a brief startup animation, and\nAfterglow's Push interface will start.\n\nTIP: For information about how to set up bindings without the sample\nshow, or more details about how it works, see\n<<mapping_sync.adoc#setting-up-grid-controller-bindings,Setting Up Grid\nController Bindings>>.\n\nHere is an overview of how the Push mapping works:\n\nimage::PushNoEffects.jpg[Push interface,1200,977]\n\n[[show-control]]\n== Show Control\n\nOnce you have the Push linked to a show, it becomes a very direct and\ntactile way to monitor and control the cues and other aspects of the\nshow.\n\nThe text area at the top of the Push displays the effects currently\nrunning, and can optionally display <<metronome-control,metronome>>\ninformation as well. If a cue was defined with adjustable variables\nfor its effect, they will also be displayed in the text area, and you\nwill be able to <<effect-control,adjust>> them by turning the encoder\nabove the variable.\n\nThe rightmost encoder, past the text area, adjusts the show Grand\nMaster, which controls the maximum brightness that any dimmer cue can\nachieve, so you can always use it to adjust the overall brightness of\nthe show. As soon as you touch the encoder, the current Grand Master\nlevel will appear, and be updated as you turn the encoder. When you\nrelease it, the display returns to showing whatever it was before.\n\nimage::GrandMaster.jpg[Grand Master adjustment,638,344]\n\nAs with other numeric values that you can adjust, while you are\nadjusting the Grand Master, the touch strip on the left hand side of\nthe Push will light up in the same proportion as the bar graph in the\ndisplay, and you can touch or drag it to instantly set the value to\nwhatever level you want.\n\nThe red kbd:[Stop] button to the right of the top of the cue grid can be\nused to temporarily shut down the show, blacking out all universes\nthat it controls, and suspending the processing of its effects.\n\nimage::ShowStop.jpg[Show stopped,800,600]\n\nPressing it again restarts the show where it would\nhave been had it not stopped.\n\n[[cues]]\n== Cues\n\nMost of the space on the interface is dedicated to an 8&times;8 grid\nof color coded cue trigger pads, which provide a window onto the\nshow's overall <<cues.adoc#,cue grid>>. The Push can be\n<<README.adoc#scrolling-and-linked-controllers,linked>> to the\n<<README.adoc#web-ui,web interface>> so that both always display the same\nsection of the cue grid, and the web interface can remind you of the\nnames of the cues you are looking at, or it can be scrolled\nindependently, allowing you access to more cues at the same time.\n\nTIP: If you have more than one compatible grid controller, you can\nhave Afterglow using all of them at the same time; each can be\nscrolled to different areas of the cue grid, and each can even be\nlinked to a different browser window if you have that much screen\nspace.\n\nYou can activate any cue shown by pressing its pad; running cues will\nlight up, and darken again when they end. The effects which cues\ncreate will also appear in the text area above the cue pad, from left\nto right, with the most recent effect on the right. In the photo\nbelow, &ldquo;Sparkle&rdquo; is the most recent effect, and it has two\nvariables, `chance` and `Fade`, which can be adjusted by turning the\nencoders above them. The `chance` value is changing rapidly because it\nis configured to also be adjusted through the pressure sensitive cue\npad that was used to launch it.\n\nimage::SparklePressure.jpg[Sparkle effect ajusting chance variable,814,452]\n\nTo stop a running cue, press its pad again, or press the red kbd:[End]\npad underneath its effect entry in the text area. Some cues will end\nimmediately, others will continue to run until they reach what they\nfeel is an appropriate stopping point. While they are in the process\nof ending, the cue pad will blink, and the kbd:[End] pad will be\nlabeled kbd:[Ending]. If you want the cue to end immediately even\nthough it would otherwise run for a while longer, you can press the\nblinking cue pad (or effect kbd:[Ending] pad) again and it will be\nkilled right then.\n\nThe colors assigned to cue pads by the creator of the cue grid are\nintended to help identify related cues. Some cues (especially intense\nones like strobes) are configured to run only as long as they are held\ndown. In that case, when you press cue pad, it lights up with a\nwhitened version of the cue color as a hint that this is happening,\nand as soon as you release the pad, the cue will end. If you want to\noverride this behavior, you can hold down the kbd:[Shift] button\n(towards the bottom right of the Push) as you press the cue pad, and\nit will activate as a normal cue, staying on until you press it a\nsecond time.\n\nAs noted above, cues can also be configured to take advantage of the\npressure sensitivity of the Push cue pads, so that as you vary the\npressure with which you are holding down the pad, some visible\nvariable of the cue is altered. The strobe and sparkle cues in\ncreated by\n{api-doc}afterglow.examples.html#var-make-cues[`afterglow.examples/make-cues`]\nfor the sample show work this way: the intensity and lightness of the\nstrobe are increased by pressure, and so is the chance that a sparkle\nwill be assigned to a light on each frame. You can see these\nvariables change in the text area above the cue's effect name while\nyou are adjusting them, as shown in the photo above.\n\n[[exclusivity]]Cues may be mutually exclusive by nature, and if they\nwere created to reflect this (by using the same keyword to register\ntheir effects with the show, or specifying other effect keys in their\n`:end-keys` list), when you activate one, the other cues which use the\nsame keyword are dimmed. This is a hint that when you activate one of\nthem, it will _replace_ the others, rather than running at the same\ntime. In the photo <<gobo-photo,below>>, the rest of the\nTorrent 1 fixed gobo cues (the leftmost blue cues) are dimmed because\nthey would replace the running &ldquo;T1 atom shake&rdquo; cue.\n\n[[scrolling]]\n== Scrolling\n\nThe show will likely have many more cues than fit on the pad grid; the\ndiamond of arrow buttons at the bottom right allow you to page through\nthe larger show grid. If there are more cues available in a given\ndirection, that arrow will be lit, otherwise it is dark. Pressing an\nactive arrow scrolls the view one &ldquo;page&rdquo; in that\ndirection. In the photo below, it is currently possible to scroll up\nand to the right:\n\nimage::PushScroll.jpg[Push scroll diamond,300,337]\n\nIf you hold down the kbd:[Shift] button, the arrows gain a different\npurpose, allowing you to scroll the text display left and right, to\nsee and <<effect-control,adjust>> all of the currently\nrunning effects, even though only four at a time (or three, if the\n<<metronome-control,metronome section>> is showing) fit\nin the display. Pressing the left or right arrows scrolls the next\ngroup of effects in that direction into view; pressing the up arrow\nscrolls to the oldest (leftmost) effect, and pressing the down arrow\nscrolls to the most recent (rightmost) effect. While kbd:[Shift] is\npressed, the arrows will light up according to whether they can scroll\neffects rather than cues in the corresponding direction.\n\n[[effect-control]]\n== Effect Control\n\nAs described above, the effects created by cues appear in the text\ndisplay area, and can be scrolled through and ended by pressing the\ncorresponding red kbd:[End] pad which appears underneath them.\n\n[[numeric-cue-variables]]\n=== Numeric Cue Variables\n\nIf the cue that created an effect has numeric variables assigned to\nit, the variable names and values will appear above the effect name,\nand they can be adjusted using the encoder knob above the variable.\nFor example, in addition to varying the sparkle `chance` variable\nusing the pad pressure, as was done above, its `Fade` variable can be\nadjusted using the effect variable encoder above it. As soon as you\ntouch the encoder knob associated with a variable, a graphical\nrepresentation of the current value replaces its name, and updates as\nyou turn the encoder to change the value.\n\nimage::AdjustingFade.jpg[Adjusting Fade variable,800,673]\n\nWhile you are adjusting the variable, the large touch strip on the\nleft hand side of the Push lights up to show you where you are in the\nvariable range, and you can touch and drag on the strip to instantly\nset the variable to another value. Most numeric variables will have\nvalues that grow from the bottom of the touch strip, but variables\nmarked as `:centered`, like Pan and Tilt variables, grow from the\ncenter up or down.\n\nIf an effect has only one adjustable variable, it will take up the\nentire effect area, and you can use either encoder to adjust it, as\nwhen adjusting a Focus <<cues.adoc#creating-function-cues,function cue>>\nfor the Torrent moving head spot:\n\nimage::AdjustingFocus.jpg[Adjusting Focus cue,1000,922]\n\nWhen you release the encoder knob, the adjustment graph disappears,\nand the variable name reappears.\n\nThe <- indicator at the left of the text area in the above photo is an\nindicator that there are older effects which have been scrolled to the\nleft, off the display. You will see -> at the bottom right of the\ndisplay when there are newer effects to the right. You can scroll to\nthem using the kbd:[Shift] button with the scroll arrow buttons as\ndescribed <<scrolling,above>>.\n\nThis photo also illustrates the dimming of incompatible cues discussed\n<<exclusivity,above>>: The leftmost columns of blue cues\nall establish settings for the fixed gobo wheel of one of the Torrent\nmoving-head spots. Since one of them is active (the `T1 atom\nshake` effect at the left of the text area corresponds to the\nbright blue button three rows down the second column), the others are\ndimmed to hint that pressing them would replace the active cue.\n\nThis dimming can also be seen in the web interface view of the cue grid:\n\n[[gobo-photo]]\nimage::GoboCues.png[Gobo cues,1100,769]\n\n[[boolean-cue-variables]]\n=== Boolean Cue Variables\n\nIf a cue has Boolean variables assigned to it, they will also appear\nabove the effect name, with the current value showing as `Yes` or\n`No`. To adjust them you also start by grabbing the closest encoder,\nat which point you will see the two options with an arrow pointing at\nthe currently-chosen one. Rotate the encoder towards the option you\nwant to choose and the variable will be updated:\n\nimage::AdjustingDown.jpg[Adjusting a Down? cue variable,600,494]\n\nWhen you release the encoder knob, the choices disappear and the\nvariable name reappears.\n\nYou can also use the touch strip when setting a Boolean variable;\ntouching the top half sets it to `Yes`, while the bottom half sets it to\n`No`.\n\n[[color-cue-variables]]\n=== Color Cue Variables\n\nIf a cue has color variables assigned to it, they will also appear\nabove the effect name. The currently assigned color value will be\ndisplayed as a six digit hexadecimal number, representing the eight\nbit red, green, and blue representation of the color value, #rrggbb.\nIn this photo, a cue with a color variable that starts out white has\njust been launched:\n\nimage::ColorParam.jpg[Cue with color variable,1000,785]\n\nWhen an effect is displaying a color cue variable, touching the\nassociated encoder will open up a special color selection interface,\nwhich takes over the entire cue grid, as well as the effect cell:\n\nimage::ColorPalette.jpg[Color adjustment palette,1000,750]\n\nIn addition to adjusting the color's hue and saturation using the\nencoders above the effect, you can instantly jump to a color by\ntapping any of the pads in the grid, which form a palette of four\nsaturation levels of hues spread across the rainbow. The four pads on\nthe bottom right let you select white, medium gray, and black as color\nvalues as well, and the last pad displays a preview of the currently\nselected color, rather than doing anything when you press it.\n\nIf any pad other than the preview pad matches the currently selected\ncolor, it blinks (regardless of whether you chose that color by\npressing the pad or by turning the encoders).\n\nWhile you are holding the hue or saturation encoder, you can also use\nthe touch strip to see and jump to any value in that encoder's range.\nIf both encoders are being held, the touch pad allows you to select\nsaturations, since the touch pads already give you an easy interface\nfor selecting hues.\n\nAs soon as you let go of both the hue and saturation encoders, the\npalette disappears and the normal cue grid returns.\n\n[[scrolling-through-cue-variables]]\n=== Scrolling Through Cue Variables\n\nIf a cue has more than two variables, even though you can only see two\nat a time on the Push, you can still check and adjust all of them.\nWhenever there are too many to fit, the rightmost pad just below the\neffect display will be lit with an amber color and labeled kbd:[More\n->] as shown below:\n\nimage::MoreVars.jpg[More than Two Cue Variables,800,562]\n\nEach time you press the kbd:[More ->] button, you will see the next\ntwo variables assigned to the cue. Once you reach the end of the list,\nit wraps back to the beginning. Grabbing an encoder above the\nvariables will adjust whichever variable is currently displayed\nbeneath it. (While you are holding encoders to adjust an effect's\nvariables, its kbd:[More ->] button will be blacked out and disabled.)\n\n[[saving-cues]]\n== Saving Cues\n\nIf you have made any adjustments to cue variable values, these are\nnormally discarded when you end the cue; the next time it begins, it\nstarts with the values that were configured in the show. You can\nchange that by saving the cue's variables. To begin, hold down the\nkbd:[&#9711;] button near the bottom left of the Push:\n\nimage::Saving1.jpg[Saving Cue Variables,1000,761]\n\nWhile this button is held down, the red kbd:[End] buttons beneath the\neffect list disappear, and are replaced with the cue saving interface.\nIf you have made any adjustments to a cue's variables since it was\nstarted, a green kbd:[Save] button will appear (like the one beneath\nthe `Color all` effect in the photo above). Pressing that will save\nthe adjustments you made, so the next time you launch the cue, the\nadjusted values will be used.\n\nWhen you save a color cue that is configured like the ones in the\nsample show, the color of the cue's pad in the cue grid is updated to\nreflect the new color you have chosen. (Its color in the the web\ninterface cue grid is updated as well).\n\nOnce you have saved a cue's variables, while it is running, instead of\na green kbd:[Save] button, you will see an amber kbd:[Clear] button\n(like the one beneath the `Torrent Sine` effect in the photo).\nPressing that will remove the saved values, so the cue goes back to\nits original configuration.\n\nIf you save a cue's variables, and then adjust them further, the\nkbd:[Save] button returns, allowing you to save your new values. If\nyou don't, the values you saved earlier will be used the next time you\nstart the cue.\n\nIf a cue's variables have neither been saved nor adjusted, no\nkbd:[Save] or kbd:[Update] button appears (like for the `Blade\nTriangle` effect in the photo). Of course, while saving cues, you can\nstill scroll though their variables using the kbd:[More ->]\nbuttons.\n\nOnce you release the kbd:[&#9711;] button, the save interface goes\naway, and the effect kbd:[End] buttons return.\n\n[[metronome-control]]\n== Metronome Control\n\nThe top left section of the Push lets you view and adjust the\nMetronome that the show is using to keep time with the music that is\nbeing played. Since Afterglow's effects are generally defined with\nrespect to the metronome, it is important to keep it synchronized with\nthe music. When active, the metronome section takes over the leftmost\nquarter of the text area (so there are room to see only three effects,\nrather than the normal four). To toggle the metronome section, press\nthe kbd:[Metronome] button. It will appear if it was not showing, and\ndisappear if it was there. The kbd:[Metronome] button is lit more\nbrightly when the section is active.\n\nThe metronome section shows the current speed, in Beats Per Minute, of\nthe metronome, and the kbd:[Tap Tempo] button label flashes at each beat\n(this flashing happens regardless of whether the metronome section is\nvisible in the text area). The metronome section also shows you the\ncurrent phrase number, the bar within that phrase, and the beat within\nthat bar which has been reached.\n\nimage::PushMetronome.jpg[Metronome section,600,559]\n\nThe most basic way of synchronizing the metronome is to tap the\nkbd:[Tap Tempo] button at each beat of the music. Tapping the button\naligns the metronome to a beat, and if you tap it three or more times\nwithin two seconds of each preceding tap, sets the metronome's BPM.\nTap it as you hear each beat of the music, and after three or more\ntaps, the speed of the metronome will be approximately synchronized\nwith the music.\n\nOnce the tempo is correct, you can tell Afterglow which beat is the\ndown beat by holding down the kbd:[Shift] button while pressing\nkbd:[Tap Tempo]. This combination does not change the tempo, but tells\nAfterglow that the moment when you tapped the button is the down beat\n(the first beat of a bar).\n\nYou can also adjust the BPM by turning the BPM encoder, which is the\nrightmost encoder below the Metronome button:\n\nimage::PushBPM.jpg[BPM encoder,600,450]\n\nWhile you are holding this encoder, the symbol `&uparrow;` appears below\nthe BPM value as a visual reminder of what value you are adjusting.\nTurning the encoder clockwise raises the BPM, turning counterclockwise\nlowers it. While the metronome section is showing, you can also use\nthe encoder above the BPM value to adjust it. But you can grab the\ndedicated BPM encoder below the kbd:[Metronome] button even when the\nmetronome section is not showing, and it will appear while you have\nthe encoder in your hand, so you can adjust the BPM quickly, and then\nget back to what you were doing.\n\nIf you press the kbd:[Shift] button, the BPM encoder can be used to\nadjust the BPM by whole beats rather than tenths. While kbd:[Shift] is\ndown, the `&uparrow;` will point to the left of the decimal point\nrather than to the right of it, and the BPM will change ten times as\nquickly as you turn it. You can switch back and forth in the middle of\nyour adjustments by pressing and releasing the shift key at any time.\n\nIn order to make longer chases and effects line up properly with the\nmusic, you will also want to make sure the count is right, that the\nbeat number shows `1` on the down beat, and that the bar numbers are\nright as well, so that the start of a phrase is reflected as bar\nnumber `1`. In addition to using kbd:[Shift] with kbd:[Tap Tempo] to\nset the down beat, you can adjust the current beat number using the\nbeat encoder, the leftmost encoder below the metronome button:\n\nimage::PushBeat.jpg[Beat encoder,600,474]\n\nWhile you are holding this encoder, the symbol `&uparrow;` appears\nbelow the beat number as a visual reminder of what value you are\nadjusting. Turning the encoder clockwise jumps to the next beat,\nturning counterclockwise jumps back to the previous one. As a tactile\nreminder that you are adjusting whole beats, this encoder moves with a\ndistinct click as it changes value, while the BPM encoder turns\nsmoothly as you scroll through fractional BPM values.\n\nWhile the metronome section is showing, you can also use the encoder\nabove the Beat value to adjust it. But you can grab the dedicated Beat\nencoder below the kbd:[Metronome] button even when the metronome\nsection is not showing, and it will appear while you have the encoder\nin your hand, so you can adjust the beat number quickly, and then get\nback to what you were doing.\n\nIf you press the kbd:[Shift] button, the Beat encoder can be used to\nadjust the current bar within the phrase instead of the current beat.\nWhile kbd:[Shift] is down, the `&uparrow;` will point at the bar\ninstead of the beat, and turning the encoder will jump that value\nforwards or backwards:\n\nimage::PushBar.jpg[Bar jumping,600,475]\n\nIf you know a phrase is about to begin, you can press the red Reset\npad in the metronome section right as it does. This will reset the\ncount to Phrase 1, Bar 1, Beat 1.\n\nTrying to keep up with tempo changes during dynamic shows can be\ntedious, so you will hopefully be able to take advantage of\nAfterglow's metronome synchronization features. If the DJ can send you\n<<mapping_sync.adoc#syncing-to-midi-clock,MIDI clock pulses>>, or you can\nconnect via a Local Area Network to Pioneer professional DJ gear to\nlock into the beat grid established by\n<<mapping_sync.adoc#syncing-to-pro-dj-link,Pro DJ Link>>, Afterglow can\nkeep the BPM (with MIDI) and even the beats (with Pro DJ Link and the\nTraktor Afterglow Beat Phase\n<<mapping_sync.adoc#syncing-to-traktor-beat-phase,controller mapping>>)\nsynchronized for you. The Sync pad in the Metronome section (showing\n`Manual` sync in these photos) will eventually allow you to set this\nup, but that is not yet implemented, so for now you will need to use\nthe <<README.adoc#metronome-control,web interface>> to configure it.\n\nNOTE: The pad does already change color to let you know the sync\nstatus: amber means manual, green means successful automatic sync, and\nred means a requested automatic sync has failed. It is likely that a\nfuture release of Afterglow will let you press this pad to choose your\nsync source.\n\nOnce your sync is established, the meaning of the kbd:[Tap Tempo]\nbutton changes. If you are using MIDI clock to sync the BPM, it\nbecomes a kbd:[Tap Beat] button, which simply establishes where the\nbeat falls. If you are locked in to a Pro DJ Link beat grid or using\nthe Traktor beat phase mapping, the beats are automatically aligned\nfor you so, it becomes a kbd:[Tap Bar] button which, when pressed,\nindicates that the current beat is the down beat (start) of a bar.\n(Similarly, if you press the metronome kbd:[Reset] pad while synced to\na Pro DJ Link beat grid or Traktor beat phase, the beat itself will\nnot move, but the beat closest to when you pressed the pad will be\nidentified as Beat 1.) In these sync modes you can also use the\nkbd:[Shift] button to align at the next bigger boundary: If tapping\nwould normally move the bar, shift-tapping will move the phrase.\n\nIf you try to adjust the BPM encoder while sync is active, it will\nhave no effect, and Afterglow will point at the sync mode to explain\nwhy it is ignoring your adjustments.\n\n[[sharing-the-push]]\n== Sharing the Push\n\nIf you are using Afterglow at the same time as Ableton Live, you can\nswitch back and forth between which has control of the Push by\npressing the kbd:[User] button. If Live is not running when you press\nkbd:[User], the Push interface will simply go blank (except for the\nkbd:[User] button itself), until you press it again, at which point\nAfterglow will light it up.\n\nNOTE: Future releases may take advantage of more of the buttons on the\ncontroller.\n"
  },
  {
    "path": "doc/modules/ROOT/pages/push2.adoc",
    "content": "= Using Ableton Push 2\nJames Elliott <james@deepsymmetry.org>\n\nSome controllers have such rich capabilities that they deserve their\nown custom mapping implementations to exploit their capabilities as a\nshow control interface. The Push 2 called out for such treatment, and\nthankfully in March 2016 Ableton published\nhttps://github.com/Ableton/push-interface/blob/master/doc/AbletonPush2MIDIDisplayInterface.asc[documentation]\nwhich made that possible, and a\n{api-doc}afterglow.controllers.ableton-push-2.html[mapping] has been\ncreated. You can use it to do most of the things that you would use\nthe <<README.adoc#web-ui,web interface>> for, often with deeper control,\nsince you can press multiple cue trigger pads at the same time, and\nthey respond to variations in pressure.\n\nNOTE: Although this page discusses the second version of the Push\ncontroller, with a graphical display, there is also a page describing\nthe <<push.adoc#,original Push mapping>>, which is still\nfully supported.\n\n[[binding-to-the-push-2]]\n## Binding to the Push 2\n\nAssuming you have an Ableton Push 2 connected to the machine running\nAfterglow and powered on, it will be noticed, identified, and\nactivated as soon as you have set up the sample show. You will see a\nbrief startup animation, and Afterglow's Push 2 interface will appear.\n\nTIP: For information about how to set up bindings without the sample\nshow, or more details about how it works, see\n<<mapping_sync.adoc#setting-up-grid-controller-bindings,Setting Up Grid\nController Bindings>>.\n\nHere is an overview of how the Push 2 mapping works, with details\nexplained in the upcoming sections:\n\nimage::Push2NoEffects.jpg[Push 2 interface,1200,977]\n\nThe most exciting innovation that the Push 2 adds to the already\nexcellent Push experience is the color graphic display, and Afterglow\ncan take full advantage of it, as this example shows:\n\nimage::Example.gif[Afterglow graphic animation,960,160]\n\n[[show-control]]\n== Show Control\n\nOnce you have the Push 2 bound to a show, it becomes a very direct and\ntactile way to monitor and control the cues and other aspects of the\nshow.\n\nThe graphical display at the top of the Push displays the effects\ncurrently running, and can optionally display\n<<metronome-control,metronome>> information as well. If a cue was\ndefined with adjustable variables for its effect, they will also be\ndisplayed, and you will be able to <<effect-control,adjust>> them by\nturning the encoder above the variable.\n\nThe rightmost encoder, past the display, adjusts the show Grand\nMaster, which controls the maximum brightness that any dimmer cue can\nachieve, so you can always use it to adjust the overall brightness of\nthe show. As soon as you touch the encoder, the Grand Master level\nwill appear along with a gauge representing what fraction of its\nmaximum level is currently in effect, and both will be updated as you\nturn the encoder. When you release it, the display returns to showing\nwhatever it was before.\n\nimage::GrandMaster2.jpg[Grand Master adjustment,1200,978]\n\nAs with other numeric values that you can adjust, while you are\nadjusting the Grand Master, the touch strip on the left hand side of\nthe Push will light up in the same proportion as the circular gauge\nin the display under the encoder, and you can touch or drag on the\nstrip to instantly set the level to whatever value you want.\n\nThe red kbd:[&#9655;] button to the at the bottom left of the cue grid\ncan be used to temporarily shut down the show, blacking out all\nuniverses that it controls, and suspending the processing of its\neffects.\n\nimage::ShowStop2.jpg[Show stopped,1000,1008]\n\nWhenever the show is stopped, the kbd:[&#9655;] button turns green to\nrepresent “Play”. Pressing it in this state restarts the show where it\nwould have been had it not stopped.\n\n[[cues]]\n== Cues\n\nMost of the space on the interface is dedicated to an 8&times;8 grid\nof color coded cue trigger pads, which provide a window onto the\nshow's overall <<cues.adoc#,cue grid>>. The Push 2 can be\n<<README.adoc#scrolling-and-linked-controllers,linked>> to the\n<<README.adoc#web-ui,web interface>> so that both always display the same\nsection of the cue grid, and the web interface can remind you of the\nnames of the cues you are looking at, or it can be scrolled\nindependently, allowing you access to more cues at the same time.\n\nTIP: If you have more than one compatible grid controller, you can\nhave Afterglow using all of them at the same time; each can be\nscrolled to different areas of the cue grid, and each can even be\nlinked to a different browser window if you have that much screen\nspace.\n\nYou can activate any cue shown by pressing its pad; running cues will\nlight up, and darken again when they end. The effects which cues\ncreate will also appear in the display above the cue pad, from left to\nright, with the most recent effect on the right. The labels containing\nthe effect name are drawn in the same color as the cue pad used to\nlaunch the effect, to help keep track of which is which. In the photo\nbelow, &ldquo;Sparkle&rdquo; is the most recent effect, and it has two\nvariables, `chance` and `Fade`, which can be adjusted by turning the\nencoders above them. The `chance` value is changing because it is\nconfigured to also be adjusted through the pressure sensitive cue pad\nthat was used to launch it.\n\nimage::SparklePressure2.jpg[Sparkle effect adjusting chance variable,600,624]\n\nTo stop a running cue, press its pad again, or press the red kbd:[End]\npad underneath its effect entry in the display. Some cues will end\nimmediately, others will continue to run until they reach what they\nfeel is an appropriate stopping point. While they are in the process\nof ending, the cue pad will blink, and the kbd:[End] pad will be\nlabeled kbd:[Ending]. If you want the cue to end immediately even\nthough it would otherwise run for a while longer, you can press the\nblinking cue pad (or effect kbd:[Ending] pad) again and it will be\nkilled right then.\n\nThe colors assigned to cue pads by the creator of the cue grid are\nintended to help identify related cues. The same color is used in the\ncue label at the bottom of the graphical display, to help keep track\nof which cue came from where.\n\nSome cues (especially intense ones like strobes) are configured to run\nonly as long as they are held down. In that case, when you press cue\npad, it lights up with a whitened version of the cue color as a hint\nthat this is happening, and as soon as you release the pad, the cue\nwill end. If you want to override this behavior, you can hold down the\nkbd:[Shift] button (towards the bottom right of the Push) as you press\nthe cue pad, and it will activate as a normal cue, staying on until\nyou press its pad a second time.\n\nAs noted above, cues can also be configured to take advantage of the\npressure sensitivity of the Push cue pads, so that as you vary the\npressure with which you are holding down the pad, some visible\nvariable of the cue is altered. The strobe and sparkle cues in\ncreated by\n{api-doc}afterglow.examples.html#var-make-cues[`afterglow.examples/make-cues`]\nfor the sample show work this way: the intensity and lightness of the\nstrobe are increased by pressure, and so is the chance that a sparkle\nwill be assigned to a light on each frame. You can see these\nvariables change in the display above the cue's effect name while\nyou are adjusting them, as shown in the photo above.\n\n[[exclusivity]]Cues may be mutually exclusive by nature, and if they\nwere created to reflect this (by using the same keyword to register\ntheir effects with the show, or specifying other effect keys in their\n`:end-keys` list), when you activate one, the other cues which use the\nsame keyword are dimmed. This is a hint that when you activate one of\nthem, it will _replace_ the others, rather than running at the same\ntime. In the photo <<gobo-photo,below>>, the rest of the\nTorrent 1 fixed gobo cues (the leftmost blue cues) are dimmed because\nthey would replace the running &ldquo;T1 atom shake&rdquo; cue.\n\n[[scrolling]]\n== Scrolling\n\nThe show will likely have many more cues than fit on the pad grid; the\ndiamond of arrow buttons to the right of the top of the cue grid allow\nyou to page through the larger show grid. If there are more cues\navailable in a given direction, that arrow will be lit, otherwise it\nis dark. Pressing an active arrow scrolls the view one\n&ldquo;page&rdquo; in that direction. In the photo below, it is\ncurrently possible to scroll up and to the right:\n\nimage::PushScroll2.jpg[Push 2 scroll diamond,286,244]\n\nIf you hold down the kbd:[Shift] button, the arrows will scroll you as\nfar as possible in the direction that you press.\n\nThe kbd:[Page <] and kbd:[> Page] buttons (toward the bottom right,\njust above kbd:[Shift]) allow you to scroll the graphical display left\nand right, to see and <<effect-control,adjust>> all of the currently\nrunning effects, even though only four at a time (or three, if the\n<<metronome-control,metronome section>> is showing) fit in the\ndisplay.\n\nPressing the kbd:[Page <] scrolls the display left, showing you older\n(or lower priority) effects, and kbd:[> Page] scrolls to the right,\nshowing you newer and higher priority effects. Pressing these buttons\nwhile kbd:[Shift] is held will scroll as far as possible in the\ncorresponding direction. (As illustrated in the photo below, in\naddition to lighting up the kbd:[Page <] and kbd:[> Page] buttons when\nthere are effects off the screen in that direction, Afterglow draws\n`<` and `>` markers below the effect name labels at the corresponding\nedge of the screen.)\n\nimage::Push2Page.jpg[Push 2 page arrows,1000,832]\n\n[[effect-control]]\n== Effect Control\n\nEffects, whether created by cues or other code, appear in the display\narea, and can be scrolled through and ended by pressing the\ncorresponding red kbd:[End] pad which appears underneath them. There\nare many ways you can interact with running effects:\n\n[[numeric-cue-variables]]\n=== Numeric Cue Variables\n\nIf the effect was created by a cue that has numeric variables assigned\nto it, the variable names and values will appear above the effect\nname. The values can be adjusted using the encoder knob above the\nvariable. For example, in addition to varying the sparkle `chance`\nvariable using the pad pressure, as was done above, its `Fade`\nvariable can be adjusted using the effect variable encoder above it.\nAs soon as you touch the encoder knob associated with a variable, the\ngauge underneath its value brightens to indicate that you are\nadjusting it, and updates as you turn the encoder to change the value.\nIn the photo below, the `Confetti Dance` cue's `Min Last` variable is\nbeing adjusted.\n\nimage::AdjustingConfetti.jpg[Adjusting Min Last variable,693,566]\n\nAnd here is how the effect's display section updates while the value\nis being adjusted:\n\nimage::min-last.gif[Adjusting Min Last Animation,240,160]\n\nWhile you are adjusting the variable, the large touch strip on the\nleft hand side of the Push lights up to show you where you are in the\nvariable range, and you can touch and drag on the strip to instantly\nset the variable to another value.\n\nimage::AdjustingConfetti2.jpg[Adjusting and touch strip,800,646]\n\nMost numeric variables will have values that grow from the bottom of\nthe touch strip, but variables marked as `:centered` when created,\nlike Pan and Tilt, grow from the center up or down. (Their graphical\ngauges grow from the center as well.)\n\nimage::AdjustingCentered2.jpg[Adjusting centered cue variables,800,807]\n\nimage::pan-tilt.gif[Adjusting centered variable animation,241,160]\n\nIf an effect has only one adjustable variable, it will take up the\nentire effect area, and you can use either encoder to adjust it, as\nwhen adjusting a gobo shaking <<cues.adoc#creating-function-cues,function\ncue>> for the Torrent moving head spot:\n\nimage::AdjustingShake.jpg[Adjusting gobo shake cue,800,926]\n\nWhen you release the encoder knob, the adjustment graph returns to its\nnormal brightness, and the touch strip deactivates.\n\nThis photo also illustrates the dimming of incompatible cues discussed\n<<exclusivity,above>>: The leftmost columns of blue cues all establish\nsettings for the fixed gobo wheel of one of the Torrent moving-head\nspots. Since one of them is active (the `T1 atom shake` effect being\nadjusted corresponds to the bright blue button three rows down the\nsecond column), the others are dimmed to hint that pressing them would\nreplace the active cue.\n\nThis dimming can also be seen in the web interface view of the cue grid:\n\n[[gobo-photo]]\nimage::GoboCues.png[Gobo cues,1100,769]\n\n[[boolean-cue-variables]]\n=== Boolean Cue Variables\n\nIf a cue has Boolean variables assigned to it, they will also appear\nabove the effect name, with the current value showing as `Yes` or\n`No`. To adjust them you also start by grabbing the closest encoder.\nWith a Boolean value, the adjustment graph is always half full, and\nyou rotate it to the left for No, or right for Yes:\n\nimage::AdjustingDown2.jpg[Adjusting a Down? cue variable,700,475]\n\nNOTE: The `Blade Saw` cue in the photo is also an example of a cue\nthat defines a custom visualization. Underneath its variable gauges,\nit draws an animated view of the previous and upcoming measure of\ntime, with down beats marked in red as they are in the Metronome\nsection. The visualization is a strip chart showing the dimmer level\nthat the cue will establish at each point in time. As you adjust the\ncue variables, the visualization instantly updates to reflect your\nchanges, helping you understand how they affect it.\n\nimage::blade-saw.gif[Cue visualization animation,240,160]\n\nYou can also use the touch strip when setting a Boolean variable;\ntouching the top half sets it to `Yes`, while the bottom half sets it to\n`No`.\n\nimage::AdjustingDown2Strip.jpg[Adjusting a Down? cue with the touch strip visible,800,748]\n\nNOTE: The `Rainbow Pulse` cue to the left of the one being adjusted is\nan example of a cue with no variables to adjust.\n\n[[color-cue-variables]]\n=== Color Cue Variables\n\nIf a cue has color variables assigned to it, they will also appear\nabove the effect name. The currently assigned color value will be\ndisplayed as swatch and a six digit hexadecimal number, representing\nthe eight bit red, green, and blue representation of the color value,\n#rrggbb. In this photo, a `Color all` cue with a color variable that\nstarts out white has just been launched:\n\nimage::ColorParam2.jpg[Cue with color variable,1200,941]\n\nWhen an effect is displaying a color cue variable, the gauges beneath\nit represent hue and saturation values. (If the cue has only one\nvariable, both of these will always be visible. Otherwise, only the\none underneath the variable's encoder will be visible until you start\nadjusting that variable, at which point the other color gauge will\nappear.)\n\nTouching the associated encoder will open up a special color selection\ninterface, which takes over the entire cue grid, as well as the effect\ncell:\n\nimage::ColorPalette2.jpg[Color adjustment palette,1000,891]\n\nIn addition to adjusting the color's hue and saturation using the\nencoders above the effect, you can instantly jump to a color by\ntapping any of the pads in the grid, which form a palette of four\nsaturation levels of hues spread across the rainbow. The four pads on\nthe bottom right let you select white, medium gray, and black as color\nvalues as well, and the last pad displays a preview of the currently\nselected color, rather than doing anything when you press it.\n\nIf any pad other than the preview pad matches the currently selected\ncolor, it blinks (regardless of whether you chose that color by\npressing the pad or by turning the encoders).\n\nWhile you are holding the hue or saturation encoder, you can also use\nthe touch strip to see and jump to any value in that encoder's range.\nIf both encoders are being held, the touch pad allows you to select\nsaturations, since the touch pads already give you an easy interface\nfor selecting hues.\n\nimage::color-all.gif[Color selection animation,240,160]\n\nAs soon as you let go of both the hue and saturation encoders, the\npalette disappears and the normal cue grid returns.\n\n[[scrolling-through-cue-variables]]\n=== Scrolling Through Cue Variables\n\nIf a cue has more than two variables, even though you can only see two\nat a time on the Push, you can still check and adjust all of them.\nWhenever there are too many to fit, the rightmost pad just below the\neffect display will be lit white and labeled kbd:[Next Vars >] as shown below:\n\nimage::MoreVars2.jpg[More than Two Cue Variables,600,389]\n\nIn the photo, the `Torrent Sine` and `Blade Triangle` cues have more\nvariables than are being displayed, while the `Color all` cue does\nnot.\n\nEach time you press a kbd:[Next Vars >] button, you will see the next\ntwo variables assigned to the cue. Once you reach the end of the list,\nit wraps back to the beginning. Grabbing an encoder above the\nvariables will adjust whichever variable is currently displayed\nbeneath it. (While you are holding encoders to adjust an effect's\nvariables, its kbd:[Next Vars >] button will be blacked out and\ndisabled.)\n\n[[saving-cues]]\n=== Saving Cues\n\nIf you have made any adjustments to cue variable values, these are\nnormally discarded when you end the cue; the next time it begins, it\nstarts with the values that were configured in the show. You can\nchange that by saving the cue's variables. To begin, hold down the\nkbd:[&#9711;] button near the bottom left of the Push 2:\n\nimage::Saving2.jpg[Saving Cue Variables,1000,821]\n\nWhile this button is held down, the red kbd:[End] buttons beneath the\neffect list disappear, and are replaced with the cue saving interface.\nIf you have made any adjustments to a cue's variables since it was\nstarted, a green kbd:[Save] button will appear (like the one beneath\nthe `Color all` effect in the photo above). Pressing that will save\nthe adjustments you made, so the next time you launch the cue, the\nadjusted values will be used.\n\nWhen you save a color cue that is configured like the ones in the\nsample show, the color of the cue's pad in the cue grid is updated to\nreflect the new color you have chosen. (Its color in the the web\ninterface cue grid is updated as well).\n\nOnce you have saved a cue's variables, while it is running, instead of\na green kbd:[Save] button, you will see an amber kbd:[Clear] button\n(like the one beneath the `Torrent Sine` effect in the photo).\nPressing that will remove the saved values, so the cue goes back to\nits original configuration.\n\nIf you save a cue's variables, and then adjust them further, the\nkbd:[Save] button returns, allowing you to save your new values. If\nyou don't, the values you saved earlier will be used the next time you\nstart the cue.\n\nIf a cue's variables have neither been saved nor adjusted, no\nkbd:[Save] or kbd:[Update] button appears (like for the `Blade\nTriangle` effect in the photo). Of course, while saving cues, you can\nstill scroll though their variables using the kbd:[Next Vars >]\nbuttons.\n\nOnce you release the kbd:[&#9711;] button, the save interface goes\naway, and the effect kbd:[End] buttons return.\n\nimage::save-clear.gif[Save interface animation,960,160]\n\n[[metronome-control]]\n== Metronome Control\n\nThe top left section of the Push lets you view and adjust the\nMetronome that the show is using to keep time with the music that is\nbeing played. Since Afterglow's effects are generally defined with\nrespect to the metronome, it is important to keep it synchronized with\nthe music. When active, the metronome section takes over the leftmost\nquarter of the graphical display (so there are room to see only three\neffects, rather than the normal four). To toggle the metronome\nsection, press the kbd:[Metronome] button. It will appear if it was\nnot showing, and disappear if it was there. The kbd:[Metronome] button\nis lit more brightly when the section is active.\n\nThe metronome section shows the current speed, in Beats Per Minute, of\nthe metronome, and the kbd:[Tap Tempo] button label flashes at each beat\n(this flashing happens regardless of whether the metronome section is\nvisible in the text area). The metronome section also shows you the\ncurrent phrase number, the bar within that phrase, and the beat within\nthat bar which has been reached.\n\nimage::Metronome2.png[Metronome section,414,302]\n\nFinally, below the beat and BPM displays, there is a visualization of\nthe passing beats, bars, and phrases. The beats are drawn in white,\nwith their phase increasing until the next beat hits. In a layer\nbeneath them, the measures (bars) are drawn in red, and beneath those,\nthe phrases in blue. The current moment in time is centered in the\nvisualization with a stationary line to mark it, and there is room for\none measure before and after the line. A full phrase doesn't fit, but\nyou can see its phase gradually growing until it ends.\n\nimage::metronome-phrase.gif[One phrase of metronome animation,239,160]\n\nThe most basic way of synchronizing the metronome is to tap the\nkbd:[Tap Tempo] button at each beat of the music. Tapping the button\naligns the metronome to a beat, and if you tap it three or more times\nwithin two seconds of each preceding tap, sets the metronome's BPM.\nTap it as you hear each beat of the music, and after three or more\ntaps, the speed of the metronome will be approximately synchronized\nwith the music.\n\nOnce the tempo is correct, you can tell Afterglow which beat is the\ndown beat by holding down the kbd:[Shift] button while pressing\nkbd:[Tap Tempo]. This combination does not change the tempo, but tells\nAfterglow that the moment when you tapped the button is the down beat\n(the first beat of a bar).\n\nYou can also adjust the BPM by turning the BPM encoder, which is the\nencoder right above the kbd:[Metronome] button:\n\nimage::Push2BPM.jpg[BPM encoder,800,663]\n\nWhile you are holding this encoder, the BPM gauge brightens, along\nwith the BPM digit after the decimal point, as a visual reminder of\nwhat value you are adjusting. Turning the encoder clockwise raises the\nBPM, turning counterclockwise lowers it. While the metronome section\nis showing, you can also use the encoder above the BPM value to adjust\nit. But you can grab the dedicated BPM encoder above the\nkbd:[Metronome] button even when the metronome section is not showing,\nand it will appear while you have the encoder in your hand, so you can\nadjust the BPM quickly, and then get back to what you were doing.\n\nIf you press the kbd:[Shift] button, the BPM encoder can be used to\nadjust the BPM by whole beats rather than tenths. While kbd:[Shift] is\ndown, the BPM value before the decimal point will be brightened,\nrather than the digit after it, and the BPM will change ten times as\nquickly when you turn it. You can switch back and forth in the middle\nof your adjustments by pressing and releasing the shift key at any\ntime.\n\nimage::bpm-adjustment.gif[BPM adjustment animation,240,160]\n\nIn order to make longer chases and effects line up properly with the\nmusic, you will also want to make sure the count is right, that the\nbeat number shows `1` on the down beat, and that the bar numbers are\nright as well, so that the start of a phrase is reflected as bar\nnumber `1`. In addition to using kbd:[Shift] with kbd:[Tap Tempo] to\nset the down beat, you can adjust the current beat number using the\nbeat encoder, the encoder above the kbd:[Tap Tempo] button:\n\nimage::Push2Beat.jpg[Beat encoder,800,459]\n\nWhile you are holding this encoder, an endless circular gauge appears\nbelow the beat information, and the beat number is brightened, as a\nvisual reminder of what value you are adjusting. Turning the encoder\nclockwise jumps to the next beat, turning counterclockwise jumps back\nto the previous one. As a tactile reminder that you are adjusting\nwhole beats, this encoder moves with a distinct click as it changes\nvalue, while the BPM encoder turns smoothly as you scroll through\nfractional BPM values.\n\nWhile the metronome section is showing, you can also use the encoder\nabove the Beat value to adjust it. But you can grab the dedicated Beat\nencoder above the kbd:[Tap Tempo] button even when the metronome\nsection is not showing, and it will appear while you have the encoder\nin your hand, so you can adjust the beat number quickly, and then get\nback to what you were doing.\n\nIf you press the kbd:[Shift] button, the Beat encoder can be used to\nadjust the current bar within the phrase instead of the current beat.\nWhile kbd:[Shift] is down, the bar will be brightened instead of the\nbeat, and turning the encoder will jump that value forwards or\nbackwards:\n\nimage::beat-adjustment.gif[Beat adjustment animation,240,160]\n\nIf you know a phrase is about to begin, you can press the red\nkbd:[Reset] button in the metronome section right as it does. This\nwill reset the count to Phrase 1, Bar 1, Beat 1.\n\nTrying to keep up with tempo changes during dynamic shows can be\ntedious, so you will hopefully be able to take advantage of\nAfterglow's metronome synchronization features. If the DJ can send you\n<<mapping_sync.adoc#syncing-to-midi-clock,MIDI clock pulses>>, or you can\nconnect via a Local Area Network to Pioneer professional DJ gear to\nlock into the beat grid established by\n<<mapping_sync.adoc#syncing-to-pro-dj-link,Pro DJ Link>>, Afterglow can\nkeep the BPM (with MIDI) and even the beats (with Pro DJ Link and the\nTraktor Afterglow Beat Phase\n<<mapping_sync.adoc#syncing-to-traktor-beat-phase,controller mapping>>)\nsynchronized for you. The Sync button in the Metronome section\n(showing kbd:[Manual] sync in these photos) will eventually allow you to\nset this up, but that is not yet implemented, so for now you will need\nto use the <<README.adoc#metronome-control,web interface>> to configure it.\n\nNOTE: The button does already change color to let you know the sync\nstatus: amber means manual, green means successful automatic sync, and\nred means a requested automatic sync has failed. It is likely that a\nfuture release of Afterglow will let you press this button to choose\nyour sync source.\n\nOnce your sync is established, the meaning of the kbd:[Tap Tempo]\nbutton changes. If you are using MIDI clock to sync the BPM, it\nbecomes a kbd:[Tap Beat] button, which simply establishes where the\nbeat falls. If you are locked in to a Pro DJ Link beat grid or using\nthe Traktor beat phase mapping, the beats are automatically aligned\nfor you so, it becomes a kbd:[Tap Bar] button which, when pressed,\nindicates that the current beat is the down beat (start) of a bar.\n(Similarly, if you press the metronome kbd:[Reset] pad while synced to\na Pro DJ Link beat grid or Traktor beat phase, the beat itself will\nnot move, but the beat closest to when you pressed the pad will be\nidentified as Beat 1.) In these sync modes you can also use the\nkbd:[Shift] button to align at the next bigger boundary: If tapping\nwould normally move the bar, shift-tapping will move the phrase.\n\nIf you try to adjust the BPM encoder while sync is active, it will\nhave no effect, and Afterglow will point at the sync mode to explain\nwhy it is ignoring your adjustments.\n\n[[sharing-the-push]]\n=== Sharing the Push 2\n\nIf you are using Afterglow at the same time as Ableton Live, you can\nswitch back and forth between which has control of the Push by\npressing the kbd:[User] button. If Live is not running when you press\nkbd:[User], the Push interface will simply go blank (except for the\nkbd:[User] button itself), until you press it again, at which point\nAfterglow will light it up.\n\nNOTE: Future releases will take advantage of more of the buttons on\nthe controller.\n"
  },
  {
    "path": "doc/modules/ROOT/pages/rendering_loop.adoc",
    "content": "= The Rendering Loop\nJames Elliott <james@deepsymmetry.org>\n\nThis page contains advanced, low-level information for people who are\nready to create their own custom effect algorithms. Not to scare you\noff, but don't be discouraged if you are new to Afterglow, and this\ncontent seems rather difficult. Start experimenting in other places,\nand by the time you need this information, it will make much more\nsense!\n\nAnd once you are ready to really dive deep, you can learn how to\n<<extensions,extend>> the rendering loop to incorporate completely new\nkinds of elements, such as integrating with Pangolin Beyond laser\nshows.\n\n[[frame-rendering-stages]]\n== Frame Rendering Stages\n\nWhen an afterglow show is running, that is, from when\n{api-doc}afterglow.show.html#var-start.21[`(show/start!)`]\nhas been called, until\n{api-doc}afterglow.show.html#var-stop.21[`(show/stop!)`]\nor\n{api-doc}afterglow.show.html#var-stop-all.21[`(show/stop-all!)`]\nis called, there is a background task scheduled to run many times per\nsecond, to calculate the next “frame” of control values to send to the\nuniverses controlled by the show, and then send those values. The rate\nat which this activity is scheduled is determined by the\n`refresh-interval` value established when the show was\n{api-doc}afterglow.show.html#var-show[created].\nIf not explicitly set as a parameter to `(show/show)`, an interval of\n25 milliseconds is used, causing the lights to be updated forty times\neach second. If your DMX interface is running at a different rate, you\nwill want to configure your show to match it, so that you are getting\nthe best results possible without wasting computation on frames that\nnever get seen.\n\nTIP: Once a show has started running, you can get a sense of how heavily it\nis taxing your hardware by looking at the show’s `:statistics` atom:\n\n[source,clojure]\n----\n(clojure.pprint/pprint @(:statistics *show*))\n; {:afterglow-version \"0.1.0-SNAPSHOT\",\n;  :total-time 70429,\n;  :frames-sent 105828,\n;  :average-duration 0.6655044,\n;  :recent #amalloy/ring-buffer [30 (0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 1)],\n;  :recent-total 6,\n;  :recent-average 0.2}\n; -> nil\n----\n____\nThis tells you how many milliseconds have been spent in the rendering\nloop while the show is running, how many frames of DMX data have been\nsent to the show universes, and the average number of milliseconds spent\nin the rendering loop. If the duration of a rendering cycle ever exceeds\nthe refresh interval, Afterglow will log a warning that it is unable to\nkeep up with the effects you are trying to run.\n\nIf you have a show&rsquo;s web interface open, the `:recent` keys in\nthis atom are used to display the Load bar at the top of the screen,\nwhich fills up and turns red as the time within each frame available\nfor calculating and sending control values to the lights gets used up.\n____\n\nWhen it is time to determine the next set of values to send to the\nshow’s patched fixtures, this is what happens:\n\n. The first thing Afterglow does is take a\n{api-doc}afterglow.rhythm.html#var-ISnapshot[snapshot]\nof the show\n<<metronomes.adoc#,metronome>> to\nidentify a common point in time for all the effects to use in deciding\nhow they should look. This enables a consistent, coordinated appearance\nfor everything in the frame.\n\n. The next step is to zero out the buffers that will be used to send\nDMX data for each universe, so that if no effect tries to set a value\nfor a particular channel on this frame, a zero value will be sent for\nit.\n\n. Then Afterglow loops over all <<effects.adoc#,Effects>> that are\ncurrently active for the show, and asks if any are ready to end, as\ndescribed in the <<effects.adoc#the-effect-lifecycle,Effect\nLifecycle>> section. If any are, they are removed from the list of\nactive effects.\n\n. Then it makes another loop over any effects that did not end, to see\nhow they want to affect the lights. It does this by calling, in order,\neach effect’s {api-doc}afterglow.effects.html#var-generate[`generate`]\nfunction, passing in the show and the metronome snapshot. In order to\nmake the lights do things, each effect returns a list of\n<<assigners,Assigners>> specifying the things it wants to happen.\nThese are gathered in the order they were returned by each effect.\n\n. While being gathered, the assigners are separated into individual\nlists, divided first by the `kind` value of the assigner (`:channel`,\n`:function`, `:color`, `:pan-tilt`, `:direction`, or `:aim`, or some\nother value added by a rendering loop <<extensions,extension>>), and\nwithin each kind, further divided into lists based on the target ID\nthat the assigner wants to affect. The structure of a target ID is up\nto the Assigner kind, and may be a simple number or tuple, depending\non the needs of the Assigner implementation; the important thing from\nthe Show's perspective is that if two target IDs are equal to each\nother, the assigners are affecting the same element of the show. +\nSince the effects are run in priority order (lower priority first,\nwith effects of the same priority running in the order in which they\nwere added to the show), higher-priority and more recent effects’\nassigners will come later in the gathered lists, and will get the\nchance to modify or veto any assigners from earlier and lower-priority\neffects which are trying to control the same thing. If the effect\ndoesn’t want to do anything this frame, it can simply return an empty\nassigner list.\n\n. Once all the assigners have been collected into their kind/target\nlists, each list is evaluated. The assigner kinds are processed in the\norder established by\n{api-doc}afterglow.show.html#var-resolution-order[`show/resolution-order`]\nand starts with low-level, single channel `:channel` assigners, then\nmoves up to more complex `:function`, `:color`, `:pan-tilt`,\n`:direction`, and `:aim` assigners. (This order was chosen because\ndifferent kinds of assigners might end up affecting the same DMX\nchannel; the higher levels of abstraction are allowed to win by\nrunning last.) Within each kind, however, the lists can be processed\nin parallel, since they will all affect separate targets.\n+\nTo process a list, each assigner’s\n{api-doc}afterglow.effects.html#var-assign[`assign`]\nfunction is called, again passing in the show and the metronome\nsnapshot, the target which is being assigned (a DMX channel in a show\nuniverse, or a fixture or fixture head, depending on the assigner\nkind), as well as the assignment value the effect wanted to establish\n(a number, color, or head direction, again depending on the assigner\ntype), and the previous assignment (if any) that an earlier assigner\nwanted to set for this target. The assigner can decide what to do with\nthe previous assignment: Ignore it, blend the current assignment with\nit somehow, or honor it, depending on the nature and configuration of\nthe assigner. The `assign` function returns a single resolved value of\nthe appropriate type for the assignment, and Afterglow records it,\npotentially to pass it to the next assigner on the list. The assigner\ncan also veto any previous assignment and say that nothing should\nhappen by returning an assignment with `nil` for its value.\n+\nThe input to `assign` might be a\n<<parameters.adoc#,Dynamic Parameter>>, and the resulting\nvalue may be as well, or the assigner may choose to resolve it into a\nnon-dynamic value, in order to decide between or blend competing\nassignments.\n+\nAt the end of this process, Afterglow is left with a single assigned\nvalue for every target which any effect wanted to influence for the\ncurrent frame.\n\n. Afterglow uses these assignment results to establish actual DMX\nvalues for the frame, using the\n{api-doc}afterglow.effects.html#var-resolve-assignment[`resolve-assignment`]\nmultimethod, whose implementations (which are specific for each of the\npossible assignment kinds) finally resolve any remaining dynamic\nparameters, and then turn abstractions like color objects and aiming\nvectors into appropriate DMX channel values for the target that is\nbeing assigned.\n\n. Finally, the resulting buffers of DMX values, with zeros in any\nchannels which were not affected by assigners, are sent to their\ncorresponding universes, causing the lights to produce the desired\neffects.\n\n[[assigners]]\n== Assigners\n\nAs described above, the role of an assigner in the rendering loop is\nto actually decide what _value_ (color, direction, or the like) is\ngoing to be sent to a _target_ (a lighting fixture head for more\nabstract assigners, or a simple DMX channel for Channel assigners), at\na given point in time. It really is the heart of implementing an effect.\n\nThe assigner fulfills this responsibility by implementing the\n{api-doc}afterglow.effects.html#var-assign[`assign`]\nfunction in the\n{api-doc}afterglow.effects.html#var-IAssigner[`IAssigner`]\nprotocol. It is passed the show, the metronome snapshot which\nidentifies the point in musical time that has been reached, the target\nbeing assigned, and the value that any earlier assigners of the same\ntype have decided should be assigned to the target.\n\nIt performs its magic, using the values established in setting up the\neffect, and the algorithm that the effect author designed, to come up\nwith the resulting value that it wants assigned to the target, which\nmay or may not be influenced by the previous assignment, and returns\nthat value for Afterglow to either use, or pass on to the next\nassigner of that type in the effect chain.\n\nThe best way to understand this is probably to look at examples of\neffects that ship with Afterglow, starting with simple ones like\n{api-doc}afterglow.effects.color.html#var-color-effect[`color-effect`],\n{api-doc}afterglow.effects.dimmer.html#var-dimmer-effect[`dimmer-effect`],\nand\n{api-doc}afterglow.effects.movement.html#var-direction-effect[`direction-effect`],\nthen slightly more complex\n{api-doc}afterglow.effects.fun.html#var-strobe[`strobe`]\nand\n{api-doc}afterglow.effects.fun.html#var-sparkle[`sparkle`]\neffects, and on up to more sophisticated compound effects like\n{api-doc}afterglow.effects.fun.html#var-color-cycle-chase[`color-cycle-chase`],\nand the spatially mapped elaborations of it like\n{api-doc}afterglow.effects.fun.html#var-iris-out-color-cycle-chase[`iris-out-color-cycle-chase`].\n\nOnce you can understand how all of those pieces fit together, you will\nbe ready to build your own complex and mesmerizing effects!\n\n[[channel-assigners]]\n=== Channel Assigners\n\nChannel assigners have a `kind` of `:channel`, and their `target-id`\nis a tuple of universe ID and channel address, so `[1 234]` would\nrepresent an assignment to universe `1`, address `234`. The assignment\nvalues they return are either a valid DMX data value (see next\nparagraph), a <<parameters.adoc#,dynamic parameter>> which will\nresolve to a valid DMX data value, or `nil`, meaning no assignment\nshould take place.\n\n\n[[dmx-values]] The DMX data value is a number in the range `[0-256)`.\nIn other words, it can take any value from zero up to but not reaching\n256. Non-integer values are supported, because the channel might be a\n<<fixture_definitions.adoc#generic-channels,fine-channel>> which uses\ntwo bytes to offer more precision in control than a single byte can\noffer. In that case, the integer portion of the value is sent as the\nmost-significant byte on the main channel, and the fractional portion\nis converted to a least-significant byte and sent on the fine channel.\nIf the channel does not have a fine channel attached to it, any\nfractional part of the assigned value is simply discarded.\n\nChannels can also be _inverted_, which means the DMX values are\nreversed from the value being assigned. This is needed to support some\nfixtures which have inverted dimmers, is established by the presence\nof an `:inverted-from` entry in the\n<<fixture_definitions.adoc#inverted-channels,channel specification>>,\nand taken care of by\n{api-doc}afterglow.effects.channel.html#var-apply-channel-value[`apply-channel-value`],\nwhich is invoked by the channel assignment resolver, so channel\nassigners do not need to worry about this detail, and can always work\nin terms of non-inverted channel values. (This is important, for\nexample, when implementing highest-takes-precedence rules for a dimmer\nchannel. Bigger numbers will always mean brighter, even if at the last\nstep before sending them to the fixture they are inverted because of\nthe nature of the channel.)\n\n[[function-assigners]]\n=== Function Assigners\n\nFunction assigners have a `kind` of `:function`, and their `target-id`\nis a tuple of the head or fixture ID and the function keyword, so `[3\n:strobe]` would represent an assignment to the fixture or head with ID\n3, setting the value of that head's `:strobe`\n<<fixture_definitions.adoc#function-specifications,function>>. The\nassignment values they return are either a percentage value, a\n<<parameters.adoc#,dynamic parameter>> which will resolve to a\npercentage value, or `nil`, meaning no assignment should take place.\n\nWhen the assignment is resolved, the percentage is translated to an\nactual DMX value along the range defined in each fixture's function\nspecification. For example, if the function was defined as existing on\nthe range 20-29 for a particular fixture, and the assigned percentage\nwas 50.0, then the assignment for that fixture would send a value of\n25 to the function's channel.\n\n[[color-assigners]]\n=== Color Assigners\n\nColor assigners have a `kind` of `:color`, and their `target-id` is\nthe head or fixture ID; `42` would represent an assignment to the\nfixture or head with ID 42. The assignment values they return are\neither a <<color.adoc#,color>> object, a\n<<parameters.adoc#color-parameters,dynamic parameter>> which will\nresolve to a color object, or `nil`, meaning no assignment should take\nplace.\n\nWhen the assignment is resolved, Afterglow uses all available color\nchannels in the target head to mix the specified color. It is\nautomatically able to use `:color` intensity channels of type `:red`,\n`:green`, `:blue`, and `:white`. It will also use any other `:color`\nchannels whose hue has been\n<<fixture_definitions.adoc#hue-mixing,specified>> in the fixture\ndefinition.\n\nIf the head or fixture uses a color wheel to make colors, rather than\ntrying to mix colors using channel intensities, Afterglow will find\nthe <<fixture_definitions.adoc#color-wheel-hue,color wheel hue>>\nclosest to the hue of the color being assigned, and send the function\nvalue needed to set the color wheel to that position. The color wheel\nhue has to be &ldquo;close enough&rdquo; to the assigned hue for\nAfterglow to use it. By default, as long as the hue values are within\n60&deg; of each other (which is very lenient), Afterglow will use it.\nYou can adjust this tolerance by setting a different value in the show\nvariable `:color-wheel-hue-tolerance`. The color being assigned must\nalso have a saturation of at least 40% for the color wheel to be\nconsidered (this minimum saturation can be adjusted by setting a\ndifferent value in the show variable `:color-wheel-min-saturation`).\n\n[[pan-tilt-assigners]]\n=== Pan/Tilt Assigners\n\nPan/Tilt assigners have a `kind` of `:pan-tilt`, and their `target-id`\nis the head or fixture ID; `68` would represent an assignment to the\nfixture or head with ID 68. The assignment values they return are\neither a `javax.vecmath.Vector2d`, a\n<<parameters.adoc#direction-parameters,dynamic parameter>> which will\nresolve to a `Vector2d` object, or `nil`, meaning no assignment should\ntake place.\n\nWhen the assignment is resolved, the vector indicates the pan and tilt\nangles away from the `z` axis of the <<show_space.adoc#,frame of\nreference of the show>> to aim the fixture or head. Afterglow\ntranslates this vector to the appropriate values to send to the\nfixture's pan and tilt channels to aim it in the specified direction,\nif possible. Otherwise it gets as close as the fixture allows.\n\nIf multiple fixtures or heads are assigned the same pan-tilt vector,\nthey will all be aimed in exactly the same direction, regardless of\nthe location and orientation with which they were hung.\n\nNOTE: If there is an active Direction or Aim Assigner which affects\nthe same target, it will run later, so its effects will be the ones\nthat matter.\n\n[[direction-assigners]]\n=== Direction Assigners\n\nDirection assigners have a `kind` of `:direction`, and their\n`target-id` is the head or fixture ID; `42` would represent an\nassignment to the the fixture or head with ID 42. The assignment\nvalues they return are either a `javax.vecmath.Vector3d`, a\n<<parameters.adoc#direction-parameters,dynamic parameter>> which will\nresolve to a `Vector3d` object, or `nil`, meaning no assignment should\ntake place.\n\nWhen the assignment is resolved, the vector indicates the direction in\nthe <<show_space.adoc#,frame of reference of the show>> to aim the\nfixture or head. Afterglow translates this vector to the appropriate\nvalues to send to the fixture's pan and tilt channels to aim it in the\nspecified direction, if possible. Otherwise it gets as close as the\nfixture allows.\n\nIf multiple fixtures or heads are assigned the same direction vector,\nthey will all be aimed in exactly the same direction, regardless of\nthe location and orientation with which they were hung.\n\nNOTE: If there is an active Aim Assigner which affects the same\ntarget, it will run later, so its effects will be the ones that matter.\n\n[[aim-assigners]]\n=== Aim Assigners\n\nAim assigners have a `kind` of `:aim`, and their `target-id` is the\nhead or fixture ID; `17` would represent an assignment to the fixture\nor head with ID 17. The assignment values they return are either a\n`javax.vecmath.Point3d`, a <<parameters.adoc#aim-parameters,dynamic\nparameter>> which will resolve to a `Point3d` object, or `nil`,\nmeaning no assignment should take place.\n\nWhen the assignment is resolved, the point identifies the precise\nlocation in the <<show_space.adoc#,frame of reference of the show>> to\naim the fixture or head. Afterglow translates this point to the\nappropriate values to send to the fixture's pan and tilt channels to\naim it at that exact spot, if possible. Otherwise it gets as close as\nthe fixture allows.\n\nIf multiple fixtures or heads are assigned the same aiming point, they\nwill all be aimed at exactly the same spot, regardless of the location\nand orientation with which they were hung.\n\n[[extensions]]\n== Extensions\n\nIf you want Afterglow to control something that does not respond to\nDMX values, you might be able to do so by extending the rendering\nloop. There is an example of doing just this to control laser shows by\ncommunicating with Pangolin's Beyond software in the\n{api-doc}afterglow.beyond.html[`afterglow.beyond`]\nnamespace, and another example in\n{api-doc}afterglow.effects.show-variable.html[`afterglow.effects.show-variable`],\nwhich creates effects that set show variables when they are run.\n\n[[new-assigner-types]]\n=== Introducing New Assigner Types\n\nThe first thing you need to do is identify the kinds of assigners that\nyour new effect types will need. They will need their own unique\n`kind` keywords, and a structure for their `target-id` values which\nlets Afterglow keep track of which assigners are affecting the same\nvalue. The Beyond integration uses `:beyond-color` and `:beyond-cue`\nfor `kind` values. `:beyond-color` is global, and thus uses a\n`target-id` that references the entire Beyond server instance. In\ncontrast, more than one `:beyond-cue` can be active at once, so its\n`target-id` is composed of both the server ID and the cue coordinates.\n\nAfterglow needs to be told how to handle your new kinds of assigners.\nFirst, you need to establish the order in which they should be run by\ncalling\n{api-doc}afterglow.show.html#var-set-extension-resolution-order.21[`show/set-extension-resolution-order!`]\nwith your unique extension key and the list of all your assigner types\nin the order in which they should be resolved. You need to do this\neven if you don't care about the order, or have only one new assigner\ntype, in order to get them added to stage 6 of the frame rendering\nprocess, as described above. This is done towards the end of the\nBeyond extension source, if you would like to see a concrete example.\n\nThen you need to tell afterglow how to actually resolve one of your\nassigners. You do this in the same way Afterglow registers its own\nbuilt-in assigners, by using `defmethod` to add a new implementation\nof the\n{api-doc}afterglow.effects.html#var-resolve-assignment[`resolve-assignment`]\nmultimethod, for your new assigner keyword. Again, the end of the\nBeyond integration provides a concrete example.\n\n[[customizing-fades]]\n=== Customizing Fades for your Assigner Types\n\nIf you want to support smooth fades between different values being\nreturned by your assigners, you will also want to `defmethod` an\nimplementation of the\n{api-doc}afterglow.effects.html#var-fade-between-assignments[`fade-between-assignments`]\nmultimethod. This is the last thing that the Beyond integration does.\n\nTIP: If you do not provide an implementation of\n`fade-between-assignments` tailored to your specific assigner `kind`,\nthe default implementation is used: it simply selects whichever\nassigner is on the side of the fade which is currently above 50%.\n\n[[frame-data]]\n=== Buffering and Sending Your Frame Data\n\nChances are good that your extension will need to do some sort of\nsetup at the start of a frame before your assigners can be resolved,\nand then will want to actually do something when the frame is rendered\nand being sent to the lights. To accomplish these tasks, you register\nfunctions with a show:\n{api-doc}afterglow.show.html#var-add-empty-buffer-fn.21[`add-empty-buffer-fn!`]\ntells the show to call the supplied function when a frame is about to\nbe rendered, allowing you to set up any buffers your assigners will\nneed, and\n{api-doc}afterglow.show.html#var-add-send-buffer-fn.21[`add-send-buffer-fn!`]\ntells the show to call the supplied function when it is time to\nactually send out the frame. The Beyond integration calls these in its\n{api-doc}afterglow.beyond.html#var-bind-to-show[`bind-to-show`]\nfunction.\n\nHaving done all these things, it becomes possible to create cues which\nlaunch or end Beyond laser cues, and effects which change the color of\nthe laser beam to match (or contrast with) colors being sent to the\nlights, as well as effects which simply set show variables so that\nother effects can respond to the fact that they are running. Perhaps\nlooking at these example implementations can help inspire your own\nextension in a completely new direction! (Links to the namespaces' API\ndocumentation are at the <<extensions,top>> of this section, and as\nalways, the API docs have `view source` buttons which take you right\nto the code that makes them work.)\n"
  },
  {
    "path": "doc/modules/ROOT/pages/show_space.adoc",
    "content": "= Show Space\nJames Elliott <james@deepsymmetry.org>\n\nIn order to be able to create spatial effects, from lighting gradients\nspread across your grid, to aiming moving heads in a precise and\ncoordinated way with respect to each other or people or objects near\nthem, Afterglow needs to know where everything is, and how it is\noriented in space. This means you need to be able to specify these\nthings. When mounting a <<fixture_definitions.adoc#,fixture>>, you\nspecify where it is and where it is facing. When creating a\n<<effects.adoc#direction-effects,direction>> or\n<<effects.adoc#aim-effects,aim>> cue, you specify a direction for\nlights to face, or a point for them to aim at. In order to be able to\ncommunicate such concepts, Afterglow has a standard frame of reference\nfor the light show. The entire show has an __origin__, the zero point\nfor the three spatial axes, which you decide on before you start\npatching fixtures, and an __orientation__, which is expressed in terms\nof the origin. The afterglow show orientation is chosen to make it\neasy to think in terms of the way effects will look for the audience.\nAs shown in the diagram below, in the standard orientation, the X axis\nextends directly to the right of the origin. That is to say, X\ncoordinates are zero at the origin, increase as you move to the right,\nand decrease as you move to the left. The Y axis extends straight up;\nY coordinates grow from zero as you move up from the show origin, and\ndecrease as you move down. The Z axis extends directly towards the\naudience, increasing in that direction from zero at the origin,\ndecreasing as you move towards the back of the show.\n\nimage::Show-Space.png[Afterglow show axes,800,582]\n\nDistance units are in meters, but if you find it easier to measure\ninches or feet, you can call\n{api-doc}afterglow.transform.html#var-inches[`afterglow.transform/inches`]\nand\n{api-doc}afterglow.transform.html#var-feet[`afterglow.transform/feet`]\nto convert them to meters for you.\n\nTo express rotations, the same frame of reference is used. If a light\nhas been hung upside down compared to its standard orientation (which\nshould be documented in the <<fixture_definitions.adoc#,fixture\ndefinition>>), you need to account for that when calling\n{api-doc}afterglow.show.html#var-patch-fixture.21[`show/patch-fixture`].\nRotations are expressed in terms of the axes as well. For example, if\na fixture has been tumbled towards the audience by a quarter rotation,\nthat would be a rotation around the X axis of π/2. (Rotations are\nexpressed in radians, a complete rotation being 2π. Again, if you find\nit more convenient to work in degrees, you can call\n{api-doc}afterglow.transform.html#var-degrees[`afterglow.transform/degrees`]\nto convert them into radians for you.) To figure out which direction\nof rotation is positive, imagine you are standing looking towards the\norigin on the axis in question, so its arrowhead is pointing at your\nnose. From that perspective, a positive rotation is counter-clockwise,\nand a negative rotation is clockwise, as shown by the purple arc in\nthe figure above.\n\nWhen measuring these distances and angles you don’t need to worry about\ngetting things perfect down to the millimeter, pretty close is good\nenough, but the closer you can get, the more precisely Afterglow will be\nable to aim at things and coordinate looks for you.\n\nWhen it comes to picking your origin, it is up to you. Picking the\ncenter of your lighting grid makes conceptual sense, although if you\nwant to make it easy to create aiming effects that hit particular\nspots on the floor, having the Y axis start at floor level is handy.\nThat is what I have found most convenient in setting up shows so far:\nmy X and Z origins are in the center of the lighting rig, and Y is 0\nat the floor.\n"
  },
  {
    "path": "doc/modules/ROOT/pages/videos.adoc",
    "content": "= Videos\nJames Elliott <james@deepsymmetry.org>\n\nThis page collects performance videos that highlight Afterglow in\naction. If you have any to share, please post them to the\nhttps://deep-symmetry.zulipchat.com/#narrow/stream/318697-afterglow[Afterglow\nstream on Zulip]!\n\nSince I have been too busy working on the software to get out and\nperform with it, I was deeply grateful to\nhttps://github.com/dandaka[Vlad Rafeev] for getting this page started\nby sharing a video of a\nhttps://www.facebook.com/deepowerband/[Deepower audiovisual] show he\nlit using Afterglow in Kaliningrad, in December, 2015. He modestly\nsays, “My first experience with lights, still a lot to accomplish.”\nAnd I say, there is a ton left to implement in the software too. But\nit was fun to see the great video he shared, but it is sadly no longer\nonline.\n\nFor a more wordy and nerdy introduction, there is a video of my\nhttps://youtu.be/mvNN0SMMZDQ[presentation and demonstration] at the\nJune 2016\nhttp://www.meetup.com/Madison-Clojure-Meetup/events/229842513/[Madison\nClojure Meetup].\n"
  },
  {
    "path": "doc/primes.md",
    "content": "# Playing with Primes in Clojure\n\nMy friend Andrew recently dicovered the joys of programming, and\nshared his cool Python code for testing numbers for primality. I\nwanted to encourage this enthusiasm, and make sure that he learned\nabout functional programming before his mind got too stuck in the ruts\nof C-style imperative code (which makes up the bulk of examples out\nthere), so I decided to play around with writing some of my own\nexamples for him.\n\nI think one of the best languages for exploring functional programming\ntoday is probably [Racket](https://racket-lang.org), but I haven't had\ntime to learn that yet myself. The pinnacle in many ways is\n[Haskell](https://www.haskell.org) but that's not nearly as\napproachable, and I would be even more lost trying to introduce\nsomeone there. But I have had the privilege of using\n[Clojure](https://clojure.org) for my professional work for the past\nseveral years, and find it a lovely, practical modern Lisp with a\nfocus on simplicity and functional programming, and with a great\ninteroperability story for the Java Virtual Machine environment, which\nis the indutrial-strength platform we use to deliver our products.\n(It's also been perfect for my open-source projects in areas like\n[light show control](https://github.com/Deep-Symmetry/afterglow#afterglow)\nand [DJ performance\nsynchronization](https://github.com/Deep-Symmetry/beat-link-trigger#beat-link-trigger).)\nSo I'm well equipped to guide a tour through finding prime numbers in\nClojure!\n\n## Building Blocks\n\nSince Clojure is a Lisp, it looks very different than C-like languages\n(including Python). The first thing to get used to is that pretty much\neverything is an expression, formed by grouping a list of symbols\ninside parentheses. The first symbol specifies _what you want to do_\nand is generally a function name (or a macro, or a special form, but\nwe won't need to worry about those details in this discussion). Then\nyou follow that with _what you want to do it to_. So for example, to\ndivide 10 by 2, you would write:\n\n```clojure\n(/ 10 2)\n```\n\nAnd you would see the result, `5`. Not too surprising. A bit more\nsurprising is what happens if you try dividing 10 by 3 (from now on,\nto save space in these examples, I am going to show what I type at the\nClojure REPL prompt, followed by a comment prefixed with `;; => ` that\nshows the response):\n\n```clojure\n(/ 10 3)\n;; => 10/3\n```\n\nWait, `10/3`, what witchcraft is this? It didn't give me an answer, or\nat least not the kind I expected! In fact, Clojure is biased towards\nretaining as much precision as possible, so when you ask it to perform\na division whose result does not have an exact integer representation,\nit returns a rational value which is exactly equal to what you wanted.\nYou can continue to use that result in further mathematical operations\nwith no loss of precision, or you can tell Clojure you want a\nfloating-point approximation of the result, like you would get in most\nlanguages, like so:\n\n```clojure\n(float (/ 10 3))\n;; => 3.3333333\n```\n\nSo, for finding primes, what we want to know is whether a number\nevenly divides another. The `rem` function helps with that, giving us\nthe remainder:\n\n```clojure\n(rem 10 2)\n;; => 0\n\n(rem 10 3)\n;; => 1\n```\n\nWe can combine that with the `zero?` predicate (a predicate is a\nfunction that returns `true` or `false` given its input) to build up\nour test for whether one number evenly divides another:\n\n```clojure\n(zero? (rem 10 3))\nfalse\n\n(zero? (rem 10 2))\ntrue\n```\n\n## Building our Own Blocks\n\nGreat, we get `true` when the second number evenly divides the first,\nand `false` otherwise. This is useful enough that I want to give it a\nname, to be able to use it in other expressions. So I will define it\nas a function, using the `defn` macro:\n\n```clojure\n(defn divides?\n  \"Returns true when the numerator can be evenly divided by the\n  denominator.\"\n  [numerator denominator]\n  (zero? (rem numerator denominator)))\n;; => #'user/divides?\n```\n\nThere is a little more structure to this than we've encountered so\nfar, but hopefully it's still easy enough to figure out what is going\non. We are defining a new function named `divides?`. The string that\nfollows the function name is an optional \"doc string\", which helps\nexplain how to use the function, both when reading the definition, and\nalso when you are typing at the REPL (this word comes from \"Read,\nEval, Print, Loop\", the core of interactive programming with a Lisp\nlike Clojure). At a REPL prompt you can type `(doc divides?)` and get\nthat explanatory text:\n\n```clojure\n(doc divides?)\n;; => -------------------------\n;; => user/divides?\n;; => ([numerator denominator])\n;; =>   Returns true when the numerator can be evenly divided by the\n;; =>   denominator.\n```\n\nFollowing the doc string is the parameter list, which specifies what\nthe function expects to be given when called, in our case two values\nwhich we name `numerator` and `denominator`. And then finally, the\nlast line is the actual body of the function, which uses the `zero?`\npredicate and `rem` function as we did in our earlier examples. The\nreturn value we saw at the REPL simply reported that the function\n`divides?` had been created in the `user` namespace, which goes a bit\nfar afield from what we are talking about today.\n\nWith this in place, we can try out our new function. It works just as\nyou'd expect:\n\n```clojure\n(divides? 10 2)\n;; => true\n\n(divides? 10 3)\n;; => false\n```\n\nIncidentally, we can use `doc` on the other functions we've been using\nup to this point:\n\n```clojure\n(doc zero?)\n;; => -------------------------\n;; => clojure.core/zero?\n;; => ([num])\n;; =>  Returns true if num is zero, else false\n```\n\nAnd now we are ready to build our prime-tester! As in Andrew's example\nI want to start by verifying that we were given a positive integer.\nThere are two built-in predicates we can use for that, `integer?` and\n`pos?`. All that remains is to check whether there is any number\nranging from two up to the square root of our candidate number that\nevenly divides it. If not, then we can be sure it is prime.\n\nWhile in imperative languages you do this kind of thing by writing an\nexplicit loop that assigns a variable to hold each value you want to\nconsider, in a functional language you instead filter sequences of\nvalues using predicates. So let's start by figuring out how to express\nthe sequence of values we want to check. To test if ten is prime, the\nrange of values we need to test if it is divisible by starts at two,\nand goes up to three (the largest integer that is less than the square\nroot of ten). There is a built-in function `range` that gives a range\nof values. If we try it out with the square root of our candidate\nvalue, we see it seems _almost_ give us the numbers we want:\n\n```clojure\n(range (Math/sqrt 10))\n;; => (0 1 2 3 4)\n```\n\nWe have a couple of extra values at the beginning, because `range`\ndefaults to starting with zero, and although it goes far enough in\nthis case, because it gives you values up to _but not including_ the\nupper bound you supply, it would not work if we gave it a perfect\nsquare as its input. Let's tackle the first problem first: We could\nuse the `drop` function to get rid of the first two values, but if we\ncheck the `doc` for `range` we find that there is also another way to\ncall it, which lets us supply the starting value too:\n\n```clojure\n(doc range)\n-------------------------\nclojure.core/range\n;; => ([] [end] [start end] [start end step])\n;; =>   Returns a lazy seq of nums from start (inclusive) to end\n;; =>   (exclusive), by step, where start defaults to 0, step to 1, and end to\n;; =>   infinity. When step is equal to 0, returns an infinite sequence of\n;; =>   start. When start is equal to end, returns empty list.\n```\n\nSo `(range 2 (Math/sqrt 10))` gets us almost there; it works great for ten:\n\n```clojure\n(range 2 (Math/sqrt 10))\n;; => (2 3)\n```\n\nBut if we try it with 9, which is a perfect square, we don't get the\nvalue 3, which is its square root, and which we definitely do need to\ntest as a factor:\n\n```clojure\n(range 2 (Math/sqrt 10))\n;; => (2)\n```\n\nTo fix that, we will round the result of our square root operation\ndown to the closest integer less than or equal to it, using the\n`Math/floor` function, and then add one to that:\n\n```clojure\n(range 2 (inc (Math/floor (Math/sqrt 9))))\n(2 3)\n```\n\nThat slightly more complex formula also works for ten:\n\n```clojure\n(range 2 (inc (Math/floor (Math/sqrt 10))))\n(2 3)\n```\n\nOk, that gives us the numbers we want to check if ten is divisible by.\nTen is prime if it is not divisible by any of those numbers. And the\nway we express that in Clojure is almost shockingly concise and\nreadable, once you get over all the parentheses. At this point I want\nto show you the finished `prime?` function, and explain how the final\npieces fit together:\n\n```clojure\n(defn prime?\n  \"Returns true when `n` is prime.\"\n  [n]\n  (and (integer? n)\n       (pos? n)\n       (not-any? (partial divides? n) (range 2 (inc (Math/floor (Math/sqrt n)))))))\n```\n\nWe already looked at `defn`, the doc string, and argument list. Our\n`prime?` function takes a single argument `n`, and (as suggested by\nthe question mark at the end of the name) is a predicate, returning\n`true` or `false`. In the body, we use a new `and` function, which, as\nits name suggests, returns `true` if all of its arguments are\nthemselves true. In fact, it stops evaluating and returns false as\nsoon as it encounters a false argument, so we don't have to worry\nabout division by zero or other problems, because the first two things\nwe check are that `n` is a positive integer.\n\nThat last line is where the rubber meets the road. And at first glance\nit might seem confusing. But notice that the second half, the `range`\nexpression, we have already explored. That returns a sequence of\nintegers ranging from 2 to the square root of `n`. It is used as the\nsecond argument of the `not-any?` function. `not-any?` takes a\npredicate and a collection, and returns `true` if no elements of the\ncollection satisfy the predicate. The collection we gave it is the\nlist of numbers we want to check as potential divisors of our\ncandidate prime number. So we need a predicate that returns `true` if\nthe potential divisor evenly divides `n`.\n\nIn other words, we want a function that takes a single number, and\nreturns `true` if that number evenly divides `n`, whatever `n`\nhappened to be when `prime?` was called. One of the really powerful\nthings about functional languages is that they make it very easy to\ncreate, modify, and pass around functions, and our little bit of code\nhere is a perfect example of that. The `partial` function is an\nexample of a _higher order function_, which means a function that\nmanipulates other functions. You give `partial` the name of a function\nthat you want to work with, and some arguments, and it returns the\nresult of _partially applying_ those arguments to the function.\n\n> What?\n\nWell, let me be more conrete. We have already defined a function\n`divides?` that takes two arguments. We want a function that acts just\nlike that, only with the first argument, the numerator, already filled\nin, because we want a predicate that takes one argument and tests\nwhether that value evenly divides `n`. We can do exactly that:\n`(partial divides? n)` creates a new function that calls `divides?`\nwith the values `n` and whatever you pass to this new function. So\nthat is exactly what we need as a predicate for `not-any?` to use. Our\n`prime?` function will return `true` if no integer from 2 to the\nsquare root of `n` can evenly divide `n`. And in so few words! The\nexplanation is far bigger than the code itself, even counting the doc\nstrings. Let's try it out!\n\n```clojure\n(prime? 10)\n;; => false\n\n(prime? 11)\n;; => true\n\n(prime? 1001)\n;; => false\n\nuser=> (prime? 1009)\n;; => true\n```\n\n## Infinite, Lazy Blocks\n\nSo that was to show Andrew what his prime tester would look like in\nClojure. But this is just where the fun begins! Now that we have a\nnice `prime?` predicate, we can use it to easily build the list of all\nprime numbers:\n\n```clojure\n(def primes\n  \"The prime numbers.\"\n  (filter prime? (range)))\n```\n\nThe `filter` function takes a predicate and a collection, and returns\na new collection that contains only those elements for which the\npredicate was true. So in this case, we supply all the natural numbers\nfor our range (when you give no arguments to `range`, the lower bound\nis zero, and there is no upper bound), and filter out anything that\nisn't prime.\n\n> Whoa, James, you're crazy. That can't work. I know I bought a fancy\n> computer, but it doesn't have enough memory to store _all_ numbers,\n> and even if it could, even with my fast processor, it would take too\n> long to figure out which elements in that infinite sequence were\n> prime!\n\nHere's the crazy thing, it _does_ work! And the reason it does is that\nClojure supports _lazy sequences_, meaning the values are not produced\nuntil you actually ask for them. So we can quite happily define\ninfinite sequences, and only pay for the production of the values we\nactually want to work with. So yes, if you tried to print out the\nvalue of `primes`, your computer would chunk away until it ran out of\nmemory, but we can use the `take` function to look at as many as we\nwant to without that problem. Here are the first ten primes:\n\n```clojure\n(take 10 primes)\n;; => (1 2 3 5 7 11 13 17 19 23)\n```\n\nAnd, actually, this reveals a mistake we made early on. Technically, 1\nis not considered a prime number, and including it in this list is\ngoing to break some of the fancy things we are about to do, so let's\ngo back and fix this. (I left this change until now, because I wanted\nthe code to exactly parallel Andrew's Python example, but we are going\nto start diverging a bit.) Here is the revised version of `prime?`:\n\n```clojure\n(defn prime?\n  \"Returns true when `n` is prime.\"\n  [n]\n  (and (integer? n)\n       (> n 1)\n       (not-any? (partial divides? n) (range 2 (inc (Math/floor (Math/sqrt n)))))))\n```\n\n> I will include a complete copy of the final version of all this code\n> at the end of this article for people who want to examine it as a\n> whole, or load it into their own REPL and play.\n\nReloading everything with that change in place, we get this more\ntraditional list of the first ten primes:\n\n```clojure\n(take 10 primes)\n(2 3 5 7 11 13 17 19 23 29)\n```\n\nAnd we can combine `take` with `drop` to skip to the part of the\nsequence we're interested in. Here's how we would find out what the\nthousandth prime is:\n\n```clojure\n(take 1 (drop 999 primes))\n;; => (7919)\n```\n\nOr what about the ten-thousandth?\n\n```clojure\n(take 1 (drop 9999 primes))\n;; => (104729)\n```\n\nBut that was starting to make my computer work hard. There was a\nnoticeable delay between when I hit `return` and when I got the answer\nback. Interestingly, however, if I ask it a second time, I get the\nanswer instantly. That's because the `primes` sequence remembers\nvalues that have aleady been calculated, and only has to do work when\nyou ask it to go out beyond what it has already figured out.\n\nLet's take a look at exactly how hard it is working, and start\nexploring some interesting ways we can calculate primes faster. If I\nquit the Clojure REPL, then reload my functions, I can time how long\ngetting the ten-thousandth prime took using the `time` function.\n\nAt first I was getting utterly bogus values by trying it directly like\nthis:\n\n```clojure\n(time (take 1 (drop 9999 primes)))\n;; => \"Elapsed time: 0.02719 msecs\"\n```\n\nBut then I remembered one of the pitfalls of working with lazy\nsequences. In the above attempt, we never _did anything_ with the\nexpression, so it stayed lazy, and the prime number sequence never got\nbuilt. So to force it to really do the work, I added a call to\n`vec`, which converts the result to a non-lazy vector, thereby forcing\nevaluation. Armed with that better approach, and starting with a fresh\nClojure REPL, I got the following results:\n\n```clojure\n(time (vec (take 1 (drop 9999 primes))))\n;; => \"Elapsed time: 28318.878726 msecs\"\n;; => [104723]\n```\n\nThe square brackets around the result show it is a vector rather than\na sequence, and you can see it took nearly thirty seconds to come up\nwith the answer.\n\nRunning it a second time it already knew the primes up to that point,\nso it went vastly faster:\n\n```clojure\n(time (vec (take 1 (drop 9999 primes))))\n;; => \"Elapsed time: 1.320859 msecs\"\n;; => [104723]\n```\n\nNo noticeable delay. Lazy sequences are cool! And we can use them in\nreally powerful ways, as we will now explore.\n\n## Getting Even Smarter About It\n\nThat was some very compact code that gave us a nice list of prime\nnumbers. But we can do even better! Now that we have this sequence of\nprime numbers, we can make use of it in our definition of `prime?`\nitself, because it is actually redundant to try dividing `n` by\n_every_ number from `2` to `sqrt(n)`, we only need to test the _prime_\nnumbers in that range.\n\nTo make this convenient, let's define a couple of new functions.\nFirst, a predicate that will tell us whether the prime factor we are\nconsidering is small enough that we need to test it:\n\n```clojure\n(defn sqrt-or-less?\n  \"Returns true when `candidate` is less than or equal to the\n  square root of `n`.\"\n  [n candidate]\n  (<= candidate (Math/sqrt n)))\n```\n\nThen, a function that returns the set of prime numbers we need to try\ndividing our number by, in order to see if it is prime. In other\nwords, all prime numbers from 2 up to the square root of our number.\nBecause this function is going to use our `primes` sequence, but we\ncan't define `primes` until later because it needs to use this\nfunction, we have to promise the Clojure compiler that `primes` is a\nvalue we will define later on. Then we can write the new function\nusing it:\n\n```clojure\n(declare primes)\n\n(defn potential-prime-factors\n  \"Returns the prime numbers from 2 up to the square root of `n`.\"\n  [n]\n  (take-while (partial sqrt-or-less? n) primes))\n```\n\nThis introduces another new function, `take-while`, which is like\n`take` but instead of knowing in advance how many values we want, we\ncan supply a predicate, and we will get back all the values up to the\none for which that predicate is no longer true. The predicate we want\nis one that is true when the number is small enough to potentially be\na prime factor of `n`, so that means it is less than or equal to the\nsquare root of `n`. We once again use the `partial` higher-order\nfunction to build that predicate, by \"pre-filling\" in the value of `n`\nas the first argument of our `sqrt-or-less?` predicate, and then we\nkeep feeding it prime numbers until we reach one that is too big.\n\n> I could have done this next bit without adding those two new helper\n> functions, but that would require using Clojure's \"function\n> literals\" to define functions right where I am using them, and that\n> is more of a detour than makes sense for this introduction. And\n> sometimes spelling things out and naming them makes for a more\n> readable solution to my future self anyway.\n\nFinally, a redefinition of our `prime?` function, taking advantage of\nthese new helper functions:\n\n```clojure\n(defn prime?\n  \"Returns true if `n` is prime.\"\n  [n]\n  (and (integer? n)\n       (> n 1)\n       (not-any? (partial divides? n) (potential-prime-factors n))))\n```\n\nIt's now even more self-explanatory, thanks to the nicely named helper\nfunctions. But more importantly, is it faster? If I start in a fresh\nClojure REPL, load the code, and time it, I see...\n\n```clojure\n(time (vec (take 1 (drop 9999 primes))))\n;; => \"Elapsed time: 121.442485 msecs\"\n;; => [104729]\n```\n\nIndeed! A tenth of a second is definitely faster than thirty. Nice.\nAnd what a fun exploration this has been. Thanks, Andrew! Even though\nI kind of knew where I was hoping to end up, I was impressed by just\nhow perfectly lazy sequences fit this problem. I was able to define\nthe prime number sequence using a function that depends on the prime\nnumber sequence, and since things are not evaluated until they are\nneeded, that works perfectly, and only does work once, the first time\nit is needed.\n\n> When I first posted these examples, I had misremembered how big you\n> need to go when testing potential prime factors, and was going all\n> the way up to half of `n`, rather than to its square root. That\n> still saved time, taking just over six seconds, but a tenth of a\n> second is way better. Thanks to my newest coworker Sarah for\n> reminding me of this important fact.\n\nHere is the full code in its final version, as promised:\n\n```clojure\n(defn divides?\n  \"Returns true when the numerator can be evenly divided by the\n  denominator.\"\n  [numerator denominator]\n  (zero? (rem numerator denominator)))\n\n(defn sqrt-or-less?\n  \"Returns true when `candidate` is less than or equal to the\n  square root of `n`.\"\n  [n candidate]\n  (<= candidate (Math/sqrt n)))\n\n(declare primes)\n\n(defn potential-prime-factors\n  \"Returns the prime numbers from 2 up to the square root of `n`.\"\n  [n]\n  (take-while (partial sqrt-or-less? n) primes))\n\n(defn prime?\n  \"Returns true if `n` is prime.\"\n  [n]\n  (and (integer? n)\n       (> n 1)\n       (not-any? (partial divides? n) (potential-prime-factors n))))\n\n(def primes\n  \"The prime numbers.\"\n  (filter prime? (range)))\n\n```\n"
  },
  {
    "path": "logs/README.txt",
    "content": "This directory is where development-mode log files are written, to\nmake it easy to debug problems which happen on background threads. The\nlog files themselves are ignored by git, so when you first check out\nAfterglow, this directory will be empty (except for this explanation).\nAs you run it in your repl, you will start to collect logs here, and\nthey will hopefully help you figure out why things aren't working, if\nyou run into snags in learning how to use and extend the system.\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"private\": true,\n  \"description\": \"Used to build the documentation site, not the project itself.\",\n  \"dependencies\": {},\n  \"devDependencies\": {\n    \"@antora/cli\": \"3.1.2\",\n    \"@antora/site-generator\": \"3.1.2\",\n    \"@antora/lunr-extension\": \"^1.0.0-alpha.8\"\n  },\n  \"scripts\": {\n    \"local-docs\": \"npx antora --fetch doc/embedded.yml\",\n    \"hosted-docs\": \"npx antora --fetch doc/github-actions.yml\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/Deep-Symmetry/afterglow.git\"\n  },\n \"author\": {\n    \"name\": \"James Elliott\",\n    \"email\": \"james@deepsymmetry.org\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/Deep-Symmetry/aferglow/issues\"\n  },\n  \"homepage\": \"https://github.com/Deep-Symmetry/afterglow#readme\"\n}\n"
  },
  {
    "path": "project.clj",
    "content": "(defproject afterglow :lein-v\n  :description \"A live-coding environment for light shows, built on the Open Lighting Architecture, using bits of Overtone.\"\n  :url \"https://github.com/Deep-Symmetry/afterglow\"\n  :license {:name \"Eclipse Public License 2.0\"\n            :url  \"https://www.eclipse.org/legal/epl-2.0/\"}\n  :jvm-opts [\"-Dapple.awt.UIElement=true\"]  ; Suppress dock icon and focus stealing when compiling on a Mac.\n  :dependencies [[org.clojure/clojure \"1.11.4\"]\n                 [org.clojure/core.cache \"1.1.234\"]\n                 [org.clojure/core.async \"1.6.681\" :exclusions [org.clojure/tools.reader]]\n                 [org.clojure/data.json \"2.5.0\"]\n                 [org.clojure/data.zip \"1.1.0\"]\n                 [org.clojure/math.numeric-tower \"0.1.0\"]\n                 [org.clojure/tools.cli \"1.1.230\"]\n                 [org.clojure/tools.nrepl \"0.2.13\"]\n                 [org.clojure/tools.reader \"1.4.2\"]\n                 [org.deepsymmetry/beat-link \"8.0.0-SNAPSHOT\" :exclusions [org.slf4j/slf4j-api]]\n                 [org.deepsymmetry/lib-carabiner \"1.2.0\"]\n                 [org.deepsymmetry/wayang \"0.1.8\"]\n                 [java3d/vecmath \"1.3.1\"]\n                 [java3d/j3d-core \"1.3.1\"]\n                 [java3d/j3d-core-utils \"1.3.1\"]\n                 [overtone/at-at \"1.3.58\"]\n                 [overtone/midi-clj \"0.5.0\"]\n                 [overtone/osc-clj \"0.9.0\"]\n                 [uk.co.xfactory-librarians/coremidi4j \"1.6\"]\n                 [amalloy/ring-buffer \"1.3.1\" :exclusions [org.clojure/tools.reader\n                                                           com.google.protobuf/protobuf-java]]\n                 [com.climate/claypoole \"1.1.4\"]\n                 [org.clojars.brunchboy/protobuf \"0.8.3\"]\n                 [ola-clojure \"0.1.8\" :exclusions [org.clojure/tools.reader]]\n                 [selmer \"1.12.61\" :exclusions [cheshire]]\n                 [com.evocomputing/colors \"1.0.6\"]\n                 [environ \"1.2.0\"]\n                 [camel-snake-kebab \"0.4.3\"]\n                 [com.taoensso/timbre \"5.2.1\"]\n                 [com.taoensso/tufte \"2.2.0\"]\n                 [com.fzakaria/slf4j-timbre \"0.3.21\"]\n                 [com.taoensso/tower \"3.0.2\"]\n                 [com.taoensso/truss \"1.6.0\"]\n                 [markdown-clj \"1.12.1\"]\n                 [ring/ring-core \"1.12.2\"]\n                 [clj-time \"0.15.2\"]\n                 [compojure \"1.7.1\" :exclusions [org.eclipse.jetty/jetty-server\n                                                 ring/ring-core\n                                                 ring/ring-codec]]\n                 [ring/ring-defaults \"0.5.0\"]\n                 [ring/ring-session-timeout \"0.3.0\"]\n                 [ring-middleware-format \"0.7.5\" :exclusions [ring/ring-jetty-adapter\n                                                              cheshire\n                                                              org.clojure/tools.reader\n                                                              org.clojure/java.classpath\n                                                              org.clojure/core.memoize\n                                                              com.fasterxml.jackson.core/jackson-core]]\n                 [metosin/ring-http-response \"0.9.4\"]\n                 [prone \"2021-04-23\"]\n                 [buddy \"2.0.0\"]\n                 [instaparse \"1.5.0\"]\n                 [http-kit \"2.8.0\"]]\n  :repositories {\"sonatype-snapshots\" \"https://oss.sonatype.org/content/repositories/snapshots\"}\n  :main afterglow.core\n  :uberjar-name \"afterglow.jar\"\n\n  ;; Add project name and version information to jar file manifest\n  :manifest {\"Name\"                  ~#(str (clojure.string/replace (:group %) \".\" \"/\")\n                                            \"/\" (:name %) \"/\")\n             \"Package\"               ~#(str (:group %) \".\" (:name %))\n             \"Specification-Title\"   ~#(:name %)\n             \"Specification-Version\" ~#(:version %)}\n  :deploy-repositories [[\"snapshots\" :clojars\n                         \"releases\" :clojars]]\n\n  ;; enable to start the nREPL server when the application launches\n  ;; :env {:repl-port 16002}\n\n  :profiles {:dev     {:dependencies [[ring-mock \"0.1.5\" :exclusions [ring/ring-codec]]\n                                      [ring/ring-devel \"1.12.2\"]]\n                       :repl-options {:init-ns afterglow.examples\n                                      :welcome (println \"afterglow loaded.\")}\n                       :jvm-opts     [\"-XX:-OmitStackTraceInFastThrow\" \"-Dapple.awt.UIElement=true\"]\n                       :env          {:dev \"true\"}}\n             :uberjar {:env        {:production \"true\"}\n                       :prep-tasks [\"javac\"\n                                    \"compile\"]\n                       :aot        :all}\n             :web-docs {:prep-tasks ^:replace []}}\n  :plugins [[lein-codox \"0.10.8\"]\n            [lein-resource \"17.06.1\"]\n            [lein-environ \"1.2.0\"]\n            [lein-shell \"0.5.0\"]\n            [com.roomkey/lein-v \"7.2.0\"]]\n\n  :middleware [lein-v.plugin/middleware]\n\n  :codox {:output-path \"target/codox\"\n          :doc-files   []\n          :source-uri  \"https://github.com/Deep-Symmetry/afterglow/blob/main/{filepath}#L{line}\"\n          :metadata    {:doc/format :markdown}}\n\n  :resource {:resource-paths [[\"target/codox\"\n                               {:target-path  \"target/classes/api_doc\" ; For embedded use\n                                :extra-values {:guide-url \"http:/guide/afterglow/\"}}]\n                              [\"target/codox\"\n                               {:target-path  \"doc/build/site/api\" ; For hosting on the web\n                                :extra-values {:guide-url \"https://afterglow-guide.deepsymmetry.org/afterglow/\"}}]]}\n\n  ;; Perform the tasks which embed the developer guide and api docs before compilation,\n  ;; so they will be available both in development, and in the distributed archive.\n  :prep-tasks [[\"shell\" \"npm\" \"run\" \"local-docs\" ]\n               \"codox\"\n               \"resource\"\n               [\"v\" \"cache\" \"resources/afterglow\" \"edn\"]]\n\n  :min-lein-version \"2.0.0\")\n"
  },
  {
    "path": "resources/afterglow/readme.txt",
    "content": "This file is here to make sure Git creates the parent directory,\nwhich is needed for building the uberjar.\n"
  },
  {
    "path": "resources/docs/docs.md",
    "content": "<div class=\"bs-callout bs-callout-danger\">\n\n### Database Configuration is Required\n\nBefore continuing please follow the steps below to configure your database connection and run the necessary migrations.\n\n* Run `lein ragtime migrate` in the root of the project to create the tables.\n* Restart the application.\n\n</div>\n\n### Managing Your Middleware\n\nRequest middleware functions are located under the `my-app.middleware` namespace.\nA request logging helper called `log-request` has already been defined for you there.\n\nThis namespace also defines two vectors for organizing the middleware called `development-middleware` and `production-middleware`.\nAny middleware that you only wish to run in development mode, such as `log-request`, should be added to the first vector.\n\n### Here are some links to get started\n\n1. [HTML templating](http://www.luminusweb.net/docs/html_templating.md)\n2. [Accessing the database](http://www.luminusweb.net/docs/database.md)\n3. [Serving static resources](http://www.luminusweb.net/docs/static_resources.md)\n4. [Setting response types](http://www.luminusweb.net/docs/responses.md)\n5. [Defining routes](http://www.luminusweb.net/docs/routes.md)\n6. [Adding middleware](http://www.luminusweb.net/docs/middleware.md)\n7. [Sessions and cookies](http://www.luminusweb.net/docs/sessions_cookies.md)\n8. [Security](http://www.luminusweb.net/docs/security.md)\n9. [Deploying the application](http://www.luminusweb.net/docs/deployment.md)\n"
  },
  {
    "path": "resources/public/css/bootstrap-cyborg.css",
    "content": "@import url(\"https://fonts.googleapis.com/css?family=Roboto:400,700\");\n/*!\n * bootswatch v3.3.5\n * Homepage: http://bootswatch.com\n * Copyright 2012-2015 Thomas Park\n * Licensed under MIT\n * Based on Bootstrap\n*/\n/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n  font-family: sans-serif;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n}\nbody {\n  margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block;\n  vertical-align: baseline;\n}\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n[hidden],\ntemplate {\n  display: none;\n}\na {\n  background-color: transparent;\n}\na:active,\na:hover {\n  outline: 0;\n}\nabbr[title] {\n  border-bottom: 1px dotted;\n}\nb,\nstrong {\n  font-weight: bold;\n}\ndfn {\n  font-style: italic;\n}\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\nmark {\n  background: #ff0;\n  color: #000;\n}\nsmall {\n  font-size: 80%;\n}\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\nsup {\n  top: -0.5em;\n}\nsub {\n  bottom: -0.25em;\n}\nimg {\n  border: 0;\n}\nsvg:not(:root) {\n  overflow: hidden;\n}\nfigure {\n  margin: 1em 40px;\n}\nhr {\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n  height: 0;\n}\npre {\n  overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit;\n  font: inherit;\n  margin: 0;\n}\nbutton {\n  overflow: visible;\n}\nbutton,\nselect {\n  text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\ninput {\n  line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n  padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-appearance: textfield;\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n  border: 0;\n  padding: 0;\n}\ntextarea {\n  overflow: auto;\n}\noptgroup {\n  font-weight: bold;\n}\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\ntd,\nth {\n  padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n  *,\n  *:before,\n  *:after {\n    background: transparent !important;\n    color: #000 !important;\n    -webkit-box-shadow: none !important;\n            box-shadow: none !important;\n    text-shadow: none !important;\n  }\n  a,\n  a:visited {\n    text-decoration: underline;\n  }\n  a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n  abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n  a[href^=\"#\"]:after,\n  a[href^=\"javascript:\"]:after {\n    content: \"\";\n  }\n  pre,\n  blockquote {\n    border: 1px solid #999;\n    page-break-inside: avoid;\n  }\n  thead {\n    display: table-header-group;\n  }\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n  img {\n    max-width: 100% !important;\n  }\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n  .navbar {\n    display: none;\n  }\n  .btn > .caret,\n  .dropup > .btn > .caret {\n    border-top-color: #000 !important;\n  }\n  .label {\n    border: 1px solid #000;\n  }\n  .table {\n    border-collapse: collapse !important;\n  }\n  .table td,\n  .table th {\n    background-color: #fff !important;\n  }\n  .table-bordered th,\n  .table-bordered td {\n    border: 1px solid #ddd !important;\n  }\n}\n@font-face {\n  font-family: 'Glyphicons Halflings';\n  src: url('../fonts/glyphicons-halflings-regular.eot');\n  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');\n}\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n  content: \"\\2a\";\n}\n.glyphicon-plus:before {\n  content: \"\\2b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n  content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n  content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n  content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n  content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n  content: \"\\270f\";\n}\n.glyphicon-glass:before {\n  content: \"\\e001\";\n}\n.glyphicon-music:before {\n  content: \"\\e002\";\n}\n.glyphicon-search:before {\n  content: \"\\e003\";\n}\n.glyphicon-heart:before {\n  content: \"\\e005\";\n}\n.glyphicon-star:before {\n  content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n  content: \"\\e007\";\n}\n.glyphicon-user:before {\n  content: \"\\e008\";\n}\n.glyphicon-film:before {\n  content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n  content: \"\\e010\";\n}\n.glyphicon-th:before {\n  content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n  content: \"\\e012\";\n}\n.glyphicon-ok:before {\n  content: \"\\e013\";\n}\n.glyphicon-remove:before {\n  content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n  content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n  content: \"\\e016\";\n}\n.glyphicon-off:before {\n  content: \"\\e017\";\n}\n.glyphicon-signal:before {\n  content: \"\\e018\";\n}\n.glyphicon-cog:before {\n  content: \"\\e019\";\n}\n.glyphicon-trash:before {\n  content: \"\\e020\";\n}\n.glyphicon-home:before {\n  content: \"\\e021\";\n}\n.glyphicon-file:before {\n  content: \"\\e022\";\n}\n.glyphicon-time:before {\n  content: \"\\e023\";\n}\n.glyphicon-road:before {\n  content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n  content: \"\\e025\";\n}\n.glyphicon-download:before {\n  content: \"\\e026\";\n}\n.glyphicon-upload:before {\n  content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n  content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n  content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n  content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n  content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n  content: \"\\e032\";\n}\n.glyphicon-lock:before {\n  content: \"\\e033\";\n}\n.glyphicon-flag:before {\n  content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n  content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n  content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n  content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n  content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n  content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n  content: \"\\e040\";\n}\n.glyphicon-tag:before {\n  content: \"\\e041\";\n}\n.glyphicon-tags:before {\n  content: \"\\e042\";\n}\n.glyphicon-book:before {\n  content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n  content: \"\\e044\";\n}\n.glyphicon-print:before {\n  content: \"\\e045\";\n}\n.glyphicon-camera:before {\n  content: \"\\e046\";\n}\n.glyphicon-font:before {\n  content: \"\\e047\";\n}\n.glyphicon-bold:before {\n  content: \"\\e048\";\n}\n.glyphicon-italic:before {\n  content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n  content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n  content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n  content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n  content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n  content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n  content: \"\\e055\";\n}\n.glyphicon-list:before {\n  content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n  content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n  content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n  content: \"\\e059\";\n}\n.glyphicon-picture:before {\n  content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n  content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n  content: \"\\e063\";\n}\n.glyphicon-tint:before {\n  content: \"\\e064\";\n}\n.glyphicon-edit:before {\n  content: \"\\e065\";\n}\n.glyphicon-share:before {\n  content: \"\\e066\";\n}\n.glyphicon-check:before {\n  content: \"\\e067\";\n}\n.glyphicon-move:before {\n  content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n  content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n  content: \"\\e070\";\n}\n.glyphicon-backward:before {\n  content: \"\\e071\";\n}\n.glyphicon-play:before {\n  content: \"\\e072\";\n}\n.glyphicon-pause:before {\n  content: \"\\e073\";\n}\n.glyphicon-stop:before {\n  content: \"\\e074\";\n}\n.glyphicon-forward:before {\n  content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n  content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n  content: \"\\e077\";\n}\n.glyphicon-eject:before {\n  content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n  content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n  content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n  content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n  content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n  content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n  content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n  content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n  content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n  content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n  content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n  content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n  content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n  content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n  content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n  content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n  content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n  content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n  content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n  content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n  content: \"\\e101\";\n}\n.glyphicon-gift:before {\n  content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n  content: \"\\e103\";\n}\n.glyphicon-fire:before {\n  content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n  content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n  content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n  content: \"\\e107\";\n}\n.glyphicon-plane:before {\n  content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n  content: \"\\e109\";\n}\n.glyphicon-random:before {\n  content: \"\\e110\";\n}\n.glyphicon-comment:before {\n  content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n  content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n  content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n  content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n  content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n  content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n  content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n  content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n  content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n  content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n  content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n  content: \"\\e122\";\n}\n.glyphicon-bell:before {\n  content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n  content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n  content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n  content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n  content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n  content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n  content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n  content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n  content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n  content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n  content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n  content: \"\\e134\";\n}\n.glyphicon-globe:before {\n  content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n  content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n  content: \"\\e137\";\n}\n.glyphicon-filter:before {\n  content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n  content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n  content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n  content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n  content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n  content: \"\\e143\";\n}\n.glyphicon-link:before {\n  content: \"\\e144\";\n}\n.glyphicon-phone:before {\n  content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n  content: \"\\e146\";\n}\n.glyphicon-usd:before {\n  content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n  content: \"\\e149\";\n}\n.glyphicon-sort:before {\n  content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n  content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n  content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n  content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n  content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n  content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n  content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n  content: \"\\e157\";\n}\n.glyphicon-expand:before {\n  content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n  content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n  content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n  content: \"\\e161\";\n}\n.glyphicon-flash:before {\n  content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n  content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n  content: \"\\e164\";\n}\n.glyphicon-record:before {\n  content: \"\\e165\";\n}\n.glyphicon-save:before {\n  content: \"\\e166\";\n}\n.glyphicon-open:before {\n  content: \"\\e167\";\n}\n.glyphicon-saved:before {\n  content: \"\\e168\";\n}\n.glyphicon-import:before {\n  content: \"\\e169\";\n}\n.glyphicon-export:before {\n  content: \"\\e170\";\n}\n.glyphicon-send:before {\n  content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n  content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n  content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n  content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n  content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n  content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n  content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n  content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n  content: \"\\e179\";\n}\n.glyphicon-header:before {\n  content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n  content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n  content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n  content: \"\\e183\";\n}\n.glyphicon-tower:before {\n  content: \"\\e184\";\n}\n.glyphicon-stats:before {\n  content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n  content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n  content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n  content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n  content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n  content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n  content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n  content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n  content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n  content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n  content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n  content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n  content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n  content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n  content: \"\\e200\";\n}\n.glyphicon-cd:before {\n  content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n  content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n  content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n  content: \"\\e204\";\n}\n.glyphicon-copy:before {\n  content: \"\\e205\";\n}\n.glyphicon-paste:before {\n  content: \"\\e206\";\n}\n.glyphicon-alert:before {\n  content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n  content: \"\\e210\";\n}\n.glyphicon-king:before {\n  content: \"\\e211\";\n}\n.glyphicon-queen:before {\n  content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n  content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n  content: \"\\e214\";\n}\n.glyphicon-knight:before {\n  content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n  content: \"\\e216\";\n}\n.glyphicon-tent:before {\n  content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n  content: \"\\e218\";\n}\n.glyphicon-bed:before {\n  content: \"\\e219\";\n}\n.glyphicon-apple:before {\n  content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n  content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n  content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n  content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n  content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n  content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n  content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n  content: \"\\e227\";\n}\n.glyphicon-btc:before {\n  content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n  content: \"\\e227\";\n}\n.glyphicon-yen:before {\n  content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n  content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n  content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n  content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n  content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n  content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n  content: \"\\e232\";\n}\n.glyphicon-education:before {\n  content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n  content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n  content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n  content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n  content: \"\\e237\";\n}\n.glyphicon-oil:before {\n  content: \"\\e238\";\n}\n.glyphicon-grain:before {\n  content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n  content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n  content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n  content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n  content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n  content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n  content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n  content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n  content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n  content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n  content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n  content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n  content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n  content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n  content: \"\\e253\";\n}\n.glyphicon-console:before {\n  content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n  content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n  content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n  content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n  content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n  content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n  content: \"\\e260\";\n}\n* {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n*:before,\n*:after {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\nhtml {\n  font-size: 10px;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n  font-family: \"Roboto\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #888888;\n  background-color: #060606;\n}\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\na {\n  color: #2a9fd6;\n  text-decoration: none;\n}\na:hover,\na:focus {\n  color: #2a9fd6;\n  text-decoration: underline;\n}\na:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\nfigure {\n  margin: 0;\n}\nimg {\n  vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  display: block;\n  max-width: 100%;\n  height: auto;\n}\n.img-rounded {\n  border-radius: 6px;\n}\n.img-thumbnail {\n  padding: 4px;\n  line-height: 1.42857143;\n  background-color: #282828;\n  border: 1px solid #282828;\n  border-radius: 4px;\n  -webkit-transition: all 0.2s ease-in-out;\n  -o-transition: all 0.2s ease-in-out;\n  transition: all 0.2s ease-in-out;\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n}\n.img-circle {\n  border-radius: 50%;\n}\nhr {\n  margin-top: 20px;\n  margin-bottom: 20px;\n  border: 0;\n  border-top: 1px solid #282828;\n}\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n  position: static;\n  width: auto;\n  height: auto;\n  margin: 0;\n  overflow: visible;\n  clip: auto;\n}\n[role=\"button\"] {\n  cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n  font-family: \"Roboto\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-weight: 500;\n  line-height: 1.1;\n  color: #ffffff;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n  font-weight: normal;\n  line-height: 1;\n  color: #888888;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n  margin-top: 20px;\n  margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n  font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n  font-size: 75%;\n}\nh1,\n.h1 {\n  font-size: 56px;\n}\nh2,\n.h2 {\n  font-size: 45px;\n}\nh3,\n.h3 {\n  font-size: 34px;\n}\nh4,\n.h4 {\n  font-size: 24px;\n}\nh5,\n.h5 {\n  font-size: 20px;\n}\nh6,\n.h6 {\n  font-size: 16px;\n}\np {\n  margin: 0 0 10px;\n}\n.lead {\n  margin-bottom: 20px;\n  font-size: 16px;\n  font-weight: 300;\n  line-height: 1.4;\n}\n@media (min-width: 768px) {\n  .lead {\n    font-size: 21px;\n  }\n}\nsmall,\n.small {\n  font-size: 85%;\n}\nmark,\n.mark {\n  background-color: #ff8800;\n  padding: .2em;\n}\n.text-left {\n  text-align: left;\n}\n.text-right {\n  text-align: right;\n}\n.text-center {\n  text-align: center;\n}\n.text-justify {\n  text-align: justify;\n}\n.text-nowrap {\n  white-space: nowrap;\n}\n.text-lowercase {\n  text-transform: lowercase;\n}\n.text-uppercase {\n  text-transform: uppercase;\n}\n.text-capitalize {\n  text-transform: capitalize;\n}\n.text-muted {\n  color: #888888;\n}\n.text-primary {\n  color: #2a9fd6;\n}\na.text-primary:hover,\na.text-primary:focus {\n  color: #2180ac;\n}\n.text-success {\n  color: #ffffff;\n}\na.text-success:hover,\na.text-success:focus {\n  color: #e6e6e6;\n}\n.text-info {\n  color: #ffffff;\n}\na.text-info:hover,\na.text-info:focus {\n  color: #e6e6e6;\n}\n.text-warning {\n  color: #ffffff;\n}\na.text-warning:hover,\na.text-warning:focus {\n  color: #e6e6e6;\n}\n.text-danger {\n  color: #ffffff;\n}\na.text-danger:hover,\na.text-danger:focus {\n  color: #e6e6e6;\n}\n.bg-primary {\n  color: #fff;\n  background-color: #2a9fd6;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n  background-color: #2180ac;\n}\n.bg-success {\n  background-color: #77b300;\n}\na.bg-success:hover,\na.bg-success:focus {\n  background-color: #558000;\n}\n.bg-info {\n  background-color: #9933cc;\n}\na.bg-info:hover,\na.bg-info:focus {\n  background-color: #7a29a3;\n}\n.bg-warning {\n  background-color: #ff8800;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n  background-color: #cc6d00;\n}\n.bg-danger {\n  background-color: #cc0000;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n  background-color: #990000;\n}\n.page-header {\n  padding-bottom: 9px;\n  margin: 40px 0 20px;\n  border-bottom: 1px solid #282828;\n}\nul,\nol {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n  margin-bottom: 0;\n}\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n.list-inline {\n  padding-left: 0;\n  list-style: none;\n  margin-left: -5px;\n}\n.list-inline > li {\n  display: inline-block;\n  padding-left: 5px;\n  padding-right: 5px;\n}\ndl {\n  margin-top: 0;\n  margin-bottom: 20px;\n}\ndt,\ndd {\n  line-height: 1.42857143;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .dl-horizontal dt {\n    float: left;\n    width: 160px;\n    clear: left;\n    text-align: right;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n  .dl-horizontal dd {\n    margin-left: 180px;\n  }\n}\nabbr[title],\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #888888;\n}\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\nblockquote {\n  padding: 10px 20px;\n  margin: 0 0 20px;\n  font-size: 17.5px;\n  border-left: 5px solid #282828;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n  margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n  display: block;\n  font-size: 80%;\n  line-height: 1.42857143;\n  color: #555555;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n  content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid #282828;\n  border-left: 0;\n  text-align: right;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n  content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n  content: '\\00A0 \\2014';\n}\naddress {\n  margin-bottom: 20px;\n  font-style: normal;\n  line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #c7254e;\n  background-color: #f9f2f4;\n  border-radius: 4px;\n}\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #ffffff;\n  background-color: #333333;\n  border-radius: 3px;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n  padding: 0;\n  font-size: 100%;\n  font-weight: bold;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\npre {\n  display: block;\n  padding: 9.5px;\n  margin: 0 0 10px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: #282828;\n  background-color: #f5f5f5;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n}\npre code {\n  padding: 0;\n  font-size: inherit;\n  color: inherit;\n  white-space: pre-wrap;\n  background-color: transparent;\n  border-radius: 0;\n}\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n.container {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n@media (min-width: 768px) {\n  .container {\n    width: 750px;\n  }\n}\n@media (min-width: 992px) {\n  .container {\n    width: 970px;\n  }\n}\n@media (min-width: 1200px) {\n  .container {\n    width: 1170px;\n  }\n}\n.container-fluid {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.row {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n  position: relative;\n  min-height: 1px;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n  float: left;\n}\n.col-xs-12 {\n  width: 100%;\n}\n.col-xs-11 {\n  width: 91.66666667%;\n}\n.col-xs-10 {\n  width: 83.33333333%;\n}\n.col-xs-9 {\n  width: 75%;\n}\n.col-xs-8 {\n  width: 66.66666667%;\n}\n.col-xs-7 {\n  width: 58.33333333%;\n}\n.col-xs-6 {\n  width: 50%;\n}\n.col-xs-5 {\n  width: 41.66666667%;\n}\n.col-xs-4 {\n  width: 33.33333333%;\n}\n.col-xs-3 {\n  width: 25%;\n}\n.col-xs-2 {\n  width: 16.66666667%;\n}\n.col-xs-1 {\n  width: 8.33333333%;\n}\n.col-xs-pull-12 {\n  right: 100%;\n}\n.col-xs-pull-11 {\n  right: 91.66666667%;\n}\n.col-xs-pull-10 {\n  right: 83.33333333%;\n}\n.col-xs-pull-9 {\n  right: 75%;\n}\n.col-xs-pull-8 {\n  right: 66.66666667%;\n}\n.col-xs-pull-7 {\n  right: 58.33333333%;\n}\n.col-xs-pull-6 {\n  right: 50%;\n}\n.col-xs-pull-5 {\n  right: 41.66666667%;\n}\n.col-xs-pull-4 {\n  right: 33.33333333%;\n}\n.col-xs-pull-3 {\n  right: 25%;\n}\n.col-xs-pull-2 {\n  right: 16.66666667%;\n}\n.col-xs-pull-1 {\n  right: 8.33333333%;\n}\n.col-xs-pull-0 {\n  right: auto;\n}\n.col-xs-push-12 {\n  left: 100%;\n}\n.col-xs-push-11 {\n  left: 91.66666667%;\n}\n.col-xs-push-10 {\n  left: 83.33333333%;\n}\n.col-xs-push-9 {\n  left: 75%;\n}\n.col-xs-push-8 {\n  left: 66.66666667%;\n}\n.col-xs-push-7 {\n  left: 58.33333333%;\n}\n.col-xs-push-6 {\n  left: 50%;\n}\n.col-xs-push-5 {\n  left: 41.66666667%;\n}\n.col-xs-push-4 {\n  left: 33.33333333%;\n}\n.col-xs-push-3 {\n  left: 25%;\n}\n.col-xs-push-2 {\n  left: 16.66666667%;\n}\n.col-xs-push-1 {\n  left: 8.33333333%;\n}\n.col-xs-push-0 {\n  left: auto;\n}\n.col-xs-offset-12 {\n  margin-left: 100%;\n}\n.col-xs-offset-11 {\n  margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n  margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n  margin-left: 75%;\n}\n.col-xs-offset-8 {\n  margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n  margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n  margin-left: 50%;\n}\n.col-xs-offset-5 {\n  margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n  margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n  margin-left: 25%;\n}\n.col-xs-offset-2 {\n  margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n  margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n  margin-left: 0%;\n}\n@media (min-width: 768px) {\n  .col-sm-1, .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-sm-10, .col-sm-11, .col-sm-12 {\n    float: left;\n  }\n  .col-sm-12 {\n    width: 100%;\n  }\n  .col-sm-11 {\n    width: 91.66666667%;\n  }\n  .col-sm-10 {\n    width: 83.33333333%;\n  }\n  .col-sm-9 {\n    width: 75%;\n  }\n  .col-sm-8 {\n    width: 66.66666667%;\n  }\n  .col-sm-7 {\n    width: 58.33333333%;\n  }\n  .col-sm-6 {\n    width: 50%;\n  }\n  .col-sm-5 {\n    width: 41.66666667%;\n  }\n  .col-sm-4 {\n    width: 33.33333333%;\n  }\n  .col-sm-3 {\n    width: 25%;\n  }\n  .col-sm-2 {\n    width: 16.66666667%;\n  }\n  .col-sm-1 {\n    width: 8.33333333%;\n  }\n  .col-sm-pull-12 {\n    right: 100%;\n  }\n  .col-sm-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-sm-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-sm-pull-9 {\n    right: 75%;\n  }\n  .col-sm-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-sm-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-sm-pull-6 {\n    right: 50%;\n  }\n  .col-sm-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-sm-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-sm-pull-3 {\n    right: 25%;\n  }\n  .col-sm-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-sm-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-sm-pull-0 {\n    right: auto;\n  }\n  .col-sm-push-12 {\n    left: 100%;\n  }\n  .col-sm-push-11 {\n    left: 91.66666667%;\n  }\n  .col-sm-push-10 {\n    left: 83.33333333%;\n  }\n  .col-sm-push-9 {\n    left: 75%;\n  }\n  .col-sm-push-8 {\n    left: 66.66666667%;\n  }\n  .col-sm-push-7 {\n    left: 58.33333333%;\n  }\n  .col-sm-push-6 {\n    left: 50%;\n  }\n  .col-sm-push-5 {\n    left: 41.66666667%;\n  }\n  .col-sm-push-4 {\n    left: 33.33333333%;\n  }\n  .col-sm-push-3 {\n    left: 25%;\n  }\n  .col-sm-push-2 {\n    left: 16.66666667%;\n  }\n  .col-sm-push-1 {\n    left: 8.33333333%;\n  }\n  .col-sm-push-0 {\n    left: auto;\n  }\n  .col-sm-offset-12 {\n    margin-left: 100%;\n  }\n  .col-sm-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-sm-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-sm-offset-9 {\n    margin-left: 75%;\n  }\n  .col-sm-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-sm-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-sm-offset-6 {\n    margin-left: 50%;\n  }\n  .col-sm-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-sm-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-sm-offset-3 {\n    margin-left: 25%;\n  }\n  .col-sm-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-sm-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-sm-offset-0 {\n    margin-left: 0%;\n  }\n}\n@media (min-width: 992px) {\n  .col-md-1, .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-md-10, .col-md-11, .col-md-12 {\n    float: left;\n  }\n  .col-md-12 {\n    width: 100%;\n  }\n  .col-md-11 {\n    width: 91.66666667%;\n  }\n  .col-md-10 {\n    width: 83.33333333%;\n  }\n  .col-md-9 {\n    width: 75%;\n  }\n  .col-md-8 {\n    width: 66.66666667%;\n  }\n  .col-md-7 {\n    width: 58.33333333%;\n  }\n  .col-md-6 {\n    width: 50%;\n  }\n  .col-md-5 {\n    width: 41.66666667%;\n  }\n  .col-md-4 {\n    width: 33.33333333%;\n  }\n  .col-md-3 {\n    width: 25%;\n  }\n  .col-md-2 {\n    width: 16.66666667%;\n  }\n  .col-md-1 {\n    width: 8.33333333%;\n  }\n  .col-md-pull-12 {\n    right: 100%;\n  }\n  .col-md-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-md-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-md-pull-9 {\n    right: 75%;\n  }\n  .col-md-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-md-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-md-pull-6 {\n    right: 50%;\n  }\n  .col-md-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-md-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-md-pull-3 {\n    right: 25%;\n  }\n  .col-md-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-md-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-md-pull-0 {\n    right: auto;\n  }\n  .col-md-push-12 {\n    left: 100%;\n  }\n  .col-md-push-11 {\n    left: 91.66666667%;\n  }\n  .col-md-push-10 {\n    left: 83.33333333%;\n  }\n  .col-md-push-9 {\n    left: 75%;\n  }\n  .col-md-push-8 {\n    left: 66.66666667%;\n  }\n  .col-md-push-7 {\n    left: 58.33333333%;\n  }\n  .col-md-push-6 {\n    left: 50%;\n  }\n  .col-md-push-5 {\n    left: 41.66666667%;\n  }\n  .col-md-push-4 {\n    left: 33.33333333%;\n  }\n  .col-md-push-3 {\n    left: 25%;\n  }\n  .col-md-push-2 {\n    left: 16.66666667%;\n  }\n  .col-md-push-1 {\n    left: 8.33333333%;\n  }\n  .col-md-push-0 {\n    left: auto;\n  }\n  .col-md-offset-12 {\n    margin-left: 100%;\n  }\n  .col-md-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-md-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-md-offset-9 {\n    margin-left: 75%;\n  }\n  .col-md-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-md-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-md-offset-6 {\n    margin-left: 50%;\n  }\n  .col-md-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-md-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-md-offset-3 {\n    margin-left: 25%;\n  }\n  .col-md-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-md-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-md-offset-0 {\n    margin-left: 0%;\n  }\n}\n@media (min-width: 1200px) {\n  .col-lg-1, .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-lg-10, .col-lg-11, .col-lg-12 {\n    float: left;\n  }\n  .col-lg-12 {\n    width: 100%;\n  }\n  .col-lg-11 {\n    width: 91.66666667%;\n  }\n  .col-lg-10 {\n    width: 83.33333333%;\n  }\n  .col-lg-9 {\n    width: 75%;\n  }\n  .col-lg-8 {\n    width: 66.66666667%;\n  }\n  .col-lg-7 {\n    width: 58.33333333%;\n  }\n  .col-lg-6 {\n    width: 50%;\n  }\n  .col-lg-5 {\n    width: 41.66666667%;\n  }\n  .col-lg-4 {\n    width: 33.33333333%;\n  }\n  .col-lg-3 {\n    width: 25%;\n  }\n  .col-lg-2 {\n    width: 16.66666667%;\n  }\n  .col-lg-1 {\n    width: 8.33333333%;\n  }\n  .col-lg-pull-12 {\n    right: 100%;\n  }\n  .col-lg-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-lg-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-lg-pull-9 {\n    right: 75%;\n  }\n  .col-lg-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-lg-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-lg-pull-6 {\n    right: 50%;\n  }\n  .col-lg-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-lg-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-lg-pull-3 {\n    right: 25%;\n  }\n  .col-lg-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-lg-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-lg-pull-0 {\n    right: auto;\n  }\n  .col-lg-push-12 {\n    left: 100%;\n  }\n  .col-lg-push-11 {\n    left: 91.66666667%;\n  }\n  .col-lg-push-10 {\n    left: 83.33333333%;\n  }\n  .col-lg-push-9 {\n    left: 75%;\n  }\n  .col-lg-push-8 {\n    left: 66.66666667%;\n  }\n  .col-lg-push-7 {\n    left: 58.33333333%;\n  }\n  .col-lg-push-6 {\n    left: 50%;\n  }\n  .col-lg-push-5 {\n    left: 41.66666667%;\n  }\n  .col-lg-push-4 {\n    left: 33.33333333%;\n  }\n  .col-lg-push-3 {\n    left: 25%;\n  }\n  .col-lg-push-2 {\n    left: 16.66666667%;\n  }\n  .col-lg-push-1 {\n    left: 8.33333333%;\n  }\n  .col-lg-push-0 {\n    left: auto;\n  }\n  .col-lg-offset-12 {\n    margin-left: 100%;\n  }\n  .col-lg-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-lg-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-lg-offset-9 {\n    margin-left: 75%;\n  }\n  .col-lg-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-lg-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-lg-offset-6 {\n    margin-left: 50%;\n  }\n  .col-lg-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-lg-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-lg-offset-3 {\n    margin-left: 25%;\n  }\n  .col-lg-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-lg-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-lg-offset-0 {\n    margin-left: 0%;\n  }\n}\ntable {\n  background-color: #181818;\n}\ncaption {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  color: #888888;\n  text-align: left;\n}\nth {\n  text-align: left;\n}\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n  padding: 8px;\n  line-height: 1.42857143;\n  vertical-align: top;\n  border-top: 1px solid #282828;\n}\n.table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #282828;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n  border-top: 0;\n}\n.table > tbody + tbody {\n  border-top: 2px solid #282828;\n}\n.table .table {\n  background-color: #060606;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n  padding: 5px;\n}\n.table-bordered {\n  border: 1px solid #282828;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n  border: 1px solid #282828;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n  border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n  background-color: #080808;\n}\n.table-hover > tbody > tr:hover {\n  background-color: #282828;\n}\ntable col[class*=\"col-\"] {\n  position: static;\n  float: none;\n  display: table-column;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n  position: static;\n  float: none;\n  display: table-cell;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n  background-color: #282828;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n  background-color: #1b1b1b;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n  background-color: #77b300;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n  background-color: #669a00;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n  background-color: #9933cc;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n  background-color: #8a2eb8;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n  background-color: #ff8800;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n  background-color: #e67a00;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n  background-color: #cc0000;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n  background-color: #b30000;\n}\n.table-responsive {\n  overflow-x: auto;\n  min-height: 0.01%;\n}\n@media screen and (max-width: 767px) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: 15px;\n    overflow-y: hidden;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #282828;\n  }\n  .table-responsive > .table {\n    margin-bottom: 0;\n  }\n  .table-responsive > .table > thead > tr > th,\n  .table-responsive > .table > tbody > tr > th,\n  .table-responsive > .table > tfoot > tr > th,\n  .table-responsive > .table > thead > tr > td,\n  .table-responsive > .table > tbody > tr > td,\n  .table-responsive > .table > tfoot > tr > td {\n    white-space: nowrap;\n  }\n  .table-responsive > .table-bordered {\n    border: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:first-child,\n  .table-responsive > .table-bordered > tbody > tr > th:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n  .table-responsive > .table-bordered > thead > tr > td:first-child,\n  .table-responsive > .table-bordered > tbody > tr > td:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n    border-left: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:last-child,\n  .table-responsive > .table-bordered > tbody > tr > th:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n  .table-responsive > .table-bordered > thead > tr > td:last-child,\n  .table-responsive > .table-bordered > tbody > tr > td:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n    border-right: 0;\n  }\n  .table-responsive > .table-bordered > tbody > tr:last-child > th,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n  .table-responsive > .table-bordered > tbody > tr:last-child > td,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n    border-bottom: 0;\n  }\n}\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  min-width: 0;\n}\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 20px;\n  font-size: 21px;\n  line-height: inherit;\n  color: #888888;\n  border: 0;\n  border-bottom: 1px solid #282828;\n}\nlabel {\n  display: inline-block;\n  max-width: 100%;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  line-height: normal;\n}\ninput[type=\"file\"] {\n  display: block;\n}\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\nselect[multiple],\nselect[size] {\n  height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\noutput {\n  display: block;\n  padding-top: 9px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #888888;\n}\n.form-control {\n  display: block;\n  width: 100%;\n  height: 38px;\n  padding: 8px 12px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #888888;\n  background-color: #ffffff;\n  background-image: none;\n  border: 1px solid #282828;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n  border-color: #66afe9;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n  color: #888888;\n  opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n  color: #888888;\n}\n.form-control::-webkit-input-placeholder {\n  color: #888888;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n  background-color: #adafae;\n  opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n  cursor: not-allowed;\n}\ntextarea.form-control {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n  input[type=\"date\"].form-control,\n  input[type=\"time\"].form-control,\n  input[type=\"datetime-local\"].form-control,\n  input[type=\"month\"].form-control {\n    line-height: 38px;\n  }\n  input[type=\"date\"].input-sm,\n  input[type=\"time\"].input-sm,\n  input[type=\"datetime-local\"].input-sm,\n  input[type=\"month\"].input-sm,\n  .input-group-sm input[type=\"date\"],\n  .input-group-sm input[type=\"time\"],\n  .input-group-sm input[type=\"datetime-local\"],\n  .input-group-sm input[type=\"month\"] {\n    line-height: 30px;\n  }\n  input[type=\"date\"].input-lg,\n  input[type=\"time\"].input-lg,\n  input[type=\"datetime-local\"].input-lg,\n  input[type=\"month\"].input-lg,\n  .input-group-lg input[type=\"date\"],\n  .input-group-lg input[type=\"time\"],\n  .input-group-lg input[type=\"datetime-local\"],\n  .input-group-lg input[type=\"month\"] {\n    line-height: 54px;\n  }\n}\n.form-group {\n  margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n  position: relative;\n  display: block;\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n  min-height: 20px;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  position: absolute;\n  margin-left: -20px;\n  margin-top: 4px \\9;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n  position: relative;\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n  cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n  cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n  cursor: not-allowed;\n}\n.form-control-static {\n  padding-top: 9px;\n  padding-bottom: 9px;\n  margin-bottom: 0;\n  min-height: 34px;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n  padding-left: 0;\n  padding-right: 0;\n}\n.input-sm {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-sm {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n  height: auto;\n}\n.form-group-sm .form-control {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.form-group-sm select.form-control {\n  height: 30px;\n  line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n  height: auto;\n}\n.form-group-sm .form-control-static {\n  height: 30px;\n  min-height: 32px;\n  padding: 6px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.input-lg {\n  height: 54px;\n  padding: 14px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-lg {\n  height: 54px;\n  line-height: 54px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n  height: auto;\n}\n.form-group-lg .form-control {\n  height: 54px;\n  padding: 14px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.form-group-lg select.form-control {\n  height: 54px;\n  line-height: 54px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n  height: auto;\n}\n.form-group-lg .form-control-static {\n  height: 54px;\n  min-height: 38px;\n  padding: 15px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.has-feedback {\n  position: relative;\n}\n.has-feedback .form-control {\n  padding-right: 47.5px;\n}\n.form-control-feedback {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 2;\n  display: block;\n  width: 38px;\n  height: 38px;\n  line-height: 38px;\n  text-align: center;\n  pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n  width: 54px;\n  height: 54px;\n  line-height: 54px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n  width: 30px;\n  height: 30px;\n  line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n  color: #ffffff;\n}\n.has-success .form-control {\n  border-color: #ffffff;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n  border-color: #e6e6e6;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;\n}\n.has-success .input-group-addon {\n  color: #ffffff;\n  border-color: #ffffff;\n  background-color: #77b300;\n}\n.has-success .form-control-feedback {\n  color: #ffffff;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n  color: #ffffff;\n}\n.has-warning .form-control {\n  border-color: #ffffff;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n  border-color: #e6e6e6;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;\n}\n.has-warning .input-group-addon {\n  color: #ffffff;\n  border-color: #ffffff;\n  background-color: #ff8800;\n}\n.has-warning .form-control-feedback {\n  color: #ffffff;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n  color: #ffffff;\n}\n.has-error .form-control {\n  border-color: #ffffff;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n  border-color: #e6e6e6;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;\n}\n.has-error .input-group-addon {\n  color: #ffffff;\n  border-color: #ffffff;\n  background-color: #cc0000;\n}\n.has-error .form-control-feedback {\n  color: #ffffff;\n}\n.has-feedback label ~ .form-control-feedback {\n  top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n  top: 0;\n}\n.help-block {\n  display: block;\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: #c8c8c8;\n}\n@media (min-width: 768px) {\n  .form-inline .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .form-inline .form-control-static {\n    display: inline-block;\n  }\n  .form-inline .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .form-inline .input-group .input-group-addon,\n  .form-inline .input-group .input-group-btn,\n  .form-inline .input-group .form-control {\n    width: auto;\n  }\n  .form-inline .input-group > .form-control {\n    width: 100%;\n  }\n  .form-inline .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio,\n  .form-inline .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio label,\n  .form-inline .checkbox label {\n    padding-left: 0;\n  }\n  .form-inline .radio input[type=\"radio\"],\n  .form-inline .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .form-inline .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  margin-top: 0;\n  margin-bottom: 0;\n  padding-top: 9px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n  min-height: 29px;\n}\n.form-horizontal .form-group {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .control-label {\n    text-align: right;\n    margin-bottom: 0;\n    padding-top: 9px;\n  }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n  right: 15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-lg .control-label {\n    padding-top: 19.6666662px;\n    font-size: 18px;\n  }\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-sm .control-label {\n    padding-top: 6px;\n    font-size: 12px;\n  }\n}\n.btn {\n  display: inline-block;\n  margin-bottom: 0;\n  font-weight: normal;\n  text-align: center;\n  vertical-align: middle;\n  -ms-touch-action: manipulation;\n      touch-action: manipulation;\n  cursor: pointer;\n  background-image: none;\n  border: 1px solid transparent;\n  white-space: nowrap;\n  padding: 8px 12px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  border-radius: 4px;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n  color: #ffffff;\n  text-decoration: none;\n}\n.btn:active,\n.btn.active {\n  outline: 0;\n  background-image: none;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n  cursor: not-allowed;\n  opacity: 0.65;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n  pointer-events: none;\n}\n.btn-default {\n  color: #ffffff;\n  background-color: #424242;\n  border-color: #424242;\n}\n.btn-default:focus,\n.btn-default.focus {\n  color: #ffffff;\n  background-color: #282828;\n  border-color: #020202;\n}\n.btn-default:hover {\n  color: #ffffff;\n  background-color: #282828;\n  border-color: #232323;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  color: #ffffff;\n  background-color: #282828;\n  border-color: #232323;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n  color: #ffffff;\n  background-color: #161616;\n  border-color: #020202;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  background-image: none;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n  background-color: #424242;\n  border-color: #424242;\n}\n.btn-default .badge {\n  color: #424242;\n  background-color: #ffffff;\n}\n.btn-primary {\n  color: #ffffff;\n  background-color: #2a9fd6;\n  border-color: #2a9fd6;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n  color: #ffffff;\n  background-color: #2180ac;\n  border-color: #15506c;\n}\n.btn-primary:hover {\n  color: #ffffff;\n  background-color: #2180ac;\n  border-color: #1f79a3;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  color: #ffffff;\n  background-color: #2180ac;\n  border-color: #1f79a3;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n  color: #ffffff;\n  background-color: #1b698e;\n  border-color: #15506c;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  background-image: none;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n  background-color: #2a9fd6;\n  border-color: #2a9fd6;\n}\n.btn-primary .badge {\n  color: #2a9fd6;\n  background-color: #ffffff;\n}\n.btn-success {\n  color: #ffffff;\n  background-color: #77b300;\n  border-color: #77b300;\n}\n.btn-success:focus,\n.btn-success.focus {\n  color: #ffffff;\n  background-color: #558000;\n  border-color: #223300;\n}\n.btn-success:hover {\n  color: #ffffff;\n  background-color: #558000;\n  border-color: #4e7600;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  color: #ffffff;\n  background-color: #558000;\n  border-color: #4e7600;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n  color: #ffffff;\n  background-color: #3d5c00;\n  border-color: #223300;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  background-image: none;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n  background-color: #77b300;\n  border-color: #77b300;\n}\n.btn-success .badge {\n  color: #77b300;\n  background-color: #ffffff;\n}\n.btn-info {\n  color: #ffffff;\n  background-color: #9933cc;\n  border-color: #9933cc;\n}\n.btn-info:focus,\n.btn-info.focus {\n  color: #ffffff;\n  background-color: #7a29a3;\n  border-color: #4c1966;\n}\n.btn-info:hover {\n  color: #ffffff;\n  background-color: #7a29a3;\n  border-color: #74279b;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  color: #ffffff;\n  background-color: #7a29a3;\n  border-color: #74279b;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n  color: #ffffff;\n  background-color: #652287;\n  border-color: #4c1966;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  background-image: none;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n  background-color: #9933cc;\n  border-color: #9933cc;\n}\n.btn-info .badge {\n  color: #9933cc;\n  background-color: #ffffff;\n}\n.btn-warning {\n  color: #ffffff;\n  background-color: #ff8800;\n  border-color: #ff8800;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n  color: #ffffff;\n  background-color: #cc6d00;\n  border-color: #804400;\n}\n.btn-warning:hover {\n  color: #ffffff;\n  background-color: #cc6d00;\n  border-color: #c26700;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  color: #ffffff;\n  background-color: #cc6d00;\n  border-color: #c26700;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n  color: #ffffff;\n  background-color: #a85a00;\n  border-color: #804400;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  background-image: none;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n  background-color: #ff8800;\n  border-color: #ff8800;\n}\n.btn-warning .badge {\n  color: #ff8800;\n  background-color: #ffffff;\n}\n.btn-danger {\n  color: #ffffff;\n  background-color: #cc0000;\n  border-color: #cc0000;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n  color: #ffffff;\n  background-color: #990000;\n  border-color: #4d0000;\n}\n.btn-danger:hover {\n  color: #ffffff;\n  background-color: #990000;\n  border-color: #8f0000;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  color: #ffffff;\n  background-color: #990000;\n  border-color: #8f0000;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n  color: #ffffff;\n  background-color: #750000;\n  border-color: #4d0000;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  background-image: none;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n  background-color: #cc0000;\n  border-color: #cc0000;\n}\n.btn-danger .badge {\n  color: #cc0000;\n  background-color: #ffffff;\n}\n.btn-link {\n  color: #2a9fd6;\n  font-weight: normal;\n  border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n  background-color: transparent;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n  border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n  color: #2a9fd6;\n  text-decoration: underline;\n  background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n  color: #888888;\n  text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n  padding: 14px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n  padding: 1px 5px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-block {\n  display: block;\n  width: 100%;\n}\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n  width: 100%;\n}\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity 0.15s linear;\n  -o-transition: opacity 0.15s linear;\n  transition: opacity 0.15s linear;\n}\n.fade.in {\n  opacity: 1;\n}\n.collapse {\n  display: none;\n}\n.collapse.in {\n  display: block;\n}\ntr.collapse.in {\n  display: table-row;\n}\ntbody.collapse.in {\n  display: table-row-group;\n}\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition-property: height, visibility;\n  -o-transition-property: height, visibility;\n     transition-property: height, visibility;\n  -webkit-transition-duration: 0.35s;\n  -o-transition-duration: 0.35s;\n     transition-duration: 0.35s;\n  -webkit-transition-timing-function: ease;\n  -o-transition-timing-function: ease;\n     transition-timing-function: ease;\n}\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top: 4px dashed;\n  border-top: 4px solid \\9;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n  position: relative;\n}\n.dropdown-toggle:focus {\n  outline: 0;\n}\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  list-style: none;\n  font-size: 14px;\n  text-align: left;\n  background-color: #222222;\n  border: 1px solid #444444;\n  border: 1px solid rgba(255, 255, 255, 0.1);\n  border-radius: 4px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n}\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu .divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: rgba(255, 255, 255, 0.1);\n}\n.dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 1.42857143;\n  color: #ffffff;\n  white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  text-decoration: none;\n  color: #ffffff;\n  background-color: #2a9fd6;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  color: #ffffff;\n  text-decoration: none;\n  outline: 0;\n  background-color: #2a9fd6;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  color: #888888;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  cursor: not-allowed;\n}\n.open > .dropdown-menu {\n  display: block;\n}\n.open > a {\n  outline: 0;\n}\n.dropdown-menu-right {\n  left: auto;\n  right: 0;\n}\n.dropdown-menu-left {\n  left: 0;\n  right: auto;\n}\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.42857143;\n  color: #888888;\n  white-space: nowrap;\n}\n.dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: 990;\n}\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  border-top: 0;\n  border-bottom: 4px dashed;\n  border-bottom: 4px solid \\9;\n  content: \"\";\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n  .navbar-right .dropdown-menu {\n    left: auto;\n    right: 0;\n  }\n  .navbar-right .dropdown-menu-left {\n    left: 0;\n    right: auto;\n  }\n}\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n  position: relative;\n  float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n  z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n  margin-left: -1px;\n}\n.btn-toolbar {\n  margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n  float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n  margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n.btn-group > .btn:first-child {\n  margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n  padding-left: 8px;\n  padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n.btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.btn .caret {\n  margin-left: 0;\n}\n.btn-lg .caret {\n  border-width: 5px 5px 0;\n  border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n  border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n  display: block;\n  float: none;\n  width: 100%;\n  max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n  float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n  margin-top: -1px;\n  margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n  border-bottom-left-radius: 4px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n  float: none;\n  display: table-cell;\n  width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n  width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n  left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n  position: absolute;\n  clip: rect(0, 0, 0, 0);\n  pointer-events: none;\n}\n.input-group {\n  position: relative;\n  display: table;\n  border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n  float: none;\n  padding-left: 0;\n  padding-right: 0;\n}\n.input-group .form-control {\n  position: relative;\n  z-index: 2;\n  float: left;\n  width: 100%;\n  margin-bottom: 0;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  height: 54px;\n  padding: 14px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n  height: 54px;\n  line-height: 54px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n.input-group-addon {\n  padding: 8px 12px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1;\n  color: #888888;\n  text-align: center;\n  background-color: #adafae;\n  border: 1px solid #282828;\n  border-radius: 4px;\n}\n.input-group-addon.input-sm {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 3px;\n}\n.input-group-addon.input-lg {\n  padding: 14px 16px;\n  font-size: 18px;\n  border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n  margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n.input-group-btn {\n  position: relative;\n  font-size: 0;\n  white-space: nowrap;\n}\n.input-group-btn > .btn {\n  position: relative;\n}\n.input-group-btn > .btn + .btn {\n  margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n  z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n  margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n  z-index: 2;\n  margin-left: -1px;\n}\n.nav {\n  margin-bottom: 0;\n  padding-left: 0;\n  list-style: none;\n}\n.nav > li {\n  position: relative;\n  display: block;\n}\n.nav > li > a {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n  text-decoration: none;\n  background-color: #222222;\n}\n.nav > li.disabled > a {\n  color: #888888;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n  color: #888888;\n  text-decoration: none;\n  background-color: transparent;\n  cursor: not-allowed;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n  background-color: #222222;\n  border-color: #2a9fd6;\n}\n.nav .nav-divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.nav > li > a > img {\n  max-width: none;\n}\n.nav-tabs {\n  border-bottom: 1px solid #282828;\n}\n.nav-tabs > li {\n  float: left;\n  margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n  margin-right: 2px;\n  line-height: 1.42857143;\n  border: 1px solid transparent;\n  border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n  border-color: transparent transparent #282828;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n  color: #ffffff;\n  background-color: #2a9fd6;\n  border: 1px solid #282828;\n  border-bottom-color: transparent;\n  cursor: default;\n}\n.nav-tabs.nav-justified {\n  width: 100%;\n  border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n  float: none;\n}\n.nav-tabs.nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-tabs.nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs.nav-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n  border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs.nav-justified > .active > a,\n  .nav-tabs.nav-justified > .active > a:hover,\n  .nav-tabs.nav-justified > .active > a:focus {\n    border-bottom-color: #060606;\n  }\n}\n.nav-pills > li {\n  float: left;\n}\n.nav-pills > li > a {\n  border-radius: 4px;\n}\n.nav-pills > li + li {\n  margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n  color: #ffffff;\n  background-color: #2a9fd6;\n}\n.nav-stacked > li {\n  float: none;\n}\n.nav-stacked > li + li {\n  margin-top: 2px;\n  margin-left: 0;\n}\n.nav-justified {\n  width: 100%;\n}\n.nav-justified > li {\n  float: none;\n}\n.nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs-justified {\n  border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n  border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs-justified > .active > a,\n  .nav-tabs-justified > .active > a:hover,\n  .nav-tabs-justified > .active > a:focus {\n    border-bottom-color: #060606;\n  }\n}\n.tab-content > .tab-pane {\n  display: none;\n}\n.tab-content > .active {\n  display: block;\n}\n.nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.navbar {\n  position: relative;\n  min-height: 50px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n  .navbar {\n    border-radius: 4px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-header {\n    float: left;\n  }\n}\n.navbar-collapse {\n  overflow-x: visible;\n  padding-right: 15px;\n  padding-left: 15px;\n  border-top: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n  -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n  overflow-y: auto;\n}\n@media (min-width: 768px) {\n  .navbar-collapse {\n    width: auto;\n    border-top: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .navbar-collapse.collapse {\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n  .navbar-collapse.in {\n    overflow-y: visible;\n  }\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-static-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    padding-left: 0;\n    padding-right: 0;\n  }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n  max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    max-height: 200px;\n  }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .container > .navbar-header,\n  .container-fluid > .navbar-header,\n  .container > .navbar-collapse,\n  .container-fluid > .navbar-collapse {\n    margin-right: 0;\n    margin-left: 0;\n  }\n}\n.navbar-static-top {\n  z-index: 1000;\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .navbar-static-top {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n}\n@media (min-width: 768px) {\n  .navbar-fixed-top,\n  .navbar-fixed-bottom {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0;\n  border-width: 1px 0 0;\n}\n.navbar-brand {\n  float: left;\n  padding: 15px 15px;\n  font-size: 18px;\n  line-height: 20px;\n  height: 50px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n  text-decoration: none;\n}\n.navbar-brand > img {\n  display: block;\n}\n@media (min-width: 768px) {\n  .navbar > .container .navbar-brand,\n  .navbar > .container-fluid .navbar-brand {\n    margin-left: -15px;\n  }\n}\n.navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: 15px;\n  padding: 9px 10px;\n  margin-top: 8px;\n  margin-bottom: 8px;\n  background-color: transparent;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.navbar-toggle:focus {\n  outline: 0;\n}\n.navbar-toggle .icon-bar {\n  display: block;\n  width: 22px;\n  height: 2px;\n  border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n  margin-top: 4px;\n}\n@media (min-width: 768px) {\n  .navbar-toggle {\n    display: none;\n  }\n}\n.navbar-nav {\n  margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 20px;\n}\n@media (max-width: 767px) {\n  .navbar-nav .open .dropdown-menu {\n    position: static;\n    float: none;\n    width: auto;\n    margin-top: 0;\n    background-color: transparent;\n    border: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .navbar-nav .open .dropdown-menu > li > a,\n  .navbar-nav .open .dropdown-menu .dropdown-header {\n    padding: 5px 15px 5px 25px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a {\n    line-height: 20px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-nav .open .dropdown-menu > li > a:focus {\n    background-image: none;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-nav {\n    float: left;\n    margin: 0;\n  }\n  .navbar-nav > li {\n    float: left;\n  }\n  .navbar-nav > li > a {\n    padding-top: 15px;\n    padding-bottom: 15px;\n  }\n}\n.navbar-form {\n  margin-left: -15px;\n  margin-right: -15px;\n  padding: 10px 15px;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  margin-top: 6px;\n  margin-bottom: 6px;\n}\n@media (min-width: 768px) {\n  .navbar-form .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control-static {\n    display: inline-block;\n  }\n  .navbar-form .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .navbar-form .input-group .input-group-addon,\n  .navbar-form .input-group .input-group-btn,\n  .navbar-form .input-group .form-control {\n    width: auto;\n  }\n  .navbar-form .input-group > .form-control {\n    width: 100%;\n  }\n  .navbar-form .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio,\n  .navbar-form .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio label,\n  .navbar-form .checkbox label {\n    padding-left: 0;\n  }\n  .navbar-form .radio input[type=\"radio\"],\n  .navbar-form .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .navbar-form .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n@media (max-width: 767px) {\n  .navbar-form .form-group {\n    margin-bottom: 5px;\n  }\n  .navbar-form .form-group:last-child {\n    margin-bottom: 0;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-form {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n  }\n}\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  margin-bottom: 0;\n  border-top-right-radius: 4px;\n  border-top-left-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.navbar-btn {\n  margin-top: 6px;\n  margin-bottom: 6px;\n}\n.navbar-btn.btn-sm {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n  margin-top: 14px;\n  margin-bottom: 14px;\n}\n.navbar-text {\n  margin-top: 15px;\n  margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n  .navbar-text {\n    float: left;\n    margin-left: 15px;\n    margin-right: 15px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-left {\n    float: left !important;\n  }\n  .navbar-right {\n    float: right !important;\n    margin-right: -15px;\n  }\n  .navbar-right ~ .navbar-right {\n    margin-right: 0;\n  }\n}\n.navbar-default {\n  background-color: #060606;\n  border-color: #282828;\n}\n.navbar-default .navbar-brand {\n  color: #ffffff;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.navbar-default .navbar-text {\n  color: #888888;\n}\n.navbar-default .navbar-nav > li > a {\n  color: #888888;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n  color: #888888;\n  background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n  border-color: #282828;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n  background-color: #282828;\n}\n.navbar-default .navbar-toggle .icon-bar {\n  background-color: #cccccc;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n  border-color: #282828;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n  background-color: transparent;\n  color: #ffffff;\n}\n@media (max-width: 767px) {\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #888888;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #ffffff;\n    background-color: transparent;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #ffffff;\n    background-color: transparent;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #888888;\n    background-color: transparent;\n  }\n}\n.navbar-default .navbar-link {\n  color: #888888;\n}\n.navbar-default .navbar-link:hover {\n  color: #ffffff;\n}\n.navbar-default .btn-link {\n  color: #888888;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n  color: #ffffff;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n  color: #888888;\n}\n.navbar-inverse {\n  background-color: #222222;\n  border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n  color: #ffffff;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n  color: #888888;\n}\n.navbar-inverse .navbar-nav > li > a {\n  color: #888888;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n  color: #aaaaaa;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n  border-color: #333333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n  background-color: #333333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #ffffff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n  border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n  background-color: transparent;\n  color: #ffffff;\n}\n@media (max-width: 767px) {\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n    background-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n    color: #888888;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #ffffff;\n    background-color: transparent;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #ffffff;\n    background-color: transparent;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #aaaaaa;\n    background-color: transparent;\n  }\n}\n.navbar-inverse .navbar-link {\n  color: #888888;\n}\n.navbar-inverse .navbar-link:hover {\n  color: #ffffff;\n}\n.navbar-inverse .btn-link {\n  color: #888888;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n  color: #ffffff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n  color: #aaaaaa;\n}\n.breadcrumb {\n  padding: 8px 15px;\n  margin-bottom: 20px;\n  list-style: none;\n  background-color: #222222;\n  border-radius: 4px;\n}\n.breadcrumb > li {\n  display: inline-block;\n}\n.breadcrumb > li + li:before {\n  content: \"/\\00a0\";\n  padding: 0 5px;\n  color: #ffffff;\n}\n.breadcrumb > .active {\n  color: #888888;\n}\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 20px 0;\n  border-radius: 4px;\n}\n.pagination > li {\n  display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n  position: relative;\n  float: left;\n  padding: 8px 12px;\n  line-height: 1.42857143;\n  text-decoration: none;\n  color: #ffffff;\n  background-color: #222222;\n  border: 1px solid #282828;\n  margin-left: -1px;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n  margin-left: 0;\n  border-bottom-left-radius: 4px;\n  border-top-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n  border-bottom-right-radius: 4px;\n  border-top-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n  z-index: 3;\n  color: #ffffff;\n  background-color: #2a9fd6;\n  border-color: transparent;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n  z-index: 2;\n  color: #ffffff;\n  background-color: #2a9fd6;\n  border-color: transparent;\n  cursor: default;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n  color: #888888;\n  background-color: #222222;\n  border-color: #282828;\n  cursor: not-allowed;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n  padding: 14px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n  border-bottom-left-radius: 6px;\n  border-top-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n  border-bottom-right-radius: 6px;\n  border-top-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n  border-bottom-left-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n  border-bottom-right-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.pager {\n  padding-left: 0;\n  margin: 20px 0;\n  list-style: none;\n  text-align: center;\n}\n.pager li {\n  display: inline;\n}\n.pager li > a,\n.pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #222222;\n  border: 1px solid #282828;\n  border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n  text-decoration: none;\n  background-color: #2a9fd6;\n}\n.pager .next > a,\n.pager .next > span {\n  float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n  float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n  color: #888888;\n  background-color: #222222;\n  cursor: not-allowed;\n}\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: #ffffff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.label:empty {\n  display: none;\n}\n.btn .label {\n  position: relative;\n  top: -1px;\n}\n.label-default {\n  background-color: #424242;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n  background-color: #282828;\n}\n.label-primary {\n  background-color: #2a9fd6;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n  background-color: #2180ac;\n}\n.label-success {\n  background-color: #77b300;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n  background-color: #558000;\n}\n.label-info {\n  background-color: #9933cc;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n  background-color: #7a29a3;\n}\n.label-warning {\n  background-color: #ff8800;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n  background-color: #cc6d00;\n}\n.label-danger {\n  background-color: #cc0000;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n  background-color: #990000;\n}\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: bold;\n  color: #ffffff;\n  line-height: 1;\n  vertical-align: middle;\n  white-space: nowrap;\n  text-align: center;\n  background-color: #2a9fd6;\n  border-radius: 10px;\n}\n.badge:empty {\n  display: none;\n}\n.btn .badge {\n  position: relative;\n  top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n  top: 0;\n  padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: #2a9fd6;\n  background-color: #ffffff;\n}\n.list-group-item > .badge {\n  float: right;\n}\n.list-group-item > .badge + .badge {\n  margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n.jumbotron {\n  padding-top: 30px;\n  padding-bottom: 30px;\n  margin-bottom: 30px;\n  color: inherit;\n  background-color: #151515;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n  color: inherit;\n}\n.jumbotron p {\n  margin-bottom: 15px;\n  font-size: 21px;\n  font-weight: 200;\n}\n.jumbotron > hr {\n  border-top-color: #000000;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n  border-radius: 6px;\n}\n.jumbotron .container {\n  max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n  .jumbotron {\n    padding-top: 48px;\n    padding-bottom: 48px;\n  }\n  .container .jumbotron,\n  .container-fluid .jumbotron {\n    padding-left: 60px;\n    padding-right: 60px;\n  }\n  .jumbotron h1,\n  .jumbotron .h1 {\n    font-size: 63px;\n  }\n}\n.thumbnail {\n  display: block;\n  padding: 4px;\n  margin-bottom: 20px;\n  line-height: 1.42857143;\n  background-color: #282828;\n  border: 1px solid #282828;\n  border-radius: 4px;\n  -webkit-transition: border 0.2s ease-in-out;\n  -o-transition: border 0.2s ease-in-out;\n  transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n  margin-left: auto;\n  margin-right: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #2a9fd6;\n}\n.thumbnail .caption {\n  padding: 9px;\n  color: #888888;\n}\n.alert {\n  padding: 15px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.alert h4 {\n  margin-top: 0;\n  color: inherit;\n}\n.alert .alert-link {\n  font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n  margin-bottom: 0;\n}\n.alert > p + p {\n  margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n  padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  color: inherit;\n}\n.alert-success {\n  background-color: #77b300;\n  border-color: #809a00;\n  color: #ffffff;\n}\n.alert-success hr {\n  border-top-color: #6a8000;\n}\n.alert-success .alert-link {\n  color: #e6e6e6;\n}\n.alert-info {\n  background-color: #9933cc;\n  border-color: #6e2caf;\n  color: #ffffff;\n}\n.alert-info hr {\n  border-top-color: #61279b;\n}\n.alert-info .alert-link {\n  color: #e6e6e6;\n}\n.alert-warning {\n  background-color: #ff8800;\n  border-color: #f05800;\n  color: #ffffff;\n}\n.alert-warning hr {\n  border-top-color: #d64f00;\n}\n.alert-warning .alert-link {\n  color: #e6e6e6;\n}\n.alert-danger {\n  background-color: #cc0000;\n  border-color: #bd001f;\n  color: #ffffff;\n}\n.alert-danger hr {\n  border-top-color: #a3001b;\n}\n.alert-danger .alert-link {\n  color: #e6e6e6;\n}\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@-o-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n.progress {\n  overflow: hidden;\n  height: 20px;\n  margin-bottom: 20px;\n  background-color: #222222;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #2a9fd6;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-transition: width 0.6s ease;\n  -o-transition: width 0.6s ease;\n  transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  -webkit-background-size: 40px 40px;\n          background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n  -o-animation: progress-bar-stripes 2s linear infinite;\n  animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n  background-color: #77b300;\n}\n.progress-striped .progress-bar-success {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n  background-color: #9933cc;\n}\n.progress-striped .progress-bar-info {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n  background-color: #ff8800;\n}\n.progress-striped .progress-bar-warning {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n  background-color: #cc0000;\n}\n.progress-striped .progress-bar-danger {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n  margin-top: 15px;\n}\n.media:first-child {\n  margin-top: 0;\n}\n.media,\n.media-body {\n  zoom: 1;\n  overflow: hidden;\n}\n.media-body {\n  width: 10000px;\n}\n.media-object {\n  display: block;\n}\n.media-object.img-thumbnail {\n  max-width: none;\n}\n.media-right,\n.media > .pull-right {\n  padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n  padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n  display: table-cell;\n  vertical-align: top;\n}\n.media-middle {\n  vertical-align: middle;\n}\n.media-bottom {\n  vertical-align: bottom;\n}\n.media-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n.list-group {\n  margin-bottom: 20px;\n  padding-left: 0;\n}\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #222222;\n  border: 1px solid #282828;\n}\n.list-group-item:first-child {\n  border-top-right-radius: 4px;\n  border-top-left-radius: 4px;\n}\n.list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\na.list-group-item,\nbutton.list-group-item {\n  color: #888888;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n  color: #ffffff;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n  text-decoration: none;\n  color: #888888;\n  background-color: #484848;\n}\nbutton.list-group-item {\n  width: 100%;\n  text-align: left;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n  background-color: #adafae;\n  color: #888888;\n  cursor: not-allowed;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n  color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n  color: #888888;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  z-index: 2;\n  color: #ffffff;\n  background-color: #2a9fd6;\n  border-color: #2a9fd6;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n  color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n  color: #d5ecf7;\n}\n.list-group-item-success {\n  color: #ffffff;\n  background-color: #77b300;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n  color: #ffffff;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n  color: #ffffff;\n  background-color: #669a00;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n  color: #fff;\n  background-color: #ffffff;\n  border-color: #ffffff;\n}\n.list-group-item-info {\n  color: #ffffff;\n  background-color: #9933cc;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n  color: #ffffff;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n  color: #ffffff;\n  background-color: #8a2eb8;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n  color: #fff;\n  background-color: #ffffff;\n  border-color: #ffffff;\n}\n.list-group-item-warning {\n  color: #ffffff;\n  background-color: #ff8800;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n  color: #ffffff;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n  color: #ffffff;\n  background-color: #e67a00;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n  color: #fff;\n  background-color: #ffffff;\n  border-color: #ffffff;\n}\n.list-group-item-danger {\n  color: #ffffff;\n  background-color: #cc0000;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n  color: #ffffff;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n  color: #ffffff;\n  background-color: #b30000;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n  color: #fff;\n  background-color: #ffffff;\n  border-color: #ffffff;\n}\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n.panel {\n  margin-bottom: 20px;\n  background-color: #222222;\n  border: 1px solid transparent;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n  padding: 15px;\n}\n.panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n  color: inherit;\n}\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: 16px;\n  color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n  color: inherit;\n}\n.panel-footer {\n  padding: 10px 15px;\n  background-color: #3c3c3c;\n  border-top: 1px solid #282828;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n  margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n  border-width: 1px 0;\n  border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n  border-top: 0;\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n  border-bottom: 0;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n  border-top-width: 0;\n}\n.list-group + .panel-footer {\n  border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n  margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n  border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n  border-bottom-left-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n  border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n  border-top: 1px solid #282828;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n  border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n  border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n  border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n  border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n  border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n  border-bottom: 0;\n}\n.panel > .table-responsive {\n  border: 0;\n  margin-bottom: 0;\n}\n.panel-group {\n  margin-bottom: 20px;\n}\n.panel-group .panel {\n  margin-bottom: 0;\n  border-radius: 4px;\n}\n.panel-group .panel + .panel {\n  margin-top: 5px;\n}\n.panel-group .panel-heading {\n  border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n  border-top: 1px solid #282828;\n}\n.panel-group .panel-footer {\n  border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n  border-bottom: 1px solid #282828;\n}\n.panel-default {\n  border-color: #282828;\n}\n.panel-default > .panel-heading {\n  color: #888888;\n  background-color: #3c3c3c;\n  border-color: #282828;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #282828;\n}\n.panel-default > .panel-heading .badge {\n  color: #3c3c3c;\n  background-color: #888888;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #282828;\n}\n.panel-primary {\n  border-color: #2a9fd6;\n}\n.panel-primary > .panel-heading {\n  color: #ffffff;\n  background-color: #2a9fd6;\n  border-color: #2a9fd6;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #2a9fd6;\n}\n.panel-primary > .panel-heading .badge {\n  color: #2a9fd6;\n  background-color: #ffffff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #2a9fd6;\n}\n.panel-success {\n  border-color: #809a00;\n}\n.panel-success > .panel-heading {\n  color: #ffffff;\n  background-color: #77b300;\n  border-color: #809a00;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #809a00;\n}\n.panel-success > .panel-heading .badge {\n  color: #77b300;\n  background-color: #ffffff;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #809a00;\n}\n.panel-info {\n  border-color: #6e2caf;\n}\n.panel-info > .panel-heading {\n  color: #ffffff;\n  background-color: #9933cc;\n  border-color: #6e2caf;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #6e2caf;\n}\n.panel-info > .panel-heading .badge {\n  color: #9933cc;\n  background-color: #ffffff;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #6e2caf;\n}\n.panel-warning {\n  border-color: #f05800;\n}\n.panel-warning > .panel-heading {\n  color: #ffffff;\n  background-color: #ff8800;\n  border-color: #f05800;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #f05800;\n}\n.panel-warning > .panel-heading .badge {\n  color: #ff8800;\n  background-color: #ffffff;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #f05800;\n}\n.panel-danger {\n  border-color: #bd001f;\n}\n.panel-danger > .panel-heading {\n  color: #ffffff;\n  background-color: #cc0000;\n  border-color: #bd001f;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #bd001f;\n}\n.panel-danger > .panel-heading .badge {\n  color: #cc0000;\n  background-color: #ffffff;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #bd001f;\n}\n.embed-responsive {\n  position: relative;\n  display: block;\n  height: 0;\n  padding: 0;\n  overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  height: 100%;\n  width: 100%;\n  border: 0;\n}\n.embed-responsive-16by9 {\n  padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n  padding-bottom: 75%;\n}\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #151515;\n  border: 1px solid #030303;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n  padding: 24px;\n  border-radius: 6px;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: 3px;\n}\n.close {\n  float: right;\n  font-size: 21px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000000;\n  text-shadow: 0 1px 0 #ffffff;\n  opacity: 0.2;\n  filter: alpha(opacity=20);\n}\n.close:hover,\n.close:focus {\n  color: #000000;\n  text-decoration: none;\n  cursor: pointer;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\nbutton.close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n.modal-open {\n  overflow: hidden;\n}\n.modal {\n  display: none;\n  overflow: hidden;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1050;\n  -webkit-overflow-scrolling: touch;\n  outline: 0;\n}\n.modal.fade .modal-dialog {\n  -webkit-transform: translate(0, -25%);\n  -ms-transform: translate(0, -25%);\n  -o-transform: translate(0, -25%);\n  transform: translate(0, -25%);\n  -webkit-transition: -webkit-transform 0.3s ease-out;\n  -o-transition: -o-transform 0.3s ease-out;\n  transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n  -webkit-transform: translate(0, 0);\n  -ms-transform: translate(0, 0);\n  -o-transform: translate(0, 0);\n  transform: translate(0, 0);\n}\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n.modal-content {\n  position: relative;\n  background-color: #202020;\n  border: 1px solid #999999;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  outline: 0;\n}\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000000;\n}\n.modal-backdrop.fade {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n.modal-header {\n  padding: 15px;\n  border-bottom: 1px solid #282828;\n  min-height: 16.42857143px;\n}\n.modal-header .close {\n  margin-top: -2px;\n}\n.modal-title {\n  margin: 0;\n  line-height: 1.42857143;\n}\n.modal-body {\n  position: relative;\n  padding: 20px;\n}\n.modal-footer {\n  padding: 20px;\n  text-align: right;\n  border-top: 1px solid #282828;\n}\n.modal-footer .btn + .btn {\n  margin-left: 5px;\n  margin-bottom: 0;\n}\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n  margin-left: 0;\n}\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n@media (min-width: 768px) {\n  .modal-dialog {\n    width: 600px;\n    margin: 30px auto;\n  }\n  .modal-content {\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n  }\n  .modal-sm {\n    width: 300px;\n  }\n}\n@media (min-width: 992px) {\n  .modal-lg {\n    width: 900px;\n  }\n}\n.tooltip {\n  position: absolute;\n  z-index: 1070;\n  display: block;\n  font-family: \"Roboto\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-style: normal;\n  font-weight: normal;\n  letter-spacing: normal;\n  line-break: auto;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  white-space: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  font-size: 12px;\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.tooltip.in {\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n.tooltip.top {\n  margin-top: -3px;\n  padding: 5px 0;\n}\n.tooltip.right {\n  margin-left: 3px;\n  padding: 0 5px;\n}\n.tooltip.bottom {\n  margin-top: 3px;\n  padding: 5px 0;\n}\n.tooltip.left {\n  margin-left: -3px;\n  padding: 0 5px;\n}\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #000000;\n  border-radius: 4px;\n}\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\n}\n.tooltip.top-left .tooltip-arrow {\n  bottom: 0;\n  right: 5px;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\n}\n.tooltip.top-right .tooltip-arrow {\n  bottom: 0;\n  left: 5px;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\n}\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-width: 5px 5px 5px 0;\n  border-right-color: #000000;\n}\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-width: 5px 0 5px 5px;\n  border-left-color: #000000;\n}\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n  top: 0;\n  right: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n  top: 0;\n  left: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1060;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  font-family: \"Roboto\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-style: normal;\n  font-weight: normal;\n  letter-spacing: normal;\n  line-break: auto;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  white-space: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  font-size: 14px;\n  background-color: #202020;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #999999;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n.popover.top {\n  margin-top: -10px;\n}\n.popover.right {\n  margin-left: 10px;\n}\n.popover.bottom {\n  margin-top: 10px;\n}\n.popover.left {\n  margin-left: -10px;\n}\n.popover-title {\n  margin: 0;\n  padding: 8px 14px;\n  font-size: 14px;\n  background-color: #181818;\n  border-bottom: 1px solid #0b0b0b;\n  border-radius: 5px 5px 0 0;\n}\n.popover-content {\n  padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n  position: absolute;\n  display: block;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.popover > .arrow {\n  border-width: 11px;\n}\n.popover > .arrow:after {\n  border-width: 10px;\n  content: \"\";\n}\n.popover.top > .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-bottom-width: 0;\n  border-top-color: #666666;\n  border-top-color: rgba(0, 0, 0, 0.25);\n  bottom: -11px;\n}\n.popover.top > .arrow:after {\n  content: \" \";\n  bottom: 1px;\n  margin-left: -10px;\n  border-bottom-width: 0;\n  border-top-color: #202020;\n}\n.popover.right > .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-left-width: 0;\n  border-right-color: #666666;\n  border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right > .arrow:after {\n  content: \" \";\n  left: 1px;\n  bottom: -10px;\n  border-left-width: 0;\n  border-right-color: #202020;\n}\n.popover.bottom > .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #666666;\n  border-bottom-color: rgba(0, 0, 0, 0.25);\n  top: -11px;\n}\n.popover.bottom > .arrow:after {\n  content: \" \";\n  top: 1px;\n  margin-left: -10px;\n  border-top-width: 0;\n  border-bottom-color: #202020;\n}\n.popover.left > .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #666666;\n  border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n  content: \" \";\n  right: 1px;\n  border-right-width: 0;\n  border-left-color: #202020;\n  bottom: -10px;\n}\n.carousel {\n  position: relative;\n}\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n}\n.carousel-inner > .item {\n  display: none;\n  position: relative;\n  -webkit-transition: 0.6s ease-in-out left;\n  -o-transition: 0.6s ease-in-out left;\n  transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n  .carousel-inner > .item {\n    -webkit-transition: -webkit-transform 0.6s ease-in-out;\n    -o-transition: -o-transform 0.6s ease-in-out;\n    transition: transform 0.6s ease-in-out;\n    -webkit-backface-visibility: hidden;\n    backface-visibility: hidden;\n    -webkit-perspective: 1000px;\n    perspective: 1000px;\n  }\n  .carousel-inner > .item.next,\n  .carousel-inner > .item.active.right {\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n    left: 0;\n  }\n  .carousel-inner > .item.prev,\n  .carousel-inner > .item.active.left {\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n    left: 0;\n  }\n  .carousel-inner > .item.next.left,\n  .carousel-inner > .item.prev.right,\n  .carousel-inner > .item.active {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    left: 0;\n  }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  display: block;\n}\n.carousel-inner > .active {\n  left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n.carousel-inner > .next {\n  left: 100%;\n}\n.carousel-inner > .prev {\n  left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n  left: 0;\n}\n.carousel-inner > .active.left {\n  left: -100%;\n}\n.carousel-inner > .active.right {\n  left: 100%;\n}\n.carousel-control {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  width: 15%;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n  font-size: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-control.left {\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.0001)));\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n  left: auto;\n  right: 0;\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.5)));\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n  outline: 0;\n  color: #ffffff;\n  text-decoration: none;\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n  position: absolute;\n  top: 50%;\n  margin-top: -10px;\n  z-index: 5;\n  display: inline-block;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n  left: 50%;\n  margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n  right: 50%;\n  margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n  width: 20px;\n  height: 20px;\n  line-height: 1;\n  font-family: serif;\n}\n.carousel-control .icon-prev:before {\n  content: '\\2039';\n}\n.carousel-control .icon-next:before {\n  content: '\\203a';\n}\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n}\n.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  border: 1px solid #ffffff;\n  border-radius: 10px;\n  cursor: pointer;\n  background-color: #000 \\9;\n  background-color: rgba(0, 0, 0, 0);\n}\n.carousel-indicators .active {\n  margin: 0;\n  width: 12px;\n  height: 12px;\n  background-color: #ffffff;\n}\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n  text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next {\n    width: 30px;\n    height: 30px;\n    margin-top: -15px;\n    font-size: 30px;\n  }\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .icon-prev {\n    margin-left: -15px;\n  }\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-next {\n    margin-right: -15px;\n  }\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-footer:before,\n.modal-footer:after {\n  content: \" \";\n  display: table;\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-footer:after {\n  clear: both;\n}\n.center-block {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n.hidden {\n  display: none !important;\n}\n.affix {\n  position: fixed;\n}\n@-ms-viewport {\n  width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-xs {\n    display: block !important;\n  }\n  table.visible-xs {\n    display: table !important;\n  }\n  tr.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-xs,\n  td.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-block {\n    display: block !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline {\n    display: inline !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm {\n    display: block !important;\n  }\n  table.visible-sm {\n    display: table !important;\n  }\n  tr.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-sm,\n  td.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-block {\n    display: block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md {\n    display: block !important;\n  }\n  table.visible-md {\n    display: table !important;\n  }\n  tr.visible-md {\n    display: table-row !important;\n  }\n  th.visible-md,\n  td.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-block {\n    display: block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg {\n    display: block !important;\n  }\n  table.visible-lg {\n    display: table !important;\n  }\n  tr.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-lg,\n  td.visible-lg {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-block {\n    display: block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (max-width: 767px) {\n  .hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-lg {\n    display: none !important;\n  }\n}\n.visible-print {\n  display: none !important;\n}\n@media print {\n  .visible-print {\n    display: block !important;\n  }\n  table.visible-print {\n    display: table !important;\n  }\n  tr.visible-print {\n    display: table-row !important;\n  }\n  th.visible-print,\n  td.visible-print {\n    display: table-cell !important;\n  }\n}\n.visible-print-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-block {\n    display: block !important;\n  }\n}\n.visible-print-inline {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline {\n    display: inline !important;\n  }\n}\n.visible-print-inline-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline-block {\n    display: inline-block !important;\n  }\n}\n@media print {\n  .hidden-print {\n    display: none !important;\n  }\n}\n.text-primary,\n.text-primary:hover {\n  color: #2a9fd6;\n}\n.text-success,\n.text-success:hover {\n  color: #77b300;\n}\n.text-danger,\n.text-danger:hover {\n  color: #cc0000;\n}\n.text-warning,\n.text-warning:hover {\n  color: #ff8800;\n}\n.text-info,\n.text-info:hover {\n  color: #9933cc;\n}\ntable,\n.table {\n  color: #fff;\n}\ntable a:not(.btn),\n.table a:not(.btn) {\n  color: #fff;\n  text-decoration: underline;\n}\ntable .dropdown-menu a,\n.table .dropdown-menu a {\n  text-decoration: none;\n}\ntable .text-muted,\n.table .text-muted {\n  color: #888888;\n}\n.table-responsive > .table {\n  background-color: #181818;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .form-control-feedback {\n  color: #ff8800;\n}\n.has-warning .form-control,\n.has-warning .form-control:focus,\n.has-warning .input-group-addon {\n  border-color: #ff8800;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .form-control-feedback {\n  color: #cc0000;\n}\n.has-error .form-control,\n.has-error .form-control:focus,\n.has-error .input-group-addon {\n  border-color: #cc0000;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .form-control-feedback {\n  color: #77b300;\n}\n.has-success .form-control,\n.has-success .form-control:focus,\n.has-success .input-group-addon {\n  border-color: #77b300;\n}\nlegend {\n  color: #fff;\n}\n.input-group-addon {\n  background-color: #424242;\n}\n.nav-tabs a,\n.nav-pills a,\n.breadcrumb a,\n.pager a {\n  color: #fff;\n}\n.alert .alert-link,\n.alert a {\n  color: #ffffff;\n  text-decoration: underline;\n}\n.alert .close {\n  text-decoration: none;\n}\n.close {\n  color: #fff;\n  text-decoration: none;\n  opacity: 0.4;\n}\n.close:hover,\n.close:focus {\n  color: #fff;\n  opacity: 1;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #282828;\n}\na.list-group-item.active,\na.list-group-item.active:hover,\na.list-group-item.active:focus {\n  border-color: #282828;\n}\na.list-group-item-success.active {\n  background-color: #77b300;\n}\na.list-group-item-success.active:hover,\na.list-group-item-success.active:focus {\n  background-color: #669a00;\n}\na.list-group-item-warning.active {\n  background-color: #ff8800;\n}\na.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus {\n  background-color: #e67a00;\n}\na.list-group-item-danger.active {\n  background-color: #cc0000;\n}\na.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus {\n  background-color: #b30000;\n}\n.jumbotron h1,\n.jumbotron h2,\n.jumbotron h3,\n.jumbotron h4,\n.jumbotron h5,\n.jumbotron h6 {\n  color: #fff;\n}\n"
  },
  {
    "path": "resources/public/css/bootstrap-slider.css",
    "content": "/*! =======================================================\n                      VERSION  6.0.10              \n========================================================= */\n/*! =========================================================\n * bootstrap-slider.js\n *\n * Maintainers:\n *\t\tKyle Kemp\n *\t\t\t- Twitter: @seiyria\n *\t\t\t- Github:  seiyria\n *\t\tRohit Kalkur\n *\t\t\t- Twitter: @Rovolutionary\n *\t\t\t- Github:  rovolution\n *\n * =========================================================\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================= */\n.slider {\n  display: inline-block;\n  vertical-align: middle;\n  position: relative;\n}\n.slider.slider-horizontal {\n  width: 210px;\n  height: 20px;\n}\n.slider.slider-horizontal .slider-track {\n  height: 10px;\n  width: 100%;\n  margin-top: -5px;\n  top: 50%;\n  left: 0;\n}\n.slider.slider-horizontal .slider-selection,\n.slider.slider-horizontal .slider-track-low,\n.slider.slider-horizontal .slider-track-high {\n  height: 100%;\n  top: 0;\n  bottom: 0;\n}\n.slider.slider-horizontal .slider-tick,\n.slider.slider-horizontal .slider-handle {\n  margin-left: -10px;\n  margin-top: -5px;\n}\n.slider.slider-horizontal .slider-tick.triangle,\n.slider.slider-horizontal .slider-handle.triangle {\n  border-width: 0 10px 10px 10px;\n  width: 0;\n  height: 0;\n  border-bottom-color: #0480be;\n  margin-top: 0;\n}\n.slider.slider-horizontal .slider-tick-label-container {\n  white-space: nowrap;\n  margin-top: 20px;\n}\n.slider.slider-horizontal .slider-tick-label-container .slider-tick-label {\n  padding-top: 4px;\n  display: inline-block;\n  text-align: center;\n}\n.slider.slider-vertical {\n  height: 210px;\n  width: 20px;\n}\n.slider.slider-vertical .slider-track {\n  width: 10px;\n  height: 100%;\n  margin-left: -5px;\n  left: 50%;\n  top: 0;\n}\n.slider.slider-vertical .slider-selection {\n  width: 100%;\n  left: 0;\n  top: 0;\n  bottom: 0;\n}\n.slider.slider-vertical .slider-track-low,\n.slider.slider-vertical .slider-track-high {\n  width: 100%;\n  left: 0;\n  right: 0;\n}\n.slider.slider-vertical .slider-tick,\n.slider.slider-vertical .slider-handle {\n  margin-left: -5px;\n  margin-top: -10px;\n}\n.slider.slider-vertical .slider-tick.triangle,\n.slider.slider-vertical .slider-handle.triangle {\n  border-width: 10px 0 10px 10px;\n  width: 1px;\n  height: 1px;\n  border-left-color: #0480be;\n  margin-left: 0;\n}\n.slider.slider-vertical .slider-tick-label-container {\n  white-space: nowrap;\n}\n.slider.slider-vertical .slider-tick-label-container .slider-tick-label {\n  padding-left: 4px;\n}\n.slider.slider-disabled .slider-handle {\n  background-image: -webkit-linear-gradient(top, #dfdfdf 0%, #bebebe 100%);\n  background-image: -o-linear-gradient(top, #dfdfdf 0%, #bebebe 100%);\n  background-image: linear-gradient(to bottom, #dfdfdf 0%, #bebebe 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdfdfdf', endColorstr='#ffbebebe', GradientType=0);\n}\n.slider.slider-disabled .slider-track {\n  background-image: -webkit-linear-gradient(top, #e5e5e5 0%, #e9e9e9 100%);\n  background-image: -o-linear-gradient(top, #e5e5e5 0%, #e9e9e9 100%);\n  background-image: linear-gradient(to bottom, #e5e5e5 0%, #e9e9e9 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe5e5e5', endColorstr='#ffe9e9e9', GradientType=0);\n  cursor: not-allowed;\n}\n.slider input {\n  display: none;\n}\n.slider .tooltip.top {\n  margin-top: -36px;\n}\n.slider .tooltip-inner {\n  white-space: nowrap;\n}\n.slider .hide {\n  display: none;\n}\n.slider-track {\n  position: absolute;\n  cursor: pointer;\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #f9f9f9 100%);\n  background-image: -o-linear-gradient(top, #f5f5f5 0%, #f9f9f9 100%);\n  background-image: linear-gradient(to bottom, #f5f5f5 0%, #f9f9f9 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n  border-radius: 4px;\n}\n.slider-selection {\n  position: absolute;\n  background-image: -webkit-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%);\n  background-image: -o-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%);\n  background-image: linear-gradient(to bottom, #f9f9f9 0%, #f5f5f5 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0);\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n  border-radius: 4px;\n}\n.slider-selection.tick-slider-selection {\n  background-image: -webkit-linear-gradient(top, #89cdef 0%, #81bfde 100%);\n  background-image: -o-linear-gradient(top, #89cdef 0%, #81bfde 100%);\n  background-image: linear-gradient(to bottom, #89cdef 0%, #81bfde 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff89cdef', endColorstr='#ff81bfde', GradientType=0);\n}\n.slider-track-low,\n.slider-track-high {\n  position: absolute;\n  background: transparent;\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n  border-radius: 4px;\n}\n.slider-handle {\n  position: absolute;\n  width: 20px;\n  height: 20px;\n  background-color: #337ab7;\n  background-image: -webkit-linear-gradient(top, #149bdf 0%, #0480be 100%);\n  background-image: -o-linear-gradient(top, #149bdf 0%, #0480be 100%);\n  background-image: linear-gradient(to bottom, #149bdf 0%, #0480be 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);\n  filter: none;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);\n  box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);\n  border: 0px solid transparent;\n}\n.slider-handle.round {\n  border-radius: 50%;\n}\n.slider-handle.triangle {\n  background: transparent none;\n}\n.slider-handle.custom {\n  background: transparent none;\n}\n.slider-handle.custom::before {\n  line-height: 20px;\n  font-size: 20px;\n  content: '\\2605';\n  color: #726204;\n}\n.slider-tick {\n  position: absolute;\n  width: 20px;\n  height: 20px;\n  background-image: -webkit-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%);\n  background-image: -o-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%);\n  background-image: linear-gradient(to bottom, #f9f9f9 0%, #f5f5f5 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0);\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n  filter: none;\n  opacity: 0.8;\n  border: 0px solid transparent;\n}\n.slider-tick.round {\n  border-radius: 50%;\n}\n.slider-tick.triangle {\n  background: transparent none;\n}\n.slider-tick.custom {\n  background: transparent none;\n}\n.slider-tick.custom::before {\n  line-height: 20px;\n  font-size: 20px;\n  content: '\\2605';\n  color: #726204;\n}\n.slider-tick.in-selection {\n  background-image: -webkit-linear-gradient(top, #89cdef 0%, #81bfde 100%);\n  background-image: -o-linear-gradient(top, #89cdef 0%, #81bfde 100%);\n  background-image: linear-gradient(to bottom, #89cdef 0%, #81bfde 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff89cdef', endColorstr='#ff81bfde', GradientType=0);\n  opacity: 1;\n}\n"
  },
  {
    "path": "resources/public/css/bootstrap-switch.css",
    "content": "/* ========================================================================\n * bootstrap-switch - v3.3.2\n * http://www.bootstrap-switch.org\n * ========================================================================\n * Copyright 2012-2013 Mattia Larentis\n *\n * ========================================================================\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================================\n */\n\n.bootstrap-switch {\n  display: inline-block;\n  direction: ltr;\n  cursor: pointer;\n  border-radius: 4px;\n  border: 1px solid;\n  border-color: #cccccc;\n  position: relative;\n  text-align: left;\n  overflow: hidden;\n  line-height: 8px;\n  z-index: 0;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  vertical-align: middle;\n  -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.bootstrap-switch .bootstrap-switch-container {\n  display: inline-block;\n  top: 0;\n  border-radius: 4px;\n  -webkit-transform: translate3d(0, 0, 0);\n  transform: translate3d(0, 0, 0);\n}\n.bootstrap-switch .bootstrap-switch-handle-on,\n.bootstrap-switch .bootstrap-switch-handle-off,\n.bootstrap-switch .bootstrap-switch-label {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n  cursor: pointer;\n  display: inline-block !important;\n  height: 100%;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 20px;\n}\n.bootstrap-switch .bootstrap-switch-handle-on,\n.bootstrap-switch .bootstrap-switch-handle-off {\n  text-align: center;\n  z-index: 1;\n}\n.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary,\n.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary {\n  color: #fff;\n  background: #337ab7;\n}\n.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info,\n.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info {\n  color: #fff;\n  background: #5bc0de;\n}\n.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success,\n.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success {\n  color: #fff;\n  background: #5cb85c;\n}\n.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning,\n.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning {\n  background: #f0ad4e;\n  color: #fff;\n}\n.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger,\n.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger {\n  color: #fff;\n  background: #d9534f;\n}\n.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default,\n.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default {\n  color: #000;\n  background: #eeeeee;\n}\n.bootstrap-switch .bootstrap-switch-label {\n  text-align: center;\n  margin-top: -1px;\n  margin-bottom: -1px;\n  z-index: 100;\n  color: #333333;\n  background: #ffffff;\n}\n.bootstrap-switch .bootstrap-switch-handle-on {\n  border-bottom-left-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.bootstrap-switch .bootstrap-switch-handle-off {\n  border-bottom-right-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.bootstrap-switch input[type='radio'],\n.bootstrap-switch input[type='checkbox'] {\n  position: absolute !important;\n  top: 0;\n  left: 0;\n  margin: 0;\n  z-index: -1;\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-on,\n.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-off,\n.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-label {\n  padding: 1px 5px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-on,\n.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-off,\n.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-label {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-on,\n.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-off,\n.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-label {\n  padding: 6px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.bootstrap-switch.bootstrap-switch-disabled,\n.bootstrap-switch.bootstrap-switch-readonly,\n.bootstrap-switch.bootstrap-switch-indeterminate {\n  cursor: default !important;\n}\n.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-on,\n.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-on,\n.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-on,\n.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-off,\n.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-off,\n.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-off,\n.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-label,\n.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-label,\n.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-label {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n  cursor: default !important;\n}\n.bootstrap-switch.bootstrap-switch-animate .bootstrap-switch-container {\n  -webkit-transition: margin-left 0.5s;\n  -o-transition: margin-left 0.5s;\n  transition: margin-left 0.5s;\n}\n.bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-on {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n  border-bottom-right-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-off {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n  border-bottom-left-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.bootstrap-switch.bootstrap-switch-focused {\n  border-color: #66afe9;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.bootstrap-switch.bootstrap-switch-on .bootstrap-switch-label,\n.bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-off .bootstrap-switch-label {\n  border-bottom-right-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.bootstrap-switch.bootstrap-switch-off .bootstrap-switch-label,\n.bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-on .bootstrap-switch-label {\n  border-bottom-left-radius: 3px;\n  border-top-left-radius: 3px;\n}\n"
  },
  {
    "path": "resources/public/css/bootstrap-theme.css",
    "content": "/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn-default.disabled,\n.btn-primary.disabled,\n.btn-success.disabled,\n.btn-info.disabled,\n.btn-warning.disabled,\n.btn-danger.disabled,\n.btn-default[disabled],\n.btn-primary[disabled],\n.btn-success[disabled],\n.btn-info[disabled],\n.btn-warning[disabled],\n.btn-danger[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-danger {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n  text-shadow: none;\n}\n.btn:active,\n.btn.active {\n  background-image: none;\n}\n.btn-default {\n  text-shadow: 0 1px 0 #fff;\n  background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n  background-image:      -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));\n  background-image:         linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #dbdbdb;\n  border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n  background-color: #e0e0e0;\n  background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n  background-color: #e0e0e0;\n  border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n  background-color: #e0e0e0;\n  background-image: none;\n}\n.btn-primary {\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #265a88 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #265a88 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #245580;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n  background-color: #265a88;\n  background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n  background-color: #265a88;\n  border-color: #245580;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n  background-color: #265a88;\n  background-image: none;\n}\n.btn-success {\n  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n  background-image:      -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));\n  background-image:         linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n  background-color: #419641;\n  background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n  background-color: #419641;\n  border-color: #3e8f3e;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n  background-color: #419641;\n  background-image: none;\n}\n.btn-info {\n  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n  background-image:      -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));\n  background-image:         linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n  background-color: #2aabd2;\n  background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n  background-color: #2aabd2;\n  border-color: #28a4c9;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n  background-color: #2aabd2;\n  background-image: none;\n}\n.btn-warning {\n  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n  background-image:      -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));\n  background-image:         linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n  background-color: #eb9316;\n  background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n  background-color: #eb9316;\n  border-color: #e38d13;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n  background-color: #eb9316;\n  background-image: none;\n}\n.btn-danger {\n  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n  background-image:      -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));\n  background-image:         linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n  background-color: #c12e2a;\n  background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n  background-color: #c12e2a;\n  border-color: #b92c28;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n  background-color: #c12e2a;\n  background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  background-color: #e8e8e8;\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));\n  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n  background-repeat: repeat-x;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  background-color: #2e6da4;\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n  background-repeat: repeat-x;\n}\n.navbar-default {\n  background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);\n  background-image:      -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));\n  background-image:         linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n  background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n  background-image:      -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));\n  background-image:         linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n  background-repeat: repeat-x;\n  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n  text-shadow: 0 1px 0 rgba(255, 255, 255, .25);\n}\n.navbar-inverse {\n  background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);\n  background-image:      -o-linear-gradient(top, #3c3c3c 0%, #222 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));\n  background-image:         linear-gradient(to bottom, #3c3c3c 0%, #222 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  background-repeat: repeat-x;\n  border-radius: 4px;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n  background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n  background-image:      -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));\n  background-image:         linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n  background-repeat: repeat-x;\n  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);\n          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  border-radius: 0;\n}\n@media (max-width: 767px) {\n  .navbar .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #fff;\n    background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n    background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n    background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));\n    background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n    background-repeat: repeat-x;\n  }\n}\n.alert {\n  text-shadow: 0 1px 0 rgba(255, 255, 255, .2);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);\n}\n.alert-success {\n  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n  background-image:      -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));\n  background-image:         linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #b2dba1;\n}\n.alert-info {\n  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n  background-image:      -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));\n  background-image:         linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #9acfea;\n}\n.alert-warning {\n  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n  background-image:      -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));\n  background-image:         linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #f5e79e;\n}\n.alert-danger {\n  background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n  background-image:      -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));\n  background-image:         linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #dca7a7;\n}\n.progress {\n  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n  background-image:      -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));\n  background-image:         linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar {\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #286090 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #286090 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-success {\n  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n  background-image:      -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));\n  background-image:         linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-info {\n  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n  background-image:      -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));\n  background-image:         linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-warning {\n  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n  background-image:      -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));\n  background-image:         linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-danger {\n  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n  background-image:      -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));\n  background-image:         linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n  background-repeat: repeat-x;\n}\n.progress-bar-striped {\n  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);\n  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);\n  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);\n}\n.list-group {\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  text-shadow: 0 -1px 0 #286090;\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #2b669a;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n  text-shadow: none;\n}\n.panel {\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, .05);\n}\n.panel-default > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));\n  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-primary > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n  background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));\n  background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-success > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n  background-image:      -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));\n  background-image:         linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-info > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n  background-image:      -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));\n  background-image:         linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-warning > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n  background-image:      -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));\n  background-image:         linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n  background-repeat: repeat-x;\n}\n.panel-danger > .panel-heading {\n  background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n  background-image:      -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));\n  background-image:         linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n  background-repeat: repeat-x;\n}\n.well {\n  background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n  background-image:      -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n  background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));\n  background-image:         linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n  background-repeat: repeat-x;\n  border-color: #dcdcdc;\n  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);\n          box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */\n"
  },
  {
    "path": "resources/public/css/bootstrap.css",
    "content": "/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n  font-family: sans-serif;\n  -webkit-text-size-adjust: 100%;\n      -ms-text-size-adjust: 100%;\n}\nbody {\n  margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block;\n  vertical-align: baseline;\n}\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n[hidden],\ntemplate {\n  display: none;\n}\na {\n  background-color: transparent;\n}\na:active,\na:hover {\n  outline: 0;\n}\nabbr[title] {\n  border-bottom: 1px dotted;\n}\nb,\nstrong {\n  font-weight: bold;\n}\ndfn {\n  font-style: italic;\n}\nh1 {\n  margin: .67em 0;\n  font-size: 2em;\n}\nmark {\n  color: #000;\n  background: #ff0;\n}\nsmall {\n  font-size: 80%;\n}\nsub,\nsup {\n  position: relative;\n  font-size: 75%;\n  line-height: 0;\n  vertical-align: baseline;\n}\nsup {\n  top: -.5em;\n}\nsub {\n  bottom: -.25em;\n}\nimg {\n  border: 0;\n}\nsvg:not(:root) {\n  overflow: hidden;\n}\nfigure {\n  margin: 1em 40px;\n}\nhr {\n  height: 0;\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n}\npre {\n  overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  margin: 0;\n  font: inherit;\n  color: inherit;\n}\nbutton {\n  overflow: visible;\n}\nbutton,\nselect {\n  text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\ninput {\n  line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n  padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n  -webkit-appearance: textfield;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\nfieldset {\n  padding: .35em .625em .75em;\n  margin: 0 2px;\n  border: 1px solid #c0c0c0;\n}\nlegend {\n  padding: 0;\n  border: 0;\n}\ntextarea {\n  overflow: auto;\n}\noptgroup {\n  font-weight: bold;\n}\ntable {\n  border-spacing: 0;\n  border-collapse: collapse;\n}\ntd,\nth {\n  padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n  *,\n  *:before,\n  *:after {\n    color: #000 !important;\n    text-shadow: none !important;\n    background: transparent !important;\n    -webkit-box-shadow: none !important;\n            box-shadow: none !important;\n  }\n  a,\n  a:visited {\n    text-decoration: underline;\n  }\n  a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n  abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n  a[href^=\"#\"]:after,\n  a[href^=\"javascript:\"]:after {\n    content: \"\";\n  }\n  pre,\n  blockquote {\n    border: 1px solid #999;\n\n    page-break-inside: avoid;\n  }\n  thead {\n    display: table-header-group;\n  }\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n  img {\n    max-width: 100% !important;\n  }\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n  .navbar {\n    display: none;\n  }\n  .btn > .caret,\n  .dropup > .btn > .caret {\n    border-top-color: #000 !important;\n  }\n  .label {\n    border: 1px solid #000;\n  }\n  .table {\n    border-collapse: collapse !important;\n  }\n  .table td,\n  .table th {\n    background-color: #fff !important;\n  }\n  .table-bordered th,\n  .table-bordered td {\n    border: 1px solid #ddd !important;\n  }\n}\n@font-face {\n  font-family: 'Glyphicons Halflings';\n\n  src: url('../fonts/glyphicons-halflings-regular.eot');\n  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');\n}\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n  content: \"\\2a\";\n}\n.glyphicon-plus:before {\n  content: \"\\2b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n  content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n  content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n  content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n  content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n  content: \"\\270f\";\n}\n.glyphicon-glass:before {\n  content: \"\\e001\";\n}\n.glyphicon-music:before {\n  content: \"\\e002\";\n}\n.glyphicon-search:before {\n  content: \"\\e003\";\n}\n.glyphicon-heart:before {\n  content: \"\\e005\";\n}\n.glyphicon-star:before {\n  content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n  content: \"\\e007\";\n}\n.glyphicon-user:before {\n  content: \"\\e008\";\n}\n.glyphicon-film:before {\n  content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n  content: \"\\e010\";\n}\n.glyphicon-th:before {\n  content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n  content: \"\\e012\";\n}\n.glyphicon-ok:before {\n  content: \"\\e013\";\n}\n.glyphicon-remove:before {\n  content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n  content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n  content: \"\\e016\";\n}\n.glyphicon-off:before {\n  content: \"\\e017\";\n}\n.glyphicon-signal:before {\n  content: \"\\e018\";\n}\n.glyphicon-cog:before {\n  content: \"\\e019\";\n}\n.glyphicon-trash:before {\n  content: \"\\e020\";\n}\n.glyphicon-home:before {\n  content: \"\\e021\";\n}\n.glyphicon-file:before {\n  content: \"\\e022\";\n}\n.glyphicon-time:before {\n  content: \"\\e023\";\n}\n.glyphicon-road:before {\n  content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n  content: \"\\e025\";\n}\n.glyphicon-download:before {\n  content: \"\\e026\";\n}\n.glyphicon-upload:before {\n  content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n  content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n  content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n  content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n  content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n  content: \"\\e032\";\n}\n.glyphicon-lock:before {\n  content: \"\\e033\";\n}\n.glyphicon-flag:before {\n  content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n  content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n  content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n  content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n  content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n  content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n  content: \"\\e040\";\n}\n.glyphicon-tag:before {\n  content: \"\\e041\";\n}\n.glyphicon-tags:before {\n  content: \"\\e042\";\n}\n.glyphicon-book:before {\n  content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n  content: \"\\e044\";\n}\n.glyphicon-print:before {\n  content: \"\\e045\";\n}\n.glyphicon-camera:before {\n  content: \"\\e046\";\n}\n.glyphicon-font:before {\n  content: \"\\e047\";\n}\n.glyphicon-bold:before {\n  content: \"\\e048\";\n}\n.glyphicon-italic:before {\n  content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n  content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n  content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n  content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n  content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n  content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n  content: \"\\e055\";\n}\n.glyphicon-list:before {\n  content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n  content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n  content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n  content: \"\\e059\";\n}\n.glyphicon-picture:before {\n  content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n  content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n  content: \"\\e063\";\n}\n.glyphicon-tint:before {\n  content: \"\\e064\";\n}\n.glyphicon-edit:before {\n  content: \"\\e065\";\n}\n.glyphicon-share:before {\n  content: \"\\e066\";\n}\n.glyphicon-check:before {\n  content: \"\\e067\";\n}\n.glyphicon-move:before {\n  content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n  content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n  content: \"\\e070\";\n}\n.glyphicon-backward:before {\n  content: \"\\e071\";\n}\n.glyphicon-play:before {\n  content: \"\\e072\";\n}\n.glyphicon-pause:before {\n  content: \"\\e073\";\n}\n.glyphicon-stop:before {\n  content: \"\\e074\";\n}\n.glyphicon-forward:before {\n  content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n  content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n  content: \"\\e077\";\n}\n.glyphicon-eject:before {\n  content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n  content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n  content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n  content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n  content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n  content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n  content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n  content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n  content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n  content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n  content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n  content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n  content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n  content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n  content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n  content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n  content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n  content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n  content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n  content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n  content: \"\\e101\";\n}\n.glyphicon-gift:before {\n  content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n  content: \"\\e103\";\n}\n.glyphicon-fire:before {\n  content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n  content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n  content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n  content: \"\\e107\";\n}\n.glyphicon-plane:before {\n  content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n  content: \"\\e109\";\n}\n.glyphicon-random:before {\n  content: \"\\e110\";\n}\n.glyphicon-comment:before {\n  content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n  content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n  content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n  content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n  content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n  content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n  content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n  content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n  content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n  content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n  content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n  content: \"\\e122\";\n}\n.glyphicon-bell:before {\n  content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n  content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n  content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n  content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n  content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n  content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n  content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n  content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n  content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n  content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n  content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n  content: \"\\e134\";\n}\n.glyphicon-globe:before {\n  content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n  content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n  content: \"\\e137\";\n}\n.glyphicon-filter:before {\n  content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n  content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n  content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n  content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n  content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n  content: \"\\e143\";\n}\n.glyphicon-link:before {\n  content: \"\\e144\";\n}\n.glyphicon-phone:before {\n  content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n  content: \"\\e146\";\n}\n.glyphicon-usd:before {\n  content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n  content: \"\\e149\";\n}\n.glyphicon-sort:before {\n  content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n  content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n  content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n  content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n  content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n  content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n  content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n  content: \"\\e157\";\n}\n.glyphicon-expand:before {\n  content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n  content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n  content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n  content: \"\\e161\";\n}\n.glyphicon-flash:before {\n  content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n  content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n  content: \"\\e164\";\n}\n.glyphicon-record:before {\n  content: \"\\e165\";\n}\n.glyphicon-save:before {\n  content: \"\\e166\";\n}\n.glyphicon-open:before {\n  content: \"\\e167\";\n}\n.glyphicon-saved:before {\n  content: \"\\e168\";\n}\n.glyphicon-import:before {\n  content: \"\\e169\";\n}\n.glyphicon-export:before {\n  content: \"\\e170\";\n}\n.glyphicon-send:before {\n  content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n  content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n  content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n  content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n  content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n  content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n  content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n  content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n  content: \"\\e179\";\n}\n.glyphicon-header:before {\n  content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n  content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n  content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n  content: \"\\e183\";\n}\n.glyphicon-tower:before {\n  content: \"\\e184\";\n}\n.glyphicon-stats:before {\n  content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n  content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n  content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n  content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n  content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n  content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n  content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n  content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n  content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n  content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n  content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n  content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n  content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n  content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n  content: \"\\e200\";\n}\n.glyphicon-cd:before {\n  content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n  content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n  content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n  content: \"\\e204\";\n}\n.glyphicon-copy:before {\n  content: \"\\e205\";\n}\n.glyphicon-paste:before {\n  content: \"\\e206\";\n}\n.glyphicon-alert:before {\n  content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n  content: \"\\e210\";\n}\n.glyphicon-king:before {\n  content: \"\\e211\";\n}\n.glyphicon-queen:before {\n  content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n  content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n  content: \"\\e214\";\n}\n.glyphicon-knight:before {\n  content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n  content: \"\\e216\";\n}\n.glyphicon-tent:before {\n  content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n  content: \"\\e218\";\n}\n.glyphicon-bed:before {\n  content: \"\\e219\";\n}\n.glyphicon-apple:before {\n  content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n  content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n  content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n  content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n  content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n  content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n  content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n  content: \"\\e227\";\n}\n.glyphicon-btc:before {\n  content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n  content: \"\\e227\";\n}\n.glyphicon-yen:before {\n  content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n  content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n  content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n  content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n  content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n  content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n  content: \"\\e232\";\n}\n.glyphicon-education:before {\n  content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n  content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n  content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n  content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n  content: \"\\e237\";\n}\n.glyphicon-oil:before {\n  content: \"\\e238\";\n}\n.glyphicon-grain:before {\n  content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n  content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n  content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n  content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n  content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n  content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n  content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n  content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n  content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n  content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n  content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n  content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n  content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n  content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n  content: \"\\e253\";\n}\n.glyphicon-console:before {\n  content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n  content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n  content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n  content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n  content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n  content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n  content: \"\\e260\";\n}\n* {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n*:before,\n*:after {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\nhtml {\n  font-size: 10px;\n\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #333;\n  background-color: #fff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\na {\n  color: #337ab7;\n  text-decoration: none;\n}\na:hover,\na:focus {\n  color: #23527c;\n  text-decoration: underline;\n}\na:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\nfigure {\n  margin: 0;\n}\nimg {\n  vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  display: block;\n  max-width: 100%;\n  height: auto;\n}\n.img-rounded {\n  border-radius: 6px;\n}\n.img-thumbnail {\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n  padding: 4px;\n  line-height: 1.42857143;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n  -webkit-transition: all .2s ease-in-out;\n       -o-transition: all .2s ease-in-out;\n          transition: all .2s ease-in-out;\n}\n.img-circle {\n  border-radius: 50%;\n}\nhr {\n  margin-top: 20px;\n  margin-bottom: 20px;\n  border: 0;\n  border-top: 1px solid #eee;\n}\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n  position: static;\n  width: auto;\n  height: auto;\n  margin: 0;\n  overflow: visible;\n  clip: auto;\n}\n[role=\"button\"] {\n  cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n  font-family: inherit;\n  font-weight: 500;\n  line-height: 1.1;\n  color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n  font-weight: normal;\n  line-height: 1;\n  color: #777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n  margin-top: 20px;\n  margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n  font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n  font-size: 75%;\n}\nh1,\n.h1 {\n  font-size: 36px;\n}\nh2,\n.h2 {\n  font-size: 30px;\n}\nh3,\n.h3 {\n  font-size: 24px;\n}\nh4,\n.h4 {\n  font-size: 18px;\n}\nh5,\n.h5 {\n  font-size: 14px;\n}\nh6,\n.h6 {\n  font-size: 12px;\n}\np {\n  margin: 0 0 10px;\n}\n.lead {\n  margin-bottom: 20px;\n  font-size: 16px;\n  font-weight: 300;\n  line-height: 1.4;\n}\n@media (min-width: 768px) {\n  .lead {\n    font-size: 21px;\n  }\n}\nsmall,\n.small {\n  font-size: 85%;\n}\nmark,\n.mark {\n  padding: .2em;\n  background-color: #fcf8e3;\n}\n.text-left {\n  text-align: left;\n}\n.text-right {\n  text-align: right;\n}\n.text-center {\n  text-align: center;\n}\n.text-justify {\n  text-align: justify;\n}\n.text-nowrap {\n  white-space: nowrap;\n}\n.text-lowercase {\n  text-transform: lowercase;\n}\n.text-uppercase {\n  text-transform: uppercase;\n}\n.text-capitalize {\n  text-transform: capitalize;\n}\n.text-muted {\n  color: #777;\n}\n.text-primary {\n  color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n  color: #286090;\n}\n.text-success {\n  color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n  color: #2b542c;\n}\n.text-info {\n  color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n  color: #245269;\n}\n.text-warning {\n  color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n  color: #66512c;\n}\n.text-danger {\n  color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n  color: #843534;\n}\n.bg-primary {\n  color: #fff;\n  background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n  background-color: #286090;\n}\n.bg-success {\n  background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n  background-color: #c1e2b3;\n}\n.bg-info {\n  background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n  background-color: #afd9ee;\n}\n.bg-warning {\n  background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n  background-color: #f7ecb5;\n}\n.bg-danger {\n  background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n  background-color: #e4b9b9;\n}\n.page-header {\n  padding-bottom: 9px;\n  margin: 40px 0 20px;\n  border-bottom: 1px solid #eee;\n}\nul,\nol {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n  margin-bottom: 0;\n}\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n.list-inline {\n  padding-left: 0;\n  margin-left: -5px;\n  list-style: none;\n}\n.list-inline > li {\n  display: inline-block;\n  padding-right: 5px;\n  padding-left: 5px;\n}\ndl {\n  margin-top: 0;\n  margin-bottom: 20px;\n}\ndt,\ndd {\n  line-height: 1.42857143;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .dl-horizontal dt {\n    float: left;\n    width: 160px;\n    overflow: hidden;\n    clear: left;\n    text-align: right;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n  .dl-horizontal dd {\n    margin-left: 180px;\n  }\n}\nabbr[title],\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #777;\n}\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\nblockquote {\n  padding: 10px 20px;\n  margin: 0 0 20px;\n  font-size: 17.5px;\n  border-left: 5px solid #eee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n  margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n  display: block;\n  font-size: 80%;\n  line-height: 1.42857143;\n  color: #777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n  content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  text-align: right;\n  border-right: 5px solid #eee;\n  border-left: 0;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n  content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n  content: '\\00A0 \\2014';\n}\naddress {\n  margin-bottom: 20px;\n  font-style: normal;\n  line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #c7254e;\n  background-color: #f9f2f4;\n  border-radius: 4px;\n}\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #fff;\n  background-color: #333;\n  border-radius: 3px;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n}\nkbd kbd {\n  padding: 0;\n  font-size: 100%;\n  font-weight: bold;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\npre {\n  display: block;\n  padding: 9.5px;\n  margin: 0 0 10px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  color: #333;\n  word-break: break-all;\n  word-wrap: break-word;\n  background-color: #f5f5f5;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\npre code {\n  padding: 0;\n  font-size: inherit;\n  color: inherit;\n  white-space: pre-wrap;\n  background-color: transparent;\n  border-radius: 0;\n}\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n.container {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n@media (min-width: 768px) {\n  .container {\n    width: 750px;\n  }\n}\n@media (min-width: 992px) {\n  .container {\n    width: 970px;\n  }\n}\n@media (min-width: 1200px) {\n  .container {\n    width: 1170px;\n  }\n}\n.container-fluid {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n.row {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n  position: relative;\n  min-height: 1px;\n  padding-right: 15px;\n  padding-left: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n  float: left;\n}\n.col-xs-12 {\n  width: 100%;\n}\n.col-xs-11 {\n  width: 91.66666667%;\n}\n.col-xs-10 {\n  width: 83.33333333%;\n}\n.col-xs-9 {\n  width: 75%;\n}\n.col-xs-8 {\n  width: 66.66666667%;\n}\n.col-xs-7 {\n  width: 58.33333333%;\n}\n.col-xs-6 {\n  width: 50%;\n}\n.col-xs-5 {\n  width: 41.66666667%;\n}\n.col-xs-4 {\n  width: 33.33333333%;\n}\n.col-xs-3 {\n  width: 25%;\n}\n.col-xs-2 {\n  width: 16.66666667%;\n}\n.col-xs-1 {\n  width: 8.33333333%;\n}\n.col-xs-pull-12 {\n  right: 100%;\n}\n.col-xs-pull-11 {\n  right: 91.66666667%;\n}\n.col-xs-pull-10 {\n  right: 83.33333333%;\n}\n.col-xs-pull-9 {\n  right: 75%;\n}\n.col-xs-pull-8 {\n  right: 66.66666667%;\n}\n.col-xs-pull-7 {\n  right: 58.33333333%;\n}\n.col-xs-pull-6 {\n  right: 50%;\n}\n.col-xs-pull-5 {\n  right: 41.66666667%;\n}\n.col-xs-pull-4 {\n  right: 33.33333333%;\n}\n.col-xs-pull-3 {\n  right: 25%;\n}\n.col-xs-pull-2 {\n  right: 16.66666667%;\n}\n.col-xs-pull-1 {\n  right: 8.33333333%;\n}\n.col-xs-pull-0 {\n  right: auto;\n}\n.col-xs-push-12 {\n  left: 100%;\n}\n.col-xs-push-11 {\n  left: 91.66666667%;\n}\n.col-xs-push-10 {\n  left: 83.33333333%;\n}\n.col-xs-push-9 {\n  left: 75%;\n}\n.col-xs-push-8 {\n  left: 66.66666667%;\n}\n.col-xs-push-7 {\n  left: 58.33333333%;\n}\n.col-xs-push-6 {\n  left: 50%;\n}\n.col-xs-push-5 {\n  left: 41.66666667%;\n}\n.col-xs-push-4 {\n  left: 33.33333333%;\n}\n.col-xs-push-3 {\n  left: 25%;\n}\n.col-xs-push-2 {\n  left: 16.66666667%;\n}\n.col-xs-push-1 {\n  left: 8.33333333%;\n}\n.col-xs-push-0 {\n  left: auto;\n}\n.col-xs-offset-12 {\n  margin-left: 100%;\n}\n.col-xs-offset-11 {\n  margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n  margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n  margin-left: 75%;\n}\n.col-xs-offset-8 {\n  margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n  margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n  margin-left: 50%;\n}\n.col-xs-offset-5 {\n  margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n  margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n  margin-left: 25%;\n}\n.col-xs-offset-2 {\n  margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n  margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .col-sm-1, .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-sm-10, .col-sm-11, .col-sm-12 {\n    float: left;\n  }\n  .col-sm-12 {\n    width: 100%;\n  }\n  .col-sm-11 {\n    width: 91.66666667%;\n  }\n  .col-sm-10 {\n    width: 83.33333333%;\n  }\n  .col-sm-9 {\n    width: 75%;\n  }\n  .col-sm-8 {\n    width: 66.66666667%;\n  }\n  .col-sm-7 {\n    width: 58.33333333%;\n  }\n  .col-sm-6 {\n    width: 50%;\n  }\n  .col-sm-5 {\n    width: 41.66666667%;\n  }\n  .col-sm-4 {\n    width: 33.33333333%;\n  }\n  .col-sm-3 {\n    width: 25%;\n  }\n  .col-sm-2 {\n    width: 16.66666667%;\n  }\n  .col-sm-1 {\n    width: 8.33333333%;\n  }\n  .col-sm-pull-12 {\n    right: 100%;\n  }\n  .col-sm-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-sm-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-sm-pull-9 {\n    right: 75%;\n  }\n  .col-sm-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-sm-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-sm-pull-6 {\n    right: 50%;\n  }\n  .col-sm-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-sm-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-sm-pull-3 {\n    right: 25%;\n  }\n  .col-sm-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-sm-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-sm-pull-0 {\n    right: auto;\n  }\n  .col-sm-push-12 {\n    left: 100%;\n  }\n  .col-sm-push-11 {\n    left: 91.66666667%;\n  }\n  .col-sm-push-10 {\n    left: 83.33333333%;\n  }\n  .col-sm-push-9 {\n    left: 75%;\n  }\n  .col-sm-push-8 {\n    left: 66.66666667%;\n  }\n  .col-sm-push-7 {\n    left: 58.33333333%;\n  }\n  .col-sm-push-6 {\n    left: 50%;\n  }\n  .col-sm-push-5 {\n    left: 41.66666667%;\n  }\n  .col-sm-push-4 {\n    left: 33.33333333%;\n  }\n  .col-sm-push-3 {\n    left: 25%;\n  }\n  .col-sm-push-2 {\n    left: 16.66666667%;\n  }\n  .col-sm-push-1 {\n    left: 8.33333333%;\n  }\n  .col-sm-push-0 {\n    left: auto;\n  }\n  .col-sm-offset-12 {\n    margin-left: 100%;\n  }\n  .col-sm-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-sm-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-sm-offset-9 {\n    margin-left: 75%;\n  }\n  .col-sm-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-sm-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-sm-offset-6 {\n    margin-left: 50%;\n  }\n  .col-sm-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-sm-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-sm-offset-3 {\n    margin-left: 25%;\n  }\n  .col-sm-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-sm-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-sm-offset-0 {\n    margin-left: 0;\n  }\n}\n@media (min-width: 992px) {\n  .col-md-1, .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-md-10, .col-md-11, .col-md-12 {\n    float: left;\n  }\n  .col-md-12 {\n    width: 100%;\n  }\n  .col-md-11 {\n    width: 91.66666667%;\n  }\n  .col-md-10 {\n    width: 83.33333333%;\n  }\n  .col-md-9 {\n    width: 75%;\n  }\n  .col-md-8 {\n    width: 66.66666667%;\n  }\n  .col-md-7 {\n    width: 58.33333333%;\n  }\n  .col-md-6 {\n    width: 50%;\n  }\n  .col-md-5 {\n    width: 41.66666667%;\n  }\n  .col-md-4 {\n    width: 33.33333333%;\n  }\n  .col-md-3 {\n    width: 25%;\n  }\n  .col-md-2 {\n    width: 16.66666667%;\n  }\n  .col-md-1 {\n    width: 8.33333333%;\n  }\n  .col-md-pull-12 {\n    right: 100%;\n  }\n  .col-md-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-md-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-md-pull-9 {\n    right: 75%;\n  }\n  .col-md-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-md-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-md-pull-6 {\n    right: 50%;\n  }\n  .col-md-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-md-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-md-pull-3 {\n    right: 25%;\n  }\n  .col-md-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-md-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-md-pull-0 {\n    right: auto;\n  }\n  .col-md-push-12 {\n    left: 100%;\n  }\n  .col-md-push-11 {\n    left: 91.66666667%;\n  }\n  .col-md-push-10 {\n    left: 83.33333333%;\n  }\n  .col-md-push-9 {\n    left: 75%;\n  }\n  .col-md-push-8 {\n    left: 66.66666667%;\n  }\n  .col-md-push-7 {\n    left: 58.33333333%;\n  }\n  .col-md-push-6 {\n    left: 50%;\n  }\n  .col-md-push-5 {\n    left: 41.66666667%;\n  }\n  .col-md-push-4 {\n    left: 33.33333333%;\n  }\n  .col-md-push-3 {\n    left: 25%;\n  }\n  .col-md-push-2 {\n    left: 16.66666667%;\n  }\n  .col-md-push-1 {\n    left: 8.33333333%;\n  }\n  .col-md-push-0 {\n    left: auto;\n  }\n  .col-md-offset-12 {\n    margin-left: 100%;\n  }\n  .col-md-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-md-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-md-offset-9 {\n    margin-left: 75%;\n  }\n  .col-md-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-md-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-md-offset-6 {\n    margin-left: 50%;\n  }\n  .col-md-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-md-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-md-offset-3 {\n    margin-left: 25%;\n  }\n  .col-md-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-md-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-md-offset-0 {\n    margin-left: 0;\n  }\n}\n@media (min-width: 1200px) {\n  .col-lg-1, .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-lg-10, .col-lg-11, .col-lg-12 {\n    float: left;\n  }\n  .col-lg-12 {\n    width: 100%;\n  }\n  .col-lg-11 {\n    width: 91.66666667%;\n  }\n  .col-lg-10 {\n    width: 83.33333333%;\n  }\n  .col-lg-9 {\n    width: 75%;\n  }\n  .col-lg-8 {\n    width: 66.66666667%;\n  }\n  .col-lg-7 {\n    width: 58.33333333%;\n  }\n  .col-lg-6 {\n    width: 50%;\n  }\n  .col-lg-5 {\n    width: 41.66666667%;\n  }\n  .col-lg-4 {\n    width: 33.33333333%;\n  }\n  .col-lg-3 {\n    width: 25%;\n  }\n  .col-lg-2 {\n    width: 16.66666667%;\n  }\n  .col-lg-1 {\n    width: 8.33333333%;\n  }\n  .col-lg-pull-12 {\n    right: 100%;\n  }\n  .col-lg-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-lg-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-lg-pull-9 {\n    right: 75%;\n  }\n  .col-lg-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-lg-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-lg-pull-6 {\n    right: 50%;\n  }\n  .col-lg-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-lg-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-lg-pull-3 {\n    right: 25%;\n  }\n  .col-lg-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-lg-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-lg-pull-0 {\n    right: auto;\n  }\n  .col-lg-push-12 {\n    left: 100%;\n  }\n  .col-lg-push-11 {\n    left: 91.66666667%;\n  }\n  .col-lg-push-10 {\n    left: 83.33333333%;\n  }\n  .col-lg-push-9 {\n    left: 75%;\n  }\n  .col-lg-push-8 {\n    left: 66.66666667%;\n  }\n  .col-lg-push-7 {\n    left: 58.33333333%;\n  }\n  .col-lg-push-6 {\n    left: 50%;\n  }\n  .col-lg-push-5 {\n    left: 41.66666667%;\n  }\n  .col-lg-push-4 {\n    left: 33.33333333%;\n  }\n  .col-lg-push-3 {\n    left: 25%;\n  }\n  .col-lg-push-2 {\n    left: 16.66666667%;\n  }\n  .col-lg-push-1 {\n    left: 8.33333333%;\n  }\n  .col-lg-push-0 {\n    left: auto;\n  }\n  .col-lg-offset-12 {\n    margin-left: 100%;\n  }\n  .col-lg-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-lg-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-lg-offset-9 {\n    margin-left: 75%;\n  }\n  .col-lg-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-lg-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-lg-offset-6 {\n    margin-left: 50%;\n  }\n  .col-lg-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-lg-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-lg-offset-3 {\n    margin-left: 25%;\n  }\n  .col-lg-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-lg-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-lg-offset-0 {\n    margin-left: 0;\n  }\n}\ntable {\n  background-color: transparent;\n}\ncaption {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  color: #777;\n  text-align: left;\n}\nth {\n  text-align: left;\n}\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n  padding: 8px;\n  line-height: 1.42857143;\n  vertical-align: top;\n  border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n  border-top: 0;\n}\n.table > tbody + tbody {\n  border-top: 2px solid #ddd;\n}\n.table .table {\n  background-color: #fff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n  padding: 5px;\n}\n.table-bordered {\n  border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n  border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n  border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n  background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n  background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n  position: static;\n  display: table-column;\n  float: none;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n  position: static;\n  display: table-cell;\n  float: none;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n  background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n  background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n  background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n  background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n  background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n  background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n  background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n  background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n  background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n  background-color: #ebcccc;\n}\n.table-responsive {\n  min-height: .01%;\n  overflow-x: auto;\n}\n@media screen and (max-width: 767px) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: 15px;\n    overflow-y: hidden;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #ddd;\n  }\n  .table-responsive > .table {\n    margin-bottom: 0;\n  }\n  .table-responsive > .table > thead > tr > th,\n  .table-responsive > .table > tbody > tr > th,\n  .table-responsive > .table > tfoot > tr > th,\n  .table-responsive > .table > thead > tr > td,\n  .table-responsive > .table > tbody > tr > td,\n  .table-responsive > .table > tfoot > tr > td {\n    white-space: nowrap;\n  }\n  .table-responsive > .table-bordered {\n    border: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:first-child,\n  .table-responsive > .table-bordered > tbody > tr > th:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n  .table-responsive > .table-bordered > thead > tr > td:first-child,\n  .table-responsive > .table-bordered > tbody > tr > td:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n    border-left: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:last-child,\n  .table-responsive > .table-bordered > tbody > tr > th:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n  .table-responsive > .table-bordered > thead > tr > td:last-child,\n  .table-responsive > .table-bordered > tbody > tr > td:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n    border-right: 0;\n  }\n  .table-responsive > .table-bordered > tbody > tr:last-child > th,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n  .table-responsive > .table-bordered > tbody > tr:last-child > td,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n    border-bottom: 0;\n  }\n}\nfieldset {\n  min-width: 0;\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 20px;\n  font-size: 21px;\n  line-height: inherit;\n  color: #333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n  display: inline-block;\n  max-width: 100%;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  line-height: normal;\n}\ninput[type=\"file\"] {\n  display: block;\n}\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\nselect[multiple],\nselect[size] {\n  height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\noutput {\n  display: block;\n  padding-top: 7px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555;\n}\n.form-control {\n  display: block;\n  width: 100%;\n  height: 34px;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555;\n  background-color: #fff;\n  background-image: none;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n       -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n          transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n  border-color: #66afe9;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n          box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n}\n.form-control::-moz-placeholder {\n  color: #999;\n  opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n  color: #999;\n}\n.form-control::-webkit-input-placeholder {\n  color: #999;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n  background-color: #eee;\n  opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n  cursor: not-allowed;\n}\ntextarea.form-control {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n  input[type=\"date\"].form-control,\n  input[type=\"time\"].form-control,\n  input[type=\"datetime-local\"].form-control,\n  input[type=\"month\"].form-control {\n    line-height: 34px;\n  }\n  input[type=\"date\"].input-sm,\n  input[type=\"time\"].input-sm,\n  input[type=\"datetime-local\"].input-sm,\n  input[type=\"month\"].input-sm,\n  .input-group-sm input[type=\"date\"],\n  .input-group-sm input[type=\"time\"],\n  .input-group-sm input[type=\"datetime-local\"],\n  .input-group-sm input[type=\"month\"] {\n    line-height: 30px;\n  }\n  input[type=\"date\"].input-lg,\n  input[type=\"time\"].input-lg,\n  input[type=\"datetime-local\"].input-lg,\n  input[type=\"month\"].input-lg,\n  .input-group-lg input[type=\"date\"],\n  .input-group-lg input[type=\"time\"],\n  .input-group-lg input[type=\"datetime-local\"],\n  .input-group-lg input[type=\"month\"] {\n    line-height: 46px;\n  }\n}\n.form-group {\n  margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n  position: relative;\n  display: block;\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n  min-height: 20px;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  position: absolute;\n  margin-top: 4px \\9;\n  margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n  position: relative;\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  vertical-align: middle;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n  cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n  cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n  cursor: not-allowed;\n}\n.form-control-static {\n  min-height: 34px;\n  padding-top: 7px;\n  padding-bottom: 7px;\n  margin-bottom: 0;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n  padding-right: 0;\n  padding-left: 0;\n}\n.input-sm {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-sm {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n  height: auto;\n}\n.form-group-sm .form-control {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.form-group-sm select.form-control {\n  height: 30px;\n  line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n  height: auto;\n}\n.form-group-sm .form-control-static {\n  height: 30px;\n  min-height: 32px;\n  padding: 6px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.input-lg {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-lg {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n  height: auto;\n}\n.form-group-lg .form-control {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.form-group-lg select.form-control {\n  height: 46px;\n  line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n  height: auto;\n}\n.form-group-lg .form-control-static {\n  height: 46px;\n  min-height: 38px;\n  padding: 11px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.has-feedback {\n  position: relative;\n}\n.has-feedback .form-control {\n  padding-right: 42.5px;\n}\n.form-control-feedback {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 2;\n  display: block;\n  width: 34px;\n  height: 34px;\n  line-height: 34px;\n  text-align: center;\n  pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n  width: 46px;\n  height: 46px;\n  line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n  width: 30px;\n  height: 30px;\n  line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n  color: #3c763d;\n}\n.has-success .form-control {\n  border-color: #3c763d;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-success .form-control:focus {\n  border-color: #2b542c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #3c763d;\n}\n.has-success .form-control-feedback {\n  color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n  color: #8a6d3b;\n}\n.has-warning .form-control {\n  border-color: #8a6d3b;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-warning .form-control:focus {\n  border-color: #66512c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #8a6d3b;\n}\n.has-warning .form-control-feedback {\n  color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n  color: #a94442;\n}\n.has-error .form-control {\n  border-color: #a94442;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-error .form-control:focus {\n  border-color: #843534;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #a94442;\n}\n.has-error .form-control-feedback {\n  color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n  top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n  top: 0;\n}\n.help-block {\n  display: block;\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: #737373;\n}\n@media (min-width: 768px) {\n  .form-inline .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .form-inline .form-control-static {\n    display: inline-block;\n  }\n  .form-inline .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .form-inline .input-group .input-group-addon,\n  .form-inline .input-group .input-group-btn,\n  .form-inline .input-group .form-control {\n    width: auto;\n  }\n  .form-inline .input-group > .form-control {\n    width: 100%;\n  }\n  .form-inline .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio,\n  .form-inline .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio label,\n  .form-inline .checkbox label {\n    padding-left: 0;\n  }\n  .form-inline .radio input[type=\"radio\"],\n  .form-inline .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .form-inline .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  padding-top: 7px;\n  margin-top: 0;\n  margin-bottom: 0;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n  min-height: 27px;\n}\n.form-horizontal .form-group {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .control-label {\n    padding-top: 7px;\n    margin-bottom: 0;\n    text-align: right;\n  }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n  right: 15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-lg .control-label {\n    padding-top: 14.333333px;\n    font-size: 18px;\n  }\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-sm .control-label {\n    padding-top: 6px;\n    font-size: 12px;\n  }\n}\n.btn {\n  display: inline-block;\n  padding: 6px 12px;\n  margin-bottom: 0;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: middle;\n  -ms-touch-action: manipulation;\n      touch-action: manipulation;\n  cursor: pointer;\n  -webkit-user-select: none;\n     -moz-user-select: none;\n      -ms-user-select: none;\n          user-select: none;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n  color: #333;\n  text-decoration: none;\n}\n.btn:active,\n.btn.active {\n  background-image: none;\n  outline: 0;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n  cursor: not-allowed;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n          box-shadow: none;\n  opacity: .65;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n  pointer-events: none;\n}\n.btn-default {\n  color: #333;\n  background-color: #fff;\n  border-color: #ccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #8c8c8c;\n}\n.btn-default:hover {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n  color: #333;\n  background-color: #d4d4d4;\n  border-color: #8c8c8c;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  background-image: none;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n  background-color: #fff;\n  border-color: #ccc;\n}\n.btn-default .badge {\n  color: #fff;\n  background-color: #333;\n}\n.btn-primary {\n  color: #fff;\n  background-color: #337ab7;\n  border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n  color: #fff;\n  background-color: #286090;\n  border-color: #122b40;\n}\n.btn-primary:hover {\n  color: #fff;\n  background-color: #286090;\n  border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  color: #fff;\n  background-color: #286090;\n  border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n  color: #fff;\n  background-color: #204d74;\n  border-color: #122b40;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  background-image: none;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n  background-color: #337ab7;\n  border-color: #2e6da4;\n}\n.btn-primary .badge {\n  color: #337ab7;\n  background-color: #fff;\n}\n.btn-success {\n  color: #fff;\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #255625;\n}\n.btn-success:hover {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n  color: #fff;\n  background-color: #398439;\n  border-color: #255625;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  background-image: none;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.btn-success .badge {\n  color: #5cb85c;\n  background-color: #fff;\n}\n.btn-info {\n  color: #fff;\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #1b6d85;\n}\n.btn-info:hover {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n  color: #fff;\n  background-color: #269abc;\n  border-color: #1b6d85;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  background-image: none;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.btn-info .badge {\n  color: #5bc0de;\n  background-color: #fff;\n}\n.btn-warning {\n  color: #fff;\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #985f0d;\n}\n.btn-warning:hover {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n  color: #fff;\n  background-color: #d58512;\n  border-color: #985f0d;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  background-image: none;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.btn-warning .badge {\n  color: #f0ad4e;\n  background-color: #fff;\n}\n.btn-danger {\n  color: #fff;\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #761c19;\n}\n.btn-danger:hover {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n  color: #fff;\n  background-color: #ac2925;\n  border-color: #761c19;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  background-image: none;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.btn-danger .badge {\n  color: #d9534f;\n  background-color: #fff;\n}\n.btn-link {\n  font-weight: normal;\n  color: #337ab7;\n  border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n  background-color: transparent;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n  border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n  color: #23527c;\n  text-decoration: underline;\n  background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n  color: #777;\n  text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n  padding: 1px 5px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-block {\n  display: block;\n  width: 100%;\n}\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n  width: 100%;\n}\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity .15s linear;\n       -o-transition: opacity .15s linear;\n          transition: opacity .15s linear;\n}\n.fade.in {\n  opacity: 1;\n}\n.collapse {\n  display: none;\n}\n.collapse.in {\n  display: block;\n}\ntr.collapse.in {\n  display: table-row;\n}\ntbody.collapse.in {\n  display: table-row-group;\n}\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition-timing-function: ease;\n       -o-transition-timing-function: ease;\n          transition-timing-function: ease;\n  -webkit-transition-duration: .35s;\n       -o-transition-duration: .35s;\n          transition-duration: .35s;\n  -webkit-transition-property: height, visibility;\n       -o-transition-property: height, visibility;\n          transition-property: height, visibility;\n}\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top: 4px dashed;\n  border-top: 4px solid \\9;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n  position: relative;\n}\n.dropdown-toggle:focus {\n  outline: 0;\n}\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  font-size: 14px;\n  text-align: left;\n  list-style: none;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, .15);\n  border-radius: 4px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n}\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu .divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 1.42857143;\n  color: #333;\n  white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  color: #262626;\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  color: #fff;\n  text-decoration: none;\n  background-color: #337ab7;\n  outline: 0;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  color: #777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  cursor: not-allowed;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.open > .dropdown-menu {\n  display: block;\n}\n.open > a {\n  outline: 0;\n}\n.dropdown-menu-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu-left {\n  right: auto;\n  left: 0;\n}\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.42857143;\n  color: #777;\n  white-space: nowrap;\n}\n.dropdown-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 990;\n}\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  content: \"\";\n  border-top: 0;\n  border-bottom: 4px dashed;\n  border-bottom: 4px solid \\9;\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n  .navbar-right .dropdown-menu {\n    right: 0;\n    left: auto;\n  }\n  .navbar-right .dropdown-menu-left {\n    right: auto;\n    left: 0;\n  }\n}\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n  position: relative;\n  float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n  z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n  margin-left: -1px;\n}\n.btn-toolbar {\n  margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n  float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n  margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n.btn-group > .btn:first-child {\n  margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n  padding-right: 8px;\n  padding-left: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-right: 12px;\n  padding-left: 12px;\n}\n.btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn .caret {\n  margin-left: 0;\n}\n.btn-lg .caret {\n  border-width: 5px 5px 0;\n  border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n  border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n  display: block;\n  float: none;\n  width: 100%;\n  max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n  float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n  margin-top: -1px;\n  margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n  border-bottom-left-radius: 4px;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n  display: table-cell;\n  float: none;\n  width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n  width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n  left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n  position: absolute;\n  clip: rect(0, 0, 0, 0);\n  pointer-events: none;\n}\n.input-group {\n  position: relative;\n  display: table;\n  border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n  float: none;\n  padding-right: 0;\n  padding-left: 0;\n}\n.input-group .form-control {\n  position: relative;\n  z-index: 2;\n  float: left;\n  width: 100%;\n  margin-bottom: 0;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n.input-group-addon {\n  padding: 6px 12px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1;\n  color: #555;\n  text-align: center;\n  background-color: #eee;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\n.input-group-addon.input-sm {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 3px;\n}\n.input-group-addon.input-lg {\n  padding: 10px 16px;\n  font-size: 18px;\n  border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n  margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n.input-group-btn {\n  position: relative;\n  font-size: 0;\n  white-space: nowrap;\n}\n.input-group-btn > .btn {\n  position: relative;\n}\n.input-group-btn > .btn + .btn {\n  margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n  z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n  margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n  z-index: 2;\n  margin-left: -1px;\n}\n.nav {\n  padding-left: 0;\n  margin-bottom: 0;\n  list-style: none;\n}\n.nav > li {\n  position: relative;\n  display: block;\n}\n.nav > li > a {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n  text-decoration: none;\n  background-color: #eee;\n}\n.nav > li.disabled > a {\n  color: #777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n  color: #777;\n  text-decoration: none;\n  cursor: not-allowed;\n  background-color: transparent;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n  background-color: #eee;\n  border-color: #337ab7;\n}\n.nav .nav-divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.nav > li > a > img {\n  max-width: none;\n}\n.nav-tabs {\n  border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n  float: left;\n  margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n  margin-right: 2px;\n  line-height: 1.42857143;\n  border: 1px solid transparent;\n  border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n  border-color: #eee #eee #ddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n  color: #555;\n  cursor: default;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-bottom-color: transparent;\n}\n.nav-tabs.nav-justified {\n  width: 100%;\n  border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n  float: none;\n}\n.nav-tabs.nav-justified > li > a {\n  margin-bottom: 5px;\n  text-align: center;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-tabs.nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs.nav-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n  border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #ddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs.nav-justified > .active > a,\n  .nav-tabs.nav-justified > .active > a:hover,\n  .nav-tabs.nav-justified > .active > a:focus {\n    border-bottom-color: #fff;\n  }\n}\n.nav-pills > li {\n  float: left;\n}\n.nav-pills > li > a {\n  border-radius: 4px;\n}\n.nav-pills > li + li {\n  margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n  color: #fff;\n  background-color: #337ab7;\n}\n.nav-stacked > li {\n  float: none;\n}\n.nav-stacked > li + li {\n  margin-top: 2px;\n  margin-left: 0;\n}\n.nav-justified {\n  width: 100%;\n}\n.nav-justified > li {\n  float: none;\n}\n.nav-justified > li > a {\n  margin-bottom: 5px;\n  text-align: center;\n}\n.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs-justified {\n  border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n  border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs-justified > li > a {\n    border-bottom: 1px solid #ddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs-justified > .active > a,\n  .nav-tabs-justified > .active > a:hover,\n  .nav-tabs-justified > .active > a:focus {\n    border-bottom-color: #fff;\n  }\n}\n.tab-content > .tab-pane {\n  display: none;\n}\n.tab-content > .active {\n  display: block;\n}\n.nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.navbar {\n  position: relative;\n  min-height: 50px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n  .navbar {\n    border-radius: 4px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-header {\n    float: left;\n  }\n}\n.navbar-collapse {\n  padding-right: 15px;\n  padding-left: 15px;\n  overflow-x: visible;\n  -webkit-overflow-scrolling: touch;\n  border-top: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n}\n.navbar-collapse.in {\n  overflow-y: auto;\n}\n@media (min-width: 768px) {\n  .navbar-collapse {\n    width: auto;\n    border-top: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .navbar-collapse.collapse {\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n  .navbar-collapse.in {\n    overflow-y: visible;\n  }\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-static-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    padding-right: 0;\n    padding-left: 0;\n  }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n  max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    max-height: 200px;\n  }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .container > .navbar-header,\n  .container-fluid > .navbar-header,\n  .container > .navbar-collapse,\n  .container-fluid > .navbar-collapse {\n    margin-right: 0;\n    margin-left: 0;\n  }\n}\n.navbar-static-top {\n  z-index: 1000;\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .navbar-static-top {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n}\n@media (min-width: 768px) {\n  .navbar-fixed-top,\n  .navbar-fixed-bottom {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0;\n  border-width: 1px 0 0;\n}\n.navbar-brand {\n  float: left;\n  height: 50px;\n  padding: 15px 15px;\n  font-size: 18px;\n  line-height: 20px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n  text-decoration: none;\n}\n.navbar-brand > img {\n  display: block;\n}\n@media (min-width: 768px) {\n  .navbar > .container .navbar-brand,\n  .navbar > .container-fluid .navbar-brand {\n    margin-left: -15px;\n  }\n}\n.navbar-toggle {\n  position: relative;\n  float: right;\n  padding: 9px 10px;\n  margin-top: 8px;\n  margin-right: 15px;\n  margin-bottom: 8px;\n  background-color: transparent;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.navbar-toggle:focus {\n  outline: 0;\n}\n.navbar-toggle .icon-bar {\n  display: block;\n  width: 22px;\n  height: 2px;\n  border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n  margin-top: 4px;\n}\n@media (min-width: 768px) {\n  .navbar-toggle {\n    display: none;\n  }\n}\n.navbar-nav {\n  margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 20px;\n}\n@media (max-width: 767px) {\n  .navbar-nav .open .dropdown-menu {\n    position: static;\n    float: none;\n    width: auto;\n    margin-top: 0;\n    background-color: transparent;\n    border: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .navbar-nav .open .dropdown-menu > li > a,\n  .navbar-nav .open .dropdown-menu .dropdown-header {\n    padding: 5px 15px 5px 25px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a {\n    line-height: 20px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-nav .open .dropdown-menu > li > a:focus {\n    background-image: none;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-nav {\n    float: left;\n    margin: 0;\n  }\n  .navbar-nav > li {\n    float: left;\n  }\n  .navbar-nav > li > a {\n    padding-top: 15px;\n    padding-bottom: 15px;\n  }\n}\n.navbar-form {\n  padding: 10px 15px;\n  margin-top: 8px;\n  margin-right: -15px;\n  margin-bottom: 8px;\n  margin-left: -15px;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n}\n@media (min-width: 768px) {\n  .navbar-form .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control-static {\n    display: inline-block;\n  }\n  .navbar-form .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .navbar-form .input-group .input-group-addon,\n  .navbar-form .input-group .input-group-btn,\n  .navbar-form .input-group .form-control {\n    width: auto;\n  }\n  .navbar-form .input-group > .form-control {\n    width: 100%;\n  }\n  .navbar-form .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio,\n  .navbar-form .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio label,\n  .navbar-form .checkbox label {\n    padding-left: 0;\n  }\n  .navbar-form .radio input[type=\"radio\"],\n  .navbar-form .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .navbar-form .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n@media (max-width: 767px) {\n  .navbar-form .form-group {\n    margin-bottom: 5px;\n  }\n  .navbar-form .form-group:last-child {\n    margin-bottom: 0;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-form {\n    width: auto;\n    padding-top: 0;\n    padding-bottom: 0;\n    margin-right: 0;\n    margin-left: 0;\n    border: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n}\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  margin-bottom: 0;\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.navbar-btn {\n  margin-top: 8px;\n  margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n  margin-top: 14px;\n  margin-bottom: 14px;\n}\n.navbar-text {\n  margin-top: 15px;\n  margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n  .navbar-text {\n    float: left;\n    margin-right: 15px;\n    margin-left: 15px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-left {\n    float: left !important;\n  }\n  .navbar-right {\n    float: right !important;\n    margin-right: -15px;\n  }\n  .navbar-right ~ .navbar-right {\n    margin-right: 0;\n  }\n}\n.navbar-default {\n  background-color: #f8f8f8;\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n  color: #777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n  color: #5e5e5e;\n  background-color: transparent;\n}\n.navbar-default .navbar-text {\n  color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n  color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n  color: #333;\n  background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n  color: #ccc;\n  background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n  border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n  background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n  background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n@media (max-width: 767px) {\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #777;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #333;\n    background-color: transparent;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #555;\n    background-color: #e7e7e7;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #ccc;\n    background-color: transparent;\n  }\n}\n.navbar-default .navbar-link {\n  color: #777;\n}\n.navbar-default .navbar-link:hover {\n  color: #333;\n}\n.navbar-default .btn-link {\n  color: #777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n  color: #333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n  color: #ccc;\n}\n.navbar-inverse {\n  background-color: #222;\n  border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n  color: #fff;\n  background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n  color: #444;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n  border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n  background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n  border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n  color: #fff;\n  background-color: #080808;\n}\n@media (max-width: 767px) {\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n    background-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n    color: #9d9d9d;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #fff;\n    background-color: transparent;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #fff;\n    background-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #444;\n    background-color: transparent;\n  }\n}\n.navbar-inverse .navbar-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n  color: #fff;\n}\n.navbar-inverse .btn-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n  color: #fff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n  color: #444;\n}\n.breadcrumb {\n  padding: 8px 15px;\n  margin-bottom: 20px;\n  list-style: none;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n}\n.breadcrumb > li {\n  display: inline-block;\n}\n.breadcrumb > li + li:before {\n  padding: 0 5px;\n  color: #ccc;\n  content: \"/\\00a0\";\n}\n.breadcrumb > .active {\n  color: #777;\n}\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 20px 0;\n  border-radius: 4px;\n}\n.pagination > li {\n  display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n  position: relative;\n  float: left;\n  padding: 6px 12px;\n  margin-left: -1px;\n  line-height: 1.42857143;\n  color: #337ab7;\n  text-decoration: none;\n  background-color: #fff;\n  border: 1px solid #ddd;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n  margin-left: 0;\n  border-top-left-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n  z-index: 3;\n  color: #23527c;\n  background-color: #eee;\n  border-color: #ddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n  z-index: 2;\n  color: #fff;\n  cursor: default;\n  background-color: #337ab7;\n  border-color: #337ab7;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n  color: #777;\n  cursor: not-allowed;\n  background-color: #fff;\n  border-color: #ddd;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n  border-top-left-radius: 6px;\n  border-bottom-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n  border-top-right-radius: 6px;\n  border-bottom-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.pager {\n  padding-left: 0;\n  margin: 20px 0;\n  text-align: center;\n  list-style: none;\n}\n.pager li {\n  display: inline;\n}\n.pager li > a,\n.pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n  text-decoration: none;\n  background-color: #eee;\n}\n.pager .next > a,\n.pager .next > span {\n  float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n  float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n  color: #777;\n  cursor: not-allowed;\n  background-color: #fff;\n}\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: #fff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n  color: #fff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.label:empty {\n  display: none;\n}\n.btn .label {\n  position: relative;\n  top: -1px;\n}\n.label-default {\n  background-color: #777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n  background-color: #5e5e5e;\n}\n.label-primary {\n  background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n  background-color: #286090;\n}\n.label-success {\n  background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n  background-color: #449d44;\n}\n.label-info {\n  background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n  background-color: #31b0d5;\n}\n.label-warning {\n  background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n  background-color: #ec971f;\n}\n.label-danger {\n  background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n  background-color: #c9302c;\n}\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: bold;\n  line-height: 1;\n  color: #fff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: middle;\n  background-color: #777;\n  border-radius: 10px;\n}\n.badge:empty {\n  display: none;\n}\n.btn .badge {\n  position: relative;\n  top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n  top: 0;\n  padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n  color: #fff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: #337ab7;\n  background-color: #fff;\n}\n.list-group-item > .badge {\n  float: right;\n}\n.list-group-item > .badge + .badge {\n  margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n.jumbotron {\n  padding-top: 30px;\n  padding-bottom: 30px;\n  margin-bottom: 30px;\n  color: inherit;\n  background-color: #eee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n  color: inherit;\n}\n.jumbotron p {\n  margin-bottom: 15px;\n  font-size: 21px;\n  font-weight: 200;\n}\n.jumbotron > hr {\n  border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n  border-radius: 6px;\n}\n.jumbotron .container {\n  max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n  .jumbotron {\n    padding-top: 48px;\n    padding-bottom: 48px;\n  }\n  .container .jumbotron,\n  .container-fluid .jumbotron {\n    padding-right: 60px;\n    padding-left: 60px;\n  }\n  .jumbotron h1,\n  .jumbotron .h1 {\n    font-size: 63px;\n  }\n}\n.thumbnail {\n  display: block;\n  padding: 4px;\n  margin-bottom: 20px;\n  line-height: 1.42857143;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n  -webkit-transition: border .2s ease-in-out;\n       -o-transition: border .2s ease-in-out;\n          transition: border .2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n  margin-right: auto;\n  margin-left: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #337ab7;\n}\n.thumbnail .caption {\n  padding: 9px;\n  color: #333;\n}\n.alert {\n  padding: 15px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.alert h4 {\n  margin-top: 0;\n  color: inherit;\n}\n.alert .alert-link {\n  font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n  margin-bottom: 0;\n}\n.alert > p + p {\n  margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n  padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  color: inherit;\n}\n.alert-success {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.alert-success hr {\n  border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n  color: #2b542c;\n}\n.alert-info {\n  color: #31708f;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.alert-info hr {\n  border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n  color: #245269;\n}\n.alert-warning {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.alert-warning hr {\n  border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n  color: #66512c;\n}\n.alert-danger {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.alert-danger hr {\n  border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n  color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@-o-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n.progress {\n  height: 20px;\n  margin-bottom: 20px;\n  overflow: hidden;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n}\n.progress-bar {\n  float: left;\n  width: 0;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #fff;\n  text-align: center;\n  background-color: #337ab7;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n  -webkit-transition: width .6s ease;\n       -o-transition: width .6s ease;\n          transition: width .6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  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);\n  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);\n  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);\n  -webkit-background-size: 40px 40px;\n          background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n       -o-animation: progress-bar-stripes 2s linear infinite;\n          animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n  background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n  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);\n  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);\n  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);\n}\n.progress-bar-info {\n  background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n  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);\n  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);\n  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);\n}\n.progress-bar-warning {\n  background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n  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);\n  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);\n  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);\n}\n.progress-bar-danger {\n  background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n  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);\n  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);\n  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);\n}\n.media {\n  margin-top: 15px;\n}\n.media:first-child {\n  margin-top: 0;\n}\n.media,\n.media-body {\n  overflow: hidden;\n  zoom: 1;\n}\n.media-body {\n  width: 10000px;\n}\n.media-object {\n  display: block;\n}\n.media-object.img-thumbnail {\n  max-width: none;\n}\n.media-right,\n.media > .pull-right {\n  padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n  padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n  display: table-cell;\n  vertical-align: top;\n}\n.media-middle {\n  vertical-align: middle;\n}\n.media-bottom {\n  vertical-align: bottom;\n}\n.media-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n.list-group {\n  padding-left: 0;\n  margin-bottom: 20px;\n}\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n}\n.list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\na.list-group-item,\nbutton.list-group-item {\n  color: #555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n  color: #333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n  color: #555;\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\nbutton.list-group-item {\n  width: 100%;\n  text-align: left;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n  color: #777;\n  cursor: not-allowed;\n  background-color: #eee;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n  color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n  color: #777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  z-index: 2;\n  color: #fff;\n  background-color: #337ab7;\n  border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n  color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n  color: #c7ddef;\n}\n.list-group-item-success {\n  color: #3c763d;\n  background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n  color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n  color: #3c763d;\n  background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n  color: #fff;\n  background-color: #3c763d;\n  border-color: #3c763d;\n}\n.list-group-item-info {\n  color: #31708f;\n  background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n  color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n  color: #31708f;\n  background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n  color: #fff;\n  background-color: #31708f;\n  border-color: #31708f;\n}\n.list-group-item-warning {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n  color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n  color: #8a6d3b;\n  background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n  color: #fff;\n  background-color: #8a6d3b;\n  border-color: #8a6d3b;\n}\n.list-group-item-danger {\n  color: #a94442;\n  background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n  color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n  color: #a94442;\n  background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n  color: #fff;\n  background-color: #a94442;\n  border-color: #a94442;\n}\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n.panel {\n  margin-bottom: 20px;\n  background-color: #fff;\n  border: 1px solid transparent;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n          box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n}\n.panel-body {\n  padding: 15px;\n}\n.panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n  color: inherit;\n}\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: 16px;\n  color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n  color: inherit;\n}\n.panel-footer {\n  padding: 10px 15px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #ddd;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n  margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n  border-width: 1px 0;\n  border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n  border-top: 0;\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n  border-bottom: 0;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n  border-top-width: 0;\n}\n.list-group + .panel-footer {\n  border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n  margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n  padding-right: 15px;\n  padding-left: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n  border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n  border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n  border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n  border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n  border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n  border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n  border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n  border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n  border-bottom: 0;\n}\n.panel > .table-responsive {\n  margin-bottom: 0;\n  border: 0;\n}\n.panel-group {\n  margin-bottom: 20px;\n}\n.panel-group .panel {\n  margin-bottom: 0;\n  border-radius: 4px;\n}\n.panel-group .panel + .panel {\n  margin-top: 5px;\n}\n.panel-group .panel-heading {\n  border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n  border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n  border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n  border-bottom: 1px solid #ddd;\n}\n.panel-default {\n  border-color: #ddd;\n}\n.panel-default > .panel-heading {\n  color: #333;\n  background-color: #f5f5f5;\n  border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #ddd;\n}\n.panel-default > .panel-heading .badge {\n  color: #f5f5f5;\n  background-color: #333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #ddd;\n}\n.panel-primary {\n  border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n  color: #fff;\n  background-color: #337ab7;\n  border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n  color: #337ab7;\n  background-color: #fff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #337ab7;\n}\n.panel-success {\n  border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n  color: #dff0d8;\n  background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #d6e9c6;\n}\n.panel-info {\n  border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n  color: #31708f;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n  color: #d9edf7;\n  background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #bce8f1;\n}\n.panel-warning {\n  border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n  color: #fcf8e3;\n  background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #faebcc;\n}\n.panel-danger {\n  border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n  color: #f2dede;\n  background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n  position: relative;\n  display: block;\n  height: 0;\n  padding: 0;\n  overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  border: 0;\n}\n.embed-responsive-16by9 {\n  padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n  padding-bottom: 75%;\n}\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border: 1px solid #e3e3e3;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n}\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, .15);\n}\n.well-lg {\n  padding: 24px;\n  border-radius: 6px;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: 3px;\n}\n.close {\n  float: right;\n  font-size: 21px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000;\n  text-shadow: 0 1px 0 #fff;\n  filter: alpha(opacity=20);\n  opacity: .2;\n}\n.close:hover,\n.close:focus {\n  color: #000;\n  text-decoration: none;\n  cursor: pointer;\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\nbutton.close {\n  -webkit-appearance: none;\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n}\n.modal-open {\n  overflow: hidden;\n}\n.modal {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1050;\n  display: none;\n  overflow: hidden;\n  -webkit-overflow-scrolling: touch;\n  outline: 0;\n}\n.modal.fade .modal-dialog {\n  -webkit-transition: -webkit-transform .3s ease-out;\n       -o-transition:      -o-transform .3s ease-out;\n          transition:         transform .3s ease-out;\n  -webkit-transform: translate(0, -25%);\n      -ms-transform: translate(0, -25%);\n       -o-transform: translate(0, -25%);\n          transform: translate(0, -25%);\n}\n.modal.in .modal-dialog {\n  -webkit-transform: translate(0, 0);\n      -ms-transform: translate(0, 0);\n       -o-transform: translate(0, 0);\n          transform: translate(0, 0);\n}\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n.modal-content {\n  position: relative;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #999;\n  border: 1px solid rgba(0, 0, 0, .2);\n  border-radius: 6px;\n  outline: 0;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n          box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n}\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000;\n}\n.modal-backdrop.fade {\n  filter: alpha(opacity=0);\n  opacity: 0;\n}\n.modal-backdrop.in {\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\n.modal-header {\n  min-height: 16.42857143px;\n  padding: 15px;\n  border-bottom: 1px solid #e5e5e5;\n}\n.modal-header .close {\n  margin-top: -2px;\n}\n.modal-title {\n  margin: 0;\n  line-height: 1.42857143;\n}\n.modal-body {\n  position: relative;\n  padding: 15px;\n}\n.modal-footer {\n  padding: 15px;\n  text-align: right;\n  border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n  margin-bottom: 0;\n  margin-left: 5px;\n}\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n  margin-left: 0;\n}\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n@media (min-width: 768px) {\n  .modal-dialog {\n    width: 600px;\n    margin: 30px auto;\n  }\n  .modal-content {\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n            box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n  }\n  .modal-sm {\n    width: 300px;\n  }\n}\n@media (min-width: 992px) {\n  .modal-lg {\n    width: 900px;\n  }\n}\n.tooltip {\n  position: absolute;\n  z-index: 1070;\n  display: block;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 12px;\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  letter-spacing: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  white-space: normal;\n  filter: alpha(opacity=0);\n  opacity: 0;\n\n  line-break: auto;\n}\n.tooltip.in {\n  filter: alpha(opacity=90);\n  opacity: .9;\n}\n.tooltip.top {\n  padding: 5px 0;\n  margin-top: -3px;\n}\n.tooltip.right {\n  padding: 0 5px;\n  margin-left: 3px;\n}\n.tooltip.bottom {\n  padding: 5px 0;\n  margin-top: 3px;\n}\n.tooltip.left {\n  padding: 0 5px;\n  margin-left: -3px;\n}\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #fff;\n  text-align: center;\n  background-color: #000;\n  border-radius: 4px;\n}\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n  right: 5px;\n  bottom: 0;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n  bottom: 0;\n  left: 5px;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-width: 5px 5px 5px 0;\n  border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-width: 5px 0 5px 5px;\n  border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n  top: 0;\n  right: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n  top: 0;\n  left: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1060;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  letter-spacing: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  white-space: normal;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, .2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n\n  line-break: auto;\n}\n.popover.top {\n  margin-top: -10px;\n}\n.popover.right {\n  margin-left: 10px;\n}\n.popover.bottom {\n  margin-top: 10px;\n}\n.popover.left {\n  margin-left: -10px;\n}\n.popover-title {\n  padding: 8px 14px;\n  margin: 0;\n  font-size: 14px;\n  background-color: #f7f7f7;\n  border-bottom: 1px solid #ebebeb;\n  border-radius: 5px 5px 0 0;\n}\n.popover-content {\n  padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n  position: absolute;\n  display: block;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.popover > .arrow {\n  border-width: 11px;\n}\n.popover > .arrow:after {\n  content: \"\";\n  border-width: 10px;\n}\n.popover.top > .arrow {\n  bottom: -11px;\n  left: 50%;\n  margin-left: -11px;\n  border-top-color: #999;\n  border-top-color: rgba(0, 0, 0, .25);\n  border-bottom-width: 0;\n}\n.popover.top > .arrow:after {\n  bottom: 1px;\n  margin-left: -10px;\n  content: \" \";\n  border-top-color: #fff;\n  border-bottom-width: 0;\n}\n.popover.right > .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-right-color: #999;\n  border-right-color: rgba(0, 0, 0, .25);\n  border-left-width: 0;\n}\n.popover.right > .arrow:after {\n  bottom: -10px;\n  left: 1px;\n  content: \" \";\n  border-right-color: #fff;\n  border-left-width: 0;\n}\n.popover.bottom > .arrow {\n  top: -11px;\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #999;\n  border-bottom-color: rgba(0, 0, 0, .25);\n}\n.popover.bottom > .arrow:after {\n  top: 1px;\n  margin-left: -10px;\n  content: \" \";\n  border-top-width: 0;\n  border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #999;\n  border-left-color: rgba(0, 0, 0, .25);\n}\n.popover.left > .arrow:after {\n  right: 1px;\n  bottom: -10px;\n  content: \" \";\n  border-right-width: 0;\n  border-left-color: #fff;\n}\n.carousel {\n  position: relative;\n}\n.carousel-inner {\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n}\n.carousel-inner > .item {\n  position: relative;\n  display: none;\n  -webkit-transition: .6s ease-in-out left;\n       -o-transition: .6s ease-in-out left;\n          transition: .6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n  .carousel-inner > .item {\n    -webkit-transition: -webkit-transform .6s ease-in-out;\n         -o-transition:      -o-transform .6s ease-in-out;\n            transition:         transform .6s ease-in-out;\n\n    -webkit-backface-visibility: hidden;\n            backface-visibility: hidden;\n    -webkit-perspective: 1000px;\n            perspective: 1000px;\n  }\n  .carousel-inner > .item.next,\n  .carousel-inner > .item.active.right {\n    left: 0;\n    -webkit-transform: translate3d(100%, 0, 0);\n            transform: translate3d(100%, 0, 0);\n  }\n  .carousel-inner > .item.prev,\n  .carousel-inner > .item.active.left {\n    left: 0;\n    -webkit-transform: translate3d(-100%, 0, 0);\n            transform: translate3d(-100%, 0, 0);\n  }\n  .carousel-inner > .item.next.left,\n  .carousel-inner > .item.prev.right,\n  .carousel-inner > .item.active {\n    left: 0;\n    -webkit-transform: translate3d(0, 0, 0);\n            transform: translate3d(0, 0, 0);\n  }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  display: block;\n}\n.carousel-inner > .active {\n  left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n.carousel-inner > .next {\n  left: 100%;\n}\n.carousel-inner > .prev {\n  left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n  left: 0;\n}\n.carousel-inner > .active.left {\n  left: -100%;\n}\n.carousel-inner > .active.right {\n  left: 100%;\n}\n.carousel-control {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 15%;\n  font-size: 20px;\n  color: #fff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\n.carousel-control.left {\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));\n  background-image:         linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n  background-repeat: repeat-x;\n}\n.carousel-control.right {\n  right: 0;\n  left: auto;\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));\n  background-image:         linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n  background-repeat: repeat-x;\n}\n.carousel-control:hover,\n.carousel-control:focus {\n  color: #fff;\n  text-decoration: none;\n  filter: alpha(opacity=90);\n  outline: 0;\n  opacity: .9;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n  position: absolute;\n  top: 50%;\n  z-index: 5;\n  display: inline-block;\n  margin-top: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n  left: 50%;\n  margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n  right: 50%;\n  margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n  width: 20px;\n  height: 20px;\n  font-family: serif;\n  line-height: 1;\n}\n.carousel-control .icon-prev:before {\n  content: '\\2039';\n}\n.carousel-control .icon-next:before {\n  content: '\\203a';\n}\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  padding-left: 0;\n  margin-left: -30%;\n  text-align: center;\n  list-style: none;\n}\n.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  cursor: pointer;\n  background-color: #000 \\9;\n  background-color: rgba(0, 0, 0, 0);\n  border: 1px solid #fff;\n  border-radius: 10px;\n}\n.carousel-indicators .active {\n  width: 12px;\n  height: 12px;\n  margin: 0;\n  background-color: #fff;\n}\n.carousel-caption {\n  position: absolute;\n  right: 15%;\n  bottom: 20px;\n  left: 15%;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #fff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n}\n.carousel-caption .btn {\n  text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next {\n    width: 30px;\n    height: 30px;\n    margin-top: -15px;\n    font-size: 30px;\n  }\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .icon-prev {\n    margin-left: -15px;\n  }\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-next {\n    margin-right: -15px;\n  }\n  .carousel-caption {\n    right: 20%;\n    left: 20%;\n    padding-bottom: 30px;\n  }\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-footer:before,\n.modal-footer:after {\n  display: table;\n  content: \" \";\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-footer:after {\n  clear: both;\n}\n.center-block {\n  display: block;\n  margin-right: auto;\n  margin-left: auto;\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n.hidden {\n  display: none !important;\n}\n.affix {\n  position: fixed;\n}\n@-ms-viewport {\n  width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-xs {\n    display: block !important;\n  }\n  table.visible-xs {\n    display: table !important;\n  }\n  tr.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-xs,\n  td.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-block {\n    display: block !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline {\n    display: inline !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm {\n    display: block !important;\n  }\n  table.visible-sm {\n    display: table !important;\n  }\n  tr.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-sm,\n  td.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-block {\n    display: block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md {\n    display: block !important;\n  }\n  table.visible-md {\n    display: table !important;\n  }\n  tr.visible-md {\n    display: table-row !important;\n  }\n  th.visible-md,\n  td.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-block {\n    display: block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg {\n    display: block !important;\n  }\n  table.visible-lg {\n    display: table !important;\n  }\n  tr.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-lg,\n  td.visible-lg {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-block {\n    display: block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (max-width: 767px) {\n  .hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-lg {\n    display: none !important;\n  }\n}\n.visible-print {\n  display: none !important;\n}\n@media print {\n  .visible-print {\n    display: block !important;\n  }\n  table.visible-print {\n    display: table !important;\n  }\n  tr.visible-print {\n    display: table-row !important;\n  }\n  th.visible-print,\n  td.visible-print {\n    display: table-cell !important;\n  }\n}\n.visible-print-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-block {\n    display: block !important;\n  }\n}\n.visible-print-inline {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline {\n    display: inline !important;\n  }\n}\n.visible-print-inline-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline-block {\n    display: inline-block !important;\n  }\n}\n@media print {\n  .hidden-print {\n    display: none !important;\n  }\n}\n/*# sourceMappingURL=bootstrap.css.map */\n"
  },
  {
    "path": "resources/public/css/jquery.minicolors.css",
    "content": ".minicolors {\n  position: relative;\n}\n\n.minicolors-sprite {\n  background-image: url(jquery.minicolors.png);\n}\n\n.minicolors-swatch {\n  position: absolute;\n  vertical-align: middle;\n  background-position: -80px 0;\n  border: solid 1px #ccc;\n  cursor: text;\n  padding: 0;\n  margin: 0;\n  display: inline-block;\n}\n\n.minicolors-swatch-color {\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n}\n\n.minicolors input[type=hidden] + .minicolors-swatch {\n  width: 28px;\n  position: static;\n  cursor: pointer;\n}\n\n.minicolors input[type=hidden][disabled] + .minicolors-swatch {\n  cursor: default;\n}\n\n/* Panel */\n.minicolors-panel {\n  position: absolute;\n  width: 173px;\n  background: white;\n  border: solid 1px #CCC;\n  box-shadow: 0 0 20px rgba(0, 0, 0, .2);\n  z-index: 99999;\n  box-sizing: content-box;\n  display: none;\n}\n\n.minicolors-panel.minicolors-visible {\n  display: block;\n}\n\n/* Panel positioning */\n.minicolors-position-top .minicolors-panel {\n  top: -154px;\n}\n\n.minicolors-position-right .minicolors-panel {\n  right: 0;\n}\n\n.minicolors-position-bottom .minicolors-panel {\n  top: auto;\n}\n\n.minicolors-position-left .minicolors-panel {\n  left: 0;\n}\n\n.minicolors-with-opacity .minicolors-panel {\n  width: 194px;\n}\n\n.minicolors .minicolors-grid {\n  position: relative;\n  top: 1px;\n  left: 1px; /* LTR */\n  width: 150px;\n  height: 150px;\n  margin-bottom: 2px;\n  background-position: -120px 0;\n  cursor: crosshair;\n}\n[dir=rtl] .minicolors .minicolors-grid {\n  right: 1px;\n}\n\n.minicolors .minicolors-grid-inner {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 150px;\n  height: 150px;\n}\n\n.minicolors-slider-saturation .minicolors-grid {\n  background-position: -420px 0;\n}\n\n.minicolors-slider-saturation .minicolors-grid-inner {\n  background-position: -270px 0;\n  background-image: inherit;\n}\n\n.minicolors-slider-brightness .minicolors-grid {\n  background-position: -570px 0;\n}\n\n.minicolors-slider-brightness .minicolors-grid-inner {\n  background-color: black;\n}\n\n.minicolors-slider-wheel .minicolors-grid {\n  background-position: -720px 0;\n}\n\n.minicolors-slider,\n.minicolors-opacity-slider {\n  position: absolute;\n  top: 1px;\n  left: 152px; /* LTR */\n  width: 20px;\n  height: 150px;\n  background-color: white;\n  background-position: 0 0;\n  cursor: row-resize;\n}\n[dir=rtl] .minicolors-slider,\n[dir=rtl] .minicolors-opacity-slider {\n  right: 152px;\n}\n\n.minicolors-slider-saturation .minicolors-slider {\n  background-position: -60px 0;\n}\n\n.minicolors-slider-brightness .minicolors-slider {\n  background-position: -20px 0;\n}\n\n.minicolors-slider-wheel .minicolors-slider {\n  background-position: -20px 0;\n}\n\n.minicolors-opacity-slider {\n  left: 173px; /* LTR */\n  background-position: -40px 0;\n  display: none;\n}\n[dir=rtl] .minicolors-opacity-slider {\n  right: 173px;\n}\n\n.minicolors-with-opacity .minicolors-opacity-slider {\n  display: block;\n}\n\n/* Pickers */\n.minicolors-grid .minicolors-picker {\n  position: absolute;\n  top: 70px;\n  left: 70px;\n  width: 12px;\n  height: 12px;\n  border: solid 1px black;\n  border-radius: 10px;\n  margin-top: -6px;\n  margin-left: -6px;\n  background: none;\n}\n\n.minicolors-grid .minicolors-picker > div {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 8px;\n  height: 8px;\n  border-radius: 8px;\n  border: solid 2px white;\n  box-sizing: content-box;\n}\n\n.minicolors-picker {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 18px;\n  height: 2px;\n  background: white;\n  border: solid 1px black;\n  margin-top: -2px;\n  box-sizing: content-box;\n}\n\n/* Swatches */\n.minicolors-swatches,\n.minicolors-swatches li {\n  margin: 5px 0 3px 5px; /* LTR */\n  padding: 0;\n  list-style: none;\n  overflow: hidden;\n}\n[dir=rtl] .minicolors-swatches,\n[dir=rtl] .minicolors-swatches li {\n  margin: 5px 5px 3px 0;\n}\n\n.minicolors-swatches .minicolors-swatch {\n  position: relative;\n  float: left; /* LTR */\n  cursor: pointer;\n  margin:0 4px 0 0; /* LTR */\n}\n[dir=rtl] .minicolors-swatches .minicolors-swatch {\n  float: right;\n  margin:0 0 0 4px;\n}\n\n.minicolors-with-opacity .minicolors-swatches .minicolors-swatch {\n  margin-right: 7px; /* LTR */\n}\n[dir=rtl] .minicolors-with-opacity .minicolors-swatches .minicolors-swatch {\n  margin-right: 0;\n  margin-left: 7px;\n}\n\n.minicolors-swatch.selected {\n  border-color: #000;\n}\n\n/* Inline controls */\n.minicolors-inline {\n  display: inline-block;\n}\n\n.minicolors-inline .minicolors-input {\n  display: none !important;\n}\n\n.minicolors-inline .minicolors-panel {\n  position: relative;\n  top: auto;\n  left: auto; /* LTR */\n  box-shadow: none;\n  z-index: auto;\n  display: inline-block;\n}\n[dir=rtl] .minicolors-inline .minicolors-panel {\n  right: auto;\n}\n\n/* Default theme */\n.minicolors-theme-default .minicolors-swatch {\n  top: 5px;\n  left: 5px; /* LTR */\n  width: 18px;\n  height: 18px;\n}\n[dir=rtl] .minicolors-theme-default .minicolors-swatch {\n  right: 5px;\n}\n.minicolors-theme-default .minicolors-swatches .minicolors-swatch {\n  margin-bottom: 2px;\n  top: 0;\n  left: 0; /* LTR */\n  width: 18px;\n  height: 18px;\n}\n[dir=rtl] .minicolors-theme-default .minicolors-swatches .minicolors-swatch {\n  right: 0;\n}\n.minicolors-theme-default.minicolors-position-right .minicolors-swatch {\n  left: auto; /* LTR */\n  right: 5px; /* LTR */\n}\n[dir=rtl] .minicolors-theme-default.minicolors-position-left .minicolors-swatch {\n  right: auto;\n  left: 5px;\n}\n.minicolors-theme-default.minicolors {\n  width: auto;\n  display: inline-block;\n}\n.minicolors-theme-default .minicolors-input {\n  height: 20px;\n  width: auto;\n  display: inline-block;\n  padding-left: 26px; /* LTR */\n}\n[dir=rtl] .minicolors-theme-default .minicolors-input {\n  text-align: right;\n  unicode-bidi: plaintext;\n  padding-left: 1px;\n  padding-right: 26px;\n}\n.minicolors-theme-default.minicolors-position-right .minicolors-input {\n  padding-right: 26px; /* LTR */\n  padding-left: inherit; /* LTR */\n}\n[dir=rtl] .minicolors-theme-default.minicolors-position-left .minicolors-input {\n  padding-right: inherit;\n  padding-left: 26px;\n}\n\n/* Bootstrap theme */\n.minicolors-theme-bootstrap .minicolors-swatch {\n  z-index: 2;\n  top: 3px;\n  left: 3px; /* LTR */\n  width: 28px;\n  height: 28px;\n  border-radius: 3px;\n}\n[dir=rtl] .minicolors-theme-bootstrap .minicolors-swatch {\n  right: 3px;\n}\n.minicolors-theme-bootstrap .minicolors-swatches .minicolors-swatch {\n  margin-bottom: 2px;\n  top: 0;\n  left: 0; /* LTR */\n  width: 20px;\n  height: 20px;\n}\n[dir=rtl] .minicolors-theme-bootstrap .minicolors-swatches .minicolors-swatch {\n  right: 0;\n}\n.minicolors-theme-bootstrap .minicolors-swatch-color {\n  border-radius: inherit;\n}\n.minicolors-theme-bootstrap.minicolors-position-right > .minicolors-swatch {\n  left: auto; /* LTR */\n  right: 3px; /* LTR */\n}\n[dir=rtl] .minicolors-theme-bootstrap.minicolors-position-left > .minicolors-swatch {\n  right: auto;\n  left: 3px;\n}\n.minicolors-theme-bootstrap .minicolors-input {\n  float: none;\n  padding-left: 44px; /* LTR */\n}\n[dir=rtl] .minicolors-theme-bootstrap .minicolors-input {\n  text-align: right;\n  unicode-bidi: plaintext;\n  padding-left: 12px;\n  padding-right: 44px;\n}\n.minicolors-theme-bootstrap.minicolors-position-right .minicolors-input {\n  padding-right: 44px; /* LTR */\n  padding-left: 12px; /* LTR */\n}\n[dir=rtl] .minicolors-theme-bootstrap.minicolors-position-left .minicolors-input {\n  padding-right: 12px;\n  padding-left: 44px;\n}\n.minicolors-theme-bootstrap .minicolors-input.input-lg + .minicolors-swatch {\n  top: 4px;\n  left: 4px; /* LTR */\n  width: 37px;\n  height: 37px;\n  border-radius: 5px;\n}\n[dir=rtl] .minicolors-theme-bootstrap .minicolors-input.input-lg + .minicolors-swatch {\n  right: 4px;\n}\n.minicolors-theme-bootstrap .minicolors-input.input-sm + .minicolors-swatch {\n  width: 24px;\n  height: 24px;\n}\n.minicolors-theme-bootstrap .minicolors-input.input-xs + .minicolors-swatch {\n  width: 18px;\n  height: 18px;\n}\n.input-group .minicolors-theme-bootstrap:not(:first-child) .minicolors-input {\n  border-top-left-radius: 0; /* LTR */\n  border-bottom-left-radius: 0; /* LTR */\n}\n[dir=rtl] .input-group .minicolors-theme-bootstrap .minicolors-input {\n  border-radius: 4px;\n}\n[dir=rtl] .input-group .minicolors-theme-bootstrap:not(:first-child) .minicolors-input {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n[dir=rtl] .input-group .minicolors-theme-bootstrap:not(:last-child) .minicolors-input {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n/* bootstrap input-group rtl override */\n[dir=rtl] .input-group .form-control,\n[dir=rtl] .input-group-addon,\n[dir=rtl] .input-group-btn > .btn,\n[dir=rtl] .input-group-btn > .btn-group > .btn,\n[dir=rtl] .input-group-btn > .dropdown-toggle {\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\n[dir=rtl] .input-group .form-control:first-child,\n[dir=rtl] .input-group-addon:first-child,\n[dir=rtl] .input-group-btn:first-child > .btn,\n[dir=rtl] .input-group-btn:first-child > .btn-group > .btn,\n[dir=rtl] .input-group-btn:first-child > .dropdown-toggle,\n[dir=rtl] .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n[dir=rtl] .input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n  border-left: 0;\n}\n[dir=rtl] .input-group .form-control:last-child,\n[dir=rtl] .input-group-addon:last-child,\n[dir=rtl] .input-group-btn:last-child > .btn,\n[dir=rtl] .input-group-btn:last-child > .btn-group > .btn,\n[dir=rtl] .input-group-btn:last-child > .dropdown-toggle,\n[dir=rtl] .input-group-btn:first-child > .btn:not(:first-child),\n[dir=rtl] .input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n\n/* Semantic Ui theme */\n.minicolors-theme-semanticui .minicolors-swatch {\n  top: 0;\n  left: 0; /* LTR */\n  padding: 18px;\n}\n[dir=rtl] .minicolors-theme-semanticui .minicolors-swatch {\n  right: 0;\n}\n.minicolors-theme-semanticui input {\n  text-indent: 30px;\n}\n"
  },
  {
    "path": "resources/public/css/screen.css",
    "content": "html,\nbody {\n    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n    height: 100%;\n    padding-top: 35px;\n}\n.table>tbody>tr>td {\n    padding: 3px;\n}\n.table-bordered>tbody>tr>td {\n    border: 2px solid #060606;\n}\n"
  },
  {
    "path": "resources/public/css/show.css",
    "content": "td.cue-cell {\n    width: 90px;\n    max-width: 100px;\n    height: 50px;\n    max-height: 60px;\n    text-align: center;\n    overflow: hidden;\n    -ms-text-overflow: ellipsis;\n    -o-text-overflow: ellipsis;\n    text-overflow: ellipsis;\n    word-wrap: break-word;\n    -webkit-user-select: none; /* webkit (safari, chrome) browsers */\n    -moz-user-select: none; /* mozilla browsers */\n    -khtml-user-select: none; /* webkit (konqueror) browsers */\n    -ms-user-select: none; /* IE10+ */\n}\n\n.btn-mini {\n    padding: 2px 6px;\n    font-size: 11px;\n    line-height: 13px;\n}\n\ntable.metronome {\n    text-align: center;\n}\n\n.table tbody>tr>th.division {\n    text-align: center;\n}\n\n.table>tbody>tr>td.metronome {\n    padding: 0px;\n    -webkit-user-select: none; /* webkit (safari, chrome) browsers */\n    -moz-user-select: none; /* mozilla browsers */\n    -khtml-user-select: none; /* webkit (konqueror) browsers */\n    -ms-user-select: none; /* IE10+ */\n}\n\n.table>tbody>tr>th.metronome {\n    padding: 0px;\n    -webkit-user-select: none; /* webkit (safari, chrome) browsers */\n    -moz-user-select: none; /* mozilla browsers */\n    -khtml-user-select: none; /* webkit (konqueror) browsers */\n    -ms-user-select: none; /* IE10+ */\n}\n.table tbody>tr>td.metronome-sync {\n    text-align: left;\n    vertical-align: middle;\n}\n\n.table tbody>tr>td.metronome-sync .metronome-active {\n    background-color: lightblue;\n}\n\n.table tbody>tr>td.metronome-sync .metronome-blink {\n    color: yellow;\n}\n\n.table tbody>tr>td.metronome-adjust .metronome-active {\n    color: lightblue;\n}\n\n.table tbody>tr>td.metronome-reset {\n    color: red;\n}\n\n.table tbody>tr>td.metronome-reset .metronome-active {\n    color: #f77;\n}\n\n.time-fraction {\n    color: #aaa;\n}\n\n.slider-track {\n    background-color: slategray;\n}\n.slider-track-high {\n    background-color: darkslategray;\n}\n.slider-track-low {\n    background-color: slategray;\n}\n.slider-selection {\n    background: slategray;\n}\n\n/*\n#slider-in-bpm .slider-track-high {\n    background: darkslategray;\n}\n\n#slider-in-bpm .slider-selection {\n    background: slategray;\n}\n*/\n\n#slider-in-grand-master .tooltip-inner {\n    background-color: slategray;\n}\n\n#slider-in-grand-master .tooltip.bottom .tooltip-arrow {\n    border-bottom-color: slategray;\n}\n\n#loadBar {\n    vertical-align: text-top;\n}\n\n#effects-table .tooltip-inner {\n    background-color: gray;\n}\n\n#effects-table .tooltip.top .tooltip-arrow {\n    border-top-color: gray;\n}\n\n#effects-table td {\n    vertical-align: middle;\n}\n\n.effect-var-table {\n    background: transparent;\n}\n.effect-var-table td {\n    padding: 1px;\n    background: transparent;\n}\n"
  },
  {
    "path": "resources/public/css/web-repl.css",
    "content": "#console {\n    background: #222222;\n    color: #888888;\n    margin: 10px;\n    border-radius: 5px;\n    -moz-border-radius: 5px;\n    border: 1px solid #080808;\n}\n\n#console div.jquery-console-inner {\n    margin: 10px 10px;\n    overflow: auto;\n    text-align: left;\n}\n\n#console div.jquery-console-welcome {\n    color: #55aaff;\n    font-family: sans-serif;\n    font-weight: bold;\n    padding: 0.1em;\n}\n\n#console div.jquery-console-message-value {\n    color: #4488ff;\n    font-family: monospace;\n    padding: 0.1em;\n}\n\n#console div.jquery-console-prompt-box {\n    color: #ffffcc;\n    font-family: monospace;\n}\n\n#console div.jquery-console-focus span.jquery-console-cursor {\n    background: #eee;\n    color: #333;\n    font-weight: bold;\n}\n\n#console div.jquery-console-message-error {\n    color: #ef0505;\n    font-family: sans-serif;\n    font-weight: bold;\n    padding: 0.1em;\n}\n\n#console div.jquery-console-message-success {\n    color: #187718;\n    font-family: monospace;\n    padding: 0.1em;\n}\n\n#console span.jquery-console-prompt-label {\n    font-weight: bold;\n}\n"
  },
  {
    "path": "resources/public/epl-v10.html",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n<title>Eclipse Public License - Version 1.0</title>\n<style type=\"text/css\">\n  body {\n    size: 8.5in 11.0in;\n    margin: 0.25in 0.5in 0.25in 0.5in;\n    tab-interval: 0.5in;\n    }\n  p {  \t\n    margin-left: auto;\n    margin-top:  0.5em;\n    margin-bottom: 0.5em;\n    }\n  p.list {\n  \tmargin-left: 0.5in;\n    margin-top:  0.05em;\n    margin-bottom: 0.05em;\n    }\n  </style>\n\n</head>\n\n<body lang=\"EN-US\">\n\n<h2>Eclipse Public License - v 1.0</h2>\n\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\nPUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE, REPRODUCTION OR\nDISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS\nAGREEMENT.</p>\n\n<p><b>1. DEFINITIONS</b></p>\n\n<p>&quot;Contribution&quot; means:</p>\n\n<p class=\"list\">a) in the case of the initial Contributor, the initial\ncode and documentation distributed under this Agreement, and</p>\n<p class=\"list\">b) in the case of each subsequent Contributor:</p>\n<p class=\"list\">i) changes to the Program, and</p>\n<p class=\"list\">ii) additions to the Program;</p>\n<p class=\"list\">where such changes and/or additions to the Program\noriginate from and are distributed by that particular Contributor. A\nContribution 'originates' from a Contributor if it was added to the\nProgram by such Contributor itself or anyone acting on such\nContributor's behalf. Contributions do not include additions to the\nProgram which: (i) are separate modules of software distributed in\nconjunction with the Program under their own license agreement, and (ii)\nare not derivative works of the Program.</p>\n\n<p>&quot;Contributor&quot; means any person or entity that distributes\nthe Program.</p>\n\n<p>&quot;Licensed Patents&quot; mean patent claims licensable by a\nContributor which are necessarily infringed by the use or sale of its\nContribution alone or when combined with the Program.</p>\n\n<p>&quot;Program&quot; means the Contributions distributed in accordance\nwith this Agreement.</p>\n\n<p>&quot;Recipient&quot; means anyone who receives the Program under\nthis Agreement, including all Contributors.</p>\n\n<p><b>2. GRANT OF RIGHTS</b></p>\n\n<p class=\"list\">a) Subject to the terms of this Agreement, each\nContributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free copyright license to reproduce, prepare derivative works\nof, publicly display, publicly perform, distribute and sublicense the\nContribution of such Contributor, if any, and such derivative works, in\nsource code and object code form.</p>\n\n<p class=\"list\">b) Subject to the terms of this Agreement, each\nContributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free patent license under Licensed Patents to make, use, sell,\noffer to sell, import and otherwise transfer the Contribution of such\nContributor, if any, in source code and object code form. This patent\nlicense shall apply to the combination of the Contribution and the\nProgram if, at the time the Contribution is added by the Contributor,\nsuch addition of the Contribution causes such combination to be covered\nby the Licensed Patents. The patent license shall not apply to any other\ncombinations which include the Contribution. No hardware per se is\nlicensed hereunder.</p>\n\n<p class=\"list\">c) Recipient understands that although each Contributor\ngrants the licenses to its Contributions set forth herein, no assurances\nare provided by any Contributor that the Program does not infringe the\npatent or other intellectual property rights of any other entity. Each\nContributor disclaims any liability to Recipient for claims brought by\nany other entity based on infringement of intellectual property rights\nor otherwise. As a condition to exercising the rights and licenses\ngranted hereunder, each Recipient hereby assumes sole responsibility to\nsecure any other intellectual property rights needed, if any. For\nexample, if a third party patent license is required to allow Recipient\nto distribute the Program, it is Recipient's responsibility to acquire\nthat license before distributing the Program.</p>\n\n<p class=\"list\">d) Each Contributor represents that to its knowledge it\nhas sufficient copyright rights in its Contribution, if any, to grant\nthe copyright license set forth in this Agreement.</p>\n\n<p><b>3. REQUIREMENTS</b></p>\n\n<p>A Contributor may choose to distribute the Program in object code\nform under its own license agreement, provided that:</p>\n\n<p class=\"list\">a) it complies with the terms and conditions of this\nAgreement; and</p>\n\n<p class=\"list\">b) its license agreement:</p>\n\n<p class=\"list\">i) effectively disclaims on behalf of all Contributors\nall warranties and conditions, express and implied, including warranties\nor conditions of title and non-infringement, and implied warranties or\nconditions of merchantability and fitness for a particular purpose;</p>\n\n<p class=\"list\">ii) effectively excludes on behalf of all Contributors\nall liability for damages, including direct, indirect, special,\nincidental and consequential damages, such as lost profits;</p>\n\n<p class=\"list\">iii) states that any provisions which differ from this\nAgreement are offered by that Contributor alone and not by any other\nparty; and</p>\n\n<p class=\"list\">iv) states that source code for the Program is available\nfrom such Contributor, and informs licensees how to obtain it in a\nreasonable manner on or through a medium customarily used for software\nexchange.</p>\n\n<p>When the Program is made available in source code form:</p>\n\n<p class=\"list\">a) it must be made available under this Agreement; and</p>\n\n<p class=\"list\">b) a copy of this Agreement must be included with each\ncopy of the Program.</p>\n\n<p>Contributors may not remove or alter any copyright notices contained\nwithin the Program.</p>\n\n<p>Each Contributor must identify itself as the originator of its\nContribution, if any, in a manner that reasonably allows subsequent\nRecipients to identify the originator of the Contribution.</p>\n\n<p><b>4. COMMERCIAL DISTRIBUTION</b></p>\n\n<p>Commercial distributors of software may accept certain\nresponsibilities with respect to end users, business partners and the\nlike. While this license is intended to facilitate the commercial use of\nthe Program, the Contributor who includes the Program in a commercial\nproduct offering should do so in a manner which does not create\npotential liability for other Contributors. Therefore, if a Contributor\nincludes the Program in a commercial product offering, such Contributor\n(&quot;Commercial Contributor&quot;) hereby agrees to defend and\nindemnify every other Contributor (&quot;Indemnified Contributor&quot;)\nagainst any losses, damages and costs (collectively &quot;Losses&quot;)\narising from claims, lawsuits and other legal actions brought by a third\nparty against the Indemnified Contributor to the extent caused by the\nacts or omissions of such Commercial Contributor in connection with its\ndistribution of the Program in a commercial product offering. The\nobligations in this section do not apply to any claims or Losses\nrelating to any actual or alleged intellectual property infringement. In\norder to qualify, an Indemnified Contributor must: a) promptly notify\nthe Commercial Contributor in writing of such claim, and b) allow the\nCommercial Contributor to control, and cooperate with the Commercial\nContributor in, the defense and any related settlement negotiations. The\nIndemnified Contributor may participate in any such claim at its own\nexpense.</p>\n\n<p>For example, a Contributor might include the Program in a commercial\nproduct offering, Product X. That Contributor is then a Commercial\nContributor. If that Commercial Contributor then makes performance\nclaims, or offers warranties related to Product X, those performance\nclaims and warranties are such Commercial Contributor's responsibility\nalone. Under this section, the Commercial Contributor would have to\ndefend claims against the other Contributors related to those\nperformance claims and warranties, and if a court requires any other\nContributor to pay any damages as a result, the Commercial Contributor\nmust pay those damages.</p>\n\n<p><b>5. NO WARRANTY</b></p>\n\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS\nPROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS\nOF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,\nANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY\nOR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely\nresponsible for determining the appropriateness of using and\ndistributing the Program and assumes all risks associated with its\nexercise of rights under this Agreement , including but not limited to\nthe risks and costs of program errors, compliance with applicable laws,\ndamage to or loss of data, programs or equipment, and unavailability or\ninterruption of operations.</p>\n\n<p><b>6. DISCLAIMER OF LIABILITY</b></p>\n\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT\nNOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING\nWITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR\nDISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED\nHEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>\n\n<p><b>7. GENERAL</b></p>\n\n<p>If any provision of this Agreement is invalid or unenforceable under\napplicable law, it shall not affect the validity or enforceability of\nthe remainder of the terms of this Agreement, and without further action\nby the parties hereto, such provision shall be reformed to the minimum\nextent necessary to make such provision valid and enforceable.</p>\n\n<p>If Recipient institutes patent litigation against any entity\n(including a cross-claim or counterclaim in a lawsuit) alleging that the\nProgram itself (excluding combinations of the Program with other\nsoftware or hardware) infringes such Recipient's patent(s), then such\nRecipient's rights granted under Section 2(b) shall terminate as of the\ndate such litigation is filed.</p>\n\n<p>All Recipient's rights under this Agreement shall terminate if it\nfails to comply with any of the material terms or conditions of this\nAgreement and does not cure such failure in a reasonable period of time\nafter becoming aware of such noncompliance. If all Recipient's rights\nunder this Agreement terminate, Recipient agrees to cease use and\ndistribution of the Program as soon as reasonably practicable. However,\nRecipient's obligations under this Agreement and any licenses granted by\nRecipient relating to the Program shall continue and survive.</p>\n\n<p>Everyone is permitted to copy and distribute copies of this\nAgreement, but in order to avoid inconsistency the Agreement is\ncopyrighted and may only be modified in the following manner. The\nAgreement Steward reserves the right to publish new versions (including\nrevisions) of this Agreement from time to time. No one other than the\nAgreement Steward has the right to modify this Agreement. The Eclipse\nFoundation is the initial Agreement Steward. The Eclipse Foundation may\nassign the responsibility to serve as the Agreement Steward to a\nsuitable separate entity. Each new version of the Agreement will be\ngiven a distinguishing version number. The Program (including\nContributions) may always be distributed subject to the version of the\nAgreement under which it was received. In addition, after a new version\nof the Agreement is published, Contributor may elect to distribute the\nProgram (including its Contributions) under the new version. Except as\nexpressly stated in Sections 2(a) and 2(b) above, Recipient receives no\nrights or licenses to the intellectual property of any Contributor under\nthis Agreement, whether expressly, by implication, estoppel or\notherwise. All rights in the Program not expressly granted under this\nAgreement are reserved.</p>\n\n<p>This Agreement is governed by the laws of the State of New York and\nthe intellectual property laws of the United States of America. No party\nto this Agreement will bring a legal action under this Agreement more\nthan one year after the cause of action arose. Each party waives its\nrights to a jury trial in any resulting litigation.</p>\n\n</body>\n\n</html>"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/HELP-US-OUT.txt",
    "content": "I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project,\nFonticons (https://fonticons.com). It makes it easy to put the perfect icons on your website. Choose from our awesome,\ncomprehensive icon sets or copy and paste your own.\n\nPlease. Check it out.\n\n-Dave Gandy\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/css/font-awesome.css",
    "content": "/*!\n *  Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)\n */\n/* FONT PATH\n * -------------------------- */\n@font-face {\n  font-family: 'FontAwesome';\n  src: url('../fonts/fontawesome-webfont.eot?v=4.5.0');\n  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg');\n  font-weight: normal;\n  font-style: normal;\n}\n.fa {\n  display: inline-block;\n  font: normal normal normal 14px/1 FontAwesome;\n  font-size: inherit;\n  text-rendering: auto;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n/* makes the font 33% larger relative to the icon container */\n.fa-lg {\n  font-size: 1.33333333em;\n  line-height: 0.75em;\n  vertical-align: -15%;\n}\n.fa-2x {\n  font-size: 2em;\n}\n.fa-3x {\n  font-size: 3em;\n}\n.fa-4x {\n  font-size: 4em;\n}\n.fa-5x {\n  font-size: 5em;\n}\n.fa-fw {\n  width: 1.28571429em;\n  text-align: center;\n}\n.fa-ul {\n  padding-left: 0;\n  margin-left: 2.14285714em;\n  list-style-type: none;\n}\n.fa-ul > li {\n  position: relative;\n}\n.fa-li {\n  position: absolute;\n  left: -2.14285714em;\n  width: 2.14285714em;\n  top: 0.14285714em;\n  text-align: center;\n}\n.fa-li.fa-lg {\n  left: -1.85714286em;\n}\n.fa-border {\n  padding: .2em .25em .15em;\n  border: solid 0.08em #eeeeee;\n  border-radius: .1em;\n}\n.fa-pull-left {\n  float: left;\n}\n.fa-pull-right {\n  float: right;\n}\n.fa.fa-pull-left {\n  margin-right: .3em;\n}\n.fa.fa-pull-right {\n  margin-left: .3em;\n}\n/* Deprecated as of 4.4.0 */\n.pull-right {\n  float: right;\n}\n.pull-left {\n  float: left;\n}\n.fa.pull-left {\n  margin-right: .3em;\n}\n.fa.pull-right {\n  margin-left: .3em;\n}\n.fa-spin {\n  -webkit-animation: fa-spin 2s infinite linear;\n  animation: fa-spin 2s infinite linear;\n}\n.fa-pulse {\n  -webkit-animation: fa-spin 1s infinite steps(8);\n  animation: fa-spin 1s infinite steps(8);\n}\n@-webkit-keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg);\n  }\n}\n@keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg);\n  }\n}\n.fa-rotate-90 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);\n  -webkit-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  transform: rotate(90deg);\n}\n.fa-rotate-180 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);\n  -webkit-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n.fa-rotate-270 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);\n  -webkit-transform: rotate(270deg);\n  -ms-transform: rotate(270deg);\n  transform: rotate(270deg);\n}\n.fa-flip-horizontal {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);\n  -webkit-transform: scale(-1, 1);\n  -ms-transform: scale(-1, 1);\n  transform: scale(-1, 1);\n}\n.fa-flip-vertical {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);\n  -webkit-transform: scale(1, -1);\n  -ms-transform: scale(1, -1);\n  transform: scale(1, -1);\n}\n:root .fa-rotate-90,\n:root .fa-rotate-180,\n:root .fa-rotate-270,\n:root .fa-flip-horizontal,\n:root .fa-flip-vertical {\n  filter: none;\n}\n.fa-stack {\n  position: relative;\n  display: inline-block;\n  width: 2em;\n  height: 2em;\n  line-height: 2em;\n  vertical-align: middle;\n}\n.fa-stack-1x,\n.fa-stack-2x {\n  position: absolute;\n  left: 0;\n  width: 100%;\n  text-align: center;\n}\n.fa-stack-1x {\n  line-height: inherit;\n}\n.fa-stack-2x {\n  font-size: 2em;\n}\n.fa-inverse {\n  color: #ffffff;\n}\n/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\n   readers do not read off random characters that represent icons */\n.fa-glass:before {\n  content: \"\\f000\";\n}\n.fa-music:before {\n  content: \"\\f001\";\n}\n.fa-search:before {\n  content: \"\\f002\";\n}\n.fa-envelope-o:before {\n  content: \"\\f003\";\n}\n.fa-heart:before {\n  content: \"\\f004\";\n}\n.fa-star:before {\n  content: \"\\f005\";\n}\n.fa-star-o:before {\n  content: \"\\f006\";\n}\n.fa-user:before {\n  content: \"\\f007\";\n}\n.fa-film:before {\n  content: \"\\f008\";\n}\n.fa-th-large:before {\n  content: \"\\f009\";\n}\n.fa-th:before {\n  content: \"\\f00a\";\n}\n.fa-th-list:before {\n  content: \"\\f00b\";\n}\n.fa-check:before {\n  content: \"\\f00c\";\n}\n.fa-remove:before,\n.fa-close:before,\n.fa-times:before {\n  content: \"\\f00d\";\n}\n.fa-search-plus:before {\n  content: \"\\f00e\";\n}\n.fa-search-minus:before {\n  content: \"\\f010\";\n}\n.fa-power-off:before {\n  content: \"\\f011\";\n}\n.fa-signal:before {\n  content: \"\\f012\";\n}\n.fa-gear:before,\n.fa-cog:before {\n  content: \"\\f013\";\n}\n.fa-trash-o:before {\n  content: \"\\f014\";\n}\n.fa-home:before {\n  content: \"\\f015\";\n}\n.fa-file-o:before {\n  content: \"\\f016\";\n}\n.fa-clock-o:before {\n  content: \"\\f017\";\n}\n.fa-road:before {\n  content: \"\\f018\";\n}\n.fa-download:before {\n  content: \"\\f019\";\n}\n.fa-arrow-circle-o-down:before {\n  content: \"\\f01a\";\n}\n.fa-arrow-circle-o-up:before {\n  content: \"\\f01b\";\n}\n.fa-inbox:before {\n  content: \"\\f01c\";\n}\n.fa-play-circle-o:before {\n  content: \"\\f01d\";\n}\n.fa-rotate-right:before,\n.fa-repeat:before {\n  content: \"\\f01e\";\n}\n.fa-refresh:before {\n  content: \"\\f021\";\n}\n.fa-list-alt:before {\n  content: \"\\f022\";\n}\n.fa-lock:before {\n  content: \"\\f023\";\n}\n.fa-flag:before {\n  content: \"\\f024\";\n}\n.fa-headphones:before {\n  content: \"\\f025\";\n}\n.fa-volume-off:before {\n  content: \"\\f026\";\n}\n.fa-volume-down:before {\n  content: \"\\f027\";\n}\n.fa-volume-up:before {\n  content: \"\\f028\";\n}\n.fa-qrcode:before {\n  content: \"\\f029\";\n}\n.fa-barcode:before {\n  content: \"\\f02a\";\n}\n.fa-tag:before {\n  content: \"\\f02b\";\n}\n.fa-tags:before {\n  content: \"\\f02c\";\n}\n.fa-book:before {\n  content: \"\\f02d\";\n}\n.fa-bookmark:before {\n  content: \"\\f02e\";\n}\n.fa-print:before {\n  content: \"\\f02f\";\n}\n.fa-camera:before {\n  content: \"\\f030\";\n}\n.fa-font:before {\n  content: \"\\f031\";\n}\n.fa-bold:before {\n  content: \"\\f032\";\n}\n.fa-italic:before {\n  content: \"\\f033\";\n}\n.fa-text-height:before {\n  content: \"\\f034\";\n}\n.fa-text-width:before {\n  content: \"\\f035\";\n}\n.fa-align-left:before {\n  content: \"\\f036\";\n}\n.fa-align-center:before {\n  content: \"\\f037\";\n}\n.fa-align-right:before {\n  content: \"\\f038\";\n}\n.fa-align-justify:before {\n  content: \"\\f039\";\n}\n.fa-list:before {\n  content: \"\\f03a\";\n}\n.fa-dedent:before,\n.fa-outdent:before {\n  content: \"\\f03b\";\n}\n.fa-indent:before {\n  content: \"\\f03c\";\n}\n.fa-video-camera:before {\n  content: \"\\f03d\";\n}\n.fa-photo:before,\n.fa-image:before,\n.fa-picture-o:before {\n  content: \"\\f03e\";\n}\n.fa-pencil:before {\n  content: \"\\f040\";\n}\n.fa-map-marker:before {\n  content: \"\\f041\";\n}\n.fa-adjust:before {\n  content: \"\\f042\";\n}\n.fa-tint:before {\n  content: \"\\f043\";\n}\n.fa-edit:before,\n.fa-pencil-square-o:before {\n  content: \"\\f044\";\n}\n.fa-share-square-o:before {\n  content: \"\\f045\";\n}\n.fa-check-square-o:before {\n  content: \"\\f046\";\n}\n.fa-arrows:before {\n  content: \"\\f047\";\n}\n.fa-step-backward:before {\n  content: \"\\f048\";\n}\n.fa-fast-backward:before {\n  content: \"\\f049\";\n}\n.fa-backward:before {\n  content: \"\\f04a\";\n}\n.fa-play:before {\n  content: \"\\f04b\";\n}\n.fa-pause:before {\n  content: \"\\f04c\";\n}\n.fa-stop:before {\n  content: \"\\f04d\";\n}\n.fa-forward:before {\n  content: \"\\f04e\";\n}\n.fa-fast-forward:before {\n  content: \"\\f050\";\n}\n.fa-step-forward:before {\n  content: \"\\f051\";\n}\n.fa-eject:before {\n  content: \"\\f052\";\n}\n.fa-chevron-left:before {\n  content: \"\\f053\";\n}\n.fa-chevron-right:before {\n  content: \"\\f054\";\n}\n.fa-plus-circle:before {\n  content: \"\\f055\";\n}\n.fa-minus-circle:before {\n  content: \"\\f056\";\n}\n.fa-times-circle:before {\n  content: \"\\f057\";\n}\n.fa-check-circle:before {\n  content: \"\\f058\";\n}\n.fa-question-circle:before {\n  content: \"\\f059\";\n}\n.fa-info-circle:before {\n  content: \"\\f05a\";\n}\n.fa-crosshairs:before {\n  content: \"\\f05b\";\n}\n.fa-times-circle-o:before {\n  content: \"\\f05c\";\n}\n.fa-check-circle-o:before {\n  content: \"\\f05d\";\n}\n.fa-ban:before {\n  content: \"\\f05e\";\n}\n.fa-arrow-left:before {\n  content: \"\\f060\";\n}\n.fa-arrow-right:before {\n  content: \"\\f061\";\n}\n.fa-arrow-up:before {\n  content: \"\\f062\";\n}\n.fa-arrow-down:before {\n  content: \"\\f063\";\n}\n.fa-mail-forward:before,\n.fa-share:before {\n  content: \"\\f064\";\n}\n.fa-expand:before {\n  content: \"\\f065\";\n}\n.fa-compress:before {\n  content: \"\\f066\";\n}\n.fa-plus:before {\n  content: \"\\f067\";\n}\n.fa-minus:before {\n  content: \"\\f068\";\n}\n.fa-asterisk:before {\n  content: \"\\f069\";\n}\n.fa-exclamation-circle:before {\n  content: \"\\f06a\";\n}\n.fa-gift:before {\n  content: \"\\f06b\";\n}\n.fa-leaf:before {\n  content: \"\\f06c\";\n}\n.fa-fire:before {\n  content: \"\\f06d\";\n}\n.fa-eye:before {\n  content: \"\\f06e\";\n}\n.fa-eye-slash:before {\n  content: \"\\f070\";\n}\n.fa-warning:before,\n.fa-exclamation-triangle:before {\n  content: \"\\f071\";\n}\n.fa-plane:before {\n  content: \"\\f072\";\n}\n.fa-calendar:before {\n  content: \"\\f073\";\n}\n.fa-random:before {\n  content: \"\\f074\";\n}\n.fa-comment:before {\n  content: \"\\f075\";\n}\n.fa-magnet:before {\n  content: \"\\f076\";\n}\n.fa-chevron-up:before {\n  content: \"\\f077\";\n}\n.fa-chevron-down:before {\n  content: \"\\f078\";\n}\n.fa-retweet:before {\n  content: \"\\f079\";\n}\n.fa-shopping-cart:before {\n  content: \"\\f07a\";\n}\n.fa-folder:before {\n  content: \"\\f07b\";\n}\n.fa-folder-open:before {\n  content: \"\\f07c\";\n}\n.fa-arrows-v:before {\n  content: \"\\f07d\";\n}\n.fa-arrows-h:before {\n  content: \"\\f07e\";\n}\n.fa-bar-chart-o:before,\n.fa-bar-chart:before {\n  content: \"\\f080\";\n}\n.fa-twitter-square:before {\n  content: \"\\f081\";\n}\n.fa-facebook-square:before {\n  content: \"\\f082\";\n}\n.fa-camera-retro:before {\n  content: \"\\f083\";\n}\n.fa-key:before {\n  content: \"\\f084\";\n}\n.fa-gears:before,\n.fa-cogs:before {\n  content: \"\\f085\";\n}\n.fa-comments:before {\n  content: \"\\f086\";\n}\n.fa-thumbs-o-up:before {\n  content: \"\\f087\";\n}\n.fa-thumbs-o-down:before {\n  content: \"\\f088\";\n}\n.fa-star-half:before {\n  content: \"\\f089\";\n}\n.fa-heart-o:before {\n  content: \"\\f08a\";\n}\n.fa-sign-out:before {\n  content: \"\\f08b\";\n}\n.fa-linkedin-square:before {\n  content: \"\\f08c\";\n}\n.fa-thumb-tack:before {\n  content: \"\\f08d\";\n}\n.fa-external-link:before {\n  content: \"\\f08e\";\n}\n.fa-sign-in:before {\n  content: \"\\f090\";\n}\n.fa-trophy:before {\n  content: \"\\f091\";\n}\n.fa-github-square:before {\n  content: \"\\f092\";\n}\n.fa-upload:before {\n  content: \"\\f093\";\n}\n.fa-lemon-o:before {\n  content: \"\\f094\";\n}\n.fa-phone:before {\n  content: \"\\f095\";\n}\n.fa-square-o:before {\n  content: \"\\f096\";\n}\n.fa-bookmark-o:before {\n  content: \"\\f097\";\n}\n.fa-phone-square:before {\n  content: \"\\f098\";\n}\n.fa-twitter:before {\n  content: \"\\f099\";\n}\n.fa-facebook-f:before,\n.fa-facebook:before {\n  content: \"\\f09a\";\n}\n.fa-github:before {\n  content: \"\\f09b\";\n}\n.fa-unlock:before {\n  content: \"\\f09c\";\n}\n.fa-credit-card:before {\n  content: \"\\f09d\";\n}\n.fa-feed:before,\n.fa-rss:before {\n  content: \"\\f09e\";\n}\n.fa-hdd-o:before {\n  content: \"\\f0a0\";\n}\n.fa-bullhorn:before {\n  content: \"\\f0a1\";\n}\n.fa-bell:before {\n  content: \"\\f0f3\";\n}\n.fa-certificate:before {\n  content: \"\\f0a3\";\n}\n.fa-hand-o-right:before {\n  content: \"\\f0a4\";\n}\n.fa-hand-o-left:before {\n  content: \"\\f0a5\";\n}\n.fa-hand-o-up:before {\n  content: \"\\f0a6\";\n}\n.fa-hand-o-down:before {\n  content: \"\\f0a7\";\n}\n.fa-arrow-circle-left:before {\n  content: \"\\f0a8\";\n}\n.fa-arrow-circle-right:before {\n  content: \"\\f0a9\";\n}\n.fa-arrow-circle-up:before {\n  content: \"\\f0aa\";\n}\n.fa-arrow-circle-down:before {\n  content: \"\\f0ab\";\n}\n.fa-globe:before {\n  content: \"\\f0ac\";\n}\n.fa-wrench:before {\n  content: \"\\f0ad\";\n}\n.fa-tasks:before {\n  content: \"\\f0ae\";\n}\n.fa-filter:before {\n  content: \"\\f0b0\";\n}\n.fa-briefcase:before {\n  content: \"\\f0b1\";\n}\n.fa-arrows-alt:before {\n  content: \"\\f0b2\";\n}\n.fa-group:before,\n.fa-users:before {\n  content: \"\\f0c0\";\n}\n.fa-chain:before,\n.fa-link:before {\n  content: \"\\f0c1\";\n}\n.fa-cloud:before {\n  content: \"\\f0c2\";\n}\n.fa-flask:before {\n  content: \"\\f0c3\";\n}\n.fa-cut:before,\n.fa-scissors:before {\n  content: \"\\f0c4\";\n}\n.fa-copy:before,\n.fa-files-o:before {\n  content: \"\\f0c5\";\n}\n.fa-paperclip:before {\n  content: \"\\f0c6\";\n}\n.fa-save:before,\n.fa-floppy-o:before {\n  content: \"\\f0c7\";\n}\n.fa-square:before {\n  content: \"\\f0c8\";\n}\n.fa-navicon:before,\n.fa-reorder:before,\n.fa-bars:before {\n  content: \"\\f0c9\";\n}\n.fa-list-ul:before {\n  content: \"\\f0ca\";\n}\n.fa-list-ol:before {\n  content: \"\\f0cb\";\n}\n.fa-strikethrough:before {\n  content: \"\\f0cc\";\n}\n.fa-underline:before {\n  content: \"\\f0cd\";\n}\n.fa-table:before {\n  content: \"\\f0ce\";\n}\n.fa-magic:before {\n  content: \"\\f0d0\";\n}\n.fa-truck:before {\n  content: \"\\f0d1\";\n}\n.fa-pinterest:before {\n  content: \"\\f0d2\";\n}\n.fa-pinterest-square:before {\n  content: \"\\f0d3\";\n}\n.fa-google-plus-square:before {\n  content: \"\\f0d4\";\n}\n.fa-google-plus:before {\n  content: \"\\f0d5\";\n}\n.fa-money:before {\n  content: \"\\f0d6\";\n}\n.fa-caret-down:before {\n  content: \"\\f0d7\";\n}\n.fa-caret-up:before {\n  content: \"\\f0d8\";\n}\n.fa-caret-left:before {\n  content: \"\\f0d9\";\n}\n.fa-caret-right:before {\n  content: \"\\f0da\";\n}\n.fa-columns:before {\n  content: \"\\f0db\";\n}\n.fa-unsorted:before,\n.fa-sort:before {\n  content: \"\\f0dc\";\n}\n.fa-sort-down:before,\n.fa-sort-desc:before {\n  content: \"\\f0dd\";\n}\n.fa-sort-up:before,\n.fa-sort-asc:before {\n  content: \"\\f0de\";\n}\n.fa-envelope:before {\n  content: \"\\f0e0\";\n}\n.fa-linkedin:before {\n  content: \"\\f0e1\";\n}\n.fa-rotate-left:before,\n.fa-undo:before {\n  content: \"\\f0e2\";\n}\n.fa-legal:before,\n.fa-gavel:before {\n  content: \"\\f0e3\";\n}\n.fa-dashboard:before,\n.fa-tachometer:before {\n  content: \"\\f0e4\";\n}\n.fa-comment-o:before {\n  content: \"\\f0e5\";\n}\n.fa-comments-o:before {\n  content: \"\\f0e6\";\n}\n.fa-flash:before,\n.fa-bolt:before {\n  content: \"\\f0e7\";\n}\n.fa-sitemap:before {\n  content: \"\\f0e8\";\n}\n.fa-umbrella:before {\n  content: \"\\f0e9\";\n}\n.fa-paste:before,\n.fa-clipboard:before {\n  content: \"\\f0ea\";\n}\n.fa-lightbulb-o:before {\n  content: \"\\f0eb\";\n}\n.fa-exchange:before {\n  content: \"\\f0ec\";\n}\n.fa-cloud-download:before {\n  content: \"\\f0ed\";\n}\n.fa-cloud-upload:before {\n  content: \"\\f0ee\";\n}\n.fa-user-md:before {\n  content: \"\\f0f0\";\n}\n.fa-stethoscope:before {\n  content: \"\\f0f1\";\n}\n.fa-suitcase:before {\n  content: \"\\f0f2\";\n}\n.fa-bell-o:before {\n  content: \"\\f0a2\";\n}\n.fa-coffee:before {\n  content: \"\\f0f4\";\n}\n.fa-cutlery:before {\n  content: \"\\f0f5\";\n}\n.fa-file-text-o:before {\n  content: \"\\f0f6\";\n}\n.fa-building-o:before {\n  content: \"\\f0f7\";\n}\n.fa-hospital-o:before {\n  content: \"\\f0f8\";\n}\n.fa-ambulance:before {\n  content: \"\\f0f9\";\n}\n.fa-medkit:before {\n  content: \"\\f0fa\";\n}\n.fa-fighter-jet:before {\n  content: \"\\f0fb\";\n}\n.fa-beer:before {\n  content: \"\\f0fc\";\n}\n.fa-h-square:before {\n  content: \"\\f0fd\";\n}\n.fa-plus-square:before {\n  content: \"\\f0fe\";\n}\n.fa-angle-double-left:before {\n  content: \"\\f100\";\n}\n.fa-angle-double-right:before {\n  content: \"\\f101\";\n}\n.fa-angle-double-up:before {\n  content: \"\\f102\";\n}\n.fa-angle-double-down:before {\n  content: \"\\f103\";\n}\n.fa-angle-left:before {\n  content: \"\\f104\";\n}\n.fa-angle-right:before {\n  content: \"\\f105\";\n}\n.fa-angle-up:before {\n  content: \"\\f106\";\n}\n.fa-angle-down:before {\n  content: \"\\f107\";\n}\n.fa-desktop:before {\n  content: \"\\f108\";\n}\n.fa-laptop:before {\n  content: \"\\f109\";\n}\n.fa-tablet:before {\n  content: \"\\f10a\";\n}\n.fa-mobile-phone:before,\n.fa-mobile:before {\n  content: \"\\f10b\";\n}\n.fa-circle-o:before {\n  content: \"\\f10c\";\n}\n.fa-quote-left:before {\n  content: \"\\f10d\";\n}\n.fa-quote-right:before {\n  content: \"\\f10e\";\n}\n.fa-spinner:before {\n  content: \"\\f110\";\n}\n.fa-circle:before {\n  content: \"\\f111\";\n}\n.fa-mail-reply:before,\n.fa-reply:before {\n  content: \"\\f112\";\n}\n.fa-github-alt:before {\n  content: \"\\f113\";\n}\n.fa-folder-o:before {\n  content: \"\\f114\";\n}\n.fa-folder-open-o:before {\n  content: \"\\f115\";\n}\n.fa-smile-o:before {\n  content: \"\\f118\";\n}\n.fa-frown-o:before {\n  content: \"\\f119\";\n}\n.fa-meh-o:before {\n  content: \"\\f11a\";\n}\n.fa-gamepad:before {\n  content: \"\\f11b\";\n}\n.fa-keyboard-o:before {\n  content: \"\\f11c\";\n}\n.fa-flag-o:before {\n  content: \"\\f11d\";\n}\n.fa-flag-checkered:before {\n  content: \"\\f11e\";\n}\n.fa-terminal:before {\n  content: \"\\f120\";\n}\n.fa-code:before {\n  content: \"\\f121\";\n}\n.fa-mail-reply-all:before,\n.fa-reply-all:before {\n  content: \"\\f122\";\n}\n.fa-star-half-empty:before,\n.fa-star-half-full:before,\n.fa-star-half-o:before {\n  content: \"\\f123\";\n}\n.fa-location-arrow:before {\n  content: \"\\f124\";\n}\n.fa-crop:before {\n  content: \"\\f125\";\n}\n.fa-code-fork:before {\n  content: \"\\f126\";\n}\n.fa-unlink:before,\n.fa-chain-broken:before {\n  content: \"\\f127\";\n}\n.fa-question:before {\n  content: \"\\f128\";\n}\n.fa-info:before {\n  content: \"\\f129\";\n}\n.fa-exclamation:before {\n  content: \"\\f12a\";\n}\n.fa-superscript:before {\n  content: \"\\f12b\";\n}\n.fa-subscript:before {\n  content: \"\\f12c\";\n}\n.fa-eraser:before {\n  content: \"\\f12d\";\n}\n.fa-puzzle-piece:before {\n  content: \"\\f12e\";\n}\n.fa-microphone:before {\n  content: \"\\f130\";\n}\n.fa-microphone-slash:before {\n  content: \"\\f131\";\n}\n.fa-shield:before {\n  content: \"\\f132\";\n}\n.fa-calendar-o:before {\n  content: \"\\f133\";\n}\n.fa-fire-extinguisher:before {\n  content: \"\\f134\";\n}\n.fa-rocket:before {\n  content: \"\\f135\";\n}\n.fa-maxcdn:before {\n  content: \"\\f136\";\n}\n.fa-chevron-circle-left:before {\n  content: \"\\f137\";\n}\n.fa-chevron-circle-right:before {\n  content: \"\\f138\";\n}\n.fa-chevron-circle-up:before {\n  content: \"\\f139\";\n}\n.fa-chevron-circle-down:before {\n  content: \"\\f13a\";\n}\n.fa-html5:before {\n  content: \"\\f13b\";\n}\n.fa-css3:before {\n  content: \"\\f13c\";\n}\n.fa-anchor:before {\n  content: \"\\f13d\";\n}\n.fa-unlock-alt:before {\n  content: \"\\f13e\";\n}\n.fa-bullseye:before {\n  content: \"\\f140\";\n}\n.fa-ellipsis-h:before {\n  content: \"\\f141\";\n}\n.fa-ellipsis-v:before {\n  content: \"\\f142\";\n}\n.fa-rss-square:before {\n  content: \"\\f143\";\n}\n.fa-play-circle:before {\n  content: \"\\f144\";\n}\n.fa-ticket:before {\n  content: \"\\f145\";\n}\n.fa-minus-square:before {\n  content: \"\\f146\";\n}\n.fa-minus-square-o:before {\n  content: \"\\f147\";\n}\n.fa-level-up:before {\n  content: \"\\f148\";\n}\n.fa-level-down:before {\n  content: \"\\f149\";\n}\n.fa-check-square:before {\n  content: \"\\f14a\";\n}\n.fa-pencil-square:before {\n  content: \"\\f14b\";\n}\n.fa-external-link-square:before {\n  content: \"\\f14c\";\n}\n.fa-share-square:before {\n  content: \"\\f14d\";\n}\n.fa-compass:before {\n  content: \"\\f14e\";\n}\n.fa-toggle-down:before,\n.fa-caret-square-o-down:before {\n  content: \"\\f150\";\n}\n.fa-toggle-up:before,\n.fa-caret-square-o-up:before {\n  content: \"\\f151\";\n}\n.fa-toggle-right:before,\n.fa-caret-square-o-right:before {\n  content: \"\\f152\";\n}\n.fa-euro:before,\n.fa-eur:before {\n  content: \"\\f153\";\n}\n.fa-gbp:before {\n  content: \"\\f154\";\n}\n.fa-dollar:before,\n.fa-usd:before {\n  content: \"\\f155\";\n}\n.fa-rupee:before,\n.fa-inr:before {\n  content: \"\\f156\";\n}\n.fa-cny:before,\n.fa-rmb:before,\n.fa-yen:before,\n.fa-jpy:before {\n  content: \"\\f157\";\n}\n.fa-ruble:before,\n.fa-rouble:before,\n.fa-rub:before {\n  content: \"\\f158\";\n}\n.fa-won:before,\n.fa-krw:before {\n  content: \"\\f159\";\n}\n.fa-bitcoin:before,\n.fa-btc:before {\n  content: \"\\f15a\";\n}\n.fa-file:before {\n  content: \"\\f15b\";\n}\n.fa-file-text:before {\n  content: \"\\f15c\";\n}\n.fa-sort-alpha-asc:before {\n  content: \"\\f15d\";\n}\n.fa-sort-alpha-desc:before {\n  content: \"\\f15e\";\n}\n.fa-sort-amount-asc:before {\n  content: \"\\f160\";\n}\n.fa-sort-amount-desc:before {\n  content: \"\\f161\";\n}\n.fa-sort-numeric-asc:before {\n  content: \"\\f162\";\n}\n.fa-sort-numeric-desc:before {\n  content: \"\\f163\";\n}\n.fa-thumbs-up:before {\n  content: \"\\f164\";\n}\n.fa-thumbs-down:before {\n  content: \"\\f165\";\n}\n.fa-youtube-square:before {\n  content: \"\\f166\";\n}\n.fa-youtube:before {\n  content: \"\\f167\";\n}\n.fa-xing:before {\n  content: \"\\f168\";\n}\n.fa-xing-square:before {\n  content: \"\\f169\";\n}\n.fa-youtube-play:before {\n  content: \"\\f16a\";\n}\n.fa-dropbox:before {\n  content: \"\\f16b\";\n}\n.fa-stack-overflow:before {\n  content: \"\\f16c\";\n}\n.fa-instagram:before {\n  content: \"\\f16d\";\n}\n.fa-flickr:before {\n  content: \"\\f16e\";\n}\n.fa-adn:before {\n  content: \"\\f170\";\n}\n.fa-bitbucket:before {\n  content: \"\\f171\";\n}\n.fa-bitbucket-square:before {\n  content: \"\\f172\";\n}\n.fa-tumblr:before {\n  content: \"\\f173\";\n}\n.fa-tumblr-square:before {\n  content: \"\\f174\";\n}\n.fa-long-arrow-down:before {\n  content: \"\\f175\";\n}\n.fa-long-arrow-up:before {\n  content: \"\\f176\";\n}\n.fa-long-arrow-left:before {\n  content: \"\\f177\";\n}\n.fa-long-arrow-right:before {\n  content: \"\\f178\";\n}\n.fa-apple:before {\n  content: \"\\f179\";\n}\n.fa-windows:before {\n  content: \"\\f17a\";\n}\n.fa-android:before {\n  content: \"\\f17b\";\n}\n.fa-linux:before {\n  content: \"\\f17c\";\n}\n.fa-dribbble:before {\n  content: \"\\f17d\";\n}\n.fa-skype:before {\n  content: \"\\f17e\";\n}\n.fa-foursquare:before {\n  content: \"\\f180\";\n}\n.fa-trello:before {\n  content: \"\\f181\";\n}\n.fa-female:before {\n  content: \"\\f182\";\n}\n.fa-male:before {\n  content: \"\\f183\";\n}\n.fa-gittip:before,\n.fa-gratipay:before {\n  content: \"\\f184\";\n}\n.fa-sun-o:before {\n  content: \"\\f185\";\n}\n.fa-moon-o:before {\n  content: \"\\f186\";\n}\n.fa-archive:before {\n  content: \"\\f187\";\n}\n.fa-bug:before {\n  content: \"\\f188\";\n}\n.fa-vk:before {\n  content: \"\\f189\";\n}\n.fa-weibo:before {\n  content: \"\\f18a\";\n}\n.fa-renren:before {\n  content: \"\\f18b\";\n}\n.fa-pagelines:before {\n  content: \"\\f18c\";\n}\n.fa-stack-exchange:before {\n  content: \"\\f18d\";\n}\n.fa-arrow-circle-o-right:before {\n  content: \"\\f18e\";\n}\n.fa-arrow-circle-o-left:before {\n  content: \"\\f190\";\n}\n.fa-toggle-left:before,\n.fa-caret-square-o-left:before {\n  content: \"\\f191\";\n}\n.fa-dot-circle-o:before {\n  content: \"\\f192\";\n}\n.fa-wheelchair:before {\n  content: \"\\f193\";\n}\n.fa-vimeo-square:before {\n  content: \"\\f194\";\n}\n.fa-turkish-lira:before,\n.fa-try:before {\n  content: \"\\f195\";\n}\n.fa-plus-square-o:before {\n  content: \"\\f196\";\n}\n.fa-space-shuttle:before {\n  content: \"\\f197\";\n}\n.fa-slack:before {\n  content: \"\\f198\";\n}\n.fa-envelope-square:before {\n  content: \"\\f199\";\n}\n.fa-wordpress:before {\n  content: \"\\f19a\";\n}\n.fa-openid:before {\n  content: \"\\f19b\";\n}\n.fa-institution:before,\n.fa-bank:before,\n.fa-university:before {\n  content: \"\\f19c\";\n}\n.fa-mortar-board:before,\n.fa-graduation-cap:before {\n  content: \"\\f19d\";\n}\n.fa-yahoo:before {\n  content: \"\\f19e\";\n}\n.fa-google:before {\n  content: \"\\f1a0\";\n}\n.fa-reddit:before {\n  content: \"\\f1a1\";\n}\n.fa-reddit-square:before {\n  content: \"\\f1a2\";\n}\n.fa-stumbleupon-circle:before {\n  content: \"\\f1a3\";\n}\n.fa-stumbleupon:before {\n  content: \"\\f1a4\";\n}\n.fa-delicious:before {\n  content: \"\\f1a5\";\n}\n.fa-digg:before {\n  content: \"\\f1a6\";\n}\n.fa-pied-piper:before {\n  content: \"\\f1a7\";\n}\n.fa-pied-piper-alt:before {\n  content: \"\\f1a8\";\n}\n.fa-drupal:before {\n  content: \"\\f1a9\";\n}\n.fa-joomla:before {\n  content: \"\\f1aa\";\n}\n.fa-language:before {\n  content: \"\\f1ab\";\n}\n.fa-fax:before {\n  content: \"\\f1ac\";\n}\n.fa-building:before {\n  content: \"\\f1ad\";\n}\n.fa-child:before {\n  content: \"\\f1ae\";\n}\n.fa-paw:before {\n  content: \"\\f1b0\";\n}\n.fa-spoon:before {\n  content: \"\\f1b1\";\n}\n.fa-cube:before {\n  content: \"\\f1b2\";\n}\n.fa-cubes:before {\n  content: \"\\f1b3\";\n}\n.fa-behance:before {\n  content: \"\\f1b4\";\n}\n.fa-behance-square:before {\n  content: \"\\f1b5\";\n}\n.fa-steam:before {\n  content: \"\\f1b6\";\n}\n.fa-steam-square:before {\n  content: \"\\f1b7\";\n}\n.fa-recycle:before {\n  content: \"\\f1b8\";\n}\n.fa-automobile:before,\n.fa-car:before {\n  content: \"\\f1b9\";\n}\n.fa-cab:before,\n.fa-taxi:before {\n  content: \"\\f1ba\";\n}\n.fa-tree:before {\n  content: \"\\f1bb\";\n}\n.fa-spotify:before {\n  content: \"\\f1bc\";\n}\n.fa-deviantart:before {\n  content: \"\\f1bd\";\n}\n.fa-soundcloud:before {\n  content: \"\\f1be\";\n}\n.fa-database:before {\n  content: \"\\f1c0\";\n}\n.fa-file-pdf-o:before {\n  content: \"\\f1c1\";\n}\n.fa-file-word-o:before {\n  content: \"\\f1c2\";\n}\n.fa-file-excel-o:before {\n  content: \"\\f1c3\";\n}\n.fa-file-powerpoint-o:before {\n  content: \"\\f1c4\";\n}\n.fa-file-photo-o:before,\n.fa-file-picture-o:before,\n.fa-file-image-o:before {\n  content: \"\\f1c5\";\n}\n.fa-file-zip-o:before,\n.fa-file-archive-o:before {\n  content: \"\\f1c6\";\n}\n.fa-file-sound-o:before,\n.fa-file-audio-o:before {\n  content: \"\\f1c7\";\n}\n.fa-file-movie-o:before,\n.fa-file-video-o:before {\n  content: \"\\f1c8\";\n}\n.fa-file-code-o:before {\n  content: \"\\f1c9\";\n}\n.fa-vine:before {\n  content: \"\\f1ca\";\n}\n.fa-codepen:before {\n  content: \"\\f1cb\";\n}\n.fa-jsfiddle:before {\n  content: \"\\f1cc\";\n}\n.fa-life-bouy:before,\n.fa-life-buoy:before,\n.fa-life-saver:before,\n.fa-support:before,\n.fa-life-ring:before {\n  content: \"\\f1cd\";\n}\n.fa-circle-o-notch:before {\n  content: \"\\f1ce\";\n}\n.fa-ra:before,\n.fa-rebel:before {\n  content: \"\\f1d0\";\n}\n.fa-ge:before,\n.fa-empire:before {\n  content: \"\\f1d1\";\n}\n.fa-git-square:before {\n  content: \"\\f1d2\";\n}\n.fa-git:before {\n  content: \"\\f1d3\";\n}\n.fa-y-combinator-square:before,\n.fa-yc-square:before,\n.fa-hacker-news:before {\n  content: \"\\f1d4\";\n}\n.fa-tencent-weibo:before {\n  content: \"\\f1d5\";\n}\n.fa-qq:before {\n  content: \"\\f1d6\";\n}\n.fa-wechat:before,\n.fa-weixin:before {\n  content: \"\\f1d7\";\n}\n.fa-send:before,\n.fa-paper-plane:before {\n  content: \"\\f1d8\";\n}\n.fa-send-o:before,\n.fa-paper-plane-o:before {\n  content: \"\\f1d9\";\n}\n.fa-history:before {\n  content: \"\\f1da\";\n}\n.fa-circle-thin:before {\n  content: \"\\f1db\";\n}\n.fa-header:before {\n  content: \"\\f1dc\";\n}\n.fa-paragraph:before {\n  content: \"\\f1dd\";\n}\n.fa-sliders:before {\n  content: \"\\f1de\";\n}\n.fa-share-alt:before {\n  content: \"\\f1e0\";\n}\n.fa-share-alt-square:before {\n  content: \"\\f1e1\";\n}\n.fa-bomb:before {\n  content: \"\\f1e2\";\n}\n.fa-soccer-ball-o:before,\n.fa-futbol-o:before {\n  content: \"\\f1e3\";\n}\n.fa-tty:before {\n  content: \"\\f1e4\";\n}\n.fa-binoculars:before {\n  content: \"\\f1e5\";\n}\n.fa-plug:before {\n  content: \"\\f1e6\";\n}\n.fa-slideshare:before {\n  content: \"\\f1e7\";\n}\n.fa-twitch:before {\n  content: \"\\f1e8\";\n}\n.fa-yelp:before {\n  content: \"\\f1e9\";\n}\n.fa-newspaper-o:before {\n  content: \"\\f1ea\";\n}\n.fa-wifi:before {\n  content: \"\\f1eb\";\n}\n.fa-calculator:before {\n  content: \"\\f1ec\";\n}\n.fa-paypal:before {\n  content: \"\\f1ed\";\n}\n.fa-google-wallet:before {\n  content: \"\\f1ee\";\n}\n.fa-cc-visa:before {\n  content: \"\\f1f0\";\n}\n.fa-cc-mastercard:before {\n  content: \"\\f1f1\";\n}\n.fa-cc-discover:before {\n  content: \"\\f1f2\";\n}\n.fa-cc-amex:before {\n  content: \"\\f1f3\";\n}\n.fa-cc-paypal:before {\n  content: \"\\f1f4\";\n}\n.fa-cc-stripe:before {\n  content: \"\\f1f5\";\n}\n.fa-bell-slash:before {\n  content: \"\\f1f6\";\n}\n.fa-bell-slash-o:before {\n  content: \"\\f1f7\";\n}\n.fa-trash:before {\n  content: \"\\f1f8\";\n}\n.fa-copyright:before {\n  content: \"\\f1f9\";\n}\n.fa-at:before {\n  content: \"\\f1fa\";\n}\n.fa-eyedropper:before {\n  content: \"\\f1fb\";\n}\n.fa-paint-brush:before {\n  content: \"\\f1fc\";\n}\n.fa-birthday-cake:before {\n  content: \"\\f1fd\";\n}\n.fa-area-chart:before {\n  content: \"\\f1fe\";\n}\n.fa-pie-chart:before {\n  content: \"\\f200\";\n}\n.fa-line-chart:before {\n  content: \"\\f201\";\n}\n.fa-lastfm:before {\n  content: \"\\f202\";\n}\n.fa-lastfm-square:before {\n  content: \"\\f203\";\n}\n.fa-toggle-off:before {\n  content: \"\\f204\";\n}\n.fa-toggle-on:before {\n  content: \"\\f205\";\n}\n.fa-bicycle:before {\n  content: \"\\f206\";\n}\n.fa-bus:before {\n  content: \"\\f207\";\n}\n.fa-ioxhost:before {\n  content: \"\\f208\";\n}\n.fa-angellist:before {\n  content: \"\\f209\";\n}\n.fa-cc:before {\n  content: \"\\f20a\";\n}\n.fa-shekel:before,\n.fa-sheqel:before,\n.fa-ils:before {\n  content: \"\\f20b\";\n}\n.fa-meanpath:before {\n  content: \"\\f20c\";\n}\n.fa-buysellads:before {\n  content: \"\\f20d\";\n}\n.fa-connectdevelop:before {\n  content: \"\\f20e\";\n}\n.fa-dashcube:before {\n  content: \"\\f210\";\n}\n.fa-forumbee:before {\n  content: \"\\f211\";\n}\n.fa-leanpub:before {\n  content: \"\\f212\";\n}\n.fa-sellsy:before {\n  content: \"\\f213\";\n}\n.fa-shirtsinbulk:before {\n  content: \"\\f214\";\n}\n.fa-simplybuilt:before {\n  content: \"\\f215\";\n}\n.fa-skyatlas:before {\n  content: \"\\f216\";\n}\n.fa-cart-plus:before {\n  content: \"\\f217\";\n}\n.fa-cart-arrow-down:before {\n  content: \"\\f218\";\n}\n.fa-diamond:before {\n  content: \"\\f219\";\n}\n.fa-ship:before {\n  content: \"\\f21a\";\n}\n.fa-user-secret:before {\n  content: \"\\f21b\";\n}\n.fa-motorcycle:before {\n  content: \"\\f21c\";\n}\n.fa-street-view:before {\n  content: \"\\f21d\";\n}\n.fa-heartbeat:before {\n  content: \"\\f21e\";\n}\n.fa-venus:before {\n  content: \"\\f221\";\n}\n.fa-mars:before {\n  content: \"\\f222\";\n}\n.fa-mercury:before {\n  content: \"\\f223\";\n}\n.fa-intersex:before,\n.fa-transgender:before {\n  content: \"\\f224\";\n}\n.fa-transgender-alt:before {\n  content: \"\\f225\";\n}\n.fa-venus-double:before {\n  content: \"\\f226\";\n}\n.fa-mars-double:before {\n  content: \"\\f227\";\n}\n.fa-venus-mars:before {\n  content: \"\\f228\";\n}\n.fa-mars-stroke:before {\n  content: \"\\f229\";\n}\n.fa-mars-stroke-v:before {\n  content: \"\\f22a\";\n}\n.fa-mars-stroke-h:before {\n  content: \"\\f22b\";\n}\n.fa-neuter:before {\n  content: \"\\f22c\";\n}\n.fa-genderless:before {\n  content: \"\\f22d\";\n}\n.fa-facebook-official:before {\n  content: \"\\f230\";\n}\n.fa-pinterest-p:before {\n  content: \"\\f231\";\n}\n.fa-whatsapp:before {\n  content: \"\\f232\";\n}\n.fa-server:before {\n  content: \"\\f233\";\n}\n.fa-user-plus:before {\n  content: \"\\f234\";\n}\n.fa-user-times:before {\n  content: \"\\f235\";\n}\n.fa-hotel:before,\n.fa-bed:before {\n  content: \"\\f236\";\n}\n.fa-viacoin:before {\n  content: \"\\f237\";\n}\n.fa-train:before {\n  content: \"\\f238\";\n}\n.fa-subway:before {\n  content: \"\\f239\";\n}\n.fa-medium:before {\n  content: \"\\f23a\";\n}\n.fa-yc:before,\n.fa-y-combinator:before {\n  content: \"\\f23b\";\n}\n.fa-optin-monster:before {\n  content: \"\\f23c\";\n}\n.fa-opencart:before {\n  content: \"\\f23d\";\n}\n.fa-expeditedssl:before {\n  content: \"\\f23e\";\n}\n.fa-battery-4:before,\n.fa-battery-full:before {\n  content: \"\\f240\";\n}\n.fa-battery-3:before,\n.fa-battery-three-quarters:before {\n  content: \"\\f241\";\n}\n.fa-battery-2:before,\n.fa-battery-half:before {\n  content: \"\\f242\";\n}\n.fa-battery-1:before,\n.fa-battery-quarter:before {\n  content: \"\\f243\";\n}\n.fa-battery-0:before,\n.fa-battery-empty:before {\n  content: \"\\f244\";\n}\n.fa-mouse-pointer:before {\n  content: \"\\f245\";\n}\n.fa-i-cursor:before {\n  content: \"\\f246\";\n}\n.fa-object-group:before {\n  content: \"\\f247\";\n}\n.fa-object-ungroup:before {\n  content: \"\\f248\";\n}\n.fa-sticky-note:before {\n  content: \"\\f249\";\n}\n.fa-sticky-note-o:before {\n  content: \"\\f24a\";\n}\n.fa-cc-jcb:before {\n  content: \"\\f24b\";\n}\n.fa-cc-diners-club:before {\n  content: \"\\f24c\";\n}\n.fa-clone:before {\n  content: \"\\f24d\";\n}\n.fa-balance-scale:before {\n  content: \"\\f24e\";\n}\n.fa-hourglass-o:before {\n  content: \"\\f250\";\n}\n.fa-hourglass-1:before,\n.fa-hourglass-start:before {\n  content: \"\\f251\";\n}\n.fa-hourglass-2:before,\n.fa-hourglass-half:before {\n  content: \"\\f252\";\n}\n.fa-hourglass-3:before,\n.fa-hourglass-end:before {\n  content: \"\\f253\";\n}\n.fa-hourglass:before {\n  content: \"\\f254\";\n}\n.fa-hand-grab-o:before,\n.fa-hand-rock-o:before {\n  content: \"\\f255\";\n}\n.fa-hand-stop-o:before,\n.fa-hand-paper-o:before {\n  content: \"\\f256\";\n}\n.fa-hand-scissors-o:before {\n  content: \"\\f257\";\n}\n.fa-hand-lizard-o:before {\n  content: \"\\f258\";\n}\n.fa-hand-spock-o:before {\n  content: \"\\f259\";\n}\n.fa-hand-pointer-o:before {\n  content: \"\\f25a\";\n}\n.fa-hand-peace-o:before {\n  content: \"\\f25b\";\n}\n.fa-trademark:before {\n  content: \"\\f25c\";\n}\n.fa-registered:before {\n  content: \"\\f25d\";\n}\n.fa-creative-commons:before {\n  content: \"\\f25e\";\n}\n.fa-gg:before {\n  content: \"\\f260\";\n}\n.fa-gg-circle:before {\n  content: \"\\f261\";\n}\n.fa-tripadvisor:before {\n  content: \"\\f262\";\n}\n.fa-odnoklassniki:before {\n  content: \"\\f263\";\n}\n.fa-odnoklassniki-square:before {\n  content: \"\\f264\";\n}\n.fa-get-pocket:before {\n  content: \"\\f265\";\n}\n.fa-wikipedia-w:before {\n  content: \"\\f266\";\n}\n.fa-safari:before {\n  content: \"\\f267\";\n}\n.fa-chrome:before {\n  content: \"\\f268\";\n}\n.fa-firefox:before {\n  content: \"\\f269\";\n}\n.fa-opera:before {\n  content: \"\\f26a\";\n}\n.fa-internet-explorer:before {\n  content: \"\\f26b\";\n}\n.fa-tv:before,\n.fa-television:before {\n  content: \"\\f26c\";\n}\n.fa-contao:before {\n  content: \"\\f26d\";\n}\n.fa-500px:before {\n  content: \"\\f26e\";\n}\n.fa-amazon:before {\n  content: \"\\f270\";\n}\n.fa-calendar-plus-o:before {\n  content: \"\\f271\";\n}\n.fa-calendar-minus-o:before {\n  content: \"\\f272\";\n}\n.fa-calendar-times-o:before {\n  content: \"\\f273\";\n}\n.fa-calendar-check-o:before {\n  content: \"\\f274\";\n}\n.fa-industry:before {\n  content: \"\\f275\";\n}\n.fa-map-pin:before {\n  content: \"\\f276\";\n}\n.fa-map-signs:before {\n  content: \"\\f277\";\n}\n.fa-map-o:before {\n  content: \"\\f278\";\n}\n.fa-map:before {\n  content: \"\\f279\";\n}\n.fa-commenting:before {\n  content: \"\\f27a\";\n}\n.fa-commenting-o:before {\n  content: \"\\f27b\";\n}\n.fa-houzz:before {\n  content: \"\\f27c\";\n}\n.fa-vimeo:before {\n  content: \"\\f27d\";\n}\n.fa-black-tie:before {\n  content: \"\\f27e\";\n}\n.fa-fonticons:before {\n  content: \"\\f280\";\n}\n.fa-reddit-alien:before {\n  content: \"\\f281\";\n}\n.fa-edge:before {\n  content: \"\\f282\";\n}\n.fa-credit-card-alt:before {\n  content: \"\\f283\";\n}\n.fa-codiepie:before {\n  content: \"\\f284\";\n}\n.fa-modx:before {\n  content: \"\\f285\";\n}\n.fa-fort-awesome:before {\n  content: \"\\f286\";\n}\n.fa-usb:before {\n  content: \"\\f287\";\n}\n.fa-product-hunt:before {\n  content: \"\\f288\";\n}\n.fa-mixcloud:before {\n  content: \"\\f289\";\n}\n.fa-scribd:before {\n  content: \"\\f28a\";\n}\n.fa-pause-circle:before {\n  content: \"\\f28b\";\n}\n.fa-pause-circle-o:before {\n  content: \"\\f28c\";\n}\n.fa-stop-circle:before {\n  content: \"\\f28d\";\n}\n.fa-stop-circle-o:before {\n  content: \"\\f28e\";\n}\n.fa-shopping-bag:before {\n  content: \"\\f290\";\n}\n.fa-shopping-basket:before {\n  content: \"\\f291\";\n}\n.fa-hashtag:before {\n  content: \"\\f292\";\n}\n.fa-bluetooth:before {\n  content: \"\\f293\";\n}\n.fa-bluetooth-b:before {\n  content: \"\\f294\";\n}\n.fa-percent:before {\n  content: \"\\f295\";\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/animated.less",
    "content": "// Animated Icons\n// --------------------------\n\n.@{fa-css-prefix}-spin {\n  -webkit-animation: fa-spin 2s infinite linear;\n          animation: fa-spin 2s infinite linear;\n}\n\n.@{fa-css-prefix}-pulse {\n  -webkit-animation: fa-spin 1s infinite steps(8);\n          animation: fa-spin 1s infinite steps(8);\n}\n\n@-webkit-keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n            transform: rotate(359deg);\n  }\n}\n\n@keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n            transform: rotate(359deg);\n  }\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/bordered-pulled.less",
    "content": "// Bordered & Pulled\n// -------------------------\n\n.@{fa-css-prefix}-border {\n  padding: .2em .25em .15em;\n  border: solid .08em @fa-border-color;\n  border-radius: .1em;\n}\n\n.@{fa-css-prefix}-pull-left { float: left; }\n.@{fa-css-prefix}-pull-right { float: right; }\n\n.@{fa-css-prefix} {\n  &.@{fa-css-prefix}-pull-left { margin-right: .3em; }\n  &.@{fa-css-prefix}-pull-right { margin-left: .3em; }\n}\n\n/* Deprecated as of 4.4.0 */\n.pull-right { float: right; }\n.pull-left { float: left; }\n\n.@{fa-css-prefix} {\n  &.pull-left { margin-right: .3em; }\n  &.pull-right { margin-left: .3em; }\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/core.less",
    "content": "// Base Class Definition\n// -------------------------\n\n.@{fa-css-prefix} {\n  display: inline-block;\n  font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration\n  font-size: inherit; // can't have font-size inherit on line above, so need to override\n  text-rendering: auto; // optimizelegibility throws things off #1094\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/fixed-width.less",
    "content": "// Fixed Width Icons\n// -------------------------\n.@{fa-css-prefix}-fw {\n  width: (18em / 14);\n  text-align: center;\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/font-awesome.less",
    "content": "/*!\n *  Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)\n */\n\n@import \"variables.less\";\n@import \"mixins.less\";\n@import \"path.less\";\n@import \"core.less\";\n@import \"larger.less\";\n@import \"fixed-width.less\";\n@import \"list.less\";\n@import \"bordered-pulled.less\";\n@import \"animated.less\";\n@import \"rotated-flipped.less\";\n@import \"stacked.less\";\n@import \"icons.less\";\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/icons.less",
    "content": "/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\n   readers do not read off random characters that represent icons */\n\n.@{fa-css-prefix}-glass:before { content: @fa-var-glass; }\n.@{fa-css-prefix}-music:before { content: @fa-var-music; }\n.@{fa-css-prefix}-search:before { content: @fa-var-search; }\n.@{fa-css-prefix}-envelope-o:before { content: @fa-var-envelope-o; }\n.@{fa-css-prefix}-heart:before { content: @fa-var-heart; }\n.@{fa-css-prefix}-star:before { content: @fa-var-star; }\n.@{fa-css-prefix}-star-o:before { content: @fa-var-star-o; }\n.@{fa-css-prefix}-user:before { content: @fa-var-user; }\n.@{fa-css-prefix}-film:before { content: @fa-var-film; }\n.@{fa-css-prefix}-th-large:before { content: @fa-var-th-large; }\n.@{fa-css-prefix}-th:before { content: @fa-var-th; }\n.@{fa-css-prefix}-th-list:before { content: @fa-var-th-list; }\n.@{fa-css-prefix}-check:before { content: @fa-var-check; }\n.@{fa-css-prefix}-remove:before,\n.@{fa-css-prefix}-close:before,\n.@{fa-css-prefix}-times:before { content: @fa-var-times; }\n.@{fa-css-prefix}-search-plus:before { content: @fa-var-search-plus; }\n.@{fa-css-prefix}-search-minus:before { content: @fa-var-search-minus; }\n.@{fa-css-prefix}-power-off:before { content: @fa-var-power-off; }\n.@{fa-css-prefix}-signal:before { content: @fa-var-signal; }\n.@{fa-css-prefix}-gear:before,\n.@{fa-css-prefix}-cog:before { content: @fa-var-cog; }\n.@{fa-css-prefix}-trash-o:before { content: @fa-var-trash-o; }\n.@{fa-css-prefix}-home:before { content: @fa-var-home; }\n.@{fa-css-prefix}-file-o:before { content: @fa-var-file-o; }\n.@{fa-css-prefix}-clock-o:before { content: @fa-var-clock-o; }\n.@{fa-css-prefix}-road:before { content: @fa-var-road; }\n.@{fa-css-prefix}-download:before { content: @fa-var-download; }\n.@{fa-css-prefix}-arrow-circle-o-down:before { content: @fa-var-arrow-circle-o-down; }\n.@{fa-css-prefix}-arrow-circle-o-up:before { content: @fa-var-arrow-circle-o-up; }\n.@{fa-css-prefix}-inbox:before { content: @fa-var-inbox; }\n.@{fa-css-prefix}-play-circle-o:before { content: @fa-var-play-circle-o; }\n.@{fa-css-prefix}-rotate-right:before,\n.@{fa-css-prefix}-repeat:before { content: @fa-var-repeat; }\n.@{fa-css-prefix}-refresh:before { content: @fa-var-refresh; }\n.@{fa-css-prefix}-list-alt:before { content: @fa-var-list-alt; }\n.@{fa-css-prefix}-lock:before { content: @fa-var-lock; }\n.@{fa-css-prefix}-flag:before { content: @fa-var-flag; }\n.@{fa-css-prefix}-headphones:before { content: @fa-var-headphones; }\n.@{fa-css-prefix}-volume-off:before { content: @fa-var-volume-off; }\n.@{fa-css-prefix}-volume-down:before { content: @fa-var-volume-down; }\n.@{fa-css-prefix}-volume-up:before { content: @fa-var-volume-up; }\n.@{fa-css-prefix}-qrcode:before { content: @fa-var-qrcode; }\n.@{fa-css-prefix}-barcode:before { content: @fa-var-barcode; }\n.@{fa-css-prefix}-tag:before { content: @fa-var-tag; }\n.@{fa-css-prefix}-tags:before { content: @fa-var-tags; }\n.@{fa-css-prefix}-book:before { content: @fa-var-book; }\n.@{fa-css-prefix}-bookmark:before { content: @fa-var-bookmark; }\n.@{fa-css-prefix}-print:before { content: @fa-var-print; }\n.@{fa-css-prefix}-camera:before { content: @fa-var-camera; }\n.@{fa-css-prefix}-font:before { content: @fa-var-font; }\n.@{fa-css-prefix}-bold:before { content: @fa-var-bold; }\n.@{fa-css-prefix}-italic:before { content: @fa-var-italic; }\n.@{fa-css-prefix}-text-height:before { content: @fa-var-text-height; }\n.@{fa-css-prefix}-text-width:before { content: @fa-var-text-width; }\n.@{fa-css-prefix}-align-left:before { content: @fa-var-align-left; }\n.@{fa-css-prefix}-align-center:before { content: @fa-var-align-center; }\n.@{fa-css-prefix}-align-right:before { content: @fa-var-align-right; }\n.@{fa-css-prefix}-align-justify:before { content: @fa-var-align-justify; }\n.@{fa-css-prefix}-list:before { content: @fa-var-list; }\n.@{fa-css-prefix}-dedent:before,\n.@{fa-css-prefix}-outdent:before { content: @fa-var-outdent; }\n.@{fa-css-prefix}-indent:before { content: @fa-var-indent; }\n.@{fa-css-prefix}-video-camera:before { content: @fa-var-video-camera; }\n.@{fa-css-prefix}-photo:before,\n.@{fa-css-prefix}-image:before,\n.@{fa-css-prefix}-picture-o:before { content: @fa-var-picture-o; }\n.@{fa-css-prefix}-pencil:before { content: @fa-var-pencil; }\n.@{fa-css-prefix}-map-marker:before { content: @fa-var-map-marker; }\n.@{fa-css-prefix}-adjust:before { content: @fa-var-adjust; }\n.@{fa-css-prefix}-tint:before { content: @fa-var-tint; }\n.@{fa-css-prefix}-edit:before,\n.@{fa-css-prefix}-pencil-square-o:before { content: @fa-var-pencil-square-o; }\n.@{fa-css-prefix}-share-square-o:before { content: @fa-var-share-square-o; }\n.@{fa-css-prefix}-check-square-o:before { content: @fa-var-check-square-o; }\n.@{fa-css-prefix}-arrows:before { content: @fa-var-arrows; }\n.@{fa-css-prefix}-step-backward:before { content: @fa-var-step-backward; }\n.@{fa-css-prefix}-fast-backward:before { content: @fa-var-fast-backward; }\n.@{fa-css-prefix}-backward:before { content: @fa-var-backward; }\n.@{fa-css-prefix}-play:before { content: @fa-var-play; }\n.@{fa-css-prefix}-pause:before { content: @fa-var-pause; }\n.@{fa-css-prefix}-stop:before { content: @fa-var-stop; }\n.@{fa-css-prefix}-forward:before { content: @fa-var-forward; }\n.@{fa-css-prefix}-fast-forward:before { content: @fa-var-fast-forward; }\n.@{fa-css-prefix}-step-forward:before { content: @fa-var-step-forward; }\n.@{fa-css-prefix}-eject:before { content: @fa-var-eject; }\n.@{fa-css-prefix}-chevron-left:before { content: @fa-var-chevron-left; }\n.@{fa-css-prefix}-chevron-right:before { content: @fa-var-chevron-right; }\n.@{fa-css-prefix}-plus-circle:before { content: @fa-var-plus-circle; }\n.@{fa-css-prefix}-minus-circle:before { content: @fa-var-minus-circle; }\n.@{fa-css-prefix}-times-circle:before { content: @fa-var-times-circle; }\n.@{fa-css-prefix}-check-circle:before { content: @fa-var-check-circle; }\n.@{fa-css-prefix}-question-circle:before { content: @fa-var-question-circle; }\n.@{fa-css-prefix}-info-circle:before { content: @fa-var-info-circle; }\n.@{fa-css-prefix}-crosshairs:before { content: @fa-var-crosshairs; }\n.@{fa-css-prefix}-times-circle-o:before { content: @fa-var-times-circle-o; }\n.@{fa-css-prefix}-check-circle-o:before { content: @fa-var-check-circle-o; }\n.@{fa-css-prefix}-ban:before { content: @fa-var-ban; }\n.@{fa-css-prefix}-arrow-left:before { content: @fa-var-arrow-left; }\n.@{fa-css-prefix}-arrow-right:before { content: @fa-var-arrow-right; }\n.@{fa-css-prefix}-arrow-up:before { content: @fa-var-arrow-up; }\n.@{fa-css-prefix}-arrow-down:before { content: @fa-var-arrow-down; }\n.@{fa-css-prefix}-mail-forward:before,\n.@{fa-css-prefix}-share:before { content: @fa-var-share; }\n.@{fa-css-prefix}-expand:before { content: @fa-var-expand; }\n.@{fa-css-prefix}-compress:before { content: @fa-var-compress; }\n.@{fa-css-prefix}-plus:before { content: @fa-var-plus; }\n.@{fa-css-prefix}-minus:before { content: @fa-var-minus; }\n.@{fa-css-prefix}-asterisk:before { content: @fa-var-asterisk; }\n.@{fa-css-prefix}-exclamation-circle:before { content: @fa-var-exclamation-circle; }\n.@{fa-css-prefix}-gift:before { content: @fa-var-gift; }\n.@{fa-css-prefix}-leaf:before { content: @fa-var-leaf; }\n.@{fa-css-prefix}-fire:before { content: @fa-var-fire; }\n.@{fa-css-prefix}-eye:before { content: @fa-var-eye; }\n.@{fa-css-prefix}-eye-slash:before { content: @fa-var-eye-slash; }\n.@{fa-css-prefix}-warning:before,\n.@{fa-css-prefix}-exclamation-triangle:before { content: @fa-var-exclamation-triangle; }\n.@{fa-css-prefix}-plane:before { content: @fa-var-plane; }\n.@{fa-css-prefix}-calendar:before { content: @fa-var-calendar; }\n.@{fa-css-prefix}-random:before { content: @fa-var-random; }\n.@{fa-css-prefix}-comment:before { content: @fa-var-comment; }\n.@{fa-css-prefix}-magnet:before { content: @fa-var-magnet; }\n.@{fa-css-prefix}-chevron-up:before { content: @fa-var-chevron-up; }\n.@{fa-css-prefix}-chevron-down:before { content: @fa-var-chevron-down; }\n.@{fa-css-prefix}-retweet:before { content: @fa-var-retweet; }\n.@{fa-css-prefix}-shopping-cart:before { content: @fa-var-shopping-cart; }\n.@{fa-css-prefix}-folder:before { content: @fa-var-folder; }\n.@{fa-css-prefix}-folder-open:before { content: @fa-var-folder-open; }\n.@{fa-css-prefix}-arrows-v:before { content: @fa-var-arrows-v; }\n.@{fa-css-prefix}-arrows-h:before { content: @fa-var-arrows-h; }\n.@{fa-css-prefix}-bar-chart-o:before,\n.@{fa-css-prefix}-bar-chart:before { content: @fa-var-bar-chart; }\n.@{fa-css-prefix}-twitter-square:before { content: @fa-var-twitter-square; }\n.@{fa-css-prefix}-facebook-square:before { content: @fa-var-facebook-square; }\n.@{fa-css-prefix}-camera-retro:before { content: @fa-var-camera-retro; }\n.@{fa-css-prefix}-key:before { content: @fa-var-key; }\n.@{fa-css-prefix}-gears:before,\n.@{fa-css-prefix}-cogs:before { content: @fa-var-cogs; }\n.@{fa-css-prefix}-comments:before { content: @fa-var-comments; }\n.@{fa-css-prefix}-thumbs-o-up:before { content: @fa-var-thumbs-o-up; }\n.@{fa-css-prefix}-thumbs-o-down:before { content: @fa-var-thumbs-o-down; }\n.@{fa-css-prefix}-star-half:before { content: @fa-var-star-half; }\n.@{fa-css-prefix}-heart-o:before { content: @fa-var-heart-o; }\n.@{fa-css-prefix}-sign-out:before { content: @fa-var-sign-out; }\n.@{fa-css-prefix}-linkedin-square:before { content: @fa-var-linkedin-square; }\n.@{fa-css-prefix}-thumb-tack:before { content: @fa-var-thumb-tack; }\n.@{fa-css-prefix}-external-link:before { content: @fa-var-external-link; }\n.@{fa-css-prefix}-sign-in:before { content: @fa-var-sign-in; }\n.@{fa-css-prefix}-trophy:before { content: @fa-var-trophy; }\n.@{fa-css-prefix}-github-square:before { content: @fa-var-github-square; }\n.@{fa-css-prefix}-upload:before { content: @fa-var-upload; }\n.@{fa-css-prefix}-lemon-o:before { content: @fa-var-lemon-o; }\n.@{fa-css-prefix}-phone:before { content: @fa-var-phone; }\n.@{fa-css-prefix}-square-o:before { content: @fa-var-square-o; }\n.@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; }\n.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; }\n.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; }\n.@{fa-css-prefix}-facebook-f:before,\n.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; }\n.@{fa-css-prefix}-github:before { content: @fa-var-github; }\n.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; }\n.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; }\n.@{fa-css-prefix}-feed:before,\n.@{fa-css-prefix}-rss:before { content: @fa-var-rss; }\n.@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; }\n.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; }\n.@{fa-css-prefix}-bell:before { content: @fa-var-bell; }\n.@{fa-css-prefix}-certificate:before { content: @fa-var-certificate; }\n.@{fa-css-prefix}-hand-o-right:before { content: @fa-var-hand-o-right; }\n.@{fa-css-prefix}-hand-o-left:before { content: @fa-var-hand-o-left; }\n.@{fa-css-prefix}-hand-o-up:before { content: @fa-var-hand-o-up; }\n.@{fa-css-prefix}-hand-o-down:before { content: @fa-var-hand-o-down; }\n.@{fa-css-prefix}-arrow-circle-left:before { content: @fa-var-arrow-circle-left; }\n.@{fa-css-prefix}-arrow-circle-right:before { content: @fa-var-arrow-circle-right; }\n.@{fa-css-prefix}-arrow-circle-up:before { content: @fa-var-arrow-circle-up; }\n.@{fa-css-prefix}-arrow-circle-down:before { content: @fa-var-arrow-circle-down; }\n.@{fa-css-prefix}-globe:before { content: @fa-var-globe; }\n.@{fa-css-prefix}-wrench:before { content: @fa-var-wrench; }\n.@{fa-css-prefix}-tasks:before { content: @fa-var-tasks; }\n.@{fa-css-prefix}-filter:before { content: @fa-var-filter; }\n.@{fa-css-prefix}-briefcase:before { content: @fa-var-briefcase; }\n.@{fa-css-prefix}-arrows-alt:before { content: @fa-var-arrows-alt; }\n.@{fa-css-prefix}-group:before,\n.@{fa-css-prefix}-users:before { content: @fa-var-users; }\n.@{fa-css-prefix}-chain:before,\n.@{fa-css-prefix}-link:before { content: @fa-var-link; }\n.@{fa-css-prefix}-cloud:before { content: @fa-var-cloud; }\n.@{fa-css-prefix}-flask:before { content: @fa-var-flask; }\n.@{fa-css-prefix}-cut:before,\n.@{fa-css-prefix}-scissors:before { content: @fa-var-scissors; }\n.@{fa-css-prefix}-copy:before,\n.@{fa-css-prefix}-files-o:before { content: @fa-var-files-o; }\n.@{fa-css-prefix}-paperclip:before { content: @fa-var-paperclip; }\n.@{fa-css-prefix}-save:before,\n.@{fa-css-prefix}-floppy-o:before { content: @fa-var-floppy-o; }\n.@{fa-css-prefix}-square:before { content: @fa-var-square; }\n.@{fa-css-prefix}-navicon:before,\n.@{fa-css-prefix}-reorder:before,\n.@{fa-css-prefix}-bars:before { content: @fa-var-bars; }\n.@{fa-css-prefix}-list-ul:before { content: @fa-var-list-ul; }\n.@{fa-css-prefix}-list-ol:before { content: @fa-var-list-ol; }\n.@{fa-css-prefix}-strikethrough:before { content: @fa-var-strikethrough; }\n.@{fa-css-prefix}-underline:before { content: @fa-var-underline; }\n.@{fa-css-prefix}-table:before { content: @fa-var-table; }\n.@{fa-css-prefix}-magic:before { content: @fa-var-magic; }\n.@{fa-css-prefix}-truck:before { content: @fa-var-truck; }\n.@{fa-css-prefix}-pinterest:before { content: @fa-var-pinterest; }\n.@{fa-css-prefix}-pinterest-square:before { content: @fa-var-pinterest-square; }\n.@{fa-css-prefix}-google-plus-square:before { content: @fa-var-google-plus-square; }\n.@{fa-css-prefix}-google-plus:before { content: @fa-var-google-plus; }\n.@{fa-css-prefix}-money:before { content: @fa-var-money; }\n.@{fa-css-prefix}-caret-down:before { content: @fa-var-caret-down; }\n.@{fa-css-prefix}-caret-up:before { content: @fa-var-caret-up; }\n.@{fa-css-prefix}-caret-left:before { content: @fa-var-caret-left; }\n.@{fa-css-prefix}-caret-right:before { content: @fa-var-caret-right; }\n.@{fa-css-prefix}-columns:before { content: @fa-var-columns; }\n.@{fa-css-prefix}-unsorted:before,\n.@{fa-css-prefix}-sort:before { content: @fa-var-sort; }\n.@{fa-css-prefix}-sort-down:before,\n.@{fa-css-prefix}-sort-desc:before { content: @fa-var-sort-desc; }\n.@{fa-css-prefix}-sort-up:before,\n.@{fa-css-prefix}-sort-asc:before { content: @fa-var-sort-asc; }\n.@{fa-css-prefix}-envelope:before { content: @fa-var-envelope; }\n.@{fa-css-prefix}-linkedin:before { content: @fa-var-linkedin; }\n.@{fa-css-prefix}-rotate-left:before,\n.@{fa-css-prefix}-undo:before { content: @fa-var-undo; }\n.@{fa-css-prefix}-legal:before,\n.@{fa-css-prefix}-gavel:before { content: @fa-var-gavel; }\n.@{fa-css-prefix}-dashboard:before,\n.@{fa-css-prefix}-tachometer:before { content: @fa-var-tachometer; }\n.@{fa-css-prefix}-comment-o:before { content: @fa-var-comment-o; }\n.@{fa-css-prefix}-comments-o:before { content: @fa-var-comments-o; }\n.@{fa-css-prefix}-flash:before,\n.@{fa-css-prefix}-bolt:before { content: @fa-var-bolt; }\n.@{fa-css-prefix}-sitemap:before { content: @fa-var-sitemap; }\n.@{fa-css-prefix}-umbrella:before { content: @fa-var-umbrella; }\n.@{fa-css-prefix}-paste:before,\n.@{fa-css-prefix}-clipboard:before { content: @fa-var-clipboard; }\n.@{fa-css-prefix}-lightbulb-o:before { content: @fa-var-lightbulb-o; }\n.@{fa-css-prefix}-exchange:before { content: @fa-var-exchange; }\n.@{fa-css-prefix}-cloud-download:before { content: @fa-var-cloud-download; }\n.@{fa-css-prefix}-cloud-upload:before { content: @fa-var-cloud-upload; }\n.@{fa-css-prefix}-user-md:before { content: @fa-var-user-md; }\n.@{fa-css-prefix}-stethoscope:before { content: @fa-var-stethoscope; }\n.@{fa-css-prefix}-suitcase:before { content: @fa-var-suitcase; }\n.@{fa-css-prefix}-bell-o:before { content: @fa-var-bell-o; }\n.@{fa-css-prefix}-coffee:before { content: @fa-var-coffee; }\n.@{fa-css-prefix}-cutlery:before { content: @fa-var-cutlery; }\n.@{fa-css-prefix}-file-text-o:before { content: @fa-var-file-text-o; }\n.@{fa-css-prefix}-building-o:before { content: @fa-var-building-o; }\n.@{fa-css-prefix}-hospital-o:before { content: @fa-var-hospital-o; }\n.@{fa-css-prefix}-ambulance:before { content: @fa-var-ambulance; }\n.@{fa-css-prefix}-medkit:before { content: @fa-var-medkit; }\n.@{fa-css-prefix}-fighter-jet:before { content: @fa-var-fighter-jet; }\n.@{fa-css-prefix}-beer:before { content: @fa-var-beer; }\n.@{fa-css-prefix}-h-square:before { content: @fa-var-h-square; }\n.@{fa-css-prefix}-plus-square:before { content: @fa-var-plus-square; }\n.@{fa-css-prefix}-angle-double-left:before { content: @fa-var-angle-double-left; }\n.@{fa-css-prefix}-angle-double-right:before { content: @fa-var-angle-double-right; }\n.@{fa-css-prefix}-angle-double-up:before { content: @fa-var-angle-double-up; }\n.@{fa-css-prefix}-angle-double-down:before { content: @fa-var-angle-double-down; }\n.@{fa-css-prefix}-angle-left:before { content: @fa-var-angle-left; }\n.@{fa-css-prefix}-angle-right:before { content: @fa-var-angle-right; }\n.@{fa-css-prefix}-angle-up:before { content: @fa-var-angle-up; }\n.@{fa-css-prefix}-angle-down:before { content: @fa-var-angle-down; }\n.@{fa-css-prefix}-desktop:before { content: @fa-var-desktop; }\n.@{fa-css-prefix}-laptop:before { content: @fa-var-laptop; }\n.@{fa-css-prefix}-tablet:before { content: @fa-var-tablet; }\n.@{fa-css-prefix}-mobile-phone:before,\n.@{fa-css-prefix}-mobile:before { content: @fa-var-mobile; }\n.@{fa-css-prefix}-circle-o:before { content: @fa-var-circle-o; }\n.@{fa-css-prefix}-quote-left:before { content: @fa-var-quote-left; }\n.@{fa-css-prefix}-quote-right:before { content: @fa-var-quote-right; }\n.@{fa-css-prefix}-spinner:before { content: @fa-var-spinner; }\n.@{fa-css-prefix}-circle:before { content: @fa-var-circle; }\n.@{fa-css-prefix}-mail-reply:before,\n.@{fa-css-prefix}-reply:before { content: @fa-var-reply; }\n.@{fa-css-prefix}-github-alt:before { content: @fa-var-github-alt; }\n.@{fa-css-prefix}-folder-o:before { content: @fa-var-folder-o; }\n.@{fa-css-prefix}-folder-open-o:before { content: @fa-var-folder-open-o; }\n.@{fa-css-prefix}-smile-o:before { content: @fa-var-smile-o; }\n.@{fa-css-prefix}-frown-o:before { content: @fa-var-frown-o; }\n.@{fa-css-prefix}-meh-o:before { content: @fa-var-meh-o; }\n.@{fa-css-prefix}-gamepad:before { content: @fa-var-gamepad; }\n.@{fa-css-prefix}-keyboard-o:before { content: @fa-var-keyboard-o; }\n.@{fa-css-prefix}-flag-o:before { content: @fa-var-flag-o; }\n.@{fa-css-prefix}-flag-checkered:before { content: @fa-var-flag-checkered; }\n.@{fa-css-prefix}-terminal:before { content: @fa-var-terminal; }\n.@{fa-css-prefix}-code:before { content: @fa-var-code; }\n.@{fa-css-prefix}-mail-reply-all:before,\n.@{fa-css-prefix}-reply-all:before { content: @fa-var-reply-all; }\n.@{fa-css-prefix}-star-half-empty:before,\n.@{fa-css-prefix}-star-half-full:before,\n.@{fa-css-prefix}-star-half-o:before { content: @fa-var-star-half-o; }\n.@{fa-css-prefix}-location-arrow:before { content: @fa-var-location-arrow; }\n.@{fa-css-prefix}-crop:before { content: @fa-var-crop; }\n.@{fa-css-prefix}-code-fork:before { content: @fa-var-code-fork; }\n.@{fa-css-prefix}-unlink:before,\n.@{fa-css-prefix}-chain-broken:before { content: @fa-var-chain-broken; }\n.@{fa-css-prefix}-question:before { content: @fa-var-question; }\n.@{fa-css-prefix}-info:before { content: @fa-var-info; }\n.@{fa-css-prefix}-exclamation:before { content: @fa-var-exclamation; }\n.@{fa-css-prefix}-superscript:before { content: @fa-var-superscript; }\n.@{fa-css-prefix}-subscript:before { content: @fa-var-subscript; }\n.@{fa-css-prefix}-eraser:before { content: @fa-var-eraser; }\n.@{fa-css-prefix}-puzzle-piece:before { content: @fa-var-puzzle-piece; }\n.@{fa-css-prefix}-microphone:before { content: @fa-var-microphone; }\n.@{fa-css-prefix}-microphone-slash:before { content: @fa-var-microphone-slash; }\n.@{fa-css-prefix}-shield:before { content: @fa-var-shield; }\n.@{fa-css-prefix}-calendar-o:before { content: @fa-var-calendar-o; }\n.@{fa-css-prefix}-fire-extinguisher:before { content: @fa-var-fire-extinguisher; }\n.@{fa-css-prefix}-rocket:before { content: @fa-var-rocket; }\n.@{fa-css-prefix}-maxcdn:before { content: @fa-var-maxcdn; }\n.@{fa-css-prefix}-chevron-circle-left:before { content: @fa-var-chevron-circle-left; }\n.@{fa-css-prefix}-chevron-circle-right:before { content: @fa-var-chevron-circle-right; }\n.@{fa-css-prefix}-chevron-circle-up:before { content: @fa-var-chevron-circle-up; }\n.@{fa-css-prefix}-chevron-circle-down:before { content: @fa-var-chevron-circle-down; }\n.@{fa-css-prefix}-html5:before { content: @fa-var-html5; }\n.@{fa-css-prefix}-css3:before { content: @fa-var-css3; }\n.@{fa-css-prefix}-anchor:before { content: @fa-var-anchor; }\n.@{fa-css-prefix}-unlock-alt:before { content: @fa-var-unlock-alt; }\n.@{fa-css-prefix}-bullseye:before { content: @fa-var-bullseye; }\n.@{fa-css-prefix}-ellipsis-h:before { content: @fa-var-ellipsis-h; }\n.@{fa-css-prefix}-ellipsis-v:before { content: @fa-var-ellipsis-v; }\n.@{fa-css-prefix}-rss-square:before { content: @fa-var-rss-square; }\n.@{fa-css-prefix}-play-circle:before { content: @fa-var-play-circle; }\n.@{fa-css-prefix}-ticket:before { content: @fa-var-ticket; }\n.@{fa-css-prefix}-minus-square:before { content: @fa-var-minus-square; }\n.@{fa-css-prefix}-minus-square-o:before { content: @fa-var-minus-square-o; }\n.@{fa-css-prefix}-level-up:before { content: @fa-var-level-up; }\n.@{fa-css-prefix}-level-down:before { content: @fa-var-level-down; }\n.@{fa-css-prefix}-check-square:before { content: @fa-var-check-square; }\n.@{fa-css-prefix}-pencil-square:before { content: @fa-var-pencil-square; }\n.@{fa-css-prefix}-external-link-square:before { content: @fa-var-external-link-square; }\n.@{fa-css-prefix}-share-square:before { content: @fa-var-share-square; }\n.@{fa-css-prefix}-compass:before { content: @fa-var-compass; }\n.@{fa-css-prefix}-toggle-down:before,\n.@{fa-css-prefix}-caret-square-o-down:before { content: @fa-var-caret-square-o-down; }\n.@{fa-css-prefix}-toggle-up:before,\n.@{fa-css-prefix}-caret-square-o-up:before { content: @fa-var-caret-square-o-up; }\n.@{fa-css-prefix}-toggle-right:before,\n.@{fa-css-prefix}-caret-square-o-right:before { content: @fa-var-caret-square-o-right; }\n.@{fa-css-prefix}-euro:before,\n.@{fa-css-prefix}-eur:before { content: @fa-var-eur; }\n.@{fa-css-prefix}-gbp:before { content: @fa-var-gbp; }\n.@{fa-css-prefix}-dollar:before,\n.@{fa-css-prefix}-usd:before { content: @fa-var-usd; }\n.@{fa-css-prefix}-rupee:before,\n.@{fa-css-prefix}-inr:before { content: @fa-var-inr; }\n.@{fa-css-prefix}-cny:before,\n.@{fa-css-prefix}-rmb:before,\n.@{fa-css-prefix}-yen:before,\n.@{fa-css-prefix}-jpy:before { content: @fa-var-jpy; }\n.@{fa-css-prefix}-ruble:before,\n.@{fa-css-prefix}-rouble:before,\n.@{fa-css-prefix}-rub:before { content: @fa-var-rub; }\n.@{fa-css-prefix}-won:before,\n.@{fa-css-prefix}-krw:before { content: @fa-var-krw; }\n.@{fa-css-prefix}-bitcoin:before,\n.@{fa-css-prefix}-btc:before { content: @fa-var-btc; }\n.@{fa-css-prefix}-file:before { content: @fa-var-file; }\n.@{fa-css-prefix}-file-text:before { content: @fa-var-file-text; }\n.@{fa-css-prefix}-sort-alpha-asc:before { content: @fa-var-sort-alpha-asc; }\n.@{fa-css-prefix}-sort-alpha-desc:before { content: @fa-var-sort-alpha-desc; }\n.@{fa-css-prefix}-sort-amount-asc:before { content: @fa-var-sort-amount-asc; }\n.@{fa-css-prefix}-sort-amount-desc:before { content: @fa-var-sort-amount-desc; }\n.@{fa-css-prefix}-sort-numeric-asc:before { content: @fa-var-sort-numeric-asc; }\n.@{fa-css-prefix}-sort-numeric-desc:before { content: @fa-var-sort-numeric-desc; }\n.@{fa-css-prefix}-thumbs-up:before { content: @fa-var-thumbs-up; }\n.@{fa-css-prefix}-thumbs-down:before { content: @fa-var-thumbs-down; }\n.@{fa-css-prefix}-youtube-square:before { content: @fa-var-youtube-square; }\n.@{fa-css-prefix}-youtube:before { content: @fa-var-youtube; }\n.@{fa-css-prefix}-xing:before { content: @fa-var-xing; }\n.@{fa-css-prefix}-xing-square:before { content: @fa-var-xing-square; }\n.@{fa-css-prefix}-youtube-play:before { content: @fa-var-youtube-play; }\n.@{fa-css-prefix}-dropbox:before { content: @fa-var-dropbox; }\n.@{fa-css-prefix}-stack-overflow:before { content: @fa-var-stack-overflow; }\n.@{fa-css-prefix}-instagram:before { content: @fa-var-instagram; }\n.@{fa-css-prefix}-flickr:before { content: @fa-var-flickr; }\n.@{fa-css-prefix}-adn:before { content: @fa-var-adn; }\n.@{fa-css-prefix}-bitbucket:before { content: @fa-var-bitbucket; }\n.@{fa-css-prefix}-bitbucket-square:before { content: @fa-var-bitbucket-square; }\n.@{fa-css-prefix}-tumblr:before { content: @fa-var-tumblr; }\n.@{fa-css-prefix}-tumblr-square:before { content: @fa-var-tumblr-square; }\n.@{fa-css-prefix}-long-arrow-down:before { content: @fa-var-long-arrow-down; }\n.@{fa-css-prefix}-long-arrow-up:before { content: @fa-var-long-arrow-up; }\n.@{fa-css-prefix}-long-arrow-left:before { content: @fa-var-long-arrow-left; }\n.@{fa-css-prefix}-long-arrow-right:before { content: @fa-var-long-arrow-right; }\n.@{fa-css-prefix}-apple:before { content: @fa-var-apple; }\n.@{fa-css-prefix}-windows:before { content: @fa-var-windows; }\n.@{fa-css-prefix}-android:before { content: @fa-var-android; }\n.@{fa-css-prefix}-linux:before { content: @fa-var-linux; }\n.@{fa-css-prefix}-dribbble:before { content: @fa-var-dribbble; }\n.@{fa-css-prefix}-skype:before { content: @fa-var-skype; }\n.@{fa-css-prefix}-foursquare:before { content: @fa-var-foursquare; }\n.@{fa-css-prefix}-trello:before { content: @fa-var-trello; }\n.@{fa-css-prefix}-female:before { content: @fa-var-female; }\n.@{fa-css-prefix}-male:before { content: @fa-var-male; }\n.@{fa-css-prefix}-gittip:before,\n.@{fa-css-prefix}-gratipay:before { content: @fa-var-gratipay; }\n.@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; }\n.@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; }\n.@{fa-css-prefix}-archive:before { content: @fa-var-archive; }\n.@{fa-css-prefix}-bug:before { content: @fa-var-bug; }\n.@{fa-css-prefix}-vk:before { content: @fa-var-vk; }\n.@{fa-css-prefix}-weibo:before { content: @fa-var-weibo; }\n.@{fa-css-prefix}-renren:before { content: @fa-var-renren; }\n.@{fa-css-prefix}-pagelines:before { content: @fa-var-pagelines; }\n.@{fa-css-prefix}-stack-exchange:before { content: @fa-var-stack-exchange; }\n.@{fa-css-prefix}-arrow-circle-o-right:before { content: @fa-var-arrow-circle-o-right; }\n.@{fa-css-prefix}-arrow-circle-o-left:before { content: @fa-var-arrow-circle-o-left; }\n.@{fa-css-prefix}-toggle-left:before,\n.@{fa-css-prefix}-caret-square-o-left:before { content: @fa-var-caret-square-o-left; }\n.@{fa-css-prefix}-dot-circle-o:before { content: @fa-var-dot-circle-o; }\n.@{fa-css-prefix}-wheelchair:before { content: @fa-var-wheelchair; }\n.@{fa-css-prefix}-vimeo-square:before { content: @fa-var-vimeo-square; }\n.@{fa-css-prefix}-turkish-lira:before,\n.@{fa-css-prefix}-try:before { content: @fa-var-try; }\n.@{fa-css-prefix}-plus-square-o:before { content: @fa-var-plus-square-o; }\n.@{fa-css-prefix}-space-shuttle:before { content: @fa-var-space-shuttle; }\n.@{fa-css-prefix}-slack:before { content: @fa-var-slack; }\n.@{fa-css-prefix}-envelope-square:before { content: @fa-var-envelope-square; }\n.@{fa-css-prefix}-wordpress:before { content: @fa-var-wordpress; }\n.@{fa-css-prefix}-openid:before { content: @fa-var-openid; }\n.@{fa-css-prefix}-institution:before,\n.@{fa-css-prefix}-bank:before,\n.@{fa-css-prefix}-university:before { content: @fa-var-university; }\n.@{fa-css-prefix}-mortar-board:before,\n.@{fa-css-prefix}-graduation-cap:before { content: @fa-var-graduation-cap; }\n.@{fa-css-prefix}-yahoo:before { content: @fa-var-yahoo; }\n.@{fa-css-prefix}-google:before { content: @fa-var-google; }\n.@{fa-css-prefix}-reddit:before { content: @fa-var-reddit; }\n.@{fa-css-prefix}-reddit-square:before { content: @fa-var-reddit-square; }\n.@{fa-css-prefix}-stumbleupon-circle:before { content: @fa-var-stumbleupon-circle; }\n.@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; }\n.@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; }\n.@{fa-css-prefix}-digg:before { content: @fa-var-digg; }\n.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; }\n.@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; }\n.@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; }\n.@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; }\n.@{fa-css-prefix}-language:before { content: @fa-var-language; }\n.@{fa-css-prefix}-fax:before { content: @fa-var-fax; }\n.@{fa-css-prefix}-building:before { content: @fa-var-building; }\n.@{fa-css-prefix}-child:before { content: @fa-var-child; }\n.@{fa-css-prefix}-paw:before { content: @fa-var-paw; }\n.@{fa-css-prefix}-spoon:before { content: @fa-var-spoon; }\n.@{fa-css-prefix}-cube:before { content: @fa-var-cube; }\n.@{fa-css-prefix}-cubes:before { content: @fa-var-cubes; }\n.@{fa-css-prefix}-behance:before { content: @fa-var-behance; }\n.@{fa-css-prefix}-behance-square:before { content: @fa-var-behance-square; }\n.@{fa-css-prefix}-steam:before { content: @fa-var-steam; }\n.@{fa-css-prefix}-steam-square:before { content: @fa-var-steam-square; }\n.@{fa-css-prefix}-recycle:before { content: @fa-var-recycle; }\n.@{fa-css-prefix}-automobile:before,\n.@{fa-css-prefix}-car:before { content: @fa-var-car; }\n.@{fa-css-prefix}-cab:before,\n.@{fa-css-prefix}-taxi:before { content: @fa-var-taxi; }\n.@{fa-css-prefix}-tree:before { content: @fa-var-tree; }\n.@{fa-css-prefix}-spotify:before { content: @fa-var-spotify; }\n.@{fa-css-prefix}-deviantart:before { content: @fa-var-deviantart; }\n.@{fa-css-prefix}-soundcloud:before { content: @fa-var-soundcloud; }\n.@{fa-css-prefix}-database:before { content: @fa-var-database; }\n.@{fa-css-prefix}-file-pdf-o:before { content: @fa-var-file-pdf-o; }\n.@{fa-css-prefix}-file-word-o:before { content: @fa-var-file-word-o; }\n.@{fa-css-prefix}-file-excel-o:before { content: @fa-var-file-excel-o; }\n.@{fa-css-prefix}-file-powerpoint-o:before { content: @fa-var-file-powerpoint-o; }\n.@{fa-css-prefix}-file-photo-o:before,\n.@{fa-css-prefix}-file-picture-o:before,\n.@{fa-css-prefix}-file-image-o:before { content: @fa-var-file-image-o; }\n.@{fa-css-prefix}-file-zip-o:before,\n.@{fa-css-prefix}-file-archive-o:before { content: @fa-var-file-archive-o; }\n.@{fa-css-prefix}-file-sound-o:before,\n.@{fa-css-prefix}-file-audio-o:before { content: @fa-var-file-audio-o; }\n.@{fa-css-prefix}-file-movie-o:before,\n.@{fa-css-prefix}-file-video-o:before { content: @fa-var-file-video-o; }\n.@{fa-css-prefix}-file-code-o:before { content: @fa-var-file-code-o; }\n.@{fa-css-prefix}-vine:before { content: @fa-var-vine; }\n.@{fa-css-prefix}-codepen:before { content: @fa-var-codepen; }\n.@{fa-css-prefix}-jsfiddle:before { content: @fa-var-jsfiddle; }\n.@{fa-css-prefix}-life-bouy:before,\n.@{fa-css-prefix}-life-buoy:before,\n.@{fa-css-prefix}-life-saver:before,\n.@{fa-css-prefix}-support:before,\n.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; }\n.@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; }\n.@{fa-css-prefix}-ra:before,\n.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; }\n.@{fa-css-prefix}-ge:before,\n.@{fa-css-prefix}-empire:before { content: @fa-var-empire; }\n.@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; }\n.@{fa-css-prefix}-git:before { content: @fa-var-git; }\n.@{fa-css-prefix}-y-combinator-square:before,\n.@{fa-css-prefix}-yc-square:before,\n.@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; }\n.@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; }\n.@{fa-css-prefix}-qq:before { content: @fa-var-qq; }\n.@{fa-css-prefix}-wechat:before,\n.@{fa-css-prefix}-weixin:before { content: @fa-var-weixin; }\n.@{fa-css-prefix}-send:before,\n.@{fa-css-prefix}-paper-plane:before { content: @fa-var-paper-plane; }\n.@{fa-css-prefix}-send-o:before,\n.@{fa-css-prefix}-paper-plane-o:before { content: @fa-var-paper-plane-o; }\n.@{fa-css-prefix}-history:before { content: @fa-var-history; }\n.@{fa-css-prefix}-circle-thin:before { content: @fa-var-circle-thin; }\n.@{fa-css-prefix}-header:before { content: @fa-var-header; }\n.@{fa-css-prefix}-paragraph:before { content: @fa-var-paragraph; }\n.@{fa-css-prefix}-sliders:before { content: @fa-var-sliders; }\n.@{fa-css-prefix}-share-alt:before { content: @fa-var-share-alt; }\n.@{fa-css-prefix}-share-alt-square:before { content: @fa-var-share-alt-square; }\n.@{fa-css-prefix}-bomb:before { content: @fa-var-bomb; }\n.@{fa-css-prefix}-soccer-ball-o:before,\n.@{fa-css-prefix}-futbol-o:before { content: @fa-var-futbol-o; }\n.@{fa-css-prefix}-tty:before { content: @fa-var-tty; }\n.@{fa-css-prefix}-binoculars:before { content: @fa-var-binoculars; }\n.@{fa-css-prefix}-plug:before { content: @fa-var-plug; }\n.@{fa-css-prefix}-slideshare:before { content: @fa-var-slideshare; }\n.@{fa-css-prefix}-twitch:before { content: @fa-var-twitch; }\n.@{fa-css-prefix}-yelp:before { content: @fa-var-yelp; }\n.@{fa-css-prefix}-newspaper-o:before { content: @fa-var-newspaper-o; }\n.@{fa-css-prefix}-wifi:before { content: @fa-var-wifi; }\n.@{fa-css-prefix}-calculator:before { content: @fa-var-calculator; }\n.@{fa-css-prefix}-paypal:before { content: @fa-var-paypal; }\n.@{fa-css-prefix}-google-wallet:before { content: @fa-var-google-wallet; }\n.@{fa-css-prefix}-cc-visa:before { content: @fa-var-cc-visa; }\n.@{fa-css-prefix}-cc-mastercard:before { content: @fa-var-cc-mastercard; }\n.@{fa-css-prefix}-cc-discover:before { content: @fa-var-cc-discover; }\n.@{fa-css-prefix}-cc-amex:before { content: @fa-var-cc-amex; }\n.@{fa-css-prefix}-cc-paypal:before { content: @fa-var-cc-paypal; }\n.@{fa-css-prefix}-cc-stripe:before { content: @fa-var-cc-stripe; }\n.@{fa-css-prefix}-bell-slash:before { content: @fa-var-bell-slash; }\n.@{fa-css-prefix}-bell-slash-o:before { content: @fa-var-bell-slash-o; }\n.@{fa-css-prefix}-trash:before { content: @fa-var-trash; }\n.@{fa-css-prefix}-copyright:before { content: @fa-var-copyright; }\n.@{fa-css-prefix}-at:before { content: @fa-var-at; }\n.@{fa-css-prefix}-eyedropper:before { content: @fa-var-eyedropper; }\n.@{fa-css-prefix}-paint-brush:before { content: @fa-var-paint-brush; }\n.@{fa-css-prefix}-birthday-cake:before { content: @fa-var-birthday-cake; }\n.@{fa-css-prefix}-area-chart:before { content: @fa-var-area-chart; }\n.@{fa-css-prefix}-pie-chart:before { content: @fa-var-pie-chart; }\n.@{fa-css-prefix}-line-chart:before { content: @fa-var-line-chart; }\n.@{fa-css-prefix}-lastfm:before { content: @fa-var-lastfm; }\n.@{fa-css-prefix}-lastfm-square:before { content: @fa-var-lastfm-square; }\n.@{fa-css-prefix}-toggle-off:before { content: @fa-var-toggle-off; }\n.@{fa-css-prefix}-toggle-on:before { content: @fa-var-toggle-on; }\n.@{fa-css-prefix}-bicycle:before { content: @fa-var-bicycle; }\n.@{fa-css-prefix}-bus:before { content: @fa-var-bus; }\n.@{fa-css-prefix}-ioxhost:before { content: @fa-var-ioxhost; }\n.@{fa-css-prefix}-angellist:before { content: @fa-var-angellist; }\n.@{fa-css-prefix}-cc:before { content: @fa-var-cc; }\n.@{fa-css-prefix}-shekel:before,\n.@{fa-css-prefix}-sheqel:before,\n.@{fa-css-prefix}-ils:before { content: @fa-var-ils; }\n.@{fa-css-prefix}-meanpath:before { content: @fa-var-meanpath; }\n.@{fa-css-prefix}-buysellads:before { content: @fa-var-buysellads; }\n.@{fa-css-prefix}-connectdevelop:before { content: @fa-var-connectdevelop; }\n.@{fa-css-prefix}-dashcube:before { content: @fa-var-dashcube; }\n.@{fa-css-prefix}-forumbee:before { content: @fa-var-forumbee; }\n.@{fa-css-prefix}-leanpub:before { content: @fa-var-leanpub; }\n.@{fa-css-prefix}-sellsy:before { content: @fa-var-sellsy; }\n.@{fa-css-prefix}-shirtsinbulk:before { content: @fa-var-shirtsinbulk; }\n.@{fa-css-prefix}-simplybuilt:before { content: @fa-var-simplybuilt; }\n.@{fa-css-prefix}-skyatlas:before { content: @fa-var-skyatlas; }\n.@{fa-css-prefix}-cart-plus:before { content: @fa-var-cart-plus; }\n.@{fa-css-prefix}-cart-arrow-down:before { content: @fa-var-cart-arrow-down; }\n.@{fa-css-prefix}-diamond:before { content: @fa-var-diamond; }\n.@{fa-css-prefix}-ship:before { content: @fa-var-ship; }\n.@{fa-css-prefix}-user-secret:before { content: @fa-var-user-secret; }\n.@{fa-css-prefix}-motorcycle:before { content: @fa-var-motorcycle; }\n.@{fa-css-prefix}-street-view:before { content: @fa-var-street-view; }\n.@{fa-css-prefix}-heartbeat:before { content: @fa-var-heartbeat; }\n.@{fa-css-prefix}-venus:before { content: @fa-var-venus; }\n.@{fa-css-prefix}-mars:before { content: @fa-var-mars; }\n.@{fa-css-prefix}-mercury:before { content: @fa-var-mercury; }\n.@{fa-css-prefix}-intersex:before,\n.@{fa-css-prefix}-transgender:before { content: @fa-var-transgender; }\n.@{fa-css-prefix}-transgender-alt:before { content: @fa-var-transgender-alt; }\n.@{fa-css-prefix}-venus-double:before { content: @fa-var-venus-double; }\n.@{fa-css-prefix}-mars-double:before { content: @fa-var-mars-double; }\n.@{fa-css-prefix}-venus-mars:before { content: @fa-var-venus-mars; }\n.@{fa-css-prefix}-mars-stroke:before { content: @fa-var-mars-stroke; }\n.@{fa-css-prefix}-mars-stroke-v:before { content: @fa-var-mars-stroke-v; }\n.@{fa-css-prefix}-mars-stroke-h:before { content: @fa-var-mars-stroke-h; }\n.@{fa-css-prefix}-neuter:before { content: @fa-var-neuter; }\n.@{fa-css-prefix}-genderless:before { content: @fa-var-genderless; }\n.@{fa-css-prefix}-facebook-official:before { content: @fa-var-facebook-official; }\n.@{fa-css-prefix}-pinterest-p:before { content: @fa-var-pinterest-p; }\n.@{fa-css-prefix}-whatsapp:before { content: @fa-var-whatsapp; }\n.@{fa-css-prefix}-server:before { content: @fa-var-server; }\n.@{fa-css-prefix}-user-plus:before { content: @fa-var-user-plus; }\n.@{fa-css-prefix}-user-times:before { content: @fa-var-user-times; }\n.@{fa-css-prefix}-hotel:before,\n.@{fa-css-prefix}-bed:before { content: @fa-var-bed; }\n.@{fa-css-prefix}-viacoin:before { content: @fa-var-viacoin; }\n.@{fa-css-prefix}-train:before { content: @fa-var-train; }\n.@{fa-css-prefix}-subway:before { content: @fa-var-subway; }\n.@{fa-css-prefix}-medium:before { content: @fa-var-medium; }\n.@{fa-css-prefix}-yc:before,\n.@{fa-css-prefix}-y-combinator:before { content: @fa-var-y-combinator; }\n.@{fa-css-prefix}-optin-monster:before { content: @fa-var-optin-monster; }\n.@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; }\n.@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; }\n.@{fa-css-prefix}-battery-4:before,\n.@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; }\n.@{fa-css-prefix}-battery-3:before,\n.@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; }\n.@{fa-css-prefix}-battery-2:before,\n.@{fa-css-prefix}-battery-half:before { content: @fa-var-battery-half; }\n.@{fa-css-prefix}-battery-1:before,\n.@{fa-css-prefix}-battery-quarter:before { content: @fa-var-battery-quarter; }\n.@{fa-css-prefix}-battery-0:before,\n.@{fa-css-prefix}-battery-empty:before { content: @fa-var-battery-empty; }\n.@{fa-css-prefix}-mouse-pointer:before { content: @fa-var-mouse-pointer; }\n.@{fa-css-prefix}-i-cursor:before { content: @fa-var-i-cursor; }\n.@{fa-css-prefix}-object-group:before { content: @fa-var-object-group; }\n.@{fa-css-prefix}-object-ungroup:before { content: @fa-var-object-ungroup; }\n.@{fa-css-prefix}-sticky-note:before { content: @fa-var-sticky-note; }\n.@{fa-css-prefix}-sticky-note-o:before { content: @fa-var-sticky-note-o; }\n.@{fa-css-prefix}-cc-jcb:before { content: @fa-var-cc-jcb; }\n.@{fa-css-prefix}-cc-diners-club:before { content: @fa-var-cc-diners-club; }\n.@{fa-css-prefix}-clone:before { content: @fa-var-clone; }\n.@{fa-css-prefix}-balance-scale:before { content: @fa-var-balance-scale; }\n.@{fa-css-prefix}-hourglass-o:before { content: @fa-var-hourglass-o; }\n.@{fa-css-prefix}-hourglass-1:before,\n.@{fa-css-prefix}-hourglass-start:before { content: @fa-var-hourglass-start; }\n.@{fa-css-prefix}-hourglass-2:before,\n.@{fa-css-prefix}-hourglass-half:before { content: @fa-var-hourglass-half; }\n.@{fa-css-prefix}-hourglass-3:before,\n.@{fa-css-prefix}-hourglass-end:before { content: @fa-var-hourglass-end; }\n.@{fa-css-prefix}-hourglass:before { content: @fa-var-hourglass; }\n.@{fa-css-prefix}-hand-grab-o:before,\n.@{fa-css-prefix}-hand-rock-o:before { content: @fa-var-hand-rock-o; }\n.@{fa-css-prefix}-hand-stop-o:before,\n.@{fa-css-prefix}-hand-paper-o:before { content: @fa-var-hand-paper-o; }\n.@{fa-css-prefix}-hand-scissors-o:before { content: @fa-var-hand-scissors-o; }\n.@{fa-css-prefix}-hand-lizard-o:before { content: @fa-var-hand-lizard-o; }\n.@{fa-css-prefix}-hand-spock-o:before { content: @fa-var-hand-spock-o; }\n.@{fa-css-prefix}-hand-pointer-o:before { content: @fa-var-hand-pointer-o; }\n.@{fa-css-prefix}-hand-peace-o:before { content: @fa-var-hand-peace-o; }\n.@{fa-css-prefix}-trademark:before { content: @fa-var-trademark; }\n.@{fa-css-prefix}-registered:before { content: @fa-var-registered; }\n.@{fa-css-prefix}-creative-commons:before { content: @fa-var-creative-commons; }\n.@{fa-css-prefix}-gg:before { content: @fa-var-gg; }\n.@{fa-css-prefix}-gg-circle:before { content: @fa-var-gg-circle; }\n.@{fa-css-prefix}-tripadvisor:before { content: @fa-var-tripadvisor; }\n.@{fa-css-prefix}-odnoklassniki:before { content: @fa-var-odnoklassniki; }\n.@{fa-css-prefix}-odnoklassniki-square:before { content: @fa-var-odnoklassniki-square; }\n.@{fa-css-prefix}-get-pocket:before { content: @fa-var-get-pocket; }\n.@{fa-css-prefix}-wikipedia-w:before { content: @fa-var-wikipedia-w; }\n.@{fa-css-prefix}-safari:before { content: @fa-var-safari; }\n.@{fa-css-prefix}-chrome:before { content: @fa-var-chrome; }\n.@{fa-css-prefix}-firefox:before { content: @fa-var-firefox; }\n.@{fa-css-prefix}-opera:before { content: @fa-var-opera; }\n.@{fa-css-prefix}-internet-explorer:before { content: @fa-var-internet-explorer; }\n.@{fa-css-prefix}-tv:before,\n.@{fa-css-prefix}-television:before { content: @fa-var-television; }\n.@{fa-css-prefix}-contao:before { content: @fa-var-contao; }\n.@{fa-css-prefix}-500px:before { content: @fa-var-500px; }\n.@{fa-css-prefix}-amazon:before { content: @fa-var-amazon; }\n.@{fa-css-prefix}-calendar-plus-o:before { content: @fa-var-calendar-plus-o; }\n.@{fa-css-prefix}-calendar-minus-o:before { content: @fa-var-calendar-minus-o; }\n.@{fa-css-prefix}-calendar-times-o:before { content: @fa-var-calendar-times-o; }\n.@{fa-css-prefix}-calendar-check-o:before { content: @fa-var-calendar-check-o; }\n.@{fa-css-prefix}-industry:before { content: @fa-var-industry; }\n.@{fa-css-prefix}-map-pin:before { content: @fa-var-map-pin; }\n.@{fa-css-prefix}-map-signs:before { content: @fa-var-map-signs; }\n.@{fa-css-prefix}-map-o:before { content: @fa-var-map-o; }\n.@{fa-css-prefix}-map:before { content: @fa-var-map; }\n.@{fa-css-prefix}-commenting:before { content: @fa-var-commenting; }\n.@{fa-css-prefix}-commenting-o:before { content: @fa-var-commenting-o; }\n.@{fa-css-prefix}-houzz:before { content: @fa-var-houzz; }\n.@{fa-css-prefix}-vimeo:before { content: @fa-var-vimeo; }\n.@{fa-css-prefix}-black-tie:before { content: @fa-var-black-tie; }\n.@{fa-css-prefix}-fonticons:before { content: @fa-var-fonticons; }\n.@{fa-css-prefix}-reddit-alien:before { content: @fa-var-reddit-alien; }\n.@{fa-css-prefix}-edge:before { content: @fa-var-edge; }\n.@{fa-css-prefix}-credit-card-alt:before { content: @fa-var-credit-card-alt; }\n.@{fa-css-prefix}-codiepie:before { content: @fa-var-codiepie; }\n.@{fa-css-prefix}-modx:before { content: @fa-var-modx; }\n.@{fa-css-prefix}-fort-awesome:before { content: @fa-var-fort-awesome; }\n.@{fa-css-prefix}-usb:before { content: @fa-var-usb; }\n.@{fa-css-prefix}-product-hunt:before { content: @fa-var-product-hunt; }\n.@{fa-css-prefix}-mixcloud:before { content: @fa-var-mixcloud; }\n.@{fa-css-prefix}-scribd:before { content: @fa-var-scribd; }\n.@{fa-css-prefix}-pause-circle:before { content: @fa-var-pause-circle; }\n.@{fa-css-prefix}-pause-circle-o:before { content: @fa-var-pause-circle-o; }\n.@{fa-css-prefix}-stop-circle:before { content: @fa-var-stop-circle; }\n.@{fa-css-prefix}-stop-circle-o:before { content: @fa-var-stop-circle-o; }\n.@{fa-css-prefix}-shopping-bag:before { content: @fa-var-shopping-bag; }\n.@{fa-css-prefix}-shopping-basket:before { content: @fa-var-shopping-basket; }\n.@{fa-css-prefix}-hashtag:before { content: @fa-var-hashtag; }\n.@{fa-css-prefix}-bluetooth:before { content: @fa-var-bluetooth; }\n.@{fa-css-prefix}-bluetooth-b:before { content: @fa-var-bluetooth-b; }\n.@{fa-css-prefix}-percent:before { content: @fa-var-percent; }\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/larger.less",
    "content": "// Icon Sizes\n// -------------------------\n\n/* makes the font 33% larger relative to the icon container */\n.@{fa-css-prefix}-lg {\n  font-size: (4em / 3);\n  line-height: (3em / 4);\n  vertical-align: -15%;\n}\n.@{fa-css-prefix}-2x { font-size: 2em; }\n.@{fa-css-prefix}-3x { font-size: 3em; }\n.@{fa-css-prefix}-4x { font-size: 4em; }\n.@{fa-css-prefix}-5x { font-size: 5em; }\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/list.less",
    "content": "// List Icons\n// -------------------------\n\n.@{fa-css-prefix}-ul {\n  padding-left: 0;\n  margin-left: @fa-li-width;\n  list-style-type: none;\n  > li { position: relative; }\n}\n.@{fa-css-prefix}-li {\n  position: absolute;\n  left: -@fa-li-width;\n  width: @fa-li-width;\n  top: (2em / 14);\n  text-align: center;\n  &.@{fa-css-prefix}-lg {\n    left: (-@fa-li-width + (4em / 14));\n  }\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/mixins.less",
    "content": "// Mixins\n// --------------------------\n\n.fa-icon() {\n  display: inline-block;\n  font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration\n  font-size: inherit; // can't have font-size inherit on line above, so need to override\n  text-rendering: auto; // optimizelegibility throws things off #1094\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n\n}\n\n.fa-icon-rotate(@degrees, @rotation) {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation);\n  -webkit-transform: rotate(@degrees);\n      -ms-transform: rotate(@degrees);\n          transform: rotate(@degrees);\n}\n\n.fa-icon-flip(@horiz, @vert, @rotation) {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1);\n  -webkit-transform: scale(@horiz, @vert);\n      -ms-transform: scale(@horiz, @vert);\n          transform: scale(@horiz, @vert);\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/path.less",
    "content": "/* FONT PATH\n * -------------------------- */\n\n@font-face {\n  font-family: 'FontAwesome';\n  src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');\n  src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),\n    url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),\n    url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),\n    url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),\n    url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');\n//  src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts\n  font-weight: normal;\n  font-style: normal;\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/rotated-flipped.less",
    "content": "// Rotated & Flipped Icons\n// -------------------------\n\n.@{fa-css-prefix}-rotate-90  { .fa-icon-rotate(90deg, 1);  }\n.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }\n.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }\n\n.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }\n.@{fa-css-prefix}-flip-vertical   { .fa-icon-flip(1, -1, 2); }\n\n// Hook for IE8-9\n// -------------------------\n\n:root .@{fa-css-prefix}-rotate-90,\n:root .@{fa-css-prefix}-rotate-180,\n:root .@{fa-css-prefix}-rotate-270,\n:root .@{fa-css-prefix}-flip-horizontal,\n:root .@{fa-css-prefix}-flip-vertical {\n  filter: none;\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/stacked.less",
    "content": "// Stacked Icons\n// -------------------------\n\n.@{fa-css-prefix}-stack {\n  position: relative;\n  display: inline-block;\n  width: 2em;\n  height: 2em;\n  line-height: 2em;\n  vertical-align: middle;\n}\n.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {\n  position: absolute;\n  left: 0;\n  width: 100%;\n  text-align: center;\n}\n.@{fa-css-prefix}-stack-1x { line-height: inherit; }\n.@{fa-css-prefix}-stack-2x { font-size: 2em; }\n.@{fa-css-prefix}-inverse { color: @fa-inverse; }\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/less/variables.less",
    "content": "// Variables\n// --------------------------\n\n@fa-font-path:        \"../fonts\";\n@fa-font-size-base:   14px;\n@fa-line-height-base: 1;\n//@fa-font-path:        \"//netdna.bootstrapcdn.com/font-awesome/4.5.0/fonts\"; // for referencing Bootstrap CDN font files directly\n@fa-css-prefix:       fa;\n@fa-version:          \"4.5.0\";\n@fa-border-color:     #eee;\n@fa-inverse:          #fff;\n@fa-li-width:         (30em / 14);\n\n@fa-var-500px: \"\\f26e\";\n@fa-var-adjust: \"\\f042\";\n@fa-var-adn: \"\\f170\";\n@fa-var-align-center: \"\\f037\";\n@fa-var-align-justify: \"\\f039\";\n@fa-var-align-left: \"\\f036\";\n@fa-var-align-right: \"\\f038\";\n@fa-var-amazon: \"\\f270\";\n@fa-var-ambulance: \"\\f0f9\";\n@fa-var-anchor: \"\\f13d\";\n@fa-var-android: \"\\f17b\";\n@fa-var-angellist: \"\\f209\";\n@fa-var-angle-double-down: \"\\f103\";\n@fa-var-angle-double-left: \"\\f100\";\n@fa-var-angle-double-right: \"\\f101\";\n@fa-var-angle-double-up: \"\\f102\";\n@fa-var-angle-down: \"\\f107\";\n@fa-var-angle-left: \"\\f104\";\n@fa-var-angle-right: \"\\f105\";\n@fa-var-angle-up: \"\\f106\";\n@fa-var-apple: \"\\f179\";\n@fa-var-archive: \"\\f187\";\n@fa-var-area-chart: \"\\f1fe\";\n@fa-var-arrow-circle-down: \"\\f0ab\";\n@fa-var-arrow-circle-left: \"\\f0a8\";\n@fa-var-arrow-circle-o-down: \"\\f01a\";\n@fa-var-arrow-circle-o-left: \"\\f190\";\n@fa-var-arrow-circle-o-right: \"\\f18e\";\n@fa-var-arrow-circle-o-up: \"\\f01b\";\n@fa-var-arrow-circle-right: \"\\f0a9\";\n@fa-var-arrow-circle-up: \"\\f0aa\";\n@fa-var-arrow-down: \"\\f063\";\n@fa-var-arrow-left: \"\\f060\";\n@fa-var-arrow-right: \"\\f061\";\n@fa-var-arrow-up: \"\\f062\";\n@fa-var-arrows: \"\\f047\";\n@fa-var-arrows-alt: \"\\f0b2\";\n@fa-var-arrows-h: \"\\f07e\";\n@fa-var-arrows-v: \"\\f07d\";\n@fa-var-asterisk: \"\\f069\";\n@fa-var-at: \"\\f1fa\";\n@fa-var-automobile: \"\\f1b9\";\n@fa-var-backward: \"\\f04a\";\n@fa-var-balance-scale: \"\\f24e\";\n@fa-var-ban: \"\\f05e\";\n@fa-var-bank: \"\\f19c\";\n@fa-var-bar-chart: \"\\f080\";\n@fa-var-bar-chart-o: \"\\f080\";\n@fa-var-barcode: \"\\f02a\";\n@fa-var-bars: \"\\f0c9\";\n@fa-var-battery-0: \"\\f244\";\n@fa-var-battery-1: \"\\f243\";\n@fa-var-battery-2: \"\\f242\";\n@fa-var-battery-3: \"\\f241\";\n@fa-var-battery-4: \"\\f240\";\n@fa-var-battery-empty: \"\\f244\";\n@fa-var-battery-full: \"\\f240\";\n@fa-var-battery-half: \"\\f242\";\n@fa-var-battery-quarter: \"\\f243\";\n@fa-var-battery-three-quarters: \"\\f241\";\n@fa-var-bed: \"\\f236\";\n@fa-var-beer: \"\\f0fc\";\n@fa-var-behance: \"\\f1b4\";\n@fa-var-behance-square: \"\\f1b5\";\n@fa-var-bell: \"\\f0f3\";\n@fa-var-bell-o: \"\\f0a2\";\n@fa-var-bell-slash: \"\\f1f6\";\n@fa-var-bell-slash-o: \"\\f1f7\";\n@fa-var-bicycle: \"\\f206\";\n@fa-var-binoculars: \"\\f1e5\";\n@fa-var-birthday-cake: \"\\f1fd\";\n@fa-var-bitbucket: \"\\f171\";\n@fa-var-bitbucket-square: \"\\f172\";\n@fa-var-bitcoin: \"\\f15a\";\n@fa-var-black-tie: \"\\f27e\";\n@fa-var-bluetooth: \"\\f293\";\n@fa-var-bluetooth-b: \"\\f294\";\n@fa-var-bold: \"\\f032\";\n@fa-var-bolt: \"\\f0e7\";\n@fa-var-bomb: \"\\f1e2\";\n@fa-var-book: \"\\f02d\";\n@fa-var-bookmark: \"\\f02e\";\n@fa-var-bookmark-o: \"\\f097\";\n@fa-var-briefcase: \"\\f0b1\";\n@fa-var-btc: \"\\f15a\";\n@fa-var-bug: \"\\f188\";\n@fa-var-building: \"\\f1ad\";\n@fa-var-building-o: \"\\f0f7\";\n@fa-var-bullhorn: \"\\f0a1\";\n@fa-var-bullseye: \"\\f140\";\n@fa-var-bus: \"\\f207\";\n@fa-var-buysellads: \"\\f20d\";\n@fa-var-cab: \"\\f1ba\";\n@fa-var-calculator: \"\\f1ec\";\n@fa-var-calendar: \"\\f073\";\n@fa-var-calendar-check-o: \"\\f274\";\n@fa-var-calendar-minus-o: \"\\f272\";\n@fa-var-calendar-o: \"\\f133\";\n@fa-var-calendar-plus-o: \"\\f271\";\n@fa-var-calendar-times-o: \"\\f273\";\n@fa-var-camera: \"\\f030\";\n@fa-var-camera-retro: \"\\f083\";\n@fa-var-car: \"\\f1b9\";\n@fa-var-caret-down: \"\\f0d7\";\n@fa-var-caret-left: \"\\f0d9\";\n@fa-var-caret-right: \"\\f0da\";\n@fa-var-caret-square-o-down: \"\\f150\";\n@fa-var-caret-square-o-left: \"\\f191\";\n@fa-var-caret-square-o-right: \"\\f152\";\n@fa-var-caret-square-o-up: \"\\f151\";\n@fa-var-caret-up: \"\\f0d8\";\n@fa-var-cart-arrow-down: \"\\f218\";\n@fa-var-cart-plus: \"\\f217\";\n@fa-var-cc: \"\\f20a\";\n@fa-var-cc-amex: \"\\f1f3\";\n@fa-var-cc-diners-club: \"\\f24c\";\n@fa-var-cc-discover: \"\\f1f2\";\n@fa-var-cc-jcb: \"\\f24b\";\n@fa-var-cc-mastercard: \"\\f1f1\";\n@fa-var-cc-paypal: \"\\f1f4\";\n@fa-var-cc-stripe: \"\\f1f5\";\n@fa-var-cc-visa: \"\\f1f0\";\n@fa-var-certificate: \"\\f0a3\";\n@fa-var-chain: \"\\f0c1\";\n@fa-var-chain-broken: \"\\f127\";\n@fa-var-check: \"\\f00c\";\n@fa-var-check-circle: \"\\f058\";\n@fa-var-check-circle-o: \"\\f05d\";\n@fa-var-check-square: \"\\f14a\";\n@fa-var-check-square-o: \"\\f046\";\n@fa-var-chevron-circle-down: \"\\f13a\";\n@fa-var-chevron-circle-left: \"\\f137\";\n@fa-var-chevron-circle-right: \"\\f138\";\n@fa-var-chevron-circle-up: \"\\f139\";\n@fa-var-chevron-down: \"\\f078\";\n@fa-var-chevron-left: \"\\f053\";\n@fa-var-chevron-right: \"\\f054\";\n@fa-var-chevron-up: \"\\f077\";\n@fa-var-child: \"\\f1ae\";\n@fa-var-chrome: \"\\f268\";\n@fa-var-circle: \"\\f111\";\n@fa-var-circle-o: \"\\f10c\";\n@fa-var-circle-o-notch: \"\\f1ce\";\n@fa-var-circle-thin: \"\\f1db\";\n@fa-var-clipboard: \"\\f0ea\";\n@fa-var-clock-o: \"\\f017\";\n@fa-var-clone: \"\\f24d\";\n@fa-var-close: \"\\f00d\";\n@fa-var-cloud: \"\\f0c2\";\n@fa-var-cloud-download: \"\\f0ed\";\n@fa-var-cloud-upload: \"\\f0ee\";\n@fa-var-cny: \"\\f157\";\n@fa-var-code: \"\\f121\";\n@fa-var-code-fork: \"\\f126\";\n@fa-var-codepen: \"\\f1cb\";\n@fa-var-codiepie: \"\\f284\";\n@fa-var-coffee: \"\\f0f4\";\n@fa-var-cog: \"\\f013\";\n@fa-var-cogs: \"\\f085\";\n@fa-var-columns: \"\\f0db\";\n@fa-var-comment: \"\\f075\";\n@fa-var-comment-o: \"\\f0e5\";\n@fa-var-commenting: \"\\f27a\";\n@fa-var-commenting-o: \"\\f27b\";\n@fa-var-comments: \"\\f086\";\n@fa-var-comments-o: \"\\f0e6\";\n@fa-var-compass: \"\\f14e\";\n@fa-var-compress: \"\\f066\";\n@fa-var-connectdevelop: \"\\f20e\";\n@fa-var-contao: \"\\f26d\";\n@fa-var-copy: \"\\f0c5\";\n@fa-var-copyright: \"\\f1f9\";\n@fa-var-creative-commons: \"\\f25e\";\n@fa-var-credit-card: \"\\f09d\";\n@fa-var-credit-card-alt: \"\\f283\";\n@fa-var-crop: \"\\f125\";\n@fa-var-crosshairs: \"\\f05b\";\n@fa-var-css3: \"\\f13c\";\n@fa-var-cube: \"\\f1b2\";\n@fa-var-cubes: \"\\f1b3\";\n@fa-var-cut: \"\\f0c4\";\n@fa-var-cutlery: \"\\f0f5\";\n@fa-var-dashboard: \"\\f0e4\";\n@fa-var-dashcube: \"\\f210\";\n@fa-var-database: \"\\f1c0\";\n@fa-var-dedent: \"\\f03b\";\n@fa-var-delicious: \"\\f1a5\";\n@fa-var-desktop: \"\\f108\";\n@fa-var-deviantart: \"\\f1bd\";\n@fa-var-diamond: \"\\f219\";\n@fa-var-digg: \"\\f1a6\";\n@fa-var-dollar: \"\\f155\";\n@fa-var-dot-circle-o: \"\\f192\";\n@fa-var-download: \"\\f019\";\n@fa-var-dribbble: \"\\f17d\";\n@fa-var-dropbox: \"\\f16b\";\n@fa-var-drupal: \"\\f1a9\";\n@fa-var-edge: \"\\f282\";\n@fa-var-edit: \"\\f044\";\n@fa-var-eject: \"\\f052\";\n@fa-var-ellipsis-h: \"\\f141\";\n@fa-var-ellipsis-v: \"\\f142\";\n@fa-var-empire: \"\\f1d1\";\n@fa-var-envelope: \"\\f0e0\";\n@fa-var-envelope-o: \"\\f003\";\n@fa-var-envelope-square: \"\\f199\";\n@fa-var-eraser: \"\\f12d\";\n@fa-var-eur: \"\\f153\";\n@fa-var-euro: \"\\f153\";\n@fa-var-exchange: \"\\f0ec\";\n@fa-var-exclamation: \"\\f12a\";\n@fa-var-exclamation-circle: \"\\f06a\";\n@fa-var-exclamation-triangle: \"\\f071\";\n@fa-var-expand: \"\\f065\";\n@fa-var-expeditedssl: \"\\f23e\";\n@fa-var-external-link: \"\\f08e\";\n@fa-var-external-link-square: \"\\f14c\";\n@fa-var-eye: \"\\f06e\";\n@fa-var-eye-slash: \"\\f070\";\n@fa-var-eyedropper: \"\\f1fb\";\n@fa-var-facebook: \"\\f09a\";\n@fa-var-facebook-f: \"\\f09a\";\n@fa-var-facebook-official: \"\\f230\";\n@fa-var-facebook-square: \"\\f082\";\n@fa-var-fast-backward: \"\\f049\";\n@fa-var-fast-forward: \"\\f050\";\n@fa-var-fax: \"\\f1ac\";\n@fa-var-feed: \"\\f09e\";\n@fa-var-female: \"\\f182\";\n@fa-var-fighter-jet: \"\\f0fb\";\n@fa-var-file: \"\\f15b\";\n@fa-var-file-archive-o: \"\\f1c6\";\n@fa-var-file-audio-o: \"\\f1c7\";\n@fa-var-file-code-o: \"\\f1c9\";\n@fa-var-file-excel-o: \"\\f1c3\";\n@fa-var-file-image-o: \"\\f1c5\";\n@fa-var-file-movie-o: \"\\f1c8\";\n@fa-var-file-o: \"\\f016\";\n@fa-var-file-pdf-o: \"\\f1c1\";\n@fa-var-file-photo-o: \"\\f1c5\";\n@fa-var-file-picture-o: \"\\f1c5\";\n@fa-var-file-powerpoint-o: \"\\f1c4\";\n@fa-var-file-sound-o: \"\\f1c7\";\n@fa-var-file-text: \"\\f15c\";\n@fa-var-file-text-o: \"\\f0f6\";\n@fa-var-file-video-o: \"\\f1c8\";\n@fa-var-file-word-o: \"\\f1c2\";\n@fa-var-file-zip-o: \"\\f1c6\";\n@fa-var-files-o: \"\\f0c5\";\n@fa-var-film: \"\\f008\";\n@fa-var-filter: \"\\f0b0\";\n@fa-var-fire: \"\\f06d\";\n@fa-var-fire-extinguisher: \"\\f134\";\n@fa-var-firefox: \"\\f269\";\n@fa-var-flag: \"\\f024\";\n@fa-var-flag-checkered: \"\\f11e\";\n@fa-var-flag-o: \"\\f11d\";\n@fa-var-flash: \"\\f0e7\";\n@fa-var-flask: \"\\f0c3\";\n@fa-var-flickr: \"\\f16e\";\n@fa-var-floppy-o: \"\\f0c7\";\n@fa-var-folder: \"\\f07b\";\n@fa-var-folder-o: \"\\f114\";\n@fa-var-folder-open: \"\\f07c\";\n@fa-var-folder-open-o: \"\\f115\";\n@fa-var-font: \"\\f031\";\n@fa-var-fonticons: \"\\f280\";\n@fa-var-fort-awesome: \"\\f286\";\n@fa-var-forumbee: \"\\f211\";\n@fa-var-forward: \"\\f04e\";\n@fa-var-foursquare: \"\\f180\";\n@fa-var-frown-o: \"\\f119\";\n@fa-var-futbol-o: \"\\f1e3\";\n@fa-var-gamepad: \"\\f11b\";\n@fa-var-gavel: \"\\f0e3\";\n@fa-var-gbp: \"\\f154\";\n@fa-var-ge: \"\\f1d1\";\n@fa-var-gear: \"\\f013\";\n@fa-var-gears: \"\\f085\";\n@fa-var-genderless: \"\\f22d\";\n@fa-var-get-pocket: \"\\f265\";\n@fa-var-gg: \"\\f260\";\n@fa-var-gg-circle: \"\\f261\";\n@fa-var-gift: \"\\f06b\";\n@fa-var-git: \"\\f1d3\";\n@fa-var-git-square: \"\\f1d2\";\n@fa-var-github: \"\\f09b\";\n@fa-var-github-alt: \"\\f113\";\n@fa-var-github-square: \"\\f092\";\n@fa-var-gittip: \"\\f184\";\n@fa-var-glass: \"\\f000\";\n@fa-var-globe: \"\\f0ac\";\n@fa-var-google: \"\\f1a0\";\n@fa-var-google-plus: \"\\f0d5\";\n@fa-var-google-plus-square: \"\\f0d4\";\n@fa-var-google-wallet: \"\\f1ee\";\n@fa-var-graduation-cap: \"\\f19d\";\n@fa-var-gratipay: \"\\f184\";\n@fa-var-group: \"\\f0c0\";\n@fa-var-h-square: \"\\f0fd\";\n@fa-var-hacker-news: \"\\f1d4\";\n@fa-var-hand-grab-o: \"\\f255\";\n@fa-var-hand-lizard-o: \"\\f258\";\n@fa-var-hand-o-down: \"\\f0a7\";\n@fa-var-hand-o-left: \"\\f0a5\";\n@fa-var-hand-o-right: \"\\f0a4\";\n@fa-var-hand-o-up: \"\\f0a6\";\n@fa-var-hand-paper-o: \"\\f256\";\n@fa-var-hand-peace-o: \"\\f25b\";\n@fa-var-hand-pointer-o: \"\\f25a\";\n@fa-var-hand-rock-o: \"\\f255\";\n@fa-var-hand-scissors-o: \"\\f257\";\n@fa-var-hand-spock-o: \"\\f259\";\n@fa-var-hand-stop-o: \"\\f256\";\n@fa-var-hashtag: \"\\f292\";\n@fa-var-hdd-o: \"\\f0a0\";\n@fa-var-header: \"\\f1dc\";\n@fa-var-headphones: \"\\f025\";\n@fa-var-heart: \"\\f004\";\n@fa-var-heart-o: \"\\f08a\";\n@fa-var-heartbeat: \"\\f21e\";\n@fa-var-history: \"\\f1da\";\n@fa-var-home: \"\\f015\";\n@fa-var-hospital-o: \"\\f0f8\";\n@fa-var-hotel: \"\\f236\";\n@fa-var-hourglass: \"\\f254\";\n@fa-var-hourglass-1: \"\\f251\";\n@fa-var-hourglass-2: \"\\f252\";\n@fa-var-hourglass-3: \"\\f253\";\n@fa-var-hourglass-end: \"\\f253\";\n@fa-var-hourglass-half: \"\\f252\";\n@fa-var-hourglass-o: \"\\f250\";\n@fa-var-hourglass-start: \"\\f251\";\n@fa-var-houzz: \"\\f27c\";\n@fa-var-html5: \"\\f13b\";\n@fa-var-i-cursor: \"\\f246\";\n@fa-var-ils: \"\\f20b\";\n@fa-var-image: \"\\f03e\";\n@fa-var-inbox: \"\\f01c\";\n@fa-var-indent: \"\\f03c\";\n@fa-var-industry: \"\\f275\";\n@fa-var-info: \"\\f129\";\n@fa-var-info-circle: \"\\f05a\";\n@fa-var-inr: \"\\f156\";\n@fa-var-instagram: \"\\f16d\";\n@fa-var-institution: \"\\f19c\";\n@fa-var-internet-explorer: \"\\f26b\";\n@fa-var-intersex: \"\\f224\";\n@fa-var-ioxhost: \"\\f208\";\n@fa-var-italic: \"\\f033\";\n@fa-var-joomla: \"\\f1aa\";\n@fa-var-jpy: \"\\f157\";\n@fa-var-jsfiddle: \"\\f1cc\";\n@fa-var-key: \"\\f084\";\n@fa-var-keyboard-o: \"\\f11c\";\n@fa-var-krw: \"\\f159\";\n@fa-var-language: \"\\f1ab\";\n@fa-var-laptop: \"\\f109\";\n@fa-var-lastfm: \"\\f202\";\n@fa-var-lastfm-square: \"\\f203\";\n@fa-var-leaf: \"\\f06c\";\n@fa-var-leanpub: \"\\f212\";\n@fa-var-legal: \"\\f0e3\";\n@fa-var-lemon-o: \"\\f094\";\n@fa-var-level-down: \"\\f149\";\n@fa-var-level-up: \"\\f148\";\n@fa-var-life-bouy: \"\\f1cd\";\n@fa-var-life-buoy: \"\\f1cd\";\n@fa-var-life-ring: \"\\f1cd\";\n@fa-var-life-saver: \"\\f1cd\";\n@fa-var-lightbulb-o: \"\\f0eb\";\n@fa-var-line-chart: \"\\f201\";\n@fa-var-link: \"\\f0c1\";\n@fa-var-linkedin: \"\\f0e1\";\n@fa-var-linkedin-square: \"\\f08c\";\n@fa-var-linux: \"\\f17c\";\n@fa-var-list: \"\\f03a\";\n@fa-var-list-alt: \"\\f022\";\n@fa-var-list-ol: \"\\f0cb\";\n@fa-var-list-ul: \"\\f0ca\";\n@fa-var-location-arrow: \"\\f124\";\n@fa-var-lock: \"\\f023\";\n@fa-var-long-arrow-down: \"\\f175\";\n@fa-var-long-arrow-left: \"\\f177\";\n@fa-var-long-arrow-right: \"\\f178\";\n@fa-var-long-arrow-up: \"\\f176\";\n@fa-var-magic: \"\\f0d0\";\n@fa-var-magnet: \"\\f076\";\n@fa-var-mail-forward: \"\\f064\";\n@fa-var-mail-reply: \"\\f112\";\n@fa-var-mail-reply-all: \"\\f122\";\n@fa-var-male: \"\\f183\";\n@fa-var-map: \"\\f279\";\n@fa-var-map-marker: \"\\f041\";\n@fa-var-map-o: \"\\f278\";\n@fa-var-map-pin: \"\\f276\";\n@fa-var-map-signs: \"\\f277\";\n@fa-var-mars: \"\\f222\";\n@fa-var-mars-double: \"\\f227\";\n@fa-var-mars-stroke: \"\\f229\";\n@fa-var-mars-stroke-h: \"\\f22b\";\n@fa-var-mars-stroke-v: \"\\f22a\";\n@fa-var-maxcdn: \"\\f136\";\n@fa-var-meanpath: \"\\f20c\";\n@fa-var-medium: \"\\f23a\";\n@fa-var-medkit: \"\\f0fa\";\n@fa-var-meh-o: \"\\f11a\";\n@fa-var-mercury: \"\\f223\";\n@fa-var-microphone: \"\\f130\";\n@fa-var-microphone-slash: \"\\f131\";\n@fa-var-minus: \"\\f068\";\n@fa-var-minus-circle: \"\\f056\";\n@fa-var-minus-square: \"\\f146\";\n@fa-var-minus-square-o: \"\\f147\";\n@fa-var-mixcloud: \"\\f289\";\n@fa-var-mobile: \"\\f10b\";\n@fa-var-mobile-phone: \"\\f10b\";\n@fa-var-modx: \"\\f285\";\n@fa-var-money: \"\\f0d6\";\n@fa-var-moon-o: \"\\f186\";\n@fa-var-mortar-board: \"\\f19d\";\n@fa-var-motorcycle: \"\\f21c\";\n@fa-var-mouse-pointer: \"\\f245\";\n@fa-var-music: \"\\f001\";\n@fa-var-navicon: \"\\f0c9\";\n@fa-var-neuter: \"\\f22c\";\n@fa-var-newspaper-o: \"\\f1ea\";\n@fa-var-object-group: \"\\f247\";\n@fa-var-object-ungroup: \"\\f248\";\n@fa-var-odnoklassniki: \"\\f263\";\n@fa-var-odnoklassniki-square: \"\\f264\";\n@fa-var-opencart: \"\\f23d\";\n@fa-var-openid: \"\\f19b\";\n@fa-var-opera: \"\\f26a\";\n@fa-var-optin-monster: \"\\f23c\";\n@fa-var-outdent: \"\\f03b\";\n@fa-var-pagelines: \"\\f18c\";\n@fa-var-paint-brush: \"\\f1fc\";\n@fa-var-paper-plane: \"\\f1d8\";\n@fa-var-paper-plane-o: \"\\f1d9\";\n@fa-var-paperclip: \"\\f0c6\";\n@fa-var-paragraph: \"\\f1dd\";\n@fa-var-paste: \"\\f0ea\";\n@fa-var-pause: \"\\f04c\";\n@fa-var-pause-circle: \"\\f28b\";\n@fa-var-pause-circle-o: \"\\f28c\";\n@fa-var-paw: \"\\f1b0\";\n@fa-var-paypal: \"\\f1ed\";\n@fa-var-pencil: \"\\f040\";\n@fa-var-pencil-square: \"\\f14b\";\n@fa-var-pencil-square-o: \"\\f044\";\n@fa-var-percent: \"\\f295\";\n@fa-var-phone: \"\\f095\";\n@fa-var-phone-square: \"\\f098\";\n@fa-var-photo: \"\\f03e\";\n@fa-var-picture-o: \"\\f03e\";\n@fa-var-pie-chart: \"\\f200\";\n@fa-var-pied-piper: \"\\f1a7\";\n@fa-var-pied-piper-alt: \"\\f1a8\";\n@fa-var-pinterest: \"\\f0d2\";\n@fa-var-pinterest-p: \"\\f231\";\n@fa-var-pinterest-square: \"\\f0d3\";\n@fa-var-plane: \"\\f072\";\n@fa-var-play: \"\\f04b\";\n@fa-var-play-circle: \"\\f144\";\n@fa-var-play-circle-o: \"\\f01d\";\n@fa-var-plug: \"\\f1e6\";\n@fa-var-plus: \"\\f067\";\n@fa-var-plus-circle: \"\\f055\";\n@fa-var-plus-square: \"\\f0fe\";\n@fa-var-plus-square-o: \"\\f196\";\n@fa-var-power-off: \"\\f011\";\n@fa-var-print: \"\\f02f\";\n@fa-var-product-hunt: \"\\f288\";\n@fa-var-puzzle-piece: \"\\f12e\";\n@fa-var-qq: \"\\f1d6\";\n@fa-var-qrcode: \"\\f029\";\n@fa-var-question: \"\\f128\";\n@fa-var-question-circle: \"\\f059\";\n@fa-var-quote-left: \"\\f10d\";\n@fa-var-quote-right: \"\\f10e\";\n@fa-var-ra: \"\\f1d0\";\n@fa-var-random: \"\\f074\";\n@fa-var-rebel: \"\\f1d0\";\n@fa-var-recycle: \"\\f1b8\";\n@fa-var-reddit: \"\\f1a1\";\n@fa-var-reddit-alien: \"\\f281\";\n@fa-var-reddit-square: \"\\f1a2\";\n@fa-var-refresh: \"\\f021\";\n@fa-var-registered: \"\\f25d\";\n@fa-var-remove: \"\\f00d\";\n@fa-var-renren: \"\\f18b\";\n@fa-var-reorder: \"\\f0c9\";\n@fa-var-repeat: \"\\f01e\";\n@fa-var-reply: \"\\f112\";\n@fa-var-reply-all: \"\\f122\";\n@fa-var-retweet: \"\\f079\";\n@fa-var-rmb: \"\\f157\";\n@fa-var-road: \"\\f018\";\n@fa-var-rocket: \"\\f135\";\n@fa-var-rotate-left: \"\\f0e2\";\n@fa-var-rotate-right: \"\\f01e\";\n@fa-var-rouble: \"\\f158\";\n@fa-var-rss: \"\\f09e\";\n@fa-var-rss-square: \"\\f143\";\n@fa-var-rub: \"\\f158\";\n@fa-var-ruble: \"\\f158\";\n@fa-var-rupee: \"\\f156\";\n@fa-var-safari: \"\\f267\";\n@fa-var-save: \"\\f0c7\";\n@fa-var-scissors: \"\\f0c4\";\n@fa-var-scribd: \"\\f28a\";\n@fa-var-search: \"\\f002\";\n@fa-var-search-minus: \"\\f010\";\n@fa-var-search-plus: \"\\f00e\";\n@fa-var-sellsy: \"\\f213\";\n@fa-var-send: \"\\f1d8\";\n@fa-var-send-o: \"\\f1d9\";\n@fa-var-server: \"\\f233\";\n@fa-var-share: \"\\f064\";\n@fa-var-share-alt: \"\\f1e0\";\n@fa-var-share-alt-square: \"\\f1e1\";\n@fa-var-share-square: \"\\f14d\";\n@fa-var-share-square-o: \"\\f045\";\n@fa-var-shekel: \"\\f20b\";\n@fa-var-sheqel: \"\\f20b\";\n@fa-var-shield: \"\\f132\";\n@fa-var-ship: \"\\f21a\";\n@fa-var-shirtsinbulk: \"\\f214\";\n@fa-var-shopping-bag: \"\\f290\";\n@fa-var-shopping-basket: \"\\f291\";\n@fa-var-shopping-cart: \"\\f07a\";\n@fa-var-sign-in: \"\\f090\";\n@fa-var-sign-out: \"\\f08b\";\n@fa-var-signal: \"\\f012\";\n@fa-var-simplybuilt: \"\\f215\";\n@fa-var-sitemap: \"\\f0e8\";\n@fa-var-skyatlas: \"\\f216\";\n@fa-var-skype: \"\\f17e\";\n@fa-var-slack: \"\\f198\";\n@fa-var-sliders: \"\\f1de\";\n@fa-var-slideshare: \"\\f1e7\";\n@fa-var-smile-o: \"\\f118\";\n@fa-var-soccer-ball-o: \"\\f1e3\";\n@fa-var-sort: \"\\f0dc\";\n@fa-var-sort-alpha-asc: \"\\f15d\";\n@fa-var-sort-alpha-desc: \"\\f15e\";\n@fa-var-sort-amount-asc: \"\\f160\";\n@fa-var-sort-amount-desc: \"\\f161\";\n@fa-var-sort-asc: \"\\f0de\";\n@fa-var-sort-desc: \"\\f0dd\";\n@fa-var-sort-down: \"\\f0dd\";\n@fa-var-sort-numeric-asc: \"\\f162\";\n@fa-var-sort-numeric-desc: \"\\f163\";\n@fa-var-sort-up: \"\\f0de\";\n@fa-var-soundcloud: \"\\f1be\";\n@fa-var-space-shuttle: \"\\f197\";\n@fa-var-spinner: \"\\f110\";\n@fa-var-spoon: \"\\f1b1\";\n@fa-var-spotify: \"\\f1bc\";\n@fa-var-square: \"\\f0c8\";\n@fa-var-square-o: \"\\f096\";\n@fa-var-stack-exchange: \"\\f18d\";\n@fa-var-stack-overflow: \"\\f16c\";\n@fa-var-star: \"\\f005\";\n@fa-var-star-half: \"\\f089\";\n@fa-var-star-half-empty: \"\\f123\";\n@fa-var-star-half-full: \"\\f123\";\n@fa-var-star-half-o: \"\\f123\";\n@fa-var-star-o: \"\\f006\";\n@fa-var-steam: \"\\f1b6\";\n@fa-var-steam-square: \"\\f1b7\";\n@fa-var-step-backward: \"\\f048\";\n@fa-var-step-forward: \"\\f051\";\n@fa-var-stethoscope: \"\\f0f1\";\n@fa-var-sticky-note: \"\\f249\";\n@fa-var-sticky-note-o: \"\\f24a\";\n@fa-var-stop: \"\\f04d\";\n@fa-var-stop-circle: \"\\f28d\";\n@fa-var-stop-circle-o: \"\\f28e\";\n@fa-var-street-view: \"\\f21d\";\n@fa-var-strikethrough: \"\\f0cc\";\n@fa-var-stumbleupon: \"\\f1a4\";\n@fa-var-stumbleupon-circle: \"\\f1a3\";\n@fa-var-subscript: \"\\f12c\";\n@fa-var-subway: \"\\f239\";\n@fa-var-suitcase: \"\\f0f2\";\n@fa-var-sun-o: \"\\f185\";\n@fa-var-superscript: \"\\f12b\";\n@fa-var-support: \"\\f1cd\";\n@fa-var-table: \"\\f0ce\";\n@fa-var-tablet: \"\\f10a\";\n@fa-var-tachometer: \"\\f0e4\";\n@fa-var-tag: \"\\f02b\";\n@fa-var-tags: \"\\f02c\";\n@fa-var-tasks: \"\\f0ae\";\n@fa-var-taxi: \"\\f1ba\";\n@fa-var-television: \"\\f26c\";\n@fa-var-tencent-weibo: \"\\f1d5\";\n@fa-var-terminal: \"\\f120\";\n@fa-var-text-height: \"\\f034\";\n@fa-var-text-width: \"\\f035\";\n@fa-var-th: \"\\f00a\";\n@fa-var-th-large: \"\\f009\";\n@fa-var-th-list: \"\\f00b\";\n@fa-var-thumb-tack: \"\\f08d\";\n@fa-var-thumbs-down: \"\\f165\";\n@fa-var-thumbs-o-down: \"\\f088\";\n@fa-var-thumbs-o-up: \"\\f087\";\n@fa-var-thumbs-up: \"\\f164\";\n@fa-var-ticket: \"\\f145\";\n@fa-var-times: \"\\f00d\";\n@fa-var-times-circle: \"\\f057\";\n@fa-var-times-circle-o: \"\\f05c\";\n@fa-var-tint: \"\\f043\";\n@fa-var-toggle-down: \"\\f150\";\n@fa-var-toggle-left: \"\\f191\";\n@fa-var-toggle-off: \"\\f204\";\n@fa-var-toggle-on: \"\\f205\";\n@fa-var-toggle-right: \"\\f152\";\n@fa-var-toggle-up: \"\\f151\";\n@fa-var-trademark: \"\\f25c\";\n@fa-var-train: \"\\f238\";\n@fa-var-transgender: \"\\f224\";\n@fa-var-transgender-alt: \"\\f225\";\n@fa-var-trash: \"\\f1f8\";\n@fa-var-trash-o: \"\\f014\";\n@fa-var-tree: \"\\f1bb\";\n@fa-var-trello: \"\\f181\";\n@fa-var-tripadvisor: \"\\f262\";\n@fa-var-trophy: \"\\f091\";\n@fa-var-truck: \"\\f0d1\";\n@fa-var-try: \"\\f195\";\n@fa-var-tty: \"\\f1e4\";\n@fa-var-tumblr: \"\\f173\";\n@fa-var-tumblr-square: \"\\f174\";\n@fa-var-turkish-lira: \"\\f195\";\n@fa-var-tv: \"\\f26c\";\n@fa-var-twitch: \"\\f1e8\";\n@fa-var-twitter: \"\\f099\";\n@fa-var-twitter-square: \"\\f081\";\n@fa-var-umbrella: \"\\f0e9\";\n@fa-var-underline: \"\\f0cd\";\n@fa-var-undo: \"\\f0e2\";\n@fa-var-university: \"\\f19c\";\n@fa-var-unlink: \"\\f127\";\n@fa-var-unlock: \"\\f09c\";\n@fa-var-unlock-alt: \"\\f13e\";\n@fa-var-unsorted: \"\\f0dc\";\n@fa-var-upload: \"\\f093\";\n@fa-var-usb: \"\\f287\";\n@fa-var-usd: \"\\f155\";\n@fa-var-user: \"\\f007\";\n@fa-var-user-md: \"\\f0f0\";\n@fa-var-user-plus: \"\\f234\";\n@fa-var-user-secret: \"\\f21b\";\n@fa-var-user-times: \"\\f235\";\n@fa-var-users: \"\\f0c0\";\n@fa-var-venus: \"\\f221\";\n@fa-var-venus-double: \"\\f226\";\n@fa-var-venus-mars: \"\\f228\";\n@fa-var-viacoin: \"\\f237\";\n@fa-var-video-camera: \"\\f03d\";\n@fa-var-vimeo: \"\\f27d\";\n@fa-var-vimeo-square: \"\\f194\";\n@fa-var-vine: \"\\f1ca\";\n@fa-var-vk: \"\\f189\";\n@fa-var-volume-down: \"\\f027\";\n@fa-var-volume-off: \"\\f026\";\n@fa-var-volume-up: \"\\f028\";\n@fa-var-warning: \"\\f071\";\n@fa-var-wechat: \"\\f1d7\";\n@fa-var-weibo: \"\\f18a\";\n@fa-var-weixin: \"\\f1d7\";\n@fa-var-whatsapp: \"\\f232\";\n@fa-var-wheelchair: \"\\f193\";\n@fa-var-wifi: \"\\f1eb\";\n@fa-var-wikipedia-w: \"\\f266\";\n@fa-var-windows: \"\\f17a\";\n@fa-var-won: \"\\f159\";\n@fa-var-wordpress: \"\\f19a\";\n@fa-var-wrench: \"\\f0ad\";\n@fa-var-xing: \"\\f168\";\n@fa-var-xing-square: \"\\f169\";\n@fa-var-y-combinator: \"\\f23b\";\n@fa-var-y-combinator-square: \"\\f1d4\";\n@fa-var-yahoo: \"\\f19e\";\n@fa-var-yc: \"\\f23b\";\n@fa-var-yc-square: \"\\f1d4\";\n@fa-var-yelp: \"\\f1e9\";\n@fa-var-yen: \"\\f157\";\n@fa-var-youtube: \"\\f167\";\n@fa-var-youtube-play: \"\\f16a\";\n@fa-var-youtube-square: \"\\f166\";\n\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/_animated.scss",
    "content": "// Spinning Icons\n// --------------------------\n\n.#{$fa-css-prefix}-spin {\n  -webkit-animation: fa-spin 2s infinite linear;\n          animation: fa-spin 2s infinite linear;\n}\n\n.#{$fa-css-prefix}-pulse {\n  -webkit-animation: fa-spin 1s infinite steps(8);\n          animation: fa-spin 1s infinite steps(8);\n}\n\n@-webkit-keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n            transform: rotate(359deg);\n  }\n}\n\n@keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n            transform: rotate(359deg);\n  }\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/_bordered-pulled.scss",
    "content": "// Bordered & Pulled\n// -------------------------\n\n.#{$fa-css-prefix}-border {\n  padding: .2em .25em .15em;\n  border: solid .08em $fa-border-color;\n  border-radius: .1em;\n}\n\n.#{$fa-css-prefix}-pull-left { float: left; }\n.#{$fa-css-prefix}-pull-right { float: right; }\n\n.#{$fa-css-prefix} {\n  &.#{$fa-css-prefix}-pull-left { margin-right: .3em; }\n  &.#{$fa-css-prefix}-pull-right { margin-left: .3em; }\n}\n\n/* Deprecated as of 4.4.0 */\n.pull-right { float: right; }\n.pull-left { float: left; }\n\n.#{$fa-css-prefix} {\n  &.pull-left { margin-right: .3em; }\n  &.pull-right { margin-left: .3em; }\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/_core.scss",
    "content": "// Base Class Definition\n// -------------------------\n\n.#{$fa-css-prefix} {\n  display: inline-block;\n  font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration\n  font-size: inherit; // can't have font-size inherit on line above, so need to override\n  text-rendering: auto; // optimizelegibility throws things off #1094\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/_fixed-width.scss",
    "content": "// Fixed Width Icons\n// -------------------------\n.#{$fa-css-prefix}-fw {\n  width: (18em / 14);\n  text-align: center;\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/_icons.scss",
    "content": "/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\n   readers do not read off random characters that represent icons */\n\n.#{$fa-css-prefix}-glass:before { content: $fa-var-glass; }\n.#{$fa-css-prefix}-music:before { content: $fa-var-music; }\n.#{$fa-css-prefix}-search:before { content: $fa-var-search; }\n.#{$fa-css-prefix}-envelope-o:before { content: $fa-var-envelope-o; }\n.#{$fa-css-prefix}-heart:before { content: $fa-var-heart; }\n.#{$fa-css-prefix}-star:before { content: $fa-var-star; }\n.#{$fa-css-prefix}-star-o:before { content: $fa-var-star-o; }\n.#{$fa-css-prefix}-user:before { content: $fa-var-user; }\n.#{$fa-css-prefix}-film:before { content: $fa-var-film; }\n.#{$fa-css-prefix}-th-large:before { content: $fa-var-th-large; }\n.#{$fa-css-prefix}-th:before { content: $fa-var-th; }\n.#{$fa-css-prefix}-th-list:before { content: $fa-var-th-list; }\n.#{$fa-css-prefix}-check:before { content: $fa-var-check; }\n.#{$fa-css-prefix}-remove:before,\n.#{$fa-css-prefix}-close:before,\n.#{$fa-css-prefix}-times:before { content: $fa-var-times; }\n.#{$fa-css-prefix}-search-plus:before { content: $fa-var-search-plus; }\n.#{$fa-css-prefix}-search-minus:before { content: $fa-var-search-minus; }\n.#{$fa-css-prefix}-power-off:before { content: $fa-var-power-off; }\n.#{$fa-css-prefix}-signal:before { content: $fa-var-signal; }\n.#{$fa-css-prefix}-gear:before,\n.#{$fa-css-prefix}-cog:before { content: $fa-var-cog; }\n.#{$fa-css-prefix}-trash-o:before { content: $fa-var-trash-o; }\n.#{$fa-css-prefix}-home:before { content: $fa-var-home; }\n.#{$fa-css-prefix}-file-o:before { content: $fa-var-file-o; }\n.#{$fa-css-prefix}-clock-o:before { content: $fa-var-clock-o; }\n.#{$fa-css-prefix}-road:before { content: $fa-var-road; }\n.#{$fa-css-prefix}-download:before { content: $fa-var-download; }\n.#{$fa-css-prefix}-arrow-circle-o-down:before { content: $fa-var-arrow-circle-o-down; }\n.#{$fa-css-prefix}-arrow-circle-o-up:before { content: $fa-var-arrow-circle-o-up; }\n.#{$fa-css-prefix}-inbox:before { content: $fa-var-inbox; }\n.#{$fa-css-prefix}-play-circle-o:before { content: $fa-var-play-circle-o; }\n.#{$fa-css-prefix}-rotate-right:before,\n.#{$fa-css-prefix}-repeat:before { content: $fa-var-repeat; }\n.#{$fa-css-prefix}-refresh:before { content: $fa-var-refresh; }\n.#{$fa-css-prefix}-list-alt:before { content: $fa-var-list-alt; }\n.#{$fa-css-prefix}-lock:before { content: $fa-var-lock; }\n.#{$fa-css-prefix}-flag:before { content: $fa-var-flag; }\n.#{$fa-css-prefix}-headphones:before { content: $fa-var-headphones; }\n.#{$fa-css-prefix}-volume-off:before { content: $fa-var-volume-off; }\n.#{$fa-css-prefix}-volume-down:before { content: $fa-var-volume-down; }\n.#{$fa-css-prefix}-volume-up:before { content: $fa-var-volume-up; }\n.#{$fa-css-prefix}-qrcode:before { content: $fa-var-qrcode; }\n.#{$fa-css-prefix}-barcode:before { content: $fa-var-barcode; }\n.#{$fa-css-prefix}-tag:before { content: $fa-var-tag; }\n.#{$fa-css-prefix}-tags:before { content: $fa-var-tags; }\n.#{$fa-css-prefix}-book:before { content: $fa-var-book; }\n.#{$fa-css-prefix}-bookmark:before { content: $fa-var-bookmark; }\n.#{$fa-css-prefix}-print:before { content: $fa-var-print; }\n.#{$fa-css-prefix}-camera:before { content: $fa-var-camera; }\n.#{$fa-css-prefix}-font:before { content: $fa-var-font; }\n.#{$fa-css-prefix}-bold:before { content: $fa-var-bold; }\n.#{$fa-css-prefix}-italic:before { content: $fa-var-italic; }\n.#{$fa-css-prefix}-text-height:before { content: $fa-var-text-height; }\n.#{$fa-css-prefix}-text-width:before { content: $fa-var-text-width; }\n.#{$fa-css-prefix}-align-left:before { content: $fa-var-align-left; }\n.#{$fa-css-prefix}-align-center:before { content: $fa-var-align-center; }\n.#{$fa-css-prefix}-align-right:before { content: $fa-var-align-right; }\n.#{$fa-css-prefix}-align-justify:before { content: $fa-var-align-justify; }\n.#{$fa-css-prefix}-list:before { content: $fa-var-list; }\n.#{$fa-css-prefix}-dedent:before,\n.#{$fa-css-prefix}-outdent:before { content: $fa-var-outdent; }\n.#{$fa-css-prefix}-indent:before { content: $fa-var-indent; }\n.#{$fa-css-prefix}-video-camera:before { content: $fa-var-video-camera; }\n.#{$fa-css-prefix}-photo:before,\n.#{$fa-css-prefix}-image:before,\n.#{$fa-css-prefix}-picture-o:before { content: $fa-var-picture-o; }\n.#{$fa-css-prefix}-pencil:before { content: $fa-var-pencil; }\n.#{$fa-css-prefix}-map-marker:before { content: $fa-var-map-marker; }\n.#{$fa-css-prefix}-adjust:before { content: $fa-var-adjust; }\n.#{$fa-css-prefix}-tint:before { content: $fa-var-tint; }\n.#{$fa-css-prefix}-edit:before,\n.#{$fa-css-prefix}-pencil-square-o:before { content: $fa-var-pencil-square-o; }\n.#{$fa-css-prefix}-share-square-o:before { content: $fa-var-share-square-o; }\n.#{$fa-css-prefix}-check-square-o:before { content: $fa-var-check-square-o; }\n.#{$fa-css-prefix}-arrows:before { content: $fa-var-arrows; }\n.#{$fa-css-prefix}-step-backward:before { content: $fa-var-step-backward; }\n.#{$fa-css-prefix}-fast-backward:before { content: $fa-var-fast-backward; }\n.#{$fa-css-prefix}-backward:before { content: $fa-var-backward; }\n.#{$fa-css-prefix}-play:before { content: $fa-var-play; }\n.#{$fa-css-prefix}-pause:before { content: $fa-var-pause; }\n.#{$fa-css-prefix}-stop:before { content: $fa-var-stop; }\n.#{$fa-css-prefix}-forward:before { content: $fa-var-forward; }\n.#{$fa-css-prefix}-fast-forward:before { content: $fa-var-fast-forward; }\n.#{$fa-css-prefix}-step-forward:before { content: $fa-var-step-forward; }\n.#{$fa-css-prefix}-eject:before { content: $fa-var-eject; }\n.#{$fa-css-prefix}-chevron-left:before { content: $fa-var-chevron-left; }\n.#{$fa-css-prefix}-chevron-right:before { content: $fa-var-chevron-right; }\n.#{$fa-css-prefix}-plus-circle:before { content: $fa-var-plus-circle; }\n.#{$fa-css-prefix}-minus-circle:before { content: $fa-var-minus-circle; }\n.#{$fa-css-prefix}-times-circle:before { content: $fa-var-times-circle; }\n.#{$fa-css-prefix}-check-circle:before { content: $fa-var-check-circle; }\n.#{$fa-css-prefix}-question-circle:before { content: $fa-var-question-circle; }\n.#{$fa-css-prefix}-info-circle:before { content: $fa-var-info-circle; }\n.#{$fa-css-prefix}-crosshairs:before { content: $fa-var-crosshairs; }\n.#{$fa-css-prefix}-times-circle-o:before { content: $fa-var-times-circle-o; }\n.#{$fa-css-prefix}-check-circle-o:before { content: $fa-var-check-circle-o; }\n.#{$fa-css-prefix}-ban:before { content: $fa-var-ban; }\n.#{$fa-css-prefix}-arrow-left:before { content: $fa-var-arrow-left; }\n.#{$fa-css-prefix}-arrow-right:before { content: $fa-var-arrow-right; }\n.#{$fa-css-prefix}-arrow-up:before { content: $fa-var-arrow-up; }\n.#{$fa-css-prefix}-arrow-down:before { content: $fa-var-arrow-down; }\n.#{$fa-css-prefix}-mail-forward:before,\n.#{$fa-css-prefix}-share:before { content: $fa-var-share; }\n.#{$fa-css-prefix}-expand:before { content: $fa-var-expand; }\n.#{$fa-css-prefix}-compress:before { content: $fa-var-compress; }\n.#{$fa-css-prefix}-plus:before { content: $fa-var-plus; }\n.#{$fa-css-prefix}-minus:before { content: $fa-var-minus; }\n.#{$fa-css-prefix}-asterisk:before { content: $fa-var-asterisk; }\n.#{$fa-css-prefix}-exclamation-circle:before { content: $fa-var-exclamation-circle; }\n.#{$fa-css-prefix}-gift:before { content: $fa-var-gift; }\n.#{$fa-css-prefix}-leaf:before { content: $fa-var-leaf; }\n.#{$fa-css-prefix}-fire:before { content: $fa-var-fire; }\n.#{$fa-css-prefix}-eye:before { content: $fa-var-eye; }\n.#{$fa-css-prefix}-eye-slash:before { content: $fa-var-eye-slash; }\n.#{$fa-css-prefix}-warning:before,\n.#{$fa-css-prefix}-exclamation-triangle:before { content: $fa-var-exclamation-triangle; }\n.#{$fa-css-prefix}-plane:before { content: $fa-var-plane; }\n.#{$fa-css-prefix}-calendar:before { content: $fa-var-calendar; }\n.#{$fa-css-prefix}-random:before { content: $fa-var-random; }\n.#{$fa-css-prefix}-comment:before { content: $fa-var-comment; }\n.#{$fa-css-prefix}-magnet:before { content: $fa-var-magnet; }\n.#{$fa-css-prefix}-chevron-up:before { content: $fa-var-chevron-up; }\n.#{$fa-css-prefix}-chevron-down:before { content: $fa-var-chevron-down; }\n.#{$fa-css-prefix}-retweet:before { content: $fa-var-retweet; }\n.#{$fa-css-prefix}-shopping-cart:before { content: $fa-var-shopping-cart; }\n.#{$fa-css-prefix}-folder:before { content: $fa-var-folder; }\n.#{$fa-css-prefix}-folder-open:before { content: $fa-var-folder-open; }\n.#{$fa-css-prefix}-arrows-v:before { content: $fa-var-arrows-v; }\n.#{$fa-css-prefix}-arrows-h:before { content: $fa-var-arrows-h; }\n.#{$fa-css-prefix}-bar-chart-o:before,\n.#{$fa-css-prefix}-bar-chart:before { content: $fa-var-bar-chart; }\n.#{$fa-css-prefix}-twitter-square:before { content: $fa-var-twitter-square; }\n.#{$fa-css-prefix}-facebook-square:before { content: $fa-var-facebook-square; }\n.#{$fa-css-prefix}-camera-retro:before { content: $fa-var-camera-retro; }\n.#{$fa-css-prefix}-key:before { content: $fa-var-key; }\n.#{$fa-css-prefix}-gears:before,\n.#{$fa-css-prefix}-cogs:before { content: $fa-var-cogs; }\n.#{$fa-css-prefix}-comments:before { content: $fa-var-comments; }\n.#{$fa-css-prefix}-thumbs-o-up:before { content: $fa-var-thumbs-o-up; }\n.#{$fa-css-prefix}-thumbs-o-down:before { content: $fa-var-thumbs-o-down; }\n.#{$fa-css-prefix}-star-half:before { content: $fa-var-star-half; }\n.#{$fa-css-prefix}-heart-o:before { content: $fa-var-heart-o; }\n.#{$fa-css-prefix}-sign-out:before { content: $fa-var-sign-out; }\n.#{$fa-css-prefix}-linkedin-square:before { content: $fa-var-linkedin-square; }\n.#{$fa-css-prefix}-thumb-tack:before { content: $fa-var-thumb-tack; }\n.#{$fa-css-prefix}-external-link:before { content: $fa-var-external-link; }\n.#{$fa-css-prefix}-sign-in:before { content: $fa-var-sign-in; }\n.#{$fa-css-prefix}-trophy:before { content: $fa-var-trophy; }\n.#{$fa-css-prefix}-github-square:before { content: $fa-var-github-square; }\n.#{$fa-css-prefix}-upload:before { content: $fa-var-upload; }\n.#{$fa-css-prefix}-lemon-o:before { content: $fa-var-lemon-o; }\n.#{$fa-css-prefix}-phone:before { content: $fa-var-phone; }\n.#{$fa-css-prefix}-square-o:before { content: $fa-var-square-o; }\n.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; }\n.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; }\n.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; }\n.#{$fa-css-prefix}-facebook-f:before,\n.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; }\n.#{$fa-css-prefix}-github:before { content: $fa-var-github; }\n.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; }\n.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; }\n.#{$fa-css-prefix}-feed:before,\n.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; }\n.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; }\n.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; }\n.#{$fa-css-prefix}-bell:before { content: $fa-var-bell; }\n.#{$fa-css-prefix}-certificate:before { content: $fa-var-certificate; }\n.#{$fa-css-prefix}-hand-o-right:before { content: $fa-var-hand-o-right; }\n.#{$fa-css-prefix}-hand-o-left:before { content: $fa-var-hand-o-left; }\n.#{$fa-css-prefix}-hand-o-up:before { content: $fa-var-hand-o-up; }\n.#{$fa-css-prefix}-hand-o-down:before { content: $fa-var-hand-o-down; }\n.#{$fa-css-prefix}-arrow-circle-left:before { content: $fa-var-arrow-circle-left; }\n.#{$fa-css-prefix}-arrow-circle-right:before { content: $fa-var-arrow-circle-right; }\n.#{$fa-css-prefix}-arrow-circle-up:before { content: $fa-var-arrow-circle-up; }\n.#{$fa-css-prefix}-arrow-circle-down:before { content: $fa-var-arrow-circle-down; }\n.#{$fa-css-prefix}-globe:before { content: $fa-var-globe; }\n.#{$fa-css-prefix}-wrench:before { content: $fa-var-wrench; }\n.#{$fa-css-prefix}-tasks:before { content: $fa-var-tasks; }\n.#{$fa-css-prefix}-filter:before { content: $fa-var-filter; }\n.#{$fa-css-prefix}-briefcase:before { content: $fa-var-briefcase; }\n.#{$fa-css-prefix}-arrows-alt:before { content: $fa-var-arrows-alt; }\n.#{$fa-css-prefix}-group:before,\n.#{$fa-css-prefix}-users:before { content: $fa-var-users; }\n.#{$fa-css-prefix}-chain:before,\n.#{$fa-css-prefix}-link:before { content: $fa-var-link; }\n.#{$fa-css-prefix}-cloud:before { content: $fa-var-cloud; }\n.#{$fa-css-prefix}-flask:before { content: $fa-var-flask; }\n.#{$fa-css-prefix}-cut:before,\n.#{$fa-css-prefix}-scissors:before { content: $fa-var-scissors; }\n.#{$fa-css-prefix}-copy:before,\n.#{$fa-css-prefix}-files-o:before { content: $fa-var-files-o; }\n.#{$fa-css-prefix}-paperclip:before { content: $fa-var-paperclip; }\n.#{$fa-css-prefix}-save:before,\n.#{$fa-css-prefix}-floppy-o:before { content: $fa-var-floppy-o; }\n.#{$fa-css-prefix}-square:before { content: $fa-var-square; }\n.#{$fa-css-prefix}-navicon:before,\n.#{$fa-css-prefix}-reorder:before,\n.#{$fa-css-prefix}-bars:before { content: $fa-var-bars; }\n.#{$fa-css-prefix}-list-ul:before { content: $fa-var-list-ul; }\n.#{$fa-css-prefix}-list-ol:before { content: $fa-var-list-ol; }\n.#{$fa-css-prefix}-strikethrough:before { content: $fa-var-strikethrough; }\n.#{$fa-css-prefix}-underline:before { content: $fa-var-underline; }\n.#{$fa-css-prefix}-table:before { content: $fa-var-table; }\n.#{$fa-css-prefix}-magic:before { content: $fa-var-magic; }\n.#{$fa-css-prefix}-truck:before { content: $fa-var-truck; }\n.#{$fa-css-prefix}-pinterest:before { content: $fa-var-pinterest; }\n.#{$fa-css-prefix}-pinterest-square:before { content: $fa-var-pinterest-square; }\n.#{$fa-css-prefix}-google-plus-square:before { content: $fa-var-google-plus-square; }\n.#{$fa-css-prefix}-google-plus:before { content: $fa-var-google-plus; }\n.#{$fa-css-prefix}-money:before { content: $fa-var-money; }\n.#{$fa-css-prefix}-caret-down:before { content: $fa-var-caret-down; }\n.#{$fa-css-prefix}-caret-up:before { content: $fa-var-caret-up; }\n.#{$fa-css-prefix}-caret-left:before { content: $fa-var-caret-left; }\n.#{$fa-css-prefix}-caret-right:before { content: $fa-var-caret-right; }\n.#{$fa-css-prefix}-columns:before { content: $fa-var-columns; }\n.#{$fa-css-prefix}-unsorted:before,\n.#{$fa-css-prefix}-sort:before { content: $fa-var-sort; }\n.#{$fa-css-prefix}-sort-down:before,\n.#{$fa-css-prefix}-sort-desc:before { content: $fa-var-sort-desc; }\n.#{$fa-css-prefix}-sort-up:before,\n.#{$fa-css-prefix}-sort-asc:before { content: $fa-var-sort-asc; }\n.#{$fa-css-prefix}-envelope:before { content: $fa-var-envelope; }\n.#{$fa-css-prefix}-linkedin:before { content: $fa-var-linkedin; }\n.#{$fa-css-prefix}-rotate-left:before,\n.#{$fa-css-prefix}-undo:before { content: $fa-var-undo; }\n.#{$fa-css-prefix}-legal:before,\n.#{$fa-css-prefix}-gavel:before { content: $fa-var-gavel; }\n.#{$fa-css-prefix}-dashboard:before,\n.#{$fa-css-prefix}-tachometer:before { content: $fa-var-tachometer; }\n.#{$fa-css-prefix}-comment-o:before { content: $fa-var-comment-o; }\n.#{$fa-css-prefix}-comments-o:before { content: $fa-var-comments-o; }\n.#{$fa-css-prefix}-flash:before,\n.#{$fa-css-prefix}-bolt:before { content: $fa-var-bolt; }\n.#{$fa-css-prefix}-sitemap:before { content: $fa-var-sitemap; }\n.#{$fa-css-prefix}-umbrella:before { content: $fa-var-umbrella; }\n.#{$fa-css-prefix}-paste:before,\n.#{$fa-css-prefix}-clipboard:before { content: $fa-var-clipboard; }\n.#{$fa-css-prefix}-lightbulb-o:before { content: $fa-var-lightbulb-o; }\n.#{$fa-css-prefix}-exchange:before { content: $fa-var-exchange; }\n.#{$fa-css-prefix}-cloud-download:before { content: $fa-var-cloud-download; }\n.#{$fa-css-prefix}-cloud-upload:before { content: $fa-var-cloud-upload; }\n.#{$fa-css-prefix}-user-md:before { content: $fa-var-user-md; }\n.#{$fa-css-prefix}-stethoscope:before { content: $fa-var-stethoscope; }\n.#{$fa-css-prefix}-suitcase:before { content: $fa-var-suitcase; }\n.#{$fa-css-prefix}-bell-o:before { content: $fa-var-bell-o; }\n.#{$fa-css-prefix}-coffee:before { content: $fa-var-coffee; }\n.#{$fa-css-prefix}-cutlery:before { content: $fa-var-cutlery; }\n.#{$fa-css-prefix}-file-text-o:before { content: $fa-var-file-text-o; }\n.#{$fa-css-prefix}-building-o:before { content: $fa-var-building-o; }\n.#{$fa-css-prefix}-hospital-o:before { content: $fa-var-hospital-o; }\n.#{$fa-css-prefix}-ambulance:before { content: $fa-var-ambulance; }\n.#{$fa-css-prefix}-medkit:before { content: $fa-var-medkit; }\n.#{$fa-css-prefix}-fighter-jet:before { content: $fa-var-fighter-jet; }\n.#{$fa-css-prefix}-beer:before { content: $fa-var-beer; }\n.#{$fa-css-prefix}-h-square:before { content: $fa-var-h-square; }\n.#{$fa-css-prefix}-plus-square:before { content: $fa-var-plus-square; }\n.#{$fa-css-prefix}-angle-double-left:before { content: $fa-var-angle-double-left; }\n.#{$fa-css-prefix}-angle-double-right:before { content: $fa-var-angle-double-right; }\n.#{$fa-css-prefix}-angle-double-up:before { content: $fa-var-angle-double-up; }\n.#{$fa-css-prefix}-angle-double-down:before { content: $fa-var-angle-double-down; }\n.#{$fa-css-prefix}-angle-left:before { content: $fa-var-angle-left; }\n.#{$fa-css-prefix}-angle-right:before { content: $fa-var-angle-right; }\n.#{$fa-css-prefix}-angle-up:before { content: $fa-var-angle-up; }\n.#{$fa-css-prefix}-angle-down:before { content: $fa-var-angle-down; }\n.#{$fa-css-prefix}-desktop:before { content: $fa-var-desktop; }\n.#{$fa-css-prefix}-laptop:before { content: $fa-var-laptop; }\n.#{$fa-css-prefix}-tablet:before { content: $fa-var-tablet; }\n.#{$fa-css-prefix}-mobile-phone:before,\n.#{$fa-css-prefix}-mobile:before { content: $fa-var-mobile; }\n.#{$fa-css-prefix}-circle-o:before { content: $fa-var-circle-o; }\n.#{$fa-css-prefix}-quote-left:before { content: $fa-var-quote-left; }\n.#{$fa-css-prefix}-quote-right:before { content: $fa-var-quote-right; }\n.#{$fa-css-prefix}-spinner:before { content: $fa-var-spinner; }\n.#{$fa-css-prefix}-circle:before { content: $fa-var-circle; }\n.#{$fa-css-prefix}-mail-reply:before,\n.#{$fa-css-prefix}-reply:before { content: $fa-var-reply; }\n.#{$fa-css-prefix}-github-alt:before { content: $fa-var-github-alt; }\n.#{$fa-css-prefix}-folder-o:before { content: $fa-var-folder-o; }\n.#{$fa-css-prefix}-folder-open-o:before { content: $fa-var-folder-open-o; }\n.#{$fa-css-prefix}-smile-o:before { content: $fa-var-smile-o; }\n.#{$fa-css-prefix}-frown-o:before { content: $fa-var-frown-o; }\n.#{$fa-css-prefix}-meh-o:before { content: $fa-var-meh-o; }\n.#{$fa-css-prefix}-gamepad:before { content: $fa-var-gamepad; }\n.#{$fa-css-prefix}-keyboard-o:before { content: $fa-var-keyboard-o; }\n.#{$fa-css-prefix}-flag-o:before { content: $fa-var-flag-o; }\n.#{$fa-css-prefix}-flag-checkered:before { content: $fa-var-flag-checkered; }\n.#{$fa-css-prefix}-terminal:before { content: $fa-var-terminal; }\n.#{$fa-css-prefix}-code:before { content: $fa-var-code; }\n.#{$fa-css-prefix}-mail-reply-all:before,\n.#{$fa-css-prefix}-reply-all:before { content: $fa-var-reply-all; }\n.#{$fa-css-prefix}-star-half-empty:before,\n.#{$fa-css-prefix}-star-half-full:before,\n.#{$fa-css-prefix}-star-half-o:before { content: $fa-var-star-half-o; }\n.#{$fa-css-prefix}-location-arrow:before { content: $fa-var-location-arrow; }\n.#{$fa-css-prefix}-crop:before { content: $fa-var-crop; }\n.#{$fa-css-prefix}-code-fork:before { content: $fa-var-code-fork; }\n.#{$fa-css-prefix}-unlink:before,\n.#{$fa-css-prefix}-chain-broken:before { content: $fa-var-chain-broken; }\n.#{$fa-css-prefix}-question:before { content: $fa-var-question; }\n.#{$fa-css-prefix}-info:before { content: $fa-var-info; }\n.#{$fa-css-prefix}-exclamation:before { content: $fa-var-exclamation; }\n.#{$fa-css-prefix}-superscript:before { content: $fa-var-superscript; }\n.#{$fa-css-prefix}-subscript:before { content: $fa-var-subscript; }\n.#{$fa-css-prefix}-eraser:before { content: $fa-var-eraser; }\n.#{$fa-css-prefix}-puzzle-piece:before { content: $fa-var-puzzle-piece; }\n.#{$fa-css-prefix}-microphone:before { content: $fa-var-microphone; }\n.#{$fa-css-prefix}-microphone-slash:before { content: $fa-var-microphone-slash; }\n.#{$fa-css-prefix}-shield:before { content: $fa-var-shield; }\n.#{$fa-css-prefix}-calendar-o:before { content: $fa-var-calendar-o; }\n.#{$fa-css-prefix}-fire-extinguisher:before { content: $fa-var-fire-extinguisher; }\n.#{$fa-css-prefix}-rocket:before { content: $fa-var-rocket; }\n.#{$fa-css-prefix}-maxcdn:before { content: $fa-var-maxcdn; }\n.#{$fa-css-prefix}-chevron-circle-left:before { content: $fa-var-chevron-circle-left; }\n.#{$fa-css-prefix}-chevron-circle-right:before { content: $fa-var-chevron-circle-right; }\n.#{$fa-css-prefix}-chevron-circle-up:before { content: $fa-var-chevron-circle-up; }\n.#{$fa-css-prefix}-chevron-circle-down:before { content: $fa-var-chevron-circle-down; }\n.#{$fa-css-prefix}-html5:before { content: $fa-var-html5; }\n.#{$fa-css-prefix}-css3:before { content: $fa-var-css3; }\n.#{$fa-css-prefix}-anchor:before { content: $fa-var-anchor; }\n.#{$fa-css-prefix}-unlock-alt:before { content: $fa-var-unlock-alt; }\n.#{$fa-css-prefix}-bullseye:before { content: $fa-var-bullseye; }\n.#{$fa-css-prefix}-ellipsis-h:before { content: $fa-var-ellipsis-h; }\n.#{$fa-css-prefix}-ellipsis-v:before { content: $fa-var-ellipsis-v; }\n.#{$fa-css-prefix}-rss-square:before { content: $fa-var-rss-square; }\n.#{$fa-css-prefix}-play-circle:before { content: $fa-var-play-circle; }\n.#{$fa-css-prefix}-ticket:before { content: $fa-var-ticket; }\n.#{$fa-css-prefix}-minus-square:before { content: $fa-var-minus-square; }\n.#{$fa-css-prefix}-minus-square-o:before { content: $fa-var-minus-square-o; }\n.#{$fa-css-prefix}-level-up:before { content: $fa-var-level-up; }\n.#{$fa-css-prefix}-level-down:before { content: $fa-var-level-down; }\n.#{$fa-css-prefix}-check-square:before { content: $fa-var-check-square; }\n.#{$fa-css-prefix}-pencil-square:before { content: $fa-var-pencil-square; }\n.#{$fa-css-prefix}-external-link-square:before { content: $fa-var-external-link-square; }\n.#{$fa-css-prefix}-share-square:before { content: $fa-var-share-square; }\n.#{$fa-css-prefix}-compass:before { content: $fa-var-compass; }\n.#{$fa-css-prefix}-toggle-down:before,\n.#{$fa-css-prefix}-caret-square-o-down:before { content: $fa-var-caret-square-o-down; }\n.#{$fa-css-prefix}-toggle-up:before,\n.#{$fa-css-prefix}-caret-square-o-up:before { content: $fa-var-caret-square-o-up; }\n.#{$fa-css-prefix}-toggle-right:before,\n.#{$fa-css-prefix}-caret-square-o-right:before { content: $fa-var-caret-square-o-right; }\n.#{$fa-css-prefix}-euro:before,\n.#{$fa-css-prefix}-eur:before { content: $fa-var-eur; }\n.#{$fa-css-prefix}-gbp:before { content: $fa-var-gbp; }\n.#{$fa-css-prefix}-dollar:before,\n.#{$fa-css-prefix}-usd:before { content: $fa-var-usd; }\n.#{$fa-css-prefix}-rupee:before,\n.#{$fa-css-prefix}-inr:before { content: $fa-var-inr; }\n.#{$fa-css-prefix}-cny:before,\n.#{$fa-css-prefix}-rmb:before,\n.#{$fa-css-prefix}-yen:before,\n.#{$fa-css-prefix}-jpy:before { content: $fa-var-jpy; }\n.#{$fa-css-prefix}-ruble:before,\n.#{$fa-css-prefix}-rouble:before,\n.#{$fa-css-prefix}-rub:before { content: $fa-var-rub; }\n.#{$fa-css-prefix}-won:before,\n.#{$fa-css-prefix}-krw:before { content: $fa-var-krw; }\n.#{$fa-css-prefix}-bitcoin:before,\n.#{$fa-css-prefix}-btc:before { content: $fa-var-btc; }\n.#{$fa-css-prefix}-file:before { content: $fa-var-file; }\n.#{$fa-css-prefix}-file-text:before { content: $fa-var-file-text; }\n.#{$fa-css-prefix}-sort-alpha-asc:before { content: $fa-var-sort-alpha-asc; }\n.#{$fa-css-prefix}-sort-alpha-desc:before { content: $fa-var-sort-alpha-desc; }\n.#{$fa-css-prefix}-sort-amount-asc:before { content: $fa-var-sort-amount-asc; }\n.#{$fa-css-prefix}-sort-amount-desc:before { content: $fa-var-sort-amount-desc; }\n.#{$fa-css-prefix}-sort-numeric-asc:before { content: $fa-var-sort-numeric-asc; }\n.#{$fa-css-prefix}-sort-numeric-desc:before { content: $fa-var-sort-numeric-desc; }\n.#{$fa-css-prefix}-thumbs-up:before { content: $fa-var-thumbs-up; }\n.#{$fa-css-prefix}-thumbs-down:before { content: $fa-var-thumbs-down; }\n.#{$fa-css-prefix}-youtube-square:before { content: $fa-var-youtube-square; }\n.#{$fa-css-prefix}-youtube:before { content: $fa-var-youtube; }\n.#{$fa-css-prefix}-xing:before { content: $fa-var-xing; }\n.#{$fa-css-prefix}-xing-square:before { content: $fa-var-xing-square; }\n.#{$fa-css-prefix}-youtube-play:before { content: $fa-var-youtube-play; }\n.#{$fa-css-prefix}-dropbox:before { content: $fa-var-dropbox; }\n.#{$fa-css-prefix}-stack-overflow:before { content: $fa-var-stack-overflow; }\n.#{$fa-css-prefix}-instagram:before { content: $fa-var-instagram; }\n.#{$fa-css-prefix}-flickr:before { content: $fa-var-flickr; }\n.#{$fa-css-prefix}-adn:before { content: $fa-var-adn; }\n.#{$fa-css-prefix}-bitbucket:before { content: $fa-var-bitbucket; }\n.#{$fa-css-prefix}-bitbucket-square:before { content: $fa-var-bitbucket-square; }\n.#{$fa-css-prefix}-tumblr:before { content: $fa-var-tumblr; }\n.#{$fa-css-prefix}-tumblr-square:before { content: $fa-var-tumblr-square; }\n.#{$fa-css-prefix}-long-arrow-down:before { content: $fa-var-long-arrow-down; }\n.#{$fa-css-prefix}-long-arrow-up:before { content: $fa-var-long-arrow-up; }\n.#{$fa-css-prefix}-long-arrow-left:before { content: $fa-var-long-arrow-left; }\n.#{$fa-css-prefix}-long-arrow-right:before { content: $fa-var-long-arrow-right; }\n.#{$fa-css-prefix}-apple:before { content: $fa-var-apple; }\n.#{$fa-css-prefix}-windows:before { content: $fa-var-windows; }\n.#{$fa-css-prefix}-android:before { content: $fa-var-android; }\n.#{$fa-css-prefix}-linux:before { content: $fa-var-linux; }\n.#{$fa-css-prefix}-dribbble:before { content: $fa-var-dribbble; }\n.#{$fa-css-prefix}-skype:before { content: $fa-var-skype; }\n.#{$fa-css-prefix}-foursquare:before { content: $fa-var-foursquare; }\n.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; }\n.#{$fa-css-prefix}-female:before { content: $fa-var-female; }\n.#{$fa-css-prefix}-male:before { content: $fa-var-male; }\n.#{$fa-css-prefix}-gittip:before,\n.#{$fa-css-prefix}-gratipay:before { content: $fa-var-gratipay; }\n.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; }\n.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; }\n.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; }\n.#{$fa-css-prefix}-bug:before { content: $fa-var-bug; }\n.#{$fa-css-prefix}-vk:before { content: $fa-var-vk; }\n.#{$fa-css-prefix}-weibo:before { content: $fa-var-weibo; }\n.#{$fa-css-prefix}-renren:before { content: $fa-var-renren; }\n.#{$fa-css-prefix}-pagelines:before { content: $fa-var-pagelines; }\n.#{$fa-css-prefix}-stack-exchange:before { content: $fa-var-stack-exchange; }\n.#{$fa-css-prefix}-arrow-circle-o-right:before { content: $fa-var-arrow-circle-o-right; }\n.#{$fa-css-prefix}-arrow-circle-o-left:before { content: $fa-var-arrow-circle-o-left; }\n.#{$fa-css-prefix}-toggle-left:before,\n.#{$fa-css-prefix}-caret-square-o-left:before { content: $fa-var-caret-square-o-left; }\n.#{$fa-css-prefix}-dot-circle-o:before { content: $fa-var-dot-circle-o; }\n.#{$fa-css-prefix}-wheelchair:before { content: $fa-var-wheelchair; }\n.#{$fa-css-prefix}-vimeo-square:before { content: $fa-var-vimeo-square; }\n.#{$fa-css-prefix}-turkish-lira:before,\n.#{$fa-css-prefix}-try:before { content: $fa-var-try; }\n.#{$fa-css-prefix}-plus-square-o:before { content: $fa-var-plus-square-o; }\n.#{$fa-css-prefix}-space-shuttle:before { content: $fa-var-space-shuttle; }\n.#{$fa-css-prefix}-slack:before { content: $fa-var-slack; }\n.#{$fa-css-prefix}-envelope-square:before { content: $fa-var-envelope-square; }\n.#{$fa-css-prefix}-wordpress:before { content: $fa-var-wordpress; }\n.#{$fa-css-prefix}-openid:before { content: $fa-var-openid; }\n.#{$fa-css-prefix}-institution:before,\n.#{$fa-css-prefix}-bank:before,\n.#{$fa-css-prefix}-university:before { content: $fa-var-university; }\n.#{$fa-css-prefix}-mortar-board:before,\n.#{$fa-css-prefix}-graduation-cap:before { content: $fa-var-graduation-cap; }\n.#{$fa-css-prefix}-yahoo:before { content: $fa-var-yahoo; }\n.#{$fa-css-prefix}-google:before { content: $fa-var-google; }\n.#{$fa-css-prefix}-reddit:before { content: $fa-var-reddit; }\n.#{$fa-css-prefix}-reddit-square:before { content: $fa-var-reddit-square; }\n.#{$fa-css-prefix}-stumbleupon-circle:before { content: $fa-var-stumbleupon-circle; }\n.#{$fa-css-prefix}-stumbleupon:before { content: $fa-var-stumbleupon; }\n.#{$fa-css-prefix}-delicious:before { content: $fa-var-delicious; }\n.#{$fa-css-prefix}-digg:before { content: $fa-var-digg; }\n.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; }\n.#{$fa-css-prefix}-pied-piper-alt:before { content: $fa-var-pied-piper-alt; }\n.#{$fa-css-prefix}-drupal:before { content: $fa-var-drupal; }\n.#{$fa-css-prefix}-joomla:before { content: $fa-var-joomla; }\n.#{$fa-css-prefix}-language:before { content: $fa-var-language; }\n.#{$fa-css-prefix}-fax:before { content: $fa-var-fax; }\n.#{$fa-css-prefix}-building:before { content: $fa-var-building; }\n.#{$fa-css-prefix}-child:before { content: $fa-var-child; }\n.#{$fa-css-prefix}-paw:before { content: $fa-var-paw; }\n.#{$fa-css-prefix}-spoon:before { content: $fa-var-spoon; }\n.#{$fa-css-prefix}-cube:before { content: $fa-var-cube; }\n.#{$fa-css-prefix}-cubes:before { content: $fa-var-cubes; }\n.#{$fa-css-prefix}-behance:before { content: $fa-var-behance; }\n.#{$fa-css-prefix}-behance-square:before { content: $fa-var-behance-square; }\n.#{$fa-css-prefix}-steam:before { content: $fa-var-steam; }\n.#{$fa-css-prefix}-steam-square:before { content: $fa-var-steam-square; }\n.#{$fa-css-prefix}-recycle:before { content: $fa-var-recycle; }\n.#{$fa-css-prefix}-automobile:before,\n.#{$fa-css-prefix}-car:before { content: $fa-var-car; }\n.#{$fa-css-prefix}-cab:before,\n.#{$fa-css-prefix}-taxi:before { content: $fa-var-taxi; }\n.#{$fa-css-prefix}-tree:before { content: $fa-var-tree; }\n.#{$fa-css-prefix}-spotify:before { content: $fa-var-spotify; }\n.#{$fa-css-prefix}-deviantart:before { content: $fa-var-deviantart; }\n.#{$fa-css-prefix}-soundcloud:before { content: $fa-var-soundcloud; }\n.#{$fa-css-prefix}-database:before { content: $fa-var-database; }\n.#{$fa-css-prefix}-file-pdf-o:before { content: $fa-var-file-pdf-o; }\n.#{$fa-css-prefix}-file-word-o:before { content: $fa-var-file-word-o; }\n.#{$fa-css-prefix}-file-excel-o:before { content: $fa-var-file-excel-o; }\n.#{$fa-css-prefix}-file-powerpoint-o:before { content: $fa-var-file-powerpoint-o; }\n.#{$fa-css-prefix}-file-photo-o:before,\n.#{$fa-css-prefix}-file-picture-o:before,\n.#{$fa-css-prefix}-file-image-o:before { content: $fa-var-file-image-o; }\n.#{$fa-css-prefix}-file-zip-o:before,\n.#{$fa-css-prefix}-file-archive-o:before { content: $fa-var-file-archive-o; }\n.#{$fa-css-prefix}-file-sound-o:before,\n.#{$fa-css-prefix}-file-audio-o:before { content: $fa-var-file-audio-o; }\n.#{$fa-css-prefix}-file-movie-o:before,\n.#{$fa-css-prefix}-file-video-o:before { content: $fa-var-file-video-o; }\n.#{$fa-css-prefix}-file-code-o:before { content: $fa-var-file-code-o; }\n.#{$fa-css-prefix}-vine:before { content: $fa-var-vine; }\n.#{$fa-css-prefix}-codepen:before { content: $fa-var-codepen; }\n.#{$fa-css-prefix}-jsfiddle:before { content: $fa-var-jsfiddle; }\n.#{$fa-css-prefix}-life-bouy:before,\n.#{$fa-css-prefix}-life-buoy:before,\n.#{$fa-css-prefix}-life-saver:before,\n.#{$fa-css-prefix}-support:before,\n.#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; }\n.#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; }\n.#{$fa-css-prefix}-ra:before,\n.#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; }\n.#{$fa-css-prefix}-ge:before,\n.#{$fa-css-prefix}-empire:before { content: $fa-var-empire; }\n.#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; }\n.#{$fa-css-prefix}-git:before { content: $fa-var-git; }\n.#{$fa-css-prefix}-y-combinator-square:before,\n.#{$fa-css-prefix}-yc-square:before,\n.#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; }\n.#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; }\n.#{$fa-css-prefix}-qq:before { content: $fa-var-qq; }\n.#{$fa-css-prefix}-wechat:before,\n.#{$fa-css-prefix}-weixin:before { content: $fa-var-weixin; }\n.#{$fa-css-prefix}-send:before,\n.#{$fa-css-prefix}-paper-plane:before { content: $fa-var-paper-plane; }\n.#{$fa-css-prefix}-send-o:before,\n.#{$fa-css-prefix}-paper-plane-o:before { content: $fa-var-paper-plane-o; }\n.#{$fa-css-prefix}-history:before { content: $fa-var-history; }\n.#{$fa-css-prefix}-circle-thin:before { content: $fa-var-circle-thin; }\n.#{$fa-css-prefix}-header:before { content: $fa-var-header; }\n.#{$fa-css-prefix}-paragraph:before { content: $fa-var-paragraph; }\n.#{$fa-css-prefix}-sliders:before { content: $fa-var-sliders; }\n.#{$fa-css-prefix}-share-alt:before { content: $fa-var-share-alt; }\n.#{$fa-css-prefix}-share-alt-square:before { content: $fa-var-share-alt-square; }\n.#{$fa-css-prefix}-bomb:before { content: $fa-var-bomb; }\n.#{$fa-css-prefix}-soccer-ball-o:before,\n.#{$fa-css-prefix}-futbol-o:before { content: $fa-var-futbol-o; }\n.#{$fa-css-prefix}-tty:before { content: $fa-var-tty; }\n.#{$fa-css-prefix}-binoculars:before { content: $fa-var-binoculars; }\n.#{$fa-css-prefix}-plug:before { content: $fa-var-plug; }\n.#{$fa-css-prefix}-slideshare:before { content: $fa-var-slideshare; }\n.#{$fa-css-prefix}-twitch:before { content: $fa-var-twitch; }\n.#{$fa-css-prefix}-yelp:before { content: $fa-var-yelp; }\n.#{$fa-css-prefix}-newspaper-o:before { content: $fa-var-newspaper-o; }\n.#{$fa-css-prefix}-wifi:before { content: $fa-var-wifi; }\n.#{$fa-css-prefix}-calculator:before { content: $fa-var-calculator; }\n.#{$fa-css-prefix}-paypal:before { content: $fa-var-paypal; }\n.#{$fa-css-prefix}-google-wallet:before { content: $fa-var-google-wallet; }\n.#{$fa-css-prefix}-cc-visa:before { content: $fa-var-cc-visa; }\n.#{$fa-css-prefix}-cc-mastercard:before { content: $fa-var-cc-mastercard; }\n.#{$fa-css-prefix}-cc-discover:before { content: $fa-var-cc-discover; }\n.#{$fa-css-prefix}-cc-amex:before { content: $fa-var-cc-amex; }\n.#{$fa-css-prefix}-cc-paypal:before { content: $fa-var-cc-paypal; }\n.#{$fa-css-prefix}-cc-stripe:before { content: $fa-var-cc-stripe; }\n.#{$fa-css-prefix}-bell-slash:before { content: $fa-var-bell-slash; }\n.#{$fa-css-prefix}-bell-slash-o:before { content: $fa-var-bell-slash-o; }\n.#{$fa-css-prefix}-trash:before { content: $fa-var-trash; }\n.#{$fa-css-prefix}-copyright:before { content: $fa-var-copyright; }\n.#{$fa-css-prefix}-at:before { content: $fa-var-at; }\n.#{$fa-css-prefix}-eyedropper:before { content: $fa-var-eyedropper; }\n.#{$fa-css-prefix}-paint-brush:before { content: $fa-var-paint-brush; }\n.#{$fa-css-prefix}-birthday-cake:before { content: $fa-var-birthday-cake; }\n.#{$fa-css-prefix}-area-chart:before { content: $fa-var-area-chart; }\n.#{$fa-css-prefix}-pie-chart:before { content: $fa-var-pie-chart; }\n.#{$fa-css-prefix}-line-chart:before { content: $fa-var-line-chart; }\n.#{$fa-css-prefix}-lastfm:before { content: $fa-var-lastfm; }\n.#{$fa-css-prefix}-lastfm-square:before { content: $fa-var-lastfm-square; }\n.#{$fa-css-prefix}-toggle-off:before { content: $fa-var-toggle-off; }\n.#{$fa-css-prefix}-toggle-on:before { content: $fa-var-toggle-on; }\n.#{$fa-css-prefix}-bicycle:before { content: $fa-var-bicycle; }\n.#{$fa-css-prefix}-bus:before { content: $fa-var-bus; }\n.#{$fa-css-prefix}-ioxhost:before { content: $fa-var-ioxhost; }\n.#{$fa-css-prefix}-angellist:before { content: $fa-var-angellist; }\n.#{$fa-css-prefix}-cc:before { content: $fa-var-cc; }\n.#{$fa-css-prefix}-shekel:before,\n.#{$fa-css-prefix}-sheqel:before,\n.#{$fa-css-prefix}-ils:before { content: $fa-var-ils; }\n.#{$fa-css-prefix}-meanpath:before { content: $fa-var-meanpath; }\n.#{$fa-css-prefix}-buysellads:before { content: $fa-var-buysellads; }\n.#{$fa-css-prefix}-connectdevelop:before { content: $fa-var-connectdevelop; }\n.#{$fa-css-prefix}-dashcube:before { content: $fa-var-dashcube; }\n.#{$fa-css-prefix}-forumbee:before { content: $fa-var-forumbee; }\n.#{$fa-css-prefix}-leanpub:before { content: $fa-var-leanpub; }\n.#{$fa-css-prefix}-sellsy:before { content: $fa-var-sellsy; }\n.#{$fa-css-prefix}-shirtsinbulk:before { content: $fa-var-shirtsinbulk; }\n.#{$fa-css-prefix}-simplybuilt:before { content: $fa-var-simplybuilt; }\n.#{$fa-css-prefix}-skyatlas:before { content: $fa-var-skyatlas; }\n.#{$fa-css-prefix}-cart-plus:before { content: $fa-var-cart-plus; }\n.#{$fa-css-prefix}-cart-arrow-down:before { content: $fa-var-cart-arrow-down; }\n.#{$fa-css-prefix}-diamond:before { content: $fa-var-diamond; }\n.#{$fa-css-prefix}-ship:before { content: $fa-var-ship; }\n.#{$fa-css-prefix}-user-secret:before { content: $fa-var-user-secret; }\n.#{$fa-css-prefix}-motorcycle:before { content: $fa-var-motorcycle; }\n.#{$fa-css-prefix}-street-view:before { content: $fa-var-street-view; }\n.#{$fa-css-prefix}-heartbeat:before { content: $fa-var-heartbeat; }\n.#{$fa-css-prefix}-venus:before { content: $fa-var-venus; }\n.#{$fa-css-prefix}-mars:before { content: $fa-var-mars; }\n.#{$fa-css-prefix}-mercury:before { content: $fa-var-mercury; }\n.#{$fa-css-prefix}-intersex:before,\n.#{$fa-css-prefix}-transgender:before { content: $fa-var-transgender; }\n.#{$fa-css-prefix}-transgender-alt:before { content: $fa-var-transgender-alt; }\n.#{$fa-css-prefix}-venus-double:before { content: $fa-var-venus-double; }\n.#{$fa-css-prefix}-mars-double:before { content: $fa-var-mars-double; }\n.#{$fa-css-prefix}-venus-mars:before { content: $fa-var-venus-mars; }\n.#{$fa-css-prefix}-mars-stroke:before { content: $fa-var-mars-stroke; }\n.#{$fa-css-prefix}-mars-stroke-v:before { content: $fa-var-mars-stroke-v; }\n.#{$fa-css-prefix}-mars-stroke-h:before { content: $fa-var-mars-stroke-h; }\n.#{$fa-css-prefix}-neuter:before { content: $fa-var-neuter; }\n.#{$fa-css-prefix}-genderless:before { content: $fa-var-genderless; }\n.#{$fa-css-prefix}-facebook-official:before { content: $fa-var-facebook-official; }\n.#{$fa-css-prefix}-pinterest-p:before { content: $fa-var-pinterest-p; }\n.#{$fa-css-prefix}-whatsapp:before { content: $fa-var-whatsapp; }\n.#{$fa-css-prefix}-server:before { content: $fa-var-server; }\n.#{$fa-css-prefix}-user-plus:before { content: $fa-var-user-plus; }\n.#{$fa-css-prefix}-user-times:before { content: $fa-var-user-times; }\n.#{$fa-css-prefix}-hotel:before,\n.#{$fa-css-prefix}-bed:before { content: $fa-var-bed; }\n.#{$fa-css-prefix}-viacoin:before { content: $fa-var-viacoin; }\n.#{$fa-css-prefix}-train:before { content: $fa-var-train; }\n.#{$fa-css-prefix}-subway:before { content: $fa-var-subway; }\n.#{$fa-css-prefix}-medium:before { content: $fa-var-medium; }\n.#{$fa-css-prefix}-yc:before,\n.#{$fa-css-prefix}-y-combinator:before { content: $fa-var-y-combinator; }\n.#{$fa-css-prefix}-optin-monster:before { content: $fa-var-optin-monster; }\n.#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; }\n.#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; }\n.#{$fa-css-prefix}-battery-4:before,\n.#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; }\n.#{$fa-css-prefix}-battery-3:before,\n.#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; }\n.#{$fa-css-prefix}-battery-2:before,\n.#{$fa-css-prefix}-battery-half:before { content: $fa-var-battery-half; }\n.#{$fa-css-prefix}-battery-1:before,\n.#{$fa-css-prefix}-battery-quarter:before { content: $fa-var-battery-quarter; }\n.#{$fa-css-prefix}-battery-0:before,\n.#{$fa-css-prefix}-battery-empty:before { content: $fa-var-battery-empty; }\n.#{$fa-css-prefix}-mouse-pointer:before { content: $fa-var-mouse-pointer; }\n.#{$fa-css-prefix}-i-cursor:before { content: $fa-var-i-cursor; }\n.#{$fa-css-prefix}-object-group:before { content: $fa-var-object-group; }\n.#{$fa-css-prefix}-object-ungroup:before { content: $fa-var-object-ungroup; }\n.#{$fa-css-prefix}-sticky-note:before { content: $fa-var-sticky-note; }\n.#{$fa-css-prefix}-sticky-note-o:before { content: $fa-var-sticky-note-o; }\n.#{$fa-css-prefix}-cc-jcb:before { content: $fa-var-cc-jcb; }\n.#{$fa-css-prefix}-cc-diners-club:before { content: $fa-var-cc-diners-club; }\n.#{$fa-css-prefix}-clone:before { content: $fa-var-clone; }\n.#{$fa-css-prefix}-balance-scale:before { content: $fa-var-balance-scale; }\n.#{$fa-css-prefix}-hourglass-o:before { content: $fa-var-hourglass-o; }\n.#{$fa-css-prefix}-hourglass-1:before,\n.#{$fa-css-prefix}-hourglass-start:before { content: $fa-var-hourglass-start; }\n.#{$fa-css-prefix}-hourglass-2:before,\n.#{$fa-css-prefix}-hourglass-half:before { content: $fa-var-hourglass-half; }\n.#{$fa-css-prefix}-hourglass-3:before,\n.#{$fa-css-prefix}-hourglass-end:before { content: $fa-var-hourglass-end; }\n.#{$fa-css-prefix}-hourglass:before { content: $fa-var-hourglass; }\n.#{$fa-css-prefix}-hand-grab-o:before,\n.#{$fa-css-prefix}-hand-rock-o:before { content: $fa-var-hand-rock-o; }\n.#{$fa-css-prefix}-hand-stop-o:before,\n.#{$fa-css-prefix}-hand-paper-o:before { content: $fa-var-hand-paper-o; }\n.#{$fa-css-prefix}-hand-scissors-o:before { content: $fa-var-hand-scissors-o; }\n.#{$fa-css-prefix}-hand-lizard-o:before { content: $fa-var-hand-lizard-o; }\n.#{$fa-css-prefix}-hand-spock-o:before { content: $fa-var-hand-spock-o; }\n.#{$fa-css-prefix}-hand-pointer-o:before { content: $fa-var-hand-pointer-o; }\n.#{$fa-css-prefix}-hand-peace-o:before { content: $fa-var-hand-peace-o; }\n.#{$fa-css-prefix}-trademark:before { content: $fa-var-trademark; }\n.#{$fa-css-prefix}-registered:before { content: $fa-var-registered; }\n.#{$fa-css-prefix}-creative-commons:before { content: $fa-var-creative-commons; }\n.#{$fa-css-prefix}-gg:before { content: $fa-var-gg; }\n.#{$fa-css-prefix}-gg-circle:before { content: $fa-var-gg-circle; }\n.#{$fa-css-prefix}-tripadvisor:before { content: $fa-var-tripadvisor; }\n.#{$fa-css-prefix}-odnoklassniki:before { content: $fa-var-odnoklassniki; }\n.#{$fa-css-prefix}-odnoklassniki-square:before { content: $fa-var-odnoklassniki-square; }\n.#{$fa-css-prefix}-get-pocket:before { content: $fa-var-get-pocket; }\n.#{$fa-css-prefix}-wikipedia-w:before { content: $fa-var-wikipedia-w; }\n.#{$fa-css-prefix}-safari:before { content: $fa-var-safari; }\n.#{$fa-css-prefix}-chrome:before { content: $fa-var-chrome; }\n.#{$fa-css-prefix}-firefox:before { content: $fa-var-firefox; }\n.#{$fa-css-prefix}-opera:before { content: $fa-var-opera; }\n.#{$fa-css-prefix}-internet-explorer:before { content: $fa-var-internet-explorer; }\n.#{$fa-css-prefix}-tv:before,\n.#{$fa-css-prefix}-television:before { content: $fa-var-television; }\n.#{$fa-css-prefix}-contao:before { content: $fa-var-contao; }\n.#{$fa-css-prefix}-500px:before { content: $fa-var-500px; }\n.#{$fa-css-prefix}-amazon:before { content: $fa-var-amazon; }\n.#{$fa-css-prefix}-calendar-plus-o:before { content: $fa-var-calendar-plus-o; }\n.#{$fa-css-prefix}-calendar-minus-o:before { content: $fa-var-calendar-minus-o; }\n.#{$fa-css-prefix}-calendar-times-o:before { content: $fa-var-calendar-times-o; }\n.#{$fa-css-prefix}-calendar-check-o:before { content: $fa-var-calendar-check-o; }\n.#{$fa-css-prefix}-industry:before { content: $fa-var-industry; }\n.#{$fa-css-prefix}-map-pin:before { content: $fa-var-map-pin; }\n.#{$fa-css-prefix}-map-signs:before { content: $fa-var-map-signs; }\n.#{$fa-css-prefix}-map-o:before { content: $fa-var-map-o; }\n.#{$fa-css-prefix}-map:before { content: $fa-var-map; }\n.#{$fa-css-prefix}-commenting:before { content: $fa-var-commenting; }\n.#{$fa-css-prefix}-commenting-o:before { content: $fa-var-commenting-o; }\n.#{$fa-css-prefix}-houzz:before { content: $fa-var-houzz; }\n.#{$fa-css-prefix}-vimeo:before { content: $fa-var-vimeo; }\n.#{$fa-css-prefix}-black-tie:before { content: $fa-var-black-tie; }\n.#{$fa-css-prefix}-fonticons:before { content: $fa-var-fonticons; }\n.#{$fa-css-prefix}-reddit-alien:before { content: $fa-var-reddit-alien; }\n.#{$fa-css-prefix}-edge:before { content: $fa-var-edge; }\n.#{$fa-css-prefix}-credit-card-alt:before { content: $fa-var-credit-card-alt; }\n.#{$fa-css-prefix}-codiepie:before { content: $fa-var-codiepie; }\n.#{$fa-css-prefix}-modx:before { content: $fa-var-modx; }\n.#{$fa-css-prefix}-fort-awesome:before { content: $fa-var-fort-awesome; }\n.#{$fa-css-prefix}-usb:before { content: $fa-var-usb; }\n.#{$fa-css-prefix}-product-hunt:before { content: $fa-var-product-hunt; }\n.#{$fa-css-prefix}-mixcloud:before { content: $fa-var-mixcloud; }\n.#{$fa-css-prefix}-scribd:before { content: $fa-var-scribd; }\n.#{$fa-css-prefix}-pause-circle:before { content: $fa-var-pause-circle; }\n.#{$fa-css-prefix}-pause-circle-o:before { content: $fa-var-pause-circle-o; }\n.#{$fa-css-prefix}-stop-circle:before { content: $fa-var-stop-circle; }\n.#{$fa-css-prefix}-stop-circle-o:before { content: $fa-var-stop-circle-o; }\n.#{$fa-css-prefix}-shopping-bag:before { content: $fa-var-shopping-bag; }\n.#{$fa-css-prefix}-shopping-basket:before { content: $fa-var-shopping-basket; }\n.#{$fa-css-prefix}-hashtag:before { content: $fa-var-hashtag; }\n.#{$fa-css-prefix}-bluetooth:before { content: $fa-var-bluetooth; }\n.#{$fa-css-prefix}-bluetooth-b:before { content: $fa-var-bluetooth-b; }\n.#{$fa-css-prefix}-percent:before { content: $fa-var-percent; }\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/_larger.scss",
    "content": "// Icon Sizes\n// -------------------------\n\n/* makes the font 33% larger relative to the icon container */\n.#{$fa-css-prefix}-lg {\n  font-size: (4em / 3);\n  line-height: (3em / 4);\n  vertical-align: -15%;\n}\n.#{$fa-css-prefix}-2x { font-size: 2em; }\n.#{$fa-css-prefix}-3x { font-size: 3em; }\n.#{$fa-css-prefix}-4x { font-size: 4em; }\n.#{$fa-css-prefix}-5x { font-size: 5em; }\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/_list.scss",
    "content": "// List Icons\n// -------------------------\n\n.#{$fa-css-prefix}-ul {\n  padding-left: 0;\n  margin-left: $fa-li-width;\n  list-style-type: none;\n  > li { position: relative; }\n}\n.#{$fa-css-prefix}-li {\n  position: absolute;\n  left: -$fa-li-width;\n  width: $fa-li-width;\n  top: (2em / 14);\n  text-align: center;\n  &.#{$fa-css-prefix}-lg {\n    left: -$fa-li-width + (4em / 14);\n  }\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/_mixins.scss",
    "content": "// Mixins\n// --------------------------\n\n@mixin fa-icon() {\n  display: inline-block;\n  font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration\n  font-size: inherit; // can't have font-size inherit on line above, so need to override\n  text-rendering: auto; // optimizelegibility throws things off #1094\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n\n}\n\n@mixin fa-icon-rotate($degrees, $rotation) {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation});\n  -webkit-transform: rotate($degrees);\n      -ms-transform: rotate($degrees);\n          transform: rotate($degrees);\n}\n\n@mixin fa-icon-flip($horiz, $vert, $rotation) {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation});\n  -webkit-transform: scale($horiz, $vert);\n      -ms-transform: scale($horiz, $vert);\n          transform: scale($horiz, $vert);\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/_path.scss",
    "content": "/* FONT PATH\n * -------------------------- */\n\n@font-face {\n  font-family: 'FontAwesome';\n  src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');\n  src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),\n    url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),\n    url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),\n    url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),\n    url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');\n//  src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts\n  font-weight: normal;\n  font-style: normal;\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/_rotated-flipped.scss",
    "content": "// Rotated & Flipped Icons\n// -------------------------\n\n.#{$fa-css-prefix}-rotate-90  { @include fa-icon-rotate(90deg, 1);  }\n.#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); }\n.#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); }\n\n.#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); }\n.#{$fa-css-prefix}-flip-vertical   { @include fa-icon-flip(1, -1, 2); }\n\n// Hook for IE8-9\n// -------------------------\n\n:root .#{$fa-css-prefix}-rotate-90,\n:root .#{$fa-css-prefix}-rotate-180,\n:root .#{$fa-css-prefix}-rotate-270,\n:root .#{$fa-css-prefix}-flip-horizontal,\n:root .#{$fa-css-prefix}-flip-vertical {\n  filter: none;\n}\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/_stacked.scss",
    "content": "// Stacked Icons\n// -------------------------\n\n.#{$fa-css-prefix}-stack {\n  position: relative;\n  display: inline-block;\n  width: 2em;\n  height: 2em;\n  line-height: 2em;\n  vertical-align: middle;\n}\n.#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x {\n  position: absolute;\n  left: 0;\n  width: 100%;\n  text-align: center;\n}\n.#{$fa-css-prefix}-stack-1x { line-height: inherit; }\n.#{$fa-css-prefix}-stack-2x { font-size: 2em; }\n.#{$fa-css-prefix}-inverse { color: $fa-inverse; }\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/_variables.scss",
    "content": "// Variables\n// --------------------------\n\n$fa-font-path:        \"../fonts\" !default;\n$fa-font-size-base:   14px !default;\n$fa-line-height-base: 1 !default;\n//$fa-font-path:        \"//netdna.bootstrapcdn.com/font-awesome/4.5.0/fonts\" !default; // for referencing Bootstrap CDN font files directly\n$fa-css-prefix:       fa !default;\n$fa-version:          \"4.5.0\" !default;\n$fa-border-color:     #eee !default;\n$fa-inverse:          #fff !default;\n$fa-li-width:         (30em / 14) !default;\n\n$fa-var-500px: \"\\f26e\";\n$fa-var-adjust: \"\\f042\";\n$fa-var-adn: \"\\f170\";\n$fa-var-align-center: \"\\f037\";\n$fa-var-align-justify: \"\\f039\";\n$fa-var-align-left: \"\\f036\";\n$fa-var-align-right: \"\\f038\";\n$fa-var-amazon: \"\\f270\";\n$fa-var-ambulance: \"\\f0f9\";\n$fa-var-anchor: \"\\f13d\";\n$fa-var-android: \"\\f17b\";\n$fa-var-angellist: \"\\f209\";\n$fa-var-angle-double-down: \"\\f103\";\n$fa-var-angle-double-left: \"\\f100\";\n$fa-var-angle-double-right: \"\\f101\";\n$fa-var-angle-double-up: \"\\f102\";\n$fa-var-angle-down: \"\\f107\";\n$fa-var-angle-left: \"\\f104\";\n$fa-var-angle-right: \"\\f105\";\n$fa-var-angle-up: \"\\f106\";\n$fa-var-apple: \"\\f179\";\n$fa-var-archive: \"\\f187\";\n$fa-var-area-chart: \"\\f1fe\";\n$fa-var-arrow-circle-down: \"\\f0ab\";\n$fa-var-arrow-circle-left: \"\\f0a8\";\n$fa-var-arrow-circle-o-down: \"\\f01a\";\n$fa-var-arrow-circle-o-left: \"\\f190\";\n$fa-var-arrow-circle-o-right: \"\\f18e\";\n$fa-var-arrow-circle-o-up: \"\\f01b\";\n$fa-var-arrow-circle-right: \"\\f0a9\";\n$fa-var-arrow-circle-up: \"\\f0aa\";\n$fa-var-arrow-down: \"\\f063\";\n$fa-var-arrow-left: \"\\f060\";\n$fa-var-arrow-right: \"\\f061\";\n$fa-var-arrow-up: \"\\f062\";\n$fa-var-arrows: \"\\f047\";\n$fa-var-arrows-alt: \"\\f0b2\";\n$fa-var-arrows-h: \"\\f07e\";\n$fa-var-arrows-v: \"\\f07d\";\n$fa-var-asterisk: \"\\f069\";\n$fa-var-at: \"\\f1fa\";\n$fa-var-automobile: \"\\f1b9\";\n$fa-var-backward: \"\\f04a\";\n$fa-var-balance-scale: \"\\f24e\";\n$fa-var-ban: \"\\f05e\";\n$fa-var-bank: \"\\f19c\";\n$fa-var-bar-chart: \"\\f080\";\n$fa-var-bar-chart-o: \"\\f080\";\n$fa-var-barcode: \"\\f02a\";\n$fa-var-bars: \"\\f0c9\";\n$fa-var-battery-0: \"\\f244\";\n$fa-var-battery-1: \"\\f243\";\n$fa-var-battery-2: \"\\f242\";\n$fa-var-battery-3: \"\\f241\";\n$fa-var-battery-4: \"\\f240\";\n$fa-var-battery-empty: \"\\f244\";\n$fa-var-battery-full: \"\\f240\";\n$fa-var-battery-half: \"\\f242\";\n$fa-var-battery-quarter: \"\\f243\";\n$fa-var-battery-three-quarters: \"\\f241\";\n$fa-var-bed: \"\\f236\";\n$fa-var-beer: \"\\f0fc\";\n$fa-var-behance: \"\\f1b4\";\n$fa-var-behance-square: \"\\f1b5\";\n$fa-var-bell: \"\\f0f3\";\n$fa-var-bell-o: \"\\f0a2\";\n$fa-var-bell-slash: \"\\f1f6\";\n$fa-var-bell-slash-o: \"\\f1f7\";\n$fa-var-bicycle: \"\\f206\";\n$fa-var-binoculars: \"\\f1e5\";\n$fa-var-birthday-cake: \"\\f1fd\";\n$fa-var-bitbucket: \"\\f171\";\n$fa-var-bitbucket-square: \"\\f172\";\n$fa-var-bitcoin: \"\\f15a\";\n$fa-var-black-tie: \"\\f27e\";\n$fa-var-bluetooth: \"\\f293\";\n$fa-var-bluetooth-b: \"\\f294\";\n$fa-var-bold: \"\\f032\";\n$fa-var-bolt: \"\\f0e7\";\n$fa-var-bomb: \"\\f1e2\";\n$fa-var-book: \"\\f02d\";\n$fa-var-bookmark: \"\\f02e\";\n$fa-var-bookmark-o: \"\\f097\";\n$fa-var-briefcase: \"\\f0b1\";\n$fa-var-btc: \"\\f15a\";\n$fa-var-bug: \"\\f188\";\n$fa-var-building: \"\\f1ad\";\n$fa-var-building-o: \"\\f0f7\";\n$fa-var-bullhorn: \"\\f0a1\";\n$fa-var-bullseye: \"\\f140\";\n$fa-var-bus: \"\\f207\";\n$fa-var-buysellads: \"\\f20d\";\n$fa-var-cab: \"\\f1ba\";\n$fa-var-calculator: \"\\f1ec\";\n$fa-var-calendar: \"\\f073\";\n$fa-var-calendar-check-o: \"\\f274\";\n$fa-var-calendar-minus-o: \"\\f272\";\n$fa-var-calendar-o: \"\\f133\";\n$fa-var-calendar-plus-o: \"\\f271\";\n$fa-var-calendar-times-o: \"\\f273\";\n$fa-var-camera: \"\\f030\";\n$fa-var-camera-retro: \"\\f083\";\n$fa-var-car: \"\\f1b9\";\n$fa-var-caret-down: \"\\f0d7\";\n$fa-var-caret-left: \"\\f0d9\";\n$fa-var-caret-right: \"\\f0da\";\n$fa-var-caret-square-o-down: \"\\f150\";\n$fa-var-caret-square-o-left: \"\\f191\";\n$fa-var-caret-square-o-right: \"\\f152\";\n$fa-var-caret-square-o-up: \"\\f151\";\n$fa-var-caret-up: \"\\f0d8\";\n$fa-var-cart-arrow-down: \"\\f218\";\n$fa-var-cart-plus: \"\\f217\";\n$fa-var-cc: \"\\f20a\";\n$fa-var-cc-amex: \"\\f1f3\";\n$fa-var-cc-diners-club: \"\\f24c\";\n$fa-var-cc-discover: \"\\f1f2\";\n$fa-var-cc-jcb: \"\\f24b\";\n$fa-var-cc-mastercard: \"\\f1f1\";\n$fa-var-cc-paypal: \"\\f1f4\";\n$fa-var-cc-stripe: \"\\f1f5\";\n$fa-var-cc-visa: \"\\f1f0\";\n$fa-var-certificate: \"\\f0a3\";\n$fa-var-chain: \"\\f0c1\";\n$fa-var-chain-broken: \"\\f127\";\n$fa-var-check: \"\\f00c\";\n$fa-var-check-circle: \"\\f058\";\n$fa-var-check-circle-o: \"\\f05d\";\n$fa-var-check-square: \"\\f14a\";\n$fa-var-check-square-o: \"\\f046\";\n$fa-var-chevron-circle-down: \"\\f13a\";\n$fa-var-chevron-circle-left: \"\\f137\";\n$fa-var-chevron-circle-right: \"\\f138\";\n$fa-var-chevron-circle-up: \"\\f139\";\n$fa-var-chevron-down: \"\\f078\";\n$fa-var-chevron-left: \"\\f053\";\n$fa-var-chevron-right: \"\\f054\";\n$fa-var-chevron-up: \"\\f077\";\n$fa-var-child: \"\\f1ae\";\n$fa-var-chrome: \"\\f268\";\n$fa-var-circle: \"\\f111\";\n$fa-var-circle-o: \"\\f10c\";\n$fa-var-circle-o-notch: \"\\f1ce\";\n$fa-var-circle-thin: \"\\f1db\";\n$fa-var-clipboard: \"\\f0ea\";\n$fa-var-clock-o: \"\\f017\";\n$fa-var-clone: \"\\f24d\";\n$fa-var-close: \"\\f00d\";\n$fa-var-cloud: \"\\f0c2\";\n$fa-var-cloud-download: \"\\f0ed\";\n$fa-var-cloud-upload: \"\\f0ee\";\n$fa-var-cny: \"\\f157\";\n$fa-var-code: \"\\f121\";\n$fa-var-code-fork: \"\\f126\";\n$fa-var-codepen: \"\\f1cb\";\n$fa-var-codiepie: \"\\f284\";\n$fa-var-coffee: \"\\f0f4\";\n$fa-var-cog: \"\\f013\";\n$fa-var-cogs: \"\\f085\";\n$fa-var-columns: \"\\f0db\";\n$fa-var-comment: \"\\f075\";\n$fa-var-comment-o: \"\\f0e5\";\n$fa-var-commenting: \"\\f27a\";\n$fa-var-commenting-o: \"\\f27b\";\n$fa-var-comments: \"\\f086\";\n$fa-var-comments-o: \"\\f0e6\";\n$fa-var-compass: \"\\f14e\";\n$fa-var-compress: \"\\f066\";\n$fa-var-connectdevelop: \"\\f20e\";\n$fa-var-contao: \"\\f26d\";\n$fa-var-copy: \"\\f0c5\";\n$fa-var-copyright: \"\\f1f9\";\n$fa-var-creative-commons: \"\\f25e\";\n$fa-var-credit-card: \"\\f09d\";\n$fa-var-credit-card-alt: \"\\f283\";\n$fa-var-crop: \"\\f125\";\n$fa-var-crosshairs: \"\\f05b\";\n$fa-var-css3: \"\\f13c\";\n$fa-var-cube: \"\\f1b2\";\n$fa-var-cubes: \"\\f1b3\";\n$fa-var-cut: \"\\f0c4\";\n$fa-var-cutlery: \"\\f0f5\";\n$fa-var-dashboard: \"\\f0e4\";\n$fa-var-dashcube: \"\\f210\";\n$fa-var-database: \"\\f1c0\";\n$fa-var-dedent: \"\\f03b\";\n$fa-var-delicious: \"\\f1a5\";\n$fa-var-desktop: \"\\f108\";\n$fa-var-deviantart: \"\\f1bd\";\n$fa-var-diamond: \"\\f219\";\n$fa-var-digg: \"\\f1a6\";\n$fa-var-dollar: \"\\f155\";\n$fa-var-dot-circle-o: \"\\f192\";\n$fa-var-download: \"\\f019\";\n$fa-var-dribbble: \"\\f17d\";\n$fa-var-dropbox: \"\\f16b\";\n$fa-var-drupal: \"\\f1a9\";\n$fa-var-edge: \"\\f282\";\n$fa-var-edit: \"\\f044\";\n$fa-var-eject: \"\\f052\";\n$fa-var-ellipsis-h: \"\\f141\";\n$fa-var-ellipsis-v: \"\\f142\";\n$fa-var-empire: \"\\f1d1\";\n$fa-var-envelope: \"\\f0e0\";\n$fa-var-envelope-o: \"\\f003\";\n$fa-var-envelope-square: \"\\f199\";\n$fa-var-eraser: \"\\f12d\";\n$fa-var-eur: \"\\f153\";\n$fa-var-euro: \"\\f153\";\n$fa-var-exchange: \"\\f0ec\";\n$fa-var-exclamation: \"\\f12a\";\n$fa-var-exclamation-circle: \"\\f06a\";\n$fa-var-exclamation-triangle: \"\\f071\";\n$fa-var-expand: \"\\f065\";\n$fa-var-expeditedssl: \"\\f23e\";\n$fa-var-external-link: \"\\f08e\";\n$fa-var-external-link-square: \"\\f14c\";\n$fa-var-eye: \"\\f06e\";\n$fa-var-eye-slash: \"\\f070\";\n$fa-var-eyedropper: \"\\f1fb\";\n$fa-var-facebook: \"\\f09a\";\n$fa-var-facebook-f: \"\\f09a\";\n$fa-var-facebook-official: \"\\f230\";\n$fa-var-facebook-square: \"\\f082\";\n$fa-var-fast-backward: \"\\f049\";\n$fa-var-fast-forward: \"\\f050\";\n$fa-var-fax: \"\\f1ac\";\n$fa-var-feed: \"\\f09e\";\n$fa-var-female: \"\\f182\";\n$fa-var-fighter-jet: \"\\f0fb\";\n$fa-var-file: \"\\f15b\";\n$fa-var-file-archive-o: \"\\f1c6\";\n$fa-var-file-audio-o: \"\\f1c7\";\n$fa-var-file-code-o: \"\\f1c9\";\n$fa-var-file-excel-o: \"\\f1c3\";\n$fa-var-file-image-o: \"\\f1c5\";\n$fa-var-file-movie-o: \"\\f1c8\";\n$fa-var-file-o: \"\\f016\";\n$fa-var-file-pdf-o: \"\\f1c1\";\n$fa-var-file-photo-o: \"\\f1c5\";\n$fa-var-file-picture-o: \"\\f1c5\";\n$fa-var-file-powerpoint-o: \"\\f1c4\";\n$fa-var-file-sound-o: \"\\f1c7\";\n$fa-var-file-text: \"\\f15c\";\n$fa-var-file-text-o: \"\\f0f6\";\n$fa-var-file-video-o: \"\\f1c8\";\n$fa-var-file-word-o: \"\\f1c2\";\n$fa-var-file-zip-o: \"\\f1c6\";\n$fa-var-files-o: \"\\f0c5\";\n$fa-var-film: \"\\f008\";\n$fa-var-filter: \"\\f0b0\";\n$fa-var-fire: \"\\f06d\";\n$fa-var-fire-extinguisher: \"\\f134\";\n$fa-var-firefox: \"\\f269\";\n$fa-var-flag: \"\\f024\";\n$fa-var-flag-checkered: \"\\f11e\";\n$fa-var-flag-o: \"\\f11d\";\n$fa-var-flash: \"\\f0e7\";\n$fa-var-flask: \"\\f0c3\";\n$fa-var-flickr: \"\\f16e\";\n$fa-var-floppy-o: \"\\f0c7\";\n$fa-var-folder: \"\\f07b\";\n$fa-var-folder-o: \"\\f114\";\n$fa-var-folder-open: \"\\f07c\";\n$fa-var-folder-open-o: \"\\f115\";\n$fa-var-font: \"\\f031\";\n$fa-var-fonticons: \"\\f280\";\n$fa-var-fort-awesome: \"\\f286\";\n$fa-var-forumbee: \"\\f211\";\n$fa-var-forward: \"\\f04e\";\n$fa-var-foursquare: \"\\f180\";\n$fa-var-frown-o: \"\\f119\";\n$fa-var-futbol-o: \"\\f1e3\";\n$fa-var-gamepad: \"\\f11b\";\n$fa-var-gavel: \"\\f0e3\";\n$fa-var-gbp: \"\\f154\";\n$fa-var-ge: \"\\f1d1\";\n$fa-var-gear: \"\\f013\";\n$fa-var-gears: \"\\f085\";\n$fa-var-genderless: \"\\f22d\";\n$fa-var-get-pocket: \"\\f265\";\n$fa-var-gg: \"\\f260\";\n$fa-var-gg-circle: \"\\f261\";\n$fa-var-gift: \"\\f06b\";\n$fa-var-git: \"\\f1d3\";\n$fa-var-git-square: \"\\f1d2\";\n$fa-var-github: \"\\f09b\";\n$fa-var-github-alt: \"\\f113\";\n$fa-var-github-square: \"\\f092\";\n$fa-var-gittip: \"\\f184\";\n$fa-var-glass: \"\\f000\";\n$fa-var-globe: \"\\f0ac\";\n$fa-var-google: \"\\f1a0\";\n$fa-var-google-plus: \"\\f0d5\";\n$fa-var-google-plus-square: \"\\f0d4\";\n$fa-var-google-wallet: \"\\f1ee\";\n$fa-var-graduation-cap: \"\\f19d\";\n$fa-var-gratipay: \"\\f184\";\n$fa-var-group: \"\\f0c0\";\n$fa-var-h-square: \"\\f0fd\";\n$fa-var-hacker-news: \"\\f1d4\";\n$fa-var-hand-grab-o: \"\\f255\";\n$fa-var-hand-lizard-o: \"\\f258\";\n$fa-var-hand-o-down: \"\\f0a7\";\n$fa-var-hand-o-left: \"\\f0a5\";\n$fa-var-hand-o-right: \"\\f0a4\";\n$fa-var-hand-o-up: \"\\f0a6\";\n$fa-var-hand-paper-o: \"\\f256\";\n$fa-var-hand-peace-o: \"\\f25b\";\n$fa-var-hand-pointer-o: \"\\f25a\";\n$fa-var-hand-rock-o: \"\\f255\";\n$fa-var-hand-scissors-o: \"\\f257\";\n$fa-var-hand-spock-o: \"\\f259\";\n$fa-var-hand-stop-o: \"\\f256\";\n$fa-var-hashtag: \"\\f292\";\n$fa-var-hdd-o: \"\\f0a0\";\n$fa-var-header: \"\\f1dc\";\n$fa-var-headphones: \"\\f025\";\n$fa-var-heart: \"\\f004\";\n$fa-var-heart-o: \"\\f08a\";\n$fa-var-heartbeat: \"\\f21e\";\n$fa-var-history: \"\\f1da\";\n$fa-var-home: \"\\f015\";\n$fa-var-hospital-o: \"\\f0f8\";\n$fa-var-hotel: \"\\f236\";\n$fa-var-hourglass: \"\\f254\";\n$fa-var-hourglass-1: \"\\f251\";\n$fa-var-hourglass-2: \"\\f252\";\n$fa-var-hourglass-3: \"\\f253\";\n$fa-var-hourglass-end: \"\\f253\";\n$fa-var-hourglass-half: \"\\f252\";\n$fa-var-hourglass-o: \"\\f250\";\n$fa-var-hourglass-start: \"\\f251\";\n$fa-var-houzz: \"\\f27c\";\n$fa-var-html5: \"\\f13b\";\n$fa-var-i-cursor: \"\\f246\";\n$fa-var-ils: \"\\f20b\";\n$fa-var-image: \"\\f03e\";\n$fa-var-inbox: \"\\f01c\";\n$fa-var-indent: \"\\f03c\";\n$fa-var-industry: \"\\f275\";\n$fa-var-info: \"\\f129\";\n$fa-var-info-circle: \"\\f05a\";\n$fa-var-inr: \"\\f156\";\n$fa-var-instagram: \"\\f16d\";\n$fa-var-institution: \"\\f19c\";\n$fa-var-internet-explorer: \"\\f26b\";\n$fa-var-intersex: \"\\f224\";\n$fa-var-ioxhost: \"\\f208\";\n$fa-var-italic: \"\\f033\";\n$fa-var-joomla: \"\\f1aa\";\n$fa-var-jpy: \"\\f157\";\n$fa-var-jsfiddle: \"\\f1cc\";\n$fa-var-key: \"\\f084\";\n$fa-var-keyboard-o: \"\\f11c\";\n$fa-var-krw: \"\\f159\";\n$fa-var-language: \"\\f1ab\";\n$fa-var-laptop: \"\\f109\";\n$fa-var-lastfm: \"\\f202\";\n$fa-var-lastfm-square: \"\\f203\";\n$fa-var-leaf: \"\\f06c\";\n$fa-var-leanpub: \"\\f212\";\n$fa-var-legal: \"\\f0e3\";\n$fa-var-lemon-o: \"\\f094\";\n$fa-var-level-down: \"\\f149\";\n$fa-var-level-up: \"\\f148\";\n$fa-var-life-bouy: \"\\f1cd\";\n$fa-var-life-buoy: \"\\f1cd\";\n$fa-var-life-ring: \"\\f1cd\";\n$fa-var-life-saver: \"\\f1cd\";\n$fa-var-lightbulb-o: \"\\f0eb\";\n$fa-var-line-chart: \"\\f201\";\n$fa-var-link: \"\\f0c1\";\n$fa-var-linkedin: \"\\f0e1\";\n$fa-var-linkedin-square: \"\\f08c\";\n$fa-var-linux: \"\\f17c\";\n$fa-var-list: \"\\f03a\";\n$fa-var-list-alt: \"\\f022\";\n$fa-var-list-ol: \"\\f0cb\";\n$fa-var-list-ul: \"\\f0ca\";\n$fa-var-location-arrow: \"\\f124\";\n$fa-var-lock: \"\\f023\";\n$fa-var-long-arrow-down: \"\\f175\";\n$fa-var-long-arrow-left: \"\\f177\";\n$fa-var-long-arrow-right: \"\\f178\";\n$fa-var-long-arrow-up: \"\\f176\";\n$fa-var-magic: \"\\f0d0\";\n$fa-var-magnet: \"\\f076\";\n$fa-var-mail-forward: \"\\f064\";\n$fa-var-mail-reply: \"\\f112\";\n$fa-var-mail-reply-all: \"\\f122\";\n$fa-var-male: \"\\f183\";\n$fa-var-map: \"\\f279\";\n$fa-var-map-marker: \"\\f041\";\n$fa-var-map-o: \"\\f278\";\n$fa-var-map-pin: \"\\f276\";\n$fa-var-map-signs: \"\\f277\";\n$fa-var-mars: \"\\f222\";\n$fa-var-mars-double: \"\\f227\";\n$fa-var-mars-stroke: \"\\f229\";\n$fa-var-mars-stroke-h: \"\\f22b\";\n$fa-var-mars-stroke-v: \"\\f22a\";\n$fa-var-maxcdn: \"\\f136\";\n$fa-var-meanpath: \"\\f20c\";\n$fa-var-medium: \"\\f23a\";\n$fa-var-medkit: \"\\f0fa\";\n$fa-var-meh-o: \"\\f11a\";\n$fa-var-mercury: \"\\f223\";\n$fa-var-microphone: \"\\f130\";\n$fa-var-microphone-slash: \"\\f131\";\n$fa-var-minus: \"\\f068\";\n$fa-var-minus-circle: \"\\f056\";\n$fa-var-minus-square: \"\\f146\";\n$fa-var-minus-square-o: \"\\f147\";\n$fa-var-mixcloud: \"\\f289\";\n$fa-var-mobile: \"\\f10b\";\n$fa-var-mobile-phone: \"\\f10b\";\n$fa-var-modx: \"\\f285\";\n$fa-var-money: \"\\f0d6\";\n$fa-var-moon-o: \"\\f186\";\n$fa-var-mortar-board: \"\\f19d\";\n$fa-var-motorcycle: \"\\f21c\";\n$fa-var-mouse-pointer: \"\\f245\";\n$fa-var-music: \"\\f001\";\n$fa-var-navicon: \"\\f0c9\";\n$fa-var-neuter: \"\\f22c\";\n$fa-var-newspaper-o: \"\\f1ea\";\n$fa-var-object-group: \"\\f247\";\n$fa-var-object-ungroup: \"\\f248\";\n$fa-var-odnoklassniki: \"\\f263\";\n$fa-var-odnoklassniki-square: \"\\f264\";\n$fa-var-opencart: \"\\f23d\";\n$fa-var-openid: \"\\f19b\";\n$fa-var-opera: \"\\f26a\";\n$fa-var-optin-monster: \"\\f23c\";\n$fa-var-outdent: \"\\f03b\";\n$fa-var-pagelines: \"\\f18c\";\n$fa-var-paint-brush: \"\\f1fc\";\n$fa-var-paper-plane: \"\\f1d8\";\n$fa-var-paper-plane-o: \"\\f1d9\";\n$fa-var-paperclip: \"\\f0c6\";\n$fa-var-paragraph: \"\\f1dd\";\n$fa-var-paste: \"\\f0ea\";\n$fa-var-pause: \"\\f04c\";\n$fa-var-pause-circle: \"\\f28b\";\n$fa-var-pause-circle-o: \"\\f28c\";\n$fa-var-paw: \"\\f1b0\";\n$fa-var-paypal: \"\\f1ed\";\n$fa-var-pencil: \"\\f040\";\n$fa-var-pencil-square: \"\\f14b\";\n$fa-var-pencil-square-o: \"\\f044\";\n$fa-var-percent: \"\\f295\";\n$fa-var-phone: \"\\f095\";\n$fa-var-phone-square: \"\\f098\";\n$fa-var-photo: \"\\f03e\";\n$fa-var-picture-o: \"\\f03e\";\n$fa-var-pie-chart: \"\\f200\";\n$fa-var-pied-piper: \"\\f1a7\";\n$fa-var-pied-piper-alt: \"\\f1a8\";\n$fa-var-pinterest: \"\\f0d2\";\n$fa-var-pinterest-p: \"\\f231\";\n$fa-var-pinterest-square: \"\\f0d3\";\n$fa-var-plane: \"\\f072\";\n$fa-var-play: \"\\f04b\";\n$fa-var-play-circle: \"\\f144\";\n$fa-var-play-circle-o: \"\\f01d\";\n$fa-var-plug: \"\\f1e6\";\n$fa-var-plus: \"\\f067\";\n$fa-var-plus-circle: \"\\f055\";\n$fa-var-plus-square: \"\\f0fe\";\n$fa-var-plus-square-o: \"\\f196\";\n$fa-var-power-off: \"\\f011\";\n$fa-var-print: \"\\f02f\";\n$fa-var-product-hunt: \"\\f288\";\n$fa-var-puzzle-piece: \"\\f12e\";\n$fa-var-qq: \"\\f1d6\";\n$fa-var-qrcode: \"\\f029\";\n$fa-var-question: \"\\f128\";\n$fa-var-question-circle: \"\\f059\";\n$fa-var-quote-left: \"\\f10d\";\n$fa-var-quote-right: \"\\f10e\";\n$fa-var-ra: \"\\f1d0\";\n$fa-var-random: \"\\f074\";\n$fa-var-rebel: \"\\f1d0\";\n$fa-var-recycle: \"\\f1b8\";\n$fa-var-reddit: \"\\f1a1\";\n$fa-var-reddit-alien: \"\\f281\";\n$fa-var-reddit-square: \"\\f1a2\";\n$fa-var-refresh: \"\\f021\";\n$fa-var-registered: \"\\f25d\";\n$fa-var-remove: \"\\f00d\";\n$fa-var-renren: \"\\f18b\";\n$fa-var-reorder: \"\\f0c9\";\n$fa-var-repeat: \"\\f01e\";\n$fa-var-reply: \"\\f112\";\n$fa-var-reply-all: \"\\f122\";\n$fa-var-retweet: \"\\f079\";\n$fa-var-rmb: \"\\f157\";\n$fa-var-road: \"\\f018\";\n$fa-var-rocket: \"\\f135\";\n$fa-var-rotate-left: \"\\f0e2\";\n$fa-var-rotate-right: \"\\f01e\";\n$fa-var-rouble: \"\\f158\";\n$fa-var-rss: \"\\f09e\";\n$fa-var-rss-square: \"\\f143\";\n$fa-var-rub: \"\\f158\";\n$fa-var-ruble: \"\\f158\";\n$fa-var-rupee: \"\\f156\";\n$fa-var-safari: \"\\f267\";\n$fa-var-save: \"\\f0c7\";\n$fa-var-scissors: \"\\f0c4\";\n$fa-var-scribd: \"\\f28a\";\n$fa-var-search: \"\\f002\";\n$fa-var-search-minus: \"\\f010\";\n$fa-var-search-plus: \"\\f00e\";\n$fa-var-sellsy: \"\\f213\";\n$fa-var-send: \"\\f1d8\";\n$fa-var-send-o: \"\\f1d9\";\n$fa-var-server: \"\\f233\";\n$fa-var-share: \"\\f064\";\n$fa-var-share-alt: \"\\f1e0\";\n$fa-var-share-alt-square: \"\\f1e1\";\n$fa-var-share-square: \"\\f14d\";\n$fa-var-share-square-o: \"\\f045\";\n$fa-var-shekel: \"\\f20b\";\n$fa-var-sheqel: \"\\f20b\";\n$fa-var-shield: \"\\f132\";\n$fa-var-ship: \"\\f21a\";\n$fa-var-shirtsinbulk: \"\\f214\";\n$fa-var-shopping-bag: \"\\f290\";\n$fa-var-shopping-basket: \"\\f291\";\n$fa-var-shopping-cart: \"\\f07a\";\n$fa-var-sign-in: \"\\f090\";\n$fa-var-sign-out: \"\\f08b\";\n$fa-var-signal: \"\\f012\";\n$fa-var-simplybuilt: \"\\f215\";\n$fa-var-sitemap: \"\\f0e8\";\n$fa-var-skyatlas: \"\\f216\";\n$fa-var-skype: \"\\f17e\";\n$fa-var-slack: \"\\f198\";\n$fa-var-sliders: \"\\f1de\";\n$fa-var-slideshare: \"\\f1e7\";\n$fa-var-smile-o: \"\\f118\";\n$fa-var-soccer-ball-o: \"\\f1e3\";\n$fa-var-sort: \"\\f0dc\";\n$fa-var-sort-alpha-asc: \"\\f15d\";\n$fa-var-sort-alpha-desc: \"\\f15e\";\n$fa-var-sort-amount-asc: \"\\f160\";\n$fa-var-sort-amount-desc: \"\\f161\";\n$fa-var-sort-asc: \"\\f0de\";\n$fa-var-sort-desc: \"\\f0dd\";\n$fa-var-sort-down: \"\\f0dd\";\n$fa-var-sort-numeric-asc: \"\\f162\";\n$fa-var-sort-numeric-desc: \"\\f163\";\n$fa-var-sort-up: \"\\f0de\";\n$fa-var-soundcloud: \"\\f1be\";\n$fa-var-space-shuttle: \"\\f197\";\n$fa-var-spinner: \"\\f110\";\n$fa-var-spoon: \"\\f1b1\";\n$fa-var-spotify: \"\\f1bc\";\n$fa-var-square: \"\\f0c8\";\n$fa-var-square-o: \"\\f096\";\n$fa-var-stack-exchange: \"\\f18d\";\n$fa-var-stack-overflow: \"\\f16c\";\n$fa-var-star: \"\\f005\";\n$fa-var-star-half: \"\\f089\";\n$fa-var-star-half-empty: \"\\f123\";\n$fa-var-star-half-full: \"\\f123\";\n$fa-var-star-half-o: \"\\f123\";\n$fa-var-star-o: \"\\f006\";\n$fa-var-steam: \"\\f1b6\";\n$fa-var-steam-square: \"\\f1b7\";\n$fa-var-step-backward: \"\\f048\";\n$fa-var-step-forward: \"\\f051\";\n$fa-var-stethoscope: \"\\f0f1\";\n$fa-var-sticky-note: \"\\f249\";\n$fa-var-sticky-note-o: \"\\f24a\";\n$fa-var-stop: \"\\f04d\";\n$fa-var-stop-circle: \"\\f28d\";\n$fa-var-stop-circle-o: \"\\f28e\";\n$fa-var-street-view: \"\\f21d\";\n$fa-var-strikethrough: \"\\f0cc\";\n$fa-var-stumbleupon: \"\\f1a4\";\n$fa-var-stumbleupon-circle: \"\\f1a3\";\n$fa-var-subscript: \"\\f12c\";\n$fa-var-subway: \"\\f239\";\n$fa-var-suitcase: \"\\f0f2\";\n$fa-var-sun-o: \"\\f185\";\n$fa-var-superscript: \"\\f12b\";\n$fa-var-support: \"\\f1cd\";\n$fa-var-table: \"\\f0ce\";\n$fa-var-tablet: \"\\f10a\";\n$fa-var-tachometer: \"\\f0e4\";\n$fa-var-tag: \"\\f02b\";\n$fa-var-tags: \"\\f02c\";\n$fa-var-tasks: \"\\f0ae\";\n$fa-var-taxi: \"\\f1ba\";\n$fa-var-television: \"\\f26c\";\n$fa-var-tencent-weibo: \"\\f1d5\";\n$fa-var-terminal: \"\\f120\";\n$fa-var-text-height: \"\\f034\";\n$fa-var-text-width: \"\\f035\";\n$fa-var-th: \"\\f00a\";\n$fa-var-th-large: \"\\f009\";\n$fa-var-th-list: \"\\f00b\";\n$fa-var-thumb-tack: \"\\f08d\";\n$fa-var-thumbs-down: \"\\f165\";\n$fa-var-thumbs-o-down: \"\\f088\";\n$fa-var-thumbs-o-up: \"\\f087\";\n$fa-var-thumbs-up: \"\\f164\";\n$fa-var-ticket: \"\\f145\";\n$fa-var-times: \"\\f00d\";\n$fa-var-times-circle: \"\\f057\";\n$fa-var-times-circle-o: \"\\f05c\";\n$fa-var-tint: \"\\f043\";\n$fa-var-toggle-down: \"\\f150\";\n$fa-var-toggle-left: \"\\f191\";\n$fa-var-toggle-off: \"\\f204\";\n$fa-var-toggle-on: \"\\f205\";\n$fa-var-toggle-right: \"\\f152\";\n$fa-var-toggle-up: \"\\f151\";\n$fa-var-trademark: \"\\f25c\";\n$fa-var-train: \"\\f238\";\n$fa-var-transgender: \"\\f224\";\n$fa-var-transgender-alt: \"\\f225\";\n$fa-var-trash: \"\\f1f8\";\n$fa-var-trash-o: \"\\f014\";\n$fa-var-tree: \"\\f1bb\";\n$fa-var-trello: \"\\f181\";\n$fa-var-tripadvisor: \"\\f262\";\n$fa-var-trophy: \"\\f091\";\n$fa-var-truck: \"\\f0d1\";\n$fa-var-try: \"\\f195\";\n$fa-var-tty: \"\\f1e4\";\n$fa-var-tumblr: \"\\f173\";\n$fa-var-tumblr-square: \"\\f174\";\n$fa-var-turkish-lira: \"\\f195\";\n$fa-var-tv: \"\\f26c\";\n$fa-var-twitch: \"\\f1e8\";\n$fa-var-twitter: \"\\f099\";\n$fa-var-twitter-square: \"\\f081\";\n$fa-var-umbrella: \"\\f0e9\";\n$fa-var-underline: \"\\f0cd\";\n$fa-var-undo: \"\\f0e2\";\n$fa-var-university: \"\\f19c\";\n$fa-var-unlink: \"\\f127\";\n$fa-var-unlock: \"\\f09c\";\n$fa-var-unlock-alt: \"\\f13e\";\n$fa-var-unsorted: \"\\f0dc\";\n$fa-var-upload: \"\\f093\";\n$fa-var-usb: \"\\f287\";\n$fa-var-usd: \"\\f155\";\n$fa-var-user: \"\\f007\";\n$fa-var-user-md: \"\\f0f0\";\n$fa-var-user-plus: \"\\f234\";\n$fa-var-user-secret: \"\\f21b\";\n$fa-var-user-times: \"\\f235\";\n$fa-var-users: \"\\f0c0\";\n$fa-var-venus: \"\\f221\";\n$fa-var-venus-double: \"\\f226\";\n$fa-var-venus-mars: \"\\f228\";\n$fa-var-viacoin: \"\\f237\";\n$fa-var-video-camera: \"\\f03d\";\n$fa-var-vimeo: \"\\f27d\";\n$fa-var-vimeo-square: \"\\f194\";\n$fa-var-vine: \"\\f1ca\";\n$fa-var-vk: \"\\f189\";\n$fa-var-volume-down: \"\\f027\";\n$fa-var-volume-off: \"\\f026\";\n$fa-var-volume-up: \"\\f028\";\n$fa-var-warning: \"\\f071\";\n$fa-var-wechat: \"\\f1d7\";\n$fa-var-weibo: \"\\f18a\";\n$fa-var-weixin: \"\\f1d7\";\n$fa-var-whatsapp: \"\\f232\";\n$fa-var-wheelchair: \"\\f193\";\n$fa-var-wifi: \"\\f1eb\";\n$fa-var-wikipedia-w: \"\\f266\";\n$fa-var-windows: \"\\f17a\";\n$fa-var-won: \"\\f159\";\n$fa-var-wordpress: \"\\f19a\";\n$fa-var-wrench: \"\\f0ad\";\n$fa-var-xing: \"\\f168\";\n$fa-var-xing-square: \"\\f169\";\n$fa-var-y-combinator: \"\\f23b\";\n$fa-var-y-combinator-square: \"\\f1d4\";\n$fa-var-yahoo: \"\\f19e\";\n$fa-var-yc: \"\\f23b\";\n$fa-var-yc-square: \"\\f1d4\";\n$fa-var-yelp: \"\\f1e9\";\n$fa-var-yen: \"\\f157\";\n$fa-var-youtube: \"\\f167\";\n$fa-var-youtube-play: \"\\f16a\";\n$fa-var-youtube-square: \"\\f166\";\n\n"
  },
  {
    "path": "resources/public/font-awesome-4.5.0/scss/font-awesome.scss",
    "content": "/*!\n *  Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)\n */\n\n@import \"variables\";\n@import \"mixins\";\n@import \"path\";\n@import \"core\";\n@import \"larger\";\n@import \"fixed-width\";\n@import \"list\";\n@import \"bordered-pulled\";\n@import \"animated\";\n@import \"rotated-flipped\";\n@import \"stacked\";\n@import \"icons\";\n"
  },
  {
    "path": "resources/public/fonts/Lekton/SIL Open Font License.txt",
    "content": "This Font Software is licensed under the SIL Open Font License, Version 1.1.\nThis license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL\n\n-----------------------------------------------------------\nSIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\n-----------------------------------------------------------\n\nPREAMBLE\nThe goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.\n\nThe OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.\n\nDEFINITIONS\n\"Font Software\" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.\n\n\"Reserved Font Name\" refers to any names specified as such after the copyright statement(s).\n\n\"Original Version\" refers to the collection of Font Software components as distributed by the Copyright Holder(s).\n\n\"Modified Version\" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.\n\n\"Author\" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.\n\nPERMISSION & CONDITIONS\nPermission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:\n\n1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.\n\n2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.\n\n3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.\n\n4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.\n\n5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.\n\nTERMINATION\nThis license becomes null and void if any of the above conditions are not met.\n\nDISCLAIMER\nTHE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE."
  },
  {
    "path": "resources/public/fonts/Open_Sans_Condensed/LICENSE.txt",
    "content": "\r\n                                 Apache License\r\n                           Version 2.0, January 2004\r\n                        http://www.apache.org/licenses/\r\n\r\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r\n\r\n   1. Definitions.\r\n\r\n      \"License\" shall mean the terms and conditions for use, reproduction,\r\n      and distribution as defined by Sections 1 through 9 of this document.\r\n\r\n      \"Licensor\" shall mean the copyright owner or entity authorized by\r\n      the copyright owner that is granting the License.\r\n\r\n      \"Legal Entity\" shall mean the union of the acting entity and all\r\n      other entities that control, are controlled by, or are under common\r\n      control with that entity. For the purposes of this definition,\r\n      \"control\" means (i) the power, direct or indirect, to cause the\r\n      direction or management of such entity, whether by contract or\r\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r\n      outstanding shares, or (iii) beneficial ownership of such entity.\r\n\r\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\r\n      exercising permissions granted by this License.\r\n\r\n      \"Source\" form shall mean the preferred form for making modifications,\r\n      including but not limited to software source code, documentation\r\n      source, and configuration files.\r\n\r\n      \"Object\" form shall mean any form resulting from mechanical\r\n      transformation or translation of a Source form, including but\r\n      not limited to compiled object code, generated documentation,\r\n      and conversions to other media types.\r\n\r\n      \"Work\" shall mean the work of authorship, whether in Source or\r\n      Object form, made available under the License, as indicated by a\r\n      copyright notice that is included in or attached to the work\r\n      (an example is provided in the Appendix below).\r\n\r\n      \"Derivative Works\" shall mean any work, whether in Source or Object\r\n      form, that is based on (or derived from) the Work and for which the\r\n      editorial revisions, annotations, elaborations, or other modifications\r\n      represent, as a whole, an original work of authorship. For the purposes\r\n      of this License, Derivative Works shall not include works that remain\r\n      separable from, or merely link (or bind by name) to the interfaces of,\r\n      the Work and Derivative Works thereof.\r\n\r\n      \"Contribution\" shall mean any work of authorship, including\r\n      the original version of the Work and any modifications or additions\r\n      to that Work or Derivative Works thereof, that is intentionally\r\n      submitted to Licensor for inclusion in the Work by the copyright owner\r\n      or by an individual or Legal Entity authorized to submit on behalf of\r\n      the copyright owner. For the purposes of this definition, \"submitted\"\r\n      means any form of electronic, verbal, or written communication sent\r\n      to the Licensor or its representatives, including but not limited to\r\n      communication on electronic mailing lists, source code control systems,\r\n      and issue tracking systems that are managed by, or on behalf of, the\r\n      Licensor for the purpose of discussing and improving the Work, but\r\n      excluding communication that is conspicuously marked or otherwise\r\n      designated in writing by the copyright owner as \"Not a Contribution.\"\r\n\r\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\r\n      on behalf of whom a Contribution has been received by Licensor and\r\n      subsequently incorporated within the Work.\r\n\r\n   2. Grant of Copyright License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      copyright license to reproduce, prepare Derivative Works of,\r\n      publicly display, publicly perform, sublicense, and distribute the\r\n      Work and such Derivative Works in Source or Object form.\r\n\r\n   3. Grant of Patent License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      (except as stated in this section) patent license to make, have made,\r\n      use, offer to sell, sell, import, and otherwise transfer the Work,\r\n      where such license applies only to those patent claims licensable\r\n      by such Contributor that are necessarily infringed by their\r\n      Contribution(s) alone or by combination of their Contribution(s)\r\n      with the Work to which such Contribution(s) was submitted. If You\r\n      institute patent litigation against any entity (including a\r\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\r\n      or a Contribution incorporated within the Work constitutes direct\r\n      or contributory patent infringement, then any patent licenses\r\n      granted to You under this License for that Work shall terminate\r\n      as of the date such litigation is filed.\r\n\r\n   4. Redistribution. You may reproduce and distribute copies of the\r\n      Work or Derivative Works thereof in any medium, with or without\r\n      modifications, and in Source or Object form, provided that You\r\n      meet the following conditions:\r\n\r\n      (a) You must give any other recipients of the Work or\r\n          Derivative Works a copy of this License; and\r\n\r\n      (b) You must cause any modified files to carry prominent notices\r\n          stating that You changed the files; and\r\n\r\n      (c) You must retain, in the Source form of any Derivative Works\r\n          that You distribute, all copyright, patent, trademark, and\r\n          attribution notices from the Source form of the Work,\r\n          excluding those notices that do not pertain to any part of\r\n          the Derivative Works; and\r\n\r\n      (d) If the Work includes a \"NOTICE\" text file as part of its\r\n          distribution, then any Derivative Works that You distribute must\r\n          include a readable copy of the attribution notices contained\r\n          within such NOTICE file, excluding those notices that do not\r\n          pertain to any part of the Derivative Works, in at least one\r\n          of the following places: within a NOTICE text file distributed\r\n          as part of the Derivative Works; within the Source form or\r\n          documentation, if provided along with the Derivative Works; or,\r\n          within a display generated by the Derivative Works, if and\r\n          wherever such third-party notices normally appear. The contents\r\n          of the NOTICE file are for informational purposes only and\r\n          do not modify the License. You may add Your own attribution\r\n          notices within Derivative Works that You distribute, alongside\r\n          or as an addendum to the NOTICE text from the Work, provided\r\n          that such additional attribution notices cannot be construed\r\n          as modifying the License.\r\n\r\n      You may add Your own copyright statement to Your modifications and\r\n      may provide additional or different license terms and conditions\r\n      for use, reproduction, or distribution of Your modifications, or\r\n      for any such Derivative Works as a whole, provided Your use,\r\n      reproduction, and distribution of the Work otherwise complies with\r\n      the conditions stated in this License.\r\n\r\n   5. Submission of Contributions. Unless You explicitly state otherwise,\r\n      any Contribution intentionally submitted for inclusion in the Work\r\n      by You to the Licensor shall be under the terms and conditions of\r\n      this License, without any additional terms or conditions.\r\n      Notwithstanding the above, nothing herein shall supersede or modify\r\n      the terms of any separate license agreement you may have executed\r\n      with Licensor regarding such Contributions.\r\n\r\n   6. Trademarks. This License does not grant permission to use the trade\r\n      names, trademarks, service marks, or product names of the Licensor,\r\n      except as required for reasonable and customary use in describing the\r\n      origin of the Work and reproducing the content of the NOTICE file.\r\n\r\n   7. Disclaimer of Warranty. Unless required by applicable law or\r\n      agreed to in writing, Licensor provides the Work (and each\r\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\r\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r\n      implied, including, without limitation, any warranties or conditions\r\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r\n      PARTICULAR PURPOSE. You are solely responsible for determining the\r\n      appropriateness of using or redistributing the Work and assume any\r\n      risks associated with Your exercise of permissions under this License.\r\n\r\n   8. Limitation of Liability. In no event and under no legal theory,\r\n      whether in tort (including negligence), contract, or otherwise,\r\n      unless required by applicable law (such as deliberate and grossly\r\n      negligent acts) or agreed to in writing, shall any Contributor be\r\n      liable to You for damages, including any direct, indirect, special,\r\n      incidental, or consequential damages of any character arising as a\r\n      result of this License or out of the use or inability to use the\r\n      Work (including but not limited to damages for loss of goodwill,\r\n      work stoppage, computer failure or malfunction, or any and all\r\n      other commercial damages or losses), even if such Contributor\r\n      has been advised of the possibility of such damages.\r\n\r\n   9. Accepting Warranty or Additional Liability. While redistributing\r\n      the Work or Derivative Works thereof, You may choose to offer,\r\n      and charge a fee for, acceptance of support, warranty, indemnity,\r\n      or other liability obligations and/or rights consistent with this\r\n      License. However, in accepting such obligations, You may act only\r\n      on Your own behalf and on Your sole responsibility, not on behalf\r\n      of any other Contributor, and only if You agree to indemnify,\r\n      defend, and hold each Contributor harmless for any liability\r\n      incurred by, or claims asserted against, such Contributor by reason\r\n      of your accepting any such warranty or additional liability.\r\n\r\n   END OF TERMS AND CONDITIONS\r\n\r\n   APPENDIX: How to apply the Apache License to your work.\r\n\r\n      To apply the Apache License to your work, attach the following\r\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\r\n      replaced with your own identifying information. (Don't include\r\n      the brackets!)  The text should be enclosed in the appropriate\r\n      comment syntax for the file format. We also recommend that a\r\n      file or class name and description of purpose be included on the\r\n      same \"printed page\" as the copyright notice for easier\r\n      identification within third-party archives.\r\n\r\n   Copyright [yyyy] [name of copyright owner]\r\n\r\n   Licensed under the Apache License, Version 2.0 (the \"License\");\r\n   you may not use this file except in compliance with the License.\r\n   You may obtain a copy of the License at\r\n\r\n       http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n   Unless required by applicable law or agreed to in writing, software\r\n   distributed under the License is distributed on an \"AS IS\" BASIS,\r\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n   See the License for the specific language governing permissions and\r\n   limitations under the License.\r\n"
  },
  {
    "path": "resources/public/fonts/Roboto/LICENSE.txt",
    "content": "\r\n                                 Apache License\r\n                           Version 2.0, January 2004\r\n                        http://www.apache.org/licenses/\r\n\r\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r\n\r\n   1. Definitions.\r\n\r\n      \"License\" shall mean the terms and conditions for use, reproduction,\r\n      and distribution as defined by Sections 1 through 9 of this document.\r\n\r\n      \"Licensor\" shall mean the copyright owner or entity authorized by\r\n      the copyright owner that is granting the License.\r\n\r\n      \"Legal Entity\" shall mean the union of the acting entity and all\r\n      other entities that control, are controlled by, or are under common\r\n      control with that entity. For the purposes of this definition,\r\n      \"control\" means (i) the power, direct or indirect, to cause the\r\n      direction or management of such entity, whether by contract or\r\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r\n      outstanding shares, or (iii) beneficial ownership of such entity.\r\n\r\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\r\n      exercising permissions granted by this License.\r\n\r\n      \"Source\" form shall mean the preferred form for making modifications,\r\n      including but not limited to software source code, documentation\r\n      source, and configuration files.\r\n\r\n      \"Object\" form shall mean any form resulting from mechanical\r\n      transformation or translation of a Source form, including but\r\n      not limited to compiled object code, generated documentation,\r\n      and conversions to other media types.\r\n\r\n      \"Work\" shall mean the work of authorship, whether in Source or\r\n      Object form, made available under the License, as indicated by a\r\n      copyright notice that is included in or attached to the work\r\n      (an example is provided in the Appendix below).\r\n\r\n      \"Derivative Works\" shall mean any work, whether in Source or Object\r\n      form, that is based on (or derived from) the Work and for which the\r\n      editorial revisions, annotations, elaborations, or other modifications\r\n      represent, as a whole, an original work of authorship. For the purposes\r\n      of this License, Derivative Works shall not include works that remain\r\n      separable from, or merely link (or bind by name) to the interfaces of,\r\n      the Work and Derivative Works thereof.\r\n\r\n      \"Contribution\" shall mean any work of authorship, including\r\n      the original version of the Work and any modifications or additions\r\n      to that Work or Derivative Works thereof, that is intentionally\r\n      submitted to Licensor for inclusion in the Work by the copyright owner\r\n      or by an individual or Legal Entity authorized to submit on behalf of\r\n      the copyright owner. For the purposes of this definition, \"submitted\"\r\n      means any form of electronic, verbal, or written communication sent\r\n      to the Licensor or its representatives, including but not limited to\r\n      communication on electronic mailing lists, source code control systems,\r\n      and issue tracking systems that are managed by, or on behalf of, the\r\n      Licensor for the purpose of discussing and improving the Work, but\r\n      excluding communication that is conspicuously marked or otherwise\r\n      designated in writing by the copyright owner as \"Not a Contribution.\"\r\n\r\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\r\n      on behalf of whom a Contribution has been received by Licensor and\r\n      subsequently incorporated within the Work.\r\n\r\n   2. Grant of Copyright License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      copyright license to reproduce, prepare Derivative Works of,\r\n      publicly display, publicly perform, sublicense, and distribute the\r\n      Work and such Derivative Works in Source or Object form.\r\n\r\n   3. Grant of Patent License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      (except as stated in this section) patent license to make, have made,\r\n      use, offer to sell, sell, import, and otherwise transfer the Work,\r\n      where such license applies only to those patent claims licensable\r\n      by such Contributor that are necessarily infringed by their\r\n      Contribution(s) alone or by combination of their Contribution(s)\r\n      with the Work to which such Contribution(s) was submitted. If You\r\n      institute patent litigation against any entity (including a\r\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\r\n      or a Contribution incorporated within the Work constitutes direct\r\n      or contributory patent infringement, then any patent licenses\r\n      granted to You under this License for that Work shall terminate\r\n      as of the date such litigation is filed.\r\n\r\n   4. Redistribution. You may reproduce and distribute copies of the\r\n      Work or Derivative Works thereof in any medium, with or without\r\n      modifications, and in Source or Object form, provided that You\r\n      meet the following conditions:\r\n\r\n      (a) You must give any other recipients of the Work or\r\n          Derivative Works a copy of this License; and\r\n\r\n      (b) You must cause any modified files to carry prominent notices\r\n          stating that You changed the files; and\r\n\r\n      (c) You must retain, in the Source form of any Derivative Works\r\n          that You distribute, all copyright, patent, trademark, and\r\n          attribution notices from the Source form of the Work,\r\n          excluding those notices that do not pertain to any part of\r\n          the Derivative Works; and\r\n\r\n      (d) If the Work includes a \"NOTICE\" text file as part of its\r\n          distribution, then any Derivative Works that You distribute must\r\n          include a readable copy of the attribution notices contained\r\n          within such NOTICE file, excluding those notices that do not\r\n          pertain to any part of the Derivative Works, in at least one\r\n          of the following places: within a NOTICE text file distributed\r\n          as part of the Derivative Works; within the Source form or\r\n          documentation, if provided along with the Derivative Works; or,\r\n          within a display generated by the Derivative Works, if and\r\n          wherever such third-party notices normally appear. The contents\r\n          of the NOTICE file are for informational purposes only and\r\n          do not modify the License. You may add Your own attribution\r\n          notices within Derivative Works that You distribute, alongside\r\n          or as an addendum to the NOTICE text from the Work, provided\r\n          that such additional attribution notices cannot be construed\r\n          as modifying the License.\r\n\r\n      You may add Your own copyright statement to Your modifications and\r\n      may provide additional or different license terms and conditions\r\n      for use, reproduction, or distribution of Your modifications, or\r\n      for any such Derivative Works as a whole, provided Your use,\r\n      reproduction, and distribution of the Work otherwise complies with\r\n      the conditions stated in this License.\r\n\r\n   5. Submission of Contributions. Unless You explicitly state otherwise,\r\n      any Contribution intentionally submitted for inclusion in the Work\r\n      by You to the Licensor shall be under the terms and conditions of\r\n      this License, without any additional terms or conditions.\r\n      Notwithstanding the above, nothing herein shall supersede or modify\r\n      the terms of any separate license agreement you may have executed\r\n      with Licensor regarding such Contributions.\r\n\r\n   6. Trademarks. This License does not grant permission to use the trade\r\n      names, trademarks, service marks, or product names of the Licensor,\r\n      except as required for reasonable and customary use in describing the\r\n      origin of the Work and reproducing the content of the NOTICE file.\r\n\r\n   7. Disclaimer of Warranty. Unless required by applicable law or\r\n      agreed to in writing, Licensor provides the Work (and each\r\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\r\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r\n      implied, including, without limitation, any warranties or conditions\r\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r\n      PARTICULAR PURPOSE. You are solely responsible for determining the\r\n      appropriateness of using or redistributing the Work and assume any\r\n      risks associated with Your exercise of permissions under this License.\r\n\r\n   8. Limitation of Liability. In no event and under no legal theory,\r\n      whether in tort (including negligence), contract, or otherwise,\r\n      unless required by applicable law (such as deliberate and grossly\r\n      negligent acts) or agreed to in writing, shall any Contributor be\r\n      liable to You for damages, including any direct, indirect, special,\r\n      incidental, or consequential damages of any character arising as a\r\n      result of this License or out of the use or inability to use the\r\n      Work (including but not limited to damages for loss of goodwill,\r\n      work stoppage, computer failure or malfunction, or any and all\r\n      other commercial damages or losses), even if such Contributor\r\n      has been advised of the possibility of such damages.\r\n\r\n   9. Accepting Warranty or Additional Liability. While redistributing\r\n      the Work or Derivative Works thereof, You may choose to offer,\r\n      and charge a fee for, acceptance of support, warranty, indemnity,\r\n      or other liability obligations and/or rights consistent with this\r\n      License. However, in accepting such obligations, You may act only\r\n      on Your own behalf and on Your sole responsibility, not on behalf\r\n      of any other Contributor, and only if You agree to indemnify,\r\n      defend, and hold each Contributor harmless for any liability\r\n      incurred by, or claims asserted against, such Contributor by reason\r\n      of your accepting any such warranty or additional liability.\r\n\r\n   END OF TERMS AND CONDITIONS\r\n\r\n   APPENDIX: How to apply the Apache License to your work.\r\n\r\n      To apply the Apache License to your work, attach the following\r\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\r\n      replaced with your own identifying information. (Don't include\r\n      the brackets!)  The text should be enclosed in the appropriate\r\n      comment syntax for the file format. We also recommend that a\r\n      file or class name and description of purpose be included on the\r\n      same \"printed page\" as the copyright notice for easier\r\n      identification within third-party archives.\r\n\r\n   Copyright [yyyy] [name of copyright owner]\r\n\r\n   Licensed under the Apache License, Version 2.0 (the \"License\");\r\n   you may not use this file except in compliance with the License.\r\n   You may obtain a copy of the License at\r\n\r\n       http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n   Unless required by applicable law or agreed to in writing, software\r\n   distributed under the License is distributed on an \"AS IS\" BASIS,\r\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n   See the License for the specific language governing permissions and\r\n   limitations under the License.\r\n"
  },
  {
    "path": "resources/public/js/BootstrapMenu.js",
    "content": "/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n\n\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t/* webpack entry file to build a standalone browser script. */\n\twindow.BootstrapMenu = __webpack_require__(1);\n\n\n/***/ },\n/* 1 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\n\tvar classNames = __webpack_require__(2);\n\tvar $ = __webpack_require__(3);\n\t__webpack_require__(4);\n\n\t// modular lodash requires\n\tvar _ = function() {\n\t  throw new Error('Custom lodash build for BootstrapMenu. lodash chaining is not included');\n\t};\n\n\t_.noop = __webpack_require__(5);\n\t_.each = __webpack_require__(6);\n\t_.contains = __webpack_require__(33);\n\t_.extend = __webpack_require__(41);\n\t_.uniqueId = __webpack_require__(48);\n\t_.isFunction = __webpack_require__(18);\n\n\n\tvar defaultOptions = {\n\t    /* container of the context menu, where it will be created and where\n\t     * event listeners will be installed. */\n\t    container: 'body',\n\n\t    /* user-defined function to obtain specific data about the currently\n\t     * opened element, to pass it to the rest of user-defined functions\n\t     * of an action. */\n\t    fetchElementData: _.noop,\n\n\t    /* what the source of the context menu should be when opened.\n\t     * Valid values are 'mouse' and 'element'. */\n\t    menuSource: 'mouse',\n\n\t    /* how to calculate the position of the context menu based on its source.\n\t     * Valid values are 'aboveLeft', 'aboveRight', 'belowLeft', and 'belowRight'. */\n\t    menuPosition: 'belowLeft',\n\n\t    /* the event to listen to open the menu.\n\t     * Valid values are 'click', 'right-click', 'hover' */\n\t    menuEvent: 'right-click', // TODO rename to menuAction in next mayor version\n\n\t    /* group actions to render them next to each other, with a separator\n\t     * between each group. */\n\t    actionsGroups: [],\n\n\t    /* In some weird cases, another plugin may be installing 'click' listeners\n\t     * in the anchors used for each action of the context menu, and stopping\n\t     * the event bubbling before it reachs this plugin's listener.\n\t     *\n\t     * For those cases, _actionSelectEvent can be used to change the event we\n\t     * listen to, for example to 'mousedown'.\n\t     *\n\t     * Unless the context menu is not working due to this and a workaround is\n\t     * needed, this option can be safely ignored.\n\t     */\n\t    _actionSelectEvent: 'click'\n\t};\n\n\tfunction renderMenu(_this) {\n\t    var $menu = $('<div class=\"dropdown bootstrapMenu\" style=\"z-index:10000;position:absolute;\" />');\n\n\t    var $ul = $('<ul class=\"dropdown-menu\" style=\"position:static;display:block;font-size:0.9em;\" />');\n\n\t    // group all actions following the actionsGroups option, to\n\t    // add a separator between each of them.\n\t    var groups = [];\n\n\t    // default group where all ungrouped actions will go\n\t    groups[0] = [];\n\n\t    // add the rest of groups\n\t    _.each(_this.options.actionsGroups, function(groupArr, ind) {\n\t        groups[ind+1] = [];\n\t    });\n\n\t    // find out if any of the actions has an icon\n\t    var actionsHaveIcon = false;\n\n\t    // add each action to the group it belongs to, or the default group\n\t    _.each(_this.options.actions, function(action, actionId) {\n\t        var addedToGroup = false;\n\n\t        _.each(_this.options.actionsGroups, function(groupArr, ind) {\n\t            if (_.contains(groupArr, actionId)) {\n\t                groups[ind+1].push(actionId);\n\t                addedToGroup = true;\n\t            }\n\t        });\n\n\t        if (addedToGroup === false) {\n\t            groups[0].push(actionId);\n\t        }\n\n\t        if (typeof action.iconClass !== 'undefined') {\n\t            actionsHaveIcon = true;\n\t        }\n\t    });\n\n\t    var isFirstNonEmptyGroup = true;\n\t    _.each(groups, function(actionsIds) {\n\t        if (actionsIds.length == 0)\n\t            return;\n\n\t        if (isFirstNonEmptyGroup === false) {\n\t            $ul.append('<li class=\"divider\"></li>');\n\t        }\n\t        isFirstNonEmptyGroup = false;\n\n\t        _.each(actionsIds, function(actionId) {\n\t            var action = _this.options.actions[actionId];\n\n\t            /* At least an action has an icon. Add the icon of the current action,\n\t             * or room to align it with the actions which do have one. */\n\t            if (actionsHaveIcon === true) {\n\t                $ul.append(\n\t                    '<li role=\"presentation\" data-action=\"'+actionId+'\">' +\n\t                    '<a href=\"#\" role=\"menuitem\">' +\n\t                    '<i class=\"fa fa-fw fa-lg ' + (action.iconClass || '') + '\"></i> ' +\n\t                    '<span class=\"actionName\"></span>' +\n\t                    '</a>' +\n\t                    '</li>'\n\t                );\n\t            }\n\t            // neither of the actions have an icon.\n\t            else {\n\t                $ul.append(\n\t                    '<li role=\"presentation\" data-action=\"'+actionId+'\">' +\n\t                    '<a href=\"#\" role=\"menuitem\"><span class=\"actionName\"></span></a>' +\n\t                    '</li>'\n\t                );\n\t            }\n\t        });\n\t    });\n\n\t    return $menu.append($ul);\n\t}\n\n\tfunction setupOpenEventListeners(_this) {\n\t    var openEventName = null;\n\n\t    switch (_this.options.menuEvent) {\n\t        case 'click':\n\t            openEventName = 'click';\n\t            break;\n\t        case 'right-click':\n\t            openEventName = 'contextmenu';\n\t            break;\n\t        case 'hover':\n\t            openEventName = 'mouseenter';\n\t            break;\n\t        default:\n\t            throw new Error(\"Unknown BootstrapMenu 'menuEvent' option\");\n\t    }\n\n\t    // install the handler for every future elements where\n\t    // the context menu will open\n\t    _this.$container.on(openEventName + _this.namespace, _this.selector, function(evt) {\n\t        var $openTarget = $(this);\n\n\t        _this.open($openTarget, evt);\n\n\t        // cancel event propagation, to avoid it bubbling up to this.$container\n\t        // and closing the context menu as if the user clicked outside the menu.\n\t        return false;\n\t    });\n\t}\n\n\tfunction clearOpenEventListeners(_this) {\n\t    _this.$container.off(_this.namespace);\n\t}\n\n\tfunction setupActionsEventListeners(_this) {\n\t    var actionSelectEvent = _this.options._actionSelectEvent + _this.namespace;\n\n\t    // handler to run when an option is selected\n\t    _this.$menu.on(actionSelectEvent, function(evt) {\n\t        evt.preventDefault();\n\t        evt.stopPropagation();\n\n\t        var $target = $(evt.target);\n\n\t        var $action = $target.is('[data-action]') ? $target : $target.closest('[data-action]');\n\t        var actionId = $action.data('action');\n\n\t        // action is disabled, dont do anything\n\t        if ($action.is('.disabled'))\n\t            return;\n\n\t        var targetData = _this.options.fetchElementData(_this.$openTarget);\n\n\t        /* call the user click handler. It receives the optional user-defined data,\n\t         * or undefined. */\n\t        _this.options.actions[actionId].onClick(targetData);\n\n\t        // close the menu\n\t        _this.close();\n\t    });\n\t}\n\n\tfunction clearActionsEventListeners(_this) {\n\t    _this.$menu.off(_this.namespace);\n\t}\n\n\tfunction setupCloseEventListeners(_this) {\n\t    switch (_this.options.menuEvent) {\n\t        case 'click':\n\t            break;\n\t        case 'right-click':\n\t            break;\n\t        case 'hover':\n\t            // close the menu when the mouse is moved outside both\n\t            // the element where the context menu was opened, and\n\t            // the context menu itself.\n\t            var $elemsToCheck = _this.$openTarget.add(_this.$menu);\n\n\t            $elemsToCheck.on('mouseleave' + _this.closeNamespace, function(evt) {\n\t                var destElement = evt.toElement || evt.relatedTarget;\n\t                if (!_this.$openTarget.is(destElement) && !_this.$menu.is(destElement)) {\n\t                    $elemsToCheck.off(_this.closeNamespace);\n\t                    _this.close();\n\t                }\n\t            });\n\t            break;\n\t        default:\n\t            throw new Error(\"Unknown BootstrapMenu 'menuEvent' option\");\n\t    }\n\n\t    // it the user clicks outside the context menu, close it.\n\t    _this.$container.on('click' + _this.closeNamespace, function() {\n\t        _this.close();\n\t    });\n\t}\n\n\tfunction clearCloseEventListeners(_this) {\n\t    _this.$container.off(_this.closeNamespace);\n\t}\n\n\tvar BootstrapMenu = function(selector, options) {\n\t    this.selector = selector;\n\t    this.options = _.extend({}, defaultOptions, options);\n\n\t    // namespaces to use when registering event listeners\n\t    this.namespace = _.uniqueId('.BootstrapMenu_');\n\t    this.closeNamespace = _.uniqueId('.BootstrapMenuClose_');\n\n\t    this.init();\n\t};\n\n\tvar existingInstances = [];\n\n\tBootstrapMenu.prototype.init = function() {\n\t    this.$container = $(this.options.container);\n\n\t    // jQuery object of the rendered context menu. Not part of the DOM yet.\n\t    this.$menu = renderMenu(this);\n\t    this.$menuList = this.$menu.children();\n\n\t    /* append the context menu to <body> to be able to use \"position: absolute\"\n\t     * absolute to the whole window. */\n\t    this.$menu.hide().appendTo(this.$container);\n\n\t    /* the element in which the context menu was opened. Updated every time\n\t     * the menu is opened. */\n\t    this.$openTarget = null;\n\n\t    /* event that triggered the context menu to open. Updated every time\n\t     * the menu is opened. */\n\t    this.openEvent = null;\n\n\t    setupOpenEventListeners(this);\n\n\t    setupActionsEventListeners(this);\n\n\t    // keep track of all the existing context menu instances in the page\n\t    existingInstances.push(this);\n\t};\n\n\tBootstrapMenu.prototype.updatePosition = function() {\n\t    var menuLocation = null; // my\n\t    var relativeToElem = null; // of\n\t    var relativeToLocation = null; // at\n\n\t    switch (this.options.menuSource) {\n\t        case 'element':\n\t            relativeToElem = this.$openTarget;\n\t            break;\n\t        case 'mouse':\n\t            relativeToElem = this.openEvent;\n\t            break;\n\t        default:\n\t            throw new Error(\"Unknown BootstrapMenu 'menuSource' option\");\n\t    }\n\n\t    switch (this.options.menuPosition) {\n\t        case 'belowRight':\n\t            menuLocation = 'right top';\n\t            relativeToLocation = 'right bottom';\n\t            break;\n\t        case 'belowLeft':\n\t            menuLocation = 'left top';\n\t            relativeToLocation = 'left bottom';\n\t            break;\n\t        case 'aboveRight':\n\t            menuLocation = 'right bottom';\n\t            relativeToLocation = 'right top';\n\t            break;\n\t        case 'aboveLeft':\n\t            menuLocation = 'left bottom';\n\t            relativeToLocation = 'left top';\n\t            break;\n\t        default:\n\t            throw new Error(\"Unknown BootstrapMenu 'menuPosition' option\");\n\t    }\n\n\t    // update the menu's height and width manually\n\t    this.$menu.css({ display: 'block' });\n\n\t    // once the menu is not hidden anymore, we can obtain its content's height and width,\n\t    // to manually update it in the menu\n\t    this.$menu.css({\n\t        height: this.$menuList.height(),\n\t        width: this.$menuList.width()\n\t    });\n\n\t    this.$menu.position({ my: menuLocation, at: relativeToLocation, of: relativeToElem });\n\t};\n\n\t// open the context menu\n\tBootstrapMenu.prototype.open = function($openTarget, event) {\n\t    var _this = this;\n\n\t    // first close all open instances of opened context menus in the page\n\t    BootstrapMenu.closeAll();\n\n\t    this.$openTarget = $openTarget;\n\n\t    this.openEvent = event;\n\n\t    var targetData = _this.options.fetchElementData(_this.$openTarget);\n\n\t    var $actions = this.$menu.find('[data-action]');\n\n\t    // clear previously hidden actions\n\t    $actions.show();\n\n\t    /* go through all actions to update the text to show, which ones to show\n\t     * enabled/disabled and which ones to hide. */\n\t    $actions.each(function() {\n\t        var $action = $(this);\n\n\t        var actionId = $action.data('action');\n\t        var action = _this.options.actions[actionId];\n\n\t        var classes = action.classNames || null;\n\n\t        if (classes && _.isFunction(classes))\n\t            classes = classes(targetData);\n\n\t        $action.attr('class', classNames(classes || ''));\n\n\t        if (action.isShown && action.isShown(targetData) === false) {\n\t            $action.hide();\n\t            return;\n\t        }\n\n\t        // the name provided for an action may be dynamic, provided as a function\n\t        $action.find('.actionName').html(\n\t            _.isFunction(action.name) && action.name(targetData) || action.name\n\t        );\n\n\t        if (action.isEnabled && action.isEnabled(targetData) === false) {\n\t            $action.addClass('disabled');\n\t        }\n\t    });\n\n\t    // once it is known which actions are or arent being shown\n\t    // (so we know the final height of the context menu),\n\t    // calculate its position\n\t    this.updatePosition();\n\n\t    this.$menu.show();\n\n\t    setupCloseEventListeners(this);\n\t};\n\n\t// close the context menu\n\tBootstrapMenu.prototype.close = function() {\n\t    // hide the menu\n\t    this.$menu.hide();\n\n\t    clearCloseEventListeners(this);\n\t};\n\n\tBootstrapMenu.prototype.destroy = function() {\n\t    this.close();\n\t    clearOpenEventListeners(this);\n\t    clearActionsEventListeners(this);\n\t};\n\n\t// close all instances of context menus\n\tBootstrapMenu.closeAll = function() {\n\t    _.each(existingInstances, function(contextMenu) {\n\t        contextMenu.close();\n\t    });\n\t};\n\n\tmodule.exports = BootstrapMenu;\n\n\n/***/ },\n/* 2 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!\n\t  Copyright (c) 2016 Jed Watson.\n\t  Licensed under the MIT License (MIT), see\n\t  http://jedwatson.github.io/classnames\n\t*/\n\t/* global define */\n\n\t(function () {\n\t\t'use strict';\n\n\t\tvar hasOwn = {}.hasOwnProperty;\n\n\t\tfunction classNames () {\n\t\t\tvar classes = [];\n\n\t\t\tfor (var i = 0; i < arguments.length; i++) {\n\t\t\t\tvar arg = arguments[i];\n\t\t\t\tif (!arg) continue;\n\n\t\t\t\tvar argType = typeof arg;\n\n\t\t\t\tif (argType === 'string' || argType === 'number') {\n\t\t\t\t\tclasses.push(arg);\n\t\t\t\t} else if (Array.isArray(arg)) {\n\t\t\t\t\tclasses.push(classNames.apply(null, arg));\n\t\t\t\t} else if (argType === 'object') {\n\t\t\t\t\tfor (var key in arg) {\n\t\t\t\t\t\tif (hasOwn.call(arg, key) && arg[key]) {\n\t\t\t\t\t\t\tclasses.push(key);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn classes.join(' ');\n\t\t}\n\n\t\tif (typeof module !== 'undefined' && module.exports) {\n\t\t\tmodule.exports = classNames;\n\t\t} else if (true) {\n\t\t\t// register as 'classnames', consistent with npm package name\n\t\t\t!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () {\n\t\t\t\treturn classNames;\n\t\t\t}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n\t\t} else {\n\t\t\twindow.classNames = classNames;\n\t\t}\n\t}());\n\n\n/***/ },\n/* 3 */\n/***/ function(module, exports) {\n\n\tmodule.exports = jQuery;\n\n/***/ },\n/* 4 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar jQuery = __webpack_require__(3);\n\n\t/*!\n\t * jQuery UI Position 1.10.4\n\t * http://jqueryui.com\n\t *\n\t * Copyright 2014 jQuery Foundation and other contributors\n\t * Released under the MIT license.\n\t * http://jquery.org/license\n\t *\n\t * http://api.jqueryui.com/position/\n\t */\n\t(function( $, undefined ) {\n\n\t$.ui = $.ui || {};\n\n\tvar cachedScrollbarWidth,\n\t\tmax = Math.max,\n\t\tabs = Math.abs,\n\t\tround = Math.round,\n\t\trhorizontal = /left|center|right/,\n\t\trvertical = /top|center|bottom/,\n\t\troffset = /[\\+\\-]\\d+(\\.[\\d]+)?%?/,\n\t\trposition = /^\\w+/,\n\t\trpercent = /%$/,\n\t\t_position = $.fn.position;\n\n\tfunction getOffsets( offsets, width, height ) {\n\t\treturn [\n\t\t\tparseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),\n\t\t\tparseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )\n\t\t];\n\t}\n\n\tfunction parseCss( element, property ) {\n\t\treturn parseInt( $.css( element, property ), 10 ) || 0;\n\t}\n\n\tfunction getDimensions( elem ) {\n\t\tvar raw = elem[0];\n\t\tif ( raw.nodeType === 9 ) {\n\t\t\treturn {\n\t\t\t\twidth: elem.width(),\n\t\t\t\theight: elem.height(),\n\t\t\t\toffset: { top: 0, left: 0 }\n\t\t\t};\n\t\t}\n\t\tif ( $.isWindow( raw ) ) {\n\t\t\treturn {\n\t\t\t\twidth: elem.width(),\n\t\t\t\theight: elem.height(),\n\t\t\t\toffset: { top: elem.scrollTop(), left: elem.scrollLeft() }\n\t\t\t};\n\t\t}\n\t\tif ( raw.preventDefault ) {\n\t\t\treturn {\n\t\t\t\twidth: 0,\n\t\t\t\theight: 0,\n\t\t\t\toffset: { top: raw.pageY, left: raw.pageX }\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\twidth: elem.outerWidth(),\n\t\t\theight: elem.outerHeight(),\n\t\t\toffset: elem.offset()\n\t\t};\n\t}\n\n\t$.position = {\n\t\tscrollbarWidth: function() {\n\t\t\tif ( cachedScrollbarWidth !== undefined ) {\n\t\t\t\treturn cachedScrollbarWidth;\n\t\t\t}\n\t\t\tvar w1, w2,\n\t\t\t\tdiv = $( \"<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>\" ),\n\t\t\t\tinnerDiv = div.children()[0];\n\n\t\t\t$( \"body\" ).append( div );\n\t\t\tw1 = innerDiv.offsetWidth;\n\t\t\tdiv.css( \"overflow\", \"scroll\" );\n\n\t\t\tw2 = innerDiv.offsetWidth;\n\n\t\t\tif ( w1 === w2 ) {\n\t\t\t\tw2 = div[0].clientWidth;\n\t\t\t}\n\n\t\t\tdiv.remove();\n\n\t\t\treturn (cachedScrollbarWidth = w1 - w2);\n\t\t},\n\t\tgetScrollInfo: function( within ) {\n\t\t\tvar overflowX = within.isWindow || within.isDocument ? \"\" :\n\t\t\t\t\twithin.element.css( \"overflow-x\" ),\n\t\t\t\toverflowY = within.isWindow || within.isDocument ? \"\" :\n\t\t\t\t\twithin.element.css( \"overflow-y\" ),\n\t\t\t\thasOverflowX = overflowX === \"scroll\" ||\n\t\t\t\t\t( overflowX === \"auto\" && within.width < within.element[0].scrollWidth ),\n\t\t\t\thasOverflowY = overflowY === \"scroll\" ||\n\t\t\t\t\t( overflowY === \"auto\" && within.height < within.element[0].scrollHeight );\n\t\t\treturn {\n\t\t\t\twidth: hasOverflowY ? $.position.scrollbarWidth() : 0,\n\t\t\t\theight: hasOverflowX ? $.position.scrollbarWidth() : 0\n\t\t\t};\n\t\t},\n\t\tgetWithinInfo: function( element ) {\n\t\t\tvar withinElement = $( element || window ),\n\t\t\t\tisWindow = $.isWindow( withinElement[0] ),\n\t\t\t\tisDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;\n\t\t\treturn {\n\t\t\t\telement: withinElement,\n\t\t\t\tisWindow: isWindow,\n\t\t\t\tisDocument: isDocument,\n\t\t\t\toffset: withinElement.offset() || { left: 0, top: 0 },\n\t\t\t\tscrollLeft: withinElement.scrollLeft(),\n\t\t\t\tscrollTop: withinElement.scrollTop(),\n\t\t\t\twidth: isWindow ? withinElement.width() : withinElement.outerWidth(),\n\t\t\t\theight: isWindow ? withinElement.height() : withinElement.outerHeight()\n\t\t\t};\n\t\t}\n\t};\n\n\t$.fn.position = function( options ) {\n\t\tif ( !options || !options.of ) {\n\t\t\treturn _position.apply( this, arguments );\n\t\t}\n\n\t\t// make a copy, we don't want to modify arguments\n\t\toptions = $.extend( {}, options );\n\n\t\tvar atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,\n\t\t\ttarget = $( options.of ),\n\t\t\twithin = $.position.getWithinInfo( options.within ),\n\t\t\tscrollInfo = $.position.getScrollInfo( within ),\n\t\t\tcollision = ( options.collision || \"flip\" ).split( \" \" ),\n\t\t\toffsets = {};\n\n\t\tdimensions = getDimensions( target );\n\t\tif ( target[0].preventDefault ) {\n\t\t\t// force left top to allow flipping\n\t\t\toptions.at = \"left top\";\n\t\t}\n\t\ttargetWidth = dimensions.width;\n\t\ttargetHeight = dimensions.height;\n\t\ttargetOffset = dimensions.offset;\n\t\t// clone to reuse original targetOffset later\n\t\tbasePosition = $.extend( {}, targetOffset );\n\n\t\t// force my and at to have valid horizontal and vertical positions\n\t\t// if a value is missing or invalid, it will be converted to center\n\t\t$.each( [ \"my\", \"at\" ], function() {\n\t\t\tvar pos = ( options[ this ] || \"\" ).split( \" \" ),\n\t\t\t\thorizontalOffset,\n\t\t\t\tverticalOffset;\n\n\t\t\tif ( pos.length === 1) {\n\t\t\t\tpos = rhorizontal.test( pos[ 0 ] ) ?\n\t\t\t\t\tpos.concat( [ \"center\" ] ) :\n\t\t\t\t\trvertical.test( pos[ 0 ] ) ?\n\t\t\t\t\t\t[ \"center\" ].concat( pos ) :\n\t\t\t\t\t\t[ \"center\", \"center\" ];\n\t\t\t}\n\t\t\tpos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : \"center\";\n\t\t\tpos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : \"center\";\n\n\t\t\t// calculate offsets\n\t\t\thorizontalOffset = roffset.exec( pos[ 0 ] );\n\t\t\tverticalOffset = roffset.exec( pos[ 1 ] );\n\t\t\toffsets[ this ] = [\n\t\t\t\thorizontalOffset ? horizontalOffset[ 0 ] : 0,\n\t\t\t\tverticalOffset ? verticalOffset[ 0 ] : 0\n\t\t\t];\n\n\t\t\t// reduce to just the positions without the offsets\n\t\t\toptions[ this ] = [\n\t\t\t\trposition.exec( pos[ 0 ] )[ 0 ],\n\t\t\t\trposition.exec( pos[ 1 ] )[ 0 ]\n\t\t\t];\n\t\t});\n\n\t\t// normalize collision option\n\t\tif ( collision.length === 1 ) {\n\t\t\tcollision[ 1 ] = collision[ 0 ];\n\t\t}\n\n\t\tif ( options.at[ 0 ] === \"right\" ) {\n\t\t\tbasePosition.left += targetWidth;\n\t\t} else if ( options.at[ 0 ] === \"center\" ) {\n\t\t\tbasePosition.left += targetWidth / 2;\n\t\t}\n\n\t\tif ( options.at[ 1 ] === \"bottom\" ) {\n\t\t\tbasePosition.top += targetHeight;\n\t\t} else if ( options.at[ 1 ] === \"center\" ) {\n\t\t\tbasePosition.top += targetHeight / 2;\n\t\t}\n\n\t\tatOffset = getOffsets( offsets.at, targetWidth, targetHeight );\n\t\tbasePosition.left += atOffset[ 0 ];\n\t\tbasePosition.top += atOffset[ 1 ];\n\n\t\treturn this.each(function() {\n\t\t\tvar collisionPosition, using,\n\t\t\t\telem = $( this ),\n\t\t\t\telemWidth = elem.outerWidth(),\n\t\t\t\telemHeight = elem.outerHeight(),\n\t\t\t\tmarginLeft = parseCss( this, \"marginLeft\" ),\n\t\t\t\tmarginTop = parseCss( this, \"marginTop\" ),\n\t\t\t\tcollisionWidth = elemWidth + marginLeft + parseCss( this, \"marginRight\" ) + scrollInfo.width,\n\t\t\t\tcollisionHeight = elemHeight + marginTop + parseCss( this, \"marginBottom\" ) + scrollInfo.height,\n\t\t\t\tposition = $.extend( {}, basePosition ),\n\t\t\t\tmyOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );\n\n\t\t\tif ( options.my[ 0 ] === \"right\" ) {\n\t\t\t\tposition.left -= elemWidth;\n\t\t\t} else if ( options.my[ 0 ] === \"center\" ) {\n\t\t\t\tposition.left -= elemWidth / 2;\n\t\t\t}\n\n\t\t\tif ( options.my[ 1 ] === \"bottom\" ) {\n\t\t\t\tposition.top -= elemHeight;\n\t\t\t} else if ( options.my[ 1 ] === \"center\" ) {\n\t\t\t\tposition.top -= elemHeight / 2;\n\t\t\t}\n\n\t\t\tposition.left += myOffset[ 0 ];\n\t\t\tposition.top += myOffset[ 1 ];\n\n\t\t\t// if the browser doesn't support fractions, then round for consistent results\n\t\t\tif ( !$.support.offsetFractions ) {\n\t\t\t\tposition.left = round( position.left );\n\t\t\t\tposition.top = round( position.top );\n\t\t\t}\n\n\t\t\tcollisionPosition = {\n\t\t\t\tmarginLeft: marginLeft,\n\t\t\t\tmarginTop: marginTop\n\t\t\t};\n\n\t\t\t$.each( [ \"left\", \"top\" ], function( i, dir ) {\n\t\t\t\tif ( $.ui.position[ collision[ i ] ] ) {\n\t\t\t\t\t$.ui.position[ collision[ i ] ][ dir ]( position, {\n\t\t\t\t\t\ttargetWidth: targetWidth,\n\t\t\t\t\t\ttargetHeight: targetHeight,\n\t\t\t\t\t\telemWidth: elemWidth,\n\t\t\t\t\t\telemHeight: elemHeight,\n\t\t\t\t\t\tcollisionPosition: collisionPosition,\n\t\t\t\t\t\tcollisionWidth: collisionWidth,\n\t\t\t\t\t\tcollisionHeight: collisionHeight,\n\t\t\t\t\t\toffset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],\n\t\t\t\t\t\tmy: options.my,\n\t\t\t\t\t\tat: options.at,\n\t\t\t\t\t\twithin: within,\n\t\t\t\t\t\telem : elem\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif ( options.using ) {\n\t\t\t\t// adds feedback as second argument to using callback, if present\n\t\t\t\tusing = function( props ) {\n\t\t\t\t\tvar left = targetOffset.left - position.left,\n\t\t\t\t\t\tright = left + targetWidth - elemWidth,\n\t\t\t\t\t\ttop = targetOffset.top - position.top,\n\t\t\t\t\t\tbottom = top + targetHeight - elemHeight,\n\t\t\t\t\t\tfeedback = {\n\t\t\t\t\t\t\ttarget: {\n\t\t\t\t\t\t\t\telement: target,\n\t\t\t\t\t\t\t\tleft: targetOffset.left,\n\t\t\t\t\t\t\t\ttop: targetOffset.top,\n\t\t\t\t\t\t\t\twidth: targetWidth,\n\t\t\t\t\t\t\t\theight: targetHeight\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\telement: {\n\t\t\t\t\t\t\t\telement: elem,\n\t\t\t\t\t\t\t\tleft: position.left,\n\t\t\t\t\t\t\t\ttop: position.top,\n\t\t\t\t\t\t\t\twidth: elemWidth,\n\t\t\t\t\t\t\t\theight: elemHeight\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\thorizontal: right < 0 ? \"left\" : left > 0 ? \"right\" : \"center\",\n\t\t\t\t\t\t\tvertical: bottom < 0 ? \"top\" : top > 0 ? \"bottom\" : \"middle\"\n\t\t\t\t\t\t};\n\t\t\t\t\tif ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {\n\t\t\t\t\t\tfeedback.horizontal = \"center\";\n\t\t\t\t\t}\n\t\t\t\t\tif ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {\n\t\t\t\t\t\tfeedback.vertical = \"middle\";\n\t\t\t\t\t}\n\t\t\t\t\tif ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {\n\t\t\t\t\t\tfeedback.important = \"horizontal\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfeedback.important = \"vertical\";\n\t\t\t\t\t}\n\t\t\t\t\toptions.using.call( this, props, feedback );\n\t\t\t\t};\n\t\t\t}\n\n\t\t\telem.offset( $.extend( position, { using: using } ) );\n\t\t});\n\t};\n\n\t$.ui.position = {\n\t\tfit: {\n\t\t\tleft: function( position, data ) {\n\t\t\t\tvar within = data.within,\n\t\t\t\t\twithinOffset = within.isWindow ? within.scrollLeft : within.offset.left,\n\t\t\t\t\touterWidth = within.width,\n\t\t\t\t\tcollisionPosLeft = position.left - data.collisionPosition.marginLeft,\n\t\t\t\t\toverLeft = withinOffset - collisionPosLeft,\n\t\t\t\t\toverRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,\n\t\t\t\t\tnewOverRight;\n\n\t\t\t\t// element is wider than within\n\t\t\t\tif ( data.collisionWidth > outerWidth ) {\n\t\t\t\t\t// element is initially over the left side of within\n\t\t\t\t\tif ( overLeft > 0 && overRight <= 0 ) {\n\t\t\t\t\t\tnewOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;\n\t\t\t\t\t\tposition.left += overLeft - newOverRight;\n\t\t\t\t\t// element is initially over right side of within\n\t\t\t\t\t} else if ( overRight > 0 && overLeft <= 0 ) {\n\t\t\t\t\t\tposition.left = withinOffset;\n\t\t\t\t\t// element is initially over both left and right sides of within\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( overLeft > overRight ) {\n\t\t\t\t\t\t\tposition.left = withinOffset + outerWidth - data.collisionWidth;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tposition.left = withinOffset;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t// too far left -> align with left edge\n\t\t\t\t} else if ( overLeft > 0 ) {\n\t\t\t\t\tposition.left += overLeft;\n\t\t\t\t// too far right -> align with right edge\n\t\t\t\t} else if ( overRight > 0 ) {\n\t\t\t\t\tposition.left -= overRight;\n\t\t\t\t// adjust based on position and margin\n\t\t\t\t} else {\n\t\t\t\t\tposition.left = max( position.left - collisionPosLeft, position.left );\n\t\t\t\t}\n\t\t\t},\n\t\t\ttop: function( position, data ) {\n\t\t\t\tvar within = data.within,\n\t\t\t\t\twithinOffset = within.isWindow ? within.scrollTop : within.offset.top,\n\t\t\t\t\touterHeight = data.within.height,\n\t\t\t\t\tcollisionPosTop = position.top - data.collisionPosition.marginTop,\n\t\t\t\t\toverTop = withinOffset - collisionPosTop,\n\t\t\t\t\toverBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,\n\t\t\t\t\tnewOverBottom;\n\n\t\t\t\t// element is taller than within\n\t\t\t\tif ( data.collisionHeight > outerHeight ) {\n\t\t\t\t\t// element is initially over the top of within\n\t\t\t\t\tif ( overTop > 0 && overBottom <= 0 ) {\n\t\t\t\t\t\tnewOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;\n\t\t\t\t\t\tposition.top += overTop - newOverBottom;\n\t\t\t\t\t// element is initially over bottom of within\n\t\t\t\t\t} else if ( overBottom > 0 && overTop <= 0 ) {\n\t\t\t\t\t\tposition.top = withinOffset;\n\t\t\t\t\t// element is initially over both top and bottom of within\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( overTop > overBottom ) {\n\t\t\t\t\t\t\tposition.top = withinOffset + outerHeight - data.collisionHeight;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tposition.top = withinOffset;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t// too far up -> align with top\n\t\t\t\t} else if ( overTop > 0 ) {\n\t\t\t\t\tposition.top += overTop;\n\t\t\t\t// too far down -> align with bottom edge\n\t\t\t\t} else if ( overBottom > 0 ) {\n\t\t\t\t\tposition.top -= overBottom;\n\t\t\t\t// adjust based on position and margin\n\t\t\t\t} else {\n\t\t\t\t\tposition.top = max( position.top - collisionPosTop, position.top );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tflip: {\n\t\t\tleft: function( position, data ) {\n\t\t\t\tvar within = data.within,\n\t\t\t\t\twithinOffset = within.offset.left + within.scrollLeft,\n\t\t\t\t\touterWidth = within.width,\n\t\t\t\t\toffsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,\n\t\t\t\t\tcollisionPosLeft = position.left - data.collisionPosition.marginLeft,\n\t\t\t\t\toverLeft = collisionPosLeft - offsetLeft,\n\t\t\t\t\toverRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,\n\t\t\t\t\tmyOffset = data.my[ 0 ] === \"left\" ?\n\t\t\t\t\t\t-data.elemWidth :\n\t\t\t\t\t\tdata.my[ 0 ] === \"right\" ?\n\t\t\t\t\t\t\tdata.elemWidth :\n\t\t\t\t\t\t\t0,\n\t\t\t\t\tatOffset = data.at[ 0 ] === \"left\" ?\n\t\t\t\t\t\tdata.targetWidth :\n\t\t\t\t\t\tdata.at[ 0 ] === \"right\" ?\n\t\t\t\t\t\t\t-data.targetWidth :\n\t\t\t\t\t\t\t0,\n\t\t\t\t\toffset = -2 * data.offset[ 0 ],\n\t\t\t\t\tnewOverRight,\n\t\t\t\t\tnewOverLeft;\n\n\t\t\t\tif ( overLeft < 0 ) {\n\t\t\t\t\tnewOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;\n\t\t\t\t\tif ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {\n\t\t\t\t\t\tposition.left += myOffset + atOffset + offset;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( overRight > 0 ) {\n\t\t\t\t\tnewOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;\n\t\t\t\t\tif ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {\n\t\t\t\t\t\tposition.left += myOffset + atOffset + offset;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\ttop: function( position, data ) {\n\t\t\t\tvar within = data.within,\n\t\t\t\t\twithinOffset = within.offset.top + within.scrollTop,\n\t\t\t\t\touterHeight = within.height,\n\t\t\t\t\toffsetTop = within.isWindow ? within.scrollTop : within.offset.top,\n\t\t\t\t\tcollisionPosTop = position.top - data.collisionPosition.marginTop,\n\t\t\t\t\toverTop = collisionPosTop - offsetTop,\n\t\t\t\t\toverBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,\n\t\t\t\t\ttop = data.my[ 1 ] === \"top\",\n\t\t\t\t\tmyOffset = top ?\n\t\t\t\t\t\t-data.elemHeight :\n\t\t\t\t\t\tdata.my[ 1 ] === \"bottom\" ?\n\t\t\t\t\t\t\tdata.elemHeight :\n\t\t\t\t\t\t\t0,\n\t\t\t\t\tatOffset = data.at[ 1 ] === \"top\" ?\n\t\t\t\t\t\tdata.targetHeight :\n\t\t\t\t\t\tdata.at[ 1 ] === \"bottom\" ?\n\t\t\t\t\t\t\t-data.targetHeight :\n\t\t\t\t\t\t\t0,\n\t\t\t\t\toffset = -2 * data.offset[ 1 ],\n\t\t\t\t\tnewOverTop,\n\t\t\t\t\tnewOverBottom;\n\t\t\t\tif ( overTop < 0 ) {\n\t\t\t\t\tnewOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;\n\t\t\t\t\tif ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {\n\t\t\t\t\t\tposition.top += myOffset + atOffset + offset;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( overBottom > 0 ) {\n\t\t\t\t\tnewOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;\n\t\t\t\t\tif ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {\n\t\t\t\t\t\tposition.top += myOffset + atOffset + offset;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tflipfit: {\n\t\t\tleft: function() {\n\t\t\t\t$.ui.position.flip.left.apply( this, arguments );\n\t\t\t\t$.ui.position.fit.left.apply( this, arguments );\n\t\t\t},\n\t\t\ttop: function() {\n\t\t\t\t$.ui.position.flip.top.apply( this, arguments );\n\t\t\t\t$.ui.position.fit.top.apply( this, arguments );\n\t\t\t}\n\t\t}\n\t};\n\n\t// fraction support test\n\t(function () {\n\t\tvar testElement, testElementParent, testElementStyle, offsetLeft, i,\n\t\t\tbody = document.getElementsByTagName( \"body\" )[ 0 ],\n\t\t\tdiv = document.createElement( \"div\" );\n\n\t\t//Create a \"fake body\" for testing based on method used in jQuery.support\n\t\ttestElement = document.createElement( body ? \"div\" : \"body\" );\n\t\ttestElementStyle = {\n\t\t\tvisibility: \"hidden\",\n\t\t\twidth: 0,\n\t\t\theight: 0,\n\t\t\tborder: 0,\n\t\t\tmargin: 0,\n\t\t\tbackground: \"none\"\n\t\t};\n\t\tif ( body ) {\n\t\t\t$.extend( testElementStyle, {\n\t\t\t\tposition: \"absolute\",\n\t\t\t\tleft: \"-1000px\",\n\t\t\t\ttop: \"-1000px\"\n\t\t\t});\n\t\t}\n\t\tfor ( i in testElementStyle ) {\n\t\t\ttestElement.style[ i ] = testElementStyle[ i ];\n\t\t}\n\t\ttestElement.appendChild( div );\n\t\ttestElementParent = body || document.documentElement;\n\t\ttestElementParent.insertBefore( testElement, testElementParent.firstChild );\n\n\t\tdiv.style.cssText = \"position: absolute; left: 10.7432222px;\";\n\n\t\toffsetLeft = $( div ).offset().left;\n\t\t$.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;\n\n\t\ttestElement.innerHTML = \"\";\n\t\ttestElementParent.removeChild( testElement );\n\t})();\n\n\t}( jQuery ) );\n\n\n/***/ },\n/* 5 */\n/***/ function(module, exports) {\n\n\t/**\n\t * A no-operation function that returns `undefined` regardless of the\n\t * arguments it receives.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Utility\n\t * @example\n\t *\n\t * var object = { 'user': 'fred' };\n\t *\n\t * _.noop(object) === undefined;\n\t * // => true\n\t */\n\tfunction noop() {\n\t  // No operation performed.\n\t}\n\n\tmodule.exports = noop;\n\n\n/***/ },\n/* 6 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tmodule.exports = __webpack_require__(7);\n\n\n/***/ },\n/* 7 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar arrayEach = __webpack_require__(8),\n\t    baseEach = __webpack_require__(9),\n\t    createForEach = __webpack_require__(30);\n\n\t/**\n\t * Iterates over elements of `collection` invoking `iteratee` for each element.\n\t * The `iteratee` is bound to `thisArg` and invoked with three arguments:\n\t * (value, index|key, collection). Iteratee functions may exit iteration early\n\t * by explicitly returning `false`.\n\t *\n\t * **Note:** As with other \"Collections\" methods, objects with a \"length\" property\n\t * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`\n\t * may be used for object iteration.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @alias each\n\t * @category Collection\n\t * @param {Array|Object|string} collection The collection to iterate over.\n\t * @param {Function} [iteratee=_.identity] The function invoked per iteration.\n\t * @param {*} [thisArg] The `this` binding of `iteratee`.\n\t * @returns {Array|Object|string} Returns `collection`.\n\t * @example\n\t *\n\t * _([1, 2]).forEach(function(n) {\n\t *   console.log(n);\n\t * }).value();\n\t * // => logs each value from left to right and returns the array\n\t *\n\t * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) {\n\t *   console.log(n, key);\n\t * });\n\t * // => logs each value-key pair and returns the object (iteration order is not guaranteed)\n\t */\n\tvar forEach = createForEach(arrayEach, baseEach);\n\n\tmodule.exports = forEach;\n\n\n/***/ },\n/* 8 */\n/***/ function(module, exports) {\n\n\t/**\n\t * A specialized version of `_.forEach` for arrays without support for callback\n\t * shorthands and `this` binding.\n\t *\n\t * @private\n\t * @param {Array} array The array to iterate over.\n\t * @param {Function} iteratee The function invoked per iteration.\n\t * @returns {Array} Returns `array`.\n\t */\n\tfunction arrayEach(array, iteratee) {\n\t  var index = -1,\n\t      length = array.length;\n\n\t  while (++index < length) {\n\t    if (iteratee(array[index], index, array) === false) {\n\t      break;\n\t    }\n\t  }\n\t  return array;\n\t}\n\n\tmodule.exports = arrayEach;\n\n\n/***/ },\n/* 9 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar baseForOwn = __webpack_require__(10),\n\t    createBaseEach = __webpack_require__(29);\n\n\t/**\n\t * The base implementation of `_.forEach` without support for callback\n\t * shorthands and `this` binding.\n\t *\n\t * @private\n\t * @param {Array|Object|string} collection The collection to iterate over.\n\t * @param {Function} iteratee The function invoked per iteration.\n\t * @returns {Array|Object|string} Returns `collection`.\n\t */\n\tvar baseEach = createBaseEach(baseForOwn);\n\n\tmodule.exports = baseEach;\n\n\n/***/ },\n/* 10 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar baseFor = __webpack_require__(11),\n\t    keys = __webpack_require__(15);\n\n\t/**\n\t * The base implementation of `_.forOwn` without support for callback\n\t * shorthands and `this` binding.\n\t *\n\t * @private\n\t * @param {Object} object The object to iterate over.\n\t * @param {Function} iteratee The function invoked per iteration.\n\t * @returns {Object} Returns `object`.\n\t */\n\tfunction baseForOwn(object, iteratee) {\n\t  return baseFor(object, iteratee, keys);\n\t}\n\n\tmodule.exports = baseForOwn;\n\n\n/***/ },\n/* 11 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar createBaseFor = __webpack_require__(12);\n\n\t/**\n\t * The base implementation of `baseForIn` and `baseForOwn` which iterates\n\t * over `object` properties returned by `keysFunc` invoking `iteratee` for\n\t * each property. Iteratee functions may exit iteration early by explicitly\n\t * returning `false`.\n\t *\n\t * @private\n\t * @param {Object} object The object to iterate over.\n\t * @param {Function} iteratee The function invoked per iteration.\n\t * @param {Function} keysFunc The function to get the keys of `object`.\n\t * @returns {Object} Returns `object`.\n\t */\n\tvar baseFor = createBaseFor();\n\n\tmodule.exports = baseFor;\n\n\n/***/ },\n/* 12 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar toObject = __webpack_require__(13);\n\n\t/**\n\t * Creates a base function for `_.forIn` or `_.forInRight`.\n\t *\n\t * @private\n\t * @param {boolean} [fromRight] Specify iterating from right to left.\n\t * @returns {Function} Returns the new base function.\n\t */\n\tfunction createBaseFor(fromRight) {\n\t  return function(object, iteratee, keysFunc) {\n\t    var iterable = toObject(object),\n\t        props = keysFunc(object),\n\t        length = props.length,\n\t        index = fromRight ? length : -1;\n\n\t    while ((fromRight ? index-- : ++index < length)) {\n\t      var key = props[index];\n\t      if (iteratee(iterable[key], key, iterable) === false) {\n\t        break;\n\t      }\n\t    }\n\t    return object;\n\t  };\n\t}\n\n\tmodule.exports = createBaseFor;\n\n\n/***/ },\n/* 13 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar isObject = __webpack_require__(14);\n\n\t/**\n\t * Converts `value` to an object if it's not one.\n\t *\n\t * @private\n\t * @param {*} value The value to process.\n\t * @returns {Object} Returns the object.\n\t */\n\tfunction toObject(value) {\n\t  return isObject(value) ? value : Object(value);\n\t}\n\n\tmodule.exports = toObject;\n\n\n/***/ },\n/* 14 */\n/***/ function(module, exports) {\n\n\t/**\n\t * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.\n\t * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Lang\n\t * @param {*} value The value to check.\n\t * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n\t * @example\n\t *\n\t * _.isObject({});\n\t * // => true\n\t *\n\t * _.isObject([1, 2, 3]);\n\t * // => true\n\t *\n\t * _.isObject(1);\n\t * // => false\n\t */\n\tfunction isObject(value) {\n\t  // Avoid a V8 JIT bug in Chrome 19-20.\n\t  // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.\n\t  var type = typeof value;\n\t  return !!value && (type == 'object' || type == 'function');\n\t}\n\n\tmodule.exports = isObject;\n\n\n/***/ },\n/* 15 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar getNative = __webpack_require__(16),\n\t    isArrayLike = __webpack_require__(20),\n\t    isObject = __webpack_require__(14),\n\t    shimKeys = __webpack_require__(24);\n\n\t/* Native method references for those with the same name as other `lodash` methods. */\n\tvar nativeKeys = getNative(Object, 'keys');\n\n\t/**\n\t * Creates an array of the own enumerable property names of `object`.\n\t *\n\t * **Note:** Non-object values are coerced to objects. See the\n\t * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)\n\t * for more details.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Object\n\t * @param {Object} object The object to query.\n\t * @returns {Array} Returns the array of property names.\n\t * @example\n\t *\n\t * function Foo() {\n\t *   this.a = 1;\n\t *   this.b = 2;\n\t * }\n\t *\n\t * Foo.prototype.c = 3;\n\t *\n\t * _.keys(new Foo);\n\t * // => ['a', 'b'] (iteration order is not guaranteed)\n\t *\n\t * _.keys('hi');\n\t * // => ['0', '1']\n\t */\n\tvar keys = !nativeKeys ? shimKeys : function(object) {\n\t  var Ctor = object == null ? undefined : object.constructor;\n\t  if ((typeof Ctor == 'function' && Ctor.prototype === object) ||\n\t      (typeof object != 'function' && isArrayLike(object))) {\n\t    return shimKeys(object);\n\t  }\n\t  return isObject(object) ? nativeKeys(object) : [];\n\t};\n\n\tmodule.exports = keys;\n\n\n/***/ },\n/* 16 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar isNative = __webpack_require__(17);\n\n\t/**\n\t * Gets the native function at `key` of `object`.\n\t *\n\t * @private\n\t * @param {Object} object The object to query.\n\t * @param {string} key The key of the method to get.\n\t * @returns {*} Returns the function if it's native, else `undefined`.\n\t */\n\tfunction getNative(object, key) {\n\t  var value = object == null ? undefined : object[key];\n\t  return isNative(value) ? value : undefined;\n\t}\n\n\tmodule.exports = getNative;\n\n\n/***/ },\n/* 17 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar isFunction = __webpack_require__(18),\n\t    isObjectLike = __webpack_require__(19);\n\n\t/** Used to detect host constructors (Safari > 5). */\n\tvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n\t/** Used for native method references. */\n\tvar objectProto = Object.prototype;\n\n\t/** Used to resolve the decompiled source of functions. */\n\tvar fnToString = Function.prototype.toString;\n\n\t/** Used to check objects for own properties. */\n\tvar hasOwnProperty = objectProto.hasOwnProperty;\n\n\t/** Used to detect if a method is native. */\n\tvar reIsNative = RegExp('^' +\n\t  fnToString.call(hasOwnProperty).replace(/[\\\\^$.*+?()[\\]{}|]/g, '\\\\$&')\n\t  .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n\t);\n\n\t/**\n\t * Checks if `value` is a native function.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Lang\n\t * @param {*} value The value to check.\n\t * @returns {boolean} Returns `true` if `value` is a native function, else `false`.\n\t * @example\n\t *\n\t * _.isNative(Array.prototype.push);\n\t * // => true\n\t *\n\t * _.isNative(_);\n\t * // => false\n\t */\n\tfunction isNative(value) {\n\t  if (value == null) {\n\t    return false;\n\t  }\n\t  if (isFunction(value)) {\n\t    return reIsNative.test(fnToString.call(value));\n\t  }\n\t  return isObjectLike(value) && reIsHostCtor.test(value);\n\t}\n\n\tmodule.exports = isNative;\n\n\n/***/ },\n/* 18 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar isObject = __webpack_require__(14);\n\n\t/** `Object#toString` result references. */\n\tvar funcTag = '[object Function]';\n\n\t/** Used for native method references. */\n\tvar objectProto = Object.prototype;\n\n\t/**\n\t * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)\n\t * of values.\n\t */\n\tvar objToString = objectProto.toString;\n\n\t/**\n\t * Checks if `value` is classified as a `Function` object.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Lang\n\t * @param {*} value The value to check.\n\t * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.\n\t * @example\n\t *\n\t * _.isFunction(_);\n\t * // => true\n\t *\n\t * _.isFunction(/abc/);\n\t * // => false\n\t */\n\tfunction isFunction(value) {\n\t  // The use of `Object#toString` avoids issues with the `typeof` operator\n\t  // in older versions of Chrome and Safari which return 'function' for regexes\n\t  // and Safari 8 which returns 'object' for typed array constructors.\n\t  return isObject(value) && objToString.call(value) == funcTag;\n\t}\n\n\tmodule.exports = isFunction;\n\n\n/***/ },\n/* 19 */\n/***/ function(module, exports) {\n\n\t/**\n\t * Checks if `value` is object-like.\n\t *\n\t * @private\n\t * @param {*} value The value to check.\n\t * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n\t */\n\tfunction isObjectLike(value) {\n\t  return !!value && typeof value == 'object';\n\t}\n\n\tmodule.exports = isObjectLike;\n\n\n/***/ },\n/* 20 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar getLength = __webpack_require__(21),\n\t    isLength = __webpack_require__(23);\n\n\t/**\n\t * Checks if `value` is array-like.\n\t *\n\t * @private\n\t * @param {*} value The value to check.\n\t * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n\t */\n\tfunction isArrayLike(value) {\n\t  return value != null && isLength(getLength(value));\n\t}\n\n\tmodule.exports = isArrayLike;\n\n\n/***/ },\n/* 21 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar baseProperty = __webpack_require__(22);\n\n\t/**\n\t * Gets the \"length\" property value of `object`.\n\t *\n\t * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)\n\t * that affects Safari on at least iOS 8.1-8.3 ARM64.\n\t *\n\t * @private\n\t * @param {Object} object The object to query.\n\t * @returns {*} Returns the \"length\" value.\n\t */\n\tvar getLength = baseProperty('length');\n\n\tmodule.exports = getLength;\n\n\n/***/ },\n/* 22 */\n/***/ function(module, exports) {\n\n\t/**\n\t * The base implementation of `_.property` without support for deep paths.\n\t *\n\t * @private\n\t * @param {string} key The key of the property to get.\n\t * @returns {Function} Returns the new function.\n\t */\n\tfunction baseProperty(key) {\n\t  return function(object) {\n\t    return object == null ? undefined : object[key];\n\t  };\n\t}\n\n\tmodule.exports = baseProperty;\n\n\n/***/ },\n/* 23 */\n/***/ function(module, exports) {\n\n\t/**\n\t * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)\n\t * of an array-like value.\n\t */\n\tvar MAX_SAFE_INTEGER = 9007199254740991;\n\n\t/**\n\t * Checks if `value` is a valid array-like length.\n\t *\n\t * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).\n\t *\n\t * @private\n\t * @param {*} value The value to check.\n\t * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n\t */\n\tfunction isLength(value) {\n\t  return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n\t}\n\n\tmodule.exports = isLength;\n\n\n/***/ },\n/* 24 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar isArguments = __webpack_require__(25),\n\t    isArray = __webpack_require__(26),\n\t    isIndex = __webpack_require__(27),\n\t    isLength = __webpack_require__(23),\n\t    keysIn = __webpack_require__(28);\n\n\t/** Used for native method references. */\n\tvar objectProto = Object.prototype;\n\n\t/** Used to check objects for own properties. */\n\tvar hasOwnProperty = objectProto.hasOwnProperty;\n\n\t/**\n\t * A fallback implementation of `Object.keys` which creates an array of the\n\t * own enumerable property names of `object`.\n\t *\n\t * @private\n\t * @param {Object} object The object to query.\n\t * @returns {Array} Returns the array of property names.\n\t */\n\tfunction shimKeys(object) {\n\t  var props = keysIn(object),\n\t      propsLength = props.length,\n\t      length = propsLength && object.length;\n\n\t  var allowIndexes = !!length && isLength(length) &&\n\t    (isArray(object) || isArguments(object));\n\n\t  var index = -1,\n\t      result = [];\n\n\t  while (++index < propsLength) {\n\t    var key = props[index];\n\t    if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {\n\t      result.push(key);\n\t    }\n\t  }\n\t  return result;\n\t}\n\n\tmodule.exports = shimKeys;\n\n\n/***/ },\n/* 25 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar isArrayLike = __webpack_require__(20),\n\t    isObjectLike = __webpack_require__(19);\n\n\t/** Used for native method references. */\n\tvar objectProto = Object.prototype;\n\n\t/** Used to check objects for own properties. */\n\tvar hasOwnProperty = objectProto.hasOwnProperty;\n\n\t/** Native method references. */\n\tvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n\t/**\n\t * Checks if `value` is classified as an `arguments` object.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Lang\n\t * @param {*} value The value to check.\n\t * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.\n\t * @example\n\t *\n\t * _.isArguments(function() { return arguments; }());\n\t * // => true\n\t *\n\t * _.isArguments([1, 2, 3]);\n\t * // => false\n\t */\n\tfunction isArguments(value) {\n\t  return isObjectLike(value) && isArrayLike(value) &&\n\t    hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee');\n\t}\n\n\tmodule.exports = isArguments;\n\n\n/***/ },\n/* 26 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar getNative = __webpack_require__(16),\n\t    isLength = __webpack_require__(23),\n\t    isObjectLike = __webpack_require__(19);\n\n\t/** `Object#toString` result references. */\n\tvar arrayTag = '[object Array]';\n\n\t/** Used for native method references. */\n\tvar objectProto = Object.prototype;\n\n\t/**\n\t * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)\n\t * of values.\n\t */\n\tvar objToString = objectProto.toString;\n\n\t/* Native method references for those with the same name as other `lodash` methods. */\n\tvar nativeIsArray = getNative(Array, 'isArray');\n\n\t/**\n\t * Checks if `value` is classified as an `Array` object.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Lang\n\t * @param {*} value The value to check.\n\t * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.\n\t * @example\n\t *\n\t * _.isArray([1, 2, 3]);\n\t * // => true\n\t *\n\t * _.isArray(function() { return arguments; }());\n\t * // => false\n\t */\n\tvar isArray = nativeIsArray || function(value) {\n\t  return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;\n\t};\n\n\tmodule.exports = isArray;\n\n\n/***/ },\n/* 27 */\n/***/ function(module, exports) {\n\n\t/** Used to detect unsigned integer values. */\n\tvar reIsUint = /^\\d+$/;\n\n\t/**\n\t * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)\n\t * of an array-like value.\n\t */\n\tvar MAX_SAFE_INTEGER = 9007199254740991;\n\n\t/**\n\t * Checks if `value` is a valid array-like index.\n\t *\n\t * @private\n\t * @param {*} value The value to check.\n\t * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n\t * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n\t */\n\tfunction isIndex(value, length) {\n\t  value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;\n\t  length = length == null ? MAX_SAFE_INTEGER : length;\n\t  return value > -1 && value % 1 == 0 && value < length;\n\t}\n\n\tmodule.exports = isIndex;\n\n\n/***/ },\n/* 28 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar isArguments = __webpack_require__(25),\n\t    isArray = __webpack_require__(26),\n\t    isIndex = __webpack_require__(27),\n\t    isLength = __webpack_require__(23),\n\t    isObject = __webpack_require__(14);\n\n\t/** Used for native method references. */\n\tvar objectProto = Object.prototype;\n\n\t/** Used to check objects for own properties. */\n\tvar hasOwnProperty = objectProto.hasOwnProperty;\n\n\t/**\n\t * Creates an array of the own and inherited enumerable property names of `object`.\n\t *\n\t * **Note:** Non-object values are coerced to objects.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Object\n\t * @param {Object} object The object to query.\n\t * @returns {Array} Returns the array of property names.\n\t * @example\n\t *\n\t * function Foo() {\n\t *   this.a = 1;\n\t *   this.b = 2;\n\t * }\n\t *\n\t * Foo.prototype.c = 3;\n\t *\n\t * _.keysIn(new Foo);\n\t * // => ['a', 'b', 'c'] (iteration order is not guaranteed)\n\t */\n\tfunction keysIn(object) {\n\t  if (object == null) {\n\t    return [];\n\t  }\n\t  if (!isObject(object)) {\n\t    object = Object(object);\n\t  }\n\t  var length = object.length;\n\t  length = (length && isLength(length) &&\n\t    (isArray(object) || isArguments(object)) && length) || 0;\n\n\t  var Ctor = object.constructor,\n\t      index = -1,\n\t      isProto = typeof Ctor == 'function' && Ctor.prototype === object,\n\t      result = Array(length),\n\t      skipIndexes = length > 0;\n\n\t  while (++index < length) {\n\t    result[index] = (index + '');\n\t  }\n\t  for (var key in object) {\n\t    if (!(skipIndexes && isIndex(key, length)) &&\n\t        !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {\n\t      result.push(key);\n\t    }\n\t  }\n\t  return result;\n\t}\n\n\tmodule.exports = keysIn;\n\n\n/***/ },\n/* 29 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar getLength = __webpack_require__(21),\n\t    isLength = __webpack_require__(23),\n\t    toObject = __webpack_require__(13);\n\n\t/**\n\t * Creates a `baseEach` or `baseEachRight` function.\n\t *\n\t * @private\n\t * @param {Function} eachFunc The function to iterate over a collection.\n\t * @param {boolean} [fromRight] Specify iterating from right to left.\n\t * @returns {Function} Returns the new base function.\n\t */\n\tfunction createBaseEach(eachFunc, fromRight) {\n\t  return function(collection, iteratee) {\n\t    var length = collection ? getLength(collection) : 0;\n\t    if (!isLength(length)) {\n\t      return eachFunc(collection, iteratee);\n\t    }\n\t    var index = fromRight ? length : -1,\n\t        iterable = toObject(collection);\n\n\t    while ((fromRight ? index-- : ++index < length)) {\n\t      if (iteratee(iterable[index], index, iterable) === false) {\n\t        break;\n\t      }\n\t    }\n\t    return collection;\n\t  };\n\t}\n\n\tmodule.exports = createBaseEach;\n\n\n/***/ },\n/* 30 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar bindCallback = __webpack_require__(31),\n\t    isArray = __webpack_require__(26);\n\n\t/**\n\t * Creates a function for `_.forEach` or `_.forEachRight`.\n\t *\n\t * @private\n\t * @param {Function} arrayFunc The function to iterate over an array.\n\t * @param {Function} eachFunc The function to iterate over a collection.\n\t * @returns {Function} Returns the new each function.\n\t */\n\tfunction createForEach(arrayFunc, eachFunc) {\n\t  return function(collection, iteratee, thisArg) {\n\t    return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection))\n\t      ? arrayFunc(collection, iteratee)\n\t      : eachFunc(collection, bindCallback(iteratee, thisArg, 3));\n\t  };\n\t}\n\n\tmodule.exports = createForEach;\n\n\n/***/ },\n/* 31 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar identity = __webpack_require__(32);\n\n\t/**\n\t * A specialized version of `baseCallback` which only supports `this` binding\n\t * and specifying the number of arguments to provide to `func`.\n\t *\n\t * @private\n\t * @param {Function} func The function to bind.\n\t * @param {*} thisArg The `this` binding of `func`.\n\t * @param {number} [argCount] The number of arguments to provide to `func`.\n\t * @returns {Function} Returns the callback.\n\t */\n\tfunction bindCallback(func, thisArg, argCount) {\n\t  if (typeof func != 'function') {\n\t    return identity;\n\t  }\n\t  if (thisArg === undefined) {\n\t    return func;\n\t  }\n\t  switch (argCount) {\n\t    case 1: return function(value) {\n\t      return func.call(thisArg, value);\n\t    };\n\t    case 3: return function(value, index, collection) {\n\t      return func.call(thisArg, value, index, collection);\n\t    };\n\t    case 4: return function(accumulator, value, index, collection) {\n\t      return func.call(thisArg, accumulator, value, index, collection);\n\t    };\n\t    case 5: return function(value, other, key, object, source) {\n\t      return func.call(thisArg, value, other, key, object, source);\n\t    };\n\t  }\n\t  return function() {\n\t    return func.apply(thisArg, arguments);\n\t  };\n\t}\n\n\tmodule.exports = bindCallback;\n\n\n/***/ },\n/* 32 */\n/***/ function(module, exports) {\n\n\t/**\n\t * This method returns the first argument provided to it.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Utility\n\t * @param {*} value Any value.\n\t * @returns {*} Returns `value`.\n\t * @example\n\t *\n\t * var object = { 'user': 'fred' };\n\t *\n\t * _.identity(object) === object;\n\t * // => true\n\t */\n\tfunction identity(value) {\n\t  return value;\n\t}\n\n\tmodule.exports = identity;\n\n\n/***/ },\n/* 33 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tmodule.exports = __webpack_require__(34);\n\n\n/***/ },\n/* 34 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar baseIndexOf = __webpack_require__(35),\n\t    getLength = __webpack_require__(21),\n\t    isArray = __webpack_require__(26),\n\t    isIterateeCall = __webpack_require__(37),\n\t    isLength = __webpack_require__(23),\n\t    isString = __webpack_require__(38),\n\t    values = __webpack_require__(39);\n\n\t/* Native method references for those with the same name as other `lodash` methods. */\n\tvar nativeMax = Math.max;\n\n\t/**\n\t * Checks if `target` is in `collection` using\n\t * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)\n\t * for equality comparisons. If `fromIndex` is negative, it's used as the offset\n\t * from the end of `collection`.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @alias contains, include\n\t * @category Collection\n\t * @param {Array|Object|string} collection The collection to search.\n\t * @param {*} target The value to search for.\n\t * @param {number} [fromIndex=0] The index to search from.\n\t * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`.\n\t * @returns {boolean} Returns `true` if a matching element is found, else `false`.\n\t * @example\n\t *\n\t * _.includes([1, 2, 3], 1);\n\t * // => true\n\t *\n\t * _.includes([1, 2, 3], 1, 2);\n\t * // => false\n\t *\n\t * _.includes({ 'user': 'fred', 'age': 40 }, 'fred');\n\t * // => true\n\t *\n\t * _.includes('pebbles', 'eb');\n\t * // => true\n\t */\n\tfunction includes(collection, target, fromIndex, guard) {\n\t  var length = collection ? getLength(collection) : 0;\n\t  if (!isLength(length)) {\n\t    collection = values(collection);\n\t    length = collection.length;\n\t  }\n\t  if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) {\n\t    fromIndex = 0;\n\t  } else {\n\t    fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);\n\t  }\n\t  return (typeof collection == 'string' || !isArray(collection) && isString(collection))\n\t    ? (fromIndex <= length && collection.indexOf(target, fromIndex) > -1)\n\t    : (!!length && baseIndexOf(collection, target, fromIndex) > -1);\n\t}\n\n\tmodule.exports = includes;\n\n\n/***/ },\n/* 35 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar indexOfNaN = __webpack_require__(36);\n\n\t/**\n\t * The base implementation of `_.indexOf` without support for binary searches.\n\t *\n\t * @private\n\t * @param {Array} array The array to search.\n\t * @param {*} value The value to search for.\n\t * @param {number} fromIndex The index to search from.\n\t * @returns {number} Returns the index of the matched value, else `-1`.\n\t */\n\tfunction baseIndexOf(array, value, fromIndex) {\n\t  if (value !== value) {\n\t    return indexOfNaN(array, fromIndex);\n\t  }\n\t  var index = fromIndex - 1,\n\t      length = array.length;\n\n\t  while (++index < length) {\n\t    if (array[index] === value) {\n\t      return index;\n\t    }\n\t  }\n\t  return -1;\n\t}\n\n\tmodule.exports = baseIndexOf;\n\n\n/***/ },\n/* 36 */\n/***/ function(module, exports) {\n\n\t/**\n\t * Gets the index at which the first occurrence of `NaN` is found in `array`.\n\t *\n\t * @private\n\t * @param {Array} array The array to search.\n\t * @param {number} fromIndex The index to search from.\n\t * @param {boolean} [fromRight] Specify iterating from right to left.\n\t * @returns {number} Returns the index of the matched `NaN`, else `-1`.\n\t */\n\tfunction indexOfNaN(array, fromIndex, fromRight) {\n\t  var length = array.length,\n\t      index = fromIndex + (fromRight ? 0 : -1);\n\n\t  while ((fromRight ? index-- : ++index < length)) {\n\t    var other = array[index];\n\t    if (other !== other) {\n\t      return index;\n\t    }\n\t  }\n\t  return -1;\n\t}\n\n\tmodule.exports = indexOfNaN;\n\n\n/***/ },\n/* 37 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar isArrayLike = __webpack_require__(20),\n\t    isIndex = __webpack_require__(27),\n\t    isObject = __webpack_require__(14);\n\n\t/**\n\t * Checks if the provided arguments are from an iteratee call.\n\t *\n\t * @private\n\t * @param {*} value The potential iteratee value argument.\n\t * @param {*} index The potential iteratee index or key argument.\n\t * @param {*} object The potential iteratee object argument.\n\t * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.\n\t */\n\tfunction isIterateeCall(value, index, object) {\n\t  if (!isObject(object)) {\n\t    return false;\n\t  }\n\t  var type = typeof index;\n\t  if (type == 'number'\n\t      ? (isArrayLike(object) && isIndex(index, object.length))\n\t      : (type == 'string' && index in object)) {\n\t    var other = object[index];\n\t    return value === value ? (value === other) : (other !== other);\n\t  }\n\t  return false;\n\t}\n\n\tmodule.exports = isIterateeCall;\n\n\n/***/ },\n/* 38 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar isObjectLike = __webpack_require__(19);\n\n\t/** `Object#toString` result references. */\n\tvar stringTag = '[object String]';\n\n\t/** Used for native method references. */\n\tvar objectProto = Object.prototype;\n\n\t/**\n\t * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)\n\t * of values.\n\t */\n\tvar objToString = objectProto.toString;\n\n\t/**\n\t * Checks if `value` is classified as a `String` primitive or object.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Lang\n\t * @param {*} value The value to check.\n\t * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.\n\t * @example\n\t *\n\t * _.isString('abc');\n\t * // => true\n\t *\n\t * _.isString(1);\n\t * // => false\n\t */\n\tfunction isString(value) {\n\t  return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag);\n\t}\n\n\tmodule.exports = isString;\n\n\n/***/ },\n/* 39 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar baseValues = __webpack_require__(40),\n\t    keys = __webpack_require__(15);\n\n\t/**\n\t * Creates an array of the own enumerable property values of `object`.\n\t *\n\t * **Note:** Non-object values are coerced to objects.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Object\n\t * @param {Object} object The object to query.\n\t * @returns {Array} Returns the array of property values.\n\t * @example\n\t *\n\t * function Foo() {\n\t *   this.a = 1;\n\t *   this.b = 2;\n\t * }\n\t *\n\t * Foo.prototype.c = 3;\n\t *\n\t * _.values(new Foo);\n\t * // => [1, 2] (iteration order is not guaranteed)\n\t *\n\t * _.values('hi');\n\t * // => ['h', 'i']\n\t */\n\tfunction values(object) {\n\t  return baseValues(object, keys(object));\n\t}\n\n\tmodule.exports = values;\n\n\n/***/ },\n/* 40 */\n/***/ function(module, exports) {\n\n\t/**\n\t * The base implementation of `_.values` and `_.valuesIn` which creates an\n\t * array of `object` property values corresponding to the property names\n\t * of `props`.\n\t *\n\t * @private\n\t * @param {Object} object The object to query.\n\t * @param {Array} props The property names to get values for.\n\t * @returns {Object} Returns the array of property values.\n\t */\n\tfunction baseValues(object, props) {\n\t  var index = -1,\n\t      length = props.length,\n\t      result = Array(length);\n\n\t  while (++index < length) {\n\t    result[index] = object[props[index]];\n\t  }\n\t  return result;\n\t}\n\n\tmodule.exports = baseValues;\n\n\n/***/ },\n/* 41 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tmodule.exports = __webpack_require__(42);\n\n\n/***/ },\n/* 42 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar assignWith = __webpack_require__(43),\n\t    baseAssign = __webpack_require__(44),\n\t    createAssigner = __webpack_require__(46);\n\n\t/**\n\t * Assigns own enumerable properties of source object(s) to the destination\n\t * object. Subsequent sources overwrite property assignments of previous sources.\n\t * If `customizer` is provided it's invoked to produce the assigned values.\n\t * The `customizer` is bound to `thisArg` and invoked with five arguments:\n\t * (objectValue, sourceValue, key, object, source).\n\t *\n\t * **Note:** This method mutates `object` and is based on\n\t * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign).\n\t *\n\t * @static\n\t * @memberOf _\n\t * @alias extend\n\t * @category Object\n\t * @param {Object} object The destination object.\n\t * @param {...Object} [sources] The source objects.\n\t * @param {Function} [customizer] The function to customize assigned values.\n\t * @param {*} [thisArg] The `this` binding of `customizer`.\n\t * @returns {Object} Returns `object`.\n\t * @example\n\t *\n\t * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });\n\t * // => { 'user': 'fred', 'age': 40 }\n\t *\n\t * // using a customizer callback\n\t * var defaults = _.partialRight(_.assign, function(value, other) {\n\t *   return _.isUndefined(value) ? other : value;\n\t * });\n\t *\n\t * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });\n\t * // => { 'user': 'barney', 'age': 36 }\n\t */\n\tvar assign = createAssigner(function(object, source, customizer) {\n\t  return customizer\n\t    ? assignWith(object, source, customizer)\n\t    : baseAssign(object, source);\n\t});\n\n\tmodule.exports = assign;\n\n\n/***/ },\n/* 43 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar keys = __webpack_require__(15);\n\n\t/**\n\t * A specialized version of `_.assign` for customizing assigned values without\n\t * support for argument juggling, multiple sources, and `this` binding `customizer`\n\t * functions.\n\t *\n\t * @private\n\t * @param {Object} object The destination object.\n\t * @param {Object} source The source object.\n\t * @param {Function} customizer The function to customize assigned values.\n\t * @returns {Object} Returns `object`.\n\t */\n\tfunction assignWith(object, source, customizer) {\n\t  var index = -1,\n\t      props = keys(source),\n\t      length = props.length;\n\n\t  while (++index < length) {\n\t    var key = props[index],\n\t        value = object[key],\n\t        result = customizer(value, source[key], key, object, source);\n\n\t    if ((result === result ? (result !== value) : (value === value)) ||\n\t        (value === undefined && !(key in object))) {\n\t      object[key] = result;\n\t    }\n\t  }\n\t  return object;\n\t}\n\n\tmodule.exports = assignWith;\n\n\n/***/ },\n/* 44 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar baseCopy = __webpack_require__(45),\n\t    keys = __webpack_require__(15);\n\n\t/**\n\t * The base implementation of `_.assign` without support for argument juggling,\n\t * multiple sources, and `customizer` functions.\n\t *\n\t * @private\n\t * @param {Object} object The destination object.\n\t * @param {Object} source The source object.\n\t * @returns {Object} Returns `object`.\n\t */\n\tfunction baseAssign(object, source) {\n\t  return source == null\n\t    ? object\n\t    : baseCopy(source, keys(source), object);\n\t}\n\n\tmodule.exports = baseAssign;\n\n\n/***/ },\n/* 45 */\n/***/ function(module, exports) {\n\n\t/**\n\t * Copies properties of `source` to `object`.\n\t *\n\t * @private\n\t * @param {Object} source The object to copy properties from.\n\t * @param {Array} props The property names to copy.\n\t * @param {Object} [object={}] The object to copy properties to.\n\t * @returns {Object} Returns `object`.\n\t */\n\tfunction baseCopy(source, props, object) {\n\t  object || (object = {});\n\n\t  var index = -1,\n\t      length = props.length;\n\n\t  while (++index < length) {\n\t    var key = props[index];\n\t    object[key] = source[key];\n\t  }\n\t  return object;\n\t}\n\n\tmodule.exports = baseCopy;\n\n\n/***/ },\n/* 46 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar bindCallback = __webpack_require__(31),\n\t    isIterateeCall = __webpack_require__(37),\n\t    restParam = __webpack_require__(47);\n\n\t/**\n\t * Creates a `_.assign`, `_.defaults`, or `_.merge` function.\n\t *\n\t * @private\n\t * @param {Function} assigner The function to assign values.\n\t * @returns {Function} Returns the new assigner function.\n\t */\n\tfunction createAssigner(assigner) {\n\t  return restParam(function(object, sources) {\n\t    var index = -1,\n\t        length = object == null ? 0 : sources.length,\n\t        customizer = length > 2 ? sources[length - 2] : undefined,\n\t        guard = length > 2 ? sources[2] : undefined,\n\t        thisArg = length > 1 ? sources[length - 1] : undefined;\n\n\t    if (typeof customizer == 'function') {\n\t      customizer = bindCallback(customizer, thisArg, 5);\n\t      length -= 2;\n\t    } else {\n\t      customizer = typeof thisArg == 'function' ? thisArg : undefined;\n\t      length -= (customizer ? 1 : 0);\n\t    }\n\t    if (guard && isIterateeCall(sources[0], sources[1], guard)) {\n\t      customizer = length < 3 ? undefined : customizer;\n\t      length = 1;\n\t    }\n\t    while (++index < length) {\n\t      var source = sources[index];\n\t      if (source) {\n\t        assigner(object, source, customizer);\n\t      }\n\t    }\n\t    return object;\n\t  });\n\t}\n\n\tmodule.exports = createAssigner;\n\n\n/***/ },\n/* 47 */\n/***/ function(module, exports) {\n\n\t/** Used as the `TypeError` message for \"Functions\" methods. */\n\tvar FUNC_ERROR_TEXT = 'Expected a function';\n\n\t/* Native method references for those with the same name as other `lodash` methods. */\n\tvar nativeMax = Math.max;\n\n\t/**\n\t * Creates a function that invokes `func` with the `this` binding of the\n\t * created function and arguments from `start` and beyond provided as an array.\n\t *\n\t * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/Web/JavaScript/Reference/Functions/rest_parameters).\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Function\n\t * @param {Function} func The function to apply a rest parameter to.\n\t * @param {number} [start=func.length-1] The start position of the rest parameter.\n\t * @returns {Function} Returns the new function.\n\t * @example\n\t *\n\t * var say = _.restParam(function(what, names) {\n\t *   return what + ' ' + _.initial(names).join(', ') +\n\t *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);\n\t * });\n\t *\n\t * say('hello', 'fred', 'barney', 'pebbles');\n\t * // => 'hello fred, barney, & pebbles'\n\t */\n\tfunction restParam(func, start) {\n\t  if (typeof func != 'function') {\n\t    throw new TypeError(FUNC_ERROR_TEXT);\n\t  }\n\t  start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0);\n\t  return function() {\n\t    var args = arguments,\n\t        index = -1,\n\t        length = nativeMax(args.length - start, 0),\n\t        rest = Array(length);\n\n\t    while (++index < length) {\n\t      rest[index] = args[start + index];\n\t    }\n\t    switch (start) {\n\t      case 0: return func.call(this, rest);\n\t      case 1: return func.call(this, args[0], rest);\n\t      case 2: return func.call(this, args[0], args[1], rest);\n\t    }\n\t    var otherArgs = Array(start + 1);\n\t    index = -1;\n\t    while (++index < start) {\n\t      otherArgs[index] = args[index];\n\t    }\n\t    otherArgs[start] = rest;\n\t    return func.apply(this, otherArgs);\n\t  };\n\t}\n\n\tmodule.exports = restParam;\n\n\n/***/ },\n/* 48 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar baseToString = __webpack_require__(49);\n\n\t/** Used to generate unique IDs. */\n\tvar idCounter = 0;\n\n\t/**\n\t * Generates a unique ID. If `prefix` is provided the ID is appended to it.\n\t *\n\t * @static\n\t * @memberOf _\n\t * @category Utility\n\t * @param {string} [prefix] The value to prefix the ID with.\n\t * @returns {string} Returns the unique ID.\n\t * @example\n\t *\n\t * _.uniqueId('contact_');\n\t * // => 'contact_104'\n\t *\n\t * _.uniqueId();\n\t * // => '105'\n\t */\n\tfunction uniqueId(prefix) {\n\t  var id = ++idCounter;\n\t  return baseToString(prefix) + id;\n\t}\n\n\tmodule.exports = uniqueId;\n\n\n/***/ },\n/* 49 */\n/***/ function(module, exports) {\n\n\t/**\n\t * Converts `value` to a string if it's not one. An empty string is returned\n\t * for `null` or `undefined` values.\n\t *\n\t * @private\n\t * @param {*} value The value to process.\n\t * @returns {string} Returns the string.\n\t */\n\tfunction baseToString(value) {\n\t  return value == null ? '' : (value + '');\n\t}\n\n\tmodule.exports = baseToString;\n\n\n/***/ }\n/******/ ]);"
  },
  {
    "path": "resources/public/js/bootstrap.js",
    "content": "/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under the MIT license\n */\n\nif (typeof jQuery === 'undefined') {\n  throw new Error('Bootstrap\\'s JavaScript requires jQuery')\n}\n\n+function ($) {\n  'use strict';\n  var version = $.fn.jquery.split(' ')[0].split('.')\n  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {\n    throw new Error('Bootstrap\\'s JavaScript requires jQuery version 1.9.1 or higher')\n  }\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: transition.js v3.3.5\n * http://getbootstrap.com/javascript/#transitions\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)\n  // ============================================================\n\n  function transitionEnd() {\n    var el = document.createElement('bootstrap')\n\n    var transEndEventNames = {\n      WebkitTransition : 'webkitTransitionEnd',\n      MozTransition    : 'transitionend',\n      OTransition      : 'oTransitionEnd otransitionend',\n      transition       : 'transitionend'\n    }\n\n    for (var name in transEndEventNames) {\n      if (el.style[name] !== undefined) {\n        return { end: transEndEventNames[name] }\n      }\n    }\n\n    return false // explicit for ie8 (  ._.)\n  }\n\n  // http://blog.alexmaccaw.com/css-transitions\n  $.fn.emulateTransitionEnd = function (duration) {\n    var called = false\n    var $el = this\n    $(this).one('bsTransitionEnd', function () { called = true })\n    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }\n    setTimeout(callback, duration)\n    return this\n  }\n\n  $(function () {\n    $.support.transition = transitionEnd()\n\n    if (!$.support.transition) return\n\n    $.event.special.bsTransitionEnd = {\n      bindType: $.support.transition.end,\n      delegateType: $.support.transition.end,\n      handle: function (e) {\n        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)\n      }\n    }\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: alert.js v3.3.5\n * http://getbootstrap.com/javascript/#alerts\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // ALERT CLASS DEFINITION\n  // ======================\n\n  var dismiss = '[data-dismiss=\"alert\"]'\n  var Alert   = function (el) {\n    $(el).on('click', dismiss, this.close)\n  }\n\n  Alert.VERSION = '3.3.5'\n\n  Alert.TRANSITION_DURATION = 150\n\n  Alert.prototype.close = function (e) {\n    var $this    = $(this)\n    var selector = $this.attr('data-target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    var $parent = $(selector)\n\n    if (e) e.preventDefault()\n\n    if (!$parent.length) {\n      $parent = $this.closest('.alert')\n    }\n\n    $parent.trigger(e = $.Event('close.bs.alert'))\n\n    if (e.isDefaultPrevented()) return\n\n    $parent.removeClass('in')\n\n    function removeElement() {\n      // detach from parent, fire event then clean up data\n      $parent.detach().trigger('closed.bs.alert').remove()\n    }\n\n    $.support.transition && $parent.hasClass('fade') ?\n      $parent\n        .one('bsTransitionEnd', removeElement)\n        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :\n      removeElement()\n  }\n\n\n  // ALERT PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.alert')\n\n      if (!data) $this.data('bs.alert', (data = new Alert(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  var old = $.fn.alert\n\n  $.fn.alert             = Plugin\n  $.fn.alert.Constructor = Alert\n\n\n  // ALERT NO CONFLICT\n  // =================\n\n  $.fn.alert.noConflict = function () {\n    $.fn.alert = old\n    return this\n  }\n\n\n  // ALERT DATA-API\n  // ==============\n\n  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: button.js v3.3.5\n * http://getbootstrap.com/javascript/#buttons\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // BUTTON PUBLIC CLASS DEFINITION\n  // ==============================\n\n  var Button = function (element, options) {\n    this.$element  = $(element)\n    this.options   = $.extend({}, Button.DEFAULTS, options)\n    this.isLoading = false\n  }\n\n  Button.VERSION  = '3.3.5'\n\n  Button.DEFAULTS = {\n    loadingText: 'loading...'\n  }\n\n  Button.prototype.setState = function (state) {\n    var d    = 'disabled'\n    var $el  = this.$element\n    var val  = $el.is('input') ? 'val' : 'html'\n    var data = $el.data()\n\n    state += 'Text'\n\n    if (data.resetText == null) $el.data('resetText', $el[val]())\n\n    // push to event loop to allow forms to submit\n    setTimeout($.proxy(function () {\n      $el[val](data[state] == null ? this.options[state] : data[state])\n\n      if (state == 'loadingText') {\n        this.isLoading = true\n        $el.addClass(d).attr(d, d)\n      } else if (this.isLoading) {\n        this.isLoading = false\n        $el.removeClass(d).removeAttr(d)\n      }\n    }, this), 0)\n  }\n\n  Button.prototype.toggle = function () {\n    var changed = true\n    var $parent = this.$element.closest('[data-toggle=\"buttons\"]')\n\n    if ($parent.length) {\n      var $input = this.$element.find('input')\n      if ($input.prop('type') == 'radio') {\n        if ($input.prop('checked')) changed = false\n        $parent.find('.active').removeClass('active')\n        this.$element.addClass('active')\n      } else if ($input.prop('type') == 'checkbox') {\n        if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false\n        this.$element.toggleClass('active')\n      }\n      $input.prop('checked', this.$element.hasClass('active'))\n      if (changed) $input.trigger('change')\n    } else {\n      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))\n      this.$element.toggleClass('active')\n    }\n  }\n\n\n  // BUTTON PLUGIN DEFINITION\n  // ========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.button')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.button', (data = new Button(this, options)))\n\n      if (option == 'toggle') data.toggle()\n      else if (option) data.setState(option)\n    })\n  }\n\n  var old = $.fn.button\n\n  $.fn.button             = Plugin\n  $.fn.button.Constructor = Button\n\n\n  // BUTTON NO CONFLICT\n  // ==================\n\n  $.fn.button.noConflict = function () {\n    $.fn.button = old\n    return this\n  }\n\n\n  // BUTTON DATA-API\n  // ===============\n\n  $(document)\n    .on('click.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n      var $btn = $(e.target)\n      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')\n      Plugin.call($btn, 'toggle')\n      if (!($(e.target).is('input[type=\"radio\"]') || $(e.target).is('input[type=\"checkbox\"]'))) e.preventDefault()\n    })\n    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))\n    })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: carousel.js v3.3.5\n * http://getbootstrap.com/javascript/#carousel\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // CAROUSEL CLASS DEFINITION\n  // =========================\n\n  var Carousel = function (element, options) {\n    this.$element    = $(element)\n    this.$indicators = this.$element.find('.carousel-indicators')\n    this.options     = options\n    this.paused      = null\n    this.sliding     = null\n    this.interval    = null\n    this.$active     = null\n    this.$items      = null\n\n    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))\n\n    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element\n      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))\n      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))\n  }\n\n  Carousel.VERSION  = '3.3.5'\n\n  Carousel.TRANSITION_DURATION = 600\n\n  Carousel.DEFAULTS = {\n    interval: 5000,\n    pause: 'hover',\n    wrap: true,\n    keyboard: true\n  }\n\n  Carousel.prototype.keydown = function (e) {\n    if (/input|textarea/i.test(e.target.tagName)) return\n    switch (e.which) {\n      case 37: this.prev(); break\n      case 39: this.next(); break\n      default: return\n    }\n\n    e.preventDefault()\n  }\n\n  Carousel.prototype.cycle = function (e) {\n    e || (this.paused = false)\n\n    this.interval && clearInterval(this.interval)\n\n    this.options.interval\n      && !this.paused\n      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))\n\n    return this\n  }\n\n  Carousel.prototype.getItemIndex = function (item) {\n    this.$items = item.parent().children('.item')\n    return this.$items.index(item || this.$active)\n  }\n\n  Carousel.prototype.getItemForDirection = function (direction, active) {\n    var activeIndex = this.getItemIndex(active)\n    var willWrap = (direction == 'prev' && activeIndex === 0)\n                || (direction == 'next' && activeIndex == (this.$items.length - 1))\n    if (willWrap && !this.options.wrap) return active\n    var delta = direction == 'prev' ? -1 : 1\n    var itemIndex = (activeIndex + delta) % this.$items.length\n    return this.$items.eq(itemIndex)\n  }\n\n  Carousel.prototype.to = function (pos) {\n    var that        = this\n    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))\n\n    if (pos > (this.$items.length - 1) || pos < 0) return\n\n    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, \"slid\"\n    if (activeIndex == pos) return this.pause().cycle()\n\n    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))\n  }\n\n  Carousel.prototype.pause = function (e) {\n    e || (this.paused = true)\n\n    if (this.$element.find('.next, .prev').length && $.support.transition) {\n      this.$element.trigger($.support.transition.end)\n      this.cycle(true)\n    }\n\n    this.interval = clearInterval(this.interval)\n\n    return this\n  }\n\n  Carousel.prototype.next = function () {\n    if (this.sliding) return\n    return this.slide('next')\n  }\n\n  Carousel.prototype.prev = function () {\n    if (this.sliding) return\n    return this.slide('prev')\n  }\n\n  Carousel.prototype.slide = function (type, next) {\n    var $active   = this.$element.find('.item.active')\n    var $next     = next || this.getItemForDirection(type, $active)\n    var isCycling = this.interval\n    var direction = type == 'next' ? 'left' : 'right'\n    var that      = this\n\n    if ($next.hasClass('active')) return (this.sliding = false)\n\n    var relatedTarget = $next[0]\n    var slideEvent = $.Event('slide.bs.carousel', {\n      relatedTarget: relatedTarget,\n      direction: direction\n    })\n    this.$element.trigger(slideEvent)\n    if (slideEvent.isDefaultPrevented()) return\n\n    this.sliding = true\n\n    isCycling && this.pause()\n\n    if (this.$indicators.length) {\n      this.$indicators.find('.active').removeClass('active')\n      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])\n      $nextIndicator && $nextIndicator.addClass('active')\n    }\n\n    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, \"slid\"\n    if ($.support.transition && this.$element.hasClass('slide')) {\n      $next.addClass(type)\n      $next[0].offsetWidth // force reflow\n      $active.addClass(direction)\n      $next.addClass(direction)\n      $active\n        .one('bsTransitionEnd', function () {\n          $next.removeClass([type, direction].join(' ')).addClass('active')\n          $active.removeClass(['active', direction].join(' '))\n          that.sliding = false\n          setTimeout(function () {\n            that.$element.trigger(slidEvent)\n          }, 0)\n        })\n        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)\n    } else {\n      $active.removeClass('active')\n      $next.addClass('active')\n      this.sliding = false\n      this.$element.trigger(slidEvent)\n    }\n\n    isCycling && this.cycle()\n\n    return this\n  }\n\n\n  // CAROUSEL PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.carousel')\n      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)\n      var action  = typeof option == 'string' ? option : options.slide\n\n      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))\n      if (typeof option == 'number') data.to(option)\n      else if (action) data[action]()\n      else if (options.interval) data.pause().cycle()\n    })\n  }\n\n  var old = $.fn.carousel\n\n  $.fn.carousel             = Plugin\n  $.fn.carousel.Constructor = Carousel\n\n\n  // CAROUSEL NO CONFLICT\n  // ====================\n\n  $.fn.carousel.noConflict = function () {\n    $.fn.carousel = old\n    return this\n  }\n\n\n  // CAROUSEL DATA-API\n  // =================\n\n  var clickHandler = function (e) {\n    var href\n    var $this   = $(this)\n    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) // strip for ie7\n    if (!$target.hasClass('carousel')) return\n    var options = $.extend({}, $target.data(), $this.data())\n    var slideIndex = $this.attr('data-slide-to')\n    if (slideIndex) options.interval = false\n\n    Plugin.call($target, options)\n\n    if (slideIndex) {\n      $target.data('bs.carousel').to(slideIndex)\n    }\n\n    e.preventDefault()\n  }\n\n  $(document)\n    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)\n    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)\n\n  $(window).on('load', function () {\n    $('[data-ride=\"carousel\"]').each(function () {\n      var $carousel = $(this)\n      Plugin.call($carousel, $carousel.data())\n    })\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: collapse.js v3.3.5\n * http://getbootstrap.com/javascript/#collapse\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // COLLAPSE PUBLIC CLASS DEFINITION\n  // ================================\n\n  var Collapse = function (element, options) {\n    this.$element      = $(element)\n    this.options       = $.extend({}, Collapse.DEFAULTS, options)\n    this.$trigger      = $('[data-toggle=\"collapse\"][href=\"#' + element.id + '\"],' +\n                           '[data-toggle=\"collapse\"][data-target=\"#' + element.id + '\"]')\n    this.transitioning = null\n\n    if (this.options.parent) {\n      this.$parent = this.getParent()\n    } else {\n      this.addAriaAndCollapsedClass(this.$element, this.$trigger)\n    }\n\n    if (this.options.toggle) this.toggle()\n  }\n\n  Collapse.VERSION  = '3.3.5'\n\n  Collapse.TRANSITION_DURATION = 350\n\n  Collapse.DEFAULTS = {\n    toggle: true\n  }\n\n  Collapse.prototype.dimension = function () {\n    var hasWidth = this.$element.hasClass('width')\n    return hasWidth ? 'width' : 'height'\n  }\n\n  Collapse.prototype.show = function () {\n    if (this.transitioning || this.$element.hasClass('in')) return\n\n    var activesData\n    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')\n\n    if (actives && actives.length) {\n      activesData = actives.data('bs.collapse')\n      if (activesData && activesData.transitioning) return\n    }\n\n    var startEvent = $.Event('show.bs.collapse')\n    this.$element.trigger(startEvent)\n    if (startEvent.isDefaultPrevented()) return\n\n    if (actives && actives.length) {\n      Plugin.call(actives, 'hide')\n      activesData || actives.data('bs.collapse', null)\n    }\n\n    var dimension = this.dimension()\n\n    this.$element\n      .removeClass('collapse')\n      .addClass('collapsing')[dimension](0)\n      .attr('aria-expanded', true)\n\n    this.$trigger\n      .removeClass('collapsed')\n      .attr('aria-expanded', true)\n\n    this.transitioning = 1\n\n    var complete = function () {\n      this.$element\n        .removeClass('collapsing')\n        .addClass('collapse in')[dimension]('')\n      this.transitioning = 0\n      this.$element\n        .trigger('shown.bs.collapse')\n    }\n\n    if (!$.support.transition) return complete.call(this)\n\n    var scrollSize = $.camelCase(['scroll', dimension].join('-'))\n\n    this.$element\n      .one('bsTransitionEnd', $.proxy(complete, this))\n      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])\n  }\n\n  Collapse.prototype.hide = function () {\n    if (this.transitioning || !this.$element.hasClass('in')) return\n\n    var startEvent = $.Event('hide.bs.collapse')\n    this.$element.trigger(startEvent)\n    if (startEvent.isDefaultPrevented()) return\n\n    var dimension = this.dimension()\n\n    this.$element[dimension](this.$element[dimension]())[0].offsetHeight\n\n    this.$element\n      .addClass('collapsing')\n      .removeClass('collapse in')\n      .attr('aria-expanded', false)\n\n    this.$trigger\n      .addClass('collapsed')\n      .attr('aria-expanded', false)\n\n    this.transitioning = 1\n\n    var complete = function () {\n      this.transitioning = 0\n      this.$element\n        .removeClass('collapsing')\n        .addClass('collapse')\n        .trigger('hidden.bs.collapse')\n    }\n\n    if (!$.support.transition) return complete.call(this)\n\n    this.$element\n      [dimension](0)\n      .one('bsTransitionEnd', $.proxy(complete, this))\n      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)\n  }\n\n  Collapse.prototype.toggle = function () {\n    this[this.$element.hasClass('in') ? 'hide' : 'show']()\n  }\n\n  Collapse.prototype.getParent = function () {\n    return $(this.options.parent)\n      .find('[data-toggle=\"collapse\"][data-parent=\"' + this.options.parent + '\"]')\n      .each($.proxy(function (i, element) {\n        var $element = $(element)\n        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)\n      }, this))\n      .end()\n  }\n\n  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {\n    var isOpen = $element.hasClass('in')\n\n    $element.attr('aria-expanded', isOpen)\n    $trigger\n      .toggleClass('collapsed', !isOpen)\n      .attr('aria-expanded', isOpen)\n  }\n\n  function getTargetFromTrigger($trigger) {\n    var href\n    var target = $trigger.attr('data-target')\n      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '') // strip for ie7\n\n    return $(target)\n  }\n\n\n  // COLLAPSE PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.collapse')\n      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)\n\n      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false\n      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.collapse\n\n  $.fn.collapse             = Plugin\n  $.fn.collapse.Constructor = Collapse\n\n\n  // COLLAPSE NO CONFLICT\n  // ====================\n\n  $.fn.collapse.noConflict = function () {\n    $.fn.collapse = old\n    return this\n  }\n\n\n  // COLLAPSE DATA-API\n  // =================\n\n  $(document).on('click.bs.collapse.data-api', '[data-toggle=\"collapse\"]', function (e) {\n    var $this   = $(this)\n\n    if (!$this.attr('data-target')) e.preventDefault()\n\n    var $target = getTargetFromTrigger($this)\n    var data    = $target.data('bs.collapse')\n    var option  = data ? 'toggle' : $this.data()\n\n    Plugin.call($target, option)\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: dropdown.js v3.3.5\n * http://getbootstrap.com/javascript/#dropdowns\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // DROPDOWN CLASS DEFINITION\n  // =========================\n\n  var backdrop = '.dropdown-backdrop'\n  var toggle   = '[data-toggle=\"dropdown\"]'\n  var Dropdown = function (element) {\n    $(element).on('click.bs.dropdown', this.toggle)\n  }\n\n  Dropdown.VERSION = '3.3.5'\n\n  function getParent($this) {\n    var selector = $this.attr('data-target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    var $parent = selector && $(selector)\n\n    return $parent && $parent.length ? $parent : $this.parent()\n  }\n\n  function clearMenus(e) {\n    if (e && e.which === 3) return\n    $(backdrop).remove()\n    $(toggle).each(function () {\n      var $this         = $(this)\n      var $parent       = getParent($this)\n      var relatedTarget = { relatedTarget: this }\n\n      if (!$parent.hasClass('open')) return\n\n      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return\n\n      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))\n\n      if (e.isDefaultPrevented()) return\n\n      $this.attr('aria-expanded', 'false')\n      $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)\n    })\n  }\n\n  Dropdown.prototype.toggle = function (e) {\n    var $this = $(this)\n\n    if ($this.is('.disabled, :disabled')) return\n\n    var $parent  = getParent($this)\n    var isActive = $parent.hasClass('open')\n\n    clearMenus()\n\n    if (!isActive) {\n      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {\n        // if mobile we use a backdrop because click events don't delegate\n        $(document.createElement('div'))\n          .addClass('dropdown-backdrop')\n          .insertAfter($(this))\n          .on('click', clearMenus)\n      }\n\n      var relatedTarget = { relatedTarget: this }\n      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))\n\n      if (e.isDefaultPrevented()) return\n\n      $this\n        .trigger('focus')\n        .attr('aria-expanded', 'true')\n\n      $parent\n        .toggleClass('open')\n        .trigger('shown.bs.dropdown', relatedTarget)\n    }\n\n    return false\n  }\n\n  Dropdown.prototype.keydown = function (e) {\n    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return\n\n    var $this = $(this)\n\n    e.preventDefault()\n    e.stopPropagation()\n\n    if ($this.is('.disabled, :disabled')) return\n\n    var $parent  = getParent($this)\n    var isActive = $parent.hasClass('open')\n\n    if (!isActive && e.which != 27 || isActive && e.which == 27) {\n      if (e.which == 27) $parent.find(toggle).trigger('focus')\n      return $this.trigger('click')\n    }\n\n    var desc = ' li:not(.disabled):visible a'\n    var $items = $parent.find('.dropdown-menu' + desc)\n\n    if (!$items.length) return\n\n    var index = $items.index(e.target)\n\n    if (e.which == 38 && index > 0)                 index--         // up\n    if (e.which == 40 && index < $items.length - 1) index++         // down\n    if (!~index)                                    index = 0\n\n    $items.eq(index).trigger('focus')\n  }\n\n\n  // DROPDOWN PLUGIN DEFINITION\n  // ==========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.dropdown')\n\n      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))\n      if (typeof option == 'string') data[option].call($this)\n    })\n  }\n\n  var old = $.fn.dropdown\n\n  $.fn.dropdown             = Plugin\n  $.fn.dropdown.Constructor = Dropdown\n\n\n  // DROPDOWN NO CONFLICT\n  // ====================\n\n  $.fn.dropdown.noConflict = function () {\n    $.fn.dropdown = old\n    return this\n  }\n\n\n  // APPLY TO STANDARD DROPDOWN ELEMENTS\n  // ===================================\n\n  $(document)\n    .on('click.bs.dropdown.data-api', clearMenus)\n    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })\n    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)\n    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)\n    .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: modal.js v3.3.5\n * http://getbootstrap.com/javascript/#modals\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // MODAL CLASS DEFINITION\n  // ======================\n\n  var Modal = function (element, options) {\n    this.options             = options\n    this.$body               = $(document.body)\n    this.$element            = $(element)\n    this.$dialog             = this.$element.find('.modal-dialog')\n    this.$backdrop           = null\n    this.isShown             = null\n    this.originalBodyPad     = null\n    this.scrollbarWidth      = 0\n    this.ignoreBackdropClick = false\n\n    if (this.options.remote) {\n      this.$element\n        .find('.modal-content')\n        .load(this.options.remote, $.proxy(function () {\n          this.$element.trigger('loaded.bs.modal')\n        }, this))\n    }\n  }\n\n  Modal.VERSION  = '3.3.5'\n\n  Modal.TRANSITION_DURATION = 300\n  Modal.BACKDROP_TRANSITION_DURATION = 150\n\n  Modal.DEFAULTS = {\n    backdrop: true,\n    keyboard: true,\n    show: true\n  }\n\n  Modal.prototype.toggle = function (_relatedTarget) {\n    return this.isShown ? this.hide() : this.show(_relatedTarget)\n  }\n\n  Modal.prototype.show = function (_relatedTarget) {\n    var that = this\n    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })\n\n    this.$element.trigger(e)\n\n    if (this.isShown || e.isDefaultPrevented()) return\n\n    this.isShown = true\n\n    this.checkScrollbar()\n    this.setScrollbar()\n    this.$body.addClass('modal-open')\n\n    this.escape()\n    this.resize()\n\n    this.$element.on('click.dismiss.bs.modal', '[data-dismiss=\"modal\"]', $.proxy(this.hide, this))\n\n    this.$dialog.on('mousedown.dismiss.bs.modal', function () {\n      that.$element.one('mouseup.dismiss.bs.modal', function (e) {\n        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true\n      })\n    })\n\n    this.backdrop(function () {\n      var transition = $.support.transition && that.$element.hasClass('fade')\n\n      if (!that.$element.parent().length) {\n        that.$element.appendTo(that.$body) // don't move modals dom position\n      }\n\n      that.$element\n        .show()\n        .scrollTop(0)\n\n      that.adjustDialog()\n\n      if (transition) {\n        that.$element[0].offsetWidth // force reflow\n      }\n\n      that.$element.addClass('in')\n\n      that.enforceFocus()\n\n      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })\n\n      transition ?\n        that.$dialog // wait for modal to slide in\n          .one('bsTransitionEnd', function () {\n            that.$element.trigger('focus').trigger(e)\n          })\n          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n        that.$element.trigger('focus').trigger(e)\n    })\n  }\n\n  Modal.prototype.hide = function (e) {\n    if (e) e.preventDefault()\n\n    e = $.Event('hide.bs.modal')\n\n    this.$element.trigger(e)\n\n    if (!this.isShown || e.isDefaultPrevented()) return\n\n    this.isShown = false\n\n    this.escape()\n    this.resize()\n\n    $(document).off('focusin.bs.modal')\n\n    this.$element\n      .removeClass('in')\n      .off('click.dismiss.bs.modal')\n      .off('mouseup.dismiss.bs.modal')\n\n    this.$dialog.off('mousedown.dismiss.bs.modal')\n\n    $.support.transition && this.$element.hasClass('fade') ?\n      this.$element\n        .one('bsTransitionEnd', $.proxy(this.hideModal, this))\n        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n      this.hideModal()\n  }\n\n  Modal.prototype.enforceFocus = function () {\n    $(document)\n      .off('focusin.bs.modal') // guard against infinite focus loop\n      .on('focusin.bs.modal', $.proxy(function (e) {\n        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {\n          this.$element.trigger('focus')\n        }\n      }, this))\n  }\n\n  Modal.prototype.escape = function () {\n    if (this.isShown && this.options.keyboard) {\n      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {\n        e.which == 27 && this.hide()\n      }, this))\n    } else if (!this.isShown) {\n      this.$element.off('keydown.dismiss.bs.modal')\n    }\n  }\n\n  Modal.prototype.resize = function () {\n    if (this.isShown) {\n      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))\n    } else {\n      $(window).off('resize.bs.modal')\n    }\n  }\n\n  Modal.prototype.hideModal = function () {\n    var that = this\n    this.$element.hide()\n    this.backdrop(function () {\n      that.$body.removeClass('modal-open')\n      that.resetAdjustments()\n      that.resetScrollbar()\n      that.$element.trigger('hidden.bs.modal')\n    })\n  }\n\n  Modal.prototype.removeBackdrop = function () {\n    this.$backdrop && this.$backdrop.remove()\n    this.$backdrop = null\n  }\n\n  Modal.prototype.backdrop = function (callback) {\n    var that = this\n    var animate = this.$element.hasClass('fade') ? 'fade' : ''\n\n    if (this.isShown && this.options.backdrop) {\n      var doAnimate = $.support.transition && animate\n\n      this.$backdrop = $(document.createElement('div'))\n        .addClass('modal-backdrop ' + animate)\n        .appendTo(this.$body)\n\n      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {\n        if (this.ignoreBackdropClick) {\n          this.ignoreBackdropClick = false\n          return\n        }\n        if (e.target !== e.currentTarget) return\n        this.options.backdrop == 'static'\n          ? this.$element[0].focus()\n          : this.hide()\n      }, this))\n\n      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow\n\n      this.$backdrop.addClass('in')\n\n      if (!callback) return\n\n      doAnimate ?\n        this.$backdrop\n          .one('bsTransitionEnd', callback)\n          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n        callback()\n\n    } else if (!this.isShown && this.$backdrop) {\n      this.$backdrop.removeClass('in')\n\n      var callbackRemove = function () {\n        that.removeBackdrop()\n        callback && callback()\n      }\n      $.support.transition && this.$element.hasClass('fade') ?\n        this.$backdrop\n          .one('bsTransitionEnd', callbackRemove)\n          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n        callbackRemove()\n\n    } else if (callback) {\n      callback()\n    }\n  }\n\n  // these following methods are used to handle overflowing modals\n\n  Modal.prototype.handleUpdate = function () {\n    this.adjustDialog()\n  }\n\n  Modal.prototype.adjustDialog = function () {\n    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight\n\n    this.$element.css({\n      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',\n      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''\n    })\n  }\n\n  Modal.prototype.resetAdjustments = function () {\n    this.$element.css({\n      paddingLeft: '',\n      paddingRight: ''\n    })\n  }\n\n  Modal.prototype.checkScrollbar = function () {\n    var fullWindowWidth = window.innerWidth\n    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8\n      var documentElementRect = document.documentElement.getBoundingClientRect()\n      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)\n    }\n    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth\n    this.scrollbarWidth = this.measureScrollbar()\n  }\n\n  Modal.prototype.setScrollbar = function () {\n    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)\n    this.originalBodyPad = document.body.style.paddingRight || ''\n    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)\n  }\n\n  Modal.prototype.resetScrollbar = function () {\n    this.$body.css('padding-right', this.originalBodyPad)\n  }\n\n  Modal.prototype.measureScrollbar = function () { // thx walsh\n    var scrollDiv = document.createElement('div')\n    scrollDiv.className = 'modal-scrollbar-measure'\n    this.$body.append(scrollDiv)\n    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth\n    this.$body[0].removeChild(scrollDiv)\n    return scrollbarWidth\n  }\n\n\n  // MODAL PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option, _relatedTarget) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.modal')\n      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)\n\n      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))\n      if (typeof option == 'string') data[option](_relatedTarget)\n      else if (options.show) data.show(_relatedTarget)\n    })\n  }\n\n  var old = $.fn.modal\n\n  $.fn.modal             = Plugin\n  $.fn.modal.Constructor = Modal\n\n\n  // MODAL NO CONFLICT\n  // =================\n\n  $.fn.modal.noConflict = function () {\n    $.fn.modal = old\n    return this\n  }\n\n\n  // MODAL DATA-API\n  // ==============\n\n  $(document).on('click.bs.modal.data-api', '[data-toggle=\"modal\"]', function (e) {\n    var $this   = $(this)\n    var href    = $this.attr('href')\n    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\\s]+$)/, ''))) // strip for ie7\n    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())\n\n    if ($this.is('a')) e.preventDefault()\n\n    $target.one('show.bs.modal', function (showEvent) {\n      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown\n      $target.one('hidden.bs.modal', function () {\n        $this.is(':visible') && $this.trigger('focus')\n      })\n    })\n    Plugin.call($target, option, this)\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: tooltip.js v3.3.5\n * http://getbootstrap.com/javascript/#tooltip\n * Inspired by the original jQuery.tipsy by Jason Frame\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // TOOLTIP PUBLIC CLASS DEFINITION\n  // ===============================\n\n  var Tooltip = function (element, options) {\n    this.type       = null\n    this.options    = null\n    this.enabled    = null\n    this.timeout    = null\n    this.hoverState = null\n    this.$element   = null\n    this.inState    = null\n\n    this.init('tooltip', element, options)\n  }\n\n  Tooltip.VERSION  = '3.3.5'\n\n  Tooltip.TRANSITION_DURATION = 150\n\n  Tooltip.DEFAULTS = {\n    animation: true,\n    placement: 'top',\n    selector: false,\n    template: '<div class=\"tooltip\" role=\"tooltip\"><div class=\"tooltip-arrow\"></div><div class=\"tooltip-inner\"></div></div>',\n    trigger: 'hover focus',\n    title: '',\n    delay: 0,\n    html: false,\n    container: false,\n    viewport: {\n      selector: 'body',\n      padding: 0\n    }\n  }\n\n  Tooltip.prototype.init = function (type, element, options) {\n    this.enabled   = true\n    this.type      = type\n    this.$element  = $(element)\n    this.options   = this.getOptions(options)\n    this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))\n    this.inState   = { click: false, hover: false, focus: false }\n\n    if (this.$element[0] instanceof document.constructor && !this.options.selector) {\n      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')\n    }\n\n    var triggers = this.options.trigger.split(' ')\n\n    for (var i = triggers.length; i--;) {\n      var trigger = triggers[i]\n\n      if (trigger == 'click') {\n        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))\n      } else if (trigger != 'manual') {\n        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'\n        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'\n\n        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))\n        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))\n      }\n    }\n\n    this.options.selector ?\n      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :\n      this.fixTitle()\n  }\n\n  Tooltip.prototype.getDefaults = function () {\n    return Tooltip.DEFAULTS\n  }\n\n  Tooltip.prototype.getOptions = function (options) {\n    options = $.extend({}, this.getDefaults(), this.$element.data(), options)\n\n    if (options.delay && typeof options.delay == 'number') {\n      options.delay = {\n        show: options.delay,\n        hide: options.delay\n      }\n    }\n\n    return options\n  }\n\n  Tooltip.prototype.getDelegateOptions = function () {\n    var options  = {}\n    var defaults = this.getDefaults()\n\n    this._options && $.each(this._options, function (key, value) {\n      if (defaults[key] != value) options[key] = value\n    })\n\n    return options\n  }\n\n  Tooltip.prototype.enter = function (obj) {\n    var self = obj instanceof this.constructor ?\n      obj : $(obj.currentTarget).data('bs.' + this.type)\n\n    if (!self) {\n      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n      $(obj.currentTarget).data('bs.' + this.type, self)\n    }\n\n    if (obj instanceof $.Event) {\n      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true\n    }\n\n    if (self.tip().hasClass('in') || self.hoverState == 'in') {\n      self.hoverState = 'in'\n      return\n    }\n\n    clearTimeout(self.timeout)\n\n    self.hoverState = 'in'\n\n    if (!self.options.delay || !self.options.delay.show) return self.show()\n\n    self.timeout = setTimeout(function () {\n      if (self.hoverState == 'in') self.show()\n    }, self.options.delay.show)\n  }\n\n  Tooltip.prototype.isInStateTrue = function () {\n    for (var key in this.inState) {\n      if (this.inState[key]) return true\n    }\n\n    return false\n  }\n\n  Tooltip.prototype.leave = function (obj) {\n    var self = obj instanceof this.constructor ?\n      obj : $(obj.currentTarget).data('bs.' + this.type)\n\n    if (!self) {\n      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n      $(obj.currentTarget).data('bs.' + this.type, self)\n    }\n\n    if (obj instanceof $.Event) {\n      self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false\n    }\n\n    if (self.isInStateTrue()) return\n\n    clearTimeout(self.timeout)\n\n    self.hoverState = 'out'\n\n    if (!self.options.delay || !self.options.delay.hide) return self.hide()\n\n    self.timeout = setTimeout(function () {\n      if (self.hoverState == 'out') self.hide()\n    }, self.options.delay.hide)\n  }\n\n  Tooltip.prototype.show = function () {\n    var e = $.Event('show.bs.' + this.type)\n\n    if (this.hasContent() && this.enabled) {\n      this.$element.trigger(e)\n\n      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])\n      if (e.isDefaultPrevented() || !inDom) return\n      var that = this\n\n      var $tip = this.tip()\n\n      var tipId = this.getUID(this.type)\n\n      this.setContent()\n      $tip.attr('id', tipId)\n      this.$element.attr('aria-describedby', tipId)\n\n      if (this.options.animation) $tip.addClass('fade')\n\n      var placement = typeof this.options.placement == 'function' ?\n        this.options.placement.call(this, $tip[0], this.$element[0]) :\n        this.options.placement\n\n      var autoToken = /\\s?auto?\\s?/i\n      var autoPlace = autoToken.test(placement)\n      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'\n\n      $tip\n        .detach()\n        .css({ top: 0, left: 0, display: 'block' })\n        .addClass(placement)\n        .data('bs.' + this.type, this)\n\n      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)\n      this.$element.trigger('inserted.bs.' + this.type)\n\n      var pos          = this.getPosition()\n      var actualWidth  = $tip[0].offsetWidth\n      var actualHeight = $tip[0].offsetHeight\n\n      if (autoPlace) {\n        var orgPlacement = placement\n        var viewportDim = this.getPosition(this.$viewport)\n\n        placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :\n                    placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :\n                    placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :\n                    placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :\n                    placement\n\n        $tip\n          .removeClass(orgPlacement)\n          .addClass(placement)\n      }\n\n      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)\n\n      this.applyPlacement(calculatedOffset, placement)\n\n      var complete = function () {\n        var prevHoverState = that.hoverState\n        that.$element.trigger('shown.bs.' + that.type)\n        that.hoverState = null\n\n        if (prevHoverState == 'out') that.leave(that)\n      }\n\n      $.support.transition && this.$tip.hasClass('fade') ?\n        $tip\n          .one('bsTransitionEnd', complete)\n          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n        complete()\n    }\n  }\n\n  Tooltip.prototype.applyPlacement = function (offset, placement) {\n    var $tip   = this.tip()\n    var width  = $tip[0].offsetWidth\n    var height = $tip[0].offsetHeight\n\n    // manually read margins because getBoundingClientRect includes difference\n    var marginTop = parseInt($tip.css('margin-top'), 10)\n    var marginLeft = parseInt($tip.css('margin-left'), 10)\n\n    // we must check for NaN for ie 8/9\n    if (isNaN(marginTop))  marginTop  = 0\n    if (isNaN(marginLeft)) marginLeft = 0\n\n    offset.top  += marginTop\n    offset.left += marginLeft\n\n    // $.fn.offset doesn't round pixel values\n    // so we use setOffset directly with our own function B-0\n    $.offset.setOffset($tip[0], $.extend({\n      using: function (props) {\n        $tip.css({\n          top: Math.round(props.top),\n          left: Math.round(props.left)\n        })\n      }\n    }, offset), 0)\n\n    $tip.addClass('in')\n\n    // check to see if placing tip in new offset caused the tip to resize itself\n    var actualWidth  = $tip[0].offsetWidth\n    var actualHeight = $tip[0].offsetHeight\n\n    if (placement == 'top' && actualHeight != height) {\n      offset.top = offset.top + height - actualHeight\n    }\n\n    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)\n\n    if (delta.left) offset.left += delta.left\n    else offset.top += delta.top\n\n    var isVertical          = /top|bottom/.test(placement)\n    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight\n    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'\n\n    $tip.offset(offset)\n    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)\n  }\n\n  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {\n    this.arrow()\n      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n      .css(isVertical ? 'top' : 'left', '')\n  }\n\n  Tooltip.prototype.setContent = function () {\n    var $tip  = this.tip()\n    var title = this.getTitle()\n\n    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)\n    $tip.removeClass('fade in top bottom left right')\n  }\n\n  Tooltip.prototype.hide = function (callback) {\n    var that = this\n    var $tip = $(this.$tip)\n    var e    = $.Event('hide.bs.' + this.type)\n\n    function complete() {\n      if (that.hoverState != 'in') $tip.detach()\n      that.$element\n        .removeAttr('aria-describedby')\n        .trigger('hidden.bs.' + that.type)\n      callback && callback()\n    }\n\n    this.$element.trigger(e)\n\n    if (e.isDefaultPrevented()) return\n\n    $tip.removeClass('in')\n\n    $.support.transition && $tip.hasClass('fade') ?\n      $tip\n        .one('bsTransitionEnd', complete)\n        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n      complete()\n\n    this.hoverState = null\n\n    return this\n  }\n\n  Tooltip.prototype.fixTitle = function () {\n    var $e = this.$element\n    if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {\n      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')\n    }\n  }\n\n  Tooltip.prototype.hasContent = function () {\n    return this.getTitle()\n  }\n\n  Tooltip.prototype.getPosition = function ($element) {\n    $element   = $element || this.$element\n\n    var el     = $element[0]\n    var isBody = el.tagName == 'BODY'\n\n    var elRect    = el.getBoundingClientRect()\n    if (elRect.width == null) {\n      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })\n    }\n    var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()\n    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }\n    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null\n\n    return $.extend({}, elRect, scroll, outerDims, elOffset)\n  }\n\n  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {\n    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :\n           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :\n           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :\n        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }\n\n  }\n\n  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {\n    var delta = { top: 0, left: 0 }\n    if (!this.$viewport) return delta\n\n    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0\n    var viewportDimensions = this.getPosition(this.$viewport)\n\n    if (/right|left/.test(placement)) {\n      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll\n      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight\n      if (topEdgeOffset < viewportDimensions.top) { // top overflow\n        delta.top = viewportDimensions.top - topEdgeOffset\n      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset\n      }\n    } else {\n      var leftEdgeOffset  = pos.left - viewportPadding\n      var rightEdgeOffset = pos.left + viewportPadding + actualWidth\n      if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n        delta.left = viewportDimensions.left - leftEdgeOffset\n      } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow\n        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset\n      }\n    }\n\n    return delta\n  }\n\n  Tooltip.prototype.getTitle = function () {\n    var title\n    var $e = this.$element\n    var o  = this.options\n\n    title = $e.attr('data-original-title')\n      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)\n\n    return title\n  }\n\n  Tooltip.prototype.getUID = function (prefix) {\n    do prefix += ~~(Math.random() * 1000000)\n    while (document.getElementById(prefix))\n    return prefix\n  }\n\n  Tooltip.prototype.tip = function () {\n    if (!this.$tip) {\n      this.$tip = $(this.options.template)\n      if (this.$tip.length != 1) {\n        throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')\n      }\n    }\n    return this.$tip\n  }\n\n  Tooltip.prototype.arrow = function () {\n    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))\n  }\n\n  Tooltip.prototype.enable = function () {\n    this.enabled = true\n  }\n\n  Tooltip.prototype.disable = function () {\n    this.enabled = false\n  }\n\n  Tooltip.prototype.toggleEnabled = function () {\n    this.enabled = !this.enabled\n  }\n\n  Tooltip.prototype.toggle = function (e) {\n    var self = this\n    if (e) {\n      self = $(e.currentTarget).data('bs.' + this.type)\n      if (!self) {\n        self = new this.constructor(e.currentTarget, this.getDelegateOptions())\n        $(e.currentTarget).data('bs.' + this.type, self)\n      }\n    }\n\n    if (e) {\n      self.inState.click = !self.inState.click\n      if (self.isInStateTrue()) self.enter(self)\n      else self.leave(self)\n    } else {\n      self.tip().hasClass('in') ? self.leave(self) : self.enter(self)\n    }\n  }\n\n  Tooltip.prototype.destroy = function () {\n    var that = this\n    clearTimeout(this.timeout)\n    this.hide(function () {\n      that.$element.off('.' + that.type).removeData('bs.' + that.type)\n      if (that.$tip) {\n        that.$tip.detach()\n      }\n      that.$tip = null\n      that.$arrow = null\n      that.$viewport = null\n    })\n  }\n\n\n  // TOOLTIP PLUGIN DEFINITION\n  // =========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.tooltip')\n      var options = typeof option == 'object' && option\n\n      if (!data && /destroy|hide/.test(option)) return\n      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.tooltip\n\n  $.fn.tooltip             = Plugin\n  $.fn.tooltip.Constructor = Tooltip\n\n\n  // TOOLTIP NO CONFLICT\n  // ===================\n\n  $.fn.tooltip.noConflict = function () {\n    $.fn.tooltip = old\n    return this\n  }\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: popover.js v3.3.5\n * http://getbootstrap.com/javascript/#popovers\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // POPOVER PUBLIC CLASS DEFINITION\n  // ===============================\n\n  var Popover = function (element, options) {\n    this.init('popover', element, options)\n  }\n\n  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')\n\n  Popover.VERSION  = '3.3.5'\n\n  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {\n    placement: 'right',\n    trigger: 'click',\n    content: '',\n    template: '<div class=\"popover\" role=\"tooltip\"><div class=\"arrow\"></div><h3 class=\"popover-title\"></h3><div class=\"popover-content\"></div></div>'\n  })\n\n\n  // NOTE: POPOVER EXTENDS tooltip.js\n  // ================================\n\n  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)\n\n  Popover.prototype.constructor = Popover\n\n  Popover.prototype.getDefaults = function () {\n    return Popover.DEFAULTS\n  }\n\n  Popover.prototype.setContent = function () {\n    var $tip    = this.tip()\n    var title   = this.getTitle()\n    var content = this.getContent()\n\n    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)\n    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events\n      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'\n    ](content)\n\n    $tip.removeClass('fade top bottom left right in')\n\n    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do\n    // this manually by checking the contents.\n    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()\n  }\n\n  Popover.prototype.hasContent = function () {\n    return this.getTitle() || this.getContent()\n  }\n\n  Popover.prototype.getContent = function () {\n    var $e = this.$element\n    var o  = this.options\n\n    return $e.attr('data-content')\n      || (typeof o.content == 'function' ?\n            o.content.call($e[0]) :\n            o.content)\n  }\n\n  Popover.prototype.arrow = function () {\n    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))\n  }\n\n\n  // POPOVER PLUGIN DEFINITION\n  // =========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.popover')\n      var options = typeof option == 'object' && option\n\n      if (!data && /destroy|hide/.test(option)) return\n      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.popover\n\n  $.fn.popover             = Plugin\n  $.fn.popover.Constructor = Popover\n\n\n  // POPOVER NO CONFLICT\n  // ===================\n\n  $.fn.popover.noConflict = function () {\n    $.fn.popover = old\n    return this\n  }\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: scrollspy.js v3.3.5\n * http://getbootstrap.com/javascript/#scrollspy\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // SCROLLSPY CLASS DEFINITION\n  // ==========================\n\n  function ScrollSpy(element, options) {\n    this.$body          = $(document.body)\n    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)\n    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)\n    this.selector       = (this.options.target || '') + ' .nav li > a'\n    this.offsets        = []\n    this.targets        = []\n    this.activeTarget   = null\n    this.scrollHeight   = 0\n\n    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))\n    this.refresh()\n    this.process()\n  }\n\n  ScrollSpy.VERSION  = '3.3.5'\n\n  ScrollSpy.DEFAULTS = {\n    offset: 10\n  }\n\n  ScrollSpy.prototype.getScrollHeight = function () {\n    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)\n  }\n\n  ScrollSpy.prototype.refresh = function () {\n    var that          = this\n    var offsetMethod  = 'offset'\n    var offsetBase    = 0\n\n    this.offsets      = []\n    this.targets      = []\n    this.scrollHeight = this.getScrollHeight()\n\n    if (!$.isWindow(this.$scrollElement[0])) {\n      offsetMethod = 'position'\n      offsetBase   = this.$scrollElement.scrollTop()\n    }\n\n    this.$body\n      .find(this.selector)\n      .map(function () {\n        var $el   = $(this)\n        var href  = $el.data('target') || $el.attr('href')\n        var $href = /^#./.test(href) && $(href)\n\n        return ($href\n          && $href.length\n          && $href.is(':visible')\n          && [[$href[offsetMethod]().top + offsetBase, href]]) || null\n      })\n      .sort(function (a, b) { return a[0] - b[0] })\n      .each(function () {\n        that.offsets.push(this[0])\n        that.targets.push(this[1])\n      })\n  }\n\n  ScrollSpy.prototype.process = function () {\n    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset\n    var scrollHeight = this.getScrollHeight()\n    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()\n    var offsets      = this.offsets\n    var targets      = this.targets\n    var activeTarget = this.activeTarget\n    var i\n\n    if (this.scrollHeight != scrollHeight) {\n      this.refresh()\n    }\n\n    if (scrollTop >= maxScroll) {\n      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)\n    }\n\n    if (activeTarget && scrollTop < offsets[0]) {\n      this.activeTarget = null\n      return this.clear()\n    }\n\n    for (i = offsets.length; i--;) {\n      activeTarget != targets[i]\n        && scrollTop >= offsets[i]\n        && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])\n        && this.activate(targets[i])\n    }\n  }\n\n  ScrollSpy.prototype.activate = function (target) {\n    this.activeTarget = target\n\n    this.clear()\n\n    var selector = this.selector +\n      '[data-target=\"' + target + '\"],' +\n      this.selector + '[href=\"' + target + '\"]'\n\n    var active = $(selector)\n      .parents('li')\n      .addClass('active')\n\n    if (active.parent('.dropdown-menu').length) {\n      active = active\n        .closest('li.dropdown')\n        .addClass('active')\n    }\n\n    active.trigger('activate.bs.scrollspy')\n  }\n\n  ScrollSpy.prototype.clear = function () {\n    $(this.selector)\n      .parentsUntil(this.options.target, '.active')\n      .removeClass('active')\n  }\n\n\n  // SCROLLSPY PLUGIN DEFINITION\n  // ===========================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.scrollspy')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.scrollspy\n\n  $.fn.scrollspy             = Plugin\n  $.fn.scrollspy.Constructor = ScrollSpy\n\n\n  // SCROLLSPY NO CONFLICT\n  // =====================\n\n  $.fn.scrollspy.noConflict = function () {\n    $.fn.scrollspy = old\n    return this\n  }\n\n\n  // SCROLLSPY DATA-API\n  // ==================\n\n  $(window).on('load.bs.scrollspy.data-api', function () {\n    $('[data-spy=\"scroll\"]').each(function () {\n      var $spy = $(this)\n      Plugin.call($spy, $spy.data())\n    })\n  })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: tab.js v3.3.5\n * http://getbootstrap.com/javascript/#tabs\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // TAB CLASS DEFINITION\n  // ====================\n\n  var Tab = function (element) {\n    // jscs:disable requireDollarBeforejQueryAssignment\n    this.element = $(element)\n    // jscs:enable requireDollarBeforejQueryAssignment\n  }\n\n  Tab.VERSION = '3.3.5'\n\n  Tab.TRANSITION_DURATION = 150\n\n  Tab.prototype.show = function () {\n    var $this    = this.element\n    var $ul      = $this.closest('ul:not(.dropdown-menu)')\n    var selector = $this.data('target')\n\n    if (!selector) {\n      selector = $this.attr('href')\n      selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n    }\n\n    if ($this.parent('li').hasClass('active')) return\n\n    var $previous = $ul.find('.active:last a')\n    var hideEvent = $.Event('hide.bs.tab', {\n      relatedTarget: $this[0]\n    })\n    var showEvent = $.Event('show.bs.tab', {\n      relatedTarget: $previous[0]\n    })\n\n    $previous.trigger(hideEvent)\n    $this.trigger(showEvent)\n\n    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return\n\n    var $target = $(selector)\n\n    this.activate($this.closest('li'), $ul)\n    this.activate($target, $target.parent(), function () {\n      $previous.trigger({\n        type: 'hidden.bs.tab',\n        relatedTarget: $this[0]\n      })\n      $this.trigger({\n        type: 'shown.bs.tab',\n        relatedTarget: $previous[0]\n      })\n    })\n  }\n\n  Tab.prototype.activate = function (element, container, callback) {\n    var $active    = container.find('> .active')\n    var transition = callback\n      && $.support.transition\n      && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)\n\n    function next() {\n      $active\n        .removeClass('active')\n        .find('> .dropdown-menu > .active')\n          .removeClass('active')\n        .end()\n        .find('[data-toggle=\"tab\"]')\n          .attr('aria-expanded', false)\n\n      element\n        .addClass('active')\n        .find('[data-toggle=\"tab\"]')\n          .attr('aria-expanded', true)\n\n      if (transition) {\n        element[0].offsetWidth // reflow for transition\n        element.addClass('in')\n      } else {\n        element.removeClass('fade')\n      }\n\n      if (element.parent('.dropdown-menu').length) {\n        element\n          .closest('li.dropdown')\n            .addClass('active')\n          .end()\n          .find('[data-toggle=\"tab\"]')\n            .attr('aria-expanded', true)\n      }\n\n      callback && callback()\n    }\n\n    $active.length && transition ?\n      $active\n        .one('bsTransitionEnd', next)\n        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :\n      next()\n\n    $active.removeClass('in')\n  }\n\n\n  // TAB PLUGIN DEFINITION\n  // =====================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this = $(this)\n      var data  = $this.data('bs.tab')\n\n      if (!data) $this.data('bs.tab', (data = new Tab(this)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.tab\n\n  $.fn.tab             = Plugin\n  $.fn.tab.Constructor = Tab\n\n\n  // TAB NO CONFLICT\n  // ===============\n\n  $.fn.tab.noConflict = function () {\n    $.fn.tab = old\n    return this\n  }\n\n\n  // TAB DATA-API\n  // ============\n\n  var clickHandler = function (e) {\n    e.preventDefault()\n    Plugin.call($(this), 'show')\n  }\n\n  $(document)\n    .on('click.bs.tab.data-api', '[data-toggle=\"tab\"]', clickHandler)\n    .on('click.bs.tab.data-api', '[data-toggle=\"pill\"]', clickHandler)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: affix.js v3.3.5\n * http://getbootstrap.com/javascript/#affix\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n  'use strict';\n\n  // AFFIX CLASS DEFINITION\n  // ======================\n\n  var Affix = function (element, options) {\n    this.options = $.extend({}, Affix.DEFAULTS, options)\n\n    this.$target = $(this.options.target)\n      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))\n      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))\n\n    this.$element     = $(element)\n    this.affixed      = null\n    this.unpin        = null\n    this.pinnedOffset = null\n\n    this.checkPosition()\n  }\n\n  Affix.VERSION  = '3.3.5'\n\n  Affix.RESET    = 'affix affix-top affix-bottom'\n\n  Affix.DEFAULTS = {\n    offset: 0,\n    target: window\n  }\n\n  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {\n    var scrollTop    = this.$target.scrollTop()\n    var position     = this.$element.offset()\n    var targetHeight = this.$target.height()\n\n    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false\n\n    if (this.affixed == 'bottom') {\n      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'\n      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'\n    }\n\n    var initializing   = this.affixed == null\n    var colliderTop    = initializing ? scrollTop : position.top\n    var colliderHeight = initializing ? targetHeight : height\n\n    if (offsetTop != null && scrollTop <= offsetTop) return 'top'\n    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'\n\n    return false\n  }\n\n  Affix.prototype.getPinnedOffset = function () {\n    if (this.pinnedOffset) return this.pinnedOffset\n    this.$element.removeClass(Affix.RESET).addClass('affix')\n    var scrollTop = this.$target.scrollTop()\n    var position  = this.$element.offset()\n    return (this.pinnedOffset = position.top - scrollTop)\n  }\n\n  Affix.prototype.checkPositionWithEventLoop = function () {\n    setTimeout($.proxy(this.checkPosition, this), 1)\n  }\n\n  Affix.prototype.checkPosition = function () {\n    if (!this.$element.is(':visible')) return\n\n    var height       = this.$element.height()\n    var offset       = this.options.offset\n    var offsetTop    = offset.top\n    var offsetBottom = offset.bottom\n    var scrollHeight = Math.max($(document).height(), $(document.body).height())\n\n    if (typeof offset != 'object')         offsetBottom = offsetTop = offset\n    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)\n    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)\n\n    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)\n\n    if (this.affixed != affix) {\n      if (this.unpin != null) this.$element.css('top', '')\n\n      var affixType = 'affix' + (affix ? '-' + affix : '')\n      var e         = $.Event(affixType + '.bs.affix')\n\n      this.$element.trigger(e)\n\n      if (e.isDefaultPrevented()) return\n\n      this.affixed = affix\n      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null\n\n      this.$element\n        .removeClass(Affix.RESET)\n        .addClass(affixType)\n        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')\n    }\n\n    if (affix == 'bottom') {\n      this.$element.offset({\n        top: scrollHeight - height - offsetBottom\n      })\n    }\n  }\n\n\n  // AFFIX PLUGIN DEFINITION\n  // =======================\n\n  function Plugin(option) {\n    return this.each(function () {\n      var $this   = $(this)\n      var data    = $this.data('bs.affix')\n      var options = typeof option == 'object' && option\n\n      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))\n      if (typeof option == 'string') data[option]()\n    })\n  }\n\n  var old = $.fn.affix\n\n  $.fn.affix             = Plugin\n  $.fn.affix.Constructor = Affix\n\n\n  // AFFIX NO CONFLICT\n  // =================\n\n  $.fn.affix.noConflict = function () {\n    $.fn.affix = old\n    return this\n  }\n\n\n  // AFFIX DATA-API\n  // ==============\n\n  $(window).on('load', function () {\n    $('[data-spy=\"affix\"]').each(function () {\n      var $spy = $(this)\n      var data = $spy.data()\n\n      data.offset = data.offset || {}\n\n      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom\n      if (data.offsetTop    != null) data.offset.top    = data.offsetTop\n\n      Plugin.call($spy, data)\n    })\n  })\n\n}(jQuery);\n"
  },
  {
    "path": "resources/public/js/jquery-2.1.4.js",
    "content": "/*!\n * jQuery JavaScript Library v2.1.4\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2015-04-28T16:01Z\n */\n\n(function( global, factory ) {\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n}(typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Support: Firefox 18+\n// Can't be in strict mode, several libs including ASP.NET trace\n// the stack via arguments.caller.callee and Firefox dies if\n// you try to trace through \"use strict\" call chains. (#13335)\n//\n\nvar arr = [];\n\nvar slice = arr.slice;\n\nvar concat = arr.concat;\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar support = {};\n\n\n\nvar\n\t// Use the correct document accordingly with window argument (sandbox)\n\tdocument = window.document,\n\n\tversion = \"2.1.4\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t},\n\n\t// Support: Android<4.1\n\t// Make sure we trim BOM and NBSP\n\trtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,\n\n\t// Matches dashed string for camelizing\n\trmsPrefix = /^-ms-/,\n\trdashAlpha = /-([\\da-z])/gi,\n\n\t// Used by jQuery.camelCase as callback to replace()\n\tfcamelCase = function( all, letter ) {\n\t\treturn letter.toUpperCase();\n\t};\n\njQuery.fn = jQuery.prototype = {\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// Start with an empty selector\n\tselector: \"\",\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\t\treturn num != null ?\n\n\t\t\t// Return just the one element from the set\n\t\t\t( num < 0 ? this[ num + this.length ] : this[ num ] ) :\n\n\t\t\t// Return all the elements in a clean array\n\t\t\tslice.call( this );\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\t\tret.context = this.context;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\t// (You can seed the arguments with an array of args, but this is\n\t// only used internally.)\n\teach: function( callback, args ) {\n\t\treturn jQuery.each( this, callback, args );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map(this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t}));\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor(null);\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: arr.sort,\n\tsplice: arr.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[0] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !jQuery.isFunction(target) ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\t\t// Only deal with non-null/undefined values\n\t\tif ( (options = arguments[ i ]) != null ) {\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {\n\t\t\t\t\tif ( copyIsArray ) {\n\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\tclone = src && jQuery.isArray(src) ? src : [];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src && jQuery.isPlainObject(src) ? src : {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend({\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisFunction: function( obj ) {\n\t\treturn jQuery.type(obj) === \"function\";\n\t},\n\n\tisArray: Array.isArray,\n\n\tisWindow: function( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t},\n\n\tisNumeric: function( obj ) {\n\t\t// parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t// subtraction forces infinities to NaN\n\t\t// adding 1 corrects loss of precision from parseFloat (#15100)\n\t\treturn !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0;\n\t},\n\n\tisPlainObject: function( obj ) {\n\t\t// Not plain objects:\n\t\t// - Any object or value whose internal [[Class]] property is not \"[object Object]\"\n\t\t// - DOM nodes\n\t\t// - window\n\t\tif ( jQuery.type( obj ) !== \"object\" || obj.nodeType || jQuery.isWindow( obj ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( obj.constructor &&\n\t\t\t\t!hasOwn.call( obj.constructor.prototype, \"isPrototypeOf\" ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If the function hasn't returned already, we're confident that\n\t\t// |obj| is a plain object, created by {} or constructed with new Object\n\t\treturn true;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\ttype: function( obj ) {\n\t\tif ( obj == null ) {\n\t\t\treturn obj + \"\";\n\t\t}\n\t\t// Support: Android<4.0, iOS<6 (functionish RegExp)\n\t\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\t\tclass2type[ toString.call(obj) ] || \"object\" :\n\t\t\ttypeof obj;\n\t},\n\n\t// Evaluates a script in a global context\n\tglobalEval: function( code ) {\n\t\tvar script,\n\t\t\tindirect = eval;\n\n\t\tcode = jQuery.trim( code );\n\n\t\tif ( code ) {\n\t\t\t// If the code includes a valid, prologue position\n\t\t\t// strict mode pragma, execute code by injecting a\n\t\t\t// script tag into the document.\n\t\t\tif ( code.indexOf(\"use strict\") === 1 ) {\n\t\t\t\tscript = document.createElement(\"script\");\n\t\t\t\tscript.text = code;\n\t\t\t\tdocument.head.appendChild( script ).parentNode.removeChild( script );\n\t\t\t} else {\n\t\t\t// Otherwise, avoid the DOM node creation, insertion\n\t\t\t// and removal by using an indirect global eval\n\t\t\t\tindirect( code );\n\t\t\t}\n\t\t}\n\t},\n\n\t// Convert dashed to camelCase; used by the css and data modules\n\t// Support: IE9-11+\n\t// Microsoft forgot to hump their vendor prefix (#9572)\n\tcamelCase: function( string ) {\n\t\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n\t},\n\n\tnodeName: function( elem, name ) {\n\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\t},\n\n\t// args is for internal usage only\n\teach: function( obj, callback, args ) {\n\t\tvar value,\n\t\t\ti = 0,\n\t\t\tlength = obj.length,\n\t\t\tisArray = isArraylike( obj );\n\n\t\tif ( args ) {\n\t\t\tif ( isArray ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tvalue = callback.apply( obj[ i ], args );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( i in obj ) {\n\t\t\t\t\tvalue = callback.apply( obj[ i ], args );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// A special, fast, case for the most common use of each\n\t\t} else {\n\t\t\tif ( isArray ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tvalue = callback.call( obj[ i ], i, obj[ i ] );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( i in obj ) {\n\t\t\t\t\tvalue = callback.call( obj[ i ], i, obj[ i ] );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// Support: Android<4.1\n\ttrim: function( text ) {\n\t\treturn text == null ?\n\t\t\t\"\" :\n\t\t\t( text + \"\" ).replace( rtrim, \"\" );\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArraylike( Object(arr) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar value,\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tisArray = isArraylike( elems ),\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArray ) {\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// Bind a function to a context, optionally partially applying any\n\t// arguments.\n\tproxy: function( fn, context ) {\n\t\tvar tmp, args, proxy;\n\n\t\tif ( typeof context === \"string\" ) {\n\t\t\ttmp = fn[ context ];\n\t\t\tcontext = fn;\n\t\t\tfn = tmp;\n\t\t}\n\n\t\t// Quick check to determine if target is callable, in the spec\n\t\t// this throws a TypeError, but we will just return undefined.\n\t\tif ( !jQuery.isFunction( fn ) ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Simulated bind\n\t\targs = slice.call( arguments, 2 );\n\t\tproxy = function() {\n\t\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\t\t};\n\n\t\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\t\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\t\treturn proxy;\n\t},\n\n\tnow: Date.now,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n});\n\n// Populate the class2type map\njQuery.each(\"Boolean Number String Function Array Date RegExp Object Error\".split(\" \"), function(i, name) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n});\n\nfunction isArraylike( obj ) {\n\n\t// Support: iOS 8.2 (not reproducible in simulator)\n\t// `in` check used to prevent JIT error (gh-2145)\n\t// hasOwn isn't used here due to false negatives\n\t// regarding Nodelist length in IE\n\tvar length = \"length\" in obj && obj.length,\n\t\ttype = jQuery.type( obj );\n\n\tif ( type === \"function\" || jQuery.isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\tif ( obj.nodeType === 1 && length ) {\n\t\treturn true;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v2.2.0-pre\n * http://sizzlejs.com/\n *\n * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2014-12-16\n */\n(function( window ) {\n\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\ttokenize,\n\tcompile,\n\tselect,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + 1 * new Date(),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// General-purpose constants\n\tMAX_NEGATIVE = 1 << 31,\n\n\t// Instance methods\n\thasOwn = ({}).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpush_native = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf as it's faster than native\n\t// http://jsperf.com/thor-indexof-vs-for/5\n\tindexOf = function( list, elem ) {\n\t\tvar i = 0,\n\t\t\tlen = list.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( list[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\t// http://www.w3.org/TR/css3-syntax/#characters\n\tcharacterEncoding = \"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",\n\n\t// Loosely modeled on CSS identifier characters\n\t// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors\n\t// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n\tidentifier = characterEncoding.replace( \"w\", \"w#\" ),\n\n\t// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + characterEncoding + \")(?:\" + whitespace +\n\t\t// Operator (capture 2)\n\t\t\"*([*^$|!~]?=)\" + whitespace +\n\t\t// \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n\t\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" + whitespace +\n\t\t\"*\\\\]\",\n\n\tpseudos = \":(\" + characterEncoding + \")(?:\\\\((\" +\n\t\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\t\t// 2. simple (capture 6)\n\t\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\t\t// 3. anything else (capture 2)\n\t\t\".*\" +\n\t\t\")\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace + \"*\" ),\n\n\trattributeQuotes = new RegExp( \"=\" + whitespace + \"*([^\\\\]'\\\"]*?)\" + whitespace + \"*\\\\]\", \"g\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + characterEncoding + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + characterEncoding + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + characterEncoding.replace( \"w\", \"w*\" ) + \")\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n\t\t\t\"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n\t\t\t\"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n\t\t\twhitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\trescape = /'|\\\\/g,\n\n\t// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\([\\\\da-f]{1,6}\" + whitespace + \"?|(\" + whitespace + \")|.)\", \"ig\" ),\n\tfunescape = function( _, escaped, escapedWhitespace ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\t// Support: Firefox<24\n\t\t// Workaround erroneous numeric interpretation of +\"0x\"\n\t\treturn high !== high || escapedWhitespace ?\n\t\t\tescaped :\n\t\t\thigh < 0 ?\n\t\t\t\t// BMP codepoint\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\t// Supplemental Plane codepoint (surrogate pair)\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t},\n\n\t// Used for iframes\n\t// See setDocument()\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t};\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t(arr = slice.call( preferredDoc.childNodes )),\n\t\tpreferredDoc.childNodes\n\t);\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpush_native.apply( target, slice.call(els) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( (target[j++] = els[i++]) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar match, elem, m, nodeType,\n\t\t// QSA vars\n\t\ti, groups, old, nid, newContext, newSelector;\n\n\tif ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\n\tcontext = context || document;\n\tresults = results || [];\n\tnodeType = context.nodeType;\n\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\tif ( !seed && documentIsHTML ) {\n\n\t\t// Try to shortcut find operations when possible (e.g., not under DocumentFragment)\n\t\tif ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {\n\t\t\t// Speed-up: Sizzle(\"#ID\")\n\t\t\tif ( (m = match[1]) ) {\n\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\telem = context.getElementById( m );\n\t\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t// nodes that are no longer in the document (jQuery #6963)\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Handle the case where IE, Opera, and Webkit return items\n\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Context is not a document\n\t\t\t\t\tif ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&\n\t\t\t\t\t\tcontains( context, elem ) && elem.id === m ) {\n\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Speed-up: Sizzle(\"TAG\")\n\t\t\t} else if ( match[2] ) {\n\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\treturn results;\n\n\t\t\t// Speed-up: Sizzle(\".CLASS\")\n\t\t\t} else if ( (m = match[3]) && support.getElementsByClassName ) {\n\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\treturn results;\n\t\t\t}\n\t\t}\n\n\t\t// QSA path\n\t\tif ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {\n\t\t\tnid = old = expando;\n\t\t\tnewContext = context;\n\t\t\tnewSelector = nodeType !== 1 && selector;\n\n\t\t\t// qSA works strangely on Element-rooted queries\n\t\t\t// We can work around this by specifying an extra ID on the root\n\t\t\t// and working up from there (Thanks to Andrew Dupont for the technique)\n\t\t\t// IE 8 doesn't work on object elements\n\t\t\tif ( nodeType === 1 && context.nodeName.toLowerCase() !== \"object\" ) {\n\t\t\t\tgroups = tokenize( selector );\n\n\t\t\t\tif ( (old = context.getAttribute(\"id\")) ) {\n\t\t\t\t\tnid = old.replace( rescape, \"\\\\$&\" );\n\t\t\t\t} else {\n\t\t\t\t\tcontext.setAttribute( \"id\", nid );\n\t\t\t\t}\n\t\t\t\tnid = \"[id='\" + nid + \"'] \";\n\n\t\t\t\ti = groups.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tgroups[i] = nid + toSelector( groups[i] );\n\t\t\t\t}\n\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;\n\t\t\t\tnewSelector = groups.join(\",\");\n\t\t\t}\n\n\t\t\tif ( newSelector ) {\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch(qsaError) {\n\t\t\t\t} finally {\n\t\t\t\t\tif ( !old ) {\n\t\t\t\t\t\tcontext.removeAttribute(\"id\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {Function(string, Object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn (cache[ key + \" \" ] = value);\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created div and expects a boolean result\n */\nfunction assert( fn ) {\n\tvar div = document.createElement(\"div\");\n\n\ttry {\n\t\treturn !!fn( div );\n\t} catch (e) {\n\t\treturn false;\n\t} finally {\n\t\t// Remove from its parent by default\n\t\tif ( div.parentNode ) {\n\t\t\tdiv.parentNode.removeChild( div );\n\t\t}\n\t\t// release memory in IE\n\t\tdiv = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split(\"|\"),\n\t\ti = attrs.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[i] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\t( ~b.sourceIndex || MAX_NEGATIVE ) -\n\t\t\t( ~a.sourceIndex || MAX_NEGATIVE );\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( (cur = cur.nextSibling) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn (name === \"input\" || name === \"button\") && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction(function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction(function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ (j = matchIndexes[i]) ] ) {\n\t\t\t\t\tseed[j] = !(matches[j] = seed[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833)\n\tvar documentElement = elem && (elem.ownerDocument || elem).documentElement;\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare, parent,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// If no document and documentElement is available, return\n\tif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Set our document\n\tdocument = doc;\n\tdocElem = doc.documentElement;\n\tparent = doc.defaultView;\n\n\t// Support: IE>8\n\t// If iframe document is assigned to \"document\" variable and if iframe has been reloaded,\n\t// IE will throw \"permission denied\" error when accessing \"document\" variable, see jQuery #13936\n\t// IE6-8 do not support the defaultView property so parent will be undefined\n\tif ( parent && parent !== parent.top ) {\n\t\t// IE11 does not have attachEvent, so all must suffer\n\t\tif ( parent.addEventListener ) {\n\t\t\tparent.addEventListener( \"unload\", unloadHandler, false );\n\t\t} else if ( parent.attachEvent ) {\n\t\t\tparent.attachEvent( \"onunload\", unloadHandler );\n\t\t}\n\t}\n\n\t/* Support tests\n\t---------------------------------------------------------------------- */\n\tdocumentIsHTML = !isXML( doc );\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties\n\t// (excepting IE8 booleans)\n\tsupport.attributes = assert(function( div ) {\n\t\tdiv.className = \"i\";\n\t\treturn !div.getAttribute(\"className\");\n\t});\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert(function( div ) {\n\t\tdiv.appendChild( doc.createComment(\"\") );\n\t\treturn !div.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Support: IE<9\n\tsupport.getElementsByClassName = rnative.test( doc.getElementsByClassName );\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert(function( div ) {\n\t\tdocElem.appendChild( div ).id = expando;\n\t\treturn !doc.getElementsByName || !doc.getElementsByName( expando ).length;\n\t});\n\n\t// ID find and filter\n\tif ( support.getById ) {\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar m = context.getElementById( id );\n\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\treturn m && m.parentNode ? [ m ] : [];\n\t\t\t}\n\t\t};\n\t\tExpr.filter[\"ID\"] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"id\") === attrId;\n\t\t\t};\n\t\t};\n\t} else {\n\t\t// Support: IE6/7\n\t\t// getElementById is not reliable as a find shortcut\n\t\tdelete Expr.find[\"ID\"];\n\n\t\tExpr.filter[\"ID\"] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" && elem.getAttributeNode(\"id\");\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[\"TAG\"] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else if ( support.qsa ) {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t} :\n\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\t\t\t\t// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( (elem = results[i++]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See http://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert(function( div ) {\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// http://bugs.jquery.com/ticket/12359\n\t\t\tdocElem.appendChild( div ).innerHTML = \"<a id='\" + expando + \"'></a>\" +\n\t\t\t\t\"<select id='\" + expando + \"-\\f]' msallowcapture=''>\" +\n\t\t\t\t\"<option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 11-12.16\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\t// The test attribute must be unknown in Opera but \"safe\" for WinRT\n\t\t\t// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n\t\t\tif ( div.querySelectorAll(\"[msallowcapture^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !div.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+\n\t\t\tif ( !div.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n\t\t\t\trbuggyQSA.push(\"~=\");\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":checked\").length ) {\n\t\t\t\trbuggyQSA.push(\":checked\");\n\t\t\t}\n\n\t\t\t// Support: Safari 8+, iOS 8+\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=136851\n\t\t\t// In-page `selector#id sibing-combinator selector` fails\n\t\t\tif ( !div.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n\t\t\t\trbuggyQSA.push(\".#.+[+~]\");\n\t\t\t}\n\t\t});\n\n\t\tassert(function( div ) {\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = doc.createElement(\"input\");\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tdiv.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( div.querySelectorAll(\"[name=d]\").length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":enabled\").length ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tdiv.querySelectorAll(\"*,:x\");\n\t\t\trbuggyQSA.push(\",.*:\");\n\t\t});\n\t}\n\n\tif ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector) )) ) {\n\n\t\tassert(function( div ) {\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( div, \"div\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( div, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t});\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join(\"|\") );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully does not implement inclusive descendent\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t));\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( (b = b.parentNode) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\tcompare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\tif ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\t\t\treturn a === doc ? -1 :\n\t\t\t\tb === doc ? 1 :\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[i] === bp[i] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[i], bp[i] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\tap[i] === preferredDoc ? -1 :\n\t\t\tbp[i] === preferredDoc ? 1 :\n\t\t\t0;\n\t};\n\n\treturn doc;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\t// Make sure that attribute selectors are quoted\n\texpr = expr.replace( rattributeQuotes, \"='$1']\" );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t// fragment in IE 9\n\t\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch (e) {}\n\t}\n\n\treturn Sizzle( expr, document, null, [ elem ] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\t// Set document vars if needed\n\tif ( ( context.ownerDocument || context ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t(val = elem.getAttributeNode(name)) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( (elem = results[i++]) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( (node = elem[i++]) ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[1] = match[1].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[3] = ( match[3] || match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[3] = \" \" + match[3] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[1] = match[1].toLowerCase();\n\n\t\t\tif ( match[1].slice( 0, 3 ) === \"nth\" ) {\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[3] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n\t\t\t\tmatch[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[3] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[6] && match[2];\n\n\t\t\tif ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[3] ) {\n\t\t\t\tmatch[2] = match[4] || match[5] || \"\";\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t(excess = tokenize( unquoted, true )) &&\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t(excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[0] = match[0].slice( 0, excess );\n\t\t\t\tmatch[2] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() { return true; } :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t(pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test( typeof elem.className === \"string\" && elem.className || typeof elem.getAttribute !== \"undefined\" && elem.getAttribute(\"class\") || \"\" );\n\t\t\t\t});\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tvar cache, outerCache, node, diff, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( (node = node[ dir ]) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\t\t\t\t\t\t\touterCache = parent[ expando ] || (parent[ expando ] = {});\n\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[0] === dirruns && cache[1];\n\t\t\t\t\t\t\tdiff = cache[0] === dirruns && cache[2];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {\n\t\t\t\t\t\t\tdiff = cache[1];\n\n\t\t\t\t\t\t// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\tif ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {\n\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction(function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf( seed, matched[i] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction(function( selector ) {\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction(function( seed, matches, context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = unmatched[i]) ) {\n\t\t\t\t\t\t\tseed[i] = !(matches[i] = elem);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}) :\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tinput[0] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\t\t\t\t\t// Don't keep the element (issue #299)\n\t\t\t\t\tinput[0] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t}),\n\n\t\t\"has\": markFunction(function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t}),\n\n\t\t\"contains\": markFunction(function( text ) {\n\t\t\ttext = text.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t}),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test(lang || \"\") ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( (elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\")) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": function( elem ) {\n\t\t\treturn elem.disabled === false;\n\t\t},\n\n\t\t\"disabled\": function( elem ) {\n\t\t\treturn elem.disabled === true;\n\t\t},\n\n\t\t\"checked\": function( elem ) {\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[\"empty\"]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo(function() {\n\t\t\treturn [ 0 ];\n\t\t}),\n\n\t\t\"last\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t}),\n\n\t\t\"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t}),\n\n\t\t\"even\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t})\n\t}\n};\n\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\ntokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || (match = rcomma.exec( soFar )) ) {\n\t\t\tif ( match ) {\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[0].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( (tokens = []) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( (match = rcombinators.exec( soFar )) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push({\n\t\t\t\tvalue: matched,\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[0].replace( rtrim, \" \" )\n\t\t\t});\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n\t\t\t\t(match = preFilters[ type ]( match ))) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push({\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t});\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[i].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tcheckNonElements = base && dir === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || (elem[ expando ] = {});\n\t\t\t\t\t\tif ( (oldCache = outerCache[ dir ]) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn (newCache[ 2 ] = oldCache[ 2 ]);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\touterCache[ dir ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[i]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[0];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[i], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (elem = unmatched[i]) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction(function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( (elem = temp[i]) ) {\n\t\t\t\t\tmatcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = matcherOut[i]) ) {\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( (matcherIn[i] = elem) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, (matcherOut = []), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( (elem = matcherOut[i]) &&\n\t\t\t\t\t\t(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {\n\n\t\t\t\t\t\tseed[temp] = !(results[temp] = elem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[0].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[\" \"],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\tvar ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t(checkContext = context).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\t\t\t// Avoid hanging onto element (issue #299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n\t\t\tmatchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[j].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" })\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", outermost ),\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context !== document && context;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Keep `i` a string if there are no elements so `matchedCount` will be \"00\" below\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && (elem = elems[i]) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (matcher = elementMatchers[j++]) ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( (elem = !matcher && elem) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\tmatchedCount += i;\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (matcher = setMatchers[j++]) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !(unmatched[i] || setMatched[i]) ) {\n\t\t\t\t\t\t\t\tsetMatched[i] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[i] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n};\n\n/**\n * A low-level selection function that works with Sizzle's compiled\n *  selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n *  selector function built with Sizzle.compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nselect = Sizzle.select = function( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( (selector = compiled.selector || selector) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is no seed and only one group\n\tif ( match.length === 1 ) {\n\n\t\t// Take a shortcut and set the context if the root selector is an ID\n\t\ttokens = match[0] = match[0].slice( 0 );\n\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\tsupport.getById && context.nodeType === 9 && documentIsHTML &&\n\t\t\t\tExpr.relative[ tokens[1].type ] ) {\n\n\t\t\tcontext = ( Expr.find[\"ID\"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[i];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( (seed = find(\n\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\trsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context\n\t\t\t\t)) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\trsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n};\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split(\"\").sort( sortOrder ).join(\"\") === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert(function( div1 ) {\n\t// Should return 1, but returns 4 (following)\n\treturn div1.compareDocumentPosition( document.createElement(\"div\") ) & 1;\n});\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert(function( div ) {\n\tdiv.innerHTML = \"<a href='#'></a>\";\n\treturn div.firstChild.getAttribute(\"href\") === \"#\" ;\n}) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert(function( div ) {\n\tdiv.innerHTML = \"<input/>\";\n\tdiv.firstChild.setAttribute( \"value\", \"\" );\n\treturn div.firstChild.getAttribute( \"value\" ) === \"\";\n}) ) {\n\taddHandle( \"value\", function( elem, name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert(function( div ) {\n\treturn div.getAttribute(\"disabled\") == null;\n}) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t\t(val = elem.getAttributeNode( name )) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\tnull;\n\t\t}\n\t});\n}\n\nreturn Sizzle;\n\n})( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[\":\"] = jQuery.expr.pseudos;\njQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\n\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\nvar rsingleTag = (/^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/);\n\n\n\nvar risSimple = /^.[^:#\\[\\.,]*$/;\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\t/* jshint -W018 */\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t});\n\n\t}\n\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t});\n\n\t}\n\n\tif ( typeof qualifier === \"string\" ) {\n\t\tif ( risSimple.test( qualifier ) ) {\n\t\t\treturn jQuery.filter( qualifier, elements, not );\n\t\t}\n\n\t\tqualifier = jQuery.filter( qualifier, elements );\n\t}\n\n\treturn jQuery.grep( elements, function( elem ) {\n\t\treturn ( indexOf.call( qualifier, elem ) >= 0 ) !== not;\n\t});\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\treturn elems.length === 1 && elem.nodeType === 1 ?\n\t\tjQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :\n\t\tjQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\t\treturn elem.nodeType === 1;\n\t\t}));\n};\n\njQuery.fn.extend({\n\tfind: function( selector ) {\n\t\tvar i,\n\t\t\tlen = this.length,\n\t\t\tret = [],\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter(function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}) );\n\t\t}\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\t// Needed because $( selector, context ) becomes $( context ).find( selector )\n\t\tret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );\n\t\tret.selector = this.selector ? this.selector + \" \" + selector : selector;\n\t\treturn ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector || [], false) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector || [], true) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n});\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,\n\n\tinit = jQuery.fn.init = function( selector, context ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[0] === \"<\" && selector[ selector.length - 1 ] === \">\" && selector.length >= 3 ) {\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && (match[1] || !context) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[1] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[0] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[1],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( jQuery.isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[2] );\n\n\t\t\t\t\t// Support: Blackberry 4.6\n\t\t\t\t\t// gEBID returns nodes no longer in the document (#6963)\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t\tthis[0] = elem;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.context = document;\n\t\t\t\t\tthis.selector = selector;\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || rootjQuery ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis.context = this[0] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( jQuery.isFunction( selector ) ) {\n\t\t\treturn typeof rootjQuery.ready !== \"undefined\" ?\n\t\t\t\trootjQuery.ready( selector ) :\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\tif ( selector.selector !== undefined ) {\n\t\t\tthis.selector = selector.selector;\n\t\t\tthis.context = selector.context;\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.extend({\n\tdir: function( elem, dir, until ) {\n\t\tvar matched = [],\n\t\t\ttruncate = until !== undefined;\n\n\t\twhile ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmatched.push( elem );\n\t\t\t}\n\t\t}\n\t\treturn matched;\n\t},\n\n\tsibling: function( n, elem ) {\n\t\tvar matched = [];\n\n\t\tfor ( ; n; n = n.nextSibling ) {\n\t\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\t\tmatched.push( n );\n\t\t\t}\n\t\t}\n\n\t\treturn matched;\n\t}\n});\n\njQuery.fn.extend({\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter(function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[i] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\tpos = rneedsContext.test( selectors ) || typeof selectors !== \"string\" ?\n\t\t\t\tjQuery( selectors, context || this.context ) :\n\t\t\t\t0;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tfor ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {\n\t\t\t\t// Always skip document fragments\n\t\t\t\tif ( cur.nodeType < 11 && (pos ?\n\t\t\t\t\tpos.index(cur) > -1 :\n\n\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\tjQuery.find.matchesSelector(cur, selectors)) ) {\n\n\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.unique(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter(selector)\n\t\t);\n\t}\n});\n\nfunction sibling( cur, dir ) {\n\twhile ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each({\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn jQuery.dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn jQuery.sibling( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\treturn elem.contentDocument || jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.unique( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n});\nvar rnotwhite = (/\\S+/g);\n\n\n\n// String to Object options format cache\nvar optionsCache = {};\n\n// Convert String-formatted options into Object-formatted ones and store in cache\nfunction createOptions( options ) {\n\tvar object = optionsCache[ options ] = {};\n\tjQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t});\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\t( optionsCache[ options ] || createOptions( options ) ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Last fire value (for non-forgettable lists)\n\t\tmemory,\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\t\t// Flag to know if list is currently firing\n\t\tfiring,\n\t\t// First callback to fire (used internally by add and fireWith)\n\t\tfiringStart,\n\t\t// End of the loop when firing\n\t\tfiringLength,\n\t\t// Index of currently firing callback (modified by remove if needed)\n\t\tfiringIndex,\n\t\t// Actual callback list\n\t\tlist = [],\n\t\t// Stack of fire calls for repeatable lists\n\t\tstack = !options.once && [],\n\t\t// Fire callbacks\n\t\tfire = function( data ) {\n\t\t\tmemory = options.memory && data;\n\t\t\tfired = true;\n\t\t\tfiringIndex = firingStart || 0;\n\t\t\tfiringStart = 0;\n\t\t\tfiringLength = list.length;\n\t\t\tfiring = true;\n\t\t\tfor ( ; list && firingIndex < firingLength; firingIndex++ ) {\n\t\t\t\tif ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {\n\t\t\t\t\tmemory = false; // To prevent further calls using add\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfiring = false;\n\t\t\tif ( list ) {\n\t\t\t\tif ( stack ) {\n\t\t\t\t\tif ( stack.length ) {\n\t\t\t\t\t\tfire( stack.shift() );\n\t\t\t\t\t}\n\t\t\t\t} else if ( memory ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t} else {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t// Actual Callbacks object\n\t\tself = {\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\t// First, we save the current length\n\t\t\t\t\tvar start = list.length;\n\t\t\t\t\t(function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tvar type = jQuery.type( arg );\n\t\t\t\t\t\t\tif ( type === \"function\" ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && type !== \"string\" ) {\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t})( arguments );\n\t\t\t\t\t// Do we need to add the callbacks to the\n\t\t\t\t\t// current firing batch?\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tfiringLength = list.length;\n\t\t\t\t\t// With memory, if we're not firing then\n\t\t\t\t\t// we should call right away\n\t\t\t\t\t} else if ( memory ) {\n\t\t\t\t\t\tfiringStart = start;\n\t\t\t\t\t\tfire( memory );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\t\tvar index;\n\t\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\t\tlist.splice( index, 1 );\n\t\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\t\t\tif ( index <= firingLength ) {\n\t\t\t\t\t\t\t\t\tfiringLength--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );\n\t\t\t},\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tlist = [];\n\t\t\t\tfiringLength = 0;\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Have the list do nothing anymore\n\t\t\tdisable: function() {\n\t\t\t\tlist = stack = memory = undefined;\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it disabled?\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\t\t\t// Lock the list in its current state\n\t\t\tlock: function() {\n\t\t\t\tstack = undefined;\n\t\t\t\tif ( !memory ) {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it locked?\n\t\t\tlocked: function() {\n\t\t\t\treturn !stack;\n\t\t\t},\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( list && ( !fired || stack ) ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tstack.push( args );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfire( args );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\njQuery.extend({\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\t\t\t\t// action, add listener, listener list, final state\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks(\"once memory\"), \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks(\"once memory\"), \"rejected\" ],\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks(\"memory\") ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\tthen: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\t\t\t\t\treturn jQuery.Deferred(function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\t\t\t\t\tvar fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];\n\t\t\t\t\t\t\t// deferred[ done | fail | progress ] for forwarding actions to newDefer\n\t\t\t\t\t\t\tdeferred[ tuple[1] ](function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && jQuery.isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject )\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t}).promise();\n\t\t\t\t},\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Keep pipe for back-compat\n\t\tpromise.pipe = promise.then;\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 3 ];\n\n\t\t\t// promise[ done | fail | progress ] = list.add\n\t\t\tpromise[ tuple[1] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(function() {\n\t\t\t\t\t// state = [ resolved | rejected ]\n\t\t\t\t\tstate = stateString;\n\n\t\t\t\t// [ reject_list | resolve_list ].disable; progress_list.lock\n\t\t\t\t}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );\n\t\t\t}\n\n\t\t\t// deferred[ resolve | reject | notify ]\n\t\t\tdeferred[ tuple[0] ] = function() {\n\t\t\t\tdeferred[ tuple[0] + \"With\" ]( this === deferred ? promise : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\t\t\tdeferred[ tuple[0] + \"With\" ] = list.fireWith;\n\t\t});\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( subordinate /* , ..., subordinateN */ ) {\n\t\tvar i = 0,\n\t\t\tresolveValues = slice.call( arguments ),\n\t\t\tlength = resolveValues.length,\n\n\t\t\t// the count of uncompleted subordinates\n\t\t\tremaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,\n\n\t\t\t// the master Deferred. If resolveValues consist of only a single Deferred, just use that.\n\t\t\tdeferred = remaining === 1 ? subordinate : jQuery.Deferred(),\n\n\t\t\t// Update function for both resolve and progress values\n\t\t\tupdateFunc = function( i, contexts, values ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tcontexts[ i ] = this;\n\t\t\t\t\tvalues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( values === progressValues ) {\n\t\t\t\t\t\tdeferred.notifyWith( contexts, values );\n\t\t\t\t\t} else if ( !( --remaining ) ) {\n\t\t\t\t\t\tdeferred.resolveWith( contexts, values );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tprogressValues, progressContexts, resolveContexts;\n\n\t\t// Add listeners to Deferred subordinates; treat others as resolved\n\t\tif ( length > 1 ) {\n\t\t\tprogressValues = new Array( length );\n\t\t\tprogressContexts = new Array( length );\n\t\t\tresolveContexts = new Array( length );\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {\n\t\t\t\t\tresolveValues[ i ].promise()\n\t\t\t\t\t\t.done( updateFunc( i, resolveContexts, resolveValues ) )\n\t\t\t\t\t\t.fail( deferred.reject )\n\t\t\t\t\t\t.progress( updateFunc( i, progressContexts, progressValues ) );\n\t\t\t\t} else {\n\t\t\t\t\t--remaining;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If we're not waiting on anything, resolve the master\n\t\tif ( !remaining ) {\n\t\t\tdeferred.resolveWith( resolveContexts, resolveValues );\n\t\t}\n\n\t\treturn deferred.promise();\n\t}\n});\n\n\n// The deferred used on DOM ready\nvar readyList;\n\njQuery.fn.ready = function( fn ) {\n\t// Add the callback\n\tjQuery.ready.promise().done( fn );\n\n\treturn this;\n};\n\njQuery.extend({\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Hold (or release) the ready event\n\tholdReady: function( hold ) {\n\t\tif ( hold ) {\n\t\t\tjQuery.readyWait++;\n\t\t} else {\n\t\t\tjQuery.ready( true );\n\t\t}\n\t},\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\n\t\t// Trigger any bound ready events\n\t\tif ( jQuery.fn.triggerHandler ) {\n\t\t\tjQuery( document ).triggerHandler( \"ready\" );\n\t\t\tjQuery( document ).off( \"ready\" );\n\t\t}\n\t}\n});\n\n/**\n * The ready event handler and self cleanup method\n */\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed, false );\n\twindow.removeEventListener( \"load\", completed, false );\n\tjQuery.ready();\n}\n\njQuery.ready.promise = function( obj ) {\n\tif ( !readyList ) {\n\n\t\treadyList = jQuery.Deferred();\n\n\t\t// Catch cases where $(document).ready() is called after the browser event has already occurred.\n\t\t// We once tried to use readyState \"interactive\" here, but it caused issues like the one\n\t\t// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15\n\t\tif ( document.readyState === \"complete\" ) {\n\t\t\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\t\t\tsetTimeout( jQuery.ready );\n\n\t\t} else {\n\n\t\t\t// Use the handy event callback\n\t\t\tdocument.addEventListener( \"DOMContentLoaded\", completed, false );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.addEventListener( \"load\", completed, false );\n\t\t}\n\t}\n\treturn readyList.promise( obj );\n};\n\n// Kick off the DOM ready check even if the user does not\njQuery.ready.promise();\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( jQuery.type( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\tjQuery.access( elems, fn, i, key[i], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !jQuery.isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn chainable ?\n\t\telems :\n\n\t\t// Gets\n\t\tbulk ?\n\t\t\tfn.call( elems ) :\n\t\t\tlen ? fn( elems[0], key ) : emptyGet;\n};\n\n\n/**\n * Determines whether an object can have data\n */\njQuery.acceptData = function( owner ) {\n\t// Accepts only:\n\t//  - Node\n\t//    - Node.ELEMENT_NODE\n\t//    - Node.DOCUMENT_NODE\n\t//  - Object\n\t//    - Any\n\t/* jshint -W018 */\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\nfunction Data() {\n\t// Support: Android<4,\n\t// Old WebKit does not have Object.preventExtensions/freeze method,\n\t// return new empty object instead with no [[set]] accessor\n\tObject.defineProperty( this.cache = {}, 0, {\n\t\tget: function() {\n\t\t\treturn {};\n\t\t}\n\t});\n\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\nData.accepts = jQuery.acceptData;\n\nData.prototype = {\n\tkey: function( owner ) {\n\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t// but we should not, see #8335.\n\t\t// Always return the key for a frozen object.\n\t\tif ( !Data.accepts( owner ) ) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar descriptor = {},\n\t\t\t// Check if the owner object already has a cache key\n\t\t\tunlock = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !unlock ) {\n\t\t\tunlock = Data.uid++;\n\n\t\t\t// Secure it in a non-enumerable, non-writable property\n\t\t\ttry {\n\t\t\t\tdescriptor[ this.expando ] = { value: unlock };\n\t\t\t\tObject.defineProperties( owner, descriptor );\n\n\t\t\t// Support: Android<4\n\t\t\t// Fallback to a less secure definition\n\t\t\t} catch ( e ) {\n\t\t\t\tdescriptor[ this.expando ] = unlock;\n\t\t\t\tjQuery.extend( owner, descriptor );\n\t\t\t}\n\t\t}\n\n\t\t// Ensure the cache object\n\t\tif ( !this.cache[ unlock ] ) {\n\t\t\tthis.cache[ unlock ] = {};\n\t\t}\n\n\t\treturn unlock;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\t// There may be an unlock assigned to this node,\n\t\t\t// if there is no entry for this \"owner\", create one inline\n\t\t\t// and set the unlock as though an owner entry had always existed\n\t\t\tunlock = this.key( owner ),\n\t\t\tcache = this.cache[ unlock ];\n\n\t\t// Handle: [ owner, key, value ] args\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ data ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\t\t\t// Fresh assignments by object are shallow copied\n\t\t\tif ( jQuery.isEmptyObject( cache ) ) {\n\t\t\t\tjQuery.extend( this.cache[ unlock ], data );\n\t\t\t// Otherwise, copy the properties one-by-one to the cache object\n\t\t\t} else {\n\t\t\t\tfor ( prop in data ) {\n\t\t\t\t\tcache[ prop ] = data[ prop ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\t// Either a valid cache is found, or will be created.\n\t\t// New caches will be created and the unlock returned,\n\t\t// allowing direct access to the newly created\n\t\t// empty data object. A valid owner object must be provided.\n\t\tvar cache = this.cache[ this.key( owner ) ];\n\n\t\treturn key === undefined ?\n\t\t\tcache : cache[ key ];\n\t},\n\taccess: function( owner, key, value ) {\n\t\tvar stored;\n\t\t// In cases where either:\n\t\t//\n\t\t//   1. No key was specified\n\t\t//   2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t//   1. The entire cache object\n\t\t//   2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t((key && typeof key === \"string\") && value === undefined) ) {\n\n\t\t\tstored = this.get( owner, key );\n\n\t\t\treturn stored !== undefined ?\n\t\t\t\tstored : this.get( owner, jQuery.camelCase(key) );\n\t\t}\n\n\t\t// [*]When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t//   1. An object of properties\n\t\t//   2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i, name, camel,\n\t\t\tunlock = this.key( owner ),\n\t\t\tcache = this.cache[ unlock ];\n\n\t\tif ( key === undefined ) {\n\t\t\tthis.cache[ unlock ] = {};\n\n\t\t} else {\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( jQuery.isArray( key ) ) {\n\t\t\t\t// If \"name\" is an array of keys...\n\t\t\t\t// When data is initially created, via (\"key\", \"val\") signature,\n\t\t\t\t// keys will be converted to camelCase.\n\t\t\t\t// Since there is no way to tell _how_ a key was added, remove\n\t\t\t\t// both plain key and camelCase key. #12786\n\t\t\t\t// This will only penalize the array argument path.\n\t\t\t\tname = key.concat( key.map( jQuery.camelCase ) );\n\t\t\t} else {\n\t\t\t\tcamel = jQuery.camelCase( key );\n\t\t\t\t// Try the string as a key before any manipulation\n\t\t\t\tif ( key in cache ) {\n\t\t\t\t\tname = [ key, camel ];\n\t\t\t\t} else {\n\t\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\t\tname = camel;\n\t\t\t\t\tname = name in cache ?\n\t\t\t\t\t\t[ name ] : ( name.match( rnotwhite ) || [] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ti = name.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ name[ i ] ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\treturn !jQuery.isEmptyObject(\n\t\t\tthis.cache[ owner[ this.expando ] ] || {}\n\t\t);\n\t},\n\tdiscard: function( owner ) {\n\t\tif ( owner[ this.expando ] ) {\n\t\t\tdelete this.cache[ owner[ this.expando ] ];\n\t\t}\n\t}\n};\nvar data_priv = new Data();\n\nvar data_user = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /([A-Z])/g;\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$1\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = data === \"true\" ? true :\n\t\t\t\t\tdata === \"false\" ? false :\n\t\t\t\t\tdata === \"null\" ? null :\n\t\t\t\t\t// Only convert to a number if it doesn't change the string\n\t\t\t\t\t+data + \"\" === data ? +data :\n\t\t\t\t\trbrace.test( data ) ? jQuery.parseJSON( data ) :\n\t\t\t\t\tdata;\n\t\t\t} catch( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdata_user.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend({\n\thasData: function( elem ) {\n\t\treturn data_user.hasData( elem ) || data_priv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn data_user.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdata_user.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to data_priv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn data_priv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdata_priv.remove( elem, name );\n\t}\n});\n\njQuery.fn.extend({\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = data_user.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !data_priv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE11+\n\t\t\t\t\t\t// The attrs elements can be null (#14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = jQuery.camelCase( name.slice(5) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdata_priv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each(function() {\n\t\t\t\tdata_user.set( this, key );\n\t\t\t});\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data,\n\t\t\t\tcamelKey = jQuery.camelCase( key );\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// with the key as-is\n\t\t\t\tdata = data_user.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// with the key camelized\n\t\t\t\tdata = data_user.get( elem, camelKey );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, camelKey, undefined );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each(function() {\n\t\t\t\t// First, attempt to store a copy or reference of any\n\t\t\t\t// data that might've been store with a camelCased key.\n\t\t\t\tvar data = data_user.get( this, camelKey );\n\n\t\t\t\t// For HTML5 data-* attribute interop, we have to\n\t\t\t\t// store property names with dashes in a camelCase form.\n\t\t\t\t// This might not apply to all properties...*\n\t\t\t\tdata_user.set( this, camelKey, value );\n\n\t\t\t\t// *... In the case of properties that might _actually_\n\t\t\t\t// have dashes, we need to also store a copy of that\n\t\t\t\t// unchanged property.\n\t\t\t\tif ( key.indexOf(\"-\") !== -1 && data !== undefined ) {\n\t\t\t\t\tdata_user.set( this, key, value );\n\t\t\t\t}\n\t\t\t});\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each(function() {\n\t\t\tdata_user.remove( this, key );\n\t\t});\n\t}\n});\n\n\njQuery.extend({\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = data_priv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || jQuery.isArray( data ) ) {\n\t\t\t\t\tqueue = data_priv.access( elem, type, jQuery.makeArray(data) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn data_priv.get( elem, key ) || data_priv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks(\"once memory\").add(function() {\n\t\t\t\tdata_priv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t})\n\t\t});\n\t}\n});\n\njQuery.fn.extend({\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[0], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each(function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[0] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t});\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t});\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = data_priv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n});\nvar pnum = (/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/).source;\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar isHidden = function( elem, el ) {\n\t\t// isHidden might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\t\treturn jQuery.css( elem, \"display\" ) === \"none\" || !jQuery.contains( elem.ownerDocument, elem );\n\t};\n\nvar rcheckableType = (/^(?:checkbox|radio)$/i);\n\n\n\n(function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) ),\n\t\tinput = document.createElement( \"input\" );\n\n\t// Support: Safari<=5.1\n\t// Check state lost if the name is set (#11217)\n\t// Support: Windows Web Apps (WWA)\n\t// `name` and `type` must use .setAttribute for WWA (#14901)\n\tinput.setAttribute( \"type\", \"radio\" );\n\tinput.setAttribute( \"checked\", \"checked\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\n\t// Support: Safari<=5.1, Android<4.2\n\t// Older WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE<=11+\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n})();\nvar strundefined = typeof undefined;\n\n\n\nsupport.focusinBubbles = \"onfocusin\" in window;\n\n\nvar\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,\n\trfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)$/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = data_priv.get( elem );\n\n\t\t// Don't attach events to noData or text/comment nodes (but allow plain objects)\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !(events = elemData.events) ) {\n\t\t\tevents = elemData.events = {};\n\t\t}\n\t\tif ( !(eventHandle = elemData.handle) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnotwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tmp[1];\n\t\t\tnamespaces = ( tmp[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend({\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join(\".\")\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !(handlers = events[ type ]) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle, false );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = data_priv.hasData( elem ) && data_priv.get( elem );\n\n\t\tif ( !elemData || !(events = elemData.events) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnotwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tmp[1];\n\t\t\tnamespaces = ( tmp[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[2] && new RegExp( \"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.|)\") + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector || selector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdelete elemData.handle;\n\t\t\tdata_priv.remove( elem, \"events\" );\n\t\t}\n\t},\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split(\".\") : [];\n\n\t\tcur = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf(\".\") >= 0 ) {\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split(\".\");\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf(\":\") < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join(\".\");\n\t\tevent.namespace_re = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.|)\") + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === (elem.ownerDocument || document) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {\n\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( data_priv.get( cur, \"events\" ) || {} )[ event.type ] && data_priv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && jQuery.acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&\n\t\t\t\tjQuery.acceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\t\t\t\t\telem[ type ]();\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\tdispatch: function( event ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tevent = jQuery.event.fix( event );\n\n\t\tvar i, j, ret, matched, handleObj,\n\t\t\thandlerQueue = [],\n\t\t\targs = slice.call( arguments ),\n\t\t\thandlers = ( data_priv.get( this, \"events\" ) || {} )[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[0] = event;\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// Triggered event must either 1) have no namespace, or 2) have namespace(s)\n\t\t\t\t// a subset or equal to those in the bound event (both can have no namespace).\n\t\t\t\tif ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )\n\t\t\t\t\t\t\t.apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( (event.result = ret) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, matches, sel, handleObj,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\t// Black-hole SVG <use> instance trees (#13180)\n\t\t// Avoid non-left-click bubbling in Firefox (#3861)\n\t\tif ( delegateCount && cur.nodeType && (!event.button || event.type !== \"click\") ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.disabled !== true || event.type !== \"click\" ) {\n\t\t\t\t\tmatches = [];\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matches[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatches[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) >= 0 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matches[ sel ] ) {\n\t\t\t\t\t\t\tmatches.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matches.length ) {\n\t\t\t\t\t\thandlerQueue.push({ elem: cur, handlers: matches });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\t// Includes some event props shared by KeyEvent and MouseEvent\n\tprops: \"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),\n\n\tfixHooks: {},\n\n\tkeyHooks: {\n\t\tprops: \"char charCode key keyCode\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\n\t\t\t// Add which for key events\n\t\t\tif ( event.which == null ) {\n\t\t\t\tevent.which = original.charCode != null ? original.charCode : original.keyCode;\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tmouseHooks: {\n\t\tprops: \"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\t\t\tvar eventDoc, doc, body,\n\t\t\t\tbutton = original.button;\n\n\t\t\t// Calculate pageX/Y if missing and clientX/Y available\n\t\t\tif ( event.pageX == null && original.clientX != null ) {\n\t\t\t\teventDoc = event.target.ownerDocument || document;\n\t\t\t\tdoc = eventDoc.documentElement;\n\t\t\t\tbody = eventDoc.body;\n\n\t\t\t\tevent.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );\n\t\t\t\tevent.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );\n\t\t\t}\n\n\t\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\t\t// Note: button is not normalized, so don't use it\n\t\t\tif ( !event.which && button !== undefined ) {\n\t\t\t\tevent.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tfix: function( event ) {\n\t\tif ( event[ jQuery.expando ] ) {\n\t\t\treturn event;\n\t\t}\n\n\t\t// Create a writable copy of the event object and normalize some properties\n\t\tvar i, prop, copy,\n\t\t\ttype = event.type,\n\t\t\toriginalEvent = event,\n\t\t\tfixHook = this.fixHooks[ type ];\n\n\t\tif ( !fixHook ) {\n\t\t\tthis.fixHooks[ type ] = fixHook =\n\t\t\t\trmouseEvent.test( type ) ? this.mouseHooks :\n\t\t\t\trkeyEvent.test( type ) ? this.keyHooks :\n\t\t\t\t{};\n\t\t}\n\t\tcopy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;\n\n\t\tevent = new jQuery.Event( originalEvent );\n\n\t\ti = copy.length;\n\t\twhile ( i-- ) {\n\t\t\tprop = copy[ i ];\n\t\t\tevent[ prop ] = originalEvent[ prop ];\n\t\t}\n\n\t\t// Support: Cordova 2.5 (WebKit) (#13255)\n\t\t// All events should have a target; Cordova deviceready doesn't\n\t\tif ( !event.target ) {\n\t\t\tevent.target = document;\n\t\t}\n\n\t\t// Support: Safari 6.0+, Chrome<28\n\t\t// Target should not be a text node (#504, #13143)\n\t\tif ( event.target.nodeType === 3 ) {\n\t\t\tevent.target = event.target.parentNode;\n\t\t}\n\n\t\treturn fixHook.filter ? fixHook.filter( event, originalEvent ) : event;\n\t},\n\n\tspecial: {\n\t\tload: {\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tfocus: {\n\t\t\t// Fire native event if possible so blur/focus sequence is correct\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this !== safeActiveElement() && this.focus ) {\n\t\t\t\t\tthis.focus();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusin\"\n\t\t},\n\t\tblur: {\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this === safeActiveElement() && this.blur ) {\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusout\"\n\t\t},\n\t\tclick: {\n\t\t\t// For checkbox, fire native event so checked state will be right\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this.type === \"checkbox\" && this.click && jQuery.nodeName( this, \"input\" ) ) {\n\t\t\t\t\tthis.click();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, don't fire native .click() on links\n\t\t\t_default: function( event ) {\n\t\t\t\treturn jQuery.nodeName( event.target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tsimulate: function( type, elem, event, bubble ) {\n\t\t// Piggyback on a donor event to simulate a different one.\n\t\t// Fake originalEvent to avoid donor's stopPropagation, but if the\n\t\t// simulated event prevents default then we do the same on the donor.\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true,\n\t\t\t\toriginalEvent: {}\n\t\t\t}\n\t\t);\n\t\tif ( bubble ) {\n\t\t\tjQuery.event.trigger( e, null, elem );\n\t\t} else {\n\t\t\tjQuery.event.dispatch.call( elem, e );\n\t\t}\n\t\tif ( e.isDefaultPrevented() ) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n};\n\njQuery.removeEvent = function( elem, type, handle ) {\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle, false );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\t// Allow instantiation without the 'new' keyword\n\tif ( !(this instanceof jQuery.Event) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\t\t\t\t// Support: Android<4.0\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || jQuery.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && e.preventDefault ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && e.stopPropagation ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && e.stopImmediatePropagation ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// Support: Chrome 15+\njQuery.each({\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mousenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || (related !== target && !jQuery.contains( target, related )) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n});\n\n// Support: Firefox, Chrome, Safari\n// Create \"bubbling\" focus and blur events\nif ( !support.focusinBubbles ) {\n\tjQuery.each({ focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );\n\t\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = data_priv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdata_priv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = data_priv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdata_priv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdata_priv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t});\n}\n\njQuery.fn.extend({\n\n\ton: function( types, selector, data, fn, /*INTERNAL*/ one ) {\n\t\tvar origFn, type;\n\n\t\t// Types can be a map of types/handlers\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-Object, selector, data )\n\t\t\tif ( typeof selector !== \"string\" ) {\n\t\t\t\t// ( types-Object, data )\n\t\t\t\tdata = data || selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.on( type, selector, data, types[ type ], one );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( data == null && fn == null ) {\n\t\t\t// ( types, fn )\n\t\t\tfn = selector;\n\t\t\tdata = selector = undefined;\n\t\t} else if ( fn == null ) {\n\t\t\tif ( typeof selector === \"string\" ) {\n\t\t\t\t// ( types, selector, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = undefined;\n\t\t\t} else {\n\t\t\t\t// ( types, data, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t} else if ( !fn ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( one === 1 ) {\n\t\t\torigFn = fn;\n\t\t\tfn = function( event ) {\n\t\t\t\t// Can use an empty set, since event contains the info\n\t\t\t\tjQuery().off( event );\n\t\t\t\treturn origFn.apply( this, arguments );\n\t\t\t};\n\t\t\t// Use same guid so caller can remove using origFn\n\t\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.add( this, types, fn, data, selector );\n\t\t});\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn this.on( types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ? handleObj.origType + \".\" + handleObj.namespace : handleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t});\n\t},\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t});\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[0];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n});\n\n\nvar\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/gi,\n\trtagName = /<([\\w:]+)/,\n\trhtml = /<|&#?\\w+;/,\n\trnoInnerhtml = /<(?:script|style|link)/i,\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trscriptType = /^$|\\/(?:java|ecma)script/i,\n\trscriptTypeMasked = /^true\\/(.*)/,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g,\n\n\t// We have to close these tags to support XHTML (#13200)\n\twrapMap = {\n\n\t\t// Support: IE9\n\t\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\n\t\tthead: [ 1, \"<table>\", \"</table>\" ],\n\t\tcol: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n\t\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\t\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t\t_default: [ 0, \"\", \"\" ]\n\t};\n\n// Support: IE9\nwrapMap.optgroup = wrapMap.option;\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// Support: 1.x compatibility\n// Manipulating tables requires a tbody\nfunction manipulationTarget( elem, content ) {\n\treturn jQuery.nodeName( elem, \"table\" ) &&\n\t\tjQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ?\n\n\t\telem.getElementsByTagName(\"tbody\")[0] ||\n\t\t\telem.appendChild( elem.ownerDocument.createElement(\"tbody\") ) :\n\t\telem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = (elem.getAttribute(\"type\") !== null) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tvar match = rscriptTypeMasked.exec( elem.type );\n\n\tif ( match ) {\n\t\telem.type = match[ 1 ];\n\t} else {\n\t\telem.removeAttribute(\"type\");\n\t}\n\n\treturn elem;\n}\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdata_priv.set(\n\t\t\telems[ i ], \"globalEval\", !refElements || data_priv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( data_priv.hasData( src ) ) {\n\t\tpdataOld = data_priv.access( src );\n\t\tpdataCur = data_priv.set( dest, pdataOld );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdelete pdataCur.handle;\n\t\t\tpdataCur.events = {};\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( data_user.hasData( src ) ) {\n\t\tudataOld = data_user.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdata_user.set( dest, udataCur );\n\t}\n}\n\nfunction getAll( context, tag ) {\n\tvar ret = context.getElementsByTagName ? context.getElementsByTagName( tag || \"*\" ) :\n\t\t\tcontext.querySelectorAll ? context.querySelectorAll( tag || \"*\" ) :\n\t\t\t[];\n\n\treturn tag === undefined || tag && jQuery.nodeName( context, tag ) ?\n\t\tjQuery.merge( [ context ], ret ) :\n\t\tret;\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\njQuery.extend({\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tbuildFragment: function( elems, context, scripts, selection ) {\n\t\tvar elem, tmp, tag, wrap, contains, j,\n\t\t\tfragment = context.createDocumentFragment(),\n\t\t\tnodes = [],\n\t\t\ti = 0,\n\t\t\tl = elems.length;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\telem = elems[ i ];\n\n\t\t\tif ( elem || elem === 0 ) {\n\n\t\t\t\t// Add nodes directly\n\t\t\t\tif ( jQuery.type( elem ) === \"object\" ) {\n\t\t\t\t\t// Support: QtWebKit, PhantomJS\n\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t\t// Convert non-html into a text node\n\t\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t\t// Convert html into DOM nodes\n\t\t\t\t} else {\n\t\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement(\"div\") );\n\n\t\t\t\t\t// Deserialize a standard representation\n\t\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\t\ttmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, \"<$1></$2>\" ) + wrap[ 2 ];\n\n\t\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\t\tj = wrap[ 0 ];\n\t\t\t\t\twhile ( j-- ) {\n\t\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: QtWebKit, PhantomJS\n\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t\t// Remember the top-level container\n\t\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\t\ttmp.textContent = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Remove wrapper from fragment\n\t\tfragment.textContent = \"\";\n\n\t\ti = 0;\n\t\twhile ( (elem = nodes[ i++ ]) ) {\n\n\t\t\t// #4087 - If origin and destination elements are the same, and this is\n\t\t\t// that element, do not do anything\n\t\t\tif ( selection && jQuery.inArray( elem, selection ) !== -1 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontains = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t\t// Append to fragment\n\t\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t\t// Preserve script evaluation history\n\t\t\tif ( contains ) {\n\t\t\t\tsetGlobalEval( tmp );\n\t\t\t}\n\n\t\t\t// Capture executables\n\t\t\tif ( scripts ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (elem = tmp[ j++ ]) ) {\n\t\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\t\tscripts.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn fragment;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type, key,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = elems[ i ]) !== undefined; i++ ) {\n\t\t\tif ( jQuery.acceptData( elem ) ) {\n\t\t\t\tkey = elem[ data_priv.expando ];\n\n\t\t\t\tif ( key && (data = data_priv.cache[ key ]) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( data_priv.cache[ key ] ) {\n\t\t\t\t\t\t// Discard any remaining `private` data\n\t\t\t\t\t\tdelete data_priv.cache[ key ];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Discard any remaining `user` data\n\t\t\tdelete data_user.cache[ elem[ data_user.expando ] ];\n\t\t}\n\t}\n});\n\njQuery.fn.extend({\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each(function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t});\n\t},\n\n\tprepend: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t});\n\t},\n\n\tbefore: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t});\n\t},\n\n\tafter: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t});\n\t},\n\n\tremove: function( selector, keepData /* Internal Use Only */ ) {\n\t\tvar elem,\n\t\t\telems = selector ? jQuery.filter( selector, this ) : this,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\t\t\tif ( !keepData && elem.nodeType === 1 ) {\n\t\t\t\tjQuery.cleanData( getAll( elem ) );\n\t\t\t}\n\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\tif ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\t\t\tsetGlobalEval( getAll( elem, \"script\" ) );\n\t\t\t\t}\n\t\t\t\telem.parentNode.removeChild( elem );\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = this[i]) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map(function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t});\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = value.replace( rxhtmlTag, \"<$1></$2>\" );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar arg = arguments[ 0 ];\n\n\t\t// Make the changes, replacing each context element with the new content\n\t\tthis.domManip( arguments, function( elem ) {\n\t\t\targ = this.parentNode;\n\n\t\t\tjQuery.cleanData( getAll( this ) );\n\n\t\t\tif ( arg ) {\n\t\t\t\targ.replaceChild( elem, this );\n\t\t\t}\n\t\t});\n\n\t\t// Force removal if there was no new content (e.g., from empty arguments)\n\t\treturn arg && (arg.length || arg.nodeType) ? this : this.remove();\n\t},\n\n\tdetach: function( selector ) {\n\t\treturn this.remove( selector, true );\n\t},\n\n\tdomManip: function( args, callback ) {\n\n\t\t// Flatten any nested arrays\n\t\targs = concat.apply( [], args );\n\n\t\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tset = this,\n\t\t\tiNoClone = l - 1,\n\t\t\tvalue = args[ 0 ],\n\t\t\tisFunction = jQuery.isFunction( value );\n\n\t\t// We can't cloneNode fragments that contain checked, in WebKit\n\t\tif ( isFunction ||\n\t\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\t\treturn this.each(function( index ) {\n\t\t\t\tvar self = set.eq( index );\n\t\t\t\tif ( isFunction ) {\n\t\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t\t}\n\t\t\t\tself.domManip( args, callback );\n\t\t\t});\n\t\t}\n\n\t\tif ( l ) {\n\t\t\tfragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );\n\t\t\tfirst = fragment.firstChild;\n\n\t\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\t\tfragment = first;\n\t\t\t}\n\n\t\t\tif ( first ) {\n\t\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\t\thasScripts = scripts.length;\n\n\t\t\t\t// Use the original fragment for the last item instead of the first because it can end up\n\t\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\tnode = fragment;\n\n\t\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\t\t\t// Support: QtWebKit\n\t\t\t\t\t\t\t// jQuery.merge because push.apply(_, arraylike) throws\n\t\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tcallback.call( this[ i ], node, i );\n\t\t\t\t}\n\n\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t\t// Reenable scripts\n\t\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t\t!data_priv.access( node, \"globalEval\" ) && jQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\t\tif ( node.src ) {\n\t\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\t\tif ( jQuery._evalUrl ) {\n\t\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.globalEval( node.textContent.replace( rcleanScript, \"\" ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n});\n\njQuery.each({\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: QtWebKit\n\t\t\t// .get() because push.apply(_, arraylike) throws\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n});\n\n\nvar iframe,\n\telemdisplay = {};\n\n/**\n * Retrieve the actual display of a element\n * @param {String} name nodeName of the element\n * @param {Object} doc Document object\n */\n// Called only from within defaultDisplay\nfunction actualDisplay( name, doc ) {\n\tvar style,\n\t\telem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),\n\n\t\t// getDefaultComputedStyle might be reliably used only on attached element\n\t\tdisplay = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?\n\n\t\t\t// Use of this method is a temporary fix (more like optimization) until something better comes along,\n\t\t\t// since it was removed from specification and supported only in FF\n\t\t\tstyle.display : jQuery.css( elem[ 0 ], \"display\" );\n\n\t// We don't have any data stored on the element,\n\t// so use \"detach\" method as fast way to get rid of the element\n\telem.detach();\n\n\treturn display;\n}\n\n/**\n * Try to determine the default display value of an element\n * @param {String} nodeName\n */\nfunction defaultDisplay( nodeName ) {\n\tvar doc = document,\n\t\tdisplay = elemdisplay[ nodeName ];\n\n\tif ( !display ) {\n\t\tdisplay = actualDisplay( nodeName, doc );\n\n\t\t// If the simple way fails, read from inside an iframe\n\t\tif ( display === \"none\" || !display ) {\n\n\t\t\t// Use the already-created iframe if possible\n\t\t\tiframe = (iframe || jQuery( \"<iframe frameborder='0' width='0' height='0'/>\" )).appendTo( doc.documentElement );\n\n\t\t\t// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse\n\t\t\tdoc = iframe[ 0 ].contentDocument;\n\n\t\t\t// Support: IE\n\t\t\tdoc.write();\n\t\t\tdoc.close();\n\n\t\t\tdisplay = actualDisplay( nodeName, doc );\n\t\t\tiframe.detach();\n\t\t}\n\n\t\t// Store the correct default display\n\t\telemdisplay[ nodeName ] = display;\n\t}\n\n\treturn display;\n}\nvar rmargin = (/^margin/);\n\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\t\t// Support: IE<=11+, Firefox<=30+ (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tif ( elem.ownerDocument.defaultView.opener ) {\n\t\t\treturn elem.ownerDocument.defaultView.getComputedStyle( elem, null );\n\t\t}\n\n\t\treturn window.getComputedStyle( elem, null );\n\t};\n\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// Support: IE9\n\t// getPropertyValue is only needed for .css('filter') (#12537)\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\t}\n\n\tif ( computed ) {\n\n\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// Support: iOS < 6\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// iOS < 6 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels\n\t\t// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values\n\t\tif ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\t\t// Support: IE\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn (this.get = hookFn).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\n(function() {\n\tvar pixelPositionVal, boxSizingReliableVal,\n\t\tdocElem = document.documentElement,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE9-11+\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tcontainer.style.cssText = \"border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;\" +\n\t\t\"position:absolute\";\n\tcontainer.appendChild( div );\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computePixelPositionAndBoxSizingReliable() {\n\t\tdiv.style.cssText =\n\t\t\t// Support: Firefox<29, Android 2.3\n\t\t\t// Vendor-prefix box-sizing\n\t\t\t\"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;\" +\n\t\t\t\"box-sizing:border-box;display:block;margin-top:1%;top:1%;\" +\n\t\t\t\"border:1px;padding:1px;width:4px;position:absolute\";\n\t\tdiv.innerHTML = \"\";\n\t\tdocElem.appendChild( container );\n\n\t\tvar divStyle = window.getComputedStyle( div, null );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\t\tboxSizingReliableVal = divStyle.width === \"4px\";\n\n\t\tdocElem.removeChild( container );\n\t}\n\n\t// Support: node.js jsdom\n\t// Don't assume that getComputedStyle is a property of the global object\n\tif ( window.getComputedStyle ) {\n\t\tjQuery.extend( support, {\n\t\t\tpixelPosition: function() {\n\n\t\t\t\t// This test is executed only once but we still do memoizing\n\t\t\t\t// since we can use the boxSizingReliable pre-computing.\n\t\t\t\t// No need to check if the test was already performed, though.\n\t\t\t\tcomputePixelPositionAndBoxSizingReliable();\n\t\t\t\treturn pixelPositionVal;\n\t\t\t},\n\t\t\tboxSizingReliable: function() {\n\t\t\t\tif ( boxSizingReliableVal == null ) {\n\t\t\t\t\tcomputePixelPositionAndBoxSizingReliable();\n\t\t\t\t}\n\t\t\t\treturn boxSizingReliableVal;\n\t\t\t},\n\t\t\treliableMarginRight: function() {\n\n\t\t\t\t// Support: Android 2.3\n\t\t\t\t// Check if div with explicit width and no margin-right incorrectly\n\t\t\t\t// gets computed margin-right based on width of container. (#3333)\n\t\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t\t// This support function is only executed once so no memoizing is needed.\n\t\t\t\tvar ret,\n\t\t\t\t\tmarginDiv = div.appendChild( document.createElement( \"div\" ) );\n\n\t\t\t\t// Reset CSS: box-sizing; display; margin; border; padding\n\t\t\t\tmarginDiv.style.cssText = div.style.cssText =\n\t\t\t\t\t// Support: Firefox<29, Android 2.3\n\t\t\t\t\t// Vendor-prefix box-sizing\n\t\t\t\t\t\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;\" +\n\t\t\t\t\t\"box-sizing:content-box;display:block;margin:0;border:0;padding:0\";\n\t\t\t\tmarginDiv.style.marginRight = marginDiv.style.width = \"0\";\n\t\t\t\tdiv.style.width = \"1px\";\n\t\t\t\tdocElem.appendChild( container );\n\n\t\t\t\tret = !parseFloat( window.getComputedStyle( marginDiv, null ).marginRight );\n\n\t\t\t\tdocElem.removeChild( container );\n\t\t\t\tdiv.removeChild( marginDiv );\n\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t});\n\t}\n})();\n\n\n// A method for quickly swapping in/out CSS properties to get correct calculations.\njQuery.swap = function( elem, options, callback, args ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.apply( elem, args || [] );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\nvar\n\t// Swappable if display is none or starts with table except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trnumsplit = new RegExp( \"^(\" + pnum + \")(.*)$\", \"i\" ),\n\trrelNum = new RegExp( \"^([+-])=(\" + pnum + \")\", \"i\" ),\n\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t},\n\n\tcssPrefixes = [ \"Webkit\", \"O\", \"Moz\", \"ms\" ];\n\n// Return a css property mapped to a potentially vendor prefixed property\nfunction vendorPropName( style, name ) {\n\n\t// Shortcut for names that are not vendor prefixed\n\tif ( name in style ) {\n\t\treturn name;\n\t}\n\n\t// Check for vendor prefixed names\n\tvar capName = name[0].toUpperCase() + name.slice(1),\n\t\torigName = name,\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in style ) {\n\t\t\treturn name;\n\t\t}\n\t}\n\n\treturn origName;\n}\n\nfunction setPositiveNumber( elem, value, subtract ) {\n\tvar matches = rnumsplit.exec( value );\n\treturn matches ?\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {\n\tvar i = extra === ( isBorderBox ? \"border\" : \"content\" ) ?\n\t\t// If we already have the right measurement, avoid augmentation\n\t\t4 :\n\t\t// Otherwise initialize for horizontal or vertical properties\n\t\tname === \"width\" ? 1 : 0,\n\n\t\tval = 0;\n\n\tfor ( ; i < 4; i += 2 ) {\n\t\t// Both box models exclude margin, so add it if we want it\n\t\tif ( extra === \"margin\" ) {\n\t\t\tval += jQuery.css( elem, extra + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\tif ( isBorderBox ) {\n\t\t\t// border-box includes padding, so remove it if we want content\n\t\t\tif ( extra === \"content\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// At this point, extra isn't border nor margin, so remove border\n\t\t\tif ( extra !== \"margin\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t} else {\n\t\t\t// At this point, extra isn't content, so add padding\n\t\t\tval += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// At this point, extra isn't content nor padding, so add border\n\t\t\tif ( extra !== \"padding\" ) {\n\t\t\t\tval += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn val;\n}\n\nfunction getWidthOrHeight( elem, name, extra ) {\n\n\t// Start with offset property, which is equivalent to the border-box value\n\tvar valueIsBorderBox = true,\n\t\tval = name === \"width\" ? elem.offsetWidth : elem.offsetHeight,\n\t\tstyles = getStyles( elem ),\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t// Some non-html elements return undefined for offsetWidth, so check for null/undefined\n\t// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285\n\t// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668\n\tif ( val <= 0 || val == null ) {\n\t\t// Fall back to computed then uncomputed css if necessary\n\t\tval = curCSS( elem, name, styles );\n\t\tif ( val < 0 || val == null ) {\n\t\t\tval = elem.style[ name ];\n\t\t}\n\n\t\t// Computed unit is not pixels. Stop here and return.\n\t\tif ( rnumnonpx.test(val) ) {\n\t\t\treturn val;\n\t\t}\n\n\t\t// Check for style in case a browser which returns unreliable values\n\t\t// for getComputedStyle silently falls back to the reliable elem.style\n\t\tvalueIsBorderBox = isBorderBox &&\n\t\t\t( support.boxSizingReliable() || val === elem.style[ name ] );\n\n\t\t// Normalize \"\", auto, and prepare for extra\n\t\tval = parseFloat( val ) || 0;\n\t}\n\n\t// Use the active box-sizing model to add/subtract irrelevant styles\n\treturn ( val +\n\t\taugmentWidthOrHeight(\n\t\t\telem,\n\t\t\tname,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles\n\t\t)\n\t) + \"px\";\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem, hidden,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvalues[ index ] = data_priv.get( elem, \"olddisplay\" );\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\t\t\t// Reset the inline display of this element to learn if it is\n\t\t\t// being hidden by cascaded rules or not\n\t\t\tif ( !values[ index ] && display === \"none\" ) {\n\t\t\t\telem.style.display = \"\";\n\t\t\t}\n\n\t\t\t// Set elements which have been overridden with display: none\n\t\t\t// in a stylesheet to whatever the default browser style is\n\t\t\t// for such an element\n\t\t\tif ( elem.style.display === \"\" && isHidden( elem ) ) {\n\t\t\t\tvalues[ index ] = data_priv.access( elem, \"olddisplay\", defaultDisplay(elem.nodeName) );\n\t\t\t}\n\t\t} else {\n\t\t\thidden = isHidden( elem );\n\n\t\t\tif ( display !== \"none\" || !hidden ) {\n\t\t\t\tdata_priv.set( elem, \"olddisplay\", hidden ? display : jQuery.css( elem, \"display\" ) );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of most of the elements in a second loop\n\t// to avoid the constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !show || elem.style.display === \"none\" || elem.style.display === \"\" ) {\n\t\t\telem.style.display = show ? values[ index ] || \"\" : \"none\";\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.extend({\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {\n\t\t\"float\": \"cssFloat\"\n\t},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = jQuery.camelCase( name ),\n\t\t\tstyle = elem.style;\n\n\t\tname = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && (ret = rrelNum.exec( value )) ) {\n\t\t\t\tvalue = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number, add 'px' to the (except for certain CSS properties)\n\t\t\tif ( type === \"number\" && !jQuery.cssNumber[ origName ] ) {\n\t\t\t\tvalue += \"px\";\n\t\t\t}\n\n\t\t\t// Support: IE9-11+\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !(\"set\" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {\n\t\t\t\tstyle[ name ] = value;\n\t\t\t}\n\n\t\t} else {\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = jQuery.camelCase( name );\n\n\t\t// Make sure that we're working with the right name\n\t\tname = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || jQuery.isNumeric( num ) ? num || 0 : val;\n\t\t}\n\t\treturn val;\n\t}\n});\n\njQuery.each([ \"height\", \"width\" ], function( i, name ) {\n\tjQuery.cssHooks[ name ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) && elem.offsetWidth === 0 ?\n\t\t\t\t\tjQuery.swap( elem, cssShow, function() {\n\t\t\t\t\t\treturn getWidthOrHeight( elem, name, extra );\n\t\t\t\t\t}) :\n\t\t\t\t\tgetWidthOrHeight( elem, name, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar styles = extra && getStyles( elem );\n\t\t\treturn setPositiveNumber( elem, value, extra ?\n\t\t\t\taugmentWidthOrHeight(\n\t\t\t\t\telem,\n\t\t\t\t\tname,\n\t\t\t\t\textra,\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\t\tstyles\n\t\t\t\t) : 0\n\t\t\t);\n\t\t}\n\t};\n});\n\n// Support: Android 2.3\njQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn jQuery.swap( elem, { \"display\": \"inline-block\" },\n\t\t\t\tcurCSS, [ elem, \"marginRight\" ] );\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each({\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split(\" \") : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( !rmargin.test( prefix ) ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n});\n\njQuery.fn.extend({\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( jQuery.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t},\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tif ( isHidden( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t});\n\t}\n});\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || \"swing\";\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\tif ( tween.elem[ tween.prop ] != null &&\n\t\t\t\t(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE9\n// Panic based approach to setting things on disconnected nodes\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t}\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back Compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, timerId,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trfxnum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" ),\n\trrun = /queueHooks$/,\n\tanimationPrefilters = [ defaultPrefilter ],\n\ttweeners = {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value ),\n\t\t\t\ttarget = tween.cur(),\n\t\t\t\tparts = rfxnum.exec( value ),\n\t\t\t\tunit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t\t\t// Starting value computation is required for potential unit mismatches\n\t\t\t\tstart = ( jQuery.cssNumber[ prop ] || unit !== \"px\" && +target ) &&\n\t\t\t\t\trfxnum.exec( jQuery.css( tween.elem, prop ) ),\n\t\t\t\tscale = 1,\n\t\t\t\tmaxIterations = 20;\n\n\t\t\tif ( start && start[ 3 ] !== unit ) {\n\t\t\t\t// Trust units reported by jQuery.css\n\t\t\t\tunit = unit || start[ 3 ];\n\n\t\t\t\t// Make sure we update the tween properties later on\n\t\t\t\tparts = parts || [];\n\n\t\t\t\t// Iteratively approximate from a nonzero starting point\n\t\t\t\tstart = +target || 1;\n\n\t\t\t\tdo {\n\t\t\t\t\t// If previous iteration zeroed out, double until we get *something*.\n\t\t\t\t\t// Use string for doubling so we don't accidentally see scale as unchanged below\n\t\t\t\t\tscale = scale || \".5\";\n\n\t\t\t\t\t// Adjust and apply\n\t\t\t\t\tstart = start / scale;\n\t\t\t\t\tjQuery.style( tween.elem, prop, start + unit );\n\n\t\t\t\t// Update scale, tolerating zero or NaN from tween.cur(),\n\t\t\t\t// break the loop if scale is unchanged or perfect, or if we've just had enough\n\t\t\t\t} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );\n\t\t\t}\n\n\t\t\t// Update tween properties\n\t\t\tif ( parts ) {\n\t\t\t\tstart = tween.start = +start || +target || 0;\n\t\t\t\ttween.unit = unit;\n\t\t\t\t// If a +=/-= token was provided, we're doing a relative animation\n\t\t\t\ttween.end = parts[ 1 ] ?\n\t\t\t\t\tstart + ( parts[ 1 ] + 1 ) * parts[ 2 ] :\n\t\t\t\t\t+parts[ 2 ];\n\t\t\t}\n\n\t\t\treturn tween;\n\t\t} ]\n\t};\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\tsetTimeout(function() {\n\t\tfxNow = undefined;\n\t});\n\treturn ( fxNow = jQuery.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4 ; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( tweeners[ prop ] || [] ).concat( tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( (tween = collection[ index ].call( animation, prop, value )) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\t/* jshint validthis: true */\n\tvar prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHidden( elem ),\n\t\tdataShow = data_priv.get( elem, \"fxshow\" );\n\n\t// Handle queue: false promises\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always(function() {\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always(function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t// Height/width overflow pass\n\tif ( elem.nodeType === 1 && ( \"height\" in props || \"width\" in props ) ) {\n\t\t// Make sure that nothing sneaks out\n\t\t// Record all 3 overflow attributes because IE9-10 do not\n\t\t// change the overflow attribute when overflowX and\n\t\t// overflowY are set to the same value\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Set display property to inline-block for height/width\n\t\t// animations on inline elements that are having width/height animated\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\n\t\t// Test default display if display is currently \"none\"\n\t\tcheckDisplay = display === \"none\" ?\n\t\t\tdata_priv.get( elem, \"olddisplay\" ) || defaultDisplay( elem.nodeName ) : display;\n\n\t\tif ( checkDisplay === \"inline\" && jQuery.css( elem, \"float\" ) === \"none\" ) {\n\t\t\tstyle.display = \"inline-block\";\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always(function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t});\n\t}\n\n\t// show/hide pass\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.exec( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\n\t\t// Any non-fx value stops us from restoring the original display value\n\t\t} else {\n\t\t\tdisplay = undefined;\n\t\t}\n\t}\n\n\tif ( !jQuery.isEmptyObject( orig ) ) {\n\t\tif ( dataShow ) {\n\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\thidden = dataShow.hidden;\n\t\t\t}\n\t\t} else {\n\t\t\tdataShow = data_priv.access( elem, \"fxshow\", {} );\n\t\t}\n\n\t\t// Store state if its toggle - enables .stop().toggle() to \"reverse\"\n\t\tif ( toggle ) {\n\t\t\tdataShow.hidden = !hidden;\n\t\t}\n\t\tif ( hidden ) {\n\t\t\tjQuery( elem ).show();\n\t\t} else {\n\t\t\tanim.done(function() {\n\t\t\t\tjQuery( elem ).hide();\n\t\t\t});\n\t\t}\n\t\tanim.done(function() {\n\t\t\tvar prop;\n\n\t\t\tdata_priv.remove( elem, \"fxshow\" );\n\t\t\tfor ( prop in orig ) {\n\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t}\n\t\t});\n\t\tfor ( prop in orig ) {\n\t\t\ttween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\n\t\t\tif ( !( prop in dataShow ) ) {\n\t\t\t\tdataShow[ prop ] = tween.start;\n\t\t\t\tif ( hidden ) {\n\t\t\t\t\ttween.end = tween.start;\n\t\t\t\t\ttween.start = prop === \"width\" || prop === \"height\" ? 1 : 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t// If this is a noop like .hide().hide(), restore an overwritten display value\n\t} else if ( (display === \"none\" ? defaultDisplay( elem.nodeName ) : display) === \"inline\" ) {\n\t\tstyle.display = display;\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = jQuery.camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( jQuery.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = animationPrefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t}),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\t\t\t\t// Support: Android 2.3\n\t\t\t\t// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ]);\n\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t} else {\n\t\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t\tanimation = deferred.promise({\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, { specialEasing: {} }, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t}),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length ; index++ ) {\n\t\tresult = animationPrefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( jQuery.isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t})\n\t);\n\n\t// attach callbacks from options\n\treturn animation.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweener: function( props, callback ) {\n\t\tif ( jQuery.isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.split(\" \");\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length ; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\ttweeners[ prop ] = tweeners[ prop ] || [];\n\t\t\ttweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tanimationPrefilters.unshift( callback );\n\t\t} else {\n\t\t\tanimationPrefilters.push( callback );\n\t\t}\n\t}\n});\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tjQuery.isFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !jQuery.isFunction( easing ) && easing\n\t};\n\n\topt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ? opt.duration :\n\t\topt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( jQuery.isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend({\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHidden ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate({ opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || data_priv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = data_priv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t});\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tvar index,\n\t\t\t\tdata = data_priv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t});\n\t}\n});\n\njQuery.each([ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n});\n\n// Generate shortcuts for custom animations\njQuery.each({\n\tslideDown: genFx(\"show\"),\n\tslideUp: genFx(\"hide\"),\n\tslideToggle: genFx(\"toggle\"),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n});\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = jQuery.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\t\t// Checks the timer has not already been removed\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tif ( timer() ) {\n\t\tjQuery.fx.start();\n\t} else {\n\t\tjQuery.timers.pop();\n\t}\n};\n\njQuery.fx.interval = 13;\n\njQuery.fx.start = function() {\n\tif ( !timerId ) {\n\t\ttimerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );\n\t}\n};\n\njQuery.fx.stop = function() {\n\tclearInterval( timerId );\n\ttimerId = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\tclearTimeout( timeout );\n\t\t};\n\t});\n};\n\n\n(function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: iOS<=5.1, Android<=4.2+\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE<=11+\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: Android<=2.3\n\t// Options inside disabled selects are incorrectly marked as disabled\n\tselect.disabled = true;\n\tsupport.optDisabled = !opt.disabled;\n\n\t// Support: IE<=11+\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n})();\n\n\nvar nodeHook, boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend({\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tattr: function( elem, name, value ) {\n\t\tvar hooks, ret,\n\t\t\tnType = elem.nodeType;\n\n\t\t// don't get/set attributes on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === strundefined ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// All attributes are lowercase\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\tname = name.toLowerCase();\n\t\t\thooks = jQuery.attrHooks[ name ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\n\t\t\t} else if ( hooks && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t} else if ( hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ) {\n\t\t\treturn ret;\n\n\t\t} else {\n\t\t\tret = jQuery.find.attr( elem, name );\n\n\t\t\t// Non-existent attributes return null, we normalize to undefined\n\t\t\treturn ret == null ?\n\t\t\t\tundefined :\n\t\t\t\tret;\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name, propName,\n\t\t\ti = 0,\n\t\t\tattrNames = value && value.match( rnotwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( (name = attrNames[i++]) ) {\n\t\t\t\tpropName = jQuery.propFix[ name ] || name;\n\n\t\t\t\t// Boolean attributes get special treatment (#10870)\n\t\t\t\tif ( jQuery.expr.match.bool.test( name ) ) {\n\t\t\t\t\t// Set corresponding property to false\n\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t}\n\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tjQuery.nodeName( elem, \"input\" ) ) {\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle;\n\t\tif ( !isXML ) {\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ name ];\n\t\t\tattrHandle[ name ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tname.toLowerCase() :\n\t\t\t\tnull;\n\t\t\tattrHandle[ name ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n});\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i;\n\njQuery.fn.extend({\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each(function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t},\n\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks, notxml,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\tif ( notxml ) {\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\treturn hooks && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?\n\t\t\t\tret :\n\t\t\t\t( elem[ name ] = value );\n\n\t\t} else {\n\t\t\treturn hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ?\n\t\t\t\tret :\n\t\t\t\telem[ name ];\n\t\t}\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\t\t\t\treturn elem.hasAttribute( \"tabindex\" ) || rfocusable.test( elem.nodeName ) || elem.href ?\n\t\t\t\t\telem.tabIndex :\n\t\t\t\t\t-1;\n\t\t\t}\n\t\t}\n\t}\n});\n\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t};\n}\n\njQuery.each([\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n});\n\n\n\n\nvar rclass = /[\\t\\r\\n\\f]/g;\n\njQuery.fn.extend({\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, clazz, j, finalValue,\n\t\t\tproceed = typeof value === \"string\" && value,\n\t\t\ti = 0,\n\t\t\tlen = this.length;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, this.className ) );\n\t\t\t});\n\t\t}\n\n\t\tif ( proceed ) {\n\t\t\t// The disjunction here is for better compressibility (see removeClass)\n\t\t\tclasses = ( value || \"\" ).match( rnotwhite ) || [];\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\telem = this[ i ];\n\t\t\t\tcur = elem.nodeType === 1 && ( elem.className ?\n\t\t\t\t\t( \" \" + elem.className + \" \" ).replace( rclass, \" \" ) :\n\t\t\t\t\t\" \"\n\t\t\t\t);\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (clazz = classes[j++]) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = jQuery.trim( cur );\n\t\t\t\t\tif ( elem.className !== finalValue ) {\n\t\t\t\t\t\telem.className = finalValue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, clazz, j, finalValue,\n\t\t\tproceed = arguments.length === 0 || typeof value === \"string\" && value,\n\t\t\ti = 0,\n\t\t\tlen = this.length;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, this.className ) );\n\t\t\t});\n\t\t}\n\t\tif ( proceed ) {\n\t\t\tclasses = ( value || \"\" ).match( rnotwhite ) || [];\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\telem = this[ i ];\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( elem.className ?\n\t\t\t\t\t( \" \" + elem.className + \" \" ).replace( rclass, \" \" ) :\n\t\t\t\t\t\"\"\n\t\t\t\t);\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (clazz = classes[j++]) ) {\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) >= 0 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = value ? jQuery.trim( cur ) : \"\";\n\t\t\t\t\tif ( elem.className !== finalValue ) {\n\t\t\t\t\t\telem.className = finalValue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value;\n\n\t\tif ( typeof stateVal === \"boolean\" && type === \"string\" ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tif ( type === \"string\" ) {\n\t\t\t\t// Toggle individual class names\n\t\t\t\tvar className,\n\t\t\t\t\ti = 0,\n\t\t\t\t\tself = jQuery( this ),\n\t\t\t\t\tclassNames = value.match( rnotwhite ) || [];\n\n\t\t\t\twhile ( (className = classNames[ i++ ]) ) {\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( type === strundefined || type === \"boolean\" ) {\n\t\t\t\tif ( this.className ) {\n\t\t\t\t\t// store className if set\n\t\t\t\t\tdata_priv.set( this, \"__className__\", this.className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tthis.className = this.className || value === false ? \"\" : data_priv.get( this, \"__className__\" ) || \"\";\n\t\t\t}\n\t\t});\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className = \" \" + selector + \" \",\n\t\t\ti = 0,\n\t\t\tl = this.length;\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tif ( this[i].nodeType === 1 && (\" \" + this[i].className + \" \").replace(rclass, \" \").indexOf( className ) >= 0 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n});\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend({\n\tval: function( value ) {\n\t\tvar hooks, ret, isFunction,\n\t\t\telem = this[0];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, \"value\" )) !== undefined ) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\treturn typeof ret === \"string\" ?\n\t\t\t\t\t// Handle most common string cases\n\t\t\t\t\tret.replace(rreturn, \"\") :\n\t\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\t\tret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tisFunction = jQuery.isFunction( value );\n\n\t\treturn this.each(function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( jQuery.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t});\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !(\"set\" in hooks) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\t\t\t\t\t// Support: IE10-11+\n\t\t\t\t\t// option.text throws exceptions (#14686, #14858)\n\t\t\t\t\tjQuery.trim( jQuery.text( elem ) );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\" || index < 0,\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length,\n\t\t\t\t\ti = index < 0 ?\n\t\t\t\t\t\tmax :\n\t\t\t\t\t\tone ? index : 0;\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// IE6-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t( support.optDisabled ? !option.disabled : option.getAttribute( \"disabled\" ) === null ) &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\t\t\t\t\tif ( (option.selected = jQuery.inArray( option.value, values ) >= 0) ) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Radios and checkboxes getter/setter\njQuery.each([ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( jQuery.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute(\"value\") === null ? \"on\" : elem.value;\n\t\t};\n\t}\n});\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\njQuery.each( (\"blur focus focusin focusout load resize scroll unload click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup error contextmenu\").split(\" \"), function( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n});\n\njQuery.fn.extend({\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t},\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ? this.off( selector, \"**\" ) : this.off( types, selector || \"**\", fn );\n\t}\n});\n\n\nvar nonce = jQuery.now();\n\nvar rquery = (/\\?/);\n\n\n\n// Support: Android 2.3\n// Workaround failure to string-cast null input\njQuery.parseJSON = function( data ) {\n\treturn JSON.parse( data + \"\" );\n};\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml, tmp;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE9\n\ttry {\n\t\ttmp = new DOMParser();\n\t\txml = tmp.parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {\n\t\txml = undefined;\n\t}\n\n\tif ( !xml || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\tjQuery.error( \"Invalid XML: \" + data );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trhash = /#.*$/,\n\trts = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\trurl = /^([\\w.+-]+:)(?:\\/\\/(?:[^\\/?#]*@|)([^\\/?#:]*)(?::(\\d+)|)|)/,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Document location\n\tajaxLocation = window.location.href,\n\n\t// Segment location into parts\n\tajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];\n\n\t\tif ( jQuery.isFunction( func ) ) {\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( (dataType = dataTypes[i++]) ) {\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[0] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t(structure[ dataType ] = structure[ dataType ] || []).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t(structure[ dataType ] = structure[ dataType ] || []).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t});\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader(\"Content-Type\");\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[0] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s[ \"throws\" ] ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn { state: \"parsererror\", error: conv ? e : \"No conversion from \" + prev + \" to \" + current };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend({\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: ajaxLocation,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /xml/,\n\t\t\thtml: /html/,\n\t\t\tjson: /json/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": jQuery.parseJSON,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\t\t\t// Cross-domain detection vars\n\t\t\tparts,\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\t\t\t// Loop variable\n\t\t\ti,\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\tjQuery.event,\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks(\"once memory\"),\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\t\t\t// The jqXHR state\n\t\t\tstate = 0,\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( state === 2 ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( (match = rheaders.exec( responseHeadersString )) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[1].toLowerCase() ] = match[ 2 ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match;\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn state === 2 ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tvar lname = name.toLowerCase();\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\tname = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\t// Lazy-add the new callback in a way that preserves old ones\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR ).complete = completeDeferred.add;\n\t\tjqXHR.success = jqXHR.done;\n\t\tjqXHR.error = jqXHR.fail;\n\n\t\t// Remove hash character (#7531: and string promotion)\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || ajaxLocation ) + \"\" ).replace( rhash, \"\" )\n\t\t\t.replace( rprotocol, ajaxLocParts[ 1 ] + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = jQuery.trim( s.dataType || \"*\" ).toLowerCase().match( rnotwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when we have a protocol:host:port mismatch\n\t\tif ( s.crossDomain == null ) {\n\t\t\tparts = rurl.exec( s.url.toLowerCase() );\n\t\t\ts.crossDomain = !!( parts &&\n\t\t\t\t( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||\n\t\t\t\t\t( parts[ 3 ] || ( parts[ 1 ] === \"http:\" ? \"80\" : \"443\" ) ) !==\n\t\t\t\t\t\t( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === \"http:\" ? \"80\" : \"443\" ) ) )\n\t\t\t);\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( state === 2 ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger(\"ajaxStart\");\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\tcacheURL = s.url;\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// If data is available, append data to url\n\t\t\tif ( s.data ) {\n\t\t\t\tcacheURL = ( s.url += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data );\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add anti-cache in url if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\ts.url = rts.test( cacheURL ) ?\n\n\t\t\t\t\t// If there is already a '_' parameter, set its value\n\t\t\t\t\tcacheURL.replace( rts, \"$1_=\" + nonce++ ) :\n\n\t\t\t\t\t// Otherwise add one to the end\n\t\t\t\t\tcacheURL + ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + nonce++;\n\t\t\t}\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tfor ( i in { success: 1, error: 1, complete: 1 } ) {\n\t\t\tjqXHR[ i ]( s[ i ] );\n\t\t}\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = setTimeout(function() {\n\t\t\t\t\tjqXHR.abort(\"timeout\");\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tstate = 1;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\t\t\t\t// Propagate exception as error if not done\n\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\tdone( -1, e );\n\t\t\t\t// Simply rethrow otherwise\n\t\t\t\t} else {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Called once\n\t\t\tif ( state === 2 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// State is \"done\" now\n\t\t\tstate = 2;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\tclearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader(\"Last-Modified\");\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader(\"etag\");\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger(\"ajaxStop\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n});\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\t\t// Shift arguments if data argument was omitted\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\treturn jQuery.ajax({\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t});\n\t};\n});\n\n\njQuery._evalUrl = function( url ) {\n\treturn jQuery.ajax({\n\t\turl: url,\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tasync: false,\n\t\tglobal: false,\n\t\t\"throws\": true\n\t});\n};\n\n\njQuery.fn.extend({\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).wrapAll( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\tif ( this[ 0 ] ) {\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map(function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t}).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t});\n\t},\n\n\twrap: function( html ) {\n\t\tvar isFunction = jQuery.isFunction( html );\n\n\t\treturn this.each(function( i ) {\n\t\t\tjQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );\n\t\t});\n\t},\n\n\tunwrap: function() {\n\t\treturn this.parent().each(function() {\n\t\t\tif ( !jQuery.nodeName( this, \"body\" ) ) {\n\t\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t\t}\n\t\t}).end();\n\t}\n});\n\n\njQuery.expr.filters.hidden = function( elem ) {\n\t// Support: Opera <= 12.12\n\t// Opera reports offsetWidths and offsetHeights less than zero on some elements\n\treturn elem.offsetWidth <= 0 && elem.offsetHeight <= 0;\n};\njQuery.expr.filters.visible = function( elem ) {\n\treturn !jQuery.expr.filters.hidden( elem );\n};\n\n\n\n\nvar r20 = /%20/g,\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( jQuery.isArray( obj ) ) {\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams( prefix + \"[\" + ( typeof v === \"object\" ? i : \"\" ) + \"]\", v, traditional, add );\n\t\t\t}\n\t\t});\n\n\t} else if ( !traditional && jQuery.type( obj ) === \"object\" ) {\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, value ) {\n\t\t\t// If value is a function, invoke it and return its value\n\t\t\tvalue = jQuery.isFunction( value ) ? value() : ( value == null ? \"\" : value );\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" + encodeURIComponent( value );\n\t\t};\n\n\t// Set traditional to true for jQuery <= 1.3.2 behavior.\n\tif ( traditional === undefined ) {\n\t\ttraditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t});\n\n\t} else {\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" ).replace( r20, \"+\" );\n};\n\njQuery.fn.extend({\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map(function() {\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t})\n\t\t.filter(function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t})\n\t\t.map(function( i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\treturn val == null ?\n\t\t\t\tnull :\n\t\t\t\tjQuery.isArray( val ) ?\n\t\t\t\t\tjQuery.map( val, function( val ) {\n\t\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t\t}) :\n\t\t\t\t\t{ name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t}).get();\n\t}\n});\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new XMLHttpRequest();\n\t} catch( e ) {}\n};\n\nvar xhrId = 0,\n\txhrCallbacks = {},\n\txhrSuccessStatus = {\n\t\t// file protocol always yields status code 0, assume 200\n\t\t0: 200,\n\t\t// Support: IE9\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\n// Support: IE9\n// Open requests must be manually aborted on unload (#5280)\n// See https://support.microsoft.com/kb/2856746 for more info\nif ( window.attachEvent ) {\n\twindow.attachEvent( \"onunload\", function() {\n\t\tfor ( var key in xhrCallbacks ) {\n\t\t\txhrCallbacks[ key ]();\n\t\t}\n\t});\n}\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport(function( options ) {\n\tvar callback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr(),\n\t\t\t\t\tid = ++xhrId;\n\n\t\t\t\txhr.open( options.type, options.url, options.async, options.username, options.password );\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[\"X-Requested-With\"] ) {\n\t\t\t\t\theaders[\"X-Requested-With\"] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tdelete xhrCallbacks[ id ];\n\t\t\t\t\t\t\tcallback = xhr.onload = xhr.onerror = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\t// file: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\t\t\t\t\t\t\t\t\t// Support: IE9\n\t\t\t\t\t\t\t\t\t// Accessing binary-data responseText throws an exception\n\t\t\t\t\t\t\t\t\t// (#11426)\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText === \"string\" ? {\n\t\t\t\t\t\t\t\t\t\ttext: xhr.responseText\n\t\t\t\t\t\t\t\t\t} : undefined,\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\n\t\t\t\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\txhr.onerror = callback(\"error\");\n\n\t\t\t\t// Create the abort callback\n\t\t\t\tcallback = xhrCallbacks[ id ] = callback(\"abort\");\n\n\t\t\t\ttry {\n\t\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t\t} catch ( e ) {\n\t\t\t\t\t// #14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n});\n\n\n\n\n// Install script dataType\njQuery.ajaxSetup({\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /(?:java|ecma)script/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n});\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t}\n});\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery(\"<script>\").prop({\n\t\t\t\t\tasync: true,\n\t\t\t\t\tcharset: s.scriptCharset,\n\t\t\t\t\tsrc: s.url\n\t\t\t\t}).on(\n\t\t\t\t\t\"load error\",\n\t\t\t\t\tcallback = function( evt ) {\n\t\t\t\t\t\tscript.remove();\n\t\t\t\t\t\tcallback = null;\n\t\t\t\t\t\tif ( evt ) {\n\t\t\t\t\t\t\tcomplete( evt.type === \"error\" ? 404 : 200, evt.type );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\tdocument.head.appendChild( script[ 0 ] );\n\t\t\t},\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n});\n\n\n\n\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup({\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\n\t}\n});\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" && !( s.contentType || \"\" ).indexOf(\"application/x-www-form-urlencoded\") && rjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n\t\t}\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[\"script json\"] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( callbackName + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always(function() {\n\t\t\t// Restore preexisting value\n\t\t\twindow[ callbackName ] = overwritten;\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\t\t\t\t// make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && jQuery.isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t});\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n});\n\n\n\n\n// data: string of html\n// context (optional): If specified, the fragment will be created in this context, defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\tcontext = context || document;\n\n\tvar parsed = rsingleTag.exec( data ),\n\t\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[1] ) ];\n\t}\n\n\tparsed = jQuery.buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\n// Keep a copy of the old load method\nvar _load = jQuery.fn.load;\n\n/**\n * Load a url into a page\n */\njQuery.fn.load = function( url, params, callback ) {\n\tif ( typeof url !== \"string\" && _load ) {\n\t\treturn _load.apply( this, arguments );\n\t}\n\n\tvar selector, type, response,\n\t\tself = this,\n\t\toff = url.indexOf(\" \");\n\n\tif ( off >= 0 ) {\n\t\tselector = jQuery.trim( url.slice( off ) );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( jQuery.isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax({\n\t\t\turl: url,\n\n\t\t\t// if \"type\" variable is undefined, then \"GET\" method will be used\n\t\t\ttype: type,\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t}).done(function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery(\"<div>\").append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t}).complete( callback && function( jqXHR, status ) {\n\t\t\tself.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t});\n\t}\n\n\treturn this;\n};\n\n\n\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( [ \"ajaxStart\", \"ajaxStop\", \"ajaxComplete\", \"ajaxError\", \"ajaxSuccess\", \"ajaxSend\" ], function( i, type ) {\n\tjQuery.fn[ type ] = function( fn ) {\n\t\treturn this.on( type, fn );\n\t};\n});\n\n\n\n\njQuery.expr.filters.animated = function( elem ) {\n\treturn jQuery.grep(jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t}).length;\n};\n\n\n\n\nvar docElem = window.document.documentElement;\n\n/**\n * Gets a window from an element\n */\nfunction getWindow( elem ) {\n\treturn jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;\n}\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\n\n\t\t// Set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\t( curCSSTop + curCSSLeft ).indexOf(\"auto\") > -1;\n\n\t\t// Need to be able to calculate position if either\n\t\t// top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( jQuery.isFunction( options ) ) {\n\t\t\toptions = options.call( elem, i, curOffset );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend({\n\toffset: function( options ) {\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each(function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t});\n\t\t}\n\n\t\tvar docElem, win,\n\t\t\telem = this[ 0 ],\n\t\t\tbox = { top: 0, left: 0 },\n\t\t\tdoc = elem && elem.ownerDocument;\n\n\t\tif ( !doc ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocElem = doc.documentElement;\n\n\t\t// Make sure it's not a disconnected DOM node\n\t\tif ( !jQuery.contains( docElem, elem ) ) {\n\t\t\treturn box;\n\t\t}\n\n\t\t// Support: BlackBerry 5, iOS 3 (original iPhone)\n\t\t// If we don't have gBCR, just use 0,0 rather than error\n\t\tif ( typeof elem.getBoundingClientRect !== strundefined ) {\n\t\t\tbox = elem.getBoundingClientRect();\n\t\t}\n\t\twin = getWindow( doc );\n\t\treturn {\n\t\t\ttop: box.top + win.pageYOffset - docElem.clientTop,\n\t\t\tleft: box.left + win.pageXOffset - docElem.clientLeft\n\t\t};\n\t},\n\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset,\n\t\t\telem = this[ 0 ],\n\t\t\tparentOffset = { top: 0, left: 0 };\n\n\t\t// Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\t\t\t// Assume getBoundingClientRect is there when computed position is fixed\n\t\t\toffset = elem.getBoundingClientRect();\n\n\t\t} else {\n\t\t\t// Get *real* offsetParent\n\t\t\toffsetParent = this.offsetParent();\n\n\t\t\t// Get correct offsets\n\t\t\toffset = this.offset();\n\t\t\tif ( !jQuery.nodeName( offsetParent[ 0 ], \"html\" ) ) {\n\t\t\t\tparentOffset = offsetParent.offset();\n\t\t\t}\n\n\t\t\t// Add offsetParent borders\n\t\t\tparentOffset.top += jQuery.css( offsetParent[ 0 ], \"borderTopWidth\", true );\n\t\t\tparentOffset.left += jQuery.css( offsetParent[ 0 ], \"borderLeftWidth\", true );\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n\t\t};\n\t},\n\n\toffsetParent: function() {\n\t\treturn this.map(function() {\n\t\t\tvar offsetParent = this.offsetParent || docElem;\n\n\t\t\twhile ( offsetParent && ( !jQuery.nodeName( offsetParent, \"html\" ) && jQuery.css( offsetParent, \"position\" ) === \"static\" ) ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\n\t\t\treturn offsetParent || docElem;\n\t\t});\n\t}\n});\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = \"pageYOffset\" === prop;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\t\t\tvar win = getWindow( elem );\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? win[ prop ] : elem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : window.pageXOffset,\n\t\t\t\t\ttop ? val : window.pageYOffset\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length, null );\n\t};\n});\n\n// Support: Safari<7+, Chrome<37+\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280\n// getComputedStyle returns percent when specified for top/left/bottom/right;\n// rather than make the css module depend on the offset module, just check for it here\njQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\t\t\t\t// If curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n});\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name }, function( defaultExtra, funcName ) {\n\t\t// Margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( jQuery.isWindow( elem ) ) {\n\t\t\t\t\t// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there\n\t\t\t\t\t// isn't a whole lot we can do. See pull request at this URL for discussion:\n\t\t\t\t\t// https://github.com/jquery/jquery/pull/764\n\t\t\t\t\treturn elem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n\t\t\t\t\t// whichever is greatest\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable, null );\n\t\t};\n\t});\n});\n\n\n// The number of elements contained in the matched element set\njQuery.fn.size = function() {\n\treturn this.length;\n};\n\njQuery.fn.andSelf = jQuery.fn.addBack;\n\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t});\n}\n\n\n\n\nvar\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$;\n\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in AMD\n// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( typeof noGlobal === strundefined ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\n\n\n\nreturn jQuery;\n\n}));\n"
  },
  {
    "path": "resources/public/js/jquery.console.js",
    "content": "// JQuery Console 1.0\n// Sun Feb 21 20:28:47 GMT 2010\n//\n// Copyright 2010 Chris Done, Simon David Pratt. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions\n// are met:\n//\n//    1. Redistributions of source code must retain the above\n//       copyright notice, this list of conditions and the following\n//       disclaimer.\n//\n//    2. Redistributions in binary form must reproduce the above\n//       copyright notice, this list of conditions and the following\n//       disclaimer in the documentation and/or other materials\n//       provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n// POSSIBILITY OF SUCH DAMAGE.\n\n// TESTED ON\n//   Internet Explorer 6\n//   Opera 10.01\n//   Chromium 4.0.237.0 (Ubuntu build 31094)\n//   Firefox 3.5.8, 3.6.2 (Mac)\n//   Safari 4.0.5 (6531.22.7) (Mac)\n//   Google Chrome 5.0.375.55 (Mac)\n\n(function($){\n  var isWebkit = !!~navigator.userAgent.indexOf(' AppleWebKit/');\n\n  $.fn.console = function(config){\n    ////////////////////////////////////////////////////////////////////////\n    // Constants\n    // Some are enums, data types, others just for optimisation\n    var keyCodes = {\n      // left\n      37: moveBackward,\n      // right\n      39: moveForward,\n      // up\n      38: previousHistory,\n      // down\n      40: nextHistory,\n      // backspace\n      8:  backDelete,\n      // delete\n      46: forwardDelete,\n      // end\n      35: moveToEnd,\n      // start\n      36: moveToStart,\n      // return\n      13: commandTrigger,\n      // tab\n      18: doNothing,\n      // tab\n      9: doComplete\n    };\n    var ctrlCodes = {\n      // C-a\n      65: moveToStart,\n      // C-e\n      69: moveToEnd,\n      // C-d\n      68: forwardDelete,\n      // C-n\n      78: nextHistory,\n      // C-p\n      80: previousHistory,\n      // C-b\n      66: moveBackward,\n      // C-f\n      70: moveForward,\n      // C-k\n      75: deleteUntilEnd\n    };\n    if(config.ctrlCodes) {\n      $.extend(ctrlCodes, config.ctrlCodes);\n    }\n    var altCodes = {\n      // M-f\n      70: moveToNextWord,\n      // M-b\n      66: moveToPreviousWord,\n      // M-d\n      68: deleteNextWord\n    };\n    var shiftCodes = {\n      // return\n      13: newLine,\n    };\n    var cursor = '<span class=\"jquery-console-cursor\">&nbsp;</span>';\n\n    ////////////////////////////////////////////////////////////////////////\n    // Globals\n    var container = $(this);\n    var inner = $('<div class=\"jquery-console-inner\"></div>');\n    // erjiang: changed this from a text input to a textarea so we\n    // can get pasted newlines\n    var typer = $('<textarea autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" class=\"jquery-console-typer\"></textarea>');\n    // Prompt\n    var promptBox;\n    var prompt;\n    var continuedPromptLabel = config && config.continuedPromptLabel?\n      config.continuedPromptLabel : \"> \";\n    var column = 0;\n    var promptText = '';\n    var restoreText = '';\n    var continuedText = '';\n    var fadeOnReset = config.fadeOnReset !== undefined ? config.fadeOnReset : true;\n    // Prompt history stack\n    var history = [];\n    var ringn = 0;\n    // For reasons unknown to The Sword of Michael himself, Opera\n    // triggers and sends a key character when you hit various\n    // keys like PgUp, End, etc. So there is no way of knowing\n    // when a user has typed '#' or End. My solution is in the\n    // typer.keydown and typer.keypress functions; I use the\n    // variable below to ignore the keypress event if the keydown\n    // event succeeds.\n    var cancelKeyPress = 0;\n    // When this value is false, the prompt will not respond to input\n    var acceptInput = true;\n    // When this value is true, the command has been canceled\n    var cancelCommand = false;\n\n    // External exports object\n    var extern = {};\n\n    ////////////////////////////////////////////////////////////////////////\n    // Main entry point\n    (function(){\n      extern.promptLabel = config && config.promptLabel? config.promptLabel : \"> \";\n      container.append(inner);\n      inner.append(typer);\n      typer.css({position:'absolute',top:0,left:'-9999px'});\n      if (config.welcomeMessage)\n\tmessage(config.welcomeMessage,'jquery-console-welcome');\n      newPromptBox();\n      if (config.autofocus) {\n\tinner.addClass('jquery-console-focus');\n\ttyper.focus();\n\tsetTimeout(function(){\n\t  inner.addClass('jquery-console-focus');\n\t  typer.focus();\n\t},100);\n      }\n      extern.inner = inner;\n      extern.typer = typer;\n      extern.scrollToBottom = scrollToBottom;\n      extern.report = report;\n    })();\n\n    ////////////////////////////////////////////////////////////////////////\n    // Reset terminal\n    extern.reset = function(){\n      var welcome = (typeof config.welcomeMessage != 'undefined');\n\n      var removeElements = function() {\n\tinner.find('div').each(function(){\n\t  if (!welcome) {\n\t    $(this).remove();\n\t  } else {\n\t    welcome = false;\n\t  }\n\t});\n      };\n\n      if (fadeOnReset) {\n\tinner.parent().fadeOut(function() {\n\t  removeElements();\n\t  newPromptBox();\n\t  inner.parent().fadeIn(focusConsole);\n\t});\n      }\n      else {\n\tremoveElements();\n\tnewPromptBox();\n\tfocusConsole();\n      }\n    };\n\n    var focusConsole = function() {\n      inner.addClass('jquery-console-focus');\n      typer.focus();\n    };\n\n    extern.focus = function(){\n      focusConsole();\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // Reset terminal\n    extern.notice = function(msg,style){\n      var n = $('<div class=\"notice\"></div>').append($('<div></div>').text(msg))\n\t.css({visibility:'hidden'});\n      container.append(n);\n      var focused = true;\n      if (style=='fadeout')\n\tsetTimeout(function(){\n\t  n.fadeOut(function(){\n\t    n.remove();\n\t  });\n\t},4000);\n      else if (style=='prompt') {\n\tvar a = $('<br/><div class=\"action\"><a href=\"javascript:\">OK</a><div class=\"clear\"></div></div>');\n\tn.append(a);\n\tfocused = false;\n\ta.click(function(){ n.fadeOut(function(){ n.remove();inner.css({opacity:1}) }); });\n      }\n      var h = n.height();\n      n.css({height:'0px',visibility:'visible'})\n\t.animate({height:h+'px'},function(){\n\t  if (!focused) inner.css({opacity:0.5});\n\t});\n      n.css('cursor','default');\n      return n;\n    };\n\n    ////////////////////////////////////////////////////////////////////////\n    // Make a new prompt box\n    function newPromptBox() {\n      column = 0;\n      promptText = '';\n      ringn = 0; // Reset the position of the history ring\n      enableInput();\n      promptBox = $('<div class=\"jquery-console-prompt-box\"></div>');\n      var label = $('<span class=\"jquery-console-prompt-label\"></span>');\n      var labelText = extern.continuedPrompt? continuedPromptLabel : extern.promptLabel;\n      promptBox.append(label.text(labelText).show());\n      label.html(label.html().replace(' ','&nbsp;'));\n      prompt = $('<span class=\"jquery-console-prompt\"></span>');\n      promptBox.append(prompt);\n      inner.append(promptBox);\n      updatePromptDisplay();\n    };\n\n    ////////////////////////////////////////////////////////////////////////\n    // Handle setting focus\n    container.click(function(){\n      // Don't mess with the focus if there is an active selection\n      if (window.getSelection().toString()) {\n\treturn false;\n      }\n\n      inner.addClass('jquery-console-focus');\n      inner.removeClass('jquery-console-nofocus');\n      if (isWebkit) {\n\ttyper.focusWithoutScrolling();\n      } else {\n\ttyper.css('position', 'fixed').focus();\n      }\n      scrollToBottom();\n      return false;\n    });\n\n    ////////////////////////////////////////////////////////////////////////\n    // Handle losing focus\n    typer.blur(function(){\n      inner.removeClass('jquery-console-focus');\n      inner.addClass('jquery-console-nofocus');\n    });\n\n    ////////////////////////////////////////////////////////////////////////\n    // Bind to the paste event of the input box so we know when we\n    // get pasted data\n    typer.bind('paste', function(e) {\n      // wipe typer input clean just in case\n      typer.val(\"\");\n      // this timeout is required because the onpaste event is\n      // fired *before* the text is actually pasted\n      setTimeout(function() {\n\ttyper.consoleInsert(typer.val());\n\ttyper.val(\"\");\n      }, 0);\n    });\n\n    ////////////////////////////////////////////////////////////////////////\n    // Handle key hit before translation\n    // For picking up control characters like up/left/down/right\n\n    typer.keydown(function(e){\n      cancelKeyPress = 0;\n      var keyCode = e.keyCode;\n      // C-c: cancel the execution\n      if(e.ctrlKey && keyCode == 67) {\n\tcancelKeyPress = keyCode;\n\tcancelExecution();\n\treturn false;\n      }\n      if (acceptInput) {\n\tif (e.shiftKey && keyCode in shiftCodes) {\n\t  cancelKeyPress = keyCode;\n\t  (shiftCodes[keyCode])();\n\t  return false;\n\t} else if (e.altKey  && keyCode in altCodes) {\n\t  cancelKeyPress = keyCode;\n\t  (altCodes[keyCode])();\n\t  return false;\n\t} else if (e.ctrlKey && keyCode in ctrlCodes) {\n\t  cancelKeyPress = keyCode;\n\t  (ctrlCodes[keyCode])();\n\t  return false;\n\t} else if (keyCode in keyCodes) {\n\t  cancelKeyPress = keyCode;\n\t  (keyCodes[keyCode])();\n\t  return false;\n\t}\n      }\n    });\n\n    ////////////////////////////////////////////////////////////////////////\n    // Handle key press\n    typer.keypress(function(e){\n      var keyCode = e.keyCode || e.which;\n      if (isIgnorableKey(e)) {\n\treturn false;\n      }\n      // C-v: don't insert on paste event\n      if ((e.ctrlKey || e.metaKey) && String.fromCharCode(keyCode).toLowerCase() == 'v') {\n\treturn true;\n      }\n      if (acceptInput && cancelKeyPress != keyCode && keyCode >= 32){\n\tif (cancelKeyPress) return false;\n\tif (\n\t  typeof config.charInsertTrigger == 'undefined' || (\n\t    typeof config.charInsertTrigger == 'function' &&\n\t      config.charInsertTrigger(keyCode,promptText)\n\t  )\n\t){\n\t  typer.consoleInsert(keyCode);\n\t}\n      }\n      if (isWebkit) return false;\n    });\n\n    function isIgnorableKey(e) {\n      // for now just filter alt+tab that we receive on some platforms when\n      // user switches windows (goes away from the browser)\n      return ((e.keyCode == keyCodes.tab || e.keyCode == 192) && e.altKey);\n    };\n\n    ////////////////////////////////////////////////////////////////////////\n    // Rotate through the command history\n    function rotateHistory(n){\n      if (history.length == 0) return;\n      ringn += n;\n      if (ringn < 0) ringn = history.length;\n      else if (ringn > history.length) ringn = 0;\n      var prevText = promptText;\n      if (ringn == 0) {\n\tpromptText = restoreText;\n      } else {\n\tpromptText = history[ringn - 1];\n      }\n      if (config.historyPreserveColumn) {\n\tif (promptText.length < column + 1) {\n\t  column = promptText.length;\n\t} else if (column == 0) {\n\t  column = promptText.length;\n\t}\n      } else {\n\tcolumn = promptText.length;\n      }\n      updatePromptDisplay();\n    };\n\n    function previousHistory() {\n      rotateHistory(-1);\n    };\n\n    function nextHistory() {\n      rotateHistory(1);\n    };\n\n    // Add something to the history ring\n    function addToHistory(line){\n      history.push(line);\n      restoreText = '';\n    };\n\n    // Delete the character at the current position\n    function deleteCharAtPos(){\n      if (column < promptText.length){\n\tpromptText =\n\t  promptText.substring(0,column) +\n\t  promptText.substring(column+1);\n\trestoreText = promptText;\n\treturn true;\n      } else return false;\n    };\n\n    function backDelete() {\n      if (moveColumn(-1)){\n\tdeleteCharAtPos();\n\tupdatePromptDisplay();\n      }\n    };\n\n    function forwardDelete() {\n      if (deleteCharAtPos()){\n\tupdatePromptDisplay();\n      }\n    };\n\n    function deleteUntilEnd() {\n      while(deleteCharAtPos()) {\n\tupdatePromptDisplay();\n      }\n    };\n\n    function deleteNextWord() {\n      // A word is defined within this context as a series of alphanumeric\n      // characters.\n      // Delete up to the next alphanumeric character\n      while(\n\tcolumn < promptText.length &&\n\t  !isCharAlphanumeric(promptText[column])\n      ) {\n\tdeleteCharAtPos();\n\tupdatePromptDisplay();\n      }\n      // Then, delete until the next non-alphanumeric character\n      while(\n\tcolumn < promptText.length &&\n\t  isCharAlphanumeric(promptText[column])\n      ) {\n\tdeleteCharAtPos();\n\tupdatePromptDisplay();\n      }\n    };\n\n    function newLine() {\n      var lines = promptText.split(\"\\n\");\n      var last_line = lines.slice(-1)[0];\n      var spaces = last_line.match(/^(\\s*)/g)[0];\n      var new_line = \"\\n\" + spaces;\n      promptText += new_line;\n      moveColumn(new_line.length);\n      updatePromptDisplay();\n    };\n\n    ////////////////////////////////////////////////////////////////////////\n    // Validate command and trigger it if valid, or show a validation error\n    function commandTrigger() {\n      var line = promptText;\n      if (typeof config.commandValidate == 'function') {\n\tvar ret = config.commandValidate(line);\n\tif (ret == true || ret == false) {\n\t  if (ret) {\n\t    handleCommand();\n\t  }\n\t} else {\n\t  commandResult(ret,\"jquery-console-message-error\");\n\t}\n      } else {\n\thandleCommand();\n      }\n    };\n\n    // Scroll to the bottom of the view\n    function scrollToBottom() {\n      var version = jQuery.fn.jquery.split('.');\n      var major = parseInt(version[0]);\n      var minor = parseInt(version[1]);\n\n      // check if we're using jquery > 1.6\n      if ((major == 1 && minor > 6) || major > 1) {\n\tinner.prop({ scrollTop: inner.prop(\"scrollHeight\") });\n      }\n      else {\n\tinner.attr({ scrollTop: inner.attr(\"scrollHeight\") });\n      }\n    };\n\n    function cancelExecution() {\n      if(typeof config.cancelHandle == 'function') {\n\tconfig.cancelHandle();\n      }\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // Handle a command\n    function handleCommand() {\n      if (typeof config.commandHandle == 'function') {\n\tdisableInput();\n\taddToHistory(promptText);\n\tvar text = promptText;\n\tif (extern.continuedPrompt) {\n\t  if (continuedText)\n\t    continuedText += '\\n' + promptText;\n\t  else continuedText = promptText;\n\t} else continuedText = undefined;\n\tif (continuedText) text = continuedText;\n\tvar ret = config.commandHandle(text,function(msgs){\n\t  commandResult(msgs);\n\t});\n\tif (extern.continuedPrompt && !continuedText)\n\t  continuedText = promptText;\n\tif (typeof ret == 'boolean') {\n\t  if (ret) {\n\t    // Command succeeded without a result.\n\t    commandResult();\n\t  } else {\n\t    commandResult(\n\t      'Command failed.',\n\t      \"jquery-console-message-error\"\n\t    );\n\t  }\n\t} else if (typeof ret == \"string\") {\n\t  commandResult(ret,\"jquery-console-message-success\");\n\t} else if (typeof ret == 'object' && ret.length) {\n\t  commandResult(ret);\n\t} else if (extern.continuedPrompt) {\n\t  commandResult();\n\t}\n      }\n    };\n\n    ////////////////////////////////////////////////////////////////////////\n    // Disable input\n    function disableInput() {\n      acceptInput = false;\n    };\n\n    // Enable input\n    function enableInput() {\n      acceptInput = true;\n    }\n\n    ////////////////////////////////////////////////////////////////////////\n    // Reset the prompt in invalid command\n    function commandResult(msg,className) {\n      column = -1;\n      updatePromptDisplay();\n      if (typeof msg == 'string') {\n\tmessage(msg,className);\n      } else if ($.isArray(msg)) {\n\tfor (var x in msg) {\n\t  var ret = msg[x];\n\t  message(ret.msg,ret.className);\n\t}\n      } else { // Assume it's a DOM node or jQuery object.\n\tinner.append(msg);\n      }\n      newPromptBox();\n    };\n\n    ////////////////////////////////////////////////////////////////////////\n    // Report some message into the console\n    function report(msg,className) {\n      var text = promptText;\n      promptBox.remove();\n      commandResult(msg,className);\n      extern.promptText(text);\n    };\n\n    ////////////////////////////////////////////////////////////////////////\n    // Display a message\n    function message(msg,className) {\n      var mesg = $('<div class=\"jquery-console-message\"></div>');\n      if (className) mesg.addClass(className);\n      mesg.filledText(msg).hide();\n      inner.append(mesg);\n      mesg.show();\n    };\n\n    ////////////////////////////////////////////////////////////////////////\n    // Handle normal character insertion\n    // data can either be a number, which will be interpreted as the\n    // numeric value of a single character, or a string\n    typer.consoleInsert = function(data){\n      // TODO: remove redundant indirection\n      var text = (typeof data == 'number') ? String.fromCharCode(data) : data;\n      var before = promptText.substring(0,column);\n      var after = promptText.substring(column);\n      promptText = before + text + after;\n      moveColumn(text.length);\n      restoreText = promptText;\n      updatePromptDisplay();\n    };\n\n    ////////////////////////////////////////////////////////////////////////\n    // Move to another column relative to this one\n    // Negative means go back, positive means go forward.\n    function moveColumn(n){\n      if (column + n >= 0 && column + n <= promptText.length){\n\tcolumn += n;\n\treturn true;\n      } else return false;\n    };\n\n    function moveForward() {\n      if(moveColumn(1)) {\n\tupdatePromptDisplay();\n\treturn true;\n      }\n      return false;\n    };\n\n    function moveBackward() {\n      if(moveColumn(-1)) {\n\tupdatePromptDisplay();\n\treturn true;\n      }\n      return false;\n    };\n\n    function moveToStart() {\n      if (moveColumn(-column))\n\tupdatePromptDisplay();\n    };\n\n    function moveToEnd() {\n      if (moveColumn(promptText.length-column))\n\tupdatePromptDisplay();\n    };\n\n    function moveToNextWord() {\n      while(\n\tcolumn < promptText.length &&\n\t  !isCharAlphanumeric(promptText[column]) &&\n\t  moveForward()\n      ) {}\n      while(\n\tcolumn < promptText.length &&\n\t  isCharAlphanumeric(promptText[column]) &&\n\t  moveForward()\n      ) {}\n    };\n\n    function moveToPreviousWord() {\n      // Move backward until we find the first alphanumeric\n      while(\n\tcolumn -1 >= 0 &&\n\t  !isCharAlphanumeric(promptText[column-1]) &&\n\t  moveBackward()\n      ) {}\n      // Move until we find the first non-alphanumeric\n      while(\n\tcolumn -1 >= 0 &&\n\t  isCharAlphanumeric(promptText[column-1]) &&\n\t  moveBackward()\n      ) {}\n    };\n\n    function isCharAlphanumeric(charToTest) {\n      if(typeof charToTest == 'string') {\n\tvar code = charToTest.charCodeAt();\n\treturn (code >= 'A'.charCodeAt() && code <= 'Z'.charCodeAt()) ||\n\t  (code >= 'a'.charCodeAt() && code <= 'z'.charCodeAt()) ||\n\t  (code >= '0'.charCodeAt() && code <= '9'.charCodeAt());\n      }\n      return false;\n    };\n\n    function doComplete() {\n      if(typeof config.completeHandle == 'function') {\n\tvar completions = config.completeHandle(promptText);\n\tvar len = completions.length;\n\tif (len === 1) {\n\t  extern.promptText(promptText + completions[0]);\n\t} else if (len > 1 && config.cols) {\n\t  var prompt = promptText;\n\t  // Compute the number of rows that will fit in the width\n\t  var max = 0;\n\t  for (var i = 0;i < len;i++) {\n\t    max = Math.max(max, completions[i].length);\n\t  }\n\t  max += 2;\n\t  var n = Math.floor(config.cols / max);\n\t  var buffer = \"\";\n\t  var col = 0;\n\t  for (i = 0;i < len;i++) {\n\t    var completion = completions[i];\n\t    buffer += completions[i];\n\t    for (var j = completion.length;j < max;j++) {\n\t      buffer += \" \";\n\t    }\n\t    if (++col >= n) {\n\t      buffer += \"\\n\";\n\t      col = 0;\n\t    }\n\t  }\n\t  commandResult(buffer,\"jquery-console-message-value\");\n\t  extern.promptText(prompt);\n\t}\n      }\n    };\n\n    function doNothing() {};\n\n    extern.promptText = function(text){\n      if (typeof text === 'string') {\n\tpromptText = text;\n\tcolumn = promptText.length;\n\tupdatePromptDisplay();\n      }\n      return promptText;\n    };\n\n    ////////////////////////////////////////////////////////////////////////\n    // Update the prompt display\n    function updatePromptDisplay(){\n      var line = promptText;\n      var html = '';\n      if (column > 0 && line == ''){\n\t// When we have an empty line just display a cursor.\n\thtml = cursor;\n      } else if (column == promptText.length){\n\t// We're at the end of the line, so we need to display\n\t// the text *and* cursor.\n\thtml = htmlEncode(line) + cursor;\n      } else {\n\t// Grab the current character, if there is one, and\n\t// make it the current cursor.\n\tvar before = line.substring(0, column);\n\tvar current = line.substring(column,column+1);\n\tif (current){\n\t  current =\n\t    '<span class=\"jquery-console-cursor\">' +\n\t    htmlEncode(current) +\n\t    '</span>';\n\t}\n\tvar after = line.substring(column+1);\n\thtml = htmlEncode(before) + current + htmlEncode(after);\n      }\n      prompt.html(html);\n      scrollToBottom();\n    };\n\n    // Simple HTML encoding\n    // Simply replace '<', '>' and '&'\n    // TODO: Use jQuery's .html() trick, or grab a proper, fast\n    // HTML encoder.\n    function htmlEncode(text){\n      return (\n\ttext.replace(/&/g,'&amp;')\n\t  .replace(/</g,'&lt;')\n\t  .replace(/</g,'&lt;')\n\t  .replace(/ /g,'&nbsp;')\n\t  .replace(/\\n/g,'<br />')\n      );\n    };\n\n    return extern;\n  };\n  // Simple utility for printing messages\n  $.fn.filledText = function(txt){\n    $(this).text(txt);\n    $(this).html($(this).html().replace(/\\n/g,'<br/>'));\n    return this;\n  };\n\n  // Alternative method for focus without scrolling\n  $.fn.focusWithoutScrolling = function(){\n    var x = window.scrollX, y = window.scrollY;\n    $(this).focus();\n    window.scrollTo(x, y);\n  };\n})(jQuery);\n"
  },
  {
    "path": "resources/public/js/jquery.websocket-0.0.1.js",
    "content": "/*\n * jQuery Web Sockets Plugin v0.0.1\n * http://code.google.com/p/jquery-websocket/\n *\n * This document is licensed as free software under the terms of the\n * MIT License: http://www.opensource.org/licenses/mit-license.php\n * \n * Copyright (c) 2010 by shootaroo (Shotaro Tsubouchi).\n */\n(function($){\n$.extend({\n\twebsocketSettings: {\n\t\topen: function(){},\n\t\tclose: function(){},\n\t\tmessage: function(){},\n\t\toptions: {},\n\t\tevents: {}\n\t},\n\twebsocket: function(url, s) {\n\t\tvar ws = WebSocket ? new WebSocket( url ) : {\n\t\t\tsend: function(m){ return false },\n\t\t\tclose: function(){}\n\t\t};\n\t\t$(ws)\n\t\t\t.bind('open', $.websocketSettings.open)\n\t\t\t.bind('close', $.websocketSettings.close)\n\t\t\t.bind('message', $.websocketSettings.message)\n\t\t\t.bind('message', function(e){\n\t\t\t\tvar m = $.evalJSON(e.originalEvent.data);\n\t\t\t\tvar h = $.websocketSettings.events[m.type];\n\t\t\t\tif (h) h.call(this, m);\n\t\t\t});\n\t\tws._settings = $.extend($.websocketSettings, s);\n\t\tws._send = ws.send;\n\t\tws.send = function(type, data) {\n\t\t\tvar m = {type: type};\n\t\t\tm = $.extend(true, m, $.extend(true, {}, $.websocketSettings.options, m));\n\t\t\tif (data) m['data'] = data;\n\t\t\treturn this._send($.toJSON(m));\n\t\t}\n\t\t$(window).unload(function(){ ws.close(); ws = null });\n\t\treturn ws;\n\t}\n});\n})(jQuery);\n"
  },
  {
    "path": "resources/public/js/npm.js",
    "content": "// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.\nrequire('../../js/transition.js')\nrequire('../../js/alert.js')\nrequire('../../js/button.js')\nrequire('../../js/carousel.js')\nrequire('../../js/collapse.js')\nrequire('../../js/dropdown.js')\nrequire('../../js/modal.js')\nrequire('../../js/tooltip.js')\nrequire('../../js/popover.js')\nrequire('../../js/scrollspy.js')\nrequire('../../js/tab.js')\nrequire('../../js/affix.js')"
  },
  {
    "path": "resources/public/js/show_updates.js",
    "content": "function updateCueGrid( data ) {\n    $.each( data, function( key, val ) {\n        $('#' + val.id).css('background-color', val.color);\n        $('#' + val.id).css('color', val.textColor);\n        $('#' + val.id).html(val.name);\n    });\n}\n\nfunction updateEffectState() {\n    if ($(\"#effects-table tbody tr\").length > 0) {\n        $(\"#no-effects\").hide();\n        $(\"#some-effects\").show();\n    } else {\n        $(\"#no-effects\").show();\n        $(\"#some-effects\").hide();\n    }\n}\n\nfunction buildFraction( n ) {\n    return $('<span></span>', { \"class\": \"time-fraction\" })\n        .text((n < 10? \".0\" : \".\") + n);\n}\n\nfunction buildEffectRow( data ) {\n    var row = $('<tr></tr>', { id: \"effect-\" + data.id });\n    var macroBox = \"\";\n\n    if (data.macro) {\n        macroBox = $('<input>', { id: \"effect-selected-\" + data.x + \"-\" + data.y + \"-\" + data.id,\n                                  type: \"checkbox\",\n                                  \"class\": \"macro-checkbox\"\n                                }\n                    );\n    }\n\n    var priority = \"\";\n    if (data.priority != 0) {\n        priority = $('<span></span>', { class: \"small\" })\n            .text(\" (Priority \" + data.priority + \")\")\n    }\n    effectName = $('<td></td>')\n        .append($('<h5></h5>')\n                .append(macroBox)\n                .append($('<span></span>')\n                        .text(\" \" + data.name)\n                       )\n                .append(priority)\n               )\n        .appendTo(row);\n\n    var timeFrac = $('<span></span>', { \"class\": \"time-fraction\" })\n        .text(\".\" + data[\"start-time-frac\"]);\n\n    var beatFrac = $('<span></span>', { \"class\": \"time-fraction\" })\n        .text(\".\" + data[\"start-beat-frac\"]);\n\n    $('<td></td>', { style: \"text-align: right\" })\n        .text(data[\"start-time\"])\n        .append(buildFraction(data[\"start-time-frac\"]))\n        .append(\"<br>\")\n        .append(data[\"start-beat\"])\n        .append(buildFraction(data[\"start-beat-frac\"]))\n        .appendTo(row);\n\n    var endCell = $('<td></td>');\n    $('<button/>', { type: \"button\", id: \"effect-\" + data.id + \"-end\", \"class\": \"btn btn-sm btn-warning\" })\n        .text(\"End\")\n        .click(function ( eventObject ) {\n            var jqxhr = $.post( (context + \"/ui-event/\" + page_id + \"/end-effect\"),\n                                { \"effect-id\": data.id,\n                                  \"key\": data.key,\n                                  \"__anti-forgery-token\": csrf_token } )\n                .fail(function() {\n                    console.log(\"Problem ending effect with id \" + data.id + \".\");\n                });\n        })\n        .appendTo(endCell);\n    endCell.appendTo(row);\n\n    // Space for cue variables, if any\n    $('<td>')\n        .append($('<table>', { id: \"effect-\" + data.id + \"-vars\", \"class\": \"effect-var-table\"}))\n        .appendTo(row);\n\n    $('<td></td>')\n        .append($('<button/>', { type: \"button\", id: \"effect-\" + data.id + \"-save\", \"class\": \"btn btn-sm btn-success\",\n                                 style: \"display: none\" })\n                .text(\"Save\")\n                .click(function ( eventObject ) {\n                    var jqxhr = $.post( (context + \"/ui-event/\" + page_id + \"/save-effect\"),\n                                        { \"effect-id\": data.id,\n                                          \"effect-key\": data.key,\n                                          \"__anti-forgery-token\": csrf_token } )\n                        .fail(function() {\n                            console.log(\"Problem saving effect with id \" + data.id + \".\");\n                        });\n                })\n               )\n        .append($('<button/>', { type: \"button\", id: \"effect-\" + data.id + \"-clear\", \"class\": \"btn btn-sm btn-default\",\n                                 style: \"display: none\" })\n                .text(\"Clear\")\n                .click(function ( eventObject ) {\n                    var jqxhr = $.post( (context + \"/ui-event/\" + page_id + \"/clear-effect\"),\n                                        { \"effect-id\": data.id,\n                                          \"effect-key\": data.key,\n                                          \"__anti-forgery-token\": csrf_token } )\n                        .fail(function() {\n                            console.log(\"Problem saving effect with id \" + data.id + \".\");\n                        });\n                })\n               )\n        .appendTo(row);\n\n    return row;\n}\n\nvar cueSlidersBeingDragged = { };\nvar cuePickersSentValues = { };\n\nfunction sendCueVarUpdate( effectKey, id, varKey, value ) {\n    //console.log(\"setting effectKey \" + effectKey + \" (id \" + id + \") varKey \" + varKey + \" to \" + value);\n    var jqxhr = $.post( (context + \"/ui-event/\" + page_id + \"/set-cue-var\"),\n                        { \"effect-key\": effectKey,\n                          \"effect-id\": id,\n                          \"var-key\": varKey,\n                          \"value\": value,\n                          \"__anti-forgery-token\": csrf_token } )\n        .fail(function() {\n            console.log(\"Problem setting cue variable for effect with id \" + id + \".\");\n        });\n}\n\nfunction createCueVarRow( data, varSpec, element ) {\n    var body = $('#effect-' + data.id + '-vars');\n    var cueVarRow = $('<tr></tr>')\n        .append($('<td></td>', { style: \"text-align: right\" })\n                .text(varSpec.name)\n                .append(\"&nbsp;\")\n               )\n        .append($('<td></td>')\n                .append(element)\n               );\n\n    body.append(cueVarRow);\n}\n\nfunction findOrCreateCueVarSlider( data, varSpec ) {\n    var idBase = 'cue-var-' + data.id + '-' + varSpec.key;\n    var sliderId = idBase + '-slider';\n    var valueId = idBase + '-value';\n    var result = $('#' + sliderId);\n    if (result.length < 1) {\n        var sliderProps = { value: data.value,\n                            min: varSpec.min,\n                            max: varSpec.max,\n                            handle: \"triangle\",\n                            tooltip: \"hide\" };\n        if (varSpec.resolution) {\n            sliderProps.step = resolution;\n        } else if (varSpec.type != \"integer\") {\n            var range =  varSpec.max - varSpec.min;\n            if (range < 200) {\n                sliderProps.step = range / 200;\n            }\n        }\n\n        var sliderSpan = $('<span></span>');\n        var sliderInput = $(\"<input>\", { id: sliderId });\n        sliderSpan.append(sliderInput);\n        var valueSpan = $('<span></span>', { id: valueId });\n        sliderSpan.append(valueSpan);\n        createCueVarRow(data, varSpec, sliderSpan);\n        sliderInput.slider(sliderProps)\n            .on(\"slideStart\", function( e ) {\n                cueSlidersBeingDragged[sliderId] = true;\n                sendCueVarUpdate(data.effect, data.id, varSpec.key, this.value);\n            })\n            .on(\"slide\", function ( e ) {\n                sendCueVarUpdate(data.effect, data.id, varSpec.key, this.value);\n            })\n            .on(\"slideStop\", function ( e ) {\n                sendCueVarUpdate(data.effect, data.id, varSpec.key, this.value);\n                delete cueSlidersBeingDragged[sliderId];\n            });\n\n        result = $('#' + sliderId);\n    }\n    return result;\n}\n\nfunction findOrCreateCheckbox (data, varSpec ) {\n    var idBase = 'cue-var-' + data.id + '-' + varSpec.key;\n    var boxId = idBase + '-checkbox';\n    var result = $('#' + boxId);\n    if (result.length < 1) {\n        var switchProps = { state: data.value,\n                            size: \"mini\",\n                            onText: \"Yes\",\n                            offText: \"No\",\n                            onSwitchChange: function ( e, state ) {\n                                sendCueVarUpdate(data.effect, data.id, varSpec.key, state);\n                            }};\n        var box = $('<input>', { id: boxId,\n                                 type: \"checkbox\",\n                                 value: data.value });\n        createCueVarRow(data, varSpec, box);\n\n        result = $('#' + boxId);\n        result.bootstrapSwitch(switchProps);\n        result = $('#' + boxId);\n    }\n    return result;\n}\n\nfunction findOrCreateColorPicker( data, varSpec ) {\n    var idBase = 'cue-var-' + data.id + '-' + varSpec.key;\n    var pickerId = idBase + '-slider';\n    var result = $('#' + pickerId);\n    if (result.length < 1) {\n        var pickerProps = {  };\n\n        var pickerInput = $('<input>', { id: pickerId,\n                                         type: \"hidden\",\n                                         value: data.value });\n        cuePickersSentValues[pickerId] = data.value;\n        createCueVarRow(data, varSpec, pickerInput);\n        pickerInput.minicolors({ changeDelay: 33,\n                                 position: \"top right\",\n                                 change: function( value, opacity ) {\n                                     if (cuePickersSentValues[pickerId] != value) {\n                                         cuePickersSentValues[pickerId] = value;\n                                         sendCueVarUpdate(data.effect, data.id, varSpec.key, value);\n                                     }\n                                 }});\n\n        result = $('#' + pickerId);\n    }\n    return result;\n}\n\nfunction processCueVarChange( data ) {\n\n    //console.log(data);\n    var varSpec = data[\"var\"];\n\n    switch (varSpec.type) {\n\n    case \"color\":\n        var colorPicker = findOrCreateColorPicker(data, varSpec);\n        if (data.value != cuePickersSentValues[colorPicker.attr(\"id\")]) {\n            cuePickersSentValues[colorPicker.attr(\"id\")] = data.value;\n            colorPicker.minicolors('value', data.value);\n        }\n        break;\n\n    case \"boolean\":\n        var checkbox = findOrCreateCheckbox(data, varSpec);\n        $(checkbox).bootstrapSwitch('state', data.value);\n        break;\n\n    default:  // Integer or float\n        var varSlider = findOrCreateCueVarSlider(data, varSpec);\n        if (!cueSlidersBeingDragged[varSlider.attr(\"id\")]) {\n            varSlider.slider('setValue', Number(data.value));\n        }\n        $('#cue-var-' + data.id + '-' + varSpec.key + '-value').text(' ' + varSlider.slider('getValue'));\n        break;\n    }\n}\n\nfunction processEffectUpdate( data ) {\n    $.each( data, function( key, val ) {\n\n        switch (key) {\n\n        case \"ending\":\n            $(\"#effect-\" + val).addClass(\"warning\");\n            $(\"#effect-\" + val + \"-end\").removeClass(\"btn-warning\").addClass(\"btn-danger\").text(\"Kill\");\n            break;\n\n        case \"ended\":\n            $(\"#effect-\" + val).remove();\n            break;\n\n        case \"started\":\n            if (val.after > 0) {\n                $(\"#effect-\" + val.after).after(buildEffectRow(val));\n            } else {\n                $(\"#effects-table > tbody\").prepend(buildEffectRow(val));\n            }\n            if (!makingMacro) {\n                $(\".macro-checkbox\").hide();\n            }\n            break;\n\n        case \"cue-var-change\":\n            processCueVarChange(val);\n            break;\n\n        case \"add-save-button\":\n            $(\"#effect-\" + val + \"-save\").show();\n            break;\n\n        case \"add-clear-button\":\n            $(\"#effect-\" + val + \"-clear\").show();\n            break;\n\n        case \"remove-save-button\":\n            $(\"#effect-\" + val + \"-save\").hide();\n            break;\n\n        case \"remove-clear-button\":\n            $(\"#effect-\" + val + \"-clear\").hide();\n            break;\n        }\n    });\n}\n\nfunction updateEffectList( data ) {\n    $.each( data, function( key, val ) {\n        processEffectUpdate(val);\n    });\n    updateEffectState();\n}\n\nvar grandMasterSliderBeingDragged = false;\n\nfunction updateGrandMaster( data ) {\n    if (!grandMasterSliderBeingDragged) {\n        $(\"#grand-master-slider\").slider(\"setValue\", Number(data));\n    }\n}\n\nfunction grandMasterSlideStart( eventObject ) {\n    grandMasterSliderBeingDragged = true;\n}\n\nfunction sendGrandMasterUpdate( control_id, value ) {\n    var jqxhr = $.post( (context + \"/ui-event/\" + page_id + \"/\" + control_id),\n                        { \"value\": value,\n                          \"__anti-forgery-token\": csrf_token } ).fail(function() {\n                              console.log(\"Problem specifying updated Grand Master value.\");\n                          });\n}\n\nfunction grandMasterSlide( eventObject ) {\n    sendGrandMasterUpdate(this.id, this.value);\n}\n\nfunction grandMasterSlideStop( eventObject ) {\n    grandMasterSliderBeingDragged = false;\n    sendGrandMasterUpdate(this.id, this.value);\n}\n\nfunction updateButtons( data ) {\n    $.each( data, function( key, val ) {\n        $('#' + val.id).prop('disabled', val.disabled);\n    });\n}\n\nvar bpmSliderBeingDragged = false;\nvar bpmSyncMode = \"\";\nvar shifted = false;\n\nfunction updateTapLabel( ) {\n    switch (bpmSyncMode) {\n\n    case \"bpm\":\n        $(\"#tap-tempo\").text(shifted ? \"Tap Bar\" : \"Tap Beat\");\n        break;\n\n    case \"beat\":\n        $(\"#tap-tempo\").text(shifted ? \"Tap Phrase\" : \"Tap Bar\");\n        break;\n\n    case \"bar\":\n        $(\"#tap-tempo\").text(\"Tap Phrase\");\n        break;\n\n    default:\n        $(\"#tap-tempo\").text(shifted ? \"Tap Bar\" : \"Tap Tempo\");\n    }\n}\n\nfunction updateMetronome( data ) {\n    $.each( data, function( key, val ) {\n        switch (val.id) {\n        case \"phrase\":\n        case \"beat\":\n        case \"bar\":\n            $(\"#\" + val.id).html(val.val);\n            break;\n\n        case \"bpm\":\n            $(\"#bpm\").html(val.val);\n            if (!bpmSliderBeingDragged) {\n                $(\"#bpm-slider\").slider(\"setValue\", Number(val.val));\n            }\n            break;\n\n        case \"blink\":\n            if (val.val) {\n                $('#tap-tempo').addClass('metronome-blink');\n            } else {\n                $('#tap-tempo').removeClass('metronome-blink');\n            }\n            break;\n\n        case \"sync\":\n            bpmSyncMode = val.val.level;\n            if (bpmSyncMode) {\n                $(\"#slider-in-bpm\").fadeOut();\n                $(\"#sync-button\").removeClass('btn-primary');\n                if (val.val.current) {\n                    $(\"#sync-button\").removeClass('btn-danger');\n                    $(\"#sync-button\").addClass('btn-success');\n                } else {\n                    $(\"#sync-button\").addClass('btn-danger');\n                    $(\"#sync-button\").removeClass('btn-success');\n                }\n            } else {\n                $(\"#slider-in-bpm\").fadeIn();\n                $(\"#sync-button\").addClass('btn-primary');\n                $(\"#sync-button\").removeClass('btn-danger');\n                $(\"#sync-button\").removeClass('btn-success');\n            }\n            updateTapLabel();\n            break;\n        }\n    });\n}\n\nfunction updateLinkMenu( data ) {\n    $('#link-section').html(data);\n    if ($(\"#link-select option\").length > 1) {\n        $(\"#link-section\").fadeIn();\n    } else {\n        $(\"#link-section\").fadeOut();\n    }\n    $(\"#link-select\").change(linkMenuChanged);\n}\n\nvar syncSave = \"\";\n\nfunction updateSyncMenu( data ) {\n    syncSave = data;\n    $('#sync-menu').html(data);\n}\n\nfunction updateLoad( data ) {\n    var canvas = $(\"#loadBar\")[0];\n    if (canvas.getContext) {\n        var ctx = canvas.getContext(\"2d\");\n        ctx.fillStyle = \"rgb(136,136,136)\";\n        ctx.fillRect(0,0,100,14);\n        var red = 0;\n        var green = 255;\n        var width = data * 100;\n        if (data > 0.5) {\n            red = (data - 0.5) * 512;\n            if (red > 255) {\n                red = 255;\n            }\n            green = 255 + ((0.5 - data) * 512);\n            if (green < 0) {\n                green = 0;\n            }\n        }\n        if (width > 100) {\n            width = 100;\n        }\n        ctx.fillStyle = \"rgb(\" + (red|0) + \",\" + (green|0) + \",0)\";\n        ctx.fillRect(0,0,width,14);\n    }\n}\n\nfunction updateStatus( data ) {\n    if (data.error) {\n        $('#status').html(\"Error \").removeClass('text-success').addClass('text-danger').removeClass('text-warning');\n        $('#errorDetailsButton').show();\n        $('#errorDescription').html(data.error.description);\n        $('#errorCause').html(data.error.cause);\n    } else {\n        $('#status').removeClass('text-danger');\n        $('#errorDetailsButton').hide();\n    }\n    if (data.running) {\n        $('#stopButton').show();\n        $('#startButton').hide();\n        if (!data.error) {\n            $('#status').html(\"Running \").addClass('text-success').removeClass('text-warning');\n        }\n    } else {\n        updateLoad(0);\n        $('#stopButton').hide();\n        $('#startButton').show();\n        if (!data.error) {\n            $('#status').html(\"Stopped \").removeClass('text-success').addClass('text-warning');\n        }\n    }\n}\n\nfunction updateShow() {\n    try {\n        var jqxhr = $.getJSON( (context + \"/ui-updates/\" + page_id), function( data ) {\n            $.each( data, function( key, val ) {\n                switch (key) {\n                case \"grid-changes\":\n                    updateCueGrid(val);\n                    break;\n\n                case \"effect-changes\":\n                    updateEffectList(val);\n                    break;\n\n                case \"grand-master\":\n                    updateGrandMaster(val);\n                    break;\n\n                case \"button-changes\":\n                    updateButtons(val);\n                    break;\n\n                case \"link-menu-changes\":\n                    updateLinkMenu(val);\n                    break;\n\n                case \"sync-menu-changes\":\n                    updateSyncMenu(val);\n                    break;\n\n                case \"metronome-changes\":\n                    updateMetronome(val);\n                    break;\n\n                case \"load-level\":\n                    updateLoad(val);\n                    break;\n\n                case \"show-status\":\n                    updateStatus(val);\n                    break;\n\n                case \"reload\":\n                    console.log(\"Reloading page since Afterglow does not recognize our page ID.\");\n                    location.reload(true);\n                    break;\n\n                default:\n                    console.log(\"Unknown show update response:\" + key + \":\" + val);\n                }\n            });\n            setTimeout(updateShow, 50);  // Try again quickly after success\n        }).fail(function() {\n            console.log(\"Problem updating show interface, waiting for a few seconds to try again.\");\n            setTimeout(updateShow, 3000);\n        });\n    }\n    catch(e) {\n        console.log(\"Exception while updating show interface, waiting a second to try again.\");\n        console.log(e);\n        setTimeout(updateShow, 1000);\n    }\n}\n\nfunction uiButtonClicked( eventObject ) {\n    var jqxhr = $.post( (context + \"/ui-event/\" + page_id + \"/\" + this.id),\n                        { \"__anti-forgery-token\": csrf_token,\n                          \"shift\": eventObject.shiftKey } ).fail(function() {\n        console.log(\"Problem reporting UI button press.\");\n    });\n}\n\nfunction errorDetailsClicked( eventObject ) {\n    $(\"#errorDetailsModal\").modal('show');\n}\n\nfunction metronomeAdjustClicked( eventObject ) {\n    var jqxhr = $.post( (context + \"/ui-event/\" + page_id + \"/\" + this.id),\n                        { \"__anti-forgery-token\": csrf_token,\n                          \"shift\": eventObject.shiftKey } ).fail(function() {\n        console.log(\"Problem requesting metronome adjustment.\");\n    });\n}\n\nvar $doc = $(document);\n\nfunction cueCellClicked( eventObject ) {\n    if (eventObject.which != 1) {\n        return;  // Only respond to ordinary, left-button clicks.\n    }\n    var cell = this.id;\n    var props = { \"shift\": eventObject.shiftKey };\n    if (makingMacro) {\n        var selectedEffects = [];\n        var selectedBoxes = $(\".macro-checkbox:checked\");\n        for (var i = 0; i < selectedBoxes.length; i++) {\n            var elems = selectedBoxes[i].id.split(\"-\");\n            selectedEffects = selectedEffects.concat([{x: parseInt(elems[2]), y: parseInt(elems[3]),\n                                                       id: parseInt(elems[4])}]);\n        }\n        $.extend(props, { macroName: $(\"#macroName\").val(),\n                          macroEffects: selectedEffects\n                        });\n    }\n    var jqxhr = $.ajax({\n        url: (context + \"/ui-event/\" + page_id + \"/\" + cell),\n        headers: { 'X-CSRF-Token': csrf_token },\n        type: 'POST',\n        contentType: 'application/json',\n        data: $.toJSON(props),\n        success: function(data) {\n            //console.log(data);\n            if ('error' in data) {\n              alert(\"Problem creating macro: \" + data['error']);\n            }\n            if ('macro-created' in data) {\n                if (makingMacro) {\n                    makeMacroChosen(null);\n                }\n            }\n            if ('holding' in data) {\n                var id = data['holding']['id'];\n                var x = data['holding']['x'];\n                var y = data['holding']['y'];\n                $doc.mouseup(function() {\n                    var jqxhr2 = $.post( (context + \"/ui-event/\" + page_id +\n                                          \"/release-\" + x + \"-\" + y + \"-\" + id),\n                                         { \"__anti-forgery-token\": csrf_token } ).fail(function() {\n                                             console.log(\"Problem reporting held cue release.\");\n                                         });\n                    $doc.unbind('mouseup');\n                });\n            }\n        },\n        error: function() {\n            console.log(\"Problem requesting cue toggle.\");\n        }\n    });\n}\n\nfunction deleteCue( cell ) {\n    var jqxhr = $.ajax({\n        url: (context + \"/ui-event/\" + page_id + \"/delete-\" + cell.attr('id')),\n        headers: { 'X-CSRF-Token': csrf_token },\n        type: 'POST',\n        success: function(data) {\n            //console.log(data);\n        },\n        error: function() {\n            console.log(\"Problem requesting cue deletion.\");\n        }\n    });\n}\n\nfunction linkMenuChanged( eventObject ) {\n    var jqxhr = $.post( (context + \"/ui-event/\" + page_id + \"/\" + this.id),\n                        { \"value\": this.value,\n                          \"__anti-forgery-token\": csrf_token } ).fail(function() {\n        console.log(\"Problem requesting linked controller change.\");\n    });\n}\n\nfunction syncMenuChosen( eventObject ) {\n    var syncValue = $('#sync-menu input:radio:checked').val()\n    if (syncValue) {\n        var jqxhr = $.post( (context + \"/ui-event/\" + page_id + \"/\" + this.id),\n                            { \"value\": syncValue,\n                              \"__anti-forgery-token\": csrf_token } ).fail(function() {\n                                  console.log(\"Problem requesting metronome sync change.\");\n                              });\n    }\n}\n\nfunction makeMacroChosen (eventObject) {\n    if (makingMacro) {\n        $(\".macro-definition\").hide();\n        $(\".macro-checkbox\").hide();\n        $(\"#makeMacro\").text(\"Make Macro\").addClass('btn-default').removeClass('btn-danger');\n        makingMacro = false;\n    } else {\n        $(\".macro-definition\").show();\n        $(\".macro-checkbox\").attr('checked', false);\n        $(\".macro-checkbox\").show();\n        $(\"#makeMacro\").text(\"Cancel\").removeClass('btn-default').addClass('btn-danger');\n        $(\"#macroName\").val(\"Macro \" + macroCounter).focus().select();\n        ++macroCounter;\n        makingMacro = true\n    }\n}\n\nfunction bpmSlideStart( eventObject ) {\n    bpmSliderBeingDragged = true;\n}\n\nfunction sendBpmUpdate( control_id, value ) {\n    var jqxhr = $.post( (context + \"/ui-event/\" + page_id + \"/\" + control_id),\n                        { \"value\": value,\n                          \"__anti-forgery-token\": csrf_token } ).fail(function() {\n                              console.log(\"Problem specifying updated BPM value.\");\n                          });\n}\n\nfunction bpmSlide( eventObject ) {\n    sendBpmUpdate(this.id, this.value);\n}\n\nfunction bpmSlideStop( eventObject ) {\n    bpmSliderBeingDragged = false;\n    sendBpmUpdate(this.id, this.value);\n}\n\nfunction decorateMetronomeAdjusters( selector, onMouseDown ) {\n    if (onMouseDown) {\n        $(selector).mousedown(metronomeAdjustClicked);\n    } else {\n        $(selector).click(metronomeAdjustClicked);\n    }\n    $(selector).hover(\n        function() {\n            $(this).addClass('metronome-active');\n        },\n        function() {\n            $(this).removeClass('metronome-active');\n        }\n    );\n}\n\nfunction checkShiftKey( eventObject ) {\n    if (shifted != eventObject.shiftKey) {\n        shifted = eventObject.shiftKey;\n        updateTapLabel();\n    }\n}\n\nvar cueCellMenu;\n\nfunction fakeScrollClick ( direction, eventObject ) {\n    if (!$('#cues-' + direction).attr(\"disabled\")) {\n        var jqxhr = $.post( (context + \"/ui-event/\" + page_id + \"/cues-\" + direction),\n                            { \"__anti-forgery-token\": csrf_token,\n                              \"shift\": eventObject.shiftKey } ).fail(function() {\n                                console.log(\"Problem reporting UI button press.\");\n                            });\n    }\n}\n\nfunction fakeTempoTap( eventObject ) {\n    var jqxhr = $.post( (context + \"/ui-event/\" + page_id + \"/tap-tempo\"),\n                        { \"__anti-forgery-token\": csrf_token,\n                          \"shift\": eventObject.shiftKey } ).fail(function() {\n        console.log(\"Problem requesting metronome adjustment.\");\n    });\n}\n\n$( document ).ready(function() {\n    $(\"#startButton\").click(uiButtonClicked);\n    $(\"#stopButton\").click(uiButtonClicked);\n    $(\"#errorDetailsButton\").click(errorDetailsClicked);\n    $(\".grid-scroll-button\").click(uiButtonClicked);\n    decorateMetronomeAdjusters(\".metronome-tap-target\", true);\n    decorateMetronomeAdjusters(\".metronome-adjust-target\", false);\n    decorateMetronomeAdjusters(\".metronome-reset-target\", false);\n    $(\".cue-cell\").mousedown(cueCellClicked);\n    if ($(\"#link-select option\").length > 1) {\n        $(\"#link-section\").fadeIn();\n    }\n    $(\"#link-select\").change(linkMenuChanged);\n    $(\"#choose-sync\").click(syncMenuChosen);\n    $(\"#syncModal\").on(\"show.bs.modal\", function(event) {\n        syncSave = $(\"#sync-menu\").html();\n    });\n    $(\"#syncModal\").on(\"hidden.bs.modal\", function(event) {\n        if (syncSave) {\n            $(\"#sync-menu\").html(syncSave);\n        }\n    });\n    $(\"#makeMacro\").click(makeMacroChosen);\n    $(\".macro-definition\").hide();\n\n    // Set up to keep track of the shift key and update the tap tempo label accordingly\n    $( document ).on(\"keyup keydown\", function(e) {\n        checkShiftKey(e);\n        return true;\n    });\n    $( window ).on(\"focusin\", function(e) {\n        checkShiftKey(e);\n        return true;\n    });\n\n    // See https://github.com/seiyria/bootstrap-slider\n    $(\"#bpm-slider\").slider({id: \"slider-in-bpm\"})\n        .on(\"slideStart\", bpmSlideStart)\n        .on(\"slide\", bpmSlide)\n        .on(\"slideStop\", bpmSlideStop);\n    $(\"#grand-master-slider\").slider({ id: \"slider-in-grand-master\",\n                                       min: 0,\n                                       max: 100,\n                                       step: 0.1,\n                                       handle: \"triangle\",\n                                       tooltip: \"show\",\n                                       tooltip_position: \"bottom\" })\n        .on(\"slideStart\", grandMasterSlideStart)\n        .on(\"slide\", grandMasterSlide)\n        .on(\"slideStop\", grandMasterSlideStop);\n\n    cueCellMenu = new BootstrapMenu('.cue-cell', {\n        fetchElementData: function($rowElem) {\n            return $rowElem;\n        },\n        actions: {\n            /*\n            renameCue: {\n                name: 'Rename',\n                iconClass: 'fa-pencil',\n                onClick: function(row) { console.log($(row).text()); },\n                isEnabled: function(row) { return !!$(row).text().trim(); }\n            },\n            */\n            deleteCue: {\n                name: 'Delete',\n                iconClass: 'fa-trash-o',\n                onClick: function(row) { deleteCue($(row)); },\n                isEnabled: function(row) { return !!$(row).text().trim(); }\n            }\n        }\n    });\n\n    // Respond to arrow keys when nothing is focused by acting as if the scroll buttons had been\n    // pressed.\n    $('html').keydown(function(e){\n        // console.log(\"got keydown \" + e.which + \" for \" + $(':focus').prop(\"tagName\"));\n        if (!$(':focus').prop(\"tagName\")) {\n            switch (e.which) {\n\n            case 38:\n                fakeScrollClick(\"up\", e);\n                e.preventDefault();\n                break;\n\n            case 40:\n                fakeScrollClick(\"down\", e);\n                e.preventDefault();\n                break;\n\n            case 39:\n                fakeScrollClick(\"right\", e);\n                e.preventDefault();\n                break;\n\n            case 37:\n                fakeScrollClick(\"left\", e);\n                e.preventDefault();\n                break;\n\n            case 32:\n                fakeTempoTap(e);\n                e.preventDefault();\n                break;\n\n            default:\n            }\n        }\n    });\n    // Render the current effect state, and start the thread which updates the show state.\n    updateEffectState();\n    updateShow();\n});\n"
  },
  {
    "path": "resources/public/js/web-repl.js",
    "content": "function sendCommand(line) {\n    var jqxhr = $.post( (context + \"/console\"),\n                        { \"command\": line,\n                          \"__anti-forgery-token\": csrf_token }, function (data) {\n                              $.each( data, function( key, val ) {\n                                  switch (key) {\n                                  case \"result\":\n                                      currentCallback([{msg: val,\n                                                        className: \"jquery-console-message-value\"}]);\n                                      break;\n\n                                  default:\n                                      currentCallback([{msg: val,\n                                                        className: \"jquery-console-message-error\"}]);\n                                  }\n                              });\n                          }, \"json\").fail(function() {\n                              currentCallback([\n                                  {msg: \"Problem communicating with Afterglow Web REPL.\",\n                                   className: \"jquery-console-message-error\"}\n                              ]);\n                          });\n}\n\nfunction updateSize() {\n    $('#console').css({ height: $(window).height() - 100 });\n    $('.jquery-console-inner').css({ height: $(window).height() - 120 });\n}\n\n$(document).ready(function () {\n    updateSize();\n    $(window).resize(updateSize);\n    $(\"#console\").console({\n        promptLabel: 'Afterglow> ',\n        commandValidate:function(line) {\n            if (line == \"\") {\n                return false;\n            }\n            else {\n                return true;\n            }\n        },\n        commandHandle:function(line, callback) {\n            currentCallback = callback;\n            sendCommand(line);\n        },\n        welcomeMessage:'Enter Clojure code, and it will be evaluated within Afterglow.',\n        autofocus:true,\n        animateScroll:true,\n        promptHistory:true\n    });\n});\n"
  },
  {
    "path": "resources/public/shaders/vertex.glsl",
    "content": "// switch on high precision floats\n#ifdef GL_ES\nprecision highp float;\n#endif\n\nvoid main()\n{\n  vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);\n  gl_Position = projectionMatrix * mvPosition;\n}\n\n"
  },
  {
    "path": "resources/templates/about.html",
    "content": "{% extends \"base.html\" %}\n{% block content %}\n  <p>To  be filled in, or removed. The embedded user guide is coming first.</p>\n{% endblock %}\n"
  },
  {
    "path": "resources/templates/base.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n    <title>{{title|default:\"Afterglow\"}}</title>\n    <link rel=\"icon\" type=\"image/png\" href=\"/img/Afterglow-icon.png\">\n  </head>\n  <body>\n    <!-- navbar -->\n    <div class=\"navbar navbar-inverse navbar-fixed-top\">\n      <div class=\"container\">\n        <div class=\"navbar-header\">\n          <span class=\"navbar-brand\">{{title|default:\"Afterglow\"}}</span>\n        </div>\n        <div class=\"navbar-collapse collapse \">\n          <ul class=\"nav navbar-nav\">\n            <li{% ifequal page \"home.html\" %} class=\"active\"{% endifequal %}>\n              <a href=\"{{servlet-context}}/\">Home</a>\n            </li>{% ifunequal page \"show.html\" %}\n            <li {% ifequal page \"console.html\" %} class=\"active\"{% endifequal %}>\n              <a href=\"{{servlet-context}}/console\">Console</a>\n            </li>\n            {% if show %}<li {% ifequal page \"visualizer.html\" %} class=\"active\"{% endifequal %}>\n              <a href=\"{{servlet-context}}/visualizer/{{show.id}}\">Visualizer</a>\n            </li>{% endif %}\n            <li>\n              <a href=\"{{servlet-context}}/guide\" target=\"_blank\">Guide</a>\n            </li>\n            <li>\n              <a href=\"{{servlet-context}}/api-doc\" target=\"_blank\">API</a>\n            </li>\n            <li {% ifequal page \"about.html\" %} class=\"active\"{% endifequal %}>\n              <a href=\"{{servlet-context}}/about\">About</a>\n            </li>{% endifunequal %}\n            {% block page-nav-items %}\n            {% endblock %}\n          </ul>\n        </div>\n      </div>\n    </div>\n\n    <div class=\"container\">\n      {% block content %}\n      {% endblock %}\n    </div>\n    <!-- scripts and styles -->\n    {% style \"/css/bootstrap-cyborg.min.css\" %}\n    {% style \"/css/screen.css\" %}\n\n    {% script \"/js/jquery-2.1.4.min.js\" %}\n    {% script \"/js/bootstrap.min.js\" %}\n\n    <script type=\"text/javascript\">\n      var context = \"{{servlet-context}}\";\n      var csrf_token = \"{{csrf-token}}\";\n    </script>\n    {% block page-scripts %}\n    {% endblock %}\n  </body>\n</html>\n"
  },
  {
    "path": "resources/templates/console.html",
    "content": "{% extends \"base.html\" %}\n{% block content %}\n<div class=\"row\" id=\"console\"/>\n{% endblock %}\n{% block page-scripts %}\n    {% style \"/css/web-repl.css\" %}\n    {% script \"/js/jquery.console.js\" %}\n    {% script \"/js/web-repl.js\" %}\n{% endblock %}  \n"
  },
  {
    "path": "resources/templates/cue_grid.html",
    "content": "{% for row in grid %}\n      <tr>{% for cue in row %}\n        <td class=\"cue-cell\" id=\"{{cue.id}}\" {{cue.style-color|safe}}>{{ cue.name }}</td>{% endfor %}\n      </tr>{% endfor %}\n"
  },
  {
    "path": "resources/templates/current-scene-fragment.js",
    "content": "      iNumSpots:   { type: 'i', value: {{ count }} },\n      iSpotPosition: { type: 'v3v', value: [ \n        {% for pos in positions %}new THREE.Vector3({%\n           for val in pos %}{{val}}{% if not forloop.last %}, {% endif %}{% endfor %}){% if not forloop.last %},\n        {% endif %}{% endfor %} ] },\n      iSpotRotation: { type: 'v2v', value: [ \n        {% for rot in rotations %}new THREE.Vector2({%\n           for val in rot %}{{val}}{% if not forloop.last %}, {% endif %}{% endfor %}){% if not forloop.last %},\n        {% endif %}{% endfor %} ] },\n      iSpotColor: { type: 'v4v', value: [ \n        {% for col in colors %}new THREE.Vector4({%\n           for val in col %}{{val}}{% if not forloop.last %}, {% endif %}{% endfor %}){% if not forloop.last %},\n        {% endif %}{% endfor %} ] },\n"
  },
  {
    "path": "resources/templates/current-scene.json",
    "content": "{\n    timestamp: {{ timestamp }},\n{% include \"current-scene-fragment.js\" %}\n}\n"
  },
  {
    "path": "resources/templates/error.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>Something bad happened</title>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css\">\n    <link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap-theme.min.css\">\n    <style type=\"text/css\">\n        html {\n            height: 100%;\n            min-height: 100%;\n            min-width: 100%;\n            overflow: hidden;\n            width: 100%;\n        }\n        html body {\n            height: 100%;\n            margin: 0;\n            padding: 0;\n            width: 100%;\n        }\n        html .container-fluid {\n            display: table;\n            height: 100%;\n            padding: 0;\n            width: 100%;\n        }\n        html .row-fluid {\n            display: table-cell;\n            height: 100%;\n            vertical-align: middle;\n        }\n    </style>\n</head>\n<body>\n<div class=\"container-fluid\">\n    <div class=\"row-fluid\">\n        <div class=\"col-lg-12\">\n            <div class=\"centering text-center\">\n                <div class=\"text-center\">\n                    <h1><span class=\"text-danger\">Error: 500</span></h1>\n                    <hr>\n                    <h2 class=\"without-margin\">Something very bad has happened!</h2>\n                    <h4 class=\"text-danger\">We've dispatched a team of highly trained gnomes to take care of the problem.</h4>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "resources/templates/fixture-definition.clj.template",
    "content": "(ns afterglow.fixtures.{{manufacturer|sanitize}}\n  \"Translated definition for the fixture {{model}}\n  from {{manufacturer}}.\n\n  This was created by Afterglow from the QLC+ Fixture Definintion\n  (.qxf) file, and will almost certainly need some manual adjustment\n  in order to enable full Afterglow capabilities.{% if has-pan-tilt %} For example, this\n  fixture has pan/tilt channels, so you need to configure the scaling\n  parameters (marked with TODO below), as described in Afterglow's\n  Fixture Definitions documentation:\n  https://github.com/Deep-Symmetry/afterglow/blob/master/doc/fixture_definitions.adoc#fixture-definitions{% endif %}\n\n  If you have more than one fixture definition for this manufacturer,\n  you can consolidate them into a single file if you like, with a\n  single copy of this namespace definition, since it is the same for\n  all fixture definitions translated by Afterglow.\n\n  Once you have completed the fixture definition, and are happy with\n  the way everything is being controlled by Afterglow, please consider\n  submitting it for inclusion with Afterglow, either as a Pull Request\n  at https://github.com/Deep-Symmetry/afterglow/pulls if you are\n  comfortable putting that together, or just on the Zulip chat if\n  that's easier for you:\n  https://deep-symmetry.zulipchat.com/#narrow/stream/318697-afterglow\n\n  The original fixture defintition was created by {{creator.author}}\n  using {{creator.name}} version {{creator.version}}.\n  QLC+ Fixture Type: {{type}}.\"\n  (:require [afterglow.channels :as chan]\n            [afterglow.effects.channel :as chan-fx]))\n\n(defn {{model|sanitize}}\n  \"{{model}}.\n\n  Please flesh out this documentation if you are submitting this for\n  inclusion into Afterglow. See, for example, the Blizzard fixture\n  definitions:\n  http://deepsymmetry.org/afterglow/api-doc/afterglow.fixtures.blizzard.html\"\n  {% if modes|length < 2 %}[]\n  {{open-curly}}{% if modes.0.has-pan-channel %}:pan-center 128 :pan-half-circle 128 ; TODO: Fix these values\n   {% endif %}{% if modes.0.has-tilt-channel %}:tilt-center 128 :tilt-half-circle 128 ; TODO: Fix these values\n   {% endif %}:channels [{% for ch in modes.0.channels %}{% if not forloop.first %}\n              {% endif %}{% channel ch %}{% endfor %}]{% if modes.0.heads|not-empty %}\n   :heads [{% for head in modes.0.heads %}{% if not forloop.first %}\n           {% endif %}{{open-curly}}{% if modes.0.heads|length > 1 %}:x 0 :y 0 :z 0 ; TODO: specify actual location! (and perhaps rotation?)\n            {% endif %}{% if head.has-pan-channel %}:pan-center 128 :pan-half-circle 128 ; TODO: Fix these values\n            {% endif %}{% if head.has-tilt-channel %}:tilt-center 128 :tilt-half-circle 128 ; TODO: Fix these values\n            {% endif %}:channels [{% for ch in head.channels %}{% if not forloop.first %}\n                              {% endif %}{% channel ch %}{% endfor %}]}{% endfor %}]{% endif %}\n   :name \"{{model}}\"}{% else %}([]\n   ({{model|sanitize}} :{{modes.0.name|sanitize}}))\n  ([mode]\n   (merge {:name \"{{model}}\"\n           :mode mode}\n          (case mode{% for m in modes %}\n                :{{m.name|sanitize}}\n                {{open-curly}}{% if m.has-pan-channel %}:pan-center 128 :pan-half-circle 128 ; TODO: Fix these values\n                 {% endif %}{% if m.has-tilt-channel %}:tilt-center 128 :tilt-half-circle 128 ; TODO: Fix these values\n                 {% endif %}:channels [{% for ch in m.channels %}{% if not forloop.first %}\n                            {% endif %}{% channel ch %}{% endfor %}]{% if m.heads|not-empty %}\n                 :heads [{% for head in m.heads %}{% if not forloop.first %}\n                         {% endif %}{{open-curly}}{% if m.heads|length > 1 %}:x 0 :y 0 :z 0 ; TODO: specify actual location! (and perhaps rotation?)\n                          {% endif %}{% if head.has-pan-channel %}:pan-center 128 :pan-half-circle 128 ; TODO: Fix these values\n                          {% endif %}{% if head.has-tilt-channel %}:tilt-center 128 :tilt-half-circle 128 ; TODO: Fix these values\n                          {% endif %}:channels [{% for ch in head.channels %}{% if not forloop.first %}\n                                     {% endif %}{% channel ch %}{% endfor %}]}{% endfor %}]{% endif %}}{% endfor %}))){% endif %})\n"
  },
  {
    "path": "resources/templates/fragment.glsl",
    "content": "#ifdef GL_ES\nprecision highp float;\n#endif\n\t\t\nconst int MAX_SPOTS = {{max-lights}};\nconst float SCALE = {{scale}};\n\nuniform float iGlobalTime;\nuniform sampler2D iChannel0;\nuniform vec3 iResolution;\nuniform int iNumSpots;\nuniform vec3 iSpotPosition[MAX_SPOTS];\nuniform vec4 iSpotColor[MAX_SPOTS];\nuniform vec2 iSpotRotation[MAX_SPOTS];\n\n\n//////\n// Utility stuff\n//////\n#define PI 3.14159265\n\nmat3 rotx(float a) {\n  mat3 rot;\n  rot[0] = vec3(1.0, 0.0, 0.0);\n  rot[1] = vec3(0.0, cos(a), -sin(a));\n  rot[2] = vec3(0.0, sin(a), cos(a));\n  return rot;\n}\n\nmat3 roty(float a) {\n  mat3 rot;\n  rot[0] = vec3(cos(a), 0.0, sin(a));\n  rot[1] = vec3(0.0, 1.0, 0.0);\n  rot[2] = vec3(-sin(a), 0.0, cos(a));\n  return rot;\n}\n\nmat3 rotz(float a) {\n  mat3 rot;\n  rot[0] = vec3(cos(a), -sin(a), 0.0);\n  rot[1] = vec3(sin(a), cos(a), 0.0);\n  rot[2] = vec3(0.0, 0.0, 1.0);\n  return rot;\n}\n\n// noise from iq's hell shader\nfloat noise(in vec3 x) {\n  vec3 p = floor(x);\n  vec3 f = fract(x);\n  f = f*f*(3.0-2.0*f);\n  \n  vec2 uv = (p.xy+vec2(37.0,17.0)*p.z) + f.xy;\n  vec2 rg = texture2D( iChannel0, (uv+ 0.5)/256.0, -100.0 ).yx;\n  return mix( rg.x, rg.y, f.z ) - 0.5;\n}\n\n///////\n// Distance function from http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm\n//////\n\nfloat sdCappedCylinder(vec3 p, vec2 h) {\n  vec2 d = abs(vec2(length(p.xz),p.y)) - h;\n  return min(max(d.x,d.y),0.0) + length(max(d,0.0));\n}\n\n///////////////////////////////\n\nconst float NOTHING = -0.1;\n\nconst float LIGHT_BASE_W = 0.1;\nconst float CONE_W = 0.11;\n\nvec2 maplight(vec3 orp, out bool spot_hit[MAX_SPOTS]) {\n  float t = iGlobalTime * 0.025;\n  float minm = 10000.0;\n  float mm = 10000.0;\n  float num_hit = 0.0;\n  \n  for (int i = 0; i < MAX_SPOTS; ++i) {\n    spot_hit[i] = false;\n    if (i < iNumSpots) {\n      vec3 rp = orp;\n      vec3 _rp = rp;\n      rp += iSpotPosition[i];\n      mat3 rotation = rotx(iSpotRotation[i].y);\n      rotation *= roty(iSpotRotation[i].x);\n      rp *= rotation;\n      \n      float m = sdCappedCylinder(rp, vec2(CONE_W, 1.0));\n      \n      float l = -LIGHT_BASE_W + length(rp) * 0.2;\n      m -= l;\n      float d = dot(rp, vec3(0.0, -1.0, 0.0));\n      \n      if( m < 0.0 && d >= 0.0) {\n        vec3 uv = _rp + vec3(t, 0.0, 0.0);\n        float n = noise(uv * 10.0) - 0.5;\n        \n        uv = _rp + vec3(t * 1.2, 0.0, 0.0);\n        n += noise(uv * 22.50) * 0.5;\n        \n        uv = _rp + vec3(t * 2.0, 0.0, 0.0);\n        n += noise(uv * 52.50) * 0.5;\n        \n        uv = _rp + vec3(t * 2.8, 0.0, 0.0);\n        n += noise(uv * 152.50) * 0.25;\n        \n        mm = min(n, m);\n        mm = min(mm, -0.2);\n        spot_hit[i] = true;\n        num_hit += 1.0; \n      }\n      minm = min(abs(m), minm);\n    }\n  }\n  \n  if(num_hit > 0.0) {\n    return vec2(mm, num_hit);\n  }\n  \n  return vec2(minm, NOTHING);\n}\n\n\nconst int MAX_STEPS = 250;\nconst float MIN_STEP = 0.0052;\nconst float FAR = 0.5;\n\nconst float LIGHT_POW = 2.5;\nconst float LIGHT_INTENS = 0.15;\nconst float FLOOR_Y = -0.25;\n\nvoid colorize(in vec4 fgc, in vec3 pos, in vec4 spotcol, inout vec4 color) {\n  float flf = inversesqrt(length(pos));\n  flf = pow(flf, LIGHT_POW) * LIGHT_INTENS;\n  color += fgc * flf * spotcol;\n}\n\nbool trace(in vec3 ro, in vec3 rd, out vec4 color) {\n  color = vec4(0.0);\n  vec3 rp = ro;\n  float h = 0.0;\n  float sg = (sin(iGlobalTime) + 1.0) * 0.25;\n  float sg2 = (sin(iGlobalTime * 0.5) + 1.0) * 0.25;\n  bool spot_hit[MAX_SPOTS];\n  \n  for (int i = 0; i < MAX_STEPS; ++i) {\n    rp += rd * max(MIN_STEP, h * 0.5);\n    vec2 hp = maplight(rp, spot_hit);\n    h = hp.x;\n    \n    if(rp.z > FAR) {\n      return false;\n    }\n    \n    if(h < 0.0) {\n      vec4 fgc = vec4(abs(h * 0.05));\n      \n      if (hp.y > NOTHING) {\n        for (int i = 0; i < MAX_SPOTS; ++i) {\n          if (spot_hit[i]) {\n            colorize(fgc, (-iSpotPosition[i] - rp), iSpotColor[i], color);\n          }\n        }\n      }\n            \n      if(rp.y < FLOOR_Y && rp.y > FLOOR_Y - 0.0017) {\n        vec4 floorColor = vec4(0.0);\n        for (int i = 0; i < MAX_SPOTS; ++i) {\n          if (spot_hit[i]) {\n            floorColor += iSpotColor[i];\n          }\n          color += vec4(0.1, 0.1, 0.1, 0.0) * floorColor;\n          return true;\n        }\n      }\n      \n      if(rp.y < FLOOR_Y) {\n        color = vec4(0.0);\n        return true;\n      }            \n    }\n  }\n  return false;\n}\n\n\nvoid main(void) {\n  vec2 uv = gl_FragCoord.xy / iResolution.xy;\n  float aspect = iResolution.x / iResolution.y;\n  \n  vec3 rd = (vec3(uv - vec2(0.5), 1.0));\n  rd.y /= aspect;\n  rd = normalize(rd);\n  trace(vec3(0.0, 0.0, -1.1), rd, gl_FragColor);\n}\n"
  },
  {
    "path": "resources/templates/home.html",
    "content": "{% extends \"base.html\" %}\n{% block content %}\n  <div class=\"jumbotron\">\n    <img style=\"float:right\" src=\"/img/Afterglow-logo-padded-left.png\">\n    <h2>Afterglow</h2>\n    <p>A lighting controller optimized for live coding.\n    <p>\n      <a class=\"btn btn-primary btn-lg\" href=\"{{servlet-context}}/console\">Open console &raquo;</a>\n      <a class=\"btn btn-primary btn-lg\" href=\"http://localhost:9090/new/\" target=\"_blank\">Open OLA &raquo;</a>\n      <a class=\"btn btn-info btn-lg\" href=\"{{servlet-context}}/guide\" target=\"_blank\">Developer Guide &raquo;</a>\n    </p>\n  </div>\n\n  <div class=\"row\">\n    <div class=\"span12\">\n      <h3>Shows</h3>\n        <div class=\"list-group\">\n          {% for show in shows %}\n          <a href=\"{{servlet-context}}/show/{{show.show.id}}\"\n             class=\"list-group-item\"><span class=\"glyphicon text-primary glyphicon-star-empty\" aria-hidden=\"true\"></span>\n            <span class=\"text-primary\">{{ show.description }}</span></a>\n          {% empty %}\n          <p class=\"text-info\">\n            <span class=\"glyphicon glyphicon-cog\" aria-hidden=\"true\"></span>\n            No shows have been registered. Use the\n            <a href=\"{{servlet-context}}/console\">console</a> to start one?\n          </p>\n          {% endfor %}\n        </ul>\n    </div>\n  </div>\n  <div class=\"row\">\n    <div class=\"span12\">\n      <br/>\n      <p class=\"text-center\">Copyright\n      &copy;2015&ndash;2019 <a href=\"http://deepsymmetry.org\">Deep Symmetry, LLC</a>.\n      Available under the\n        <a href=\"https://raw.githubusercontent.com/Deep-Symmetry/afterglow/master/LICENSE\">Eclipse\n          Public License 2.0</a>. Version: {{version}}</p>\n      <p class=\"text-center\"><img src=\"/img/Deep-Symmetry-logo.png\" width=\"200\"></p>\n    </div>\n  </div>\n{% comment %}\n  <div class=\"row\">\n    <div class=\"span12\">\n    {{docs|markdown}}\n    </div>\n  </div>\n{% endcomment %}\n{% endblock %}\n"
  },
  {
    "path": "resources/templates/link_menu.html",
    "content": "        Linked controller:<br/>\n        <select id=\"link-select\">{% for element in link-menu %}\n          <option value=\"{{element.value}}\"{% if element.selected %} selected{% endif %}>{{element.label}}</option>{% endfor %}\n        </select>\n"
  },
  {
    "path": "resources/templates/show.html",
    "content": "{% extends \"base.html\" %}\n\n{% block page-nav-items %}\n            <li class=\"navbar-text\">Load: <canvas id=\"loadBar\" width=\"100\" height=\"14\"></canvas></li>\n            <li class=\"navbar-text\">Status: <span id=\"status\"></span>&nbsp;\n              <button type=\"button\" id=\"errorDetailsButton\" class=\"btn btn-info btn-mini\" aria-label=\"Left Align\"\n                      style=\"display: none;\">\n                <span class=\"glyphicon glyphicon-info-sign\" aria-hidden=\"true\"> Details</span>\n              </button>&nbsp;\n              <button type=\"button\" id=\"stopButton\" class=\"btn btn-danger btn-mini\" aria-label=\"Left Align\"\n                      style=\"display: none;\">\n                <span class=\"glyphicon glyphicon-off\" aria-hidden=\"true\"> Stop</span>\n              </button>\n              <button type=\"button\" id= \"startButton\" class=\"btn btn-success btn-mini\" aria-label=\"Left Align\"\n                      style=\"display: none;\">\n                <span class=\"glyphicon glyphicon-off\" aria-hidden=\"true\"> Start</span>\n              </button>\n            </li>\n{% endblock %}\n\n{% block content %}\n  <div class=\"row\">\n    <div class=\"col-md-12\">\n      <table id=\"cue-grid\" class=\"table table-bordered\">{% include \"cue_grid.html\" %}\n      </table>\n    </div>\n  </div>\n  <div class=\"row\">\n    <div class=\"col-md-4\">\n      <table class=\"table metronome\">\n        <tr>\n          <th class=\"metronome\">Metronome</th>\n          <th class=\"metronome division\">BPM</th>\n          <th class=\"metronome division\">Phrase</th>\n          <th class=\"metronome division\">Bar</th>\n          <th class=\"metronome division\">Beat</th>\n        </tr>\n        <tr>\n          <td rowspan=\"2\" class=\"metronome metronome-sync\">\n            <button type=\"button\" class=\"btn btn-sm btn-default metronome-tap-target\" id=\"tap-tempo\">Tap Tempo</button>\n          </td>\n          <td class=\"metronome metronome-adjust\">\n            <span id=\"bpm-up\" class=\"glyphicon glyphicon-plus-sign metronome-adjust-target\"></span>\n          </td>\n          <td class=\"metronome metronome-reset\">\n            <span id=\"phrase-reset\" class=\"glyphicon glyphicon-remove-sign metronome-reset-target\"></span>\n          </td>\n          <td class=\"metronome metronome-adjust\">\n            <span id=\"bar-up\" class=\"glyphicon glyphicon-plus-sign metronome-adjust-target\"></span>\n          </td>\n          <td class=\"metronome metronome-adjust\">\n            <span id=\"beat-up\" class=\"glyphicon glyphicon-plus-sign metronome-adjust-target\"></span>\n          </td>\n        </tr>\n        <tr>\n          <td class=\"metronome\" id=\"bpm\">0</td>\n          <td class=\"metronome\" id=\"phrase\">0</td>\n          <td class=\"metronome\" id=\"bar\">0</td>\n          <td class=\"metronome\" id=\"beat\">0</td>\n        </tr>\n        <tr>\n          <td rowspan=\"2\" class=\"metronome metronome-sync\">\n            <a href=\"#syncModal\" role=\"button\" class=\"btn btn-sm btn-primary\"\n               id=\"sync-button\" data-toggle=\"modal\">Sync</a>\n          </td>\n          <td class=\"metronome metronome-adjust\">\n            <span id=\"bpm-down\" class=\"glyphicon glyphicon-minus-sign metronome-adjust-target\"></span>\n          </td>\n          <td class=\"metronome\">\n          </td>\n          <td class=\"metronome metronome-adjust\">\n            <span id=\"bar-down\" class=\"glyphicon glyphicon-minus-sign metronome-adjust-target\"></span>\n          </td>\n          <td class=\"metronome metronome-adjust\">\n            <span id=\"beat-down\" class=\"glyphicon glyphicon-minus-sign metronome-adjust-target\"></span>\n          </td>\n        </tr>\n        <tr>\n          <td class=\"metronome\" colspan=\"4\"><input id=\"bpm-slider\"\n                                                   data-slider-min=\"{{min-bpm}}\" data-slider-max=\"{{max-bpm}}\"\n                                                   data-slider-step=\"0.1\" data-slider-tooltip=\"hide\"></td>\n        </tr>\n      </table>\n    </div>\n    <div class=\"col-md-4\" style=\"text-align: center\">\n      <h6>Dimmer Grand Master</h6>\n      <input id=\"grand-master-slider\">\n    </div>\n    <div class=\"col-md-2\">\n      <div id=\"link-section\" style=\"display:none\">\n{% include \"link_menu.html\" %}\n      </div>\n    </div>\n    <div class=\"col-md-2\">\n      <table class=\"pull-right\">\n        <tr>\n          <td></td>\n          <td>\n            <button type=\"button\" class=\"btn btn-primary btn-sm grid-scroll-button\" id=\"cues-up\" disabled>\n              <span class=\"glyphicon glyphicon-menu-up\" aria-hidden=\"true\"></span></button>\n          </td>\n          <td></td>\n        </tr>\n        <tr>\n          <td>\n            <button type=\"button\" class=\"btn btn-primary btn-sm grid-scroll-button\" id=\"cues-left\" disabled>\n              <span class=\"glyphicon glyphicon-menu-left\" aria-hidden=\"true\"></span></button>\n          </td>\n          <td></td>\n          <td>\n            <button type=\"button\" class=\"btn btn-primary btn-sm grid-scroll-button\" id=\"cues-right\" disabled>\n              <span class=\"glyphicon glyphicon-menu-right\" aria-hidden=\"true\"></span></button>\n          </td>\n        </tr>\n        <tr>\n          <td></td>\n          <td>\n            <button type=\"button\" class=\"btn btn-primary btn-sm grid-scroll-button\" id=\"cues-down\" disabled>\n              <span class=\"glyphicon glyphicon-menu-down\" aria-hidden=\"true\"></span></button>\n          </td>\n          <td></td>\n        </tr>\n      </table>\n    </div>\n  </div>\n\n  <div class=\"row\">\n    <div class=\"col-md-12\">\n      <div id=\"no-effects\">\n        <p>No effects are active.</p>\n      </div>\n      <div id=\"some-effects\">\n        <table id=\"effects-table\" class=\"table table-striped effects\">\n          <thead>\n            <tr>\n              <th class=\"col-md-3\">Effect Name</th>\n              <th class=\"col-md-2\" style=\"text-align: right\">Started</th>\n              <th class=\"col-md-1\"></th>\n              <th class=\"col-md-5\" style=\"text-align: center\">Cue Variables</th>\n              <th class=\"col-md-1\">\n                <button class=\"btn btn-default\" style=\"visibility: hidden\">Clear</button>\n              </th>\n            </tr>\n          </thead>\n          <tbody></tbody>\n        </table>\n        <button type=\"button\" class=\"btn btn-default btn-sm\" id=\"makeMacro\">Make Macro</button>\n        <span class=\"macro-definition\">\n          &nbsp;<input type=\"text\" id=\"macroName\">&nbsp;\n          Pick a name, check the effects to include, then click an empty cue cell.\n      </div>\n    </div>\n </div>\n\n  <div id=\"syncModal\" class=\"modal fade\">\n    <div class=\"modal-dialog\">\n        <div class=\"modal-content\">\n            <div class=\"modal-header\">\n                <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-hidden=\"true\">&times;</button>\n                <h4 class=\"modal-title\">Metronome Sync</h4>\n            </div>\n            <div class=\"modal-body\" id=\"sync-menu\">\n              <div class=\"radio\">\n                <label><input type=\"radio\" name=\"sync\" value=\"manual\">Manual (no automatic sync).</label>\n              </div>\n              <p class=\"text-warning\">No sources of automatic synchronization have been detected.</p>\n            </div>\n            <div class=\"modal-footer\">\n                <button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">Cancel</button>\n                <button type=\"button\" class=\"btn btn-primary\" id=\"choose-sync\" data-dismiss=\"modal\">Sync</button>\n            </div>\n        </div>\n    </div>\n  </div>\n\n  <div id=\"errorDetailsModal\" class=\"modal fade\">\n    <div class=\"modal-dialog\">\n        <div class=\"modal-content\">\n            <div class=\"modal-header\">\n                <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-hidden=\"true\">&times;</button>\n                <h4 class=\"modal-title\">Show Error</h4>\n            </div>\n            <div class=\"modal-body\">\n              <h5>Description</h5>\n              <p class=\"text-primary\" id=\"errorDescription\"></p>\n              <h5>Cause</h5>\n              <p class=\"text-danger\"><strong><span id=\"errorCause\"></span></strong></p>\n            </div>\n            <div class=\"modal-footer\">\n                <button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">Close</button>\n            </div>\n        </div>\n    </div>\n  </div>\n\n{% endblock %}\n{% block page-scripts %}\n    {% script \"/js/jquery.json.min.js\" %}\n    {% style \"/css/bootstrap-slider.css\" %}\n    {% script \"/js/bootstrap-slider.min.js\" %}\n    {% style \"/css/jquery.minicolors.css\" %}\n    {% script \"/js/jquery.minicolors.min.js\" %}\n    {% style \"/css/bootstrap-switch.css\" %}\n    {% script \"/js/bootstrap-switch.min.js\" %}\n    {% style \"/font-awesome-4.5.0/css/font-awesome.min.css\" %}\n    {% script \"/js/BootstrapMenu.min.js\" %}\n    {% comment %}{% script \"/js/jquery.websocket-0.0.1.js\" %}{% endcomment %}\n\n    {% style \"/css/show.css\" %}\n    <script type=\"text/javascript\">\n      var page_id = \"{{page-id}}\";\n      var makingMacro = false;\n      var macroCounter = 1;\n    </script>\n    {% script \"/js/show_updates.js\" %}\n{% endblock %}\n"
  },
  {
    "path": "resources/templates/sync_menu.html",
    "content": "              <p>Establish a BPM or beat synchronization source for this show:\n{% for element in sync-menu %}              <div class=\"radio{% if element.selected %} active{% endif %}\">\n                <label><input type=\"radio\" name=\"sync\" value=\"{{element.value}}\"{% if element.selected %} checked=\"\"{% endif %}>{{element.label}}</label>\n              </div>\n{% if sync-menu|length-is:1 %}              <p class=\"text-warning\">No sources of automatic synchronization have been detected.</p>{% endif %}\n              </div>{% endfor %}\n"
  },
  {
    "path": "resources/templates/visualizer.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n    <style>\n      body { margin: 0; padding: 0; }\n    </style>\n    <title>Afterglow Visualizer</title>\n  </head>\n  <body>\n\n  <div id=\"container\">\n  </div>\n\n  {% script \"/js/jquery-2.1.4.min.js\" %}\n  {% script \"/js/three.min.js\" %}\n  <script>\n    // When was the fixture arrangement last modified, to see if we need to reload\n    // our fragment shader.\n    var SHOW_TIMESTAMP = {{timestamp}};\n    \n    // Helper for synchronously loading shader source\n    var getSourceSynch = function(url) {\n      var req = new XMLHttpRequest();\n      req.open(\"GET\", url, false);\n      req.send(null);\n      return (req.status == 200) ? req.responseText : null;\n    };\n\n    // Set the size of the \"screen\" on which we are projecting the volumetric rendering.\n    // This doesn't really matter because our fragment shader will happily render pixels\n    // outside these boundaries, but it is used for camera positioning.\n    var WIDTH = 100, HEIGHT = 100;\n    \n    // set some camera attributes\n    var DISTANCE = 300, ASPECT = WIDTH / HEIGHT, NEAR = 0.1, FAR = 10000;\n    \n    // get the DOM element to attach to\n    // - assume we've got jQuery to hand\n    var $container = $('#container');\n\n    var tuniform = {\n      iGlobalTime: { type: 'f', value: 0.1 },\n      iChannel0:   { type: 't', value: THREE.ImageUtils.loadTexture('/textures/noise.png') },\n      iResolution: { type: 'v3', value: new THREE.Vector3(window.innerWidth, window.innerHeight, 0) },\n{% include \"current-scene-fragment.js\" %}    \n    };\n    tuniform.iChannel0.value.wrapS = tuniform.iChannel0.value.wrapT = THREE.RepeatWrapping;\n\n    var scene, camera, renderer;\n    var geometry, material, mesh;\n    var clock;\n    var vertexShader;\n    var fragmentShader;\n\n    $.ajax({\n      url: '/shaders/vertex.glsl',\n        success: function(response) {\n          vertexShader = response;\n          $.ajax({\n            url: '/shaders/{{show.id}}/fragment.glsl',\n              success: function(response) {\n                fragmentShader = response;\n                init();\n              }\n          });\n        }\n    });\n\n    function init() {\n    \n      scene = new THREE.Scene();\n      var view_angle = 2 * Math.atan((WIDTH / ASPECT) / (2 * DISTANCE)) * (180 / Math.PI);\n      camera = new THREE.PerspectiveCamera(view_angle, ASPECT, NEAR, FAR);\n      camera.position.z = DISTANCE;\n\n      material = new THREE.ShaderMaterial( {\n        uniforms: tuniform,\n        vertexShader: vertexShader,\n        fragmentShader: fragmentShader,\n        side:THREE.DoubleSide\n      });\n\n      mesh = new THREE.Mesh(new THREE.PlaneBufferGeometry(WIDTH,HEIGHT,1,1), material);\n      scene.add(mesh);\n\n      renderer = new THREE.WebGLRenderer();\n      renderer.setSize(window.innerWidth, window.innerHeight);\n\n      clock = new THREE.Clock(false);\n      clock.start();\n\n      $container.append(renderer.domElement);\n      animate();\n      setInterval(updateLights, 50);\n    }\n\n    function animate() {\n      requestAnimationFrame( animate );\n\n      delta = clock.getDelta();\n      tuniform.iGlobalTime.value += delta;\n      tuniform.iResolution.value = new THREE.Vector3(window.innerWidth, window.innerHeight, 0);\n\n      renderer.render(scene, camera);\n    }\n\n    // Arrange things so that when the user is done resizing the window, the renderer\n    // gets updated to take up all of it again.\n    function resizeRenderer() {\n      renderer.setSize(window.innerWidth, window.innerHeight);\n    }\n\n    var resizeTimer;\n    $(window).resize(function() {\n      clearTimeout(resizeTimer);\n      resizeTimer = setTimeout(resizeRenderer, 100);\n    });\n\n    function updateLights() {\n      $.ajax({\n        url: '/visualizer-update/{{show.id}}',\n        success: function(response) {\n          var new_values;\n          eval(\"new_values=\" + response);\n\n          if (new_values.timestamp != SHOW_TIMESTAMP) {\n            console.log(\"Forcing reload because show geometry has changed.\");\n            location.reload(true);\n          } else {\n            var numSpots = new_values.iNumSpots.value;\n            tuniform.iNumSpots.value = numSpots;\n            if (numSpots > 0) {\n              tuniform.iSpotPosition.value = new_values.iSpotPosition.value;\n              tuniform.iSpotRotation.value = new_values.iSpotRotation.value;\n              tuniform.iSpotColor.value = new_values.iSpotColor.value;\n            }\n          }\n        }\n      });\n    }\n\n  </script>\n</body>\n<html>\n"
  },
  {
    "path": "src/afterglow/beyond.clj",
    "content": "(ns afterglow.beyond\n  \"Provides the ability to communicate with Pangolin's Beyond laser\n  show software, including synchronizing it with Afterglow's BPM and\n  beat grid, and triggering cues. This initial implementation assumes\n  that sending small UDP datagrams is fast enough that it can be done\n  on the caller's thread. If this turns out not to be true, it can be\n  changed to use a core.async channel the way that ola-clojure does.\"\n  (:require [afterglow.controllers :as controllers]\n            [afterglow.effects :as fx]\n            [afterglow.effects.color :as color]\n            [afterglow.effects.params :as params]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [with-show]]\n            [com.evocomputing.colors :as colors]\n            [overtone.at-at :as at-at :refer [now]]\n            [taoensso.timbre :as timbre])\n  (:import [java.net InetAddress DatagramPacket DatagramSocket]\n           [afterglow.effects Effect Assigner]))\n\n(defonce ^{:private true\n           :doc \"The socket used for sending UDP packets to Beyond.\"}\n  send-socket (DatagramSocket.))\n\n(defonce ^{:doc \"Used to give each server a unique ID, for registering\n  its metronome BPM watcher with a show.\"\n           :private true}\n  server-counter\n  (atom 0))\n\n(defn- empty-buffer\n  \"Empty the frame buffer of the specified server connection in\n  preparation for generating a new frame of the light show.\"\n  [server]\n  (dosync\n   (ref-set (:last-frame server) @(:frame-buffer server))\n   (ref-set (:frame-buffer server) {})))\n\n(defn send-command\n  \"Sends a PangoScript command to the specified Beyond Talk server.\"\n  [server command]\n  (let [payload (str command \\return \\newline)\n        packet (DatagramPacket. (.getBytes payload) (.length payload) (:address server) (:port server))]\n    (.send send-socket packet)))\n\n(defn restore-laser-color\n  \"Sets Beyond's Live Control RGBA cue color override to allow the\n  affected cue to show its normal colors.\"\n  [server]\n  (send-command server \"RGBA 255, 255, 255, 0\"))\n\n(defn set-laser-color\n  \"Sets Beyond's Live Control RGBA cue color override to match the\n  supplied color value.\"\n  [server c]\n  (send-command server (str \"RGBA \" (clojure.string/join \", \" [(colors/red c) (colors/green c) (colors/blue c) 255]))))\n\n(defn- send-buffer\n  \"Update the associated Beyond server with the differences between\n  what has been generated during this frame of the Afterglow light\n  show and the previous one, if any.\"\n  [server]\n  (when (not= (:beyond-color @(:frame-buffer server)) (:beyond-color @(:last-frame server)))\n    (if-let [new-color (:beyond-color @(:frame-buffer server))]\n      (set-laser-color server new-color)\n      (restore-laser-color server)))\n  ;; TODO: Can we consolodate these into a single message?\n  (let [previous-cues (:beyond-cue @(:last-frame server))\n        current-cues (:beyond-cue @(:frame-buffer server))]\n    (doseq [[page number] (clojure.set/difference previous-cues current-cues)]\n      (send-command server (str \"StopCue \" page \", \" number)))\n    (doseq [[page number] (clojure.set/difference current-cues previous-cues)]\n      (send-command server (str \"StartCue \" page \", \" number)))))\n\n(defn beyond-server\n  \"Creates a representation of the UDP PangoScript server running in\n  Beyond at the specified address and port. The value returned can\n  then be used with the other functions in this namespace to interact\n  with that laser show.\"\n  [address port]\n  (let [server {:id (swap! server-counter inc)\n                :address (InetAddress/getByName address)\n                :port port\n                :synced-show (ref nil)\n                :frame-buffer (ref nil)\n                :empty-fn (ref nil)\n                :send-fn (ref nil)\n                :last-frame (ref nil)\n                :task (ref nil)}]\n    (dosync\n     (ref-set (:empty-fn server) #(empty-buffer server))\n     (ref-set (:send-fn server) #(send-buffer server)))\n    server))\n\n(defn resync-to-beat\n  \"Schedules a message to the laser show being run by the specified\n  Beyond server to let it know when the beat after next takes place in\n  its synchronized show. Has no effect if the server is not synced.\"\n  [server]\n  (when-let [show @(:synced-show server)]\n    (at-at/at (long (rhythm/metro-beat (:metronome show) (inc (inc (rhythm/metro-beat (:metronome show))))))\n              #(send-command server \"BeatResync\") controllers/pool :desc \"Resync Beyond's beat grid\")))\n\n(defn- metronome-watch-key\n  \"Create a key with which to uniquely identify this server as a\n  registered bpm watcher of a show metronome.\"\n  [server]\n  (keyword (str \"afterglow.beyond.\" (:id server))))\n\n(defn bind-to-show\n  \"Causes the BPM of the laser show being run by the specified Beyond\n  Talk server to be synced with the main metronome of the specified\n  show. When sync is started, the beats will be synced as well, and\n  they will be resynced periodically to correct for potential drift.\n  The default resync interval is ten seconds, but it can be set to a\n  different value by passing a resync interval, in milliseconds, as a\n  third argument.\n\n  Also hooks this Beyond server instance into the supplied show's\n  rendering loop, so that the laser-related effects and assigners\n  provided by this namespace can participate, even though they do not\n  result in DMX values being sent to the show universes.\n\n  To undo a binding established by this function, simply call it again\n  to bind to another show, or with a `nil` show to unbind entirely.\"\n  ([server show]\n   (bind-to-show server show 10000))\n  ([server show resync-interval]\n   (dosync\n    (when-let [former-show @(:synced-show server)]\n      (rhythm/metro-remove-bpm-watch (:metronome former-show) (metronome-watch-key server))\n      (with-show former-show\n        (show/clear-empty-buffer-fn! @(:empty-fn server))\n        (show/clear-send-buffer-fn! @(:send-fn server))))\n    (ref-set (:synced-show server) show)\n    (ref-set (:frame-buffer server) nil)\n    (ref-set (:last-frame server) nil)\n    (when show\n      (send-command server (str \"SetBpm \" (rhythm/metro-bpm (:metronome show))))\n      (rhythm/metro-add-bpm-watch (:metronome show) (metronome-watch-key server)\n                                  (fn [_ _ _ bpm]\n                                    (send-command server (str \"SetBpm \" bpm))))\n      (with-show show\n        (show/add-empty-buffer-fn! @(:empty-fn server))\n        (show/add-send-buffer-fn! @(:send-fn server))))\n    (alter (:task server) (fn [former-task]\n                            (when former-task (at-at/stop former-task))\n                            (when show (at-at/every resync-interval #(resync-to-beat server) controllers/pool\n                                                    :desc \"Resync Beyond's beat grid\")))))))\n\n(defn laser-color-effect\n  \"An effect which sets the Beyond RGBA cue color override to match\n  the color parameter passed in, and sets it back to normal when\n  ended.\"\n  [server color]\n  (params/validate-param-type color :com.evocomputing.colors/color)\n  (Effect. \"Laser Color\"\n           fx/always-active\n           (fn [show snapshot]\n             (let [resolved (params/resolve-unless-frame-dynamic color show snapshot)]\n               [(Assigner. :beyond-color (:id server) server\n                            (fn [show snapshot target previous-assignment] resolved))]))\n           fx/end-immediately))\n\n(defn cue-effect\n  \"An effect which causes a laser cue to run as long as it is active.\n  The number of the grid page and the number of the cue within that\n  page are passed as arguments (and cannot be dynamic parameters).\"\n  [server page number]\n  {:pre [(integer? page) (integer? number)]}\n  (let [assigners [(Assigner. :beyond-cue [(:id server) page number] server\n                              (fn [show snapshot target previous-assignment] [page number]))]]\n    (Effect. \"Beyond Cue\"\n             fx/always-active\n             (fn [show snapshot] assigners)\n             fx/end-immediately)))\n\n;; Tell Afterglow about our assigners and the order in which they should be run.\n(show/set-extension-resolution-order! :afterglow.beyond [:beyond-color :beyond-cue])\n\n;; Set up the resolution handler for the laser cue assigner.\n(defmethod fx/resolve-assignment :beyond-cue [assignment _ _ _]\n  (let [target (:target assignment)]  ; Find the Beyond server associated with this assignment\n    (dosync (alter (:frame-buffer target) update :beyond-cue (fnil conj #{}) (:value assignment)))))\n\n;; Set up the resolution handler for the laser color assigner.\n(defmethod fx/resolve-assignment :beyond-color [assignment show snapshot _]\n  (let [target (:target assignment)  ; Find the Beyond server associated with this assignment.\n        ;; Resolve the color in the assignment value in case it is still frame dynamic.\n        resolved (params/resolve-param (:value assignment) show snapshot target)]\n    ;; Store it in our frame buffer so it can be sent when the lights are being updated.\n    (dosync (alter (:frame-buffer target) assoc :beyond-color resolved))))\n\n;; Add fade blending support for laser color assignments\n(defmethod fx/fade-between-assignments :beyond-color [from-assignment to-assignment fraction show snapshot]\n  (cond (<= fraction 0) from-assignment\n        (>= fraction 1) to-assignment\n        :else (merge from-assignment {:value (color/fade-colors (:value from-assignment) (:value to-assignment)\n                                                                fraction show snapshot (:target from-assignment))})))\n"
  },
  {
    "path": "src/afterglow/carabiner.clj",
    "content": "(ns afterglow.carabiner\n  \"Provides synchronization with Ableton Link on the local network,\n  using the lib-carabiner library.\"\n  (:require [afterglow.midi :refer [IClockSync sync-start sync-stop sync-status]]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.util :refer [unsign]]\n            [clojure.edn :as edn]\n            [clojure.java.io :as io]\n            [overtone.at-at :refer [now]]\n            [taoensso.timbre :as timbre])\n  (:import [java.net Socket InetSocketAddress]\n           [org.deepsymmetry.libcarabiner Runner]\n           [org.deepsymmetry.electro Metronome Snapshot]))\n\n(defonce ^{:private true\n           :doc \"Holds the set of active synced metronomes.\"}\n  synced-metronomes (atom #{}))\n\n(def carabiner-runner\n  \"The [`Runner`](https://deepsymmetry.org/lib-carabiner/apidocs/org/deepsymmetry/libcarabiner/Runner.html)\n  singleton that can manage an embedded Carabiner instance for us.\"\n  (Runner/getInstance))\n\n(defonce ^{:private true\n           :doc \"When connected, holds the socket used to communicate\n  with Carabiner, values which track the peer count and tempo reported\n  by the Ableton Link session, and the `:running` flag which can be\n  used to gracefully terminate that thread.\n\n  If we used lib-carabiner to start an embedded instance of Carabiner,\n  then `:embedded` will be `true` to let us know it should be stopped\n  when we disconnect.\n\n  The `:last` entry is used to assign unique integers to each\n  `:running` value as we are started and stopped, so a leftover\n  background thread from a previous run can know when it is stale and\n  should exit.)\n\n  Once we are connected to Carabiner, the current Link session tempo\n  will be available under the key `:link-bpm`.\"}\n\n  client (atom {:port 17000\n                :last      0\n                :embedded  false}))\n\n(def connect-timeout\n  \"How long the connection attempt to the Carabiner daemon can take\n  before we give up on being able to reach it.\"\n  5000)\n\n(def read-timeout\n  \"How long reads from the Carabiner daemon should block so we can\n  periodically check if we have been instructed to close the\n  connection.\"\n  2000)\n\n(defn state\n  \"Returns the current state of the Carabiner connection as a map whose\n  keys include:\n\n  `:port`, the port on which the Carabiner daemon is listening.\n\n  `:running` will have a non-`nil` value if we are connected to\n  Carabiner. Once we are connected to Carabiner, the current Link\n  session tempo will be available under the key `:link-bpm` and the\n  number of Link peers under `:link-peers`.\"\n  []\n  (select-keys @client [:port :running :link-bpm :link-peers]))\n\n(defn active?\n  \"Checks whether there is currently an active connection to a\n  Carabiner daemon.\"\n  []\n  (:running @client))\n\n(defn set-carabiner-port\n  \"Sets the port to be uesd to connect to Carabiner. Can only be called\n  when not connected.\"\n  [port]\n  (when (active?)\n    (throw (IllegalStateException. \"Cannot set port when already connected.\")))\n  (when-not (<= 1 port 65535)\n    (throw (IllegalArgumentException. \"port must be in range 1-65535\")))\n  (swap! client assoc :port port))\n\n(defn- ensure-active\n  \"Throws an exception if there is no active connection.\"\n  []\n  (when-not (active?)\n    (throw (IllegalStateException. \"No active Carabiner connection.\"))))\n\n(defn- send-message\n  \"Sends a message to the active Carabiner daemon.\"\n  [message]\n  (ensure-active)\n  (let [output-stream (.getOutputStream ^Socket (:socket @client))]\n    (.write output-stream (.getBytes (str message \"\\n\") \"UTF-8\"))\n    (.flush output-stream)))\n\n(def ^{:private true\n       :doc \"Functions to be called with the updated client state\n  whenever we have processed a status update from Carabiner.\"}\n\n  status-listeners (atom #{}))\n\n(defn add-status-listener\n  \"Registers a function to be called with the updated client state\n  whenever we have processed a status update from Carabiner. When that\n  happens, `listener` will be called with a single argument\n  containing the same map that would be returned by calling [[state]]\n  at that moment.\n  This registration can be reversed by\n  calling [[remove-status-listener]].\"\n  [listener]\n  (swap! status-listeners conj listener))\n\n(defn remove-status-listener\n  \"Removes a function from the set that is called whenever we have\n  processed a status update from Carabiner. If `listener` had been\n  passed to [[add-status-listener]], it will no longer be called.\"\n  [listener]\n  (swap! status-listeners disj listener))\n\n(defn- send-status-updates\n  \"Calls any registered status listeners with the current client state.\"\n  []\n  (when-let [listeners (seq @status-listeners)]\n      (let [updated (state)]\n        (doseq [listener listeners]\n          (try\n            (listener updated)\n            (catch Throwable t\n              (timbre/error t \"Problem running status-listener.\")))))))\n\n(defn- handle-status\n  \"Processes a status update from Carabiner. Calls any registered status\n  listeners with the resulting state.\"\n  [status]\n  (let [bpm (double (:bpm status))\n        peers (int (:peers status))]\n    (swap! client assoc :link-bpm bpm :link-peers peers)\n    (send-status-updates)))\n\n(defn- handle-phase-at-time\n  \"Processes a phase probe response from Carabiner.\"\n  [info]\n  (let [state                            @client\n        [ableton-now ^Snapshot snapshot] (:phase-probe state)\n        align-to-bar                     (:bar state)]\n    (if (= ableton-now (:when info))\n      (let [desired-phase  (if align-to-bar\n                             (/ (:phase info) 4.0)\n                             (- (:phase info) (long (:phase info))))\n            actual-phase   (if align-to-bar\n                             (.getBarPhase snapshot)\n                             (.getBeatPhase snapshot))\n            phase-delta    (Metronome/findClosestDelta (- desired-phase actual-phase))\n            phase-interval (if align-to-bar\n                             (.getBarInterval snapshot)\n                             (.getBeatInterval snapshot))\n            ms-delta       (long (* phase-delta phase-interval))]\n        ;; TODO: Rewrite this in the context of Afterglow.\n        (when (pos? (Math/abs ms-delta))\n          ;; We should shift the Pioneer timeline. But if this would cause us to skip or repeat a beat, and we\n          ;; are shifting less 1/5 of a beat or less, hold off until a safer moment.\n          #_(let [beat-phase (.getBeatPhase (.getPlaybackPosition ^VirtualCdj virtual-cdj))\n                beat-delta (if align-to-bar (* phase-delta 4.0) phase-delta)\n                beat-delta (if (pos? beat-delta) (+ beat-delta 0.1) beat-delta)]  ; Account for sending lag.\n            (when (or (zero? (Math/floor (+ beat-phase beat-delta)))  ; Staying in same beat, we are fine.\n                      (> (Math/abs beat-delta) 0.2))  ; We are moving more than 1/5 of a beat, so do it anyway.\n              (timbre/info \"Adjusting Pioneer timeline, delta-ms:\" ms-delta)\n              (.adjustPlaybackPosition ^VirtualCdj virtual-cdj ms-delta)))))\n      (timbre/warn \"Ignoring phase-at-time response for time\" (:when info) \"since was expecting\" ableton-now))))\n\n(defn- handle-version\n  \"Processes the response to a recognized version command. Warns if\n  Carabiner should be upgraded.\"\n  [version]\n  (timbre/info \"Connected to Carabiner daemon, version:\" version)\n  (when (= version \"1.1.0\")\n    (timbre/warn \"Carabiner needs to be upgraded to at least version 1.1.1 to avoid sync glitches.\")))\n\n(defn- handle-unsupported\n  \"Processes an unsupported command reponse from Carabiner.\"\n  [command]\n  (timbre/error \"Carabiner complained about not recognizing our command:\" command))\n\n(defn- shutdown-embedded-carabiner\n  \"If the client settings indicate we started the Carabiner server we\n  are disconnecting from, shut it down.\"\n  ([]\n   (shutdown-embedded-carabiner @client))\n  ([settings]\n   (when (:embedded settings)\n     (.stop ^Runner carabiner-runner))))\n\n(defonce ^{:doc \"Cleans up any embedded Carabiner instance we launched when Java is\nshutting down.\"\n           :private true}\n  shutdown-hook\n  (let [hook (Thread. shutdown-embedded-carabiner)]\n    (.addShutdownHook (Runtime/getRuntime) hook)\n    hook))\n\n(defn- response-handler\n  \"A loop that reads messages from Carabiner as long as it is supposed\n  to be running, and takes appropriate action.\"\n  [^Socket socket running]\n  (let [unexpected? (atom false)]  ; Tracks whether Carabiner unexpectedly closed the connection from its end.\n    (try\n      (let [buffer      (byte-array 1024)\n            input       (.getInputStream socket)]\n        (while (and (= running (:running @client)) (not (.isClosed socket)))\n          (try\n            (let [n (.read input buffer)]\n              (if (and (pos? n) (= running (:running @client)))  ; We got data, and were not shut down while reading\n                (let [message (String. buffer 0 n \"UTF-8\")\n                      reader  (java.io.PushbackReader. (io/reader (.getBytes message \"UTF-8\")))]\n                  (timbre/debug \"Received:\" message)\n                  (loop [cmd (edn/read reader)]\n                    (case cmd\n                      status        (handle-status (clojure.edn/read reader))\n                      phase-at-time (handle-phase-at-time (clojure.edn/read reader))\n                      version       (handle-version (clojure.edn/read reader))\n                      unsupported   (handle-unsupported (clojure.edn/read reader))\n                      (timbre/error \"Unrecognized message from Carabiner:\" message))\n                    (let [next-cmd (clojure.edn/read {:eof ::eof} reader)]\n                      (when (not= ::eof next-cmd)\n                        (recur next-cmd)))))\n                (do  ; We read zero, meaning the other side closed, or we have been instructed to terminate.\n                  (.close socket)\n                  (reset! unexpected? (= running (:running @client))))))\n            (catch java.net.SocketTimeoutException _\n              (timbre/debug \"Read from Carabiner timed out, checking if we should exit loop.\"))\n            (catch Throwable t\n              (timbre/error t \"Problem reading from Carabiner.\")))))\n      (timbre/info \"Ending read loop from Carabiner.\")\n      (swap! client (fn [oldval]\n                      (if (= running (:running oldval))\n                        (do  ; We are causing the ending.\n                          (shutdown-embedded-carabiner oldval)\n                          (dissoc oldval :running :embedded :socket :link-bpm :link-peers))\n                        oldval)))  ; Someone else caused the ending, so leave client alone; may be new connection.\n      (.close socket)  ; Either way, close the socket we had been using to communicate, and update the window state.\n      (catch Throwable t\n        (timbre/error t \"Problem managing Carabiner read loop.\")))))\n\n(defn disconnect\n  \"Closes any active Carabiner connection. The run loop will notice that\n  its run ID is no longer current, and gracefully terminate, closing\n  its socket without processing any more responses. Also shuts down\n  the embedded Carabiner process if we started it.\"\n  []\n  (swap! client (fn [oldval]\n                  (shutdown-embedded-carabiner oldval)\n                  (dissoc oldval :running :embedded :socket :link-bpm :link-peers))))\n\n(defn- connect-internal\n  \"Helper function that attempts to connect to the Carabiner daemon with\n  a particular set of client settings, returning them modified to\n  reflect the connection if it succeeded. If the settings indicate we\n  have just started an embedded Carabiner instance, keep trying to\n  connect every ten milliseconds for up to two seconds, to give it a\n  chance to come up.\"\n  [settings]\n  (let [running (inc (:last settings))\n        socket  (atom nil)\n        caught  (atom nil)]\n    (loop [tries 200]\n      (try\n        (reset! socket (Socket.))\n        (reset! caught nil)\n        (.connect ^Socket @socket (InetSocketAddress. \"127.0.0.1\" (int (:port settings))) connect-timeout)\n        (catch java.net.ConnectException e\n          (reset! caught e)))\n      (when @caught\n        (if (and (:embedded settings) (pos? tries))\n          (do\n            (Thread/sleep 10)\n            (recur (dec tries)))\n          (throw @caught))))\n    ;; We have connected successfully!\n    (.setSoTimeout ^Socket @socket read-timeout)\n    (future (response-handler @socket running))\n    (merge settings {:running running\n                     :last    running\n                     :socket  @socket})))\n\n(defn connect\n  \"Try to establish a connection to Carabiner. First checks if there is\n  already an independently managed instance of Carabiner running on\n  the configured port (see [[set-carabiner-port]]), and if so, simply\n  uses that. Otherwise, checks whether we are on a platform where we\n  can install and run our own temporary copy of Carabiner. If so,\n  tries to do that and connect to it.\n\n  Returns truthy if the initial open succeeded. Sets up a background\n  thread to reject the connection if we have not received an initial\n  status report from the Carabiner daemon within a second of opening\n  it.\"\n  []\n  (swap! client (fn [oldval]\n                  (if (:running oldval)\n                    oldval\n                    (try\n                      (try\n                        (connect-internal oldval)\n                        (catch java.net.ConnectException e\n                          ;; If we couldn't connect, see if we can run Carabiner ourselves and try again.\n                          (if (.canRunCarabiner ^Runner carabiner-runner)\n                            (do\n                              (.setPort ^Runner carabiner-runner (:port oldval))\n                              (.start ^Runner carabiner-runner)\n                              (connect-internal (assoc oldval :embedded true)))\n                            (throw e))))\n                      (catch Exception e\n                        (timbre/warn e \"Unable to connect to Carabiner\")\n                        oldval)))))\n  (when (active?)\n    (future\n      (Thread/sleep 1000)\n      (if (:link-bpm @client)\n        (do ; We are connected! Check version and configure for start/stop sync.\n          (send-message \"version\") ; Probe that a recent enough version is running.\n          (send-message \"enable-start-stop-sync\")) ; Set up support for start/stop triggers.\n        (do ; We failed to get a response, maybe we are talking to the wrong process.\n          (timbre/warn \"Did not receive inital status packet from Carabiner daemon; disconnecting.\")\n          (disconnect)))))\n  (active?))\n\n\n\n;; TODO: This section needs to be rewritten to instead align all synced metronomes.\n;; Store them and all their snapshots?\n\n#_(defn- align-pioneer-phase-to-ableton\n  \"Send a probe that will allow us to align the Virtual CDJ timeline to\n  Ableton Link's.\"\n  []\n  (let [ableton-now (+ (long (/ (System/nanoTime) 1000)) (* (:latency @client) 1000))\n        snapshot    (.getPlaybackPosition ^VirtualCdj virtual-cdj)]\n    (swap! client assoc :phase-probe [ableton-now snapshot])\n    (send-message (str \"phase-at-time \" ableton-now \" 4.0\"))))\n\n#_(defonce ^{:private true\n           :doc \"A daemon thread that periodically aligns the Pioneer phase to the\n  Ableton Link session when the sync mode requires it.\"}\n\n  full-sync-daemon\n  (Thread. (fn []\n             (loop []\n               (try\n                 ;; If we are due to send a probe to align the Virtual CDJ timeline to Link's, do so.\n                 (when (and (= :full (:sync-mode @client)) (.isTempoMaster ^VirtualCdj virtual-cdj))\n                   (align-pioneer-phase-to-ableton))\n                 (Thread/sleep 200)\n                 (catch Exception e\n                   (timbre/error e \"Problem aligning DJ Link phase to Ableton Link.\")))\n               (recur)))\n           \"Beat Carabiner Phase Alignment\"))\n\n#_(let [^Thread daemon full-sync-daemon]\n  (when-not (.isAlive daemon)\n    (.setPriority daemon Thread/MIN_PRIORITY)\n    (.setDaemon daemon true)\n    (.start daemon)))\n\n\n\n;; TODO: Finish copying relevant sections of dj_link.clj to implement this sort of syncing,\n;;       and update show.clj to be able to use it. Once that is working programatically,\n;;   [x] update web/routes/show_control.clj to be able to offer Ableton Link in the Sync menu.\n;;   [x] Always offer Ableton Link as a sync option if Carabiner connected successfully. (done!)\n;;   [ ] Figure out where that menu gets handled and implement the request to sync to Ableton.\n;;   [ ] Start Carabiner if possible when starting up a show.\n\n;; TODO: Is there an interface for choosing sync on the Push? If so add support there too.\n"
  },
  {
    "path": "src/afterglow/channels.clj",
    "content": "(ns afterglow.channels\n  \"Functions for modeling DMX channels\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.fixtures.qxf :refer [sanitize-name]]\n            [camel-snake-kebab.core :as csk]\n            [com.evocomputing.colors :as colors]))\n\n(defn channel\n  \"Creates a minimal channel specification, containing just the\n  address offset within the fixture's list of channels. The first\n  channel used by a fixture is, by convention, given offset 1.\n\n  You probably want to use [[fine-channel]] rather than this function\n  to create even channels which do not have a `:fine-offset` because\n  of the other helpful features it offers, such as setting up the\n  channel function specification for you.\"\n  [offset]\n  {:offset offset})\n\n(defn- assign-channel\n  \"Given a universe and DMX address at which a fixture is being\n  patched, and a raw channel description from the fixture definition,\n  calculate and assign the channel's actual DMX address and universe\n  that it will have in a show. Also adds the back pointer to the head\n  that owns the channel, so dynamic and spatial parameter resolution\n  can access head information.\"\n  [universe start-address head raw-channel]\n  (cond-> raw-channel\n    (:offset raw-channel) (assoc :address (+ (:offset raw-channel) (dec start-address))\n                                 :index (+ (dec (:offset raw-channel)) (dec start-address))\n                                 :universe universe)\n    (:fine-offset raw-channel) (assoc :fine-address (+ (:fine-offset raw-channel) (dec start-address))\n                                      :fine-index (+ (dec (:fine-offset raw-channel)) (dec start-address)))\n    head (assoc :head head)))\n\n(defn- patch-head\n  \"Assigns a single head to a DMX universe and starting channel; resolves all of its\n  channel assignments.\"\n  [channel-assigner fixture id-fn raw-head]\n  (assoc (update-in raw-head [:channels] #(map (partial channel-assigner raw-head) %))\n         :fixture fixture :id (id-fn)))\n\n(defn- patch-heads\n  \"Assigns the heads of a fixture to a DMX universe and starting\n  channel; resolves all of their channel assignments.\"\n  [fixture channel-assigner id-fn]\n  (let [assigner (partial patch-head channel-assigner fixture id-fn)]\n    (update-in fixture [:heads] #(map assigner %))))\n\n(defn patch-fixture\n  \"Assign a fixture to a DMX universe and starting channel; resolves\n  all of its channel assignments.\"\n  [fixture universe start-address id-fn]\n  (let [assigner (partial assign-channel universe start-address)]\n    (update-in (patch-heads fixture assigner id-fn) [:channels] #(map (partial assigner fixture) %))))\n\n(defn extract-channels\n  \"Given a fixture list, returns the channels matching the specified predicate.\"\n  [fixtures pred]\n  (filter pred (mapcat :channels fixtures)))\n\n(defn expand-heads\n  \"Given a list of fixtures, expands it to include the heads.\"\n  [fixtures]\n  (mapcat #(concat [%] (:heads %)) fixtures))\n\n(defn all-addresses\n  \"Returns all the addresses being used by a list of patched fixtures,\n  including those used by any fixture heads.\"\n  [fixtures]\n  (mapcat #(vals (select-keys % [:address :fine-address]))\n          (mapcat :channels (expand-heads fixtures))))\n\n(defn extract-heads-with-some-matching-channel\n  \"Given a fixture list, returns all heads (which may be top-level fixtures too)\n  whose channels contain a match for the specified predicate.\"\n  [fixtures pred]\n  (filter #(some pred (:channels %)) (expand-heads fixtures)))\n\n(defn find-rgb-heads\n  \"Returns all heads of the supplied fixtures which are capable of\n  mixing RGB color, in other words they have at least a red, green,\n  and blue color channel. If the second argument is present and\n  `true`, also returns heads with color wheels.\"\n  ([fixtures]\n   (find-rgb-heads fixtures false))\n  ([fixtures include-color-wheels?]\n   (filter #(or (= 3 (count (filter #{:red :green :blue} (map :color (:channels %)))))\n                (and include-color-wheels? (seq (:color-wheel-hue-map %))))\n           (expand-heads fixtures))))\n\n(defn has-rgb-heads?\n  \"Given a fixture, returns a truthy value if it has any heads capable\n  of mixing RGB color. If the second argument is present and `true`,\n  having a head with a color wheel is good enough.\"\n  ([fixture]\n   (has-rgb-heads? fixture false))\n  ([fixture include-color-wheels?]\n   (seq (find-rgb-heads [fixture] include-color-wheels?))))\n\n(defn build-function\n  \"Returns a function spefication that encompasses a range of possible\n  DMX values for a channel. If start and end are not specified, the\n  function uses the full range of the channel.\"\n  [range-type function-type label & {:keys [start end var-label] :or {start 0 end 255}}]\n  (merge {:start start\n          :end end\n          :range range-type\n          :type function-type\n          :label label}\n         (when var-label {:var-label var-label})))\n\n(defn fine-channel\n  \"Defines a channel of type `chan-type` which may be paired with a\n  second channel in order to support multi-byte values. When a value\n  is passed in with `:fine-offset`, the channel specified by `offset`\n  is understood as containing the most-significant byte of a two-byte\n  value, with the least-significant byte carried in the channel whose\n  offset followed `:fine-offset`.\n\n  Automatically creates a [function\n  specification]({{guide-url}}fixture_definitions.html#function-specifications)\n  which spans all the legal DMX values for the channel. By default,\n  the function type is taken to be the same as `chan-type`, but this\n  can be changed by passing in a different keyword with\n  `:function-type`.\n\n  Similarly, the name of the function created is, by default, a\n  capitalized version of the function type (without its leading\n  colon). Since this name is displayed in the [web\n  interface]({{guide-url}}README.html#web-ui) as the text label in the\n  cue grid cell for [Function\n  Cues]({{guide-url}}cues.html#creating-function-cues) created for the\n  function, you may wish to specify a more readable name, which you\n  can do by passing it with `:function-name`.\n\n  Finally, you may specify a label to be used when creating a user\n  interface for adjusting the value associated with this\n  function. [Function\n  Cues]({{guide-url}}cues.html#creating-function-cues)\n  will use this as the label for the cue-local variable they create,\n  and it will appear in places like the [Ableton Push Effect Control\n  interface]({{guide-url}}push2.html#effect-control).\n  You can specify what this variable label should be with\n  `:var-label`; if you do not, the generic label `Level` will be\n  used.\"\n  [chan-type offset & {:keys [fine-offset function-type function-name var-label] :or {function-type chan-type}}]\n  {:pre [(some? chan-type) (integer? offset) (<= 1 offset 512)]}\n  (let [chan-type (keyword chan-type)\n        function-type (keyword function-type)\n        function-name (or function-name (clojure.string/capitalize (name function-type)))\n        base (assoc (channel offset)\n                    :type chan-type\n                    :functions [(build-function :variable function-type function-name :var-label var-label)])]\n    (merge base\n           (when fine-offset\n             {:fine-offset fine-offset}))))\n\n(defn- expand-function-spec\n  \"Expands the specification for a function at a particular starting\n  address. If a simple keyword was given for it, creates a map with\n  default contents for a variable-value range. A string is turned into\n  a keyword, but creates a fixed-value range. A nil specification is\n  expanded into a no-function range. Otherwise, adds any missing\n  pieces to the supplied map. In either case, assigns the range's\n  starting value.\"\n  [[start spec]]\n  (cond (keyword? spec)\n        {:start start\n         :range :variable\n         :type spec\n         :label (clojure.string/replace (csk/->Camel_Snake_Case (name spec)) \"_\" \" \")}\n\n        (string? spec)\n        {:start start\n         :range :fixed\n         :type (keyword (sanitize-name spec))\n         :label spec}\n\n        (nil? spec)\n        {:start start\n         :range :fixed\n         :type :no-function\n         :label \"No function\"}\n\n        (map? spec)\n        (merge {:range :variable\n                :label (clojure.string/replace (csk/->Camel_Snake_Case (name (:type spec))) \"_\" \" \")}\n               spec\n               {:start start})\n\n        :else\n        (throw (IllegalArgumentException.\n                (str \"Don't know how to build a function specification from \" spec)))))\n\n(defn- assign-ends\n  \"Used to figure out the ends of the ranges that make up a function\n  channel, by ending each range at the value one less than where the\n  next range begins.\"\n  [[current next]]\n  (if (= :end next)\n    (assoc current :end 255)\n    (let [end (dec (:start next))]\n      (when-not (<= 0 end 255)\n        (throw (IllegalArgumentException.\n                (str \"Function ends outside of legal DMX range: \" end))))\n      (if (< (:start current) end)\n        (assoc current :end end)\n        (if (= (:start current) end)\n          (assoc current :end end :range :fixed)\n          (throw (IllegalArgumentException.\n                  (str \"No range values available for function \" (:type current)))))))))\n\n(defn- expand-function-range\n  \"Expands a sequence of function ranges. If a sequence was passed for\n  the starting point, expands it, either appending a sequential index\n  to the spec (if it is a keyword or string), or pairing up successive\n  values if the spec is itself a sequence. The starting value and spec\n  pairs are then expanded in turn by calling expand-function-spec. If\n  start is not a sequence, expand-function-range simply delegates to\n  expand-function-spec.\"\n  [[start spec]]\n  (if (sequential? start)\n    (if (sequential? spec)\n      (map #(expand-function-spec [%1 %2]) start spec)\n      (map-indexed (fn [index start]\n                     (cond (string? spec)\n                           (expand-function-spec [start (str spec \" \" (inc index))])\n\n                           (keyword? spec)\n                           (expand-function-spec [start (keyword (str (name spec) \"-\" (inc index)))])\n\n                           :else\n                           (throw (IllegalArgumentException.\n                                   (str \"Don't know how to expand function range for spec \" spec)))))\n                   start))\n    [(expand-function-spec [start spec])]))\n\n(defn functions\n  \"Defines a channel whose values are divided up into different ranges\n  which perform different functions. After the channel type and DMX\n  offset, pass a list of starting values and function specifications.\n\n  The simplest form of specification is a keyword or string\n  identifying the function type; this will be expanded into a\n  variable-range (for keywords) or fixed-range (for strings) function\n  of that type.\n\n  For more complex functions, pass in a map containing the `:type`\n  keyword and any other settings you need to make (e.g. `:label`,\n  `:range`, `:var-label`), and the rest will be filled in for you.\n\n  To skip a range, pass `nil` for its specification.\n\n  The ranges need to be in order of increasing starting\n  values, and the ending values for each will be figured out by\n  context, e.g.\n\n  ```\n  (functions :strobe 40\n             0 nil\n             10 \\\"Strobe Random\\\"\n             20 :strobe)\n  ```\n\n  See the [Developer\n  Guide]({{guide-url}}fixture_definitions.html#function-channels) for\n  more details and examples.\"\n  [chan-type offset & functions]\n  {:pre [(some? chan-type) (integer? offset) (<= 1 offset 512)]}\n  (let [chan-type (keyword chan-type)]\n    (assoc (channel offset)\n           :type chan-type\n           :functions (vec (map assign-ends\n                                (partition 2 1 [:end] (mapcat expand-function-range\n                                                              (partition 2 functions))))))))\n\n(defn color-wheel-hue\n  \"Creates a function specification which identifies a color wheel\n  position with a particular hue, so it can participate in Afterglow's\n  color effects. The hue can be specified as a number,\n  a [jolby/colors](https://github.com/jolby/colors) object, or a\n  string which is passed to the jolby/colors `create-color` function.\n\n  The label to assign the function spec can be passed via the `:label`\n  optional keyword argument, or it will be inferred from the hue value\n  supplied. The function spec will be considered a fixed range unless\n  you specify `:range :variable`.\n\n  If hue is a sequence, then returns a sequence of the results of\n  calling `color-wheel-hue` on each of the elements in that sequence,\n  with the same optional arguments.\"\n  [hue & {:keys [range label] :or {range :fixed}}]\n  {:pre [(some? hue)]}\n  (if (sequential? hue)\n    (if (some? label)\n      (map #(color-wheel-hue % :range range :label label) hue)\n      (map #(color-wheel-hue % :range range) hue))\n    ;; Was not a sequence, so return a single function spec\n    (assoc (cond (number? hue)\n                 {:color-wheel-hue (colors/clamp-hue hue)\n                  :label (or label (str \"Color wheel hue \" (colors/clamp-hue hue)))\n                  :type (keyword (str \"color-wheel-hue-\" (colors/clamp-hue hue)))}\n\n                 (string? hue)\n                 {:color-wheel-hue (colors/hue (colors/create-color hue))\n                  :label (or label (str \"Color wheel hue \" hue))\n                  :type (keyword (str \"color-wheel-hue-\" hue))}\n\n                 (instance? com.evocomputing.colors/color hue)\n                 {:color-wheel-hue (colors/hue hue)\n                  :label (or label (str \"Color wheel hue \" hue))\n                  :type (keyword (str \"color-wheel-hue-\" (colors/hue hue)))}\n\n                 :else\n                 (throw (IllegalArgumentException.\n                         (str \"Don't know how to create hue from \" hue))))\n           :range range)))\n\n(defn dimmer\n  \"A channel which controls a dimmer.\n\n  Normal dimmers are dark at zero, and get brighter as the channel\n  value increases, to a maximum brightness at 255. However, some\n  fixtures have inverted dimmers. If that is the case, pass the DMX\n  value at which the inversion takes place with `:inverted-from`. For\n  example, fixtures which are brightest at zero and darken as the\n  value approaches 255 would be specified as `:inverted-from 0`, while\n  fixtures which are dark at zero, jump to maximum brightness at 1,\n  then dim as the value grows towards 255 would be specified as\n  `:inverted-from 1`.\n\n  If the fixture uses two-byte values for the dimmer level, pass\n  the offset of the channel containing the most-significant byte in\n  `offset`, and specify the offset of the channel containing the\n  least-significant byte with `:fine-offset`.\"\n  [offset & {:keys [inverted-from fine-offset]}]\n  (merge (fine-channel :dimmer offset :fine-offset fine-offset :range-label \"Intensity\")\n         (when inverted-from\n           {:inverted-from inverted-from})))\n\n(defn color\n  \"A channel which controls a color component. If `:hue` is supplied\n  along with a hue value, this channel will participate in color\n  mixing even if `color` is not one of the standard values `:red`,\n  `:green`, `:blue`, or `:white` whose hues and contributions to color\n  mixing are automatically understood.\n\n  By default, the function created for the channel uses the name of\n  the `color` keyword as its function label. Since this label is\n  displayed in the [web interface]({{guide-url}}README.html#web-ui) as\n  the text label in the cue grid cell for [Function\n  Cues]({{guide-url}}cues.html#creating-function-cues) created for the\n  function, you may wish to specify a more readable name, which you\n  can do by passing it in with `:function-label`.\n\n  If the fixture uses two-byte values for this color component, pass\n  the offset of the channel containing the most-significant byte in\n  `offset`, and specify the offset of the channel containing the\n  least-significant byte with `:fine-offset`.\"\n  [offset color & {:keys [hue function-label fine-offset]}]\n  {:pre [(some? color)]}\n  (let [color (keyword color)]\n    (-> (fine-channel :color offset :fine-offset fine-offset\n                      :function-type color :function-label (or function-label (clojure.string/capitalize (name color))))\n        (assoc :color (keyword color))\n        (cond-> hue (assoc :hue hue)))))\n\n(defn pan\n  \"A channel which pans a moving head, with an optional second channel\n  for fine control.\"\n  ([offset]\n   (pan offset nil))\n  ([offset fine-offset]\n   (fine-channel :pan offset :fine-offset fine-offset :var-label \"Pan\")))\n\n(defn tilt\n  \"A channel which tilts a moving head, with an optional second channel\n  for fine control.\"\n  ([offset]\n   (tilt offset nil))\n  ([offset fine-offset]\n   (fine-channel :tilt offset :fine-offset fine-offset :var-label \"Tilt\")))\n\n(defn focus\n  \"A channel which adjusts focus, with an optional second channel for\n  fine control.\"\n  ([offset]\n   (focus offset nil))\n  ([offset fine-offset]\n   (fine-channel :focus offset :fine-offset fine-offset :var-label \"Focus\")))\n\n(defn iris\n  \"A channel which controls an iris, with an optional second channel\n  for fine control.\"\n  ([offset]\n   (iris offset nil))\n  ([offset fine-offset]\n   (fine-channel :iris offset :fine-offset fine-offset :var-label \"Iris\")))\n\n(defn zoom\n  \"A channel which adjusts zoom, with an optional second channel for\n  fine control.\"\n  ([offset]\n   (zoom offset nil))\n  ([offset fine-offset]\n   (fine-channel :zoom offset :fine-offset fine-offset :var-label \"Zoom\")))\n\n(defn frost\n  \"A channel which adjusts frost, with an optional second channel for\n  fine control.\"\n  ([offset]\n   (frost offset nil))\n  ([offset fine-offset]\n   (fine-channel :frost offset :fine-offset fine-offset :var-label \"Frost\")))\n"
  },
  {
    "path": "src/afterglow/controllers/ableton_push.clj",
    "content": "(ns afterglow.controllers.ableton-push\n  \"Allows the Ableton Push to be used as a control surface for\n  Afterglow. Its features are described in the [Developer\n  Guide]({{guide-url}}push.html).\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.controllers :as controllers]\n            [afterglow.controllers.tempo :as tempo]\n            [afterglow.effects.cues :as cues]\n            [afterglow.effects.dimmer :refer [master-get-level master-set-level]]\n            [afterglow.midi :as amidi]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [with-show]]\n            [afterglow.util :as util]\n            [afterglow.version :as version]\n            [clojure.math.numeric-tower :as math]\n            [clojure.set :as set]\n            [clojure.string :as str]\n            [com.evocomputing.colors :as colors]\n            [overtone.at-at :as at-at]\n            [overtone.midi :as midi]\n            [taoensso.timbre :as timbre])\n  (:import [java.util Arrays]\n           [javax.sound.midi ShortMessage]))\n\n(defn velocity-for-color\n  \"Given a target color, calculate the MIDI note velocity which will\n  achieve the closest approximation available on an Ableton Push\n  pad, using the thoughtful hue palette provided by Ableton:\n\n  ![Push pad palette](https://deepsymmetry.org/afterglow/research/PushColors.jpg)\"\n  [color]\n  {:pre [(= (type color) :com.evocomputing.colors/color)]}\n  ;; Each hue section starts with a lightened version\n  ;; of the hue, then a bright, medium, and dim version\n  ;; of the fully-saturated hue.\n  (let [brightness-shift (condp < (colors/lightness color)\n                           60 0\n                           37 1\n                           15 2\n                           3)]\n    (cond (< (colors/lightness color) 3)\n          ;; The color is effectively black.\n          0\n\n          ;; The color is effectively gray, so map it to the grayscale\n          ;; section, which ranges from black at zero, through white as\n          ;; three.\n          (< (colors/saturation color) 20)\n          (min 3 (- 4 brightness-shift))\n\n          ;; Find the note value that approximates the hue and lightness.\n          ;; From note 4 to note 59, the pads are in groups of four for\n          ;; a single hue, starting with the lightened version, then\n          ;; the bright, medium, and dim versions.\n          :else\n          (let [base-hue (colors/hue color)\n                ;; Hue to velocity gets a little non-linear at blue; tweak to look right.\n                adjusted-hue (if (> base-hue 230)\n                               (min 360 (* base-hue 1.2))\n                               base-hue)\n                hue-section (+ 4 (* 4 (math/floor (* 13 (/ adjusted-hue 360)))))]\n            (int (+ hue-section brightness-shift))))))\n\n(defonce ^{:doc \"The color of buttons that are completely off.\"}\n  off-color (colors/create-color :black))\n\n(defn set-pad-velocity\n  \"Set the velocity of one of the 64 touch pads.\"\n  [controller x y velocity]\n  {:pre [(<= 0 x 7) (<= 0 y 7)]}\n  (let [note (+ 36 x (* y 8))]  ;; Calculate note from grid coordinates\n    (midi/midi-note-on (:port-out controller) note velocity)))\n\n(defn set-pad-color-approximate\n  \"*Deprecated in favor of new [[set-pad-color]] implementation.*\n\n  Set the color of one of the 64 touch pads to the closest\n  approximation available for a desired color. This was the first\n  implementation that was discovered, but there is now a much more\n  powerful way to specify an exact color using a SysEx message.\"\n  {:deprecated \"0.1.4\"}\n  [controller x y color]\n  (set-pad-velocity controller x y (velocity-for-color color)))\n\n(defn set-pad-color\n  \"Set the color of one of the 64 touch pads to a specific RGB\n  color.\"\n  [controller x y color]\n  (let [pad (+ x (* y 8))\n        r (colors/red color)\n        g (colors/green color)\n        b (colors/blue color)]\n    (midi/midi-sysex (:port-out controller) [240 71 127 21 4 0 8 pad 0\n                                             (quot r 2r10000) (bit-and r 2r1111)\n                                             (quot g 2r10000) (bit-and g 2r1111)\n                                             (quot b 2r10000) (bit-and b 2r1111)\n                                             247])))\n\n(def monochrome-button-states\n  \"The control values and modes for a labeled button which does not\n  change color.\"\n  {:off 0 :dim 1 :dim-slow-blink 2 :dim-fast-blink 3\n   :bright 4 :bright-slow-blink 5 :bright-fast-blink 6})\n\n(def color-button-colors\n  \"The control values and modes for a labeled button which changes\n  color. These are added to the monochrome states (except for off)\n  to obtain the color and brightness/behavior.\"\n  {:red 0 :amber 6 :yellow 12 :green 18})\n\n(def control-buttons\n  \"The labeled buttons which send and respond to Control Change\n  events.\"\n  {:tap-tempo             {:control 3 :kind :monochrome}\n   :metronome             {:control 9 :kind :monochrome}\n\n   :master                {:control 28 :kind :monochrome}\n   :stop                  {:control 29 :kind :monochrome}\n\n   :quarter               {:control 36 :kind :color}\n   :quarter-triplet       {:control 37 :kind :color}\n   :eighth                {:control 38 :kind :color}\n   :eighth-triplet        {:control 39 :kind :color}\n   :sixteenth             {:control 40 :kind :color}\n   :sixteenth-triplet     {:control 41 :kind :color}\n   :thirty-second         {:control 42 :kind :color}\n   :thirty-second-triplet {:control 43 :kind :color}\n\n   :left-arrow            {:control 44 :kind :monochrome}\n   :right-arrow           {:control 45 :kind :monochrome}\n   :up-arrow              {:control 46 :kind :monochrome}\n   :down-arrow            {:control 47 :kind :monochrome}\n\n   :select                {:control 48 :kind :monochrome}\n   :shift                 {:control 49 :kind :monochrome}\n   :note                  {:control 50 :kind :monochrome}\n   :session               {:control 51 :kind :monochrome}\n   :add-device            {:control 52 :kind :monochrome}\n   :add-track             {:control 53 :kind :monochrome}\n\n   :octave-down           {:control 54 :kind :monochrome}\n   :octave-up             {:control 55 :kind :monochrome}\n   :repeat                {:control 56 :kind :monochrome}\n   :accent                {:control 57 :kind :monochrome}\n   :scales                {:control 58 :kind :monochrome}\n   :user-mode             {:control 59 :kind :monochrome}\n   :mute                  {:control 60 :kind :monochrome}\n   :solo                  {:control 61 :kind :monochrome}\n   :in                    {:control 62 :kind :monochrome}\n   :out                   {:control 63 :kind :monochrome}\n\n   :play                  {:control 85 :kind :monochrome}\n   :record                {:control 86 :kind :monochrome}\n   :new                   {:control 87 :kind :monochrome}\n   :duplicate             {:control 88 :kind :monochrome}\n   :automation            {:control 89 :kind :monochrome}\n   :fixed-length          {:control 90 :kind :monochrome}\n\n   :device-mode           {:control 110 :kind :monochrome}\n   :browse-mode           {:control 111 :kind :monochrome}\n   :track-mode            {:control 112 :kind :monochrome}\n   :clip-mode             {:control 113 :kind :monochrome}\n   :volume-mode           {:control 114 :kind :monochrome}\n   :pan-send-mode         {:control 115 :kind :monochrome}\n\n   :quantize              {:control 116 :kind :monochrome}\n   :double                {:control 117 :kind :monochrome}\n   :delete                {:control 118 :kind :monochrome}\n   :undo                  {:control 119 :kind :monochrome}})\n\n(def special-symbols\n  \"The byte values which draw special-purpose characters on the Push\n  display.\"\n  {:up-arrow            (byte 0)\n   :down-arrow          (byte 1)\n   :pancake             (byte 2)\n   :fader-left          (byte 3)\n   :fader-right         (byte 4)\n   :fader-center        (byte 5)\n   :fader-empty         (byte 6)\n   :folder              (byte 7)\n   :split-vertical-line (byte 8)\n   :degree              (byte 9)\n   :ellipsis            (byte 28)\n   :solid-block         (byte 29)\n   :right-arrow         (byte 30)\n   :left-arrow          (byte 31)\n   :selected-triangle   (byte 127)})\n\n(defn button-state\n  \"Calculate the numeric value that corresponds to a particular\n  named state for the specified button, and (if supported and\n  supplied), a named color.\"\n  ([button state]\n   (button-state button state :amber))\n  ([button state color-key]\n   (let [base-value ((keyword state) monochrome-button-states)\n         color-shift (or (when (and (= (:kind button) :color)\n                                    (not= state :off))\n                           ((keyword color-key) color-button-colors))\n                         0)]\n     (+ base-value color-shift))))\n\n(defn set-button-state\n  \"Set one of the labeled buttons to a particular state, and, if\n  supported, color. If the state is already a number, it is used\n  as-is, otherwise it is calculated using button-state.\"\n  ([controller button state]\n   (set-button-state controller button state :amber))\n  ([controller button state color-key]\n   (let [state (if (number? state)\n                 state\n                 (button-state button state color-key))]\n     (midi/midi-control (:port-out controller) (:control button) state))))\n\n(defn top-pad-state\n  \"Calculate the numeric value that corresponds to a particular\n  named state for the specified top-row pad, and (if supplied),\n  named color.\"\n  ([state]\n   (top-pad-state state :amber))\n  ([state color-key]\n   (let [base-value ((keyword state) monochrome-button-states)\n         color-shift (or (when-not (= state :off)\n                           ((keyword color-key) color-button-colors))\n                         0)]\n     (+ base-value color-shift))))\n\n(defn set-top-pad-state\n  \"Set one of the top-row pads to a particular state and color.\n  If state is already a number, it is used as-is, otherwise it is\n  calculated using top-pad-state.\"\n  ([controller x state]\n   (set-top-pad-state controller x state :amber))\n  ([controller x state color-key]\n   {:pre [(<= 0 x 7)]}\n   (let [state (if (number? state)\n                 state\n                 (top-pad-state state color-key))]\n     (midi/midi-control (:port-out controller) (+ x 20) state))))\n\n(defn set-second-pad-color\n  \"Set the color of one of the 8 second-row touch pads (right above\n  the 8x8 pad of larger, velocity sensitive, pads) to the closest\n  approximation available for a desired color.\"\n  [controller x color]\n  {:pre [(<= 0 x 7)]}\n  (let [control (+ 102 x)]  ;; Calculate controller number\n    (midi/midi-control (:port-out controller) control (velocity-for-color color))))\n\n(defn set-display-line\n  \"Sets a line of the text display.\"\n  [controller line bytes]\n  {:pre [(<= 0 line 3)]}\n  (let [message (concat [240 71 127 21 (+ line 24) 0 69 0]\n                        (take 68 (concat (map int bytes) (repeat 32)))\n                        [247])]\n    (midi/midi-sysex (:port-out controller) message)))\n\n(defn clear-display-line\n  \"Clears a line of the text display.\"\n  [controller line]\n  {:pre [(<= 0 line 3)]}\n  (midi/midi-sysex (:port-out controller) [240 71 127 21 (+ line 28) 0 0 247]))\n\n(defn show-labels\n  \"Illuminates all buttons with text labels, for development assistance.\"\n  ([controller]\n   (show-labels controller :bright :amber))\n  ([controller state]\n   (show-labels controller state :amber))\n  ([controller state color]\n   (doseq [[_ button] control-buttons]\n     (set-button-state controller button state color))))\n\n(defn- update-text\n  \"Sees if any text has changed since the last time the display\n  was updated, and if so, sends the necessary MIDI SysEx values\n  to update it on the Push.\"\n  [controller]\n  (doseq [row (range 4)]\n    (when-not (Arrays/equals (get (:next-display controller) row)\n                             (get (:last-display controller) row))\n      (set-display-line controller row (get (:next-display controller) row))\n      (System/arraycopy (get (:next-display controller) row) 0\n                        (get (:last-display controller) row) 0 68))))\n\n(defn- update-top-pads\n  \"Sees if any of the top row of pads have changed state since\n  the interface was updated, and if so, sends the necessary MIDI\n  control values to update them on the Push.\"\n  [controller]\n  (doseq [x (range 8)]\n    (let [next-state (aget (:next-top-pads controller) x)]\n      (when (not= next-state\n                  (aget (:last-top-pads controller) x))\n        (set-top-pad-state controller x next-state)\n        (aset (:last-top-pads controller) x next-state)))))\n\n(def touch-strip-mode-default\n  \"The mode to which we should return the touch strip when we are\n  shutting down.\"\n  5)\n\n(def touch-strip-mode-level\n  \"The mode to which we should set the touch strip when the user is\n  editing a pan-style control.\"\n  1)\n\n(def touch-strip-mode-pan\n  \"The mode to which we should set the touch strip when the user is\n  editing a level-style control.\"\n  2)\n\n(def touch-strip-mode-hue\n  \"The mode to which we should set the touch strip when the user is\n  editing a hue.\"\n  3)\n\n(defn- set-touch-strip-mode\n  \"Set the touch strip operating mode.\"\n  [controller mode]\n  (midi/midi-sysex (:port-out controller) [240 71 127 21 99 0 1 mode 247]))\n\n(defn- update-touch-strip\n  \"Sees if the state of the touch strip has changed since the\n  interface was updated, and if so, sends the necessary MIDI control\n  values to update it on the Push.\"\n  [controller]\n  (let [next-strip @(:next-touch-strip controller)\n        [_ last-mode] @(:last-touch-strip controller)]\n    (when (not= next-strip @(:last-touch-strip controller))\n      (if next-strip\n        (let [[value mode] next-strip\n              message (ShortMessage.)]\n          (if (not= mode last-mode)\n            (do  ; When changing mode, we have to wait until the next frame to update the value.\n              (set-touch-strip-mode controller mode)\n              (reset! (:last-touch-strip controller) [nil mode]))\n            (do\n              (.setMessage message ShortMessage/PITCH_BEND 0 (rem value 128) (quot value 128))\n              (midi/midi-send-msg (get-in controller [:port-out :receiver]) message -1)\n              (reset! (:last-touch-strip controller) next-strip))))\n        (do\n          (set-touch-strip-mode controller touch-strip-mode-default)\n          (reset! (:last-touch-strip controller) nil))))))\n\n(defn- set-touch-strip-from-value\n  \"Display a value being adjusted in the touch strip.\"\n  [controller value low high mode]\n  (let [full-range (- high low)]\n    (reset! (:next-touch-strip controller) [(math/round (* 16383 (/ (- value low) full-range))) mode])))\n\n(defn- set-touch-strip-from-cue-var\n  \"Display the value of a variable being adjusted in the touch strip.\"\n  [controller cue v effect-id]\n  (let [value (or (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id) 0)\n        low (min value (:min v))  ; In case user set \"out of bounds\".\n        high (max value (:max v))]\n    (set-touch-strip-from-value controller value low high (if (:centered v)\n                                                            touch-strip-mode-pan\n                                                            touch-strip-mode-level))))\n\n(defn- value-from-touch-strip\n  \"Convert a pitch bend message from the touch strip to the\n  corresponding variable value it represents.\"\n  [message low high]\n  (let [full-range (- high low)]\n    (+ low (* full-range (double (/ (+ (* (:data2 message) 128) (:data1 message)) 16383))))))\n\n(defn- update-text-buttons\n  \"Sees if any labeled buttons have changed state since the last time\n  the interface was updated, and if so, sends the necessary MIDI\n  control values to update them on the Push.\"\n  [controller]\n  ;; First turn off any which were on before but no longer are\n  (doseq [[button old-state] @(:last-text-buttons controller)]\n    (when-not (get @(:next-text-buttons controller) button)\n      (when-not (#{0 :off} old-state)\n        (set-button-state controller button :off))))\n\n  ;; Then, set any currently requested states\n  (doseq [[button state] @(:next-text-buttons controller)]\n    (when-not (= (get @(:last-text-buttons controller) button) state)\n      (set-button-state controller button state)))\n\n  ;; And record the new state for next time\n  (reset! (:last-text-buttons controller) @(:next-text-buttons controller)))\n\n(defn- get-safe-text-byte\n  \"Converts a character to be displayed to a byte, but if it is\n  outside the range that can be displayed by the Push, like Unicode,\n  then change it to a byte representing an ellipsis.\"\n  [c]\n  (let [i (int c)]\n    (if (> i 127)\n      (:ellipsis special-symbols)\n      i)))\n\n(defn write-display-text\n  \"Update a batch of characters within the display to be rendered on\n  the next update.\"\n  [controller row start text]\n  {:pre [(<= 0 row 3) (<= 0 start 67)]}\n  (let [bytes (map get-safe-text-byte text)]\n    (doseq [[i val] (map-indexed vector bytes)]\n      (aset (get (:next-display controller) row) (+ start i) (util/ubyte val)))))\n\n(defn- write-display-cell\n  \"Update a single text cell (of which there are four per row) in the\n  display to be rendered on the next update.\"\n  [controller row cell text]\n  {:pre [(<= 0 row 3) (<= 0 cell 3)]}\n  (let [bytes (take 17 (concat (map get-safe-text-byte text) (repeat 32)))]\n    (doseq [[i val] (map-indexed vector bytes)]\n      (aset (get (:next-display controller) row) (+ (* cell 17) i) (util/ubyte val)))))\n\n(defn make-gauge\n  \"Create a graphical gauge with an indicator that fills a line.\n  The default range is from zero to a hundred, and the default size is\n  17 characters, or a full display cell.\"\n  [value & {:keys [lowest highest width] :or {lowest 0 highest 100 width 17}}]\n  (let [range (- highest lowest)\n        scaled (int (* 2 width (/ (- value lowest) range)))\n        marker ((if (< (- value lowest) 0.1)\n                  :fader-empty\n                  (if (even? scaled) :fader-left :fader-center))\n                special-symbols)\n        leader (take (int (/ scaled 2)) (repeat (:fader-center special-symbols)))]\n    (take width (concat leader [marker] (repeat (:fader-empty special-symbols))))))\n\n(defn make-pan-gauge\n  \"Create a graphical gauge with an indicator that moves along a line.\n  The default range is from zero to a hundred, and the default size is\n  17 characters, or a full display cell.\"\n  [value & {:keys [lowest highest width] :or {lowest 0 highest 100 width 17}}]\n  (let [range (* 1.01 (- highest lowest))\n        midpoint (/ (- highest lowest) 2)\n        scaled (int (* 2 width (/ (- value lowest) range)))\n        filler (repeat (:fader-empty special-symbols))\n        centered (< (math/abs (- (- value lowest) midpoint)) (/ range 256))\n        marker ((if (and centered (odd? width))\n                  :fader-center\n                  (if (even? scaled) :fader-left :fader-right))\n                special-symbols)\n        leader (if (and centered (even? width) (even? scaled))\n                 (concat (take (dec (int (/ scaled 2))) filler) [(:fader-right special-symbols)])\n                 (take (int (/ scaled 2)) filler))]\n    (take width (concat leader [marker]\n                        (when (and centered (even? width) (odd? scaled)) [(:fader-left special-symbols)])\n                        filler))))\n\n(defn- metronome-sync-label\n  \"Determine the sync type label to display under the BPM section.\"\n  [controller]\n  (with-show (:show controller)\n    (case (:type (show/sync-status))\n      :manual \" Manual\"\n      :midi \"  MIDI\"\n      :dj-link \"DJ Link\"\n      :traktor-beat-phase \"Traktor\"\n      \"Unknown\")))\n\n(defn- metronome-sync-color\n  \"Determine the color to light the sync pad under the BPM section.\"\n  [controller]\n  (with-show (:show controller)\n    (if (= (:type (show/sync-status)) :manual)\n      :amber\n      (if (:current (show/sync-status))\n        :green\n        :red))))\n\n(defn- update-mode!\n  \"Turn a controller mode on or off, identified by the associated\n  control button number or keyword.\"\n  [controller button state]\n  (let [button (if (keyword? button) (get-in control-buttons [button :control]) button)]\n    (swap! (:modes controller) #(if state (conj % button) (disj % button)))))\n\n(defn in-mode?\n  \"Check whether the controller is in a particular mode, identified by\n  a control button number or keyword.\"\n  [controller button]\n  (let [button (if (keyword? button) (get-in control-buttons [button :control]) button)]\n    (get @(:modes controller) button)))\n\n(defn- bpm-adjusting-interface\n  \"Add an arrow showing the BPM is being adjusted, or point out that\n  it is being externally synced.\"\n  [controller snapshot]\n  (if (= (:type (show/sync-status)) :manual)\n    (let [arrow-pos (if (in-mode? controller :shift) 14 16)\n          bpm (double (:bpm snapshot))]\n      (aset (get (:next-display controller) 2) arrow-pos (:up-arrow special-symbols))\n      (set-touch-strip-from-value controller bpm controllers/minimum-bpm controllers/maximum-bpm 1))\n    (do\n      (aset (get (:next-display controller) 2) 9 (:down-arrow special-symbols))\n      (when-not (:showing @(:metronome-mode controller))\n        ;; We need to display the sync mode in order to point at it\n        (write-display-cell controller 3 0\n                            (str \"         \" (metronome-sync-label controller)))))))\n\n(defn sign-velocity\n  \"Convert a midi velocity to its signed equivalent, to translate\n  encoder rotations, which are twos-complement seven bit numbers.\"\n  [val]\n   (if (>= val 64)\n     (- val 128)\n     val))\n\n(defn- adjust-bpm-from-encoder\n  \"Adjust the current BPM based on how the encoder was twisted, unless\n  the metronome is synced.\"\n  [controller message]\n  (with-show (:show controller)\n    (when (= (:type (show/sync-status)) :manual)\n      (let [scale (if (in-mode? controller :shift) 1 10)\n            delta (/ (sign-velocity (:velocity message)) scale)\n            bpm (rhythm/metro-bpm (:metronome (:show controller)))]\n        (rhythm/metro-bpm (:metronome (:show controller)) (min controllers/maximum-bpm\n                                                               (max controllers/minimum-bpm (+ bpm delta))))))))\n\n(defn- encoder-above-bpm-touched\n  \"Add a user interface overlay to give feedback when turning the\n  encoder above the BPM display when metronome was already active,\n  since it is easy to grab that one rather than the actual BPM\n  encoder, being right above the display.\"\n  [controller]\n  (controllers/add-overlay (:overlays controller)\n               (reify controllers/IOverlay\n                 (captured-controls [_this] #{72})\n                 (captured-notes [_this] #{1 9})\n                 (adjust-interface [_this snapshot]\n                   (bpm-adjusting-interface controller snapshot)\n                   true)\n                 (handle-control-change [_this message]\n                   (adjust-bpm-from-encoder controller message))\n                 (handle-note-on [_this  _message]\n                   ;; Suppress the actual BPM encoder while we are active.\n                   true)\n                 (handle-note-off [_this message]\n                   (when (= (:note message) 1)\n                     ;; They released us, end the overlay.\n                     :done))\n                 (handle-aftertouch [_this _message])\n                 (handle-pitch-bend [_this message]\n                   (rhythm/metro-bpm (:metronome (:show controller))\n                                                 (value-from-touch-strip message controllers/minimum-bpm\n                                                                         controllers/maximum-bpm))))))\n\n(defn- beat-adjusting-interface\n  \"Add an arrow showing the beat is being adjusted.\"\n  [controller]\n  (let [marker (rhythm/metro-marker (:metronome (:show controller)))\n                         arrow-pos (if (in-mode? controller :shift)\n                                     (dec (.indexOf marker \".\" (inc (.indexOf marker \".\"))))\n                                     (dec (count marker)))]\n    (aset (get (:next-display controller) 2) arrow-pos (:up-arrow special-symbols))))\n\n(defn- adjust-beat-from-encoder\n  \"Adjust the current beat based on how the encoder was twisted.\"\n  [controller message]\n  (let [delta (sign-velocity (:velocity message))\n        metronome (:metronome (:show controller))\n        units (if (in-mode? controller :shift)\n                ;; User is adjusting the current bar\n                (rhythm/metro-tock metronome)\n                ;; User is adjusting the current beat\n                (rhythm/metro-tick metronome))\n        ms-delta (- (* delta units))]\n    (rhythm/metro-adjust metronome ms-delta)))\n\n(defn- encoder-above-beat-touched\n  \"Add a user interface overlay to give feedback when turning the\n  encoder above the beat display when metronome was already active,\n  since it is easy to grab that one rather than the actual beat\n  encoder, being right above the display.\"\n  [controller]\n  (controllers/add-overlay (:overlays controller)\n               (reify controllers/IOverlay\n                 (captured-controls [_this] #{71})\n                 (captured-notes [_this] #{0 10})\n                 (adjust-interface [_this _]\n                   (beat-adjusting-interface controller))\n                 (handle-control-change [_this message]\n                   (adjust-beat-from-encoder controller message))\n                 (handle-note-on [_this _message]\n                   ;; Suppress the actual beat encoder while we are active.\n                   true)\n                 (handle-note-off [_this message]\n                   (when (zero? (:note message))\n                     ;; They released us, end the overlay.\n                     :done))\n                 (handle-aftertouch [_this _message])\n                 (handle-pitch-bend [_this _message]))))\n\n(defn- enter-metronome-showing\n  \"Activate the persistent metronome display, with sync and reset pads\n  illuminated.\"\n  [controller]\n  (swap! (:metronome-mode controller) assoc :showing true)\n  (controllers/add-overlay (:overlays controller)\n               (reify controllers/IOverlay\n                 (captured-controls [_this] #{3 9 20 21})\n                 (captured-notes [_this] #{0 1})\n                 (adjust-interface [_this _]\n                   ;; Make the metronome button bright, since its information is active\n                   (swap! (:next-text-buttons controller)\n                          assoc (:metronome control-buttons)\n                          (button-state (:metronome control-buttons) :bright))\n\n                   ;; Add the labels for reset and sync, and light the pads\n                   (write-display-cell controller 3 0\n                                       (str \" Reset   \" (metronome-sync-label controller)))\n                   (aset (:next-top-pads controller) 0 (top-pad-state :dim :red))\n                   (aset (:next-top-pads controller) 1 (top-pad-state :dim (metronome-sync-color controller))))\n                 (handle-control-change [_this message]\n                   (case (:note message)\n                     3 ; Tap tempo button\n                     (when (pos? (:velocity message))\n                       ((:tempo-tap-handler controller))\n                       true)\n\n                     9 ; Metronome button\n                     (when (pos? (:velocity message))\n                       (swap! (:metronome-mode controller) dissoc :showing)\n                       ;; Exit the overlay\n                       :done)\n\n                     20 ; Reset pad\n                     (when (pos? (:velocity message))\n                       (rhythm/metro-phrase-start (:metronome (:show controller)) 1)\n                       (controllers/add-control-held-feedback-overlay (:overlays controller) 20\n                                                                      (fn [_] (aset (:next-top-pads controller)\n                                                                                    0 (top-pad-state :bright :red))))\n                       true)\n                     21 ; Sync pad\n                     (when (pos? (:velocity message))\n                       ;; TODO: Actually implement a new overlay\n                       (controllers/add-control-held-feedback-overlay\n                        (:overlays controller) 21 (fn [_] (aset (:next-top-pads controller)\n                                                                1 (top-pad-state :bright\n                                                                                 (metronome-sync-color controller)))))\n                       true)))\n                 (handle-note-on [_this message]\n                   ;; Whoops, user grabbed encoder closest to beat or BPM display\n                   (case (:note message)\n                     0 (encoder-above-beat-touched controller)\n                     1 (encoder-above-bpm-touched controller))\n                   true)\n                 (handle-note-off [_this _message]\n                   false)\n                 (handle-aftertouch [_this _message])\n                 (handle-pitch-bend [_this _message]))))\n\n(defn- new-beat?\n  \"Returns true if the metronome is reporting a different marker\n  position than the last time this function was called.\"\n  [controller marker]\n  (when (not= marker @(:last-marker controller))\n    (reset! (:last-marker controller) marker)))\n\n(defn- update-metronome-section\n  \"Updates the sections of the interface related to metronome\n  control.\"\n  [controller snapshot]\n  (let [marker (rhythm/snapshot-marker snapshot)\n        metronome-button (:metronome control-buttons)\n        tap-tempo-button (:tap-tempo control-buttons)\n        metronome-mode @(:metronome-mode controller)]\n    ;; Is the first cell reserved for metronome information?\n    (if (seq metronome-mode)\n      ;; Draw the beat and BPM information\n      (let [bpm (format \"%.1f\" (double (:bpm snapshot)))\n            chars (+ (count marker) (count bpm))\n            padding (str/join (take (- 17 chars) (repeat \" \")))]\n        (write-display-cell controller 1 0 (str marker padding bpm))\n        (write-display-cell controller 0 0 \"Beat        BPM  \")\n\n        ;; Make the metronome button bright, since some overlay is present\n        (swap! (:next-text-buttons controller)\n               assoc metronome-button\n               (button-state metronome-button :bright)))\n\n      ;; The metronome section is not active, so make its button dim\n      (swap! (:next-text-buttons controller)\n             assoc metronome-button (button-state metronome-button :dim)))\n\n    ;; Regardless, flash the tap tempo button on beats\n    (swap! (:next-text-buttons controller)\n           assoc tap-tempo-button\n           (button-state tap-tempo-button\n                         (if (or (new-beat? controller marker) (< (rhythm/snapshot-beat-phase snapshot) 0.15))\n                           :bright :dim)))))\n\n(defn- render-cue-grid\n  \"Figure out how the cue grid pads should be illuminated, based on the\n  currently active cues and our current point in musical time.\"\n  [controller snapshot]\n  (let [[origin-x origin-y] @(:origin controller)\n        active-keys (show/active-effect-keys (:show controller))]\n    (doseq [x (range 8)\n            y (range 8)]\n      (let [[cue active] (show/find-cue-grid-active-effect (:show controller) (+ x origin-x) (+ y origin-y))\n            ending (and active (:ending active))\n            base-color (when cue (cues/current-cue-color cue active (:show controller) snapshot))\n            l-boost (when base-color (if (zero? (colors/saturation base-color)) 20.0 0.0))\n            color (when base-color\n                    (colors/create-color\n                     :h (colors/hue base-color)\n                     :s (colors/saturation base-color)\n                     ;; Figure the brightness. Active, non-ending cues are full brightness;\n                     ;; when ending, they blink between middle and low. If they are not active,\n                     ;; they are at middle brightness unless there is another active effect with\n                     ;; the same keyword, in which case they are dim.\n                     :l (+ (if active\n                             (if ending\n                               (if (> (rhythm/snapshot-beat-phase snapshot) 0.4) 6 22)\n                               55)\n                             (if (or (active-keys (:key cue))\n                                     (seq (set/intersection active-keys (set (:end-keys cue))))) 6 22))\n                           l-boost)))]\n        (aset (:next-grid-pads controller) (+ x (* y 8)) (or color off-color))))))\n\n(defn- update-cue-grid\n  \"See if any of the cue grid button states have changed, and send any\n  required updates.\"\n  [controller]\n  (doseq [x (range 8)\n          y (range 8)]\n    (let [index (+ x (* y 8))\n          color (aget (:next-grid-pads controller) index)]\n      (when-not (= color (aget (:last-grid-pads controller) index))\n        (set-pad-color controller x y color)\n        (aset (:last-grid-pads controller) index color)))))\n\n(defn- cue-vars-for-encoders\n  \"Find the correct cue variables that correspond to each of the two\n  encoders within a cue's display region, given the cue's variable\n  list and the offset by which the user has shifted the cue\n  variables.\"\n  [cue-vars var-offset]\n  (case (count cue-vars)\n    0 nil ; No variables to adjust\n    1 (vec (repeat 2 (first cue-vars)))\n    (vec (take 2 (drop var-offset (apply concat (repeat cue-vars)))))))\n\n(defn- fit-cue-variable-name\n  \"Picks the best version of a cue variable name to fit in the specified\n  number of characters, then truncates it if necessary.\"\n  [v len]\n  (let [longer (or (:name v) (name (:key v)))\n        shorter (or (:short-name v) longer)\n        padding (str/join (repeat len \" \"))]\n    (if (<= (count longer) len)\n      (str/join (take len (str longer padding)))\n      (str/join (take len (str shorter padding))))))\n\n(defn- cue-variable-names\n  \"Determines the names of adjustable variables to display under an\n  active cue.\"\n  [controller cue effect-id]\n  (let [cue-vars (cue-vars-for-encoders (:variables cue) (get @(:cue-var-offsets controller) effect-id 0))]\n    (if (seq cue-vars)\n      (if (= (count (:variables cue)) 1)\n        (fit-cue-variable-name (first cue-vars) 17)\n        (str (fit-cue-variable-name (first cue-vars) 8) \" \"\n             (fit-cue-variable-name (second cue-vars) 8)))\n      \"\")))\n\n(defn- fit-cue-variable-value\n  \"Truncates the current value of a cue variable to fit available\n  space.\"\n  [controller cue v len effect-id]\n  (let [val (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id)\n        formatted (if (some? val)\n                    (cond\n                      (= (:type v) :integer)\n                      (int val)\n\n                      (or (= (type val) :com.evocomputing.colors/color) (= (:type v) :color))\n                      (colors/rgb-hexstr val)\n\n                      (or (= (type val) Boolean) (= (:type v) :boolean))\n                      (if val \"Yes\" \"No\")\n\n                      ;; If we don't know what else to do, at least turn ratios to doubles\n                      :else\n                      (double val))\n\n                    ;; We got no value, display an ellipsis\n                    \"...\")\n        padding (str/join (repeat len \" \"))]\n    (str/join (take len (str formatted padding)))))\n\n(defn- cue-variable-values\n  \"Formats the current values of the adjustable variables to display\n  under an active cue.\"\n  [controller cue effect-id]\n  (let [cue-vars (cue-vars-for-encoders (:variables cue) (get @(:cue-var-offsets controller) effect-id 0))]\n    (if (seq cue-vars)\n      (if (= (count (:variables cue)) 1)\n        (fit-cue-variable-value controller cue (first cue-vars) 17 effect-id)\n        (str (fit-cue-variable-value controller cue (first cue-vars) 8 effect-id) \" \"\n             (fit-cue-variable-value controller cue (second cue-vars) 8 effect-id)))\n      \"\")))\n\n(defn- room-for-effects\n  \"Determine how many display cells are available for displaying\n  effect information.\"\n  [controller]\n  (if (seq @(:metronome-mode controller)) 3 4))\n\n(defn- find-effect-offset-range\n  \"Determine the valid offset range for scrolling through the effect\n  list, based on how many effects are running, and how many currently\n  fit on the display. If we are currently scrolled beyond the sensible\n  range, correct that. Returns a tuple of the current offset, the\n  maximum sensible offset, and the number of effects displayed.\"\n  [controller]\n  (let [room (room-for-effects controller)\n        size (count (:effects @(:active-effects (:show controller))))\n        max-offset (max 0 (- size room))\n        ;; If we are offset more than now makes sense, fix that.\n        offset (swap! (:effect-offset controller) min max-offset)]\n    [offset max-offset room]))\n\n(defn- update-effect-list\n  \"Display information about the four most recently activated\n  effects (or three, if the metronome is taking up a slot).\"\n  [controller]\n\n  ;; First clean up any cue variable scroll offsets for effects that have ended\n  (swap! (:cue-var-offsets controller) select-keys (map :id (:meta @(:active-effects (:show controller)))))\n\n  ;; Then adjust our scroll offset if it no longer makes sense\n  (find-effect-offset-range controller)\n\n  (let [room        (room-for-effects controller)\n        first-cell  (- 4 room)\n        fx-info     @(:active-effects (:show controller))\n        fx          (:effects fx-info)\n        fx-meta     (:meta fx-info)\n        num-skipped (- (count fx-meta) room @(:effect-offset controller))]\n    (if (seq fx)\n      (do (loop [fx      (take room (drop num-skipped fx))\n                 fx-meta (take room (drop num-skipped fx-meta))\n                 x       first-cell]\n            (let [info        (first fx-meta)\n                  ending      ((:key info) (:ending fx-info))\n                  cue         (:cue info)\n                  end-label   (if ending \" Ending  \" \"  End    \")\n                  scroll-vars (> (count (:variables cue)) 2)\n                  more-label  (when scroll-vars (concat \" More \" [(:right-arrow special-symbols)]))\n                  cur-vals    (when cue (cues/snapshot-cue-variables cue (:id info) :show (:show controller)))\n                  saved-vals  (controllers/cue-vars-saved-at (:cue-grid (:show controller)) (:x info) (:y info))\n                  save-action (when (seq cur-vals)\n                                (if (seq saved-vals)\n                                  (if (= cur-vals saved-vals) :clear :save)\n                                  (when (not= cur-vals (:starting-vars info))\n                                    :save)))\n                  save-label  (case save-action\n                                :save  \"  Save   \"\n                                :clear \" Clear   \"\n                                \"         \")]\n              (write-display-cell controller 0 x (cue-variable-names controller cue (:id info)))\n              (write-display-cell controller 1 x (cue-variable-values controller cue (:id info)))\n              (write-display-cell controller 2 x (or (:name cue) (:name (first fx))))\n              (write-display-cell controller 3 x (concat (if (in-mode? controller :record) save-label end-label)\n                                                         more-label))\n              (if (in-mode? controller :record)\n                (when save-action\n                  (aset (:next-top-pads controller) (* 2 x)\n                        (top-pad-state :dim (case save-action\n                                              :save :green\n                                              :clear :amber))))\n                (aset (:next-top-pads controller) (* 2 x) (top-pad-state :dim :red)))\n              (when scroll-vars (aset (:next-top-pads controller) (inc (* 2 x)) (top-pad-state :dim :amber)))\n              (when (seq (rest fx))\n                (recur (rest fx) (rest fx-meta) (inc x)))))\n          ;; Draw indicators if there are effects hidden from view in either direction\n          (when (pos? num-skipped)\n            (aset (get (:next-display controller) 3) (* first-cell 17) (util/ubyte (:left-arrow special-symbols))))\n          (when (pos? @(:effect-offset controller))\n            (aset (get (:next-display controller) 3) 67 (util/ubyte (:right-arrow special-symbols)))))\n      (do (write-display-cell controller 2 1 \"       No effects\")\n          (write-display-cell controller 2 2 \"are active.\")))))\n\n(declare enter-stop-mode)\n\n(defn- update-scroll-arrows\n  \"Activate the arrow buttons for directions in which scrolling is\n  possible.\"\n  [controller]\n  (if (in-mode? controller :shift)\n    ;; In shift mode, scroll through the effects list\n    (let [[offset max-offset] (find-effect-offset-range controller)]\n      ;; If there is an offset, user can scroll to the right\n      (when (pos? offset)\n        (swap! (:next-text-buttons controller)\n               assoc (:right-arrow control-buttons)\n               (button-state (:right-arrow control-buttons) :dim))\n        (swap! (:next-text-buttons controller)\n               assoc (:down-arrow control-buttons)\n               (button-state (:down-arrow control-buttons) :dim)))\n      ;; Is there room to scroll to the left?\n      (when (< offset max-offset)\n        (swap! (:next-text-buttons controller)\n               assoc (:left-arrow control-buttons)\n               (button-state (:left-arrow control-buttons) :dim))\n        (swap! (:next-text-buttons controller)\n               assoc (:up-arrow control-buttons)\n               (button-state (:up-arrow control-buttons) :dim))))\n\n    ;; In unshifted mode, scroll through the cue grid\n    (let [[origin-x origin-y] @(:origin controller)]\n      (when (pos? origin-x)\n        (swap! (:next-text-buttons controller)\n               assoc (:left-arrow control-buttons)\n               (button-state (:left-arrow control-buttons) :dim)))\n      (when (pos? origin-y)\n        (swap! (:next-text-buttons controller)\n               assoc (:down-arrow control-buttons)\n               (button-state (:down-arrow control-buttons) :dim)))\n      (when (> (- (controllers/grid-width (:cue-grid (:show controller))) origin-x) 7)\n        (swap! (:next-text-buttons controller)\n               assoc (:right-arrow control-buttons)\n               (button-state (:right-arrow control-buttons) :dim)))\n      (when (> (- (controllers/grid-height (:cue-grid (:show controller))) origin-y) 7)\n        (swap! (:next-text-buttons controller)\n               assoc (:up-arrow control-buttons)\n               (button-state (:up-arrow control-buttons) :dim))))))\n\n(defn- update-mode-buttons\n  \"Illuminate the buttons which activate modes while they are held\n  down. Make them dim when not held, and bright when held.\"\n  [controller mode-buttons]\n  (doseq [button mode-buttons]\n    (swap! (:next-text-buttons controller)\n           assoc (button control-buttons)\n           (button-state (button control-buttons)\n                         (if (in-mode? controller button) :bright :dim)))))\n\n(defn light-custom-buttons\n   \"Light any custom buttons that have been configured to make it clear\n   they are active. (If the button already has a lightness value, it\n   was not appropriate for it to have been configured as a custom\n   button, so leave it alone.)\"\n   [controller]\n   (doseq [custom (vals @(:custom-control-buttons controller))]\n     (swap! (:next-text-buttons controller) update (:button custom) #(or % :dim))))\n\n(defn- update-interface\n  \"Determine the desired current state of the interface, and send any\n  changes needed to get it to that state.\"\n  [controller]\n  (try\n    ;; Assume we are starting out with a blank interface.\n    (doseq [row (range 4)]\n      (Arrays/fill (get (:next-display controller) row) (byte 32)))\n    (reset! (:next-text-buttons controller) {})\n    (Arrays/fill (:next-top-pads controller) 0)\n    (reset! (:next-touch-strip controller) [0 1])\n\n    (let [snapshot (rhythm/metro-snapshot (get-in controller [:show :metronome]))]\n      (update-effect-list controller)\n      (update-metronome-section controller snapshot)\n\n      ;; If the show has stopped without us noticing, enter stop mode\n      (with-show (:show controller)\n        (when-not (or (show/running?) (in-mode? controller :stop))\n          (enter-stop-mode controller :already-stopped true)))\n\n      (update-mode-buttons controller [:shift :record])\n      (render-cue-grid controller snapshot)\n      (update-scroll-arrows controller)\n\n      ;; Make the User button bright, since we live in User mode\n      (swap! (:next-text-buttons controller)\n             assoc (:user-mode control-buttons)\n             (button-state (:user-mode control-buttons) :bright))\n\n      ;; Make the stop button visible, since we support it\n      (swap! (:next-text-buttons controller)\n             assoc (:stop control-buttons)\n             (button-state (:stop control-buttons) :dim))\n\n      ;; Light up any custom buttons that have been configured.\n      (light-custom-buttons controller)\n\n      ;; Add any contributions from interface overlays, removing them\n      ;; if they report being finished.\n      (controllers/run-overlays (:overlays controller) snapshot))\n\n    (update-cue-grid controller)\n    (update-text controller)\n    (update-top-pads controller)\n    (update-text-buttons controller)\n    (update-touch-strip controller)\n\n    (catch Throwable t\n      (timbre/warn t \"Problem updating Ableton Push Interface\"))))\n\n(declare clear-interface)\n\n(defn- welcome-frame\n  \"Render a frame of the welcome animation, or if it is done, start\n  the main interface update thread, and terminate the task running the\n  animation.\"\n  [controller counter task]\n  (try\n    (cond\n      (< @counter 8)\n      (doseq [y (range 0 (inc @counter))]\n        (let [color (colors/create-color\n                     :h 0 :s 0 :l (max 10 (- 75 (/ (* 50 (- @counter y)) 6))))]\n          (set-pad-color controller 3 y color)\n          (set-pad-color controller 4 y color)))\n\n      (< @counter 12)\n      (doseq [x (range 0 (- @counter 7))\n              y (range 0 8)]\n        (let [color (colors/create-color\n                     :h 340 :s 100 :l (- 75 (* (- @counter 8 x) 20)))]\n          (set-pad-color controller (- 3 x) y color)\n          (set-pad-color controller (+ 4 x) y color)))\n\n      (< @counter 15)\n      (doseq [y (range 0 8)]\n        (let [color (colors/create-color\n                     :h (* 13 (- @counter 11)) :s 100 :l 50)]\n          (set-pad-color controller (- @counter 7) y color)\n          (set-pad-color controller (- 14 @counter) y color)))\n\n      (= @counter 15)\n      (show-labels controller :bright :amber)\n\n      (= @counter 16)\n      (doseq [x (range 0 8)]\n        (set-top-pad-state controller x :bright :amber))\n\n      (= @counter 17)\n      (doseq [x (range 0 8)]\n        (set-second-pad-color controller x\n                                (colors/create-color :h 45 :s 100 :l 50))\n        (set-top-pad-state controller x :bright :red))\n\n      (< @counter 26)\n      (doseq [x (range 0 8)]\n        (let [lightness-index (if (> x 3) (- 7 x) x)\n              lightness ([10 30 50 70] lightness-index)\n              color (colors/create-color\n                     :h (+ 60 (* 40 (- @counter 18))) :s 100 :l lightness)]\n          (set-pad-color controller x (- 25 @counter) color)))\n\n      (= @counter 26)\n      (do\n        (show-labels controller :dim :amber)\n        (doseq [x (range 0 8)]\n          (set-top-pad-state controller x :off)))\n\n      (= @counter 27)\n      (doseq [x (range 0 8)]\n          (set-second-pad-color controller x off-color))\n\n      (< @counter 36)\n      (doseq [x (range 0 8)]\n        (set-pad-color controller x (- 35 @counter) off-color))\n\n      :else\n      (do\n        (clear-interface controller)\n        (amidi/add-device-mapping (:port-in controller) @(:midi-handler controller))\n        (enter-metronome-showing controller)\n        (reset! (:task controller) (at-at/every (:refresh-interval controller)\n                                                #(update-interface controller)\n                                                controllers/pool\n                                                :initial-delay 10\n                                                :desc \"Push interface update\"))\n        (at-at/kill @task)))\n    (catch Throwable t\n      (timbre/warn t \"Animation frame failed\")))\n\n  (swap! counter inc))\n\n(defn- welcome-animation\n  \"Provide a fun animation to make it clear the Push is online.\"\n  [controller]\n  (set-display-line controller 1 (concat (repeat 24 \\space) (seq (str \"Welcome to\" (version/title)))))\n  (set-display-line controller 2 (concat (repeat 27 \\space)\n                              (seq (str \"version\" (version/tag)))))\n  (let [counter (atom 0)\n        task (atom nil)]\n    (reset! task (at-at/every 50 #(welcome-frame controller counter task)\n                              controllers/pool))))\n\n(defn clear-interface\n  \"Clears the text display and all illuminated buttons and pads.\"\n  [controller]\n  (doseq [line (range 4)]\n    (clear-display-line controller line)\n    (Arrays/fill (get (:last-display controller) line) (byte 32)))\n\n  (doseq [x (range 8)]\n    (set-top-pad-state controller x :off)\n    (set-second-pad-color controller x off-color)\n    (doseq [y (range 8)]\n      (set-pad-color controller x y off-color)))\n  (Arrays/fill (:last-top-pads controller) 0)\n  (Arrays/fill (:last-grid-pads controller) off-color)\n  (doseq [[_ button] control-buttons]\n    (set-button-state controller button :off))\n  (reset! (:last-text-buttons controller) {})\n  (set-touch-strip-mode controller touch-strip-mode-default)\n  (reset! (:last-touch-strip controller) nil))\n\n(defn- master-encoder-touched\n  \"Add a user interface overlay to give feedback when turning the\n  master encoder.\"\n  [controller]\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [_this] #{79})\n                             (captured-notes [_this] #{8})\n                             (adjust-interface [_this _]\n                               (let [level (master-get-level (get-in controller [:show :grand-master]))]\n                                 (write-display-cell controller 0 3 (make-gauge level))\n                                 (write-display-cell controller 1 3\n                                                     (str \"GrandMaster \" (format \"%5.1f\" level)))\n                                 (set-touch-strip-from-value controller level 0 100 touch-strip-mode-level))\n                               true)\n                             (handle-control-change [_this message]\n                               ;; Adjust the grand master based on how the encoder was twisted\n                               (let [delta (/ (sign-velocity (:velocity message)) 2)\n                                     level (master-get-level (get-in controller [:show :grand-master]))]\n                                 (master-set-level (get-in controller [:show :grand-master]) (+ level delta))\n                                 true))\n                             (handle-note-on [_this _message]\n                               false)\n                             (handle-note-off [_this _message]\n                               ;; Exit the overlay\n                               :done)\n                             (handle-aftertouch [_this _message])\n                             (handle-pitch-bend [_this message]\n                               (master-set-level (get-in controller [:show :grand-master])\n                                                 (value-from-touch-strip message 0 100))))))\n\n(defn- bpm-encoder-touched\n  \"Add a user interface overlay to give feedback when turning the BPM\n  encoder.\"\n  [controller]\n  ;; Reserve the metronome area for its coordinated set of overlays\n  (swap! (:metronome-mode controller) assoc :adjusting-bpm :true)\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [_this] #{15})\n                             (captured-notes [_this] #{9 1})\n                             (adjust-interface [_this snapshot]\n                               (bpm-adjusting-interface controller snapshot)\n                               true)\n                             (handle-control-change [_this message]\n                               (adjust-bpm-from-encoder controller message))\n                             (handle-note-on [_this _message]\n                               ;; Suppress the extra encoder above the BPM display.\n                               ;; We can't get a note on for the BPM encoder, because\n                               ;; that was the event that created this overlay.\n                               true)\n                             (handle-note-off [_this message]\n                               (when (= (:note message) 9)\n                                 ;; They released us, end the overlay\n                                 (swap! (:metronome-mode controller) dissoc :adjusting-bpm)\n                                 :done))\n                             (handle-aftertouch [_this _message])\n                             (handle-pitch-bend [_this message]\n                               (rhythm/metro-bpm (:metronome (:show controller))\n                                                 (value-from-touch-strip message controllers/minimum-bpm\n                                                                         controllers/maximum-bpm))))))\n\n(defn- beat-encoder-touched\n  \"Add a user interface overlay to give feedback when turning the beat\n  encoder.\"\n  [controller]\n  ;; Reserve the metronome area for its coordinated set of overlays\n  (swap! (:metronome-mode controller) assoc :adjusting-beat :true)\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [_this] #{14})\n                             (captured-notes [_this] #{10 0})\n                             (adjust-interface [_this _]\n                               (beat-adjusting-interface controller))\n                             (handle-control-change [_this message]\n                               (adjust-beat-from-encoder controller message))\n                             (handle-note-on [_this _message]\n                               ;; Suppress the extra encoder above the beat display.\n                               ;; We can't get a note on for the beat encoder, because\n                               ;; that was the event that created this overlay.\n                               true)\n                             (handle-note-off [_this message]\n                               (when (= (:note message) 10)\n                                 ;; They released us, exit the overlay\n                                 (swap! (:metronome-mode controller) dissoc :adjusting-beat)\n                                 :done))\n                             (handle-aftertouch [_this _message])\n                             (handle-pitch-bend [_this _message]))))\n\n(defn- leave-user-mode\n  \"The user has asked to exit user mode, so suspend our display\n  updates, and prepare to restore our state when user mode is pressed\n  again.\"\n  [controller]\n  (swap! (:task controller) (fn [task]\n                              (when task (at-at/kill task))\n                              nil))\n  (clear-interface controller)\n  ;; In case Live isn't running, leave the User Mode button dimly lit, to help the user return.\n  (set-button-state controller (:user-mode control-buttons)\n                    (button-state (:user-mode control-buttons) :dim))\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [_this] #{59})\n                             (captured-notes [_this] #{})\n                             (adjust-interface [_this _]\n                               true)\n                             (handle-control-change [_this message]\n                               (when (pos? (:velocity message))\n                                 ;; We are returning to user mode, restore display\n                                 (clear-interface controller)\n                                 (reset! (:task controller) (at-at/every (:refresh-interval controller)\n                                                                         #(update-interface controller)\n                                                                         controllers/pool\n                                                                         :initial-delay 250\n                                                                         :desc \"Push interface update\"))\n                                 :done))\n                             (handle-note-on [_this _message])\n                             (handle-note-off [_this _message])\n                             (handle-aftertouch [_this _message])\n                             (handle-pitch-bend [_this _message]))))\n\n(defn- enter-stop-mode\n  \"The user has asked to stop the show. Suspend its update task\n  and black it out until the stop button is pressed again.\"\n  [controller & {:keys [already-stopped]}]\n\n  (update-mode! controller :stop true)\n  (when-not already-stopped\n    (with-show (:show controller)\n      (show/stop!)\n      (Thread/sleep (:refresh-interval (:show controller)))\n      (show/blackout-show)))\n\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [_this] #{29})\n                             (captured-notes [_this] #{})\n                             (adjust-interface [_this _]\n                               (write-display-cell controller 0 1 \"\")\n                               (write-display-cell controller 0 2 \"\")\n                               (write-display-cell controller 1 1 \"         *** Show\")\n                               (write-display-cell controller 1 2 \"Stop ***\")\n                               (write-display-cell controller 2 1 \"       Press Stop\")\n                               (write-display-cell controller 2 2 \"to resume.\")\n                               (write-display-cell controller 3 1 \"\")\n                               (write-display-cell controller 3 2 \"\")\n                               (swap! (:next-text-buttons controller)\n                                      assoc (:stop control-buttons)\n                                      (button-state (:stop control-buttons) :bright))\n                               (with-show (:show controller)\n                                 (when (show/running?)\n                                   (update-mode! controller :stop false))\n                                 (in-mode? controller :stop)))\n                             (handle-control-change [_this message]\n                               (when (pos? (:velocity message))\n                                 ;; End stop mode\n                                 (with-show (:show controller)\n                                   (show/start!))\n                                 (update-mode! controller :stop false)\n                                 :done))\n                             (handle-note-on [_this _message])\n                             (handle-note-off [_this _message])\n                             (handle-aftertouch [_this _message])\n                             (handle-pitch-bend [_this _message]))))\n\n(defn add-button-held-feedback-overlay\n  \"Adds a simple overlay which keeps a control button bright as long\n  as the user is holding it down.\"\n  [controller button]\n  (controllers/add-control-held-feedback-overlay (:overlays controller) (:control button)\n                                                 (fn [_] (swap! (:next-text-buttons controller)\n                                                                assoc button (button-state button :bright)))))\n\n(defn- handle-save-effect\n  \"Process a tap on one of the pads which indicate the user wants to\n  save or clear the variables for the associated effect.\"\n  [controller note]\n  (let [room    (room-for-effects controller)\n        fx-info @(:active-effects (:show controller))\n        fx      (:effects fx-info)\n        fx-meta (:meta fx-info)\n        num-skipped (- (count fx-meta) room @(:effect-offset controller))\n        fx (vec (drop num-skipped fx))\n        fx-meta (vec (drop num-skipped fx-meta))\n        offset  (- 4 room)\n        x       (quot (- note 20) 2)\n        index   (- x offset)]\n    (when (and (seq fx) (< index (count fx)))\n      (let [info        (get fx-meta index)\n            cue         (:cue info)\n            cur-vals    (cues/snapshot-cue-variables cue (:id info) :show (:show controller))\n            saved-vals  (controllers/cue-vars-saved-at (:cue-grid (:show controller)) (:x info) (:y info))\n            save-action (when (seq cur-vals)\n                          (if (= cur-vals saved-vals) :clear :save))]\n        (when save-action\n          (case save-action\n            :save  (controllers/save-cue-vars! (:cue-grid (:show controller)) (:x info) (:y info) cur-vals)\n            :clear (controllers/clear-saved-cue-vars! (:cue-grid (:show controller)) (:x info) (:y info)))\n          (controllers/add-control-held-feedback-overlay (:overlays controller) note\n                                                         (fn [_]\n                                                           (aset (:next-top-pads controller) (* 2 x)\n                                                                 (top-pad-state :bright (case save-action\n                                                                                          :save  :green\n                                                                                          :clear :amber)))\n                                                           (write-display-cell controller 3 x\n                                                                               (case save-action\n                                                                                 :save  \"  Saved  \"\n                                                                                 :clear \"Cleared  \"))\n                                                           true)))))))\n\n(defn- handle-end-effect\n  \"Process a tap on one of the pads which indicate the user wants to\n  end the associated effect.\"\n  [controller note]\n  (let [room (room-for-effects controller)\n        fx-info @(:active-effects (:show controller))\n        fx (:effects fx-info)\n        fx-meta (:meta fx-info)\n        num-skipped (- (count fx-meta) room @(:effect-offset controller))\n        fx (vec (drop num-skipped fx))\n        fx-meta (vec (drop num-skipped fx-meta))\n        offset (- 4 room)\n        x (quot (- note 20) 2)\n        index (- x offset)]\n    (when (and (seq fx) (< index (count fx)))\n      (let [effect (get fx index)\n            info (get fx-meta index)]\n        (with-show (:show controller)\n          (show/end-effect! (:key info) :when-id (:id info)))\n        (controllers/add-overlay (:overlays controller)\n                                 (reify controllers/IOverlay\n                                   (captured-controls [_this] #{note (inc note)})\n                                   (captured-notes [_this] #{})\n                                   (adjust-interface [_this _]\n                                     (write-display-cell controller 0 x \"\")\n                                     (write-display-cell controller 1 x \"Ending:\")\n                                     (write-display-cell controller 2 x (or (:name (:cue info)) (:name effect)))\n                                     (write-display-cell controller 3 x \"\")\n                                     (aset (:next-top-pads controller) (* 2 x) (top-pad-state :bright :red))\n                                     (aset (:next-top-pads controller) (inc (* 2 x)) (top-pad-state :off))\n                                     true)\n                                   (handle-control-change [_this message]\n                                     (when (and (= (:note message) note) (zero? (:velocity message)))\n                                       :done))\n                                   (handle-note-on [_this _message])\n                                   (handle-note-off [_this _message])\n                                   (handle-aftertouch [_this _message])\n                                   (handle-pitch-bend [_this _message])))))))\n\n(defn- handle-scroll-cue-vars\n  \"Process a tap on one of the pads which indicate the user wants to\n  scroll forward in the list of cue variables.\"\n  [controller note]\n  (let [room (room-for-effects controller)\n        fx-info @(:active-effects (:show controller))\n        fx (vec (:effects fx-info))\n        fx-meta (vec (:meta fx-info))\n        num-skipped (- (count fx-meta) room @(:effect-offset controller))\n        fx (vec (drop num-skipped fx))\n        fx-meta (vec (drop num-skipped fx-meta))\n        offset (- 4 room)\n        x (quot (- note 21) 2)\n        index (- x offset)]\n    (when (and (seq fx) (< index (count fx)))\n      (let [info (get fx-meta index)\n            cue (:cue info)\n            var-count (count (:variables cue))]\n        (when (> var-count 2)\n          (swap! (:cue-var-offsets controller) update-in [(:id info)] #(mod (+ 2 (or % 0)) var-count))\n          (controllers/add-overlay (:overlays controller)\n                                   (reify controllers/IOverlay\n                                     (captured-controls [_this] #{note})\n                                     (captured-notes [_this] #{})\n                                     (adjust-interface [_this _]\n                                       (aset (:next-top-pads controller) (inc (* 2 x)) (top-pad-state :bright :amber))\n                                       true)\n                                     (handle-control-change [_this message]\n                                       (when (and (= (:note message) note) (zero? (:velocity message)))\n                                         :done))\n                                     (handle-note-on [_this _message])\n                                     (handle-note-off [_this _message])\n                                     (handle-aftertouch [_this _message])\n                                     (handle-pitch-bend [_this _message]))))))))\n\n(defn- move-origin\n  \"Changes the origin of the controller, notifying any registered\n  listeners.\"\n  [controller origin]\n  (when (not= origin @(:origin controller))\n    (reset! (:origin controller) origin)\n    (doseq [f @(:move-listeners controller)] (f @(:grid-controller-impl controller) :moved))))\n\n(defn- control-change-received\n  \"Process a control change message which was not handled by an\n  interface overlay.\"\n  [controller message]\n  (case (:note message)\n    3 ; Tap tempo button\n    (when (pos? (:velocity message))\n      ((:tempo-tap-handler controller))\n      (enter-metronome-showing controller))\n\n    9 ; Metronome button\n    (when (pos? (:velocity message))\n      (enter-metronome-showing controller))\n\n    (20 22 24 26) ; Effect end/save pads\n    (when (pos? (:velocity message))\n      (if (in-mode? controller :record)\n        (handle-save-effect controller (:note message))\n        (handle-end-effect controller (:note message))))\n\n    (21 23 25 27) ; Effect cue variable scroll pads\n    (when (pos? (:velocity message))\n      (handle-scroll-cue-vars controller (:note message)))\n\n    ;; 28 ; Master button\n\n    29 ; Stop button\n    (when (pos? (:velocity message))\n      (enter-stop-mode controller))\n\n    (49 86) ; Shift or Record button\n    (update-mode! controller (:note message) (pos? (:velocity message)))\n\n    44 ; Left arrow\n    (when (pos? (:velocity message))\n      (if (in-mode? controller :shift)\n        ;; Trying to scroll back to older effects\n        (let [[offset max-offset room] (find-effect-offset-range controller)\n              new-offset (min max-offset (+ offset room))]\n          (when (not= offset new-offset)\n            (reset! (:effect-offset controller) new-offset)\n            (add-button-held-feedback-overlay controller (:left-arrow control-buttons))))\n\n        ;; Trying to scroll left in cue grid\n        (let [[x y] @(:origin controller)]\n          (when (pos? x)\n            (move-origin controller [(max 0 (- x 8)) y])\n            (add-button-held-feedback-overlay controller (:left-arrow control-buttons))))))\n\n    45 ; Right arrow\n    (when (pos? (:velocity message))\n      (if (in-mode? controller :shift)\n        ;; Trying to scroll forward to newer effects\n        (let [[offset _max-offset room] (find-effect-offset-range controller)\n              new-offset (max 0 (- offset room))]\n          (when (not= offset new-offset)\n            (reset! (:effect-offset controller) new-offset)\n            (add-button-held-feedback-overlay controller (:right-arrow control-buttons))))\n\n        ;; Trying to scroll right in cue grid\n        (let [[x y] @(:origin controller)]\n          (when (> (- (controllers/grid-width (:cue-grid (:show controller))) x) 7)\n            (move-origin controller [(+ x 8) y])\n            (add-button-held-feedback-overlay controller (:right-arrow control-buttons))))))\n\n    46 ; Up arrow\n    (when (pos? (:velocity message))\n      (if (in-mode? controller :shift)\n        ;; Jump back to oldest effect\n        (let [[offset max-offset] (find-effect-offset-range controller)]\n          (when (not= offset max-offset)\n            (reset! (:effect-offset controller) max-offset)\n            (add-button-held-feedback-overlay controller (:up-arrow control-buttons))))\n\n        ;; Trying to scroll up in cue grid\n        (let [[x y] @(:origin controller)]\n          (when (> (- (controllers/grid-height (:cue-grid (:show controller))) y) 7)\n            (move-origin controller [x (+ y 8)])\n            (add-button-held-feedback-overlay controller (:up-arrow control-buttons))))))\n\n    47 ; Down arrow\n    (when (pos? (:velocity message))\n      (if (in-mode? controller :shift)\n        ;; Jump forward to newest effect\n        (when (pos? @(:effect-offset controller))\n          (reset! (:effect-offset controller) 0)\n          (add-button-held-feedback-overlay controller (:down-arrow control-buttons)))\n\n        ;; Trying to scroll down in cue grid\n        (let [[x y] @(:origin controller)]\n          (when (pos? y)\n            (move-origin controller [x (max 0 (- y 8))])\n            (add-button-held-feedback-overlay controller (:down-arrow control-buttons))))))\n\n    59 ; User mode button\n    (when (pos? (:velocity message))\n      (leave-user-mode controller))\n\n    ;; Something we don't explictly recognize; see if it's been registered as a custom control button.\n    (when-let [custom (get @(:custom-control-buttons controller) (:note message))]\n      (when (pos? (:velocity message))\n        (try\n          ((:press custom))\n          (catch Throwable t\n            (timbre/error t \"Problem running custom control button press function.\")))\n        (controllers/add-overlay\n         (:overlays controller)\n         (reify controllers/IOverlay\n           (captured-controls [_this] #{(:note message)})\n           (captured-notes [_this] #{})\n           (adjust-interface [_this _snapshot]\n             (swap! (:next-text-buttons controller) assoc (:button custom) :bright))\n           (handle-control-change [_this message]\n             (when (and (= (:note message) (get-in custom [:button :control]))\n                        (zero? (:velocity message)))\n               (try\n                 ((:release custom))\n                 (catch Throwable t\n                   (timbre/error t \"Problem running custom control button release function.\")))\n               :done))\n           (handle-note-on [_this _message])\n           (handle-note-off [_this _message])\n           (handle-aftertouch [_this _message])\n           (handle-pitch-bend [_this _message])))))))\n\n(defn- note-to-cue-coordinates\n  \"Translate the MIDI note associated with an incoming message to its\n  coordinates in the show cue grid.\"\n  [controller note]\n  (let [base (- note 36)\n        [origin-x origin-y] @(:origin controller)\n        pad-x (rem base 8)\n        pad-y (quot base 8)\n        cue-x (+ origin-x pad-x)\n        cue-y (+ origin-y pad-y)]\n    [cue-x cue-y pad-x pad-y]))\n\n(defn- cue-grid-pressed\n  \"One of the pads in the 8x8 pressure-sensitve cue grid was pressed.\"\n  [controller note velocity]\n  (let [[cue-x cue-y pad-x pad-y] (note-to-cue-coordinates controller note)\n        [cue active] (show/find-cue-grid-active-effect (:show controller) cue-x cue-y)]\n          (when cue\n            (with-show (:show controller)\n              (if (and active (not (:held cue)))\n                (show/end-effect! (:key cue))\n                (let [id (show/add-effect-from-cue-grid! cue-x cue-y :velocity velocity)\n                      holding (and (:held cue) (not (in-mode? controller :shift)))]\n                  (controllers/add-overlay\n                   (:overlays controller)\n                   (reify controllers/IOverlay\n                     (captured-controls [_this] #{})\n                     (captured-notes [_this] #{note})\n                     (adjust-interface [_this snapshot]\n                       (when holding\n                         (let [active (show/find-effect (:key cue))\n                               base-color (cues/current-cue-color cue active (:show controller) snapshot)\n                               color (colors/create-color\n                                      :h (colors/hue base-color)\n                                      :s (colors/saturation base-color)\n                                      :l 75)]\n                           (aset (:next-grid-pads controller) (+ pad-x (* pad-y 8)) color)))\n                       true)\n                     (handle-control-change [_this _message])\n                     (handle-note-on [_this _message])\n                     (handle-note-off [_this _message]\n                       (when holding\n                         (with-show (:show controller)\n                           (show/end-effect! (:key cue) :when-id id)))\n                       :done)\n                     (handle-aftertouch [_this message]\n                       (if (zero? (:velocity message))\n                         (do (when holding\n                               (with-show (:show controller)\n                                 (show/end-effect! (:key cue) :when-id id)))\n                             :done)\n                         (doseq [v (:variables cue)]\n                           (when (:velocity v)\n                             (cues/set-cue-variable! cue v\n                                                     (controllers/value-for-velocity v (:velocity message))\n                                                     :show (:show controller) :when-id id)))))\n                     (handle-pitch-bend [_this _message])))))))))\n\n(defn- control-for-top-encoder-note\n  \"Return the control number on which rotation of the encoder whose\n  touch events are sent on the specified note will be sent.\"\n  [note]\n  (+ note 71))\n\n(defn- draw-variable-gauge\n  \"Display the value of a variable being adjusted in the effect list.\"\n  [controller cell width offset cue v effect-id]\n  (let [value (or (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id) 0)\n        low (min value (:min v))  ; In case user set \"out of bounds\".\n        high (max value (:max v))\n        gauge (if (:centered v)\n                (make-pan-gauge value :lowest low :highest high :width width)\n                (make-gauge value :lowest low :highest high :width width))]\n    (write-display-text controller 0 (+ offset (* cell 17)) gauge)))\n\n(defn- adjust-variable-value\n  \"Handle a control change from turning an encoder associated with a\n  variable being adjusted in the effect list.\"\n  [controller message cue v effect-id]\n  (let [value (or (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id) 0)\n        low (min value (:min v))  ; In case user set \"out of bounds\".\n        high (max value (:max v))\n        raw-resolution (/ (- high low) 200)\n        resolution (or (:resolution v) (if (= :integer (:type v))\n                                         (max 1 (Math/round (double raw-resolution)))\n                                         raw-resolution))\n        delta (* (sign-velocity (:velocity message)) resolution)\n        adjusted (+ value delta)\n        normalized (if (= :integer (:type v)) (Math/round (double adjusted))\n                       (double (* (Math/round (/ adjusted resolution)) resolution)))]\n    (cues/set-cue-variable! cue v (max low (min high normalized)) :show (:show controller) :when-id effect-id)))\n\n(defn- bend-variable-value\n  \"Handle a pitch bend change while an encoder associated with a\n  variable is being adjusted in the effect list.\"\n  [controller message cue v effect-id]\n  (let [adjusted (value-from-touch-strip message (:min v) (:max v))\n        resolution (or (:resolution v) (if (= :integer (:type v))\n                                         1\n                                         (/ (- (:max v) (:min v)) 200)))\n        normalized (if (= :integer (:type v)) (Math/round (double adjusted))\n                       (double (* (Math/round (/ adjusted resolution)) resolution)))]\n    (cues/set-cue-variable! cue v (max (:min v) (min (:max v) normalized)) :show (:show controller)\n                            :when-id effect-id)))\n\n(defn- draw-boolean-gauge\n  \"Display the value of a boolean variable being adjusted in the effect list.\"\n  [controller cell width offset cue v effect-id]\n  (let [value (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id)\n        gauge (concat \"No\" (when-not value [(:left-arrow special-symbols)])\n                      (repeat (- width 6) \\ )\n                      (when value [(:right-arrow special-symbols)]) \"Yes\")]\n    (write-display-text controller 0 (+ offset (* cell 17)) gauge)))\n\n(defn- adjust-boolean-value\n  \"Handle a control change from turning an encoder associated with a\n  boolean variable being adjusted in the effect list.\"\n  [controller message cue v effect-id]\n  (let [new-value (true? (pos? (sign-velocity (:velocity message))))]\n    (cues/set-cue-variable! cue v new-value :show (:show controller) :when-id effect-id)))\n\n(defn- same-effect-active\n  \"See if the specified effect is still active with the same id.\"\n  [controller cue id]\n  (with-show (:show controller)\n    (let [effect-found (show/find-effect (:key cue))]\n      (and effect-found (= (:id effect-found) id)))))\n\n(defn- build-boolean-adjustment-overlay\n  \"Create an overlay for adjusting a boolean cue parameter. `note`\n  identifies the encoder that was touched to bring up this overlay,\n  `cue` is the cue whose variable is being adjusted, `v` is the map\n  identifying the variable itself, `effect` is the effect which that\n  cue is running, and `info` is the metadata about that effect.\n\n  Also suppresses the ability to scroll through the cue variables\n  while the encoder is being held.\"\n  [controller note cue v _effect info]\n  (let [x (quot note 2)\n        var-index (rem note 2)]\n    (if (> (count (:variables cue)) 1)\n      ;; More than one variable, adjust whichever's encoder was touched\n      (reify controllers/IOverlay\n        (captured-controls [_this] #{(control-for-top-encoder-note note) (+ 21 (* 2 x))})\n        (captured-notes [_this] #{note})\n        (adjust-interface [_this _]\n          (when (same-effect-active controller cue (:id info))\n            (draw-boolean-gauge controller x 8 (* 9 var-index) cue v (:id info))\n            (let [cur-val (or (cues/get-cue-variable cue v :show (:show controller) :when-id (:id info)) false)]\n              (set-touch-strip-from-value controller (if cur-val 1 0) 0 1 touch-strip-mode-pan))\n            (aset (:next-top-pads controller) (inc (* 2 x)) (top-pad-state :off))\n            true))\n        (handle-control-change [_this message]\n          (when (= (:note message) (control-for-top-encoder-note note))\n            (adjust-boolean-value controller message cue v (:id info)))\n          true)\n        (handle-note-on [_this _message])\n        (handle-note-off [_this _message]\n          :done)\n        (handle-aftertouch [_this _message])\n        (handle-pitch-bend [_this message]\n          (cues/set-cue-variable! cue v (true? (>= (value-from-touch-strip message 0 100) 50))\n                                  :show (:show controller) :when-id (:id info))))\n\n      ;; Just one variable, take full cell, using either encoder,\n      ;; suppress the other one.\n      (let [paired-note (if (odd? note) (dec note) (inc note))]\n        (reify controllers/IOverlay\n          (captured-controls [_this] #{(control-for-top-encoder-note note) (+ 21 (* 2 x))})\n          (captured-notes [_this] #{note paired-note})\n          (adjust-interface [_this _]\n            (when (same-effect-active controller cue (:id info))\n              (draw-boolean-gauge controller x 17 0 cue v (:id info))\n              (let [cur-val (or (cues/get-cue-variable cue v :show (:show controller) :when-id (:id info)) false)]\n                (set-touch-strip-from-value controller (if cur-val 1 0) 0 1 touch-strip-mode-pan))\n              (aset (:next-top-pads controller) (inc (* 2 x)) (top-pad-state :off))\n              true))\n          (handle-control-change [_this message]\n            (when (= (:note message) (control-for-top-encoder-note note))\n              (adjust-boolean-value controller message cue v (:id info)))\n            true)\n          (handle-note-on [_this _message]\n            true)\n          (handle-note-off [_this message]\n            (when (= (:note message) note)\n              :done))\n          (handle-aftertouch [_this _message])\n          (handle-pitch-bend [_this message]\n            (cues/set-cue-variable! cue v (true? (>= (value-from-touch-strip message 0 100) 50))\n                                  :show (:show controller) :when-id (:id info))))))))\n\n(defn- build-numeric-adjustment-overlay\n  \"Create an overlay for adjusting a numeric cue parameter. `note`\n  identifies the encoder that was touched to bring up this overlay,\n  `cue` is the cue whose variable is being adjusted, `v` is the map\n  identifying the variable itself, `effect` is the effect which that\n  cue is running, and `info` is the metadata about that effect.\n\n  Also suppresses the ability to scroll through the cue variables\n  while the encoder is being held.\"\n  [controller note cue v _effect info]\n  (let [x (quot note 2)\n        var-index (rem note 2)]\n    (if (> (count (:variables cue)) 1)\n      ;; More than one variable, adjust whichever's encoder was touched\n      (reify controllers/IOverlay\n        (captured-controls [_this] #{(control-for-top-encoder-note note) (+ 21 (* 2 x))})\n        (captured-notes [_this] #{note})\n        (adjust-interface [_this _snapshot]\n          (when (same-effect-active controller cue (:id info))\n            (draw-variable-gauge controller x 8 (* 9 var-index) cue v (:id info))\n            (aset (:next-top-pads controller) (inc (* 2 x)) (top-pad-state :off))\n            (set-touch-strip-from-cue-var controller cue v (:id info))\n            true))\n        (handle-control-change [_this message]\n          (when (= (:note message) (control-for-top-encoder-note note))\n            (adjust-variable-value controller message cue v (:id info)))\n          true)\n        (handle-note-on [_this _message])\n        (handle-note-off [_this _message]\n          :done)\n        (handle-aftertouch [_this _message])\n        (handle-pitch-bend [_this message]\n          (bend-variable-value controller message cue v (:id info))\n          true))\n\n      ;; Just one variable, take full cell, using either encoder,\n      ;; suppress the other one.\n      (let [paired-note (if (odd? note) (dec note) (inc note))]\n        (reify controllers/IOverlay\n          (captured-controls [_this] #{(control-for-top-encoder-note note) (+ 21 (* 2 x))})\n          (captured-notes [_this] #{note paired-note})\n          (adjust-interface [_this _snapshot]\n            (when (same-effect-active controller cue (:id info))\n              (draw-variable-gauge controller x 17 0 cue v (:id info))\n              (aset (:next-top-pads controller) (inc (* 2 x)) (top-pad-state :off))\n              (set-touch-strip-from-cue-var controller cue v (:id info))\n              true))\n          (handle-control-change [_this message]\n            (when (= (:note message) (control-for-top-encoder-note note))\n              (adjust-variable-value controller message cue v (:id info)))\n            true)\n          (handle-note-on [_this _message]\n            true)\n          (handle-note-off [_this message]\n            (when (= (:note message) note)\n              :done))\n          (handle-aftertouch [_this _message])\n          (handle-pitch-bend [_this message]\n            (bend-variable-value controller message cue v (:id info))\n            true))))))\n\n(def ^:private color-picker-grid\n  (let [result (make-array clojure.lang.IPersistentMap 64)]\n    (doseq [i (range 16)]\n      (let [x (* 4 (quot i 8))\n            y (- 7 (rem i 8))\n            origin (+ x (* 8 y))\n            hue (* 360 (/ i 15))\n            base-color (colors/create-color :hue hue :saturation 100 :lightness 50)]\n        (aset result origin base-color)\n        (aset result (inc origin) (colors/desaturate base-color 25))\n        (aset result (+ origin 2) (colors/desaturate base-color 50))\n        (aset result (+ origin 3) (colors/desaturate base-color 75))))\n    (aset result 4 (colors/create-color :h 0 :s 0 :l 100))\n    (aset result 5 (colors/create-color :h 0 :s 0 :l 50))\n    (aset result 6 (colors/create-color :h 0 :s 0 :l 0))\n    result))\n\n(defn- build-color-adjustment-overlay\n  \"Create an overlay for adjusting a color cue parameter. `note`\n  identifies the encoder that was touched to bring up this overlay,\n  `cue` is the cue whose variable is being adjusted, `v` is the map\n  identifying the variable itself, `effect` is the effect which that\n  cue is running, and `info` is the metadata about that effect.\n\n  Also suppresses the ability to scroll through the cue variables\n  while the encoder is being held.\"\n  [controller note cue v _effect info]\n  (let [anchors                   (atom #{note}) ; Track which encoders are keeping the overlay active\n        x                         (quot note 2)\n        effect-id                 (:id info)\n        ;; Take full cell, using both encoders to adjust hue and saturation.\n        [hue-note sat-note]       (if (odd? note) [(dec note) note] [note (inc note)])\n        [hue-control sat-control] (map control-for-top-encoder-note [hue-note sat-note])]\n    (reify controllers/IOverlay\n      (captured-controls [_this] #{hue-control sat-control (+ 21 (* 2 x))})\n      (captured-notes [_this] (set/union #{hue-note sat-note} (set (drop 36 (range 100)))))\n      (adjust-interface [_this _]\n        (when (same-effect-active controller cue (:id info))\n          ;; Draw the color picker grid\n          (System/arraycopy color-picker-grid 0 (:next-grid-pads controller) 0 64)\n          (let [current-color (or (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id)\n                                  (aget color-picker-grid 6))\n                hue           (colors/hue current-color)\n                sat           (colors/saturation current-color)]\n            ;; Show the preview color at the bottom right\n            (aset (:next-grid-pads controller) 7 current-color)\n\n            ;; Blink any pad which matches the currently selected color\n            (when (< (rhythm/metro-beat-phase (:metronome (:show controller))) 0.3)\n              (doseq [i (range 64)]\n                (when (and (not= i 7) (colors/color= current-color (aget (:next-grid-pads controller) i)))\n                  (aset (:next-grid-pads controller) i (if (= i 4)\n                                                         (colors/darken current-color 20)\n                                                         (colors/lighten current-color 20))))))\n\n            ;; Display the hue and saturation numbers and gauges\n            (let [hue-str   (str/join (take 5 (str (double hue) \"     \")))\n                  sat-str   (str/join (take 5 (str (double sat))))\n                  hue-gauge (make-pan-gauge hue :highest 360 :width 8)\n                  sat-gauge (make-gauge sat :width 8)]\n              (write-display-cell controller 0 x (str \"H: \" hue-str \" S: \" sat-str))\n              (write-display-text controller 1 (* x 17) hue-gauge)\n              (write-display-text controller 1 (+ 9 (* x 17)) sat-gauge))\n\n            ;; Put the touch pad into the appropriate state\n            (if (@anchors hue-note)\n              (set-touch-strip-from-value controller hue 0 360 touch-strip-mode-hue)\n              (set-touch-strip-from-value controller sat 0 100 touch-strip-mode-level))\n\n            ;; Darken the cue var scroll button if it was going to be lit\n            (aset (:next-top-pads controller) (inc (* 2 x)) (top-pad-state :off))\n            true)))\n      (handle-control-change [_this message]\n        ;; Adjust hue or saturation depending on controller; ignore if it was the cue var scroll button\n        (when (#{hue-control sat-control} (:note message))\n          (let [current-color (or (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id)\n                                  (aget color-picker-grid 6))\n                current-color (colors/create-color :h (colors/hue current-color) :s (colors/saturation current-color)\n                                                   :l 50)\n                delta         (* (sign-velocity (:velocity message)) 0.5)]\n            (cues/set-cue-variable! cue v\n                                    (if (= (:note message) hue-control)\n                                      (colors/adjust-hue current-color delta)\n                                      (colors/saturate current-color delta))\n                                    :show (:show controller) :when-id effect-id)))\n        true)\n      (handle-note-on [_this message]\n        (let [note (:note message)]\n          (if (#{hue-note sat-note} note)\n            ;; The user has grabbed another of our controllers, stay active until it is released.\n            (swap! anchors conj note)\n\n            ;; It's a grid pad. Set the color based on the selected note, unless it's the preview pad.\n            (when-not (= note 43)\n              (let [chosen-color (aget color-picker-grid (- note 36))]\n                (cues/set-cue-variable! cue v chosen-color :show (:show controller) :when-id effect-id)))))\n        true)\n      (handle-note-off [_this message]\n        (swap! anchors disj (:note message))\n        (when (empty? @anchors)\n          :done))\n      (handle-aftertouch [_this _message])\n      (handle-pitch-bend [_this message]\n        (let [current-color (or (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id)\n                                (aget color-picker-grid 6))\n              fraction      (value-from-touch-strip message 0 1)\n              new-hue       (if (@anchors hue-note) (* fraction 360) (colors/hue current-color))\n              new-sat       (if (@anchors sat-note) (* fraction 100) (colors/saturation current-color))]\n          (cues/set-cue-variable! cue v (colors/create-color :h new-hue :s new-sat :l 50)\n                                  :when-id effect-id))))))\n\n(defn- display-encoder-touched\n  \"One of the eight encoders above the text display was touched.\"\n  [controller note]\n  (let [room (room-for-effects controller)\n        fx-info @(:active-effects (:show controller))\n        fx-meta (:meta fx-info)\n        num-skipped (- (count fx-meta) room @(:effect-offset controller))\n        fx (vec (drop num-skipped (:effects fx-info)))\n        fx-meta (vec (drop num-skipped (:meta fx-info)))\n        offset (- 4 room)\n        x (quot note 2)\n        index (- x offset)\n        var-index (rem note 2)]\n    (when (and (seq fx) (< index (count fx)))\n      (let [effect (get fx index)\n            info (get fx-meta index)\n            cue (:cue info)\n            cue-vars (cue-vars-for-encoders (:variables cue) (get @(:cue-var-offsets controller) (:id info) 0))\n            cue-var (get cue-vars var-index)]\n        (when cue-var\n          (let [cur-val (cues/get-cue-variable cue cue-var :show (:show controller) :when-id (:id info))]\n            (cond\n              (or (number? cur-val) (#{:integer :double} (:type cue-var :double)))\n              (controllers/add-overlay (:overlays controller)\n                                       (build-numeric-adjustment-overlay controller note cue cue-var effect info))\n\n              (or (= (type cur-val) :com.evocomputing.colors/color) (= (:type cue-var) :color))\n              (controllers/add-overlay (:overlays controller)\n                                       (build-color-adjustment-overlay controller note cue cue-var effect info))\n\n              (or (= (type cur-val) Boolean) (= (:type cue-var) :boolean))\n              (controllers/add-overlay (:overlays controller)\n                                       (build-boolean-adjustment-overlay controller note cue cue-var effect info))\n\n              :else  ; Something we don't know how to adjust\n              nil)))))))\n\n(defn- note-on-received\n  \"Process a note-on message which was not handled by an interface\n  overlay.\"\n  [controller message]\n  (let [note (:note message)]\n    (cond (<= 0 note 7)\n          (display-encoder-touched controller note)\n\n          (<= 36 note 99)\n          (cue-grid-pressed controller note (:velocity message))\n\n          :else\n          ;; Some other UI element was touched\n          (case note\n            8 ; Master encoder\n            (master-encoder-touched controller)\n\n            9 ; BPM encoder\n            (bpm-encoder-touched controller)\n\n            10 ; Beat encoder\n            (beat-encoder-touched controller)\n\n            ;; Something we don't care about\n            nil))))\n\n(defn- note-off-received\n  \"Process a note-off message which was not handled by an interface\n  overlay.\"\n  [_controller message]\n  (case (:note message)\n\n    ;; Something we don't care about\n    nil))\n\n(defn- midi-received\n  \"Called whenever a MIDI message is received from the controller\n  while the mapping is active; takes whatever action is appropriate.\"\n  [controller message]\n  ;;(timbre/info message)\n  (when-not (controllers/overlay-handled? (:overlays controller) message)\n    (when (= (:command message) :control-change)\n      (control-change-received controller message))\n    (when (= (:command message) :note-on)\n      (note-on-received controller message))\n    (when (= (:command message) :note-off)\n      (note-off-received controller message))))\n\n(defn add-custom-control-button\n   \"Activates an otherwise-unused button which responds to a control\n   message, causing it to run custom code when pressed and released.\"\n   [controller button press-fn release-fn]\n   (if-let [button-info (get control-buttons button)]\n     (swap! (:custom-control-buttons controller) assoc (:control button-info)\n            {:key    button\n             :button button-info\n             :press press-fn\n             :release release-fn})\n     (throw (IllegalArgumentException. (str \"Unrecognized control button: \" button)))))\n\n(defn deactivate\n  \"Deactivates a controller interface, killing its update thread and\n  removing its MIDI listeners. If `:disconnected` is passed with a\n  `true` value, it means that the controller has already been removed\n  from the MIDI environment, so no effort will be made to clear its\n  display or take it out of User mode.\n\n  In general you will not need to call this function directly; it will\n  be dispatched to via [[controllers/deactivate]] when that is called\n  with a controller binding implementation from this namespace. It is\n  also called automatically when one of the controllers being used\n  disappears from the MIDI environment.\"\n  [controller & {:keys [disconnected] :or {disconnected false}}]\n  {:pre (= ::controller (type controller))}\n  (swap! (:task controller)\n         (fn [task]\n           (when task  ; We were running. Shut everything down.\n             (at-at/kill task)\n             (show/unregister-grid-controller @(:grid-controller-impl controller))\n             (doseq [f @(:move-listeners controller)] (f @(:grid-controller-impl controller) :deactivated))\n             (reset! (:move-listeners controller) #{})\n             (amidi/remove-device-mapping (:port-in controller) @(:midi-handler controller))\n\n             (when-not disconnected\n               (Thread/sleep 35) ; Give the UI update thread time to shut down\n               (clear-interface controller)\n\n               ;; Leave the User button bright, in case the user has Live\n               ;; running and wants to be able to see how to return to it.\n               (set-button-state controller (:user-mode control-buttons) :bright))\n\n             ;; Cancel any UI overlays which were in effect\n             (reset! (:overlays controller) (controllers/create-overlay-state))\n\n             ;; And finally, note that we are no longer active.\n             (controllers/remove-active-binding controller))\n           nil)))\n\n(def port-filter\n  \"Because the Push registers multiple ports with the MIDI\n  environment, we need to be sure to bind only to the User port. This\n  filter is used with [[filter-devices]] to screen out any port that\n  does not seem to be the User port. If port names are assigned\n  differently on your operating system, you may need to change\n  this (and please open a Pull Request); this filter seems to work for\n  Mac OS X and Windows.\"\n  [\"User Port\" \"MIDIIN2\" \"MIDIOUT2\"])\n\n(defn- recognize\n  \"Returns the controller's device ID if `message` is a response\n  from [[controllers/identify]] which marks it as an Ableton Push,\n  and the ports are User ports.\"\n  [message port-in port-out]\n  (when (and (= (take 5 (drop 4 (:data message))) '(71 21 0 25 0))\n             (= 2 (count (amidi/filter-devices port-filter [port-in port-out]))))\n    (int (aget (:data message) 1))))\n\n;; Register our recognition function and rich binding with the\n;; controller manager.\n(swap! controllers/recognizers assoc ::controller recognize)\n\n(defmethod controllers/deactivate ::controller\n  [controller & {:keys [disconnected] :or {disconnected false}}]\n  (deactivate controller :disconnected disconnected))\n\n(defmethod controllers/bind-to-show-impl ::controller\n  [_kind show port-in port-out device & {:keys [refresh-interval display-name]\n                                         :or   {refresh-interval (/ 1000 15)\n                                                display-name     \"Ableton Push\"}}]\n  (let [modes (atom #{})\n        controller\n        (with-meta\n          {:display-name           display-name\n           :device-id              device\n           :show                   show\n           :origin                 (atom [0 0])\n           :effect-offset          (atom 0)\n           :cue-var-offsets        (atom {})\n           :refresh-interval       refresh-interval\n           :port-in                port-in\n           :port-out               port-out\n           :task                   (atom nil)\n           :last-display           (vec (for [_ (range 4)] (byte-array (take 68 (repeat 32)))))\n           :next-display           (vec (for [_ (range 4)] (byte-array (take 68 (repeat 32)))))\n           :last-text-buttons      (atom {})\n           :next-text-buttons      (atom {})\n           :last-top-pads          (int-array 8)\n           :next-top-pads          (int-array 8)\n           :last-grid-pads         (make-array clojure.lang.IPersistentMap 64)\n           :next-grid-pads         (make-array clojure.lang.IPersistentMap 64)\n           :metronome-mode         (atom {})\n           :last-marker            (atom nil)\n           :modes                  modes\n           :last-touch-strip       (atom nil)\n           :next-touch-strip       (atom nil)\n           :midi-handler           (atom nil)\n           :tempo-tap-handler      (tempo/create-show-tempo-tap-handler\n                                    show :shift-fn (fn [] (get @modes (get-in control-buttons [:shift :control]))))\n           :overlays               (controllers/create-overlay-state)\n           :custom-control-buttons (atom {})\n           :move-listeners         (atom #{})\n           :grid-controller-impl   (atom nil)}\n          {:type ::controller})]\n    (reset! (:midi-handler controller) (partial midi-received controller))\n    (reset! (:grid-controller-impl controller)\n            (reify controllers/IGridController\n              (display-name [_this] (:display-name controller))\n              (controller [_this] controller)\n              (physical-height [_this] 8)\n              (physical-width [_this] 8)\n              (current-bottom [_this] (@(:origin controller) 1))\n              (current-bottom [_this y] (move-origin controller (assoc @(:origin controller) 1 y)))\n              (current-left [_this] (@(:origin controller) 0))\n              (current-left [_this x] (move-origin controller (assoc @(:origin controller) 0 x)))\n              (add-move-listener [_this f] (swap! (:move-listeners controller) conj f))\n              (remove-move-listener [_this f] (swap! (:move-listeners controller) disj f))))\n    ;; Set controller in User mode\n    (midi/midi-sysex (:port-out controller) [240 71 127 21 98 0 1 1 247])\n    ;; Put pads in aftertouch (poly) pressure mode\n    (midi/midi-sysex (:port-out controller) [240 71 127 21 92 0 1 0 247])\n    ;; Set pad sensitivity level to 1 to avoid stuck pads\n    (midi/midi-sysex (:port-out controller)\n                     [0xF0 0x47 0x7F 0x15 0x5D 0x00 0x20 0x00 0x00 0x0C 0x07 0x00 0x00 0x0D 0x0C 0x00\n                      0x00 0x00 0x01 0x04 0x0C 0x00 0x08 0x00 0x00 0x00 0x01 0x0D 0x04 0x0C 0x00 0x00\n                      0x00 0x00 0x00 0x0E 0x0A 0x06 0x00 0xF7])\n    (clear-interface controller)\n    (welcome-animation controller)\n    (controllers/add-active-binding controller)\n    (show/register-grid-controller @(:grid-controller-impl controller))\n    (amidi/add-disconnected-device-handler! port-in #(deactivate controller :disconnected true))\n    controller))\n\n(defn bind-to-show\n  \"*Deprecated in favor of the shared [[controllers/bind-to-show]]\n  implementation.*\n\n  Establish a connection to the Ableton Push, for managing the given\n  show.\n\n  Initializes the display, and starts the UI updater thread. Since\n  SysEx messages are required for updating the display, if you are on\n  a Mac, Afterglow\n  embeds [CoreMIDI4J](https://github.com/DerekCook/CoreMidi4J) to\n  provide a working implementation.\n\n  If you have more than one Ableton Push connected, or have renamed\n  how it appears in your list of MIDI devices, you need to supply a\n  value after `:device-filter` which identifies the ports to be used to\n  communicate with the Push you want this function to use. The values\n  returned by [[afterglow.midi/open-inputs-if-needed!]]\n  and [[afterglow.midi/open-outputs-if-needed!]] will be searched, and\n  the first port that matches with [[filter-devices]] will be used.\n\n  The controller will be identified in the user interface (for the\n  purposes of linking it to the web cue grid) as \\\"Ableton Push\\\". If\n  you would like to use a different name (for example, if you are\n  lucky enough to have more than one Push), you can pass in a custom\n  value after `:display-name`.\n\n  If you want the user interface to be refreshed at a different rate\n  than the default of fifteen times per second, pass your desired\n  number of milliseconds after `:refresh-interval`.\"\n  {:deprecated \"0.2.1\"}\n  [show & {:keys [device-filter refresh-interval display-name]\n           :or   {device-filter    \"User Port\"\n                  refresh-interval (/ 1000 15)\n                  display-name     \"Ableton Push\"}}]\n  (controllers/bind-to-show show device-filter :refresh-interval refresh-interval :display-name display-name))\n\n(defn auto-bind\n  \"*Deprecated in favor of the shared [[controllers/auto-bind]]\n  implementation.*\n\n  Watches for an Ableton Push controller to be connected, and as soon\n  as it is, binds it to the specified show using [[bind-to-show]]. If\n  that controller ever gets disconnected, it will be re-bound once it\n  reappears. Returns a watcher structure which can be passed\n  to [[deactivate]] if you would like to stop it watching for\n  reconnections. The underlying controller mapping, once bound, can be\n  accessed through the watcher's `:controller` key.\n\n  If you have more than one Ableton Push that might beconnected, or\n  have renamed how it appears in your list of MIDI devices, you need\n  to supply a value after `:device-filter` which identifies the ports to\n  be used to communicate with the Push you want this function to use.\n  The values returned by [[afterglow.midi/open-inputs-if-needed!]]\n  and [[afterglow.midi/open-outputs-if-needed!]] will be searched, and\n  the first port that matches using [[filter-devices]] will be used.\n\n  Once bound, the controller will be identified in the user\n  interface (for the purposes of linking it to the web cue grid) as\n  \\\"Ableton Push\\\". If you would like to use a different name (for\n  example, if you are lucky enough to have more than one Push), you\n  can pass in a custom value after `:display-name`.\n\n  If you want the user interface to be refreshed at a different rate\n  than the default of fifteen times per second, pass your desired\n  number of milliseconds after `:refresh-interval`.\"\n  {:deprecated \"0.2.1\"}\n  [show & {:keys [device-filter refresh-interval display-name]\n           :or {device-filter \"User Port\"\n                refresh-interval (/ 1000 15)\n                display-name \"Ableton Push\"}}]\n  (controllers/auto-bind show device-filter :refresh-interval refresh-interval :display-name display-name))\n"
  },
  {
    "path": "src/afterglow/controllers/ableton_push_2.clj",
    "content": "(ns afterglow.controllers.ableton-push-2\n  \"Allows the Ableton Push 2 to be used as a control surface for\n  Afterglow. Its features are described in the [Developer\n  Guide]({{guide-url}}push2.html).\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.controllers :as controllers]\n            [afterglow.controllers.tempo :as tempo]\n            [afterglow.effects.cues :as cues]\n            [afterglow.effects.dimmer :refer [master-get-level master-set-level]]\n            [afterglow.midi :as amidi]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [with-show]]\n            [afterglow.util :as util]\n            [afterglow.version :as version]\n            [clojure.java.io :as io]\n            [clojure.math.numeric-tower :as math]\n            [clojure.set :as set]\n            [clojure.string :as str]\n            [com.evocomputing.colors :as colors]\n            [overtone.at-at :as at-at]\n            [overtone.midi :as midi]\n            [taoensso.timbre :as timbre])\n  (:import [afterglow.effects Effect]\n           [org.deepsymmetry Wayang]\n           [java.awt GraphicsEnvironment Font AlphaComposite RenderingHints]\n           [javax.sound.midi ShortMessage]))\n\n(defonce fonts-loaded\n  (atom false))\n\n(defn load-fonts\n  \"Load and register the fonts we will use to draw on the display, if\n  they have not already been.\"\n  []\n  (or @fonts-loaded\n      (let [ge (GraphicsEnvironment/getLocalGraphicsEnvironment)]\n        (doseq [font-file [\"/public/fonts/Open_Sans_Condensed/OpenSans-CondLight.ttf\"\n                           \"/public/fonts/Open_Sans_Condensed/OpenSans-CondLightItalic.ttf\"\n                           \"/public/fonts/Open_Sans_Condensed/OpenSans-CondBold.ttf\"\n                           \"/public/fonts/Roboto/Roboto-Medium.ttf\"\n                           \"/public/fonts/Roboto/Roboto-MediumItalic.ttf\"\n                           \"/public/fonts/Roboto/Roboto-Regular.ttf\"\n                           \"/public/fonts/Roboto/Roboto-Bold.ttf\"\n                           \"/public/fonts/Roboto/Roboto-Italic.ttf\"\n                           \"/public/fonts/Roboto/Roboto-BoldItalic.ttf\"\n                           \"/public/fonts/Lekton/Lekton-Regular.ttf\"]]\n            (.registerFont ge (java.awt.Font/createFont\n                               java.awt.Font/TRUETYPE_FONT\n                               (.getResourceAsStream Effect font-file))))\n        (reset! fonts-loaded true))))\n\n(defn get-display-font\n  \"Find one of the fonts configured for use on the display by keyword,\n  which should be one of `:condensed`, `:condensed-light`, `:roboto`,\n  or `:roboto-medium`. The `style` argument is a `java.awt.Font` style\n  constant, and `size` is point size.\n\n  Roboto is available in all style variations, Roboto Medium in plain\n  and italic, Condensed only in bold, and condensed light in plain and\n  italic.\"\n  [k style size]\n  (case k\n    :condensed       (Font. \"Open Sans Condensed\" Font/BOLD size)\n    :condensed-light (Font. \"Open Sans Condensed Light\" style size)\n    :monospace       (Font. \"Lekton\" style size)\n    :roboto          (Font. \"Roboto\" style size)\n    :roboto-medium   (Font. \"Roboto Medium\" style size)))\n\n(defn dim\n  \"Return a dimmed version of a color.\"\n  [color]\n  (colors/darken color 35))\n\n(def off-color\n  \"The color of buttons that are completely off.\"\n  (colors/create-color :black))\n\n(def amber-color\n  \"The color for bright amber buttons.\"\n  (colors/create-color :h 45 :s 100 :l 50))\n\n(def dim-amber-color\n  \"The color for dim amber buttons.\"\n  (dim amber-color))\n\n(def red-color\n  \"The color for bright red buttons.\"\n  (colors/create-color :red))\n\n(def dim-red-color\n  \"The color for dim red buttons.\"\n  (dim red-color))\n\n(def green-color\n  \"The color for bright green buttons.\"\n  (colors/create-color :green))\n\n(def dim-green-color\n  \"The color for dim green buttons.\"\n  (dim green-color))\n\n(def white-color\n  \"The color for bright white buttons.\"\n  (colors/create-color :white))\n\n(def dim-white-color\n  \"The color for dim white buttons.\"\n  (colors/darken white-color 90))\n\n(def default-track-color\n  \"The color gauge tracks will use unless otherwise specified.\"\n  (colors/darken white-color 50))\n\n\n(defn send-sysex\n  \"Send a MIDI System Exclusive command to the Push 2 with the proper\n  prefix. The `command` argument begins with the Command ID of the\n  desired command, as listed in Table 2.4.2 of the Ableton Push 2 MIDI\n  and Display Interface Manual, followed by its parameter bytes. The\n  `SOX` byte, Ableton Sysex ID, device ID, and model ID will be\n  prepended, and the `EOX` byte appended, before sending the command.\"\n  [controller command]\n  (midi/midi-sysex (:port-out controller)\n                   (concat [0xf0 0x00 0x21 0x1d (:device-id controller) 0x01] command [0xf7])))\n\n(defn- request-led-palette-entry\n  \"Ask the Push 2 for the LED palette entry with the specified index.\"\n  [controller index]\n  (send-sysex controller [0x04 index]))\n\n(defn- save-led-palette-entry\n  \"Record an LED palette entry we have received in response to our\n  startup query, so we can preserve the white palette when setting RGB\n  colors, and restore all LED palettes when we suspend or exit our\n  mapping.\n\n  Make a note of the fact that we received a palette response at the\n  current moment in time in `gather-timestamp`, and if this was not\n  the final palette entry, request the next one. If it was the final\n  one, deliver a true value to `gather-timestamp`.\"\n  [controller data gather-timestamp gather-promise]\n  (let [index (first data)]\n    (swap! (:led-palettes controller) assoc index (vec (rest data)))\n    (reset! gather-timestamp (at-at/now))\n    (if (< index 127)  ; Ask for the next entry unless we have received them all\n      (request-led-palette-entry controller (inc index))\n      (deliver gather-promise true))))\n\n(defonce ^:private ^{:doc \"The currently active pad grid batch-update\n  function, if any. Will be called whenever we receive a display\n  backlight level Sysex response, which is our cue that the Push has\n  caught up in drawing LEDs.\"}\n  grid-batch-update-fn\n  (atom nil))\n\n(defn- sysex-received\n  \"Process a MIDI System Exclusive reply from the Push 2. The `msg`\n  argument is the raw data we have just received. If\n  `gather-timestamp` and `gather-promise` were supplied, and we see an\n  LED palette reply, this reply was received during startup when we\n  are gathering LED palette entries, so we should use them to record\n  any palette response. If we see a display backlight reply, it means\n  the Push has caught up with our batch of pad grid LED color updates,\n  and we can start sending the next.\"\n  ([controller msg]\n   (sysex-received controller msg nil nil))\n  ([controller msg gather-timestamp gather-promise]\n   (if (= (vec (take 5 (:data msg))) [0x00 0x21 0x1d (:device-id controller) 0x01])\n     (let [data (map int (butlast (drop 5 (:data msg))))\n           command (first data)\n           args (rest data)]\n       (case command\n         0x04 (if (some? gather-timestamp)\n                (save-led-palette-entry controller args gather-timestamp gather-promise)\n                (timbre/warn \"Ignoring Push 2 LED palette response when not gathering palette.\"))\n\n         0x09 (when-let [f @grid-batch-update-fn]  ; Display backlight reply; ready for next grid update batch\n                (f))\n\n         (timbre/warn \"Ignoring SysEx message from Push 2 with command ID\" command)))\n     (timbre/warn \"Received unrecognized SysEx message from Push 2 port.\" (vec (:data msg))))))\n\n(defn- gather-led-palettes\n  \"Ask the Push 2 for all of its LED palettes. We ask for the first,\n  then when we receive that, ask for the next, until we have got them\n  all, to avoid overflowing its buffers. We will wait for up to half a\n  second for this process to complete. If that elapses, and it has\n  been more than 100ms since we sent our last request, we give up.\n\n  Return a truthy value to indicate success.\"\n  [controller]\n  (let [gather-timestamp (atom (at-at/now))\n        gather-promise (promise)\n        startup-handler (fn [message]\n                          (if (= 0xf0 (:status message))\n                            (sysex-received controller message gather-timestamp gather-promise)\n                            (timbre/info \"Ignoring non-sysex message received during Push 2 startup.\")))]\n    (try\n      (amidi/add-device-mapping (:port-in controller) startup-handler)\n      (loop []\n        (request-led-palette-entry controller 0)\n        (or (deref gather-promise 500 false)\n            (if (> (- (at-at/now) @gather-timestamp) 100)\n              (timbre/error \"Failed to gather LED Palette entries for Push 2; giving up.\")\n              (do\n                (timbre/warn \"Gathering LED Palette entries for Push 2 is taking more than half a second.\")\n                (recur)))))\n      (finally (amidi/remove-device-mapping (:port-in controller) startup-handler)))))\n\n(defn- restore-led-palettes\n  \"Set the LED palettes back to the way we found them during our\n  initial binding. This is called when clearing the interface when\n  exiting user mode or deactivating the binding, so we can gracefully\n  coexist with Live.\"\n  [controller]\n  (let [sent (volatile! 0)]\n    (doseq [[index palette] @(:led-palettes controller)]\n      (send-sysex controller (concat [0x03 index] palette))\n      (when (zero? (rem (vswap! sent inc) 10))\n        (Thread/sleep 5)))))\n\n(defn set-pad-color\n  \"Set the color of one of the 64 touch pads to a specific RGB color.\n  If the color is black, we send a note off to the pad. Otherwise, we\n  take over the color palette entry whose velocity matches the note\n  number of the pad, and set it to the desired RGB value, then send it\n  a note with the velocity corresponding to the palette entry we just\n  adjusted.\n\n  Since we also have to set a white value, we pass along the white\n  value that was present in the palette we found for this velocity\n  when initially binding to the Push 2.\"\n  [controller x y color]\n  {:pre [(<= 0 x 7) (<= 0 y 7)]}\n  (let [note (+ 36 x (* y 8))\n        palette (get @(:led-palettes controller) note)]\n    (if (util/float= (colors/lightness color) 0.0)\n      (midi/midi-note-off (:port-out controller) note)\n      (let [r (colors/red color)\n            g (colors/green color)\n            b (colors/blue color)]\n        (send-sysex controller [0x03 note (bit-and r 0x7f) (quot r 0x80) (bit-and g 0x7f) (quot g 0x80)\n                                (bit-and b 0x7f) (quot b 0x80) (get palette 6) (get palette 7)])\n        (midi/midi-note-on (:port-out controller) note note)))))\n\n(def control-buttons\n  \"The labeled buttons which send and respond to Control Change\n  events.\"\n  {:tap-tempo             {:control 3 :kind :monochrome}\n   :metronome             {:control 9 :kind :monochrome}\n\n   :master                {:control 28 :kind :monochrome}\n\n   :quarter               {:control 36 :kind :color :index 8}\n   :quarter-triplet       {:control 37 :kind :color :index 9}\n   :eighth                {:control 38 :kind :color :index 10}\n   :eighth-triplet        {:control 39 :kind :color :index 11}\n   :sixteenth             {:control 40 :kind :color :index 12}\n   :sixteenth-triplet     {:control 41 :kind :color :index 13}\n   :thirty-second         {:control 42 :kind :color :index 14}\n   :thirty-second-triplet {:control 43 :kind :color :index 15}\n\n   :left-arrow            {:control 44 :kind :monochrome}\n   :right-arrow           {:control 45 :kind :monochrome}\n   :up-arrow              {:control 46 :kind :monochrome}\n   :down-arrow            {:control 47 :kind :monochrome}\n\n   :select                {:control 48 :kind :monochrome}\n   :shift                 {:control 49 :kind :monochrome}\n\n   :note                  {:control 50 :kind :monochrome}\n   :session               {:control 51 :kind :monochrome}\n\n   :add-device            {:control 52 :kind :monochrome}\n   :add-track             {:control 53 :kind :monochrome}\n\n   :device-mode           {:control 110 :kind :monochrome}\n   :browse-mode           {:control 111 :kind :monochrome}\n   :mix-mode              {:control 112 :kind :monochrome}\n   :clip-mode             {:control 113 :kind :monochrome}\n\n   :repeat                {:control 56 :kind :monochrome}\n   :accent                {:control 57 :kind :monochrome}\n   :scales                {:control 58 :kind :monochrome}\n   :layout                {:control 31 :kind :monochrome}\n\n   :setup                 {:control 30 :kind :monochrome}\n   :user-mode             {:control 59 :kind :monochrome}\n\n   :page-left             {:control 62 :kind :monochrome}\n   :page-right            {:control 63 :kind :monochrome}\n   :octave-down           {:control 54 :kind :monochrome}\n   :octave-up             {:control 55 :kind :monochrome}\n\n   :stop                  {:control 85 :kind :color :index 2}  ; The play button, but stop for stop mode.\n   :record                {:control 86 :kind :color :index 3 :dim-color dim-red-color :bright-color red-color}\n   :automate              {:control 89 :kind :color :index 4}\n   :fixed-length          {:control 90 :kind :monochrome}\n\n   :new                   {:control 87 :kind :monochrome}\n   :duplicate             {:control 88 :kind :monochrome}\n\n   :quantize              {:control 116 :kind :monochrome}\n   :double                {:control 117 :kind :monochrome}\n   :convert               {:control 35 :kind :monochrome}\n\n   :mute                  {:control 60 :kind :color :index 5}\n   :solo                  {:control 61 :kind :color :index 6}\n   :stop-clip             {:control 29 :kind :color :index 7}\n\n   :delete                {:control 118 :kind :monochrome}\n   :undo                  {:control 119 :kind :monochrome}\n\n   :top-pad-0             {:control 20 :kind :color}\n   :top-pad-1             {:control 21 :kind :color}\n   :top-pad-2             {:control 22 :kind :color}\n   :top-pad-3             {:control 23 :kind :color}\n   :top-pad-4             {:control 24 :kind :color}\n   :top-pad-5             {:control 25 :kind :color}\n   :top-pad-6             {:control 26 :kind :color}\n   :top-pad-7             {:control 27 :kind :color}\n\n   :encoder-pad-0         {:control 102 :kind :color}\n   :encoder-pad-1         {:control 103 :kind :color}\n   :encoder-pad-2         {:control 104 :kind :color}\n   :encoder-pad-3         {:control 105 :kind :color}\n   :encoder-pad-4         {:control 106 :kind :color}\n   :encoder-pad-5         {:control 107 :kind :color}\n   :encoder-pad-6         {:control 108 :kind :color}\n   :encoder-pad-7         {:control 109 :kind :color}})\n\n(defn set-cc-led-color\n  \"Set one of the color LEDs that respond to control change values to\n  a particular color. If the color is black, we send a control value\n  of zero. Otherwise, we take over the color palette entry assigned to\n  the LED, and set it to the desired RGB value, then send it a control\n  change with the velocity corresponding to the palette entry we just\n  adjusted.\n\n  Since we also have to set a white value, we pass along the white\n  value that was present in the palette we found for this entry\n  when initially binding to the Push 2.\"\n  [controller control palette-index color]\n  (let [palette (get @(:led-palettes controller) palette-index)]\n    (if (util/float= (colors/lightness color) 0.0)\n      (midi/midi-control (:port-out controller) control 0)\n        (let [r (colors/red color)\n              g (colors/green color)\n              b (colors/blue color)]\n          (send-sysex controller [0x03 palette-index (bit-and r 0x7f) (quot r 0x80) (bit-and g 0x7f) (quot g 0x80)\n                                  (bit-and b 0x7f) (quot b 0x80) (get palette 6) (get palette 7)])\n        (midi/midi-control (:port-out controller) control palette-index)))))\n\n(defn set-button-color\n  \"Set one of the labeled buttons to a particular color (if it is a\n  monochrome button, the lightness of the color is translated to a\n  control value; otherwise, the palette entry assigned to the button\n  is set to the specified color, and the corresponding velocity is\n  sent.\"\n  [controller button color]\n  (if (= :monochrome (:kind button))\n    (midi/midi-control (:port-out controller) (:control button)\n                       (math/round (* (/ (colors/lightness color) 100) 127)))\n    (set-cc-led-color controller (:control button) (or (:index button) (:control button)) color)))\n\n(defn set-top-pad-color\n  \"Set one of the top-row pads (between the grid and the display) to a\n  particular color.\"\n  [controller x color]\n  (set-button-color controller (get control-buttons (keyword (str \"top-pad-\" x))) color))\n\n(defn set-encoder-pad-color\n  \"Set one of the pads below the row of display encoders to a\n  particular color.\"\n  [controller x color]\n  (set-button-color controller (get control-buttons (keyword (str \"encoder-pad-\" x))) color))\n\n(def touch-strip-mode-flags\n  \"The values which are combined to set the touch strip into\n  particular modes.\"\n  {:touch-strip-controlled-by-push        0\n   :touch-strip-controlled-by-host        1\n   :touch-strip-host-sends-values         0\n   :touch-strip-host-sends-sysex          2\n   :touch-strip-values-sent-as-pitch-bend 0\n   :touch-strip-values-sent-as-mod-wheel  4\n   :touch-strip-leds-show-bar             0\n   :touch-strip-leds-show-point           8\n   :touch-strip-bar-starts-at-bottom      0\n   :touch-strip-bar-starts-at-center      16\n   :touch-strip-auto-return-inactive      0\n   :touch-strip-auto-return-active        32\n   :touch-strip-auto-return-to-bottom     0\n   :touch-strip-auto-return-to-center     64})\n\n(defn build-touch-strip-mode\n  \"Calculate a touch strip mode byte based on a list of flags (keys in\n  `touch-strip-mode-flags`).\"\n  [& flags]\n  (apply + (map touch-strip-mode-flags (set flags))))\n\n(def touch-strip-mode-default\n  \"The mode to which we should return the touch strip when we are\n  shutting down.\"\n  (build-touch-strip-mode :touch-strip-controlled-by-push :touch-strip-host-sends-values\n                          :touch-strip-values-sent-as-pitch-bend :touch-strip-leds-show-point\n                          :touch-strip-bar-starts-at-bottom :touch-strip-auto-return-active\n                          :touch-strip-auto-return-to-center))\n\n(def touch-strip-mode-level\n  \"The mode to which we should set the touch strip when the user is\n  editing a pan-style control.\"\n  (build-touch-strip-mode :touch-strip-controlled-by-host :touch-strip-host-sends-values\n                          :touch-strip-values-sent-as-pitch-bend :touch-strip-leds-show-bar\n                          :touch-strip-bar-starts-at-bottom :touch-strip-auto-return-inactive\n                          :touch-strip-auto-return-to-center))\n\n(def touch-strip-mode-pan\n  \"The mode to which we should set the touch strip when the user is\n  editing a level-style control.\"\n  (build-touch-strip-mode :touch-strip-controlled-by-host :touch-strip-host-sends-values\n                          :touch-strip-values-sent-as-pitch-bend :touch-strip-leds-show-bar\n                          :touch-strip-bar-starts-at-center :touch-strip-auto-return-inactive\n                          :touch-strip-auto-return-to-center))\n\n(def touch-strip-mode-hue\n  \"The mode to which we should set the touch strip when the user is\n  editing a hue.\"\n  (build-touch-strip-mode :touch-strip-controlled-by-host :touch-strip-host-sends-values\n                          :touch-strip-values-sent-as-pitch-bend :touch-strip-leds-show-point\n                          :touch-strip-bar-starts-at-bottom :touch-strip-auto-return-inactive\n                          :touch-strip-auto-return-to-center))\n\n(def touch-strip-mode-sysex\n  \"The mode to which we should set the touch strip when we want to be\n  able to individually set LEDs, for example to turn them all off.\"\n  (build-touch-strip-mode :touch-strip-controlled-by-host :touch-strip-host-sends-sysex\n                          :touch-strip-auto-return-inactive :touch-strip-auto-return-to-center))\n\n(defn clear-all-touch-strip-leds\n  \"Send a System Exclusive message which requests all touch strip LEDs\n  be turned off.\"\n  [controller]\n  (send-sysex controller (concat [0x19] (repeat 16 0))))\n\n(defn- clear-display-buffer\n  \"Clear the graphical display buffer in preparation for drawing an\n  interface frame.\"\n  [controller]\n  (let [graphics (.createGraphics (:display-buffer controller))]\n    (.setPaint graphics java.awt.Color/BLACK)\n    (.fillRect graphics 0 0 Wayang/DISPLAY_WIDTH Wayang/DISPLAY_HEIGHT)))\n\n(defn clear-display\n  \"Clear the graphical display.\"\n  [controller]\n  (clear-display-buffer controller)\n  (Wayang/sendFrame))\n\n(defn create-graphics\n  \"Create the graphics object we will use to draw in the display, and\n  configure its rendering hints properly.\"\n  [controller]\n  (let [graphics (.createGraphics (:display-buffer controller))]\n    (.setRenderingHint graphics RenderingHints/KEY_ANTIALIASING RenderingHints/VALUE_ANTIALIAS_ON)\n    graphics))\n\n(defn show-labels\n  \"Illuminates all buttons with text labels, for development assistance.\"\n  ([controller]\n   (show-labels controller (colors/create-color :white)))\n  ([controller color]\n   (doseq [[_ button] control-buttons]\n     (set-button-color controller button color))))\n\n(defn- update-top-pads\n  \"Sees if any of the top row of pads have changed state since\n  the interface was updated, and if so, sends the necessary MIDI\n  messages to update them on the Push.\"\n  [controller]\n  (doseq [x (range 8)]\n    (let [next-color (get @(:next-top-pads controller) x)]\n      (when (not= next-color\n                  (get @(:last-top-pads controller) x))\n        (set-top-pad-color controller x next-color)\n        (swap! (:last-top-pads controller) assoc x next-color)))))\n\n(defn set-touch-strip-mode\n  \"Set the touch strip operating mode.\"\n  [controller mode]\n  (send-sysex controller [0x17 mode]))\n\n(defn- update-touch-strip\n  \"Sees if the state of the touch strip has changed since the\n  interface was updated, and if so, sends the necessary MIDI control\n  values to update it on the Push.\"\n  [controller]\n  (let [next-strip @(:next-touch-strip controller)\n        [_ last-mode] @(:last-touch-strip controller)]\n    (when (not= next-strip @(:last-touch-strip controller))\n      (if next-strip\n        (let [[value mode] next-strip\n              message (ShortMessage.)]\n          (when (not= mode last-mode)\n            (set-touch-strip-mode controller mode)\n            (when (= mode touch-strip-mode-sysex)  ; We want the touch strip fully dark\n              (clear-all-touch-strip-leds controller)))\n          (when (not= mode touch-strip-mode-sysex)  ; We are actually displaying values\n            (.setMessage message ShortMessage/PITCH_BEND 0 (rem value 128) (quot value 128))\n            (midi/midi-send-msg (get-in controller [:port-out :receiver]) message -1))\n          (reset! (:last-touch-strip controller) next-strip))\n        (do\n          (set-touch-strip-mode controller touch-strip-mode-default)\n          (reset! (:last-touch-strip controller) nil))))))\n\n(defn- set-touch-strip-from-value\n  \"Display a value being adjusted in the touch strip.\"\n  [controller value low high mode]\n  (let [value      (min high (max low value))  ; Clip value to inside displayed range\n        full-range (- high low)]\n    (reset! (:next-touch-strip controller) [(math/round (* 16383 (/ (- value low) full-range))) mode])))\n\n(defn- set-touch-strip-from-cue-var\n  \"Display the value of a cue variable being adjusted in the touch\n  strip.\"\n  [controller cue v effect-id]\n  (let [value (or (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id) 0)\n        low (min value (:min v))  ; In case user set \"out of bounds\".\n        high (max value (:max v))]\n    (set-touch-strip-from-value controller value low high\n                                (if (:centered v) touch-strip-mode-pan touch-strip-mode-level))))\n\n(defn- value-from-touch-strip\n  \"Convert a pitch bend message from the touch strip to the\n  corresponding variable value it represents.\"\n  [message low high]\n  (let [full-range (- high low)]\n    (+ low (* full-range (double (/ (+ (* (:data2 message) 128) (:data1 message)) 16383))))))\n\n(defn- update-text-buttons\n  \"Sees if any labeled buttons have changed state since the last time\n  the interface was updated, and if so, sends the necessary MIDI\n  commands to update them on the Push.\"\n  [controller]\n  ;; First turn off any which were on before but no longer are\n  (doseq [[button old-color] @(:last-text-buttons controller)]\n    (when-not (get @(:next-text-buttons controller) button)\n      (when-not (= off-color old-color)\n        (set-button-color controller button off-color))))\n\n  ;; Then, set any currently requested states\n  (doseq [[button color] @(:next-text-buttons controller)]\n    (when-not (= (get @(:last-text-buttons controller) button) color)\n      (set-button-color controller button color)))\n\n  ;; And record the new state for next time\n  (reset! (:last-text-buttons controller) @(:next-text-buttons controller)))\n\n(def button-cell-width\n  \"The number of pixels allocated to each button above or below the\n  graphical display.\"\n  (/ Wayang/DISPLAY_WIDTH 8))\n\n(def button-cell-margin\n  \"The number of pixels to keep blank between labels of adjacent buttons.\"\n  4)\n\n(defn string-width\n  \"Determines how many pixels wide a string will be in a given font\n  and render context.\"\n  [text font render-context]\n  (.getWidth (.getStringBounds font text render-context)))\n\n(defn fit-string\n  \"Truncates a string (appending an ellipsis) enough to fit within a\n  given pixel width.\"\n  [text font render-context max-width]\n  (if (or (str/blank? text) (<= (string-width text font render-context) max-width))\n    text\n    (loop [truncated (subs text 0 (dec (count text)))]\n      (let [result (str truncated \"…\")]\n        (if (or (str/blank? truncated) (<= (string-width result font render-context) max-width))\n          result\n          (recur (subs truncated 0 (dec (count truncated)))))))))\n\n(defn set-graphics-color\n  \"Set the paint of the supplied graphics context to use the specified\n  color.\"\n  [graphics color]\n  (.setPaint graphics (java.awt.Color. (colors/red color) (colors/green color) (colors/blue color)\n                                       (colors/alpha color))))\n\n(defn calculate-text-width\n  \"Figure out how many pixels wide some text will be in a given font.\"\n  [graphics font text]\n  (let [context (.getFontRenderContext graphics)]\n    (.getWidth (.getStringBounds font text context))))\n\n(defn draw-bottom-button-label\n  \"Draw a label for a button below the graphical display.\"\n  [controller index text color & {:keys [background-color] :or {background-color off-color}}]\n  (let [graphics (create-graphics controller)\n        font (get-display-font :roboto-medium Font/BOLD 14)\n        context (.getFontRenderContext graphics)\n        label (fit-string text font context (- button-cell-width button-cell-margin))\n        width (string-width label font context)]\n    (set-graphics-color graphics background-color)\n    (.fillRect graphics (* index button-cell-width) (- Wayang/DISPLAY_HEIGHT 15)\n               button-cell-width 15)\n    (set-graphics-color graphics color)\n    (.setFont graphics font)\n    (.drawString graphics label (int (math/round (- (* (+ index 0.5) button-cell-width) (/ width 2))))\n                 (- Wayang/DISPLAY_HEIGHT 4))))\n\n(defn- space-for-encoder-button-label\n  \"Calculate how much room there is to draw a label under an encoder,\n  based on how many encoders the label applies to.\"\n  [encoder-count]\n  (- (* button-cell-width encoder-count) button-cell-margin))\n\n(def font-for-encoder-button-label\n  \"The font used when drawing labels under encoders.\"\n  (get-display-font :condensed Font/PLAIN 14))\n\n(def encoder-label-underline-height\n  \"The height at which to draw the line under an encoder label.\"\n  20.0)\n\n(defn draw-encoder-button-label\n  \"Draw a label under an encoder at the top of the graphical display.\"\n  [controller index encoder-count text color]\n  (let [graphics (create-graphics controller)\n        space (space-for-encoder-button-label encoder-count)\n        context (.getFontRenderContext graphics)\n        label (fit-string text font-for-encoder-button-label context space)\n        width (string-width label font-for-encoder-button-label context)]\n    (set-graphics-color graphics color)\n    (.setFont graphics font-for-encoder-button-label)\n    (.drawString graphics label\n                 (int (math/round (- (* (+ index (/ encoder-count 2)) button-cell-width) (/ width 2)))) 16)\n    (.draw graphics (java.awt.geom.Line2D$Double.\n                     (+ (* index button-cell-width) (/ button-cell-margin 2.0)) encoder-label-underline-height\n                     (- (* (+ index encoder-count) button-cell-width) (/ button-cell-margin 2.0) 1.0)\n                     encoder-label-underline-height))))\n\n(def font-for-cue-variable-values\n  \"The font used when drawing cue variable values.\"\n  (get-display-font :condensed-light Font/PLAIN 22))\n\n(def font-for-cue-variable-emphasis\n  \"The font used when drawing cue variable values.\"\n  (get-display-font :condensed Font/PLAIN 22))\n\n(defn draw-attributed-variable-value\n  \"Draw a label under an encoder at the top of the graphical display,\n  with an attributed string so the label can have mixed fonts, colors,\n  etc. Assumes the value will fit in the allocated space.\"\n  [controller index encoder-count attributed-string color]\n  (let [graphics (create-graphics controller)\n        context (.getFontRenderContext graphics)\n        iterator (.getIterator attributed-string)\n        measurer (java.awt.font.LineBreakMeasurer. iterator context)\n        layout (.nextLayout measurer Integer/MAX_VALUE)\n        width (.getWidth (.getBounds layout))]\n    ;; Establish a default color for characters that don't change it\n    (set-graphics-color graphics color)\n    (.drawString graphics iterator\n                 (int (math/round (- (* (+ index (/ encoder-count 2)) button-cell-width) (/ width 2)))) 40)))\n\n(defn draw-cue-variable-value\n  \"Draw a label under an encoder at the top of the graphical display.\"\n  ([controller index encoder-count text color]\n   (draw-cue-variable-value controller index encoder-count text color font-for-cue-variable-values))\n  ([controller index encoder-count text color font]\n   (if (= (class text) java.text.AttributedString)\n     (draw-attributed-variable-value controller index encoder-count text color)\n     (let [graphics (create-graphics controller)\n           space (space-for-encoder-button-label encoder-count)\n           context (.getFontRenderContext graphics)\n           label (fit-string text font context space)\n           width (string-width label font context)]\n       (set-graphics-color graphics color)\n       (.setFont graphics font)\n       (.drawString graphics label\n                    (int (math/round (- (* (+ index (/ encoder-count 2)) button-cell-width) (/ width 2)))) 40)))))\n\n(defn draw-null-gauge\n \"Draw a mostly meaningless gauge simply to indicate that the encoder\n is doing something. Used for beat adjustments, for example, which\n have no reasonable range or location to show.\"\n  [controller index encoder-count color]\n  (let [graphics (create-graphics controller)\n        x-center (+ (* index button-cell-width) (* encoder-count 0.5 button-cell-width))]\n    (set-graphics-color graphics color)\n    (.draw graphics (java.awt.geom.Ellipse2D$Double. (- x-center 20.0) 50.0 40.0 40.0))))\n\n(defn draw-gauge\n  \"Draw a graphical gauge with an indicator that fills an arc under a\n  variable value. The default range is from zero to a hundred, and the\n  default color for both the track and active area is dim white.\"\n  [controller index encoder-count value & {:keys [lowest highest track-color active-color]\n                                           :or {lowest 0 highest 100\n                                                track-color default-track-color active-color track-color}}]\n  (let [graphics (create-graphics controller)\n        range (- highest lowest)\n        fraction (/ (- value lowest)  range)\n        x-center (+ (* index button-cell-width) (* encoder-count 0.5 button-cell-width))\n        arc (java.awt.geom.Arc2D$Double. (- x-center 20.0) 50.0 40.0 40.0 240.0 -300.0 java.awt.geom.Arc2D/OPEN)]\n    (set-graphics-color graphics track-color)\n    (.draw graphics arc)\n    (.setStroke graphics (java.awt.BasicStroke. 5.0 java.awt.BasicStroke/CAP_ROUND java.awt.BasicStroke/JOIN_ROUND))\n    (set-graphics-color graphics active-color)\n    (.setAngleExtent arc (* -300.0 fraction))\n    (.draw graphics arc)))\n\n(defn draw-pan-gauge\n  \"Draw a graphical gauge with an indicator that extends from the top\n  center of an arc under a variable value. The default range is from\n  zero to a hundred, and the default color for both the track and\n  active area is dim white.\"\n  [controller index encoder-count value & {:keys [lowest highest track-color active-color]\n                                           :or {lowest 0 highest 100\n                                                track-color default-track-color active-color track-color}}]\n  (let [graphics (create-graphics controller)\n        range (- highest lowest)\n        fraction (/ (- value lowest) range)\n        x-center (+ (* index button-cell-width) (* encoder-count 0.5 button-cell-width))\n        arc (java.awt.geom.Arc2D$Double. (- x-center 20.0) 50.0 40.0 40.0 240.0 -300.0 java.awt.geom.Arc2D/OPEN)]\n    (set-graphics-color graphics track-color)\n    (.draw graphics arc)\n    (.setStroke graphics (java.awt.BasicStroke. 5.0 java.awt.BasicStroke/CAP_ROUND java.awt.BasicStroke/JOIN_ROUND))\n    (set-graphics-color graphics active-color)\n    (.setAngleStart arc 90.0)\n    (.setAngleExtent arc (+ 150 (* -300.0 fraction)))\n    (.draw graphics arc)))\n\n(defn draw-boolean-gauge\n  \"Draw a graphical gauge with an indicator that covers the left or\n  right half of an arc under a variable value, depending on if the\n  value is true or false. The default color for the track is dim\n  white. The color for the current value area is either red (for no)\n  or green (for yes), and is dimmed when `:active?` is false. To\n  support animating state changes, a `:fraction` parameter can be\n  supplied which specifies how far from the opposite state the\n  indicator should be drawn.\"\n  [controller index encoder-count value & {:keys [track-color active? fraction]\n                                           :or {track-color default-track-color fraction 1.0}}]\n  (let [graphics (create-graphics controller)\n        x-center (+ (* index button-cell-width) (* encoder-count 0.5 button-cell-width))\n        arc (java.awt.geom.Arc2D$Double. (- x-center 20.0) 50.0 40.0 40.0 240.0 -300.0 java.awt.geom.Arc2D/OPEN)]\n    (set-graphics-color graphics track-color)\n    (.draw graphics arc)\n    (.setStroke graphics (java.awt.BasicStroke. 5.0 java.awt.BasicStroke/CAP_ROUND java.awt.BasicStroke/JOIN_ROUND))\n    (set-graphics-color graphics (if active?\n                                   (if value green-color red-color)\n                                   (if value dim-green-color dim-red-color)))\n    (.setAngleStart arc (if value\n                          (+ 90.0 (* (- 1.0 fraction) 150))\n                          (- 240.0 (* (- 1.0 fraction) 150))))\n    (.setAngleExtent arc -150.0)\n    (.draw graphics arc)))\n\n(defn draw-circular-gauge\n  \"Draw a graphical gauge with an indicator that rides around an\n  circle (starting at the bottom) under a variable value. The default\n  range is from 0 to 360 (for hues), and the default color for both\n  the track and active area is dim white.\"\n  [controller index encoder-count value & {:keys [lowest highest track-color active-color]\n                                           :or {lowest 0 highest 360\n                                                track-color default-track-color active-color track-color}}]\n  (let [graphics (create-graphics controller)\n        range (- highest lowest)\n        fraction (/ (- value lowest)  range)\n        x-center (+ (* index button-cell-width) (* encoder-count 0.5 button-cell-width))\n        arc (java.awt.geom.Arc2D$Double. (- x-center 20.0) 50.0 40.0 40.0 240.0 -300.0 java.awt.geom.Arc2D/OPEN)]\n    (set-graphics-color graphics track-color)\n    (.draw graphics (java.awt.geom.Ellipse2D$Double. (- x-center 20.0) 50.0 40.0 40.0))\n    (.setStroke graphics (java.awt.BasicStroke. 6.0 java.awt.BasicStroke/CAP_ROUND java.awt.BasicStroke/JOIN_ROUND))\n    (set-graphics-color graphics active-color)\n    (.setAngleStart arc (+ 270.0 (* -300.0 fraction)))\n    (.setAngleExtent arc 0.0)\n    (.draw graphics arc)))\n\n(defonce ^:private\n  ^{:doc \"The circle of hues around which a hue gauge indicator\n  rolls. This is a constant image regardless of the current hue,\n  so we can draw it once and reuse it.\"}\n  hue-track\n  (let [gauge-image (java.awt.image.BufferedImage. 50 50 java.awt.image.BufferedImage/TYPE_INT_ARGB)\n        gauge-graphics (.createGraphics gauge-image)\n        mask-image (java.awt.image.BufferedImage. 50 50 java.awt.image.BufferedImage/TYPE_INT_ARGB)\n        mask-graphics (.createGraphics mask-image)\n        arc (java.awt.geom.Arc2D$Double. 5.0 5.0 40.0 40.0 270.0 -5.0 java.awt.geom.Arc2D/OPEN)]\n\n    ;; Color \"outside the lines\" that we will be masking so the mask can smoothe the edges\n    (.setStroke gauge-graphics (java.awt.BasicStroke. 5.0 java.awt.BasicStroke/CAP_ROUND\n                                                      java.awt.BasicStroke/JOIN_ROUND))\n    (dotimes [i 72]  ; Draw the circle of hues\n      (.setAngleStart arc (- 270.0 (* i 5)))\n      (set-graphics-color gauge-graphics (colors/create-color :h (* i 5) :s 100.0 :l 50.0))\n      (.draw gauge-graphics arc))\n\n    ;; Draw a mask we can use to soft clip the color hue track. Start by clearing it so all pixels have zero alpha.\n    (.setComposite mask-graphics java.awt.AlphaComposite/Clear)\n    (.fillRect mask-graphics 0 0 50 50)\n\n    ;; Render the gauge track mask, an anti-aliased circle\n    (.setComposite mask-graphics java.awt.AlphaComposite/Src)\n    (.setRenderingHint mask-graphics java.awt.RenderingHints/KEY_ANTIALIASING\n                       java.awt.RenderingHints/VALUE_ANTIALIAS_ON)\n    (.setColor mask-graphics java.awt.Color/WHITE)\n    (.draw mask-graphics (java.awt.geom.Ellipse2D$Double. 5.0 5.0 40.0 40.0))\n\n    ;; Render the track into the mask using SrcAtop, which effectively uses the alpha value as\n    ;; a coverage value for each pixel stored in the destination. For the areas outside our clip\n    ;; shape, the destination alpha will be zero, so nothing is rendered in those areas. For the\n    ;; areas inside our clip shape, the destination alpha will be fully opaque, so the full color\n    ;; is rendered. At the edges, the original antialiasing is carried over to give us the desired\n    ;; soft clipping effect.\n    (.setComposite mask-graphics java.awt.AlphaComposite/SrcAtop)\n    (.drawImage mask-graphics gauge-image 0 0 nil)\n\n    mask-image))  ; Return the masked track image\n\n(defn draw-hue-gauge\n  \"Draw a graphical gauge whose colors are the hues of the color\n  circle, with an indicator that rides around an circle (starting at\n  the bottom) under a variable value.\"\n  [controller index encoder-count value active?]\n  (let [graphics (create-graphics controller)\n        x-center (+ (* index button-cell-width) (* encoder-count 0.5 button-cell-width))\n        arc (java.awt.geom.Arc2D$Double. (- x-center 20.0) 50.0 40.0 40.0 (- 270.0 value) 0.0 java.awt.geom.Arc2D/OPEN)]\n\n    ;; Draw the precomputed hue track image\n    (.drawImage graphics hue-track (math/round (- x-center 25)) 45 nil)\n\n    ;; Then draw the larger knob at the current hue value\n    (.setStroke graphics (java.awt.BasicStroke. 6.0 java.awt.BasicStroke/CAP_ROUND java.awt.BasicStroke/JOIN_ROUND))\n    (if active?\n      (set-graphics-color graphics (colors/create-color :h value :s 100.0 :l 50.0))\n      (set-graphics-color graphics (colors/create-color :h value :s 100.0 :l 25.0)))\n    (.draw graphics arc)))\n\n(defn draw-saturation-gauge\n  \"Draw a graphical gauge whose colors are the saturation levels of\n  the specified hue circle, with an indicator like that of a level\n  gauge, under a variable value.\"\n  [controller index encoder-count hue value active?]\n  (let [graphics (create-graphics controller)\n        gauge-image (java.awt.image.BufferedImage. 50 50 java.awt.image.BufferedImage/TYPE_INT_ARGB)\n        gauge-graphics (.createGraphics gauge-image)\n        mask-image (java.awt.image.BufferedImage. 50 50 java.awt.image.BufferedImage/TYPE_INT_ARGB)\n        mask-graphics (.createGraphics mask-image)\n        x-center (+ (* index button-cell-width) (* encoder-count 0.5 button-cell-width))\n        arc (java.awt.geom.Arc2D$Double. 5.0 5.0 40.0 40.0 240.0 -3.0 java.awt.geom.Arc2D/OPEN)]\n\n    ;; Color \"outside the lines\" that we will be masking so the mask can smoothe the edges\n    (.setStroke gauge-graphics (java.awt.BasicStroke. 3.0 java.awt.BasicStroke/CAP_ROUND\n                                                      java.awt.BasicStroke/JOIN_ROUND))\n    (dotimes [i 100]  ; Draw the saturation track\n      (.setAngleStart arc (- 240.0 (* i 3)))\n      (set-graphics-color gauge-graphics (colors/create-color :h hue :s i :l 50.0))\n      (.draw gauge-graphics arc))\n\n    ;; Then draw the wider section representing the current saturation\n    (.setStroke gauge-graphics (java.awt.BasicStroke. 8.0 java.awt.BasicStroke/CAP_ROUND\n                                                      java.awt.BasicStroke/JOIN_ROUND))\n    (dotimes [i (max (math/round value) 1)]\n      (if active?\n        (set-graphics-color gauge-graphics (colors/create-color :h hue :s i :l 50.0))\n        (set-graphics-color gauge-graphics (colors/create-color :h hue :s i :l 25.0)))\n      (.setAngleStart arc (- 240.0 (* i 3)))\n      (.draw gauge-graphics arc))\n\n    ;; Draw a mask we can use to soft clip the saturation gauge. Start by clearing it so all pixels have zero alpha.\n    (.setComposite mask-graphics java.awt.AlphaComposite/Clear)\n    (.fillRect mask-graphics 0 0 50 50)\n\n    ;; Render the gauge track mask, an anti-aliased arc\n    (.setComposite mask-graphics java.awt.AlphaComposite/Src)\n    (.setRenderingHint mask-graphics java.awt.RenderingHints/KEY_ANTIALIASING\n                       java.awt.RenderingHints/VALUE_ANTIALIAS_ON)\n    (.setColor mask-graphics java.awt.Color/WHITE)\n    (.setAngleStart arc 240.0)\n    (.setAngleExtent arc -300.0)\n    (.draw mask-graphics arc)\n\n    ;; Render the gauge current saturation section, a wider anti-aliased arc\n    (.setStroke mask-graphics (java.awt.BasicStroke. 5.0 java.awt.BasicStroke/CAP_ROUND\n                                                     java.awt.BasicStroke/JOIN_ROUND))\n    (.setAngleExtent arc (* -3.0 value))\n    (.draw mask-graphics arc)\n\n    ;; Render the gauge into the mask using SrcAtop, which effectively uses the alpha value as\n    ;; a coverage value for each pixel stored in the destination. For the areas outside our clip\n    ;; shape, the destination alpha will be zero, so nothing is rendered in those areas. For the\n    ;; areas inside our clip shape, the destination alpha will be fully opaque, so the full color\n    ;; is rendered. At the edges, the original antialiasing is carried over to give us the desired\n    ;; soft clipping effect.\n    (.setComposite mask-graphics java.awt.AlphaComposite/SrcAtop)\n    (.drawImage mask-graphics gauge-image 0 0 nil)\n\n    ;; Finally, draw the soft-masked gauge onto the controller display image\n    (.drawImage graphics mask-image (math/round (- x-center 25)) 45 nil)))\n\n(defn- metronome-sync-label\n  \"Determine the sync type label to display under the BPM section.\"\n  [controller]\n  (with-show (:show controller)\n    (case (:type (show/sync-status))\n      :manual \"Manual\"\n      :midi \"MIDI\"\n      :dj-link \"DJ Link\"\n      :traktor-beat-phase \"Traktor\"\n      \"Unknown\")))\n\n(defn- metronome-sync-color\n  \"Determine the color to light the sync pad under the BPM section.\"\n  [controller]\n  (with-show (:show controller)\n    (if (= (:type (show/sync-status)) :manual)\n      amber-color\n      (if (:current (show/sync-status))\n        green-color\n        red-color))))\n\n(defn- update-mode!\n  \"Turn a controller mode on or off, identified by the associated\n  control button number or keyword.\"\n  [controller button state]\n  (let [button (if (keyword? button) (get-in control-buttons [button :control]) button)]\n    (swap! (:modes controller) #(if state (conj % button) (disj % button)))))\n\n(defn in-mode?\n  \"Check whether the controller is in a particular mode, identified by\n  a control button number or keyword.\"\n  [controller button]\n  (let [button (if (keyword? button) (get-in control-buttons [button :control]) button)]\n    (get @(:modes controller) button)))\n\n(def metronome-background\n  \"The background for the metronome section, to mark it as such.\"\n  (colors/darken (colors/desaturate (colors/create-color :blue) 55) 45))\n\n(def metronome-content\n  \"The color for content in the metronome section, to mark it as such.\"\n  (colors/desaturate (colors/create-color :aqua) 30))\n\n(def font-for-metronome-values\n  \"The font used when drawing metronome values.\"\n  (get-display-font :monospace Font/PLAIN 22))\n\n(defn- bpm-adjusting-interface\n  \"Brighten the section of the BPM that is being adjusted, and draw\n  the gauge in a brighter color, or indicate that it is being synced\n  and can't be adjusted.\"\n  [controller snapshot]\n  (if (= (:type (show/sync-status)) :manual)\n    (let [graphics (create-graphics controller)\n          bpm (double (:bpm snapshot))\n          bpm-string (format \"%.1f\" bpm)\n          label (java.text.AttributedString. bpm-string)]\n      (set-graphics-color graphics metronome-background)\n      (.fillRect graphics button-cell-width 21 button-cell-width 20)\n      (.addAttribute label java.awt.font.TextAttribute/FONT font-for-metronome-values)\n      (if (in-mode? controller :shift)\n        (.addAttribute label java.awt.font.TextAttribute/FOREGROUND (java.awt.Color/WHITE)\n                       0 (- (count bpm-string) 2))\n        (.addAttribute label java.awt.font.TextAttribute/FOREGROUND (java.awt.Color/WHITE)\n                       (dec (count bpm-string)) (count bpm-string)))\n      (draw-attributed-variable-value controller 1 1 label metronome-content)\n      (draw-gauge controller 1 1 bpm :lowest controllers/minimum-bpm :highest controllers/maximum-bpm\n                  :track-color metronome-content :active-color white-color)\n      (set-touch-strip-from-value controller bpm controllers/minimum-bpm controllers/maximum-bpm\n                                  touch-strip-mode-level))\n\n    ;; Display the sync mode in red to explain why we are not adjusting it.\n    (draw-bottom-button-label controller 1 (metronome-sync-label controller) red-color\n                              :background-color metronome-background)))\n\n(defn sign-velocity\n  \"Convert a midi velocity to its signed equivalent, to translate\n  encoder rotations, which are twos-complement seven bit numbers.\"\n  [val]\n   (if (>= val 64)\n     (- val 128)\n     val))\n\n(defn- adjust-bpm-from-encoder\n  \"Adjust the current BPM based on how the encoder was twisted, unless\n  the metronome is synced.\"\n  [controller message]\n  (with-show (:show controller)\n    (when (= (:type (show/sync-status)) :manual)\n      (let [scale (if (in-mode? controller :shift) 1 10)\n            delta (/ (sign-velocity (:velocity message)) scale)\n            bpm (rhythm/metro-bpm (:metronome (:show controller)))]\n        (rhythm/metro-bpm (:metronome (:show controller)) (min controllers/maximum-bpm\n                                                               (max controllers/minimum-bpm (+ bpm delta))))))))\n\n(defn- encoder-above-bpm-touched\n  \"Add a user interface overlay to give feedback when turning the\n  encoder above the BPM display when metronome was already active,\n  since it is easy to grab that one rather than the actual BPM\n  encoder, being right above the display.\"\n  [controller]\n  (controllers/add-overlay (:overlays controller)\n               (reify controllers/IOverlay\n                 (captured-controls [_this] #{72})\n                 (captured-notes [_this] #{1 9})\n                 (adjust-interface [_this snapshot]\n                   (bpm-adjusting-interface controller snapshot)\n                   true)\n                 (handle-control-change [_this message]\n                   (adjust-bpm-from-encoder controller message))\n                 (handle-note-on [_this _message]\n                   ;; Suppress the actual BPM encoder while we are active.\n                   true)\n                 (handle-note-off [_this message]\n                   (when (= (:note message) 1)\n                     ;; They released us, end the overlay.\n                     :done))\n                 (handle-aftertouch [_this _message])\n                 (handle-pitch-bend [_this message]\n                   (let [full-range (- controllers/maximum-bpm controllers/minimum-bpm)\n                         fraction (/ (+ (* (:data2 message) 128) (:data1 message)) 16383)\n                         adjusted (double (+ controllers/minimum-bpm (* fraction full-range)))\n                         resolution 0.1\n                         normalized (double (* (Math/round (/ adjusted resolution)) resolution))]\n                     (with-show (:show controller)\n                       (when (= (:type (show/sync-status)) :manual)\n                         (rhythm/metro-bpm (:metronome (:show controller)) normalized))))))))\n\n(defn- beat-adjusting-interface\n  \"Brighten the section of the beat which is being adjusted.\"\n  [controller snapshot]\n  (let [graphics (create-graphics controller)\n        marker (rhythm/snapshot-marker snapshot)\n        label (java.text.AttributedString. marker)\n        first-dot (.indexOf marker \".\")\n        second-dot (.indexOf marker \".\" (inc first-dot))]\n      (set-graphics-color graphics metronome-background)\n      (.fillRect graphics 0 21 button-cell-width 20)\n      (.addAttribute label java.awt.font.TextAttribute/FONT font-for-metronome-values)\n      (if (in-mode? controller :shift)\n        (.addAttribute label java.awt.font.TextAttribute/FOREGROUND (java.awt.Color/WHITE)\n                       (inc first-dot) second-dot)\n        (.addAttribute label java.awt.font.TextAttribute/FOREGROUND (java.awt.Color/WHITE)\n                       (inc second-dot) (count marker)))\n      (draw-attributed-variable-value controller 0 1 label metronome-content)\n      (draw-null-gauge controller 0 1 white-color))\n  true)\n\n(defn- adjust-beat-from-encoder\n  \"Adjust the current beat based on how the encoder was twisted.\"\n  [controller message]\n  (let [delta (sign-velocity (:velocity message))\n        metronome (:metronome (:show controller))\n        units (if (in-mode? controller :shift)\n                ;; User is adjusting the current bar\n                (rhythm/metro-tock metronome)\n                ;; User is adjusting the current beat\n                (rhythm/metro-tick metronome))\n        ms-delta (- (* delta units))]\n    (rhythm/metro-adjust metronome ms-delta)))\n\n(defn- encoder-above-beat-touched\n  \"Add a user interface overlay to give feedback when turning the\n  encoder above the beat display when metronome was already active,\n  since it is easy to grab that one rather than the actual beat\n  encoder, being right above the display.\"\n  [controller]\n  (controllers/add-overlay (:overlays controller)\n               (reify controllers/IOverlay\n                 (captured-controls [_this] #{71})\n                 (captured-notes [_this] #{0 10})\n                 (adjust-interface [_this snapshot]\n                   (beat-adjusting-interface controller snapshot))\n                 (handle-control-change [_this message]\n                   (adjust-beat-from-encoder controller message))\n                 (handle-note-on [_this _message]\n                   ;; Suppress the actual beat encoder while we are active.\n                   true)\n                 (handle-note-off [_this message]\n                   (when (zero? (:note message))\n                     ;; They released us, end the overlay.\n                     :done))\n                 (handle-aftertouch [_this _message])\n                 (handle-pitch-bend [_this _message]))))\n\n(defn- enter-metronome-showing\n  \"Activate the persistent metronome display, with sync and reset pads\n  illuminated.\"\n  [controller]\n  (swap! (:metronome-mode controller) assoc :showing true)\n  (controllers/add-overlay (:overlays controller)\n               (reify controllers/IOverlay\n                 (captured-controls [_this] #{3 9 20 21})\n                 (captured-notes [_this] #{0 1})\n                 (adjust-interface [_this _snapshot]\n                   ;; Make the metronome button bright, since its information is active\n                   (swap! (:next-text-buttons controller)\n                          assoc (:metronome control-buttons)\n                          white-color)\n\n                   ;; Add the labels for reset and sync, and light the pads\n                   (draw-bottom-button-label controller 0 \"Reset\" red-color :background-color metronome-background)\n                   (draw-bottom-button-label controller 1 (metronome-sync-label controller)\n                                             (metronome-sync-color controller) :background-color metronome-background)\n                   (swap! (:next-top-pads controller) assoc 0 dim-red-color)\n                   (swap! (:next-top-pads controller) assoc 1 (dim (metronome-sync-color controller))))\n                 (handle-control-change [_this message]\n                   (case (:note message)\n                     3 ; Tap tempo button\n                     (when (pos? (:velocity message))\n                       ((:tempo-tap-handler controller))\n                       true)\n\n                     9 ; Metronome button\n                     (when (pos? (:velocity message))\n                       (swap! (:metronome-mode controller) dissoc :showing)\n                       ;; Exit the overlay\n                       :done)\n\n                     20 ; Reset pad\n                     (when (pos? (:velocity message))\n                       (rhythm/metro-phrase-start (:metronome (:show controller)) 1)\n                       (controllers/add-control-held-feedback-overlay (:overlays controller) 20\n                                                                      (fn [_] (swap! (:next-top-pads controller)\n                                                                                     assoc 0 red-color)))\n                       true)\n                     21 ; Sync pad\n                     (when (pos? (:velocity message))\n                       ;; TODO: Actually implement a new overlay\n                       (controllers/add-control-held-feedback-overlay\n                        (:overlays controller) 21 (fn [_] (swap! (:next-top-pads controller)\n                                                                 assoc 1 (metronome-sync-color controller))))\n                       true)))\n                 (handle-note-on [_this message]\n                   ;; Whoops, user grabbed encoder closest to beat or BPM display\n                   (case (:note message)\n                     0 (encoder-above-beat-touched controller)\n                     1 (encoder-above-bpm-touched controller))\n                   true)\n                 (handle-note-off [_this _message]\n                   false)\n                 (handle-aftertouch [_this _message])\n                 (handle-pitch-bend [_this _message]))))\n\n(defn- new-beat?\n  \"Returns true if the metronome is reporting a different marker\n  position than the last time this function was called.\"\n  [controller marker]\n  (when (not= marker @(:last-marker controller))\n    (reset! (:last-marker controller) marker)))\n\n(defn- beat-mark-color\n  \"Returns the color in which to draw the stripe marking a beat. Red\n  for down beats, white for others.\"\n  [snapshot]\n  (if (rhythm/snapshot-down-beat? snapshot) java.awt.Color/RED java.awt.Color/WHITE))\n\n(defn- beat-mark-top-y\n  \"Returns the upper Y coordinate from which to draw the stripe\n  marking a beat.\"\n  [snapshot]\n  (- Wayang/DISPLAY_HEIGHT (if (rhythm/snapshot-down-beat? snapshot) 50 40)))\n\n(defn draw-beat-mark\n  \"Draw one of the marks representing a beat on the beat grid.\"\n  [graphics snapshot beat-position]\n  (.setPaint graphics (beat-mark-color snapshot))\n  (.draw graphics (java.awt.geom.Line2D$Double. beat-position (beat-mark-top-y snapshot)\n                                                beat-position (- Wayang/DISPLAY_HEIGHT 20))))\n\n(defn- draw-beat-grid-triangle\n  \"Draw a triangle growing to the specified x coordinate, with\n  specified width, top y coordinate, and color.\"\n  [graphics x width top color]\n  (let [path (java.awt.geom.Path2D$Double.)]\n    (.moveTo path x (- Wayang/DISPLAY_HEIGHT 20))\n    (.lineTo path x (- Wayang/DISPLAY_HEIGHT top))\n    (.lineTo path (- x width) (- Wayang/DISPLAY_HEIGHT 20))\n    (.closePath path)\n    (.setPaint graphics color)\n    (.fill graphics path)))\n\n(defn- render-metronome-section\n  \"Draws the sections of the interface related to metronome control.\"\n  [controller snapshot]\n  (let [marker (rhythm/snapshot-marker snapshot)\n        metronome-button (:metronome control-buttons)\n        tap-tempo-button (:tap-tempo control-buttons)\n        metronome-mode @(:metronome-mode controller)]\n    ;; Is the first cell reserved for metronome information?\n    (if (seq metronome-mode)\n      (let [graphics (create-graphics controller)\n            bpm (:bpm snapshot)\n            bpm-label (java.text.AttributedString. (format \"%.1f\" (double bpm)))]\n\n        ;; Draw the background that makes the metronome section distinctive.\n        (set-graphics-color graphics metronome-background)\n        (.fillRect graphics 0 0 (* 2 button-cell-width) Wayang/DISPLAY_HEIGHT)\n\n        ;; Draw the beat and BPM information\n        (set-graphics-color graphics metronome-content)\n        (draw-encoder-button-label controller 0 1 \"Beat\" metronome-content)\n        (draw-cue-variable-value controller 0 1 marker metronome-content font-for-metronome-values)\n        (draw-encoder-button-label controller 1 1 \"BPM\" metronome-content)\n        (.addAttribute bpm-label java.awt.font.TextAttribute/FONT font-for-metronome-values)\n        (draw-attributed-variable-value controller 1 1 bpm-label metronome-content)\n        (draw-gauge controller 1 1 bpm :lowest controllers/minimum-bpm :highest controllers/maximum-bpm\n                    :track-color metronome-content)\n\n        ;; Draw the beat grid visualization\n        (set-graphics-color graphics metronome-content)\n        (.draw graphics (java.awt.geom.Line2D$Double. button-cell-width (- Wayang/DISPLAY_HEIGHT 60)\n                                                            button-cell-width (- Wayang/DISPLAY_HEIGHT 19)))\n\n        (let [beat-width (/ button-cell-width (:bpb snapshot))\n              beat-position (- button-cell-width (* beat-width (:beat-phase snapshot)))\n              bar-position (- button-cell-width (* beat-width (:bpb snapshot) (:bar-phase snapshot)))\n              phrase-position (- button-cell-width (* beat-width (:bpb snapshot) (:bpp snapshot)\n                                                      (:phrase-phase snapshot)))\n              metro (:metronome (:show controller))\n              beat-background (java.awt.Color. 255 255 255 100)\n              down-beat-background (java.awt.Color. 255 0 0 72)\n              phrase-background (java.awt.Color. (colors/red metronome-content) (colors/green metronome-content)\n                                                 (colors/blue metronome-content) 32)]\n          (.setClip graphics  0 (- Wayang/DISPLAY_HEIGHT 60) (* 2 button-cell-width) 40)\n\n          ;; Draw a triangle representing the current measure and any following ones that at least partially fit\n          (loop [position phrase-position]\n            (draw-beat-grid-triangle graphics position (* beat-width (:bpb snapshot) (:bpp snapshot))\n                                     60 phrase-background)\n            (when (< position (* 2 button-cell-width))\n              (recur (+ position (* beat-width (:bpb snapshot) (:bpp snapshot))))))\n\n          ;; Draw a triangle representing the current measure and any following ones that at least partially fit\n          (loop [position bar-position\n                 snap snapshot]\n            (draw-beat-grid-triangle graphics position (* beat-width (:bpb snap)) 50 down-beat-background)\n            (when (< position (* 2 button-cell-width))\n              (recur (+ position (* beat-width (:bpb snap)))\n                     (rhythm/metro-snapshot metro (+ (:instant snap) (rhythm/metro-tock metro))))))\n\n          ;; Draw the current beat and any following ones that fit, and one additional triangle beyond that.\n          (loop [position beat-position\n                 snap snapshot]\n            (draw-beat-grid-triangle graphics position beat-width 40 beat-background)\n            (when (< position (* 2 button-cell-width))\n              (draw-beat-mark graphics snap position)\n              (recur (+ position beat-width)\n                     (rhythm/metro-snapshot metro (+ (:instant snap) (rhythm/metro-tick metro))))))\n\n          ;; Draw any beats preceding the current one that fit\n          (loop [position (- beat-position beat-width)\n                 snap (rhythm/metro-snapshot metro (- (:instant snapshot) (rhythm/metro-tick metro)))]\n            (when (>= position 0)\n              (draw-beat-grid-triangle graphics position beat-width 40 beat-background)\n              (draw-beat-mark graphics snap position)\n              (recur (- position beat-width)\n                     (rhythm/metro-snapshot metro (- (:instant snap) (rhythm/metro-tick metro)))))))\n\n\n\n        ;; Make the metronome button bright, since some overlay is present\n        (swap! (:next-text-buttons controller) assoc metronome-button white-color))\n\n      ;; The metronome section is not active, so make its button dim\n      (swap! (:next-text-buttons controller) assoc metronome-button dim-white-color))\n\n    ;; Regardless, flash the tap tempo button on beats\n    (swap! (:next-text-buttons controller)\n           assoc tap-tempo-button\n           (if (or (new-beat? controller marker) (< (rhythm/snapshot-beat-phase snapshot) 0.15))\n             white-color dim-white-color))))\n\n(defn- render-cue-grid\n  \"Figure out how the cue grid pads should be illuminated, based on the\n  currently active cues and our current point in musical time.\"\n  [controller snapshot]\n  (let [[origin-x origin-y] @(:origin controller)\n        active-keys (show/active-effect-keys (:show controller))]\n    (doseq [x (range 8)\n            y (range 8)]\n      (let [[cue active] (show/find-cue-grid-active-effect (:show controller) (+ x origin-x) (+ y origin-y))\n            ending (and active (:ending active))\n            base-color (when cue (cues/current-cue-color cue active (:show controller) snapshot))\n            l-boost (when base-color (if (zero? (colors/saturation base-color)) 8.0 0.0))\n            color (when base-color\n                    (colors/create-color\n                     :h (colors/hue base-color)\n                     :s (colors/saturation base-color)\n                     ;; Figure the brightness. Active, non-ending cues are full brightness;\n                     ;; when ending, they blink between middle and low. If they are not active,\n                     ;; they are at middle brightness unless there is another active effect with\n                     ;; the same keyword, in which case they are dim.\n                     :l (+ (if active\n                             (if ending\n                               (if (> (rhythm/snapshot-beat-phase snapshot) 0.4) 4 22)\n                               55)\n                             (if (or (active-keys (:key cue))\n                                     (seq (set/intersection active-keys (set (:end-keys cue))))) 4 22))\n                           l-boost)))]\n        (swap! (:next-grid-pads controller) assoc (+ x (* y 8)) (or color off-color))))))\n\n(defn cue-grid-updates\n  \"See if any of the cue grid button states have changed, and list any\n  required updates as tuples of the pad x and y coordinates,\n  corresponding grid pad array index, and the new desired color.\"\n  [controller]\n  (filter identity (for [x (range 8)\n                         y (range 8)]\n                     (let [index (+ x (* y 8))\n                           color (get @(:next-grid-pads controller) index)]\n                       (when-not (= color (get @(:last-grid-pads controller) index))\n                         [x y index color])))))\n\n(def grid-update-chunk-size\n  \"The number of cue grid LED updates that can be sent before we need\n  to wait and re-synch with the Push 2, to avoid overflowing buffers.\"\n  16)\n\n(defn update-cue-grid-chunk\n  \"Given a list of needed cue grid updates, send at most\n  `grid-update-chunk-size` of them, and return the remaining list.\"\n  [controller updates]\n  (when (seq updates)\n    (loop [countdown (dec grid-update-chunk-size)\n           [x y index color] (first updates)\n           remaining (rest updates)]\n      (set-pad-color controller x y color)\n      (swap! (:last-grid-pads controller) assoc index color)\n      (if (or (zero? countdown) (empty? remaining))\n        remaining\n        (recur (dec countdown) (first remaining) (rest remaining))))))\n\n(defn- update-cue-grid\n  \"See if any of the cue grid button states have changed, and send any\n  required updates in batches. At the end of each batch, send a Sysex\n  message asking what the display brightness is. We don't actually\n  care, but when the response comes back we will know this batch has\n  been processed, and we can send the next.\"\n  [controller]\n  (when-let [remaining (seq (update-cue-grid-chunk controller (cue-grid-updates controller)))]\n    (let [updates (atom remaining)]\n      (swap! grid-batch-update-fn\n             (fn [existing-fn]\n               (when (some? existing-fn) (timbre/warn \"Reached next Push 2 frame while still updating cue grid!\"))\n               (fn []\n                 (swap! updates #(update-cue-grid-chunk controller %))\n                 (if (seq @updates)\n                   (send-sysex controller [0x09])  ; Response will trigger next chunk\n                   (reset! grid-batch-update-fn nil))))))  ; We are done\n    (send-sysex controller [0x09])))\n\n#_(defn- ^:deprecated update-cue-grid-unbatched\n  \"See if any of the cue grid button states have changed, and send any\n  required updates. Deprecated until there is firmware that can keep\n  up with updating the entire grid at once.\"\n  [controller]\n  (doseq [x (range 8)\n          y (range 8)]\n    (let [index (+ x (* y 8))\n          color (get @(:next-grid-pads controller) index)]\n      (when-not (= color (get @(:last-grid-pads controller) index))\n        (set-pad-color controller x y color)\n        (swap! (:last-grid-pads controller) assoc index color)))))\n\n(defn- cue-vars-for-encoders\n  \"Find the correct cue variables that correspond to each of the two\n  encoders within a cue's display region, given the cue's variable\n  list and the offset by which the user has shifted the cue\n  variables.\"\n  [cue-vars var-offset]\n  (case (count cue-vars)\n    0 nil ; No variables to adjust\n    1 (vec (repeat 2 (first cue-vars)))\n    (vec (take 2 (drop var-offset (apply concat (repeat cue-vars)))))))\n\n(defn- best-cue-variable-name\n  \"Picks the best version of a cue variable name to fit under the\n  specified number of encoders.\"\n  [controller v encoder-count]\n  (let [graphics (create-graphics controller)\n        space (space-for-encoder-button-label encoder-count)\n        font font-for-encoder-button-label\n        context (.getFontRenderContext graphics)\n        longer (or (:name v) (name (:key v)))\n        shorter (or (:short-name v) longer)]\n    (if (<= (string-width longer font context) space) longer shorter)))\n\n(defn draw-cue-variable-names\n  \"Draw the names of adjustable variables under the appropriate\n  encoders for a cue.\"\n  [controller x cue effect-id]\n  (let [cue-vars (cue-vars-for-encoders (:variables cue) (get @(:cue-var-offsets controller) effect-id 0))]\n    (when (seq cue-vars)\n      (if (= (count (:variables cue)) 1)\n        (draw-encoder-button-label controller (* x 2) 2\n                                   (best-cue-variable-name controller (first cue-vars) 1) white-color)\n        (do\n          (draw-encoder-button-label controller (* x 2) 1\n                                     (best-cue-variable-name controller (first cue-vars) 1) white-color)\n          (draw-encoder-button-label controller (inc (* x 2)) 1\n                                     (best-cue-variable-name controller (second cue-vars) 1) white-color))))))\n\n(defn- format-cue-variable-value\n  \"Translates a cue variable to a string format that will look good\n  and be meaningful on the display.\"\n  [controller cue v effect-id]\n  (let [val (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id)\n        formatted (if (some? val)\n                    (cond\n                      (= (:type v) :integer)\n                      (int val)\n\n                      ;; For color values, create an attributed string which contains a swatch of\n                      ;; the actual color, followed by the RGB hex string describing it.\n                      (or (= (type val) :com.evocomputing.colors/color) (= (:type v) :color))\n                      (let [as (java.text.AttributedString. (str \"\\ufffc \" (colors/rgb-hexstr val)))\n                            swatch (java.awt.geom.Rectangle2D$Double. 0 -16 16 16)\n                            shape-attribute (java.awt.font.ShapeGraphicAttribute.\n                                             swatch java.awt.font.ShapeGraphicAttribute/ROMAN_BASELINE\n                                             java.awt.font.ShapeGraphicAttribute/FILL)]\n                        (.addAttribute as java.awt.font.TextAttribute/FONT font-for-cue-variable-values)\n                        (.addAttribute as java.awt.font.TextAttribute/CHAR_REPLACEMENT shape-attribute 0 1)\n                        (.addAttribute as java.awt.font.TextAttribute/FOREGROUND\n                                       (java.awt.Color. (colors/red val) (colors/green val) (colors/blue val))\n                                       0 1)\n                        as)\n\n                      ;; For boolean values, display yes or no.\n                      (or (= (type val) Boolean) (= (:type v) :boolean))\n                      (if val \"Yes\" \"No\")\n\n                      ;; If we don't know what else to do, at least turn ratios to doubles, and\n                      ;; round to a reasonable number of digits.\n                      :else\n                      (/ (math/round (* val 1000)) 1000.0))\n\n                    ;; We got no value, display an ellipsis\n                    \"…\")]\n    (if (= (class formatted) java.text.AttributedString)\n      formatted\n      (str formatted))))\n\n(defn- draw-cue-variable-values\n  \"Displays the current values of the adjustable variables currently\n  assigned to the encoders over an active cue.\"\n  [controller x cue effect-id]\n  (let [cue-vars (cue-vars-for-encoders (:variables cue) (get @(:cue-var-offsets controller) effect-id 0))]\n    (when (seq cue-vars)\n      (if (= (count (:variables cue)) 1)\n        (draw-cue-variable-value controller (* x 2) 2\n                                 (format-cue-variable-value controller cue (first cue-vars) effect-id) white-color)\n        (do\n          (draw-cue-variable-value controller (* x 2) 1\n                                   (format-cue-variable-value controller cue (first cue-vars) effect-id) white-color)\n          (draw-cue-variable-value controller (inc (* x 2)) 1\n                                   (format-cue-variable-value controller cue (second cue-vars) effect-id)\n                                   white-color))))))\n\n(defn draw-cue-variable-gauge\n  \"Draw an appropriate gauge for a cue variable given its type and\n  value.\"\n  [controller index encoder-count cue cue-var effect-id]\n  (let [cur-val (cues/get-cue-variable cue cue-var :show (:show controller) :when-id effect-id)]\n    (cond\n      (or (number? cur-val) (#{:integer :double} (:type cue-var :double)))\n      (if (:centered cue-var)\n        (let [cur-val (or cur-val (/ (+ (:min cue-var) (:max cue-var)) 2))]  ; Treat missing values as centered\n          (draw-pan-gauge controller index encoder-count cur-val :lowest (min cur-val (:min cue-var))\n                          :highest (max cur-val (:max cue-var))))\n        (let [cur-val (or cur-val (:min cue-var))]  ; Treat missing values as minima\n          (draw-gauge controller index encoder-count cur-val :lowest (min cur-val (:min cue-var))\n                      :highest (max cur-val (:max cue-var)))))\n\n      (or (= (type cur-val) :com.evocomputing.colors/color) (= (:type cue-var) :color))\n      (let [current-color (or (cues/get-cue-variable cue cue-var :show (:show controller) :when-id effect-id)\n                              white-color)  ; Treat missing values as white\n            hue (colors/hue current-color)\n            sat (colors/saturation current-color)]\n        (if (= encoder-count 1)\n          (if (odd? index)  ; We have room for just one gauge; draw whichever will be there in the overlay\n            (draw-saturation-gauge controller index 1 hue sat false)\n            (draw-hue-gauge controller index 1 hue false))\n          (do   ; We have room for both gauges\n            (draw-hue-gauge controller index 1 hue false)\n            (draw-saturation-gauge controller (inc index) 1 hue sat false))))\n\n      (or (= (type cur-val) Boolean) (= (:type cue-var) :boolean))\n      (draw-boolean-gauge controller index encoder-count cur-val))))\n\n(defn draw-cue-variable-gauges\n  \"Displays the appropriate style of adjustment gauge for variables\n  currently assigned to the encoders over an active cue.\"\n  [controller x cue effect-id]\n  (let [cue-vars (cue-vars-for-encoders (:variables cue) (get @(:cue-var-offsets controller) effect-id 0))]\n    (when (seq cue-vars)\n      (if (= (count (:variables cue)) 1)\n        (draw-cue-variable-gauge controller (* x 2) 2 cue (first cue-vars) effect-id)\n        (do\n          (draw-cue-variable-gauge controller (* x 2) 1 cue (first cue-vars) effect-id)\n          (draw-cue-variable-gauge controller (inc (* x 2)) 1 cue (second cue-vars) effect-id))))))\n\n(defn draw-cue-visualizer\n  \"Displays an animated visualization of the cue progress right above\n  the name for cues which support this.\"\n  [controller snapshot cell-x cue var-map]\n  (let [graphics (create-graphics controller)\n        cell-width (* 2 button-cell-width)\n        cell-left (* cell-x cell-width)\n        current-x (+ cell-left button-cell-width)\n        graph-left (+ cell-left button-cell-margin)\n        graph-width (- cell-width (* 2 button-cell-margin))\n        beat-width (/ button-cell-width (:bpb snapshot))\n        beat-position (+ cell-left (- button-cell-width (* beat-width (:beat-phase snapshot))))\n        metro (:metronome (:show controller))\n        column-time (/ (rhythm/metro-tick metro) beat-width)\n        visualizer ((:visualizer cue) var-map (:show controller))]\n    (.setClip graphics  graph-left (- Wayang/DISPLAY_HEIGHT 62) graph-width 22)\n    (set-graphics-color graphics default-track-color)\n    (doseq [x (range graph-left (+ graph-left graph-width))]\n      (let [snap (rhythm/metro-snapshot metro (+ (:instant snapshot) (* column-time (- x current-x))))]\n        (.drawLine graphics x (- Wayang/DISPLAY_HEIGHT 40)\n                   x (- Wayang/DISPLAY_HEIGHT 40 (* 20.0 (visualizer snap))))))\n\n    ;; Draw the \"now\" marker\n    (.setPaint graphics java.awt.Color/WHITE)\n    (.draw graphics (java.awt.geom.Line2D$Double. current-x (- Wayang/DISPLAY_HEIGHT 62)\n                                                  current-x (- Wayang/DISPLAY_HEIGHT 40)))\n\n    ;; Draw markers for the current beat and any following ones that fit.\n    (loop [position beat-position\n           snap snapshot]\n      (when (< position (+ graph-left graph-width))\n        (.setPaint graphics (beat-mark-color snap))\n        (.draw graphics (java.awt.geom.Line2D$Double. position (- Wayang/DISPLAY_HEIGHT 60)\n                                                      position (- Wayang/DISPLAY_HEIGHT 40)))\n        (recur (+ position beat-width)\n               (rhythm/metro-snapshot metro (+ (:instant snap) (rhythm/metro-tick metro))))))\n\n    ;; Draw any beats preceding the current one that fit\n    (loop [position (- beat-position beat-width)\n           snap (rhythm/metro-snapshot metro (- (:instant snapshot) (rhythm/metro-tick metro)))]\n      (when (>= position graph-left)\n        (.setPaint graphics (beat-mark-color snap))\n        (.draw graphics (java.awt.geom.Line2D$Double. position (- Wayang/DISPLAY_HEIGHT 60)\n                                                      position (- Wayang/DISPLAY_HEIGHT 40)))\n        (recur (- position beat-width)\n               (rhythm/metro-snapshot metro (- (:instant snap) (rhythm/metro-tick metro))))))))\n\n(defn- room-for-effects\n  \"Determine how many display cells are available for displaying\n  effect information.\"\n  [controller]\n  (if (seq @(:metronome-mode controller)) 3 4))\n\n(defn- find-effect-offset-range\n  \"Determine the valid offset range for scrolling through the effect\n  list, based on how many effects are running, and how many currently\n  fit on the display. If we are currently scrolled beyond the sensible\n  range, correct that. Returns a tuple of the current offset, the\n  maximum sensible offset, and the number of effects displayed.\"\n  [controller]\n  (let [room (room-for-effects controller)\n        size (count (:effects @(:active-effects (:show controller))))\n        max-offset (max 0 (- size room))\n        ;; If we are offset more than now makes sense, fix that.\n        offset (swap! (:effect-offset controller) min max-offset)]\n    [offset max-offset room]))\n\n(def no-effects-active-color\n  \"The color to use for the text explaining that no effects are\n  active.\"\n  (let [color (colors/desaturate (colors/create-color :blue) 70)]\n    (java.awt.Color. (colors/red color) (colors/green color) (colors/blue color))))\n\n(defn- render-effect-list\n  \"Display information about the four most recently activated\n  effects (or three, if the metronome is taking up a slot).\"\n  [controller snapshot]\n\n  ;; First clean up any cue variable scroll offsets for effects that have ended\n  (swap! (:cue-var-offsets controller) select-keys (map :id (:meta @(:active-effects (:show controller)))))\n\n  ;; Then adjust our scroll offset if it no longer makes sense\n  (find-effect-offset-range controller)\n\n  (let [room        (room-for-effects controller)\n        first-cell  (- 4 room)\n        fx-info     @(:active-effects (:show controller))\n        fx          (:effects fx-info)\n        fx-meta     (:meta fx-info)\n        num-skipped (- (count fx-meta) room @(:effect-offset controller))\n        graphics    (create-graphics controller)]\n    (if (seq fx)\n      (do (loop [fx      (take room (drop num-skipped fx))\n                 fx-meta (take room (drop num-skipped fx-meta))\n                 x       first-cell]\n            (let [info        (first fx-meta)\n                  ending      ((:key info) (:ending fx-info))\n                  cue         (:cue info)\n                  base-color       (if cue\n                                     (cues/current-cue-color cue info (:show controller) snapshot)\n                                     white-color)\n                  color (when base-color\n                          (if (and ending (> (rhythm/snapshot-beat-phase snapshot) 0.4))\n                            (colors/darken base-color 40)\n                            base-color))\n                  width       (* 2 button-cell-width)\n                  left        (* x width)\n                  scroll-vars (> (count (:variables cue)) 2)\n                  cur-vals    (when cue (cues/snapshot-cue-variables cue (:id info) :show (:show controller)))\n                  saved-vals  (controllers/cue-vars-saved-at (:cue-grid (:show controller)) (:x info) (:y info))\n                  save-action (when (seq cur-vals)\n                                (if (seq saved-vals)\n                                  (if (= cur-vals saved-vals) :clear :save)\n                                  (when (not= cur-vals (:starting-vars info))\n                                    :save)))]\n              (draw-cue-variable-names controller x cue (:id info))\n              (draw-cue-variable-values controller x cue (:id info))\n              (draw-cue-variable-gauges controller x cue (:id info))\n              (when (:visualizer cue)\n                (draw-cue-visualizer controller snapshot x cue (:variables info)))\n              (set-graphics-color graphics color)\n              (.fillRect graphics (+ left (/ button-cell-margin 2.0)) (- Wayang/DISPLAY_HEIGHT 38)\n                         (- width button-cell-margin) 20)\n              (let [label-font (get-display-font :condensed Font/PLAIN 16)\n                    context (.getFontRenderContext graphics)\n                    label (fit-string (or (:name cue) (:name (first fx))) label-font context\n                                      (- width button-cell-margin 2))\n                    label-width (string-width label label-font context)]\n                (set-graphics-color graphics (colors/create-color (util/contrasting-text-color color)))\n                (.setFont graphics label-font)\n                (.drawString graphics label (int (math/round (- (+ left button-cell-width) (/ label-width 2))))\n                             (- Wayang/DISPLAY_HEIGHT 23)))\n              (if (in-mode? controller :record)\n                (when save-action\n                  (let [save-color (case save-action\n                                     :save  green-color\n                                     :clear amber-color)]\n                    (swap! (:next-top-pads controller) assoc (* 2 x) (dim save-color))\n                    (draw-bottom-button-label controller (* 2 x) (case save-action\n                                                                   :save  \"Save\"\n                                                                   :clear \"Clear\") save-color)))\n                (do\n                  (swap! (:next-top-pads controller) assoc (* 2 x) dim-red-color)\n                  (draw-bottom-button-label controller (* 2 x) (if ending \"Ending\" \"End\") red-color)))\n              (when scroll-vars\n                (swap! (:next-top-pads controller) assoc (inc (* 2 x)) dim-white-color)\n                (draw-bottom-button-label controller (inc (* 2 x)) \"Next Vars >\" white-color))\n              (when (seq (rest fx))\n                (recur (rest fx) (rest fx-meta) (inc x)))))\n\n          ;; Draw indicators if there are effects hidden from view in either direction\n          (when (pos? num-skipped)\n            (set-graphics-color graphics white-color)\n            (.draw graphics (java.awt.geom.Line2D$Double.\n                             (+ (* first-cell 2 button-cell-width) 7) (- Wayang/DISPLAY_HEIGHT 16)\n                             (* first-cell 2 button-cell-width) (- Wayang/DISPLAY_HEIGHT 9)))\n            (.draw graphics (java.awt.geom.Line2D$Double.\n                             (* first-cell 2 button-cell-width) (- Wayang/DISPLAY_HEIGHT 9)\n                             (+ (* first-cell 2 button-cell-width) 7) (- Wayang/DISPLAY_HEIGHT 2))))\n          (when (pos? @(:effect-offset controller))\n            (set-graphics-color graphics white-color)\n            (.draw graphics (java.awt.geom.Line2D$Double.\n                             (- Wayang/DISPLAY_WIDTH 8) (- Wayang/DISPLAY_HEIGHT 16)\n                             (dec Wayang/DISPLAY_WIDTH) (- Wayang/DISPLAY_HEIGHT 9)))\n            (.draw graphics (java.awt.geom.Line2D$Double.\n                             (dec Wayang/DISPLAY_WIDTH) (- Wayang/DISPLAY_HEIGHT 9)\n                             (- Wayang/DISPLAY_WIDTH 8) (- Wayang/DISPLAY_HEIGHT 2)))))\n      (let [font  (get-display-font :condensed-light Font/ITALIC 36)\n            text  \"No effects are active.\"\n            width (calculate-text-width graphics font text)]\n        (.setFont graphics font)\n        (.setPaint graphics no-effects-active-color)\n        (.drawString graphics text (int (math/round (- (/ Wayang/DISPLAY_WIDTH 2) (/ width 2))))\n                     (/ Wayang/DISPLAY_HEIGHT 2))))))\n\n(declare enter-stop-mode)\n\n(defn- render-scroll-arrows\n  \"Activate the arrow buttons for directions in which scrolling is\n  possible.\"\n  [controller]\n  ;; The page left/right buttons scroll through the effect list\n  (let [[offset max-offset] (find-effect-offset-range controller)]\n    ;; If there is an offset, user can scroll to the right\n    (when (pos? offset)\n      (swap! (:next-text-buttons controller) assoc (:page-right control-buttons) dim-white-color))\n    ;; Is there room to scroll to the left?\n    (when (< offset max-offset)\n      (swap! (:next-text-buttons controller) assoc (:page-left control-buttons) dim-white-color)))\n\n  ;; The arrow keys scroll through the cue grid\n  (let [[origin-x origin-y] @(:origin controller)]\n    (when (pos? origin-x)\n      (swap! (:next-text-buttons controller) assoc (:left-arrow control-buttons) dim-white-color))\n    (when (pos? origin-y)\n      (swap! (:next-text-buttons controller) assoc (:down-arrow control-buttons) dim-white-color))\n    (when (> (- (controllers/grid-width (:cue-grid (:show controller))) origin-x) 7)\n      (swap! (:next-text-buttons controller)\n             assoc (:right-arrow control-buttons) dim-white-color))\n    (when (> (- (controllers/grid-height (:cue-grid (:show controller))) origin-y) 7)\n      (swap! (:next-text-buttons controller)\n             assoc (:up-arrow control-buttons) dim-white-color))))\n\n(defn- render-mode-buttons\n  \"Illuminate the buttons which activate modes while they are held\n  down. Make them dim when not held, and bright when held.\"\n  [controller mode-buttons]\n  (doseq [button-key mode-buttons]\n    (let [button (button-key control-buttons)]\n      (swap! (:next-text-buttons controller)\n             assoc button (if (in-mode? controller button-key)\n                            (or (:bright-color button) white-color)\n                            (or (:dim-color button) dim-white-color))))))\n\n(def empty-top-pads\n  \"A representation of the state when all eight of the top pads are\n  off.\"\n  (vec (repeat 8 off-color)))\n\n(def empty-grid-pads\n  \"A representation of the state when all 64 of the grid pads are\n  off.\"\n  (vec (repeat 64 off-color)))\n\n(defn light-custom-buttons\n  \"Light any custom buttons that have been configured to make it clear\n  they are active. (If the button already has a lightness value, it\n  was not appropriate for it to have been configured as a custom\n  button, so leave it alone.)\"\n  [controller]\n  (doseq [custom (vals @(:custom-control-buttons controller))]\n    (swap! (:next-text-buttons controller) update (:button custom) #(or % dim-white-color))))\n\n(defn- update-interface\n  \"Determine the desired current state of the interface, and send any\n  changes needed to get it to that state.\"\n  [controller]\n  (try\n    ;; Assume we are starting out with a blank interface.\n    (clear-display-buffer controller)\n    (reset! (:next-text-buttons controller) {})\n    (reset! (:next-top-pads controller) empty-top-pads)\n    (reset! (:next-touch-strip controller) [0 touch-strip-mode-sysex])\n\n    (let [snapshot (rhythm/metro-snapshot (get-in controller [:show :metronome]))]\n      (render-effect-list controller snapshot)\n      (render-metronome-section controller snapshot)\n\n      ;; If the show has stopped without us noticing, enter stop mode\n      (with-show (:show controller)\n        (when-not (or (show/running?) (in-mode? controller :stop))\n          (enter-stop-mode controller :already-stopped true)))\n\n      (render-mode-buttons controller [:shift :record])\n      (render-cue-grid controller snapshot)\n      (render-scroll-arrows controller)\n\n      ;; Make the User button bright, since we live in User mode\n      (swap! (:next-text-buttons controller) assoc (:user-mode control-buttons) white-color)\n\n      ;; Make the play button red, indicating it will stop the show\n      (swap! (:next-text-buttons controller) assoc (:stop control-buttons) dim-red-color)\n\n      ;; Light up any custom buttons that have been configured.\n      (light-custom-buttons controller)\n\n      ;; Add any contributions from interface overlays, removing them\n      ;; if they report being finished.\n      (controllers/run-overlays (:overlays controller) snapshot))\n\n    (update-cue-grid controller)\n    (Wayang/sendFrameAsync)\n    (update-top-pads controller)\n    (update-text-buttons controller)\n    (update-touch-strip controller)\n\n    (catch Throwable t\n      (timbre/warn t \"Problem updating Ableton Push Interface\"))))\n\n(declare clear-interface)\n\n(defn- welcome-frame\n  \"Render a frame of the welcome animation, or if it is done, start\n  the main interface update thread, and terminate the task running the\n  animation.\"\n  [controller counter task]\n  (try\n    (cond\n      (< @counter 8)\n      (doseq [y (range 0 (inc @counter))]\n        (let [color (colors/create-color\n                     :h 0 :s 0 :l (max 10 (- 75 (/ (* 50 (- @counter y)) 6))))]\n          (set-pad-color controller 3 y color)\n          (set-pad-color controller 4 y color)))\n\n      (< @counter 12)\n      (doseq [x (range 0 (- @counter 7))\n              y (range 0 8)]\n        (let [color (colors/create-color\n                     :h 340 :s 100 :l (- 75 (* (- @counter 8 x) 20)))]\n          (set-pad-color controller (- 3 x) y color)\n          (set-pad-color controller (+ 4 x) y color)))\n\n      (< @counter 15)\n      (doseq [y (range 0 8)]\n        (let [color (colors/create-color\n                     :h (* 13 (- @counter 11)) :s 100 :l 50)]\n          (set-pad-color controller (- @counter 7) y color)\n          (set-pad-color controller (- 14 @counter) y color)))\n\n      (= @counter 15)\n      (do\n        (show-labels controller white-color)\n        (Wayang/sendFrame))\n\n      (= @counter 16)\n      (doseq [x (range 0 8)]\n        (set-top-pad-color controller x amber-color))\n\n      (= @counter 17)\n      (doseq [x (range 0 8)]\n        (set-encoder-pad-color controller x amber-color)\n        (set-top-pad-color controller x red-color))\n\n      (< @counter 26)\n      (doseq [x (range 0 8)]\n        (let [lightness-index (if (> x 3) (- 7 x) x)\n              lightness ([10 30 50 70] lightness-index)\n              color (colors/create-color\n                     :h (+ 60 (* 40 (- @counter 18))) :s 100 :l lightness)]\n          (set-pad-color controller x (- 25 @counter) color)))\n\n      (= @counter 26)\n      (do\n        (show-labels controller dim-white-color)\n        (doseq [x (range 0 8)]\n          (set-top-pad-color controller x off-color)))\n\n      (= @counter 27)\n      (doseq [x (range 0 8)]\n        (set-encoder-pad-color controller x off-color))\n\n      (< @counter 36)\n      (doseq [x (range 0 8)]\n        (set-pad-color controller x (- 35 @counter) off-color))\n\n      :else\n      (do\n        (clear-interface controller)\n        (amidi/add-device-mapping (:port-in controller) @(:midi-handler controller))\n        (enter-metronome-showing controller)\n        (reset! (:task controller) (at-at/every (:refresh-interval controller)\n                                                #(update-interface controller)\n                                                controllers/pool\n                                                :initial-delay 10\n                                                :desc \"Push interface update\"))\n        (at-at/kill @task)))\n    (catch Throwable t\n      (timbre/warn t \"Animation frame failed\")))\n\n  (swap! counter inc))\n\n(defn- show-welcome-text\n  \"Draw the welcome message on the display.\"\n  [controller]\n  (clear-display-buffer controller)\n  (let [welcome (str \"Welcome to \" (version/title))\n        version (str \"version \" (version/tag))\n        graphics (create-graphics controller)\n        context (.getFontRenderContext graphics)]\n    (.setFont graphics (get-display-font :roboto-medium Font/PLAIN 42))\n    (.setPaint graphics (java.awt.Color/WHITE))\n    (let [x (int (- (/ Wayang/DISPLAY_WIDTH 2) (/ (string-width welcome (.getFont graphics) context) 2)))]\n      (.drawString graphics welcome x 80))\n    (.setFont graphics (get-display-font :condensed-light Font/ITALIC 20))\n    (.setPaint graphics (java.awt.Color/BLUE))\n    (let [x (int (- (/ Wayang/DISPLAY_WIDTH 2) (/ (string-width version (.getFont graphics) context) 2)))]\n      (.drawString graphics version x 110))\n    (let [afterglow-logo (javax.imageio.ImageIO/read\n                          (.getResourceAsStream Effect \"/public/img/Afterglow-logo-padded-left.png\"))\n          afterglow-scale (/ Wayang/DISPLAY_HEIGHT (.getHeight afterglow-logo))\n          deep-logo (javax.imageio.ImageIO/read\n                     (.getResourceAsStream Effect \"/public/img/Deep-Symmetry-logo.png\"))\n          deep-scale 0.4\n          deep-width (math/round (* (.getWidth deep-logo) deep-scale))\n          deep-height (math/round (* (.getHeight deep-logo) deep-scale))]\n      (.drawImage graphics afterglow-logo 20 0\n                  (math/round (* (.getWidth afterglow-logo) afterglow-scale)) Wayang/DISPLAY_HEIGHT nil)\n      (.drawImage graphics deep-logo\n                  (- Wayang/DISPLAY_WIDTH deep-width 20) (- (/ Wayang/DISPLAY_HEIGHT 2) (/ deep-height 2))\n                  deep-width deep-height nil)))\n  (Wayang/sendFrame))\n\n(defn- welcome-animation\n  \"Provide a fun animation to make it clear the Push is online.\"\n  [controller]\n  (show-welcome-text controller)\n  (let [counter (atom 0)\n        task (atom nil)]\n    (reset! task (at-at/every 50 #(welcome-frame controller counter task)\n                              controllers/pool))))\n\n(defn clear-interface\n  \"Clears the graphical display and all illuminated buttons and pads.\"\n  [controller]\n  (clear-display controller)\n  (doseq [x (range 8)]\n    (set-top-pad-color controller x off-color)\n    (set-encoder-pad-color controller x off-color)\n    (doseq [y (range 8)]\n      (set-pad-color controller x y off-color)))\n  (reset! (:last-top-pads controller) empty-top-pads)\n  (reset! (:last-grid-pads controller) empty-grid-pads)\n  (doseq [[_ button] control-buttons]\n    (set-button-color controller button off-color))\n  (reset! (:last-text-buttons controller) {})\n  (set-touch-strip-mode controller touch-strip-mode-default)\n  (reset! (:last-touch-strip controller) nil))\n\n(def master-background\n  \"The background for the grand master section, to mark it as such.\"\n  (colors/darken (colors/desaturate (colors/create-color :yellow) 55) 45))\n\n(def master-content\n  \"The color for content in the metronome section, to mark it as such.\"\n  (colors/lighten (colors/create-color :yellow) 20))\n\n(defn- master-encoder-touched\n  \"Add a user interface overlay to give feedback when turning the\n  master encoder.\"\n  [controller]\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [_this] #{79})\n                             (captured-notes [_this] #{8 7})\n                             (adjust-interface [_this _]\n                               (let [level (master-get-level (get-in controller [:show :grand-master]))\n                                     graphics (create-graphics controller)]\n                                 (set-graphics-color graphics master-background)\n\n                                 ;; Draw the background that makes the master section distinctive.\n                                 (set-graphics-color graphics master-background)\n                                 (.fillRect graphics (- Wayang/DISPLAY_WIDTH button-cell-width) 0\n                                            button-cell-width 100)\n\n                                 ;; Draw the label, value, and gauge\n                                 (set-graphics-color graphics master-content)\n                                 (draw-encoder-button-label controller 7 1 \"Grand Master\" master-content)\n                                 (draw-cue-variable-value controller 7 1\n                                                          (format \"%5.1f\" level) master-content)\n                                 (draw-gauge controller 7 1 level :track-color dim-amber-color\n                                             :active-color master-content)\n                                 (set-touch-strip-from-value controller level 0 100 touch-strip-mode-level))\n                               true)\n                             (handle-control-change [_this message]\n                               ;; Adjust the BPM based on how the encoder was twisted\n                               (let [delta (/ (sign-velocity (:velocity message)) 2)\n                                     level (master-get-level (get-in controller [:show :grand-master]))]\n                                 (master-set-level (get-in controller [:show :grand-master]) (+ level delta))\n                                 true))\n                             (handle-note-on [_this _message]\n                               true) ; Suppress activation of the encoder above our overlay\n                             (handle-note-off [_this message]\n                               ;; Exit the overlay if it was our own encoder being released\n                               (when (= (:note message) 8) :done))\n                             (handle-aftertouch [_this _message])\n                             (handle-pitch-bend [_this message]\n                               (master-set-level (get-in controller [:show :grand-master])\n                                                 (value-from-touch-strip message 0 100))))))\n\n(defn- bpm-encoder-touched\n  \"Add a user interface overlay to give feedback when turning the BPM\n  encoder.\"\n  [controller]\n  ;; Reserve the metronome area for its coordinated set of overlays\n  (swap! (:metronome-mode controller) assoc :adjusting-bpm :true)\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [_this] #{15})\n                             (captured-notes [_this] #{9 1})\n                             (adjust-interface [_this snapshot]\n                               (bpm-adjusting-interface controller snapshot)\n                               true)\n                             (handle-control-change [_this message]\n                               (adjust-bpm-from-encoder controller message))\n                             (handle-note-on [_this _message]\n                               ;; Suppress the extra encoder above the BPM display.\n                               ;; We can't get a note on for the BPM encoder, because\n                               ;; that was the event that created this overlay.\n                               true)\n                             (handle-note-off [_this message]\n                               (when (= (:note message) 9)\n                                 ;; They released us, end the overlay\n                                 (swap! (:metronome-mode controller) dissoc :adjusting-bpm)\n                                 :done))\n                             (handle-aftertouch [_this _message])\n                             (handle-pitch-bend [_this message]\n                               (rhythm/metro-bpm (:metronome (:show controller))\n                                                 (value-from-touch-strip message controllers/minimum-bpm\n                                                                         controllers/maximum-bpm))))))\n\n(defn- beat-encoder-touched\n  \"Add a user interface overlay to give feedback when turning the beat\n  encoder.\"\n  [controller]\n  ;; Reserve the metronome area for its coordinated set of overlays\n  (swap! (:metronome-mode controller) assoc :adjusting-beat :true)\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [_this] #{14})\n                             (captured-notes [_this] #{10 0})\n                             (adjust-interface [_this snapshot]\n                               (beat-adjusting-interface controller snapshot))\n                             (handle-control-change [_this message]\n                               (adjust-beat-from-encoder controller message))\n                             (handle-note-on [_this _message]\n                               ;; Suppress the extra encoder above the beat display.\n                               ;; We can't get a note on for the beat encoder, because\n                               ;; that was the event that created this overlay.\n                               true)\n                             (handle-note-off [_this message]\n                               (when (= (:note message) 10)\n                                 ;; They released us, exit the overlay\n                                 (swap! (:metronome-mode controller) dissoc :adjusting-beat)\n                                 :done))\n                             (handle-aftertouch [_this _message])\n                             (handle-pitch-bend [_this _message]))))\n\n(defn- leave-user-mode\n  \"The user has asked to exit user mode, so suspend our display\n  updates, and prepare to restore our state when user mode is pressed\n  again.\"\n  [controller]\n  (swap! (:task controller) (fn [task]\n                              (when task (at-at/kill task))\n                              nil))\n  (clear-interface controller)\n  (restore-led-palettes controller)\n\n  ;; In case Live isn't running, leave the User Mode button dimly lit, to help the user return.\n  (set-button-color controller (:user-mode control-buttons) dim-white-color)\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [_this] #{59})\n                             (captured-notes [_this] #{})\n                             (adjust-interface [_this _snapshot]\n                               true)\n                             (handle-control-change [_this message]\n                               (when (pos? (:velocity message))\n                                 ;; We are returning to user mode, restore display\n                                 (clear-interface controller)\n                                 (reset! (:task controller) (at-at/every (:refresh-interval controller)\n                                                                         #(update-interface controller)\n                                                                         controllers/pool\n                                                                         :initial-delay 250\n                                                                         :desc \"Push interface update\"))\n                                 :done))\n                             (handle-note-on [_this _message])\n                             (handle-note-off [_this _message])\n                             (handle-aftertouch [_this _message])\n                             (handle-pitch-bend [_this _message]))))\n\n(def stop-indicator\n  \"The overlay drawn on top of the effects when the show is stopped.\"\n  (javax.imageio.ImageIO/read (.getResourceAsStream Effect \"/public/img/Push-2-Stopped.png\")))\n\n(defn- enter-stop-mode\n  \"The user has asked to stop the show. Suspend its update task\n  and black it out until the stop button is pressed again.\"\n  [controller & {:keys [already-stopped]}]\n\n  (update-mode! controller :stop true)\n  (when-not already-stopped\n    (with-show (:show controller)\n      (show/stop!)\n      (Thread/sleep (:refresh-interval (:show controller)))\n      (show/blackout-show)))\n\n  (let [start-counter (atom 8)\n        end-counter (atom nil)\n        graphics (create-graphics controller)\n        saved-composite (.getComposite graphics)]\n    (controllers/add-overlay (:overlays controller)\n                             (reify controllers/IOverlay\n                               (captured-controls [_this] #{85})\n                               (captured-notes [_this] #{})\n                               (adjust-interface [_this _snapshot]\n                                 (if @end-counter\n                                   ;; Draw an ending animation frame, returning false once finished to end the overlay\n                                   (do\n                                     (.setComposite graphics (AlphaComposite/getInstance AlphaComposite/SRC_OVER\n                                                                                         (/ @end-counter 8.0)))\n                                     (.drawImage graphics stop-indicator 400 0 nil)\n                                     (.setComposite graphics saved-composite)\n                                     (pos? (swap! end-counter dec)))\n                                   (do\n                                     (if (pos? @start-counter)\n                                       ;; Draw a starting animation frame rather than the normal view\n                                       (let [x (quot Wayang/DISPLAY_WIDTH 2)\n                                             y (quot Wayang/DISPLAY_HEIGHT 2)\n                                             scale (/ (- 9 @start-counter) 8)\n                                             side (math/round (* scale Wayang/DISPLAY_HEIGHT))\n                                             offset (quot side 2)]\n                                         (.setComposite graphics\n                                                        (AlphaComposite/getInstance AlphaComposite/SRC_OVER\n                                                                                    (/ (- 9 @start-counter) 8.0)))\n                                         (.drawImage graphics stop-indicator (- x offset) (- y offset) side side nil)\n                                         (.setComposite graphics saved-composite)\n                                         (swap! start-counter dec))\n                                       ;; Draw the normal view\n                                       (.drawImage graphics stop-indicator 400 0 nil))\n\n                                     (when (in-mode? controller :stop)\n                                       ;; We seem to still be in stop mode, so do our normal things.\n\n                                       ;; Make the play button green to indicate it will start the show\n                                       (swap! (:next-text-buttons controller)\n                                              assoc (:stop control-buttons) dim-green-color)\n\n                                       ;; But see if we need to exit because the show has started\n                                       (with-show (:show controller)\n                                         (when (show/running?)\n                                           (update-mode! controller :stop false)\n                                           (swap! end-counter #(or % (- 8 @start-counter))))\n                                         true)))))  ; Give the ending animation a chance to run\n                               (handle-control-change [_this message]\n                                 #_(timbre/info \"Stop message\" message)\n                                 (when (pos? (:velocity message))\n                                   ;; End stop mode and start the ending animation if it isn't already\n                                   (with-show (:show controller)\n                                     (show/start!))\n                                   (update-mode! controller :stop false)\n                                   (swap! end-counter #(or % (- 8 @start-counter)))))\n                               (handle-note-on [_this _message])\n                               (handle-note-off [_this _message])\n                               (handle-aftertouch [_this _message])\n                               (handle-pitch-bend [_this _message]))\n                             :priority 100))) ; Draw the stop overlay after all others.\n\n(defn add-button-held-feedback-overlay\n  \"Adds a simple overlay which keeps a control button bright as long\n  as the user is holding it down.\"\n  [controller button]\n  (controllers/add-control-held-feedback-overlay (:overlays controller) (:control button)\n                                                 (fn [_] (swap! (:next-text-buttons controller)\n                                                                assoc button (or (:bright-color button)\n                                                                                 white-color)))))\n\n(defn- handle-save-effect\n  \"Process a tap on one of the pads which indicate the user wants to\n  save or clear the variables for the associated effect.\"\n  [controller note]\n  (let [room    (room-for-effects controller)\n        fx-info @(:active-effects (:show controller))\n        fx      (:effects fx-info)\n        fx-meta (:meta fx-info)\n        num-skipped (- (count fx-meta) room @(:effect-offset controller))\n        fx (vec (drop num-skipped fx))\n        fx-meta (vec (drop num-skipped fx-meta))\n        offset  (- 4 room)\n        x       (quot (- note 20) 2)\n        index   (- x offset)]\n    (when (and (seq fx) (< index (count fx)))\n      (let [info        (get fx-meta index)\n            cue         (:cue info)\n            cur-vals    (cues/snapshot-cue-variables cue (:id info) :show (:show controller))\n            saved-vals  (controllers/cue-vars-saved-at (:cue-grid (:show controller)) (:x info) (:y info))\n            save-action (when (seq cur-vals)\n                          (if (= cur-vals saved-vals) :clear\n                              (when (not= cur-vals (:starting-vars info)) :save)))\n            save-color (case save-action\n                         :save  green-color\n                         :clear amber-color)]\n        (when save-action\n          (case save-action\n            :save  (controllers/save-cue-vars! (:cue-grid (:show controller)) (:x info) (:y info) cur-vals)\n            :clear (controllers/clear-saved-cue-vars! (:cue-grid (:show controller)) (:x info) (:y info)))\n          (controllers/add-control-held-feedback-overlay (:overlays controller) note\n                                                         (fn [_]\n                                                           (swap! (:next-top-pads controller) assoc (* 2 x)\n                                                                  save-color)\n                                                           (draw-bottom-button-label controller (* 2 x)\n                                                                                     (case save-action\n                                                                                       :save \"Saved\"\n                                                                                       :clear \"Cleared\") save-color)\n                                                           true)))))))\n\n(defn- handle-end-effect\n  \"Process a tap on one of the pads which indicate the user wants to\n  end the associated effect.\"\n  [controller note]\n  (let [room (room-for-effects controller)\n        fx-info @(:active-effects (:show controller))\n        fx (:effects fx-info)\n        fx-meta (:meta fx-info)\n        num-skipped (- (count fx-meta) room @(:effect-offset controller))\n        fx (vec (drop num-skipped fx))\n        fx-meta (vec (drop num-skipped fx-meta))\n        offset (- 4 room)\n        x (quot (- note 20) 2)\n        index (- x offset)]\n    (when (and (seq fx) (< index (count fx)))\n      (let [info (get fx-meta index)]\n        (with-show (:show controller)\n          (show/end-effect! (:key info) :when-id (:id info)))\n        (controllers/add-overlay (:overlays controller)\n                                 (reify controllers/IOverlay\n                                   (captured-controls [_this] #{note (inc note)})\n                                   (captured-notes [_this] #{})\n                                   (adjust-interface [_this _]\n                                     (swap! (:next-top-pads controller) assoc (* 2 x) red-color)\n                                     (swap! (:next-top-pads controller) assoc (inc (* 2 x)) off-color)\n                                     true)\n                                   (handle-control-change [_this message]\n                                     (when (and (= (:note message) note) (zero? (:velocity message)))\n                                       :done))\n                                   (handle-note-on [_this _message])\n                                   (handle-note-off [_this _message])\n                                   (handle-aftertouch [_this _message])\n                                   (handle-pitch-bend [_this _message])))))))\n\n(defn- handle-scroll-cue-vars\n  \"Process a tap on one of the pads which indicate the user wants to\n  scroll forward in the list of cue variables.\"\n  [controller note]\n  (let [room (room-for-effects controller)\n        fx-info @(:active-effects (:show controller))\n        fx (vec (:effects fx-info))\n        fx-meta (vec (:meta fx-info))\n        num-skipped (- (count fx-meta) room @(:effect-offset controller))\n        fx (vec (drop num-skipped fx))\n        fx-meta (vec (drop num-skipped fx-meta))\n        offset (- 4 room)\n        x (quot (- note 21) 2)\n        index (- x offset)]\n    (when (and (seq fx) (< index (count fx)))\n      (let [info (get fx-meta index)\n            cue (:cue info)\n            var-count (count (:variables cue))]\n        (when (> var-count 2)\n          (swap! (:cue-var-offsets controller) update-in [(:id info)] #(mod (+ 2 (or % 0)) var-count))\n          (controllers/add-overlay (:overlays controller)\n                                   (reify controllers/IOverlay\n                                     (captured-controls [_this] #{note})\n                                     (captured-notes [_this] #{})\n                                     (adjust-interface [_this _]\n                                       (swap! (:next-top-pads controller) assoc (inc (* 2 x)) white-color)\n                                       true)\n                                     (handle-control-change [_this message]\n                                       (when (and (= (:note message) note) (zero? (:velocity message)))\n                                         :done))\n                                     (handle-note-on [_this _message])\n                                     (handle-note-off [_this _message])\n                                     (handle-aftertouch [_this _message])\n                                     (handle-pitch-bend [_this _message]))))))))\n\n(defn- move-origin\n  \"Changes the origin of the controller, notifying any registered\n  listeners.\"\n  [controller origin]\n  (when (not= origin @(:origin controller))\n    (reset! (:origin controller) origin)\n    (doseq [f @(:move-listeners controller)] (f @(:grid-controller-impl controller) :moved))))\n\n(defn- control-change-received\n  \"Process a control change message which was not handled by an\n  interface overlay.\"\n  [controller message]\n  (case (:note message)\n    3 ; Tap tempo button\n    (when (pos? (:velocity message))\n      ((:tempo-tap-handler controller))\n      (enter-metronome-showing controller))\n\n    9 ; Metronome button\n    (when (pos? (:velocity message))\n      (enter-metronome-showing controller))\n\n    (20 22 24 26) ; Effect end/save pads\n    (when (pos? (:velocity message))\n      (if (in-mode? controller :record)\n        (handle-save-effect controller (:note message))\n        (handle-end-effect controller (:note message))))\n\n    (21 23 25 27) ; Effect cue variable scroll pads\n    (when (pos? (:velocity message))\n      (handle-scroll-cue-vars controller (:note message)))\n\n    ;; 28 ; Master button\n\n    85 ; Play button\n    (when (pos? (:velocity message))\n      (enter-stop-mode controller))\n\n    (49 86) ; Shift or Record button\n    (update-mode! controller (:note message) (pos? (:velocity message)))\n\n    62 ; Page left, scroll back to older effects\n    (when (pos? (:velocity message))\n        (let [[offset max-offset room] (find-effect-offset-range controller)\n              new-offset (if (in-mode? controller :shift)\n                           max-offset\n                           (min max-offset (+ offset room)))]\n          (when (not= offset new-offset)\n            (reset! (:effect-offset controller) new-offset)\n            (add-button-held-feedback-overlay controller (:page-left control-buttons)))))\n\n    63 ; Page right, scroll forward to newer effects\n    (when (pos? (:velocity message))\n      (let [[offset _max-offset room] (find-effect-offset-range controller)\n            new-offset (if (in-mode? controller :shift) 0 (max 0 (- offset room)))]\n        (when (not= offset new-offset)\n          (reset! (:effect-offset controller) new-offset)\n          (add-button-held-feedback-overlay controller (:page-right control-buttons)))))\n\n    44 ; Left arrow, scroll left in cue grid\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)]\n        (when (pos? x)\n          (move-origin controller [(if (in-mode? controller :shift) 0 (max 0 (- x 8))) y])\n          (add-button-held-feedback-overlay controller (:left-arrow control-buttons)))))\n\n    45 ; Right arrow, scroll right in cue grid\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)\n            width (max (controllers/grid-width (:cue-grid (:show controller))) 1)]\n        (when (> (- width x) 7)\n          (move-origin controller [(if (in-mode? controller :shift) (* 8 (quot (dec width) 8)) (+ x 8)) y])\n          (add-button-held-feedback-overlay controller (:right-arrow control-buttons)))))\n\n    46 ; Up arrow, scroll up in cue grid\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)\n            height (max (controllers/grid-height (:cue-grid (:show controller))) 1)]\n        (when (> height 7)\n          (move-origin controller [x (if (in-mode? controller :shift) (* 8 (quot (dec height) 8)) (+ y 8))])\n          (add-button-held-feedback-overlay controller (:up-arrow control-buttons)))))\n\n    47 ; Down arrow, scroll down in cue grid\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)]\n        (when (pos? y)\n          (move-origin controller [x (if (in-mode? controller :shift) 0 (max 0 (- y 8)))])\n          (add-button-held-feedback-overlay controller (:down-arrow control-buttons)))))\n\n    59 ; User mode button\n    (when (pos? (:velocity message))\n      (leave-user-mode controller))\n\n    ;; Something we don't explictly recognize; see if it's been registered as a custom control button.\n    (when-let [custom (get @(:custom-control-buttons controller) (:note message))]\n      (when (pos? (:velocity message))\n        (try\n          ((:press custom))\n          (catch Throwable t\n            (timbre/error t \"Problem running custom control button press function.\")))\n        (controllers/add-overlay\n         (:overlays controller)\n         (reify controllers/IOverlay\n           (captured-controls [_this] #{(:note message)})\n           (captured-notes [_this] #{})\n           (adjust-interface [_this _snapshot]\n             (swap! (:next-text-buttons controller) assoc (:button custom) white-color))\n           (handle-control-change [_this message]\n             (when (and (= (:note message) (get-in custom [:button :control]))\n                        (zero? (:velocity message)))\n               (try\n                 ((:release custom))\n                 (catch Throwable t\n                   (timbre/error t \"Problem running custom control button release function.\")))\n               :done))\n           (handle-note-on [_this _message])\n           (handle-note-off [_this _message])\n           (handle-aftertouch [_this _message])\n           (handle-pitch-bend [_this _message])))))))\n\n(defn- note-to-cue-coordinates\n  \"Translate the MIDI note associated with an incoming message to its\n  coordinates in the show cue grid.\"\n  [controller note]\n  (let [base (- note 36)\n        [origin-x origin-y] @(:origin controller)\n        pad-x (rem base 8)\n        pad-y (quot base 8)\n        cue-x (+ origin-x pad-x)\n        cue-y (+ origin-y pad-y)]\n    [cue-x cue-y pad-x pad-y]))\n\n(defn- cue-grid-pressed\n  \"One of the pads in the 8x8 pressure-sensitve cue grid was pressed.\"\n  [controller note velocity]\n  (let [[cue-x cue-y pad-x pad-y] (note-to-cue-coordinates controller note)\n        [cue active] (show/find-cue-grid-active-effect (:show controller) cue-x cue-y)]\n          (when cue\n            (with-show (:show controller)\n              (if (and active (not (:held cue)))\n                (show/end-effect! (:key cue))\n                (let [id (show/add-effect-from-cue-grid! cue-x cue-y :velocity velocity)\n                      holding (and (:held cue) (not (in-mode? controller :shift)))]\n                  (controllers/add-overlay\n                   (:overlays controller)\n                   (reify controllers/IOverlay\n                     (captured-controls [_this] #{})\n                     (captured-notes [_this] #{note})\n                     (adjust-interface [_this snapshot]\n                       (when holding\n                         (let [active (show/find-effect (:key cue))\n                               base-color (cues/current-cue-color cue active (:show controller) snapshot)\n                               color (colors/create-color\n                                      :h (colors/hue base-color)\n                                      :s (colors/saturation base-color)\n                                      :l 75)]\n                           (swap! (:next-grid-pads controller) assoc (+ pad-x (* pad-y 8)) color)))\n                       true)\n                     (handle-control-change [_this _message])\n                     (handle-note-on [_this _message])\n                     (handle-note-off [_this _message]\n                       (when holding\n                         (with-show (:show controller)\n                           (show/end-effect! (:key cue) :when-id id)))\n                       :done)\n                     (handle-aftertouch [_this message]\n                       (if (zero? (:velocity message))\n                         (do (when holding\n                               (with-show (:show controller)\n                                 (show/end-effect! (:key cue) :when-id id)))\n                             :done)\n                         (doseq [v (:variables cue)]\n                           (when (:velocity v)\n                             (cues/set-cue-variable! cue v\n                                                     (controllers/value-for-velocity v (:velocity message))\n                                                     :show (:show controller) :when-id id)))))\n                     (handle-pitch-bend [_this _message])))))))))\n\n(defn- control-for-top-encoder-note\n  \"Return the control number on which rotation of the encoder whose\n  touch events are sent on the specified note will be sent.\"\n  [note]\n  (+ note 71))\n\n(defn- adjust-variable-value\n  \"Handle a control change from turning an encoder associated with a\n  variable being adjusted in the effect list.\"\n  [controller message cue v effect-id]\n  (let [value (or (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id) 0)\n        low (min value (:min v))  ; In case user set \"out of bounds\".\n        high (max value (:max v))\n        raw-resolution (/ (- high low) 200)\n        resolution (or (:resolution v) (if (= :integer (:type v))\n                                         (max 1 (Math/round (double raw-resolution)))\n                                         raw-resolution))\n        delta (* (sign-velocity (:velocity message)) resolution)\n        adjusted (+ value delta)\n        normalized (if (= :integer (:type v)) (Math/round (double adjusted))\n                       (double (* (Math/round (/ adjusted resolution)) resolution)))]\n    (cues/set-cue-variable! cue v (max low (min high normalized)) :show (:show controller) :when-id effect-id)))\n\n(defn- bend-variable-value\n  \"Handle a pitch bend change while an encoder associated with a\n  variable is being adjusted in the effect list.\"\n  [controller message cue v effect-id]\n  (let [adjusted (value-from-touch-strip message (:min v) (:max v))\n        resolution (or (:resolution v) (if (= :integer (:type v))\n                                         1\n                                         (/ (- (:max v) (:min v)) 200)))\n        normalized (if (= :integer (:type v)) (Math/round (double adjusted))\n                       (double (* (Math/round (/ adjusted resolution)) resolution)))]\n    (cues/set-cue-variable! cue v (max (:min v) (min (:max v) normalized)) :show (:show controller)\n                            :when-id effect-id)))\n\n(defn- adjust-boolean-value\n  \"Handle a control change from turning an encoder associated with a\n  boolean variable being adjusted in the effect list.\"\n  [controller message cue v effect-id]\n  (let [new-value (true? (pos? (sign-velocity (:velocity message))))]\n    (cues/set-cue-variable! cue v new-value :show (:show controller) :when-id effect-id)))\n\n(defn- same-effect-active\n  \"See if the specified effect is still active with the same id.\"\n  [controller cue id]\n  (with-show (:show controller)\n    (let [effect-found (show/find-effect (:key cue))]\n      (and effect-found (= (:id effect-found) id)))))\n\n(defn- build-boolean-adjustment-overlay\n  \"Create an overlay for adjusting a boolean cue parameter. `note`\n  identifies the encoder that was touched to bring up this overlay,\n  `cue` is the cue whose variable is being adjusted, `v` is the map\n  identifying the variable itself, `effect` is the effect which that\n  cue is running, and `info` is the metadata about that effect.\n\n  Also suppresses the ability to scroll through the cue variables\n  while the encoder is being held.\"\n  [controller note cue v _effect info]\n  (let [x (quot note 2)\n        fraction (atom nil)]\n    (if (> (count (:variables cue)) 1)\n      ;; More than one variable, adjust whichever's encoder was touched\n      (reify controllers/IOverlay\n        (captured-controls [_this] #{(control-for-top-encoder-note note) (+ 21 (* 2 x))})\n        (captured-notes [_this] #{note})\n        (adjust-interface [_this _]\n          (when (same-effect-active controller cue (:id info))\n            (let [cur-val (or (cues/get-cue-variable cue v :show (:show controller) :when-id (:id info)) false)]\n              (draw-boolean-gauge controller note 1 cur-val :active? true :fraction (or @fraction 1.0))\n              (set-touch-strip-from-value controller (if cur-val 1 0) 0 1 touch-strip-mode-pan))\n            (swap! fraction (fn [v] (when v (let [result (+ v 0.25)] (when (< result 1.0) result)))))\n            (swap! (:next-top-pads controller) assoc (inc (* 2 x)) off-color)\n            true))\n        (handle-control-change [_this message]\n          (when (= (:note message) (control-for-top-encoder-note note))\n            (let [cur-val (or (cues/get-cue-variable cue v :show (:show controller) :when-id (:id info)) false)]\n              (adjust-boolean-value controller message cue v (:id info))\n              (when (not= cur-val (cues/get-cue-variable cue v :show (:show controller) :when-id (:id info)))\n                (swap! fraction (fn [v] (if (nil? v) 0.25 (- 1.0 v)))))))\n          true)\n        (handle-note-on [_this _message])\n        (handle-note-off [_this _message]\n          :done)\n        (handle-aftertouch [_this _message])\n        (handle-pitch-bend [_this message]\n          (cues/set-cue-variable! cue v (true? (>= (value-from-touch-strip message 0 100) 50))\n                                  :show (:show controller) :when-id (:id info))\n          (reset! fraction nil)))\n\n      ;; Just one variable, take full cell, using either encoder,\n      ;; suppress the other one.\n      (let [paired-note (if (odd? note) (dec note) (inc note))]\n        (reify controllers/IOverlay\n          (captured-controls [_this] #{(control-for-top-encoder-note note) (+ 21 (* 2 x))})\n          (captured-notes [_this] #{note paired-note})\n          (adjust-interface [_this _]\n            (when (same-effect-active controller cue (:id info))\n              (let [cur-val (or (cues/get-cue-variable cue v :show (:show controller) :when-id (:id info)) false)]\n                (draw-boolean-gauge controller (* 2 x) 2 cur-val :active? true)\n                (set-touch-strip-from-value controller (if cur-val 1 0) 0 1 touch-strip-mode-pan))\n              (swap! (:next-top-pads controller) assoc (inc (* 2 x)) off-color)\n              true))\n          (handle-control-change [_this message]\n            (when (= (:note message) (control-for-top-encoder-note note))\n              (adjust-boolean-value controller message cue v (:id info)))\n            true)\n          (handle-note-on [_this _message]\n            true)\n          (handle-note-off [_this message]\n            (when (= (:note message) note)\n              :done))\n          (handle-aftertouch [_this _message])\n          (handle-pitch-bend [_this message]\n            (cues/set-cue-variable! cue v (true? (>= (value-from-touch-strip message 0 100) 50))\n                                  :show (:show controller) :when-id (:id info))))))))\n\n(defn- build-numeric-adjustment-overlay\n  \"Create an overlay for adjusting a numeric cue parameter. `note`\n  identifies the encoder that was touched to bring up this overlay,\n  `cue` is the cue whose variable is being adjusted, `v` is the map\n  identifying the variable itself, `effect` is the effect which that\n  cue is running, and `info` is the metadata about that effect.\n\n  Also suppresses the ability to scroll through the cue variables\n  while the encoder is being held.\"\n  [controller note cue cue-var _effect info]\n  (let [x (quot note 2)]\n    (if (> (count (:variables cue)) 1)\n      ;; More than one variable, adjust whichever's encoder was touched\n      (reify controllers/IOverlay\n        (captured-controls [_this] #{(control-for-top-encoder-note note) (+ 21 (* 2 x))})\n        (captured-notes [_this] #{note})\n        (adjust-interface [_this _]\n          (when (same-effect-active controller cue (:id info))\n            (let [cur-val (or (cues/get-cue-variable cue cue-var :show (:show controller) :when-id (:id info)) 0)]\n              (if (:centered cue-var)\n                (draw-pan-gauge controller note 1 cur-val :lowest (min cur-val (:min cue-var))\n                                :highest (max cur-val (:max cue-var)) :active-color white-color)\n                (draw-gauge controller note 1 cur-val :lowest (min cur-val (:min cue-var))\n                            :highest (max cur-val (:max cue-var)) :active-color white-color)))\n            (swap! (:next-top-pads controller) assoc (inc (* 2 x)) off-color)\n            (set-touch-strip-from-cue-var controller cue cue-var (:id info))\n            true))\n        (handle-control-change [_this message]\n          (when (= (:note message) (control-for-top-encoder-note note))\n            (adjust-variable-value controller message cue cue-var (:id info)))\n          true)\n        (handle-note-on [_this _message])\n        (handle-note-off [_this _message]\n          :done)\n        (handle-aftertouch [_this _message])\n        (handle-pitch-bend [_this message]\n          (bend-variable-value controller message cue cue-var (:id info))\n          true))\n\n      ;; Just one variable, take full cell, using either encoder,\n      ;; suppress the other one.\n      (let [paired-note (if (odd? note) (dec note) (inc note))]\n        (reify controllers/IOverlay\n          (captured-controls [_this] #{(control-for-top-encoder-note note) (+ 21 (* 2 x))})\n          (captured-notes [_this] #{note paired-note})\n          (adjust-interface [_this _]\n            (when (same-effect-active controller cue (:id info))\n              (let [cur-val (or (cues/get-cue-variable cue cue-var :show (:show controller) :when-id (:id info)) 0)]\n                (if (:centered cue-var)\n                  (draw-pan-gauge controller (* 2 x) 2 cur-val :lowest (min cur-val (:min cue-var))\n                                  :highest (max cur-val (:max cue-var)) :active-color white-color)\n                  (draw-gauge controller (* 2 x) 2 cur-val :lowest (min cur-val (:min cue-var))\n                              :highest (max cur-val (:max cue-var)) :active-color white-color)))\n              (swap! (:next-top-pads controller) assoc (inc (* 2 x)) off-color)\n              (set-touch-strip-from-cue-var controller cue cue-var (:id info))\n              true))\n          (handle-control-change [_this message]\n            (when (= (:note message) (control-for-top-encoder-note note))\n              (adjust-variable-value controller message cue cue-var (:id info)))\n            true)\n          (handle-note-on [_this _message]\n            true)\n          (handle-note-off [_this message]\n            (when (= (:note message) note)\n              :done))\n          (handle-aftertouch [_this _message])\n          (handle-pitch-bend [_this message]\n            (bend-variable-value controller message cue cue-var (:id info))\n            true))))))\n\n(def ^:private color-picker-grid\n  (let [result (transient (vec (repeat 64 nil)))]\n    (doseq [i (range 16)]\n      (let [x (* 4 (quot i 8))\n            y (- 7 (rem i 8))\n            origin (+ x (* 8 y))\n            hue (* 360 (/ i 15))\n            base-color (colors/create-color :hue hue :saturation 100 :lightness 50)]\n        (-> result\n            (assoc! origin base-color)\n            (assoc! (inc origin) (colors/desaturate base-color 25))\n            (assoc! (+ origin 2) (colors/desaturate base-color 50))\n            (assoc! (+ origin 3) (colors/desaturate base-color 75)))))\n    (-> result\n        (assoc! 4 (colors/create-color :h 0 :s 0 :l 100))\n        (assoc! 5 (colors/create-color :h 0 :s 0 :l 50))\n        (assoc! 6 (colors/create-color :h 0 :s 0 :l 0))\n        persistent!)))\n\n(defn- build-color-adjustment-overlay\n  \"Create an overlay for adjusting a color cue parameter. `note`\n  identifies the encoder that was touched to bring up this overlay,\n  `cue` is the cue whose variable is being adjusted, `v` is the map\n  identifying the variable itself, `effect` is the effect which that\n  cue is running, and `info` is the metadata about that effect.\n\n  Also suppresses the ability to scroll through the cue variables\n  while the encoder is being held.\"\n  [controller note cue v _effect info]\n  (let [anchors                   (atom #{note}) ; Track which encoders are keeping the overlay active\n        x                         (quot note 2)\n        effect-id                 (:id info)\n        ;; Take full cell, using both encoders to adjust hue and saturation.\n        [hue-note sat-note]       (if (odd? note) [(dec note) note] [note (inc note)])\n        [hue-control sat-control] (map control-for-top-encoder-note [hue-note sat-note])\n        graphics                  (create-graphics controller)]\n    (reify controllers/IOverlay\n      (captured-controls [_this] #{hue-control sat-control (+ 21 (* 2 x))})\n      (captured-notes [_this] (clojure.set/union #{hue-note sat-note} (set (drop 36 (range 100)))))\n      (adjust-interface [_this _]\n        (when (same-effect-active controller cue (:id info))\n          ;; Draw the color picker grid\n          (reset! (:next-grid-pads controller) color-picker-grid)\n          (let [current-color (or (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id)\n                                  white-color)\n                hue           (colors/hue current-color)\n                sat           (colors/saturation current-color)]\n            ;; Show the preview color at the bottom right\n            (swap! (:next-grid-pads controller) assoc 7 current-color)\n\n            ;; Blink any pad which matches the currently selected color\n            (when (< (rhythm/metro-beat-phase (:metronome (:show controller))) 0.3)\n              (doseq [i (range 64)]\n                (when (and (not= i 7) (colors/color= current-color (get @(:next-grid-pads controller) i)))\n                  (swap! (:next-grid-pads controller) assoc i (if (= i 4)\n                                                                (colors/darken current-color 20)\n                                                                (colors/lighten current-color 20))))))\n\n            ;; Replace the cue's variable value section with a hue and saturation editor.\n            (set-graphics-color graphics off-color)\n            (.fillRect graphics (* x 2 button-cell-width) 0 (* 2 button-cell-width) 100)\n            (draw-encoder-button-label controller (* x 2) 1 \"Hue\" white-color)\n            (draw-cue-variable-value controller (* x 2) 1 (format \"%.1f\" hue) white-color)\n            (draw-encoder-button-label controller (inc (* x 2)) 1 \"Saturation\" white-color)\n            (draw-cue-variable-value controller (inc (* x 2)) 1 (format \"%.1f\" sat) white-color)\n\n            ;; Add a larger color swatch between the gauges\n            (set-graphics-color graphics current-color)\n            (.fillRect graphics (- (* (inc (* x 2)) button-cell-width) 20) 50 40 40)\n\n            ;; Display the hue and saturation gauges\n            (draw-hue-gauge controller (* 2 x) 1 hue (@anchors hue-note))\n            (draw-saturation-gauge controller (inc (* 2 x)) 1 hue sat (@anchors sat-note))\n\n            ;; Put the touch pad into the appropriate state\n            (if (@anchors hue-note)\n              (set-touch-strip-from-value controller hue 0 360 touch-strip-mode-hue)\n              (set-touch-strip-from-value controller sat 0 100 touch-strip-mode-level))\n\n            ;; Darken the cue var scroll button if it was going to be lit\n            (swap! (:next-top-pads controller) assoc (inc (* 2 x)) off-color)\n            true)))\n      (handle-control-change [_this message]\n        ;; Adjust hue or saturation depending on controller; ignore if it was the cue var scroll button\n        (when (#{hue-control sat-control} (:note message))\n          (let [current-color (or (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id)\n                                  white-color)\n                current-color (colors/create-color :h (colors/hue current-color) :s (colors/saturation current-color)\n                                                   :l 50)\n                delta         (* (sign-velocity (:velocity message)) 0.5)]\n            (cues/set-cue-variable! cue v\n                                    (if (= (:note message) hue-control)\n                                      (colors/adjust-hue current-color delta)\n                                      (colors/saturate current-color delta))\n                                    :show (:show controller) :when-id effect-id)))\n        true)\n      (handle-note-on [_this message]\n        (let [note (:note message)]\n          (if (#{hue-note sat-note} note)\n            ;; The user has grabbed another of our controllers, stay active until it is released.\n            (swap! anchors conj note)\n\n            ;; It's a grid pad. Set the color based on the selected note, unless it's the preview pad.\n            (when-not (= note 43)\n              (let [chosen-color (get color-picker-grid (- note 36))]\n                (cues/set-cue-variable! cue v chosen-color :show (:show controller) :when-id effect-id)))))\n        true)\n      (handle-note-off [_this message]\n        (swap! anchors disj (:note message))\n        (when (empty? @anchors)\n          :done))\n      (handle-aftertouch [_this _message])\n      (handle-pitch-bend [_this message]\n        (let [current-color (or (cues/get-cue-variable cue v :show (:show controller) :when-id effect-id)\n                                white-color)\n              fraction      (value-from-touch-strip message 0 1)\n              new-hue       (if (@anchors hue-note) (* fraction 360) (colors/hue current-color))\n              new-sat       (if (@anchors sat-note) (* fraction 100) (colors/saturation current-color))]\n          (cues/set-cue-variable! cue v (colors/create-color :h new-hue :s new-sat :l 50)\n                                  :when-id effect-id))))))\n\n(defn- display-encoder-touched\n  \"One of the eight encoders above the text display was touched.\"\n  [controller note]\n  (let [room (room-for-effects controller)\n        fx-info @(:active-effects (:show controller))\n        fx-meta (:meta fx-info)\n        num-skipped (- (count fx-meta) room @(:effect-offset controller))\n        fx (vec (drop num-skipped (:effects fx-info)))\n        fx-meta (vec (drop num-skipped (:meta fx-info)))\n        offset (- 4 room)\n        x (quot note 2)\n        index (- x offset)\n        var-index (rem note 2)]\n    (when (and (seq fx) (< index (count fx)))\n      (let [effect (get fx index)\n            info (get fx-meta index)\n            cue (:cue info)\n            cue-vars (cue-vars-for-encoders (:variables cue) (get @(:cue-var-offsets controller) (:id info) 0))\n            cue-var (get cue-vars var-index)]\n        (when cue-var\n          (let [cur-val (cues/get-cue-variable cue cue-var :show (:show controller) :when-id (:id info))]\n            (cond\n              (or (number? cur-val) (#{:integer :double} (:type cue-var :double)))\n              (controllers/add-overlay (:overlays controller)\n                                       (build-numeric-adjustment-overlay controller note cue cue-var effect info))\n\n              (or (= (type cur-val) :com.evocomputing.colors/color) (= (:type cue-var) :color))\n              (controllers/add-overlay (:overlays controller)\n                                       (build-color-adjustment-overlay controller note cue cue-var effect info))\n\n              (or (= (type cur-val) Boolean) (= (:type cue-var) :boolean))\n              (controllers/add-overlay (:overlays controller)\n                                       (build-boolean-adjustment-overlay controller note cue cue-var effect info))\n\n              :else  ; Something we don't know how to adjust\n              nil)))))))\n\n(defn- note-on-received\n  \"Process a note-on message which was not handled by an interface\n  overlay.\"\n  [controller message]\n  (let [note (:note message)]\n    (cond (<= 0 note 7)\n          (display-encoder-touched controller note)\n\n          (<= 36 note 99)\n          (cue-grid-pressed controller note (:velocity message))\n\n          :else\n          ;; Some other UI element was touched\n          (case note\n            8 ; Master encoder\n            (master-encoder-touched controller)\n\n            9 ; BPM encoder\n            (bpm-encoder-touched controller)\n\n            10 ; Beat encoder\n            (beat-encoder-touched controller)\n\n            ;; Something we don't care about\n            nil))))\n\n(defn- note-off-received\n  \"Process a note-off message which was not handled by an interface\n  overlay.\"\n  [_controller message]\n  (case (:note message)\n\n    ;; Something we don't care about\n    nil))\n\n(defn- midi-received\n  \"Called whenever a MIDI message is received from the controller\n  while the mapping is active; takes whatever action is appropriate.\"\n  [controller message]\n  (try\n    (when-not (controllers/overlay-handled? (:overlays controller) message)\n      (cond\n        (= (:command message) :control-change)\n        (control-change-received controller message)\n\n        (= (:command message) :note-on)\n        (note-on-received controller message)\n\n        (= (:command message) :note-off)\n        (note-off-received controller message)\n\n        (= 0xf0 (:status message))\n        (sysex-received controller message)))\n    (catch Exception e\n      (timbre/error e \"Problem processing incoming MIDI message:\" message))))\n\n(defn add-custom-control-button\n  \"Activates an otherwise-unused button which responds to a control\n  message, causing it to run custom code when pressed and released.\"\n  [controller button press-fn release-fn]\n  (if-let [button-info (get control-buttons button)]\n    (swap! (:custom-control-buttons controller) assoc (:control button-info)\n           {:key    button\n            :button button-info\n            :press press-fn\n            :release release-fn})\n    (throw (IllegalArgumentException. (str \"Unrecognized control button: \" button)))))\n\n(defn deactivate\n  \"Deactivates a controller interface, killing its update thread and\n  removing its MIDI listeners. If `:disconnected` is passed with a\n  `true` value, it means that the controller has already been removed\n  from the MIDI environment, so no effort will be made to clear its\n  display or take it out of User mode.\n\n  In general you will not need to call this function directly; it will\n  be dispatched to via [[controllers/deactivate]] when that is called\n  with a controller binding implementation from this namespace. It is\n  also called automatically when one of the controllers being used\n  disappears from the MIDI environment.\"\n  [controller & {:keys [disconnected] :or {disconnected false}}]\n  {:pre (= ::controller (type controller))}\n  (swap! (:task controller)\n         (fn [task]\n           (when task  ; We were running. Shut everything down.\n             (at-at/kill task)\n             (show/unregister-grid-controller @(:grid-controller-impl controller))\n             (doseq [f @(:move-listeners controller)] (f @(:grid-controller-impl controller) :deactivated))\n             (reset! (:move-listeners controller) #{})\n             (amidi/remove-device-mapping (:port-in controller) @(:midi-handler controller))\n\n             (when-not disconnected\n               (Thread/sleep 35) ; Give the UI update thread time to shut down\n               (clear-interface controller)\n               (restore-led-palettes controller)\n\n               ;; Leave the User button bright, in case the user has Live\n               ;; running and wants to be able to see how to return to it.\n               (set-button-color controller (:user-mode control-buttons) white-color))\n\n             ;; Regardless of whether it was a clean or abrupt end, shut down the\n             ;; graphical display interface library.\n             (Wayang/close)\n\n             ;; Cancel any UI overlays which were in effect\n             (reset! (:overlays controller) (controllers/create-overlay-state))\n\n             ;; And finally, note that we are no longer active.\n             (controllers/remove-active-binding controller))\n           nil)))\n\n(def port-filter\n  \"Because the Push registers multiple ports with the MIDI\n  environment, we need to be sure to bind only to the User port. This\n  filter is used with [[filter-devices]] to screen out any port that\n  does not seem to be the User port. If port names are assigned\n  differently on your operating system, you may need to change\n  this (and please open a Pull Request); this filter seems to work for\n  Mac OS X and Windows.\"\n  [\"User\" \"MIDIIN2\" \"MIDIOUT2\"])\n\n(defn- recognize\n  \"Returns the controller's device ID if `message` is a response\n  from [[controllers/identify]] which marks it as an Ableton Push 2,\n  and the ports are User ports.\"\n  [message port-in port-out]\n  (when (and (= (take 7 (drop 4 (:data message))) '(0 33 29 103 50 2 0))\n             (= 2 (count (amidi/filter-devices port-filter [port-in port-out]))))\n    (int (aget (:data message) 1))))\n\n;; Register our recognition function and rich binding with the\n;; controller manager.\n(swap! controllers/recognizers assoc ::controller recognize)\n\n(defmethod controllers/deactivate ::controller\n  [controller & {:keys [disconnected] :or {disconnected false}}]\n  (deactivate controller :disconnected disconnected))\n\n(defmethod controllers/bind-to-show-impl ::controller\n  [_kind show port-in port-out device & {:keys [refresh-interval display-name]\n                                         :or   {refresh-interval (/ 1000 20)\n                                                display-name     \"Ableton Push 2\"}}]\n  {:pre [(some? show)]}\n  (load-fonts)\n  (let [modes (atom #{})\n        controller\n        (with-meta\n          {:display-name           display-name\n           :device-id              device\n           :show                   show\n           :origin                 (atom [0 0])\n           :effect-offset          (atom 0)\n           :cue-var-offsets        (atom {})\n           :refresh-interval       refresh-interval\n           :port-in                port-in\n           :port-out               port-out\n           :task                   (atom nil)\n           :led-palettes           (atom {})\n           :display-buffer         (Wayang/open)\n           :last-text-buttons      (atom {})\n           :next-text-buttons      (atom {})\n           :last-top-pads          (atom empty-top-pads)\n           :next-top-pads          (atom empty-top-pads)\n           :last-grid-pads         (atom empty-grid-pads)\n           :next-grid-pads         (atom empty-grid-pads)\n           :metronome-mode         (atom {})\n           :last-marker            (atom nil)\n           :modes                  modes\n           :last-touch-strip       (atom nil)\n           :next-touch-strip       (atom nil)\n           :midi-handler           (atom nil)\n           :tempo-tap-handler      (tempo/create-show-tempo-tap-handler\n                                    show :shift-fn (fn [] (get @modes (get-in control-buttons [:shift :control]))))\n           :overlays               (controllers/create-overlay-state)\n           :custom-control-buttons (atom {})\n           :move-listeners         (atom #{})\n           :grid-controller-impl   (atom nil)}\n          {:type ::controller})]\n    (when (gather-led-palettes controller)\n      (reset! (:midi-handler controller) (partial midi-received controller))\n      (reset! (:grid-controller-impl controller)\n              (reify controllers/IGridController\n                (display-name [_this] (:display-name controller))\n                (controller [_this] controller)\n                (physical-height [_this] 8)\n                (physical-width [_this] 8)\n                (current-bottom [_this] (@(:origin controller) 1))\n                (current-bottom [_this y] (move-origin controller (assoc @(:origin controller) 1 y)))\n                (current-left [_this] (@(:origin controller) 0))\n                (current-left [_this x] (move-origin controller (assoc @(:origin controller) 0 x)))\n                (add-move-listener [_this f] (swap! (:move-listeners controller) conj f))\n                (remove-move-listener [_this f] (swap! (:move-listeners controller) disj f))))\n\n      ;; Set controller in User mode\n      (send-sysex controller [0x0a 1])\n\n      ;; Put pads in aftertouch (poly) pressure mode\n      (send-sysex controller [0x1e 1])\n\n      ;; TODO: Set pad sensitivity level to avoid stuck pads? May not be necessary with Push 2\n\n      (clear-interface controller)\n      (welcome-animation controller)\n      (controllers/add-active-binding controller)\n      (show/register-grid-controller @(:grid-controller-impl controller))\n      (amidi/add-disconnected-device-handler! port-in #(deactivate controller :disconnected true))\n      controller)))\n\n(defn record-interface\n  \"Capture an animated GIF of the display for documentation purposes.\n  Takes a filename to which the animation should be written. Returns a\n  function which you must call to end the recording and close the\n  file. Defaults to creating an animation which loops, but you can\n  override that by passing `false` with the optional keyword argument\n  `:loop`.\"\n  [controller path & {:keys [loop] :or {loop true}}]\n  (let [output (javax.imageio.stream.FileImageOutputStream. (io/file path))\n        writer (org.deepsymmetry.GifSequenceWriter. output (:display-buffer controller)\n                                                    (int (:refresh-interval controller)) loop)\n        running (atom true)]\n    (controllers/add-overlay (:overlays controller)\n                             (reify controllers/IOverlay\n                               (captured-controls [_this] #{})\n                               (captured-notes [_this] #{})\n                               (adjust-interface [_this _snapshot]\n                                 (when @running\n                                   (.writeToSequence writer (:display-buffer controller))\n                                   true))\n                               (handle-control-change [_this _message])\n                               (handle-note-on [_this  _message])\n                               (handle-note-off [_this _message])\n                               (handle-aftertouch [_this _message])\n                               (handle-pitch-bend [_this _message]))\n                             :priority 1000000)  ; Make sure we run last, so we can capture what each overlay drew\n    (fn []\n      (when @running\n        (reset! running false)         ; Shut down the overlay\n        (Thread/sleep 100)  ; Give any last rendering a chance to finish\n        (.close writer)\n        (.close output)\n        (str path \" written.\")))))\n"
  },
  {
    "path": "src/afterglow/controllers/color.clj",
    "content": "(ns afterglow.controllers.color\n  \"Provides support for adjusting components of a show variable\n  containing a color using any MIDI controller.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.controllers :as controllers]\n            [afterglow.midi :as amidi]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [*show* with-show]]\n            [com.evocomputing.colors :as colors]\n            [taoensso.timbre :as timbre]\n            [taoensso.truss :as truss :refer (have have! have?)]))\n\n(defn add-midi-control-to-color-mapping\n  \"Cause specified `component` of the color value stored in the\n  specified `variable` in [[*show*]] to be updated by any MIDI\n  controller-change messages from the specified device sent on the\n  specified `channel` and `control-number`.\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\n\n  The values you can pass for `component` include `:red`, `:green`,\n  `:blue`, `:hue`, `:saturation`, and `:lightness`. \n\n  As control changes come in, they will be mapped from the MIDI\n  range (of `0` to `127`) to the legal range for the chosen color\n  component. If `:min` and/or `:max` are specified, the values will be\n  scaled to the supplied range instead, but will still be clamped to\n  fit within legal values for the chosen color component (RGB values\n  can range from `0` to `255`, hues from `0` to `360`, and saturation\n  and lightness from `0` to `100`).\n\n  If `:transform-fn` is specified, it will be called with the scaled\n  color component value, and its return value will be assigned to the\n  color, although once again the value will be clamped to within the\n  legal range for the component.\n\n  Returns a MIDI mapping function, which can be passed\n  to [[remove-control-mapping]] if you later want to stop the\n  MIDI control affecting the color variable.\"\n  [device-filter channel control-number variable component & {:keys [min max transform-fn]}]\n  {:pre [(have? some? device-filter) (have? integer? channel) (have? #(<= 0 % 15) channel)\n         (have? integer? control-number) (have? #(<= 0 % 127) control-number)\n         (have? some? variable) (have? #(= (type (show/get-variable %)) :com.evocomputing.colors/color) variable)\n         (have? #{:red :green :blue :hue :saturation :lightness} component)\n         (have? #(or (not %) (number? %)) max) (have? #(or (not %) (number? %)) min)\n         (have? #(or (not %) (ifn? %)) transform-fn)]}\n  (let [min (or min 0)\n        max (or max (case component\n                      (:red :green :blue) 255\n                      :hue 360\n                      (:saturation :lightness) 100))\n        show *show*  ; Bind so we can pass it to update function running on another thread\n        scale-fn (if (< min max)\n                   (let [range (- max min)]\n                     (fn [midi-val] (double (+ min (/ (* midi-val range) 127)))))\n                   (let [range (- min max)]\n                     (fn [midi-val] (double (+ max (/ (* midi-val range) 127))))))\n        calc-fn (apply comp (filter identity [transform-fn scale-fn]))\n        update-fn (fn [msg]\n                    (with-show show\n                      (let [color (show/get-variable variable)\n                            rgb {:r (colors/red color) :g (colors/green color) :b (colors/blue color)}\n                            hsl {:h (colors/hue color) :s (colors/saturation color) :l (colors/lightness color)}\n                            value (calc-fn (:velocity msg))]\n                        (show/set-variable! variable\n                                            (case component\n                                              :red (colors/create-color\n                                                    (merge rgb {:r (colors/clamp-rgb-int (Math/round value))}))\n                                              :green (colors/create-color\n                                                      (merge rgb {:g (colors/clamp-rgb-int (Math/round value))}))\n                                              :blue (colors/create-color\n                                                     (merge rgb {:b (colors/clamp-rgb-int (Math/round value))}))\n                                              :hue (colors/create-color (merge hsl {:h (colors/clamp-hue value)}))\n                                              :saturation (colors/create-color\n                                                           (merge hsl {:s (colors/clamp-percent-float value)}))\n                                              :lightness (colors/create-color\n                                                          (merge hsl {:l (colors/clamp-percent-float value)})))))))]\n    (amidi/add-control-mapping device-filter channel control-number update-fn)\n    update-fn))\n"
  },
  {
    "path": "src/afterglow/controllers/launchpad_mini.clj",
    "content": "(ns afterglow.controllers.launchpad-mini\n  \"Allows the Novation Launchpad Mini and Launchpad S to be used as\n  control surfaces for Afterglow.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.controllers :as controllers]\n            [afterglow.controllers.tempo :as tempo]\n            [afterglow.midi :as amidi]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [with-show]]\n            [overtone.at-at :as at-at]\n            [overtone.midi :as midi]\n            [taoensso.timbre :as timbre :refer [warn]]\n            [taoensso.truss :as truss :refer [have have! have?]]))\n\n(def control-buttons\n  \"The round buttons along the top which send and respond to Control\n  Change events.\"\n  {:up-arrow    104\n   :down-arrow  105\n   :left-arrow  106\n   :right-arrow 107\n   :session     108\n   :user-1      109\n   :user-2      110\n   :mixer       111})\n\n(def note-buttons\n  \"The round buttons along the right which send and respond to Note\n  events.\"\n  {:volume     8  ; Used as tap tempo\n   :pan        24\n   :send-a     40\n   :send-b     56\n   :stop       72\n   :track-on   88\n   :solo       104\n   :record-arm 120})  ; Used as shift\n\n(def button-off-color\n  \"The color of buttons that are completely off.\"\n  0x0c)\n\n(def button-dimmed-color\n  \"The color of buttons that can be pressed but are in conflict or\n  otherwise backgrounded.\"\n  0x1d)\n\n(def button-available-color\n  \"The color of buttons that can be pressed but haven't yet been.\"\n  0x2e)\n\n(def button-active-color\n  \"The color of an available button that is currently being pressed.\"\n  0x3f)\n\n(def stop-available-color\n  \"The color of the Stop button when not active.\"\n  0x0d)\n\n(def stop-active-color\n  \"The color of the Stop button when active.\"\n  0x0f)\n\n(def shift-available-color\n  \"The color of the Shift button when not active.\"\n  0x2d)\n\n(def shift-active-color\n  \"The color of the Shift button when active.\"\n  0x3e)\n\n(def tempo-unsynced-beat-color\n  \"The color of the tap tempo button when synchronization is off and a\n  beat is taking place.\"\n  0x3e)\n\n(def tempo-unsynced-off-beat-color\n  \"The color of the tap tempo button when synchronization is off and a\n  beat is not taking place.\"\n  0x1d)\n\n(def tempo-synced-beat-color\n  \"The color of the tap tempo button when the metronome is\n  synchronzied and a beat is taking place.\"\n  0x3c)\n\n(def tempo-synced-off-beat-color\n  \"The color of the tap tempo button when the metronome is\n  synchronized and a beat is not taking place.\"\n  0x1c)\n\n(def cue-held-color\n  \"The color to light up a pad when a cue runs only as long as it is\n  held.\"\n  0x3f)\n\n(def cue-running-color\n  \"The color to light up a pad when it is running a cue.\"\n  0x3c)\n\n(defn set-pad-color\n  \"Set one of the 64 grid pads to one of the color values specified\n  above.\"\n  [controller x y color]\n  (midi/midi-note-on (:port-out controller) (+ x (- 112 (* y 16))) color))\n\n(defn set-control-button-color\n  \"Set one of the top row of control buttons to one of the color\n  values specified above.\"\n  [controller button color]\n  (midi/midi-control (:port-out controller) button color))\n\n(defn set-note-button-color\n  \"Set one of the right hand row of note buttons to one of the color\n  values specified above.\"\n  [controller button color]\n  (midi/midi-note-on (:port-out controller) button color))\n\n(defn- move-origin\n  \"Changes the origin of the controller, notifying any registered\n  listeners.\"\n  [controller origin]\n  (when (not= origin @(:origin controller))\n    (reset! (:origin controller) origin)\n    (doseq [f @(:move-listeners controller)] (f @(:grid-controller-impl controller) :moved))))\n\n(defn show-round-buttons\n  \"Illuminates all round buttons.\"\n  ([controller]\n   (show-round-buttons controller button-available-color))\n  ([controller color]\n   (doseq [[_ button] control-buttons]\n     (set-control-button-color controller button color))\n   (doseq [[_ button] note-buttons]\n     (set-note-button-color controller button color))))\n\n(defn clear-interface\n  \"Clears all illuminated buttons and pads.\"\n  [controller]\n  (midi/midi-control (:port-out controller) 0 0)\n  (midi/midi-control (:port-out controller) 0 1)\n  (reset! (:last-grid-pads controller) nil)  ; Note that no buttons are lit\n  (reset! (:last-control-buttons controller) {})\n  (reset! (:last-note-buttons controller) {}))\n\n(defn- update-round-buttons\n  \"Sees if any round buttons have changed state since the last time\n  the interface was updated, and if so, sends the necessary MIDI\n  commands to update them on the Launchpad Mini.\"\n  [controller]\n  ;; First turn off any which were on before but no longer are\n  (doseq [[button old-color] @(:last-control-buttons controller)]\n    (when-not (get @(:next-control-buttons controller) button)\n      (set-control-button-color controller button button-off-color)))\n  (doseq [[button old-color] @(:last-note-buttons controller)]\n    (when-not (get @(:next-note-buttons controller) button)\n      (set-note-button-color controller button button-off-color)))\n\n  ;; Then, light any currently active buttons\n  (doseq [[button color] @(:next-control-buttons controller)]\n    (when-not (= (get @(:last-control-buttons controller) button) color)\n      (set-control-button-color controller button color)))\n  (doseq [[button color] @(:next-note-buttons controller)]\n    (when-not (= (get @(:last-note-buttons controller) button) color)\n      (set-note-button-color controller button color)))\n\n  ;; And record the new state for next time\n  (reset! (:last-control-buttons controller) @(:next-control-buttons controller))\n  (reset! (:last-note-buttons controller) @(:next-note-buttons controller)))\n\n(defn- render-cue-grid\n  \"Figure out how the cue grid pads should be illuminated, based on\n  the currently active cues and a metronome snapshot identifying the\n  point in musical time at which the interface is being rendered.\n  Returns a vector of the rows, from bottom to top. Each row is a\n  vector of the colors in that row, from left to right.\"\n  [controller snapshot]\n  (let [[origin-x origin-y] @(:origin controller)\n        active-keys (show/active-effect-keys (:show controller))]\n    (vec (for [y (range 8)]\n           (vec (for [x (range 8)]\n                  (let [[cue active] (show/find-cue-grid-active-effect (:show controller) (+ x origin-x) (+ y origin-y))\n                        ending (and active (:ending active))\n                        color (when cue (if active\n                                          (if ending\n                                            (if (> (rhythm/snapshot-beat-phase snapshot) 0.4)\n                                              stop-available-color\n                                              stop-active-color)\n                                            cue-running-color)\n                                          (if (or (active-keys (:key cue))\n                                                  (seq (clojure.set/intersection active-keys (set (:end-keys cue)))))\n                                            button-dimmed-color button-available-color)))]\n                    (or color button-off-color))))))))\n\n(defn- update-cue-grid\n  \"Set the colors of all the cue grid pads, based on the currently\n  active cues and overlays.\"\n  [controller]\n  (doseq [x (range 8)  ; Send the changes only, individually\n              y (range 8)]\n        (let [color (get-in @(:next-grid-pads controller) [y x])]\n          (when-not (= (get-in @(:last-grid-pads controller) [y x]) color)\n            (set-pad-color controller x y color)))))\n\n(defn- update-scroll-arrows\n  \"Activate the arrow buttons for directions in which scrolling is\n  possible.\"\n  [controller]\n  (let [[origin-x origin-y] @(:origin controller)]\n    (when (pos? origin-x)\n      (swap! (:next-control-buttons controller) assoc (:left-arrow control-buttons) button-available-color))\n    (when (pos? origin-y)\n      (swap! (:next-control-buttons controller) assoc (:down-arrow control-buttons) button-available-color))\n    (when (> (- (controllers/grid-width (:cue-grid (:show controller))) origin-x) 7)\n      (swap! (:next-control-buttons controller) assoc (:right-arrow control-buttons) button-available-color))\n    (when (> (- (controllers/grid-height (:cue-grid (:show controller))) origin-y) 7)\n      (swap! (:next-control-buttons controller) assoc (:up-arrow control-buttons) button-available-color))))\n\n(defn add-button-held-feedback-overlay\n  \"Adds a simple overlay which keeps a control button bright as long\n  as the user is holding it down.\"\n  ([controller button]\n   (add-button-held-feedback-overlay controller button button-active-color))\n  ([controller button color]\n   (controllers/add-control-held-feedback-overlay (:overlays controller) button\n                                                  (fn [_] (swap! (:next-control-buttons controller)\n                                                                 assoc button color)))))\n\n(defn- enter-stop-mode\n  \"The user has asked to stop the show. Suspend its update task\n  and black it out until the stop button is pressed again.\"\n  [controller & {:keys [already-stopped]}]\n\n  (reset! (:stop-mode controller) true)\n  (when-not already-stopped\n    (with-show (:show controller)\n      (show/stop!)\n      (Thread/sleep (:refresh-interval (:show controller)))\n      (show/blackout-show)))\n\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [this] #{})\n                             (captured-notes [this] #{(:stop note-buttons)})\n                             (adjust-interface [this _]\n                               (swap! (:next-note-buttons controller)\n                                      assoc (:stop note-buttons) stop-active-color)\n                               (with-show (:show controller)\n                                 (when (show/running?)\n                                   (reset! (:stop-mode controller) false))\n                                 @(:stop-mode controller)))\n                             (handle-control-change [this message])\n                             (handle-note-on [this message]\n                               (when (pos? (:velocity message))\n                                 ;; End stop mode\n                                 (with-show (:show controller)\n                                   (show/start!))\n                                 (reset! (:stop-mode controller) false)\n                                 :done))\n                             (handle-note-off [this message])\n                             (handle-aftertouch [this message])\n                             (handle-pitch-bend [this message]))))\n\n(defn- new-beat?\n  \"Returns true if the metronome is reporting a different marker\n  position than the last time this function was called.\"\n  [controller marker]\n  (when (not= marker @(:last-marker controller))\n    (reset! (:last-marker controller) marker)))\n\n(defn- metronome-sync-colors\n  \"Determine the colors to light the tap tempo button. Returns a tuple\n  of the off-beat and on-beat colors based on the current sync\n  status.\"\n  [controller]\n  (with-show (:show controller)\n    (if (= (:type (show/sync-status)) :manual)\n      [tempo-unsynced-off-beat-color tempo-unsynced-beat-color]\n      (if (:current (show/sync-status))\n        [tempo-synced-off-beat-color tempo-synced-beat-color]\n        [stop-available-color stop-active-color]))))\n\n(defn- update-interface\n  \"Determine the desired current state of the interface, and send any\n  changes needed to get it to that state.\"\n  [controller]\n  (try\n    ;; Assume we are starting out with a blank interface.\n    (reset! (:next-control-buttons controller) {})\n    (reset! (:next-note-buttons controller) {})\n\n    ;; If the show has stopped without us noticing, enter stop mode\n    (with-show (:show controller)\n      (when-not (or (show/running?) @(:stop-mode controller))\n        (enter-stop-mode controller :already-stopped true)))\n\n    ;; Reflect the shift button state\n    (swap! (:next-note-buttons controller)\n           assoc (:record-arm note-buttons)\n           (if @(:shift-mode controller) shift-active-color shift-available-color))\n\n    (update-scroll-arrows controller)\n\n    ;; Flash the tap tempo button on beats\n    (let [snapshot (rhythm/metro-snapshot (get-in controller [:show :metronome]))\n          marker (rhythm/snapshot-marker snapshot)\n          colors (metronome-sync-colors controller)]\n      (swap! (:next-note-buttons controller)\n             assoc (:volume note-buttons)\n             (if (or (new-beat? controller marker) (< (rhythm/snapshot-beat-phase snapshot) 0.15))\n               (second colors) (first colors)))\n\n      ;; Make the User 2 button bright, since we live in that layout\n      (swap! (:next-control-buttons controller)\n             assoc (:user-2 control-buttons) button-active-color)\n\n      ;; Make the stop button visible, since we support it\n      (swap! (:next-note-buttons controller)\n             assoc (:stop note-buttons)\n             stop-available-color)\n\n      (reset! (:next-grid-pads controller) (render-cue-grid controller snapshot))\n\n      ;; Add any contributions from interface overlays, removing them\n      ;; if they report being finished.\n      (controllers/run-overlays (:overlays controller) snapshot))\n\n    (update-cue-grid controller)\n    (update-round-buttons controller)\n\n    (catch Throwable t\n      (warn t \"Problem updating Launchpad Mini/S Interface\"))))\n\n\n(defn- leave-user-mode\n  \"The user has asked to exit user mode, so suspend our display\n  updates, and prepare to restore our state when user mode is pressed\n  again.\"\n  [controller]\n  (swap! (:task controller) (fn [task]\n                              (when task (at-at/kill task))\n                              nil))\n  (clear-interface controller)\n  ;; In case Live isn't running, leave the User 2 button dimly lit, to help the user return.\n  (midi/midi-control (:port-out controller) (:user-2 control-buttons) button-available-color)\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [this] #{(:user-2 control-buttons)})\n                             (captured-notes [this] #{})\n                             (adjust-interface [this _]\n                               true)\n                             (handle-control-change [this message]\n                               (when (pos? (:velocity message))\n                                 ;; We are returning to user mode, restore display\n                                 (clear-interface controller)\n                                 (reset! (:task controller) (at-at/every (:refresh-interval controller)\n                                                                         #(update-interface controller)\n                                                                         controllers/pool\n                                                                         :initial-delay 250\n                                                                         :desc \"Launchpad Mini/S interface update\"))\n                                 :done))\n                             (handle-note-on [this message])\n                             (handle-note-off [this message])\n                             (handle-aftertouch [this message])\n                             (handle-pitch-bend [this message]))))\n\n(defn- control-change-received\n  \"Process a control change message which was not handled by an\n  interface overlay.\"\n  [controller message]\n  (case (:note message)\n    106 ; Left arrow\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)]\n        (when (pos? x)\n          (move-origin controller [(if @(:shift-mode controller) 0 (max 0 (- x 8))) y])\n          (add-button-held-feedback-overlay controller (:left-arrow control-buttons)))))\n\n    107 ; Right arrow\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)\n            width (max (controllers/grid-width (:cue-grid (:show controller))) 1)]\n        (when (> (- (controllers/grid-width (:cue-grid (:show controller))) x) 7)\n          (move-origin controller [(if @(:shift-mode controller) (* 8 (quot (dec width) 8)) (+ x 8)) y])\n          (add-button-held-feedback-overlay controller (:right-arrow control-buttons)))))\n\n    104 ; Up arrow\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)\n            height (max (controllers/grid-height (:cue-grid (:show controller))) 1)]\n        (when (> (- (controllers/grid-height (:cue-grid (:show controller))) y) 7)\n          (move-origin controller [x (if @(:shift-mode controller) (* 8 (quot (dec height) 8)) (+ y 8))])\n          (add-button-held-feedback-overlay controller (:up-arrow control-buttons)))))\n\n    105 ; Down arrow\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)]\n        (when (pos? y)\n          (move-origin controller [x (max 0 (if @(:shift-mode controller) 0 (max 0 (- y 8))))])\n          (add-button-held-feedback-overlay controller (:down-arrow control-buttons)))))\n\n    110 ; User 2 button\n    (when (pos? (:velocity message))\n      (leave-user-mode controller))\n\n    ;; Something we don't care about\n    nil))\n\n(defn- note-to-cue-coordinates\n  \"Translate the MIDI note associated with an incoming message to its\n  coordinates in the show cue grid.\"\n  [controller note]\n  (let [[origin-x origin-y] @(:origin controller)\n        pad-x (rem note 16)\n        pad-y (- 7 (quot note 16))\n        cue-x (+ origin-x pad-x)\n        cue-y (+ origin-y pad-y)]\n    [cue-x cue-y pad-x pad-y]))\n\n;; TODO: Add a way for user to configure default virtual velocity for whole grid and individual cells.\n(defn- cue-grid-pressed\n  \"One of the pads in the 8x8 cue grid was pressed.\"\n  [controller note]\n  (let [[cue-x cue-y pad-x pad-y] (note-to-cue-coordinates controller note)\n        [cue active] (show/find-cue-grid-active-effect (:show controller) cue-x cue-y)]\n          (when cue\n            (with-show (:show controller)\n              (if (and active (not (:held cue)))\n                (show/end-effect! (:key cue))\n                (let [id (show/add-effect-from-cue-grid! cue-x cue-y)\n                      holding (and (:held cue) (not @(:shift-mode controller)))]\n                  (controllers/add-overlay\n                   (:overlays controller)\n                   (reify controllers/IOverlay\n                     (captured-controls [this] #{})\n                     (captured-notes [this] #{note})\n                     (adjust-interface [this snapshot]\n                       (when holding\n                         (swap! (:next-grid-pads controller) assoc-in [cue-y cue-x] cue-held-color))\n                       true)\n                     (handle-control-change [this message])\n                     (handle-note-on [this message])\n                     (handle-note-off [this message]\n                       (when holding\n                         (with-show (:show controller)\n                           (show/end-effect! (:key cue) :when-id id)))\n                       :done)\n                     (handle-aftertouch [this message])\n                     (handle-pitch-bend [this message])))))))))\n\n(defn- note-on-received\n  \"Process a note-on message which was not handled by an interface\n  overlay.\"\n  [controller message]\n  (let [note (:note message)]\n    (if (and (<= (rem note 16) 7) (<= 0 (quot note 16) 7))\n      (cue-grid-pressed controller note)\n      (case note\n        8  ; Tap tempo button\n        (when (pos? (:velocity message))\n          ((:tempo-tap-handler controller)))\n\n        72  ; Stop button\n        (when (pos? (:velocity message))\n          (enter-stop-mode controller))\n\n        120  ; Record Arm (shift) button\n        (reset! (:shift-mode controller) (pos? (:velocity message)))\n\n        ;; Something we don't care about\n        nil))))\n\n(defn- note-off-received\n  \"Process a note-off message which was not handled by an interface\n  overlay.\"\n  [controller message]\n  (case (:note message)\n\n    120  ; Record Arm (shift) button\n    (reset! (:shift-mode controller) false)\n\n    ;; Something we don't care about\n    nil))\n\n(defn- midi-received\n  \"Called whenever a MIDI message is received from the controller\n  while the mapping is active; takes whatever action is appropriate.\"\n  [controller message]\n  ;;(timbre/info message)\n  (when-not (controllers/overlay-handled? (:overlays controller) message)\n    (when (= (:command message) :control-change)\n      (control-change-received controller message))\n    (when (= (:command message) :note-on)\n      (note-on-received controller message))\n    (when (= (:command message) :note-off)\n      (note-off-received controller message))))\n\n(defn- start-interface\n  \"Set up the thread which keeps the user interface up to date.\"\n  [controller]\n  (clear-interface controller)\n  (amidi/add-device-mapping (:port-in controller) @(:midi-handler controller))\n  (reset! (:task controller) (at-at/every (:refresh-interval controller)\n                                          #(update-interface controller)\n                                          controllers/pool\n                                          :initial-delay 10\n                                          :desc \"Launchpad Mini/S interface update\")))\n\n(defn- welcome-frame\n  \"Render a frame of the welcome animation, or if it is done, start\n  the main interface update thread, and terminate the task running the\n  animation.\"\n  [controller counter task]\n  (let [gradient [0x3c 0x3e 0x3f 0x2f 0x1f 0x0f 0x0e 0x0d]]\n    (try\n      (cond\n        (< @counter 8)\n        (doseq [y (range 0 (inc @counter))]\n          (let [color (gradient (- @counter y))]\n            (set-pad-color controller 3 y color)\n            (set-pad-color controller 4 y color)))\n\n        (< @counter 12)\n        (doseq [x (range 0 (- @counter 7))\n                y (range 0 8)]\n          (let [color (gradient (- @counter 8 x))]\n            (set-pad-color controller (- 3 x) y color)\n            (set-pad-color controller (+ 4 x) y color)))\n\n        (= @counter 12)\n        (show-round-buttons controller 0x3e)\n\n        (< @counter 20)\n        nil  ; Just stall\n\n        (= @counter 20)\n        (show-round-buttons controller 0x1f)\n\n        (< @counter 29)\n        (doseq [x (range 0 8)]\n          (set-pad-color controller x (- 28 @counter) button-off-color))\n\n        :else\n        (do\n          (start-interface controller)\n          (at-at/kill @task)))\n      (catch Throwable t\n        (warn t \"Animation frame failed\"))))\n\n  (swap! counter inc))\n\n(defn- welcome-animation\n  \"Provide a fun animation to make it clear the Launchpad Mini/S is\n  online.\"\n  [controller]\n  (let [counter (atom 0)\n        task (atom nil)]\n    (reset! task (at-at/every 50 #(welcome-frame controller counter task)\n                              controllers/pool))))\n\n(defn deactivate\n  \"Deactivates a controller interface, killing its update thread and\n  removing its MIDI listeners. If `:disconnected` is passed with a\n  `true` value, it means that the controller has already been removed\n  from the MIDI environment, so no effort will be made to clear its\n  display or take it out of User mode.\n\n  In general you will not need to call this function directly; it will\n  be dispatched to via [[controllers/deactivate]] when that is called\n  with a controller binding implementation from this namespace. It is\n  also called automatically when one of the controllers being used\n  disappears from the MIDI environment.\"\n  [controller & {:keys [disconnected] :or {disconnected false}}]\n  {:pre (= ::controller (type controller))}\n  (swap! (:task controller)\n         (fn [task]\n           (when task\n             (at-at/kill task)\n             (show/unregister-grid-controller @(:grid-controller-impl controller))\n             (doseq [f @(:move-listeners controller)] (f @(:grid-controller-impl controller) :deactivated))\n             (reset! (:move-listeners controller) #{})\n             (amidi/remove-device-mapping (:port-in controller) @(:midi-handler controller))\n\n             (when-not disconnected\n               (Thread/sleep 35) ; Give the UI update thread time to shut down\n               (clear-interface controller)\n\n               ;; Leave the User button bright, in case the user has Live\n               ;; running and wants to be able to see how to return to it.\n               (set-control-button-color controller (:user-2 control-buttons) button-available-color))\n\n             ;; Cancel any UI overlays which were in effect\n             (reset! (:overlays controller) (controllers/create-overlay-state))\n\n             ;; And finally, note that we are no longer active.\n             (controllers/remove-active-binding controller))\n           nil)))\n\n(defn- recognize\n  \"Returns a tuple of the controller's device ID and model name if\n  `message` is a response from [[controllers/identify]] which marks it\n  as a Novation Launchpad Mini or S.\"\n  [message _ _]\n  (let [ident (take 5 (drop 4 (:data message)))\n        device (int (aget (:data message) 1))]\n    (cond (= ident '(0 32 41 54 0))\n          [device \"Launchpad Mini\"]\n\n          (= ident '(0 32 41 32 0))\n          [device \"Launchpad S\"])))\n\n;; Register our recognition function and rich binding with the\n;; controller manager.\n(swap! controllers/recognizers assoc ::controller recognize)\n\n(defmethod controllers/deactivate ::controller\n  [controller & {:keys [disconnected] :or {disconnected false}}]\n  (deactivate controller :disconnected disconnected))\n\n(defmethod controllers/bind-to-show-impl ::controller\n  [kind show port-in port-out [device model] & {:keys [refresh-interval display-name new-connection]\n                                                :or   {refresh-interval (/ 1000 15)}}]\n  {:pre [(have? some? show)]}\n  (let [shift-mode (atom false)\n        controller\n        (with-meta\n          {:display-name         (or display-name model)\n           :model                model\n           :device-id            device\n           :show                 show\n           :origin               (atom [0 0])\n           :refresh-interval     refresh-interval\n           :port-in              port-in\n           :port-out             port-out\n           :task                 (atom nil)\n           :last-control-buttons (atom {})\n           :next-control-buttons (atom {})\n           :last-note-buttons    (atom {})\n           :next-note-buttons    (atom {})\n           :last-grid-pads       (atom nil)\n           :next-grid-pads       (atom nil)\n           :shift-mode           shift-mode\n           :stop-mode            (atom false)\n           :midi-handler         (atom nil)\n           :tempo-tap-handler    (tempo/create-show-tempo-tap-handler show :shift-fn (fn [] @shift-mode))\n           :last-marker          (atom nil)\n           :overlays             (controllers/create-overlay-state)\n           :move-listeners       (atom #{})\n           :grid-controller-impl (atom nil)}\n          {:type ::controller})]\n    (reset! (:midi-handler controller) (partial midi-received controller))\n    (reset! (:grid-controller-impl controller)\n            (reify controllers/IGridController\n              (display-name [_this] (:display-name controller))\n              (controller [_this] controller)\n              (physical-height [_this] 8)\n              (physical-width [_this] 8)\n              (current-bottom [_this] (@(:origin controller) 1))\n              (current-bottom [_this y] (move-origin controller (assoc @(:origin controller) 1 y)))\n              (current-left [_this] (@(:origin controller) 0))\n              (current-left [_this x] (move-origin controller (assoc @(:origin controller) 0 x)))\n              (add-move-listener [_this f] (swap! (:move-listeners controller) conj f))\n              (remove-move-listener [_this f] (swap! (:move-listeners controller) disj f))))\n    (if new-connection\n      (at-at/after 3000 (fn []\n                          (clear-interface controller)\n                          (start-interface controller)) controllers/pool :desc \"Start Launchpad Mini/S interface\")\n      (do\n        (clear-interface controller)\n        (welcome-animation controller)))\n    (controllers/add-active-binding controller)\n    (show/register-grid-controller @(:grid-controller-impl controller))\n    (amidi/add-disconnected-device-handler! port-in #(deactivate controller :disconnected true))\n    controller))\n"
  },
  {
    "path": "src/afterglow/controllers/launchpad_mk2.clj",
    "content": "(ns afterglow.controllers.launchpad-mk2\n    \"Allows the Novation Launchpad Mk2 to be used as a control surface\n  for Afterglow.\" {:author \"James Elliott\"}\n  (:require [afterglow.controllers :as controllers]\n            [afterglow.controllers.tempo :as tempo]\n            [afterglow.effects.cues :as cues]\n            [afterglow.midi :as amidi]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [with-show]]\n            [afterglow.util :as util]\n            [clojure.math.numeric-tower :as math]\n            [com.evocomputing.colors :as colors]\n            [overtone.at-at :as at-at]\n            [overtone.midi :as midi]\n            [taoensso.timbre :as timbre :refer [warn]]\n            [taoensso.truss :as truss :refer [have have! have?]]))\n\n(def control-buttons\n  \"The round buttons along the top which send and respond to Control\n  Change events.\"\n  {:up-arrow    104\n   :down-arrow  105\n   :left-arrow  106\n   :right-arrow 107\n   :session     108\n   :user-1      109\n   :user-2      110\n   :mixer       111})\n\n(def note-buttons\n  \"The round buttons along the right which send and respond to Note\n  events.\"\n  {:volume     89  ; Used as tap tempo\n   :pan        79\n   :send-a     69\n   :send-b     59\n   :stop       49\n   :mute       39\n   :solo       29\n   :record-arm 19})  ; Used as shift\n\n(def button-off-color\n  \"The color of buttons that are completely off.\"\n  (colors/create-color :black))\n\n(def button-available-color\n  \"The color of buttons that can be pressed but haven't yet been.\"\n  (colors/darken (colors/create-color :orange) 45))\n\n(def button-active-color\n  \"The color of an available button that is currently being pressed.\"\n  (colors/create-color :yellow))\n\n(def stop-available-color\n  \"The color of the Stop button when not active.\"\n  (colors/darken (colors/create-color :red) 45))\n\n(def stop-active-color\n  \"The color of the stop button when active.\"\n  (colors/create-color :red))\n\n(def tempo-unsynced-beat-color\n  \"The color of the tap tempo button when synchronization is off and a\n  beat is taking place.\"\n  (colors/create-color :blue))\n\n(def tempo-unsynced-off-beat-color\n  \"The color of the tap tempo button when synchronization is off and a\n  beat is not taking place.\"\n  (colors/darken tempo-unsynced-beat-color 45))\n\n(def tempo-synced-beat-color\n  \"The color of the tap tempo button when the metronome is\n  synchronzied and a beat is taking place.\"\n  (colors/create-color :green))\n\n(def tempo-synced-off-beat-color\n  \"The color of the tap tempo button when the metronome is\n  synchronized and a beat is not taking place.\"\n  (colors/darken tempo-synced-beat-color 45))\n\n(defn set-led-color\n  \"Set one of the LEDs, given its control or note number, to a\n  specific RGB color.\"\n  [controller led color]\n  (let [r (colors/red color)\n        g (colors/green color)\n        b (colors/blue color)]\n    (midi/midi-sysex (:port-out controller) [240 0 32 41 2 24 11 led (quot r 4) (quot g 4) (quot b 4) 247])))\n\n(defn set-pad-color\n  \"Set the color of one of the 64 touch pads to a specific RGB color.\"\n  [controller x y color]\n  (set-led-color controller (+ 11 x (* y 10)) color))\n\n(defn- move-origin\n  \"Changes the origin of the controller, notifying any registered\n  listeners.\"\n  [controller origin]\n  (when (not= origin @(:origin controller))\n    (reset! (:origin controller) origin)\n    (doseq [f @(:move-listeners controller)] (f @(:grid-controller-impl controller) :moved))))\n\n(defn show-round-buttons\n  \"Illuminates all round buttons.\"\n  ([controller]\n   (show-round-buttons controller button-available-color))\n  ([controller color]\n   (doseq [[_ led] (concat control-buttons note-buttons)]\n     (set-led-color controller led color))))\n\n(defn clear-interface\n  \"Clears all illuminated buttons and pads.\"\n  [controller]\n  (midi/midi-sysex (:port-out controller) [240 0 32 41 2 24 14 0 247])  ; Sets all LEDs to blackout\n  (reset! (:last-grid-pads controller) nil)  ; Note that no buttons are lit\n  (reset! (:last-round-buttons controller) {}))\n\n(defn- update-round-buttons\n  \"Sees if any round buttons have changed state since the last time\n  the interface was updated, and if so, sends the necessary MIDI\n  commands to update them on the Launchpad Mk2.\"\n  [controller]\n  ;; First turn off any which were on before but no longer are\n  (doseq [[button old-color] @(:last-round-buttons controller)]\n    (when-not (get @(:next-round-buttons controller) button)\n      (set-led-color controller button button-off-color)))\n\n  ;; Then, light any currently active buttons\n  (doseq [[button color] @(:next-round-buttons controller)]\n    (when-not (= (get @(:last-round-buttons controller) button) color)\n      (set-led-color controller button color)))\n\n  ;; And record the new state for next time\n  (reset! (:last-round-buttons controller) @(:next-round-buttons controller)))\n\n(defn- render-cue-grid\n  \"Figure out how the cue grid pads should be illuminated, based on\n  the currently active cues and a metronome snapshot identifying the\n  point in musical time at which the interface is being rendered.\n  Returns a vector of the rows, from bottom to top. Each row is a\n  vector of the colors in that row, from left to right.\"\n  [controller snapshot]\n  (let [[origin-x origin-y] @(:origin controller)\n        active-keys (show/active-effect-keys (:show controller))]\n    (vec (for [y (range 8)]\n           (vec (for [x (range 8)]\n                  (let [[cue active] (show/find-cue-grid-active-effect (:show controller) (+ x origin-x) (+ y origin-y))\n                        ending (and active (:ending active))\n                        base-color (when cue (cues/current-cue-color cue active (:show controller) snapshot))\n                        l-boost (when base-color (if (zero? (colors/saturation base-color)) 2.0 0.0))\n                        color (when base-color\n                                (colors/create-color\n                                 :h (colors/hue base-color)\n                                 :s (colors/saturation base-color)\n                                 ;; Figure the brightness. Active, non-ending cues are full brightness;\n                                 ;; when ending, they blink between middle and low. If they are not active,\n                                 ;; they are at middle brightness unless there is another active effect with\n                                 ;; the same keyword, in which case they are dim.\n                                 :l (+ (if active\n                                         (if ending\n                                           (if (> (rhythm/snapshot-beat-phase snapshot) 0.4) 5 22)\n                                           60)\n                                         (if (or (active-keys (:key cue))\n                                                 (seq (clojure.set/intersection active-keys (set (:end-keys cue)))))\n                                           5 22))\n                                       l-boost)))]\n                    (or color button-off-color))))))))\n\n(defn- update-cue-grid\n  \"Set the colors of all the cue grid pads, based on the currently\n  active cues and overlays.\"\n  [controller]\n  (doseq [x (range 8)\n          y (range 8)]\n    (let [color (get-in @(:next-grid-pads controller) [y x])]\n      (when-not (= (get-in @(:last-grid-pads controller) [y x]) color)\n        (set-pad-color controller x y color))))\n  (reset! (:last-grid-pads controller) @(:next-grid-pads controller)))\n\n(defn- update-scroll-arrows\n  \"Activate the arrow buttons for directions in which scrolling is\n  possible.\"\n  [controller]\n  (let [[origin-x origin-y] @(:origin controller)]\n    (when (pos? origin-x)\n      (swap! (:next-round-buttons controller) assoc (:left-arrow control-buttons) button-available-color))\n    (when (pos? origin-y)\n      (swap! (:next-round-buttons controller) assoc (:down-arrow control-buttons) button-available-color))\n    (when (> (- (controllers/grid-width (:cue-grid (:show controller))) origin-x) 7)\n      (swap! (:next-round-buttons controller) assoc (:right-arrow control-buttons) button-available-color))\n    (when (> (- (controllers/grid-height (:cue-grid (:show controller))) origin-y) 7)\n      (swap! (:next-round-buttons controller) assoc (:up-arrow control-buttons) button-available-color))))\n\n(defn add-button-held-feedback-overlay\n  \"Adds a simple overlay which keeps a control button bright as long\n  as the user is holding it down.\"\n  ([controller button]\n   (add-button-held-feedback-overlay controller button button-active-color))\n  ([controller button color]\n   (controllers/add-control-held-feedback-overlay (:overlays controller) button\n                                                  (fn [_] (swap! (:next-round-buttons controller)\n                                                                 assoc button color)))))\n\n(defn- enter-stop-mode\n  \"The user has asked to stop the show. Suspend its update task\n  and black it out until the stop button is pressed again.\"\n  [controller & {:keys [already-stopped]}]\n\n  (reset! (:stop-mode controller) true)\n  (when-not already-stopped\n    (with-show (:show controller)\n      (show/stop!)\n      (Thread/sleep (:refresh-interval (:show controller)))\n      (show/blackout-show)))\n\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [this] #{})\n                             (captured-notes [this] #{(:stop note-buttons)})\n                             (adjust-interface [this _]\n                               (swap! (:next-round-buttons controller)\n                                      assoc (:stop note-buttons) stop-active-color)\n                               (with-show (:show controller)\n                                 (when (show/running?)\n                                   (reset! (:stop-mode controller) false))\n                                 @(:stop-mode controller)))\n                             (handle-control-change [this message])\n                             (handle-note-on [this message]\n                               (when (pos? (:velocity message))\n                                 ;; End stop mode\n                                 (with-show (:show controller)\n                                   (show/start!))\n                                 (reset! (:stop-mode controller) false)\n                                 :done))\n                             (handle-note-off [this message])\n                             (handle-aftertouch [this message])\n                             (handle-pitch-bend [this message]))))\n\n(defn- new-beat?\n  \"Returns true if the metronome is reporting a different marker\n  position than the last time this function was called.\"\n  [controller marker]\n  (when (not= marker @(:last-marker controller))\n    (reset! (:last-marker controller) marker)))\n\n(defn- metronome-sync-colors\n  \"Determine the colors to light the tap tempo button. Returns a tuple\n  of the off-beat and on-beat colors based on the current sync\n  status.\"\n  [controller]\n  (with-show (:show controller)\n    (if (= (:type (show/sync-status)) :manual)\n      [tempo-unsynced-off-beat-color tempo-unsynced-beat-color]\n      (if (:current (show/sync-status))\n        [tempo-synced-off-beat-color tempo-synced-beat-color]\n        [stop-available-color stop-active-color]))))\n\n(defn- update-interface\n  \"Determine the desired current state of the interface, and send any\n  changes needed to get it to that state.\"\n  [controller]\n  (try\n    ;; Assume we are starting out with a blank interface.\n    (reset! (:next-round-buttons controller) {})\n\n    ;; If the show has stopped without us noticing, enter stop mode\n    (with-show (:show controller)\n      (when-not (or (show/running?) @(:stop-mode controller))\n        (enter-stop-mode controller :already-stopped true)))\n\n    ;; Reflect the Record Arm (shift) button state\n    (swap! (:next-round-buttons controller)\n           assoc (:record-arm note-buttons)\n           (if @(:shift-mode controller) button-active-color button-available-color))\n\n    (update-scroll-arrows controller)\n\n    ;; Flash the volume (tap tempo) button on beats\n    (let [snapshot (rhythm/metro-snapshot (get-in controller [:show :metronome]))\n          marker (rhythm/snapshot-marker snapshot)\n          colors (metronome-sync-colors controller)]\n      (swap! (:next-round-buttons controller)\n             assoc (:volume note-buttons)\n             (if (or (new-beat? controller marker) (< (rhythm/snapshot-beat-phase snapshot) 0.15))\n               (second colors) (first colors)))\n\n      ;; Make the User 2 button bright, since we live in that layout\n      (swap! (:next-round-buttons controller)\n             assoc (:user-2 control-buttons) button-active-color)\n\n      ;; Make the stop button visible, since we support it\n      (swap! (:next-round-buttons controller)\n             assoc (:stop note-buttons)\n             stop-available-color)\n\n      (reset! (:next-grid-pads controller) (render-cue-grid controller snapshot))\n\n      ;; Add any contributions from interface overlays, removing them\n      ;; if they report being finished.\n      (controllers/run-overlays (:overlays controller) snapshot))\n\n    (update-cue-grid controller)\n    (update-round-buttons controller)\n\n    (catch Throwable t\n      (warn t \"Problem updating Launchpad Mk2 Interface\"))))\n\n(defn- set-layout\n  \"Put the controller in the User 2 layout, which is most appropriate\n  for Afterglow.\"\n  [controller]\n  (midi/midi-sysex (:port-out controller) [240 0 32 41 2 24 34 2 247]))\n\n(defn- leave-user-mode\n  \"The user has asked to exit user mode, so suspend our display\n  updates, and prepare to restore our state when user mode is pressed\n  again.\"\n  [controller]\n  (swap! (:task controller) (fn [task]\n                              (when task (at-at/kill task))\n                              nil))\n  (clear-interface controller)\n  ;; In case Live isn't running, leave the User 2 button dimly lit, to help the user return.\n  (set-led-color controller (:user-2 control-buttons) button-available-color)\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [this] #{(:user-2 control-buttons)})\n                             (captured-notes [this] #{})\n                             (adjust-interface [this _]\n                               true)\n                             (handle-control-change [this message]\n                               (when (pos? (:velocity message))\n                                 ;; We are returning to user mode, restore layout and display\n                                 (set-layout controller)\n                                 (clear-interface controller)\n                                 (reset! (:task controller) (at-at/every (:refresh-interval controller)\n                                                                         #(update-interface controller)\n                                                                         controllers/pool\n                                                                         :initial-delay 250\n                                                                         :desc \"Launchpad Mk2 interface update\"))\n                                 :done))\n                             (handle-note-on [this message])\n                             (handle-note-off [this message])\n                             (handle-aftertouch [this message])\n                             (handle-pitch-bend [this message]))))\n\n(defn- control-change-received\n  \"Process a control change message which was not handled by an\n  interface overlay.\"\n  [controller message]\n  (case (:note message)\n    106 ; Left arrow\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)]\n        (when (pos? x)\n          (move-origin controller [(if @(:shift-mode controller) 0 (max 0 (- x 8))) y])\n          (add-button-held-feedback-overlay controller (:left-arrow control-buttons)))))\n\n    107 ; Right arrow\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)\n            width (max (controllers/grid-width (:cue-grid (:show controller))) 1)]\n        (when (> (- (controllers/grid-width (:cue-grid (:show controller))) x) 7)\n          (move-origin controller [(if @(:shift-mode controller) (* 8 (quot (dec width) 8)) (+ x 8)) y])\n          (add-button-held-feedback-overlay controller (:right-arrow control-buttons)))))\n\n    104 ; Up arrow\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)\n            height (max (controllers/grid-height (:cue-grid (:show controller))) 1)]\n        (when (> (- (controllers/grid-height (:cue-grid (:show controller))) y) 7)\n          (move-origin controller [x (if @(:shift-mode controller) (* 8 (quot (dec height) 8)) (+ y 8))])\n          (add-button-held-feedback-overlay controller (:up-arrow control-buttons)))))\n\n    105 ; Down arrow\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)]\n        (when (pos? y)\n          (move-origin controller [x (max 0 (if @(:shift-mode controller) 0 (max 0 (- y 8))))])\n          (add-button-held-feedback-overlay controller (:down-arrow control-buttons)))))\n\n    110 ; User 2 button\n    (when (pos? (:velocity message))\n      (leave-user-mode controller))\n\n    ;; Something we don't care about\n    nil))\n\n(defn- note-to-cue-coordinates\n  \"Translate the MIDI note associated with an incoming message to its\n  coordinates in the show cue grid.\"\n  [controller note]\n  (let [base (- note 11)\n        [origin-x origin-y] @(:origin controller)\n        pad-x (rem base 10)\n        pad-y (quot base 10)\n        cue-x (+ origin-x pad-x)\n        cue-y (+ origin-y pad-y)]\n    [cue-x cue-y pad-x pad-y]))\n\n(defn- cue-grid-pressed\n  \"One of the pads in the 8x8 cue grid was pressed.\"\n  [controller note]\n  (let [[cue-x cue-y pad-x pad-y] (note-to-cue-coordinates controller note)\n        [cue active] (show/find-cue-grid-active-effect (:show controller) cue-x cue-y)]\n          (when cue\n            (with-show (:show controller)\n              (if (and active (not (:held cue)))\n                (show/end-effect! (:key cue))\n                (let [id (show/add-effect-from-cue-grid! cue-x cue-y)\n                      holding (and (:held cue) (not @(:shift-mode controller)))]\n                  (controllers/add-overlay\n                   (:overlays controller)\n                   (reify controllers/IOverlay\n                     (captured-controls [this] #{})\n                     (captured-notes [this] #{note})\n                     (adjust-interface [this snapshot]\n                       (when holding\n                         (let [active (show/find-effect (:key cue))\n                               base-color (cues/current-cue-color cue active (:show controller) snapshot)\n                               color (colors/create-color\n                                      :h (colors/hue base-color)\n                                      :s (colors/saturation base-color)\n                                      :l 75)]\n                           (swap! (:next-grid-pads controller) assoc-in [cue-y cue-x] color)))\n                       true)\n                     (handle-control-change [this message])\n                     (handle-note-on [this message])\n                     (handle-note-off [this message]\n                       (when holding\n                         (with-show (:show controller)\n                           (show/end-effect! (:key cue) :when-id id)))\n                       :done)\n                     (handle-aftertouch [this message])\n                     (handle-pitch-bend [this message])))))))))\n\n(defn- note-on-received\n  \"Process a note-on message which was not handled by an interface\n  overlay.\"\n  [controller message]\n  (let [note (:note message)]\n    (if (and (<= 1 (rem note 10) 8) (<= 1 (quot note 10) 8))\n      (cue-grid-pressed controller note)\n      (case note\n        89  ; Volume (tap tempo) button\n        (when (pos? (:velocity message))\n          ((:tempo-tap-handler controller)))\n\n        19  ; Record Arm (shift) button\n        (reset! (:shift-mode controller) (pos? (:velocity message)))\n\n        49  ; Stop button\n        (when (pos? (:velocity message))\n          (enter-stop-mode controller))\n\n        ;; Something we don't care about\n        nil))))\n\n(defn- note-off-received\n  \"Process a note-off message which was not handled by an interface\n  overlay.\"\n  [controller message]\n  (case (:note message)\n\n    19  ; Record Arm (shift) button\n    (reset! (:shift-mode controller) false)\n\n    ;; Something we don't care about\n    nil))\n\n(defn- midi-received\n  \"Called whenever a MIDI message is received from the controller\n  while the mapping is active; takes whatever action is appropriate.\"\n  [controller message]\n  ;;(timbre/info message)\n  (when-not (controllers/overlay-handled? (:overlays controller) message)\n    (when (= (:command message) :control-change)\n      (control-change-received controller message))\n    (when (= (:command message) :note-on)\n      (note-on-received controller message))\n    (when (= (:command message) :note-off)\n      (note-off-received controller message))))\n\n(defn- start-interface\n  \"Set up the thread which keeps the user interface up to date.\"\n  [controller]\n  (clear-interface controller)\n  (amidi/add-device-mapping (:port-in controller) @(:midi-handler controller))\n  (reset! (:task controller) (at-at/every (:refresh-interval controller)\n                                          #(update-interface controller)\n                                          controllers/pool\n                                          :initial-delay 10\n                                          :desc \"Launchpad Mk2 interface update\")))\n\n(defn- welcome-frame\n  \"Render a frame of the welcome animation, or if it is done, start\n  the main interface update thread, and terminate the task running the\n  animation.\"\n  [controller counter task]\n  (try\n    (cond\n      (< @counter 8)\n      (doseq [y (range 0 (inc @counter))]\n        (let [color (colors/create-color\n                     :h 0 :s 0 :l (max 10 (- 75 (/ (* 50 (- @counter y)) 6))))]\n          (set-pad-color controller 3 y color)\n          (set-pad-color controller 4 y color)))\n\n      (< @counter 12)\n      (doseq [x (range 0 (- @counter 7))\n              y (range 0 8)]\n        (let [color (colors/create-color\n                     :h 340 :s 100 :l (- 75 (* (- @counter 8 x) 20)))]\n          (set-pad-color controller (- 3 x) y color)\n          (set-pad-color controller (+ 4 x) y color)))\n\n      (< @counter 15)\n      (doseq [y (range 0 8)]\n        (let [color (colors/create-color\n                     :h (* 13 (- @counter 11)) :s 100 :l 50)]\n          (set-pad-color controller (- @counter 7) y color)\n          (set-pad-color controller (- 14 @counter) y color)))\n\n      (= @counter 15)\n      (show-round-buttons controller (colors/create-color :cyan))\n\n      (< @counter 24)\n      (doseq [x (range 0 8)]\n        (let [lightness-index (if (> x 3) (- 7 x) x)\n              lightness ([10 30 50 70] lightness-index)\n              color (colors/create-color\n                     :h (+ 60 (* 40 (- @counter 18))) :s 100 :l lightness)]\n          (set-pad-color controller x (- 23 @counter) color)))\n\n      (= @counter 24)\n      (show-round-buttons controller (colors/create-color :blue))\n\n      (< @counter 33)\n      (doseq [x (range 0 8)]\n        (set-pad-color controller x (- 32 @counter) button-off-color))\n\n      :else\n      (do\n        (start-interface controller)\n        (at-at/kill @task)))\n    (catch Throwable t\n      (warn t \"Animation frame failed\")))\n\n  (swap! counter inc))\n\n(defn- welcome-animation\n  \"Provide a fun animation to make it clear the Launchpad Mk2 is online.\"\n  [controller]\n  (let [counter (atom 0)\n        task (atom nil)]\n    (reset! task (at-at/every 50 #(welcome-frame controller counter task)\n                              controllers/pool))))\n\n(defn deactivate\n  \"Deactivates a controller interface, killing its update thread and\n  removing its MIDI listeners. If `:disconnected` is passed with a\n  `true` value, it means that the controller has already been removed\n  from the MIDI environment, so no effort will be made to clear its\n  display or take it out of User mode.\n\n  In general you will not need to call this function directly; it will\n  be dispatched to via [[controllers/deactivate]] when that is called\n  with a controller binding implementation from this namespace. It is\n  also called automatically when one of the controllers being used\n  disappears from the MIDI environment.\"\n  [controller & {:keys [disconnected] :or {disconnected false}}]\n  {:pre [(have? (= ::controller (type controller)))]}\n  (swap! (:task controller)\n         (fn [task]\n           (when task\n             (at-at/kill task)\n             (show/unregister-grid-controller @(:grid-controller-impl controller))\n             (doseq [f @(:move-listeners controller)] (f @(:grid-controller-impl controller) :deactivated))\n             (reset! (:move-listeners controller) #{})\n             (amidi/remove-device-mapping (:port-in controller) @(:midi-handler controller))\n\n             (when-not disconnected\n               (Thread/sleep 35) ; Give the UI update thread time to shut down\n               (clear-interface controller)\n\n               ;; Leave the User button bright, in case the user has Live\n               ;; running and wants to be able to see how to return to it.\n               (set-led-color controller (:user-2 control-buttons) (colors/create-color :white)))\n\n             ;; Cancel any UI overlays which were in effect\n             (reset! (:overlays controller) (controllers/create-overlay-state))\n\n             ;; And finally, note that we are no longer active.\n             (controllers/remove-active-binding controller))\n           nil)))\n\n(defn- recognize\n  \"Returns the controller's device ID if `message` is a response\n  from [[controllers/identify]] which marks it as a Novation Launchpad\n  Mk2.\"\n  [message _ _]\n  (when (= (take 5 (drop 4 (:data message))) '(0 32 41 105 0))\n    (int (aget (:data message) 1))))\n\n;; Register our recognition function and rich binding with the\n;; controller manager.\n(swap! controllers/recognizers assoc ::controller recognize)\n\n(defmethod controllers/deactivate ::controller\n  [controller & {:keys [disconnected] :or {disconnected false}}]\n  (deactivate controller :disconnected disconnected))\n\n(defmethod controllers/bind-to-show-impl ::controller\n  [kind show port-in port-out device & {:keys [refresh-interval display-name new-connection]\n                                        :or   {refresh-interval (/ 1000 15)\n                                               display-name     \"Launchpad Mk2\"}}]\n  {:pre [(some? show)]}\n  (let [shift-mode (atom false)\n        controller\n        (with-meta\n          {:display-name         display-name\n           :device-id            device\n           :show                 show\n           :origin               (atom [0 0])\n           :refresh-interval     refresh-interval\n           :port-in              port-in\n           :port-out             port-out\n           :task                 (atom nil)\n           :last-round-buttons    (atom {})\n           :next-round-buttons    (atom {})\n           :last-grid-pads       (atom nil)\n           :next-grid-pads       (atom nil)\n           :shift-mode           shift-mode\n           :stop-mode            (atom false)\n           :midi-handler         (atom nil)\n           :tempo-tap-handler    (tempo/create-show-tempo-tap-handler show :shift-fn (fn [] @shift-mode))\n           :last-marker          (atom nil)\n           :overlays             (controllers/create-overlay-state)\n           :move-listeners       (atom #{})\n           :grid-controller-impl (atom nil)}\n          {:type ::controller})]\n    (reset! (:midi-handler controller) (partial midi-received controller))\n    (reset! (:grid-controller-impl controller)\n            (reify controllers/IGridController\n              (display-name [_this] (:display-name controller))\n              (controller [_this] controller)\n              (physical-height [_this] 8)\n              (physical-width [_this] 8)\n              (current-bottom [_this] (@(:origin controller) 1))\n              (current-bottom [_this y] (move-origin controller (assoc @(:origin controller) 1 y)))\n              (current-left [_this] (@(:origin controller) 0))\n              (current-left [_this x] (move-origin controller (assoc @(:origin controller) 0 x)))\n              (add-move-listener [_this f] (swap! (:move-listeners controller) conj f))\n              (remove-move-listener [_this f] (swap! (:move-listeners controller) disj f))))\n    (if new-connection\n      (at-at/after 3000 (fn []\n                          (set-layout controller)\n                          (clear-interface controller)\n                          (start-interface controller)) controllers/pool :desc \"Start Launchpad Mk2 interface\")\n      (do\n        (set-layout controller)\n        (clear-interface controller)\n        (welcome-animation controller)))\n    (controllers/add-active-binding controller)\n    (show/register-grid-controller @(:grid-controller-impl controller))\n    (amidi/add-disconnected-device-handler! port-in #(deactivate controller :disconnected true))\n    controller))\n"
  },
  {
    "path": "src/afterglow/controllers/launchpad_pro.clj",
    "content": "(ns afterglow.controllers.launchpad-pro\n  \"Allows the Novation Launchpad Pro to be used as a control surface\n  for Afterglow.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.controllers :as controllers]\n            [afterglow.controllers.tempo :as tempo]\n            [afterglow.effects.cues :as cues]\n            [afterglow.effects.dimmer :refer [master-get-level master-set-level]]\n            [afterglow.midi :as amidi]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [with-show]]\n            [afterglow.util :as util]\n            [clojure.math.numeric-tower :as math]\n            [com.evocomputing.colors :as colors]\n            [overtone.at-at :as at-at]\n            [overtone.midi :as midi]\n            [taoensso.timbre :as timbre :refer [warn]]\n            [taoensso.truss :as truss :refer [have have! have?]]))\n\n(def control-buttons\n  \"The labeled buttons which send and respond to Control Change\n  events.\"\n  {:record-arm   1\n   :track-select 2\n   :mute         3\n   :solo         4\n   :volume       5\n   :pan          6\n   :sends        7\n   :stop         8\n\n   :circle       10\n   :double       20\n   :duplicate    30\n   :quantize     40\n   :delete       50\n   :undo         60\n   :tap-tempo    70\n   :shift        80\n\n   :row-0        19\n   :row-1        29\n   :row-2        39\n   :row-3        49\n   :row-4        59\n   :row-5        69\n   :row-6        79\n   :row-7        89\n\n   :up-arrow     91\n   :down-arrow   92\n   :left-arrow   93\n   :right-arrow  94\n   :session-mode 95\n   :note-mode    96\n   :device-mode  97\n   :user-mode    98})\n\n(def button-off-color\n  \"The color of buttons that are completely off.\"\n  (colors/create-color :black))\n\n(def button-available-color\n  \"The color of buttons that can be pressed but haven't yet been.\"\n  (colors/darken (colors/create-color :orange) 45))\n\n(def button-active-color\n  \"The color of an available button that is currently being pressed.\"\n  (colors/create-color :yellow))\n\n(def stop-available-color\n  \"The color of the Stop button when not active.\"\n  (colors/darken (colors/create-color :red) 45))\n\n(def stop-active-color\n  \"The color of the stop button when active.\"\n  (colors/create-color :red))\n\n(def click-unsynced-beat-color\n  \"The color of the tap tempo button when synchronization is off and a\n  beat is taking place.\"\n  (colors/create-color :blue))\n\n(def click-unsynced-off-beat-color\n  \"The color of the tap tempo button when synchronization is off and a\n  beat is not taking place.\"\n  (colors/darken click-unsynced-beat-color 45))\n\n(def click-synced-beat-color\n  \"The color of the tap tempo button when the metronome is\n  synchronzied and a beat is taking place.\"\n  (colors/create-color :green))\n\n(def click-synced-off-beat-color\n  \"The color of the tap tempo button when the metronome is\n  synchronized and a beat is not taking place.\"\n  (colors/darken click-synced-beat-color 45))\n\n(defn led-color-values\n  \"Given a color, return the values that should be sent in a Sysex\n  message to set an LED to that color.\"\n  [color]\n  (let [r (colors/red color)\n        g (colors/green color)\n        b (colors/blue color)]\n    (list (quot r 4) (quot g 4) (quot b 4))))\n\n(defn set-led-color\n  \"Set one of the LEDs, given its control or note number, to a\n  specific RGB color.\"\n  [controller led color]\n  (let [r (colors/red color)\n        g (colors/green color)\n        b (colors/blue color)]\n    (midi/midi-sysex (:port-out controller) [240 0 32 41 2 16 11 led (quot r 4) (quot g 4) (quot b 4) 247])))\n\n(defn set-pad-color\n  \"Set the color of one of the 64 touch pads to a specific RGB color.\"\n  [controller x y color]\n  (set-led-color controller (+ 11 x (* y 10)) color))\n\n(defn- move-origin\n  \"Changes the origin of the controller, notifying any registered\n  listeners.\"\n  [controller origin]\n  (when (not= origin @(:origin controller))\n    (reset! (:origin controller) origin)\n    (doseq [f @(:move-listeners controller)] (f @(:grid-controller-impl controller) :moved))))\n\n(defn show-labels\n  \"Illuminates all buttons with text labels, for development assistance.\"\n  ([controller]\n   (show-labels controller button-available-color))\n  ([controller color]\n   (doseq [[_ led] control-buttons]\n     (set-led-color controller led color))))\n\n(defn clear-interface\n  \"Clears all illuminated buttons and pads.\"\n  [controller]\n  (midi/midi-sysex (:port-out controller) [240 0 32 41 2 16 14 0 247])  ; Sets all LEDs to blackout\n  (reset! (:last-grid-pads controller) nil)  ; Note that no buttons are lit\n  (reset! (:last-text-buttons controller) {}))\n\n(defn- update-text-buttons\n  \"Sees if any labeled buttons have changed state since the last time\n  the interface was updated, and if so, sends the necessary MIDI\n  commands to update them on the Launchpad Pro.\"\n  [controller]\n  ;; First turn off any which were on before but no longer are\n  (doseq [[button old-color] @(:last-text-buttons controller)]\n    (when-not (get @(:next-text-buttons controller) button)\n      (set-led-color controller button button-off-color)))\n\n  ;; Then, light any currently active buttons\n  (doseq [[button color] @(:next-text-buttons controller)]\n    (when-not (= (get @(:last-text-buttons controller) button) color)\n      (set-led-color controller button color)))\n\n  ;; And record the new state for next time\n  (reset! (:last-text-buttons controller) @(:next-text-buttons controller)))\n\n(defn- render-cue-grid\n  \"Figure out how the cue grid pads should be illuminated, based on\n  the currently active cues and a metronome snapshot identifying the\n  point in musical time at which the interface is being rendered.\n  Returns a vector of the rows, from bottom to top. Each row is a\n  vector of the colors in that row, from left to right.\"\n  [controller snapshot]\n  (let [[origin-x origin-y] @(:origin controller)\n        active-keys (show/active-effect-keys (:show controller))]\n    (vec (for [y (range 8)]\n           (vec (for [x (range 8)]\n                  (let [[cue active] (show/find-cue-grid-active-effect (:show controller) (+ x origin-x) (+ y origin-y))\n                        ending (and active (:ending active))\n                        base-color (when cue (cues/current-cue-color cue active (:show controller) snapshot))\n                        l-boost (when base-color (if (zero? (colors/saturation base-color)) 2.0 0.0))\n                        color (when base-color\n                                (colors/create-color\n                                 :h (colors/hue base-color)\n                                 :s (colors/saturation base-color)\n                                 ;; Figure the brightness. Active, non-ending cues are full brightness;\n                                 ;; when ending, they blink between middle and low. If they are not active,\n                                 ;; they are at middle brightness unless there is another active effect with\n                                 ;; the same keyword, in which case they are dim.\n                                 :l (+ (if active\n                                         (if ending\n                                           (if (> (rhythm/snapshot-beat-phase snapshot) 0.4) 5 22)\n                                           60)\n                                         (if (or (active-keys (:key cue))\n                                                 (seq (clojure.set/intersection active-keys (set (:end-keys cue)))))\n                                           5 22))\n                                       l-boost)))]\n                    (or color button-off-color))))))))\n\n(defn- count-grid-changes\n  \"See how many changes we can find in the grid, with an upper limit\n  Returns the number of changes we see, or the upper bound if that is\n  reached before the end of the grid.\"\n  [controller limit]\n  (loop [found 0\n         old (flatten @(:last-grid-pads controller))\n         new (flatten @(:next-grid-pads controller))]\n    (if (or (>= found limit) (empty? new))\n      found\n      (recur\n       (if (= (first old) (first new)) found (inc found))\n       (rest old)\n       (rest new)))))\n\n(defn- update-cue-grid\n  \"Set the colors of all the cue grid pads, based on the currently\n  active cues and overlays. On the Launchpad Pro this can be done with\n  a single Sysex message, but doing that when there are few changes\n  results in a visible flicker. So as a compromise, we update the\n  whole grid when eight or more cells have changed, otherwise we send\n  the differences individually.\"\n  [controller]\n  (let [limit 8\n        changes (count-grid-changes controller limit)]\n    (if (>= changes limit)\n      (midi/midi-sysex (:port-out controller)  ; Send the entire grid as one Sysex message\n                       (concat [240 0 32 41 2 16 15 1]\n                               (flatten (map led-color-values (flatten @(:next-grid-pads controller))))\n                               [247]))\n      (doseq [x (range 8)  ; Send the changes only, individually\n              y (range 8)]\n        (let [color (get-in @(:next-grid-pads controller) [y x])]\n          (when-not (= (get-in @(:last-grid-pads controller) [y x]) color)\n            (set-pad-color controller x y color))))))\n  (reset! (:last-grid-pads controller) @(:next-grid-pads controller)))\n\n(defn- update-scroll-arrows\n  \"Activate the arrow buttons for directions in which scrolling is\n  possible.\"\n  [controller]\n  (let [[origin-x origin-y] @(:origin controller)]\n    (when (pos? origin-x)\n      (swap! (:next-text-buttons controller) assoc (:left-arrow control-buttons) button-available-color))\n    (when (pos? origin-y)\n      (swap! (:next-text-buttons controller) assoc (:down-arrow control-buttons) button-available-color))\n    (when (> (- (controllers/grid-width (:cue-grid (:show controller))) origin-x) 7)\n      (swap! (:next-text-buttons controller) assoc (:right-arrow control-buttons) button-available-color))\n    (when (> (- (controllers/grid-height (:cue-grid (:show controller))) origin-y) 7)\n      (swap! (:next-text-buttons controller) assoc (:up-arrow control-buttons) button-available-color))))\n\n(defn add-button-held-feedback-overlay\n  \"Adds a simple overlay which keeps a control button bright as long\n  as the user is holding it down.\"\n  ([controller button]\n   (add-button-held-feedback-overlay controller button button-active-color))\n  ([controller button color]\n   (controllers/add-control-held-feedback-overlay (:overlays controller) button\n                                                  (fn [_] (swap! (:next-text-buttons controller)\n                                                                 assoc button color)))))\n\n(defn- enter-stop-mode\n  \"The user has asked to stop the show. Suspend its update task\n  and black it out until the stop button is pressed again.\"\n  [controller & {:keys [already-stopped]}]\n\n  (reset! (:stop-mode controller) true)\n  (when-not already-stopped\n    (with-show (:show controller)\n      (show/stop!)\n      (Thread/sleep (:refresh-interval (:show controller)))\n      (show/blackout-show)))\n\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [this] #{(:stop control-buttons)})\n                             (captured-notes [this] #{})\n                             (adjust-interface [this _]\n                               (swap! (:next-text-buttons controller)\n                                      assoc (:stop control-buttons) stop-active-color)\n                               (with-show (:show controller)\n                                 (when (show/running?)\n                                   (reset! (:stop-mode controller) false))\n                                 @(:stop-mode controller)))\n                             (handle-control-change [this message]\n                               (when (pos? (:velocity message))\n                                 ;; End stop mode\n                                 (with-show (:show controller)\n                                   (show/start!))\n                                 (reset! (:stop-mode controller) false)\n                                 :done))\n                             (handle-note-on [this message])\n                             (handle-note-off [this message])\n                             (handle-aftertouch [this message])\n                             (handle-pitch-bend [this message]))))\n\n(defn- new-beat?\n  \"Returns true if the metronome is reporting a different marker\n  position than the last time this function was called.\"\n  [controller marker]\n  (when (not= marker @(:last-marker controller))\n    (reset! (:last-marker controller) marker)))\n\n(defn- metronome-sync-colors\n  \"Determine the colors to light the tap tempo button. Returns a tuple\n  of the off-beat and on-beat colors based on the current sync\n  status.\"\n  [controller]\n  (with-show (:show controller)\n    (if (= (:type (show/sync-status)) :manual)\n      [click-unsynced-off-beat-color click-unsynced-beat-color]\n      (if (:current (show/sync-status))\n        [click-synced-off-beat-color click-synced-beat-color]\n        [stop-available-color stop-active-color]))))\n\n(defn- update-interface\n  \"Determine the desired current state of the interface, and send any\n  changes needed to get it to that state.\"\n  [controller]\n  (try\n    ;; Assume we are starting out with a blank interface.\n    (reset! (:next-text-buttons controller) {})\n\n    ;; If the show has stopped without us noticing, enter stop mode\n    (with-show (:show controller)\n      (when-not (or (show/running?) @(:stop-mode controller))\n        (enter-stop-mode controller :already-stopped true)))\n\n    ;; Reflect the shift button state\n    (swap! (:next-text-buttons controller)\n           assoc (:shift control-buttons)\n           (if @(:shift-mode controller) button-active-color button-available-color))\n\n    (update-scroll-arrows controller)\n\n    ;; Flash the tap tempo button on beats\n    (let [snapshot (rhythm/metro-snapshot (get-in controller [:show :metronome]))\n          marker (rhythm/snapshot-marker snapshot)\n          colors (metronome-sync-colors controller)]\n      (swap! (:next-text-buttons controller)\n             assoc (:tap-tempo control-buttons)\n             (if (or (new-beat? controller marker) (< (rhythm/snapshot-beat-phase snapshot) 0.15))\n               (second colors) (first colors)))\n\n      ;; Make the User button bright, since we live in User mode\n      (swap! (:next-text-buttons controller)\n             assoc (:user-mode control-buttons) button-active-color)\n\n      ;; Make the stop button visible, since we support it\n      (swap! (:next-text-buttons controller)\n             assoc (:stop control-buttons)\n             stop-available-color)\n\n      (reset! (:next-grid-pads controller) (render-cue-grid controller snapshot))\n\n      ;; Add any contributions from interface overlays, removing them\n      ;; if they report being finished.\n      (controllers/run-overlays (:overlays controller) snapshot))\n\n    (update-cue-grid controller)\n    (update-text-buttons controller)\n\n    (catch Throwable t\n      (warn t \"Problem updating Launchpad Pro Interface\"))))\n\n(defn- set-layout\n  \"Put the controller in the Programmer layout, which is most\n  appropriate for Afterglow.\"\n  [controller]\n  (midi/midi-sysex (:port-out controller) [240 0 32 41 2 16 44 3 247]))\n\n(defn- leave-user-mode\n  \"The user has asked to exit user mode, so suspend our display\n  updates, and prepare to restore our state when user mode is pressed\n  again.\"\n  [controller]\n  (swap! (:task controller) (fn [task]\n                              (when task (at-at/kill task))\n                              nil))\n  (clear-interface controller)\n  ;; In case Live isn't running, leave the User Mode button dimly lit, to help the user return.\n  (set-led-color controller (:user-mode control-buttons) button-available-color)\n  (controllers/add-overlay (:overlays controller)\n                           (reify controllers/IOverlay\n                             (captured-controls [this] #{(:user-mode control-buttons)})\n                             (captured-notes [this] #{})\n                             (adjust-interface [this _]\n                               true)\n                             (handle-control-change [this message]\n                               (when (pos? (:velocity message))\n                                 ;; We are returning to user mode, restore layout and display\n                                 (set-layout controller)\n                                 (clear-interface controller)\n                                 (reset! (:task controller) (at-at/every (:refresh-interval controller)\n                                                                         #(update-interface controller)\n                                                                         controllers/pool\n                                                                         :initial-delay 250\n                                                                         :desc \"Launchpad Pro interface update\"))\n                                 :done))\n                             (handle-note-on [this message])\n                             (handle-note-off [this message])\n                             (handle-aftertouch [this message])\n                             (handle-pitch-bend [this message]))))\n\n(defn- control-change-received\n  \"Process a control change message which was not handled by an\n  interface overlay.\"\n  [controller message]\n  (case (:note message)\n    70  ; Tap tempo (click) button\n    (when (pos? (:velocity message))\n      ((:tempo-tap-handler controller)))\n\n    8  ; Stop button\n    (when (pos? (:velocity message))\n      (enter-stop-mode controller))\n\n    80 ; Shift button\n    (reset! (:shift-mode controller) (pos? (:velocity message)))\n\n    93 ; Left arrow\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)]\n        (when (pos? x)\n          (move-origin controller [(if @(:shift-mode controller) 0 (max 0 (- x 8))) y])\n          (add-button-held-feedback-overlay controller (:left-arrow control-buttons)))))\n\n    94 ; Right arrow\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)\n            width (max (controllers/grid-width (:cue-grid (:show controller))) 1)]\n        (when (> (- (controllers/grid-width (:cue-grid (:show controller))) x) 7)\n          (move-origin controller [(if @(:shift-mode controller) (* 8 (quot (dec width) 8)) (+ x 8)) y])\n          (add-button-held-feedback-overlay controller (:right-arrow control-buttons)))))\n\n    91 ; Up arrow\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)\n            height (max (controllers/grid-height (:cue-grid (:show controller))) 1)]\n        (when (> (- (controllers/grid-height (:cue-grid (:show controller))) y) 7)\n          (move-origin controller [x (if @(:shift-mode controller) (* 8 (quot (dec height) 8)) (+ y 8))])\n          (add-button-held-feedback-overlay controller (:up-arrow control-buttons)))))\n\n    92 ; Down arrow\n    (when (pos? (:velocity message))\n      (let [[x y] @(:origin controller)]\n        (when (pos? y)\n          (move-origin controller [x (max 0 (if @(:shift-mode controller) 0 (max 0 (- y 8))))])\n          (add-button-held-feedback-overlay controller (:down-arrow control-buttons)))))\n\n    98 ; User mode button\n    (when (pos? (:velocity message))\n      (leave-user-mode controller))\n\n    ;; Something we don't care about\n    nil))\n\n(defn- note-to-cue-coordinates\n  \"Translate the MIDI note associated with an incoming message to its\n  coordinates in the show cue grid.\"\n  [controller note]\n  (let [base (- note 11)\n        [origin-x origin-y] @(:origin controller)\n        pad-x (rem base 10)\n        pad-y (quot base 10)\n        cue-x (+ origin-x pad-x)\n        cue-y (+ origin-y pad-y)]\n    [cue-x cue-y pad-x pad-y]))\n\n(defn- cue-grid-pressed\n  \"One of the pads in the 8x8 pressure-sensitve cue grid was pressed.\"\n  [controller note velocity]\n  (let [[cue-x cue-y pad-x pad-y] (note-to-cue-coordinates controller note)\n        [cue active] (show/find-cue-grid-active-effect (:show controller) cue-x cue-y)]\n          (when cue\n            (with-show (:show controller)\n              (if (and active (not (:held cue)))\n                (show/end-effect! (:key cue))\n                (let [id (show/add-effect-from-cue-grid! cue-x cue-y :velocity velocity)\n                      holding (and (:held cue) (not @(:shift-mode controller)))]\n                  (controllers/add-overlay\n                   (:overlays controller)\n                   (reify controllers/IOverlay\n                     (captured-controls [this] #{})\n                     (captured-notes [this] #{note})\n                     (adjust-interface [this snapshot]\n                       (when holding\n                         (let [active (show/find-effect (:key cue))\n                               base-color (cues/current-cue-color cue active (:show controller) snapshot)\n                               color (colors/create-color\n                                      :h (colors/hue base-color)\n                                      :s (colors/saturation base-color)\n                                      :l 75)]\n                           (swap! (:next-grid-pads controller) assoc-in [cue-y cue-x] color)))\n                       true)\n                     (handle-control-change [this message])\n                     (handle-note-on [this message])\n                     (handle-note-off [this message]\n                       (when holding\n                         (with-show (:show controller)\n                           (show/end-effect! (:key cue) :when-id id)))\n                       :done)\n                     (handle-aftertouch [this message]\n                       (if (zero? (:velocity message))\n                         (do (when holding\n                               (with-show (:show controller)\n                                 (show/end-effect! (:key cue) :when-id id)))\n                             :done)\n                         (doseq [v (:variables cue)]\n                           (when (:velocity v)\n                             (cues/set-cue-variable! cue v\n                                                     (controllers/value-for-velocity v (:velocity message))\n                                                     :show (:show controller) :when-id id)))))\n                     (handle-pitch-bend [this message])))))))))\n\n(defn- note-on-received\n  \"Process a note-on message which was not handled by an interface\n  overlay.\"\n  [controller message]\n  (let [note (:note message)]\n    (when (and (<= 1 (rem note 10) 8) (<= 1 (quot note 10) 8))\n      (cue-grid-pressed controller note (:velocity message)))))\n\n(defn- note-off-received\n  \"Process a note-off message which was not handled by an interface\n  overlay.\"\n  [controller message]\n  (case (:note message)\n\n    ;; Something we don't care about\n    nil))\n\n(defn- midi-received\n  \"Called whenever a MIDI message is received from the controller\n  while the mapping is active; takes whatever action is appropriate.\"\n  [controller message]\n  ;;(timbre/info message)\n  (when-not (controllers/overlay-handled? (:overlays controller) message)\n    (when (= (:command message) :control-change)\n      (control-change-received controller message))\n    (when (= (:command message) :note-on)\n      (note-on-received controller message))\n    (when (= (:command message) :note-off)\n      (note-off-received controller message))))\n\n(defn- start-interface\n  \"Set up the thread which keeps the user interface up to date.\"\n  [controller]\n  (clear-interface controller)\n  (amidi/add-device-mapping (:port-in controller) @(:midi-handler controller))\n  (reset! (:task controller) (at-at/every (:refresh-interval controller)\n                                          #(update-interface controller)\n                                          controllers/pool\n                                          :initial-delay 10\n                                          :desc \"Launchpad Pro interface update\")))\n\n(defn- welcome-frame\n  \"Render a frame of the welcome animation, or if it is done, start\n  the main interface update thread, and terminate the task running the\n  animation.\"\n  [controller counter task]\n  (try\n    (cond\n      (< @counter 8)\n      (doseq [y (range 0 (inc @counter))]\n        (let [color (colors/create-color\n                     :h 0 :s 0 :l (max 10 (- 75 (/ (* 50 (- @counter y)) 6))))]\n          (set-pad-color controller 3 y color)\n          (set-pad-color controller 4 y color)))\n\n      (< @counter 12)\n      (doseq [x (range 0 (- @counter 7))\n              y (range 0 8)]\n        (let [color (colors/create-color\n                     :h 340 :s 100 :l (- 75 (* (- @counter 8 x) 20)))]\n          (set-pad-color controller (- 3 x) y color)\n          (set-pad-color controller (+ 4 x) y color)))\n\n      (< @counter 15)\n      (doseq [y (range 0 8)]\n        (let [color (colors/create-color\n                     :h (* 13 (- @counter 11)) :s 100 :l 50)]\n          (set-pad-color controller (- @counter 7) y color)\n          (set-pad-color controller (- 14 @counter) y color)))\n\n      (= @counter 15)\n      (show-labels controller (colors/create-color :cyan))\n\n      (< @counter 24)\n      (doseq [x (range 0 8)]\n        (let [lightness-index (if (> x 3) (- 7 x) x)\n              lightness ([10 30 50 70] lightness-index)\n              color (colors/create-color\n                     :h (+ 60 (* 40 (- @counter 18))) :s 100 :l lightness)]\n          (set-pad-color controller x (- 23 @counter) color)))\n\n      (= @counter 24)\n      (show-labels controller (colors/create-color :blue))\n\n      (< @counter 33)\n      (doseq [x (range 0 8)]\n        (set-pad-color controller x (- 32 @counter) button-off-color))\n\n      :else\n      (do\n        (start-interface controller)\n        (at-at/kill @task)))\n    (catch Throwable t\n      (warn t \"Animation frame failed\")))\n\n  (swap! counter inc))\n\n(defn- welcome-animation\n  \"Provide a fun animation to make it clear the Launchpad Pro is online.\"\n  [controller]\n  (let [counter (atom 0)\n        task (atom nil)]\n    (reset! task (at-at/every 50 #(welcome-frame controller counter task)\n                              controllers/pool))))\n\n(defn deactivate\n  \"Deactivates a controller interface, killing its update thread and\n  removing its MIDI listeners. If `:disconnected` is passed with a\n  `true` value, it means that the controller has already been removed\n  from the MIDI environment, so no effort will be made to clear its\n  display or take it out of User mode.\n\n  In general you will not need to call this function directly; it will\n  be dispatched to via [[controllers/deactivate]] when that is called\n  with a controller binding implementation from this namespace. It is\n  also called automatically when one of the controllers being used\n  disappears from the MIDI environment.\"\n  [controller & {:keys [disconnected] :or {disconnected false}}]\n  {:pre (= ::controller (type controller))}\n  (swap! (:task controller)\n         (fn [task]\n           (when task\n             (at-at/kill task)\n             (show/unregister-grid-controller @(:grid-controller-impl controller))\n             (doseq [f @(:move-listeners controller)] (f @(:grid-controller-impl controller) :deactivated))\n             (reset! (:move-listeners controller) #{})\n             (amidi/remove-device-mapping (:port-in controller) @(:midi-handler controller))\n\n             (when-not disconnected\n               (Thread/sleep 35) ; Give the UI update thread time to shut down\n               (clear-interface controller)\n               ;; Leave the User button bright, in case the user has Live\n               ;; running and wants to be able to see how to return to it.\n               (set-led-color controller (:user-mode control-buttons) (colors/create-color :white)))\n\n             ;; Cancel any UI overlays which were in effect\n             (reset! (:overlays controller) (controllers/create-overlay-state))\n\n             ;; And finally, note that we are no longer active.\n             (controllers/remove-active-binding controller))\n           nil)))\n\n(def port-filter\n  \"Because the Launchpad Pro registers multiple ports with the MIDI\n  environment, we need to be sure to bind only to the Standalone port.\n  This filter is used with [[filter-devices]] to screen out any port\n  that does not seem to be the Standalone port. If port names are\n  assigned differently on your operating system, you may need to\n  change this (and please open a Pull Request); this filter seems to\n  work for Mac OS X and Windows.\"\n  [\"Standalone Port\" \"MIDIIN2\" \"MIDIOUT2\"])\n\n(defn- recognize\n  \"Returns the controller's device ID if `message` is a response\n  from [[controllers/identify]] which marks it as a Novation Launchpad\n  Pro, and the ports are Standalone ports.\"\n  [message port-in port-out]\n  (when (and (= (take 5 (drop 4 (:data message))) '(0 32 41 81 0))\n             (= 2 (count (amidi/filter-devices port-filter [port-in port-out]))))\n    (int (aget (:data message) 1))))\n\n;; Register our recognition function and rich binding with the\n;; controller manager.\n(swap! controllers/recognizers assoc ::controller recognize)\n\n(defmethod controllers/deactivate ::controller\n  [controller & {:keys [disconnected] :or {disconnected false}}]\n  (deactivate controller :disconnected disconnected))\n\n(defmethod controllers/bind-to-show-impl ::controller\n  [kind show port-in port-out device & {:keys [refresh-interval display-name new-connection]\n           :or   {refresh-interval (/ 1000 15)\n                  display-name     \"Launchpad Pro\"}}]\n  {:pre [(some? show)]}\n  (let [shift-mode (atom false)\n        controller\n        (with-meta\n          {:display-name         display-name\n           :device-id            device\n           :show                 show\n           :origin               (atom [0 0])\n           :refresh-interval     refresh-interval\n           :port-in              port-in\n           :port-out             port-out\n           :task                 (atom nil)\n           :last-text-buttons    (atom {})\n           :next-text-buttons    (atom {})\n           :last-grid-pads       (atom nil)\n           :next-grid-pads       (atom nil)\n           :shift-mode           shift-mode\n           :stop-mode            (atom false)\n           :midi-handler         (atom nil)\n           :tempo-tap-handler    (tempo/create-show-tempo-tap-handler show :shift-fn (fn [] @shift-mode))\n           :last-marker          (atom nil)\n           :overlays             (controllers/create-overlay-state)\n           :move-listeners       (atom #{})\n           :grid-controller-impl (atom nil)}\n          {:type ::controller})]\n    (reset! (:midi-handler controller) (partial midi-received controller))\n    (reset! (:grid-controller-impl controller)\n            (reify controllers/IGridController\n              (display-name [_this] (:display-name controller))\n              (controller [_this] controller)\n              (physical-height [_this] 8)\n              (physical-width [_this] 8)\n              (current-bottom [_this] (@(:origin controller) 1))\n              (current-bottom [_this y] (move-origin controller (assoc @(:origin controller) 1 y)))\n              (current-left [_this] (@(:origin controller) 0))\n              (current-left [_this x] (move-origin controller (assoc @(:origin controller) 0 x)))\n              (add-move-listener [_this f] (swap! (:move-listeners controller) conj f))\n              (remove-move-listener [_this f] (swap! (:move-listeners controller) disj f))))\n    (if new-connection\n      (at-at/after 3000 (fn []\n                          (set-layout controller)\n                          (clear-interface controller)\n                          (start-interface controller)) controllers/pool :desc \"Start Launchpad Pro interface\")\n      (do\n        (set-layout controller)\n        (clear-interface controller)\n        (welcome-animation controller)))\n    (controllers/add-active-binding controller)\n    (show/register-grid-controller @(:grid-controller-impl controller))\n    (amidi/add-disconnected-device-handler! port-in #(deactivate controller :disconnected true))\n    controller))\n\n(defn bind-to-show\n  \"*Deprecated in favor of the shared [[controllers/bind-to-show]]\n  implementation.*\n\n  Establish a connection to the Novation Launchpad Pro, for managing\n  the given show.\n\n  Initializes the display and starts the UI updater thread. Since\n  SysEx messages are required for updating the display, if you are on\n  a Mac, Afterglow\n  embeds [CoreMIDI4J](https://github.com/DerekCook/CoreMidi4J) to\n  provide a working implementation.\n\n  If you have more than one Launchpad connected, or have renamed how\n  it appears in your list of MIDI devices, you need to supply a value\n  after `:device-filter` which identifies the ports to be used to\n  communicate with the Launchpad you want this function to use. The\n  values returned by [[afterglow.midi/open-inputs-if-needed!]]\n  and [[afterglow.midi/open-outputs-if-needed!]] will be searched, and\n  the first port that matches with [[filter-devices]] will be used.\n\n  The controller will be identified in the user interface (for the\n  purposes of linking it to the web cue grid) as \\\"Launchpad Pro\\\". If\n  you would like to use a different name (for example, if have more\n  than one Launchpad), you can pass in a custom value after\n  `:display-name`.\n\n  If you want the user interface to be refreshed at a different rate\n  than the default of fifteen times per second, pass your desired\n  number of milliseconds after `:refresh-interval`.\n\n  If you would like to skip the startup animation (for example because\n  the device has just powered on and run its own animation), pass\n  `true` after `:skip-animation`.\"\n  {:deprecated \"0.2.1\"}\n  [show & {:keys [device-filter refresh-interval display-name skip-animation]\n           :or   {device-filter    \"Standalone Port\"\n                  refresh-interval (/ 1000 15)\n                  display-name     \"Launchpad Pro\"}}]\n  (controllers/bind-to-show device-filter :refresh-interval refresh-interval :display-name display-name\n                            :new-connection skip-animation))\n\n(defn auto-bind\n  \"*Deprecated in favor of the shared [[controllers/auto-bind]]\n  implementation.*\n\n  Watches for a Novation Launchpad Pro controller to be connected,\n  and as soon as it is, binds it to the specified show\n  using [[bind-to-show]]. If that controller ever gets disconnected,\n  it will be re-bound once it reappears. Returns a watcher structure\n  which can be passed to [[deactivate]] if you would like to\n  stop it watching for reconnections. The underlying controller\n  mapping, once bound, can be accessed through the watcher's\n  `:controller` key.\n\n  If you have more than one Launchpad Pro that might beconnected, or\n  have renamed how it appears in your list of MIDI devices, you need\n  to supply a value after `:device-filter` which identifies the ports\n  to be used to communicate with the Launchpad you want this function\n  to use. The values returned\n  by [[afterglow.midi/open-inputs-if-needed!]]\n  and [[afterglow.midi/open-outputs-if-needed!]] will be searched, and\n  the first port that matches using [[filter-devices]] will be used.\n\n  Once bound, the controller will be identified in the user\n  interface (for the purposes of linking it to the web cue grid) as\n  \\\"Launchpad Pro\\\". If you would like to use a different name (for\n  example, if you have more than one Launchpad), you can pass in a\n  custom value after `:display-name`.\n\n  If you want the user interface to be refreshed at a different rate\n  than the default of fifteen times per second, pass your desired\n  number of milliseconds after `:refresh-interval`.\"\n  {:deprecated \"0.2.1\"}\n  [show & {:keys [device-filter refresh-interval display-name]\n           :or {device-filter \"Standalone Port\"\n                refresh-interval (/ 1000 15)\n                display-name \"Launchpad Pro\"}}]\n  (controllers/auto-bind show device-filter :refresh-interval refresh-interval :display-name display-name))\n"
  },
  {
    "path": "src/afterglow/controllers/tempo.clj",
    "content": "(ns afterglow.controllers.tempo\n  \"Provides support for easily implementing tap-tempo and shift\n  buttons on any MIDI controller.\"\n  {:author \"James Elliott\"}\n  (:require [overtone.midi :as midi]\n            [afterglow.controllers :as controllers]\n            [afterglow.midi :as amidi]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [*show* with-show]]\n            [taoensso.timbre :as timbre]\n            [taoensso.truss :as truss :refer (have have! have?)]))\n\n(defn create-show-tempo-tap-handler\n  \"Returns a function that provides higher level tempo tap support for a show,\n  based on the sync mode of the show metronome. Call the returned\n  function whenever the user has tapped your tempo button.\n\n  * If the show's sync mode is manual, this will invoke a low-level\n  metronome tap-tempo handler to align the beat to the tap, and (if\n  three or more taps occur within two seconds of each other) adjust\n  the metronome tempo.\n\n  * If the show's sync mode is MIDI, calling the returned function will\n  align the current beat to the tap.\n\n  * If the show's sync mode is DJ Link or Traktor Beat phase (so beats\n  are already automatically aligned), calling the returned function\n  will align the current beat to be a down beat (first beat of a bar).\n\n  If you have set up a button on your controller to act like the shift\n  button on one of the full-featured grid controllers, you can pass in\n  a function with `:shift-fn` that returns `true` when that the shift\n  button is held down. Whenever that function returns `true` for a\n  tempo tap, the returned tap handler function will synchronize at the\n  next higher level. (In other words, if it was going to be a tempo or\n  beat tap, it would be treated as a bar tap, and what would normally\n  be a bar tap would be promoted to start a phrase.) If the metronome\n  is not locked into a beat grid, when you set the position of a bar\n  by shift-tapping, the beat is also aligned with the tap.\n\n  Returns a map describing the result of the current tempo tap.\"\n  [show & {:keys [shift-fn] :or {shift-fn (constantly false)}}]\n  (let [metronome     (:metronome show)\n        tempo-handler (amidi/create-tempo-tap-handler metronome)]\n    (fn []\n      (with-show show\n        (let [base-level     (:level (show/sync-status))\n              also-move-beat (or (nil? base-level) (= :bpm base-level))\n              level          (if (shift-fn)\n                               (case base-level\n                                 nil   :beat\n                                 :bpm  :beat\n                                 :beat :bar\n                                 :bar  :phrase\n                                 base-level)\n                               base-level)]\n          (case level\n            nil   (do (tempo-handler)\n                      {:tempo \"adjusting\"})\n            :bpm  (do (rhythm/metro-beat-phase metronome 0)\n                      {:started \"beat\"})\n            :beat (do (rhythm/metro-bar-start metronome (rhythm/metro-bar metronome))\n                      (when also-move-beat (rhythm/metro-beat-phase metronome 0))\n                      {:started \"bar\"})\n            :bar  (do (rhythm/metro-phrase-start metronome (rhythm/metro-phrase metronome))\n                      {:started \"phrase\"})\n            (let [warning (str \"Don't know how to tap tempo for sync type\" level)]\n              (timbre/warn warning)\n              {:error warning})))))))\n\n(defn add-midi-control-to-tempo-mapping\n  \"Sets up a controller pad or button to act as a sync-aware Tap Tempo\n  button for the default metronome in [[*show*]]. Whenever the\n  specified note (when `kind` is `:note`) or controller-change (when\n  `kind` is `:control`) message is received with a non-zero\n  velocity (or control value), the appropriate tempo adjustment action\n  is taken.\n\n  * If the show's sync mode is manual, this will invoke a low-level metronome\n  tap-tempo handler to adjust the metronome tempo.\n\n  * If the show's sync mode is MIDI, calling the returned function will\n  align the current beat to the tap.\n\n  * If the show's sync mode is DJ Link or Traktor Beat phase (so beats\n  are already automatically aligned), calling the returned function\n  will align the current beat to be a down beat (first beat of a bar).\n\n  The device to be mapped is identified by `device-filter`. The first\n  input port which matches using [[filter-devices]] will be used.\n\n  Afterglow will attempt to provide feedback by flashing the pad or\n  button on each beat sending note on/off or control-change values to\n  the same controller. The note velocities or control values used can\n  be changed by passing in different values with `:feedback-on` and\n  `:feedback-off`, and this behavior can be suppressed entirely by\n  passing `false` with `:feedback-on`.\n\n  If you have set up a button on your controller to act like the shift\n  button on one of the full-featured grid controllers, you can pass in\n  a function with `:shift-fn` that returns `true` when that the shift\n  button is held down. Whenever that function returns `true` for a\n  tempo tap, the returned tap handler function will synchronize at the\n  next higher level. (In other words, if it was going to be a tempo\n  tap, it would be treated as a beat tap; what would normally be a\n  beat tap would be treated as a bar tap, and a bar tap would be\n  promoted to start a phrase.) When you map a shift button\n  using [[add-midi-control-to-shift-mapping]], it gives you a function\n  that is suitable for use with `:shift-fn` as the value of the\n  `:state` key in the map it returns.\n\n  Returns the tempo-mapping function which can be passed\n  to [[remove-midi-control-to-tempo-mapping]] if you ever want to stop\n  the MIDI control or note from affecting the metronome in the\n  future.\"\n  [device-filter channel kind note & {:keys [feedback-on feedback-off shift-fn]\n                                      :or {feedback-on 127 feedback-off 0 shift-fn (constantly false)}}]\n  {:pre [(have? some? *show*) (have? #{:control :note} kind) (have? some? device-filter)\n         (have? integer? channel) (have? #(<= 0 % 15) channel) (have? integer? note) (have? #(<= 0 % 127) note)\n         (have? #(or (not %) (and (integer? %) (<= 0 % 127))) feedback-on)\n         (have? integer? feedback-off) (have? #(<= 0 % 127) feedback-off)\n         (have? ifn? shift-fn)]}\n  (let [feedback-device (when feedback-on (amidi/find-midi-out device-filter))\n        tap-handler (create-show-tempo-tap-handler *show* :shift-fn shift-fn)\n        midi-handler (fn [message]\n                       (when (pos? (:velocity message))\n                         (tap-handler)))]\n    (when feedback-device  ; Set up to give feedback as cue activation changes\n      (controllers/add-beat-feedback! (:metronome *show*) feedback-device channel kind note\n                                      :on feedback-on :off feedback-off))\n    (case kind\n      :control (amidi/add-control-mapping device-filter channel note midi-handler)\n      :note (amidi/add-note-mapping device-filter channel note midi-handler))\n    midi-handler))\n\n(defn remove-midi-control-to-tempo-mapping\n  \"Undoes the effect of [[add-midi-control-to-tempo-mapping]]. You\n  must pass the value that was returned by that function as the\n  argument `f`.\"\n  [device-filter channel kind note f]\n  {:pre [(have? some? *show*) (have? #{:control :note} kind) (have? some? device-filter)\n         (have? integer? channel) (have? #(<= 0 % 15) channel) (have? integer? note) (have? #(<= 0 % 127) note)\n         (have? ifn? f)]}\n  (let [feedback-device (amidi/find-midi-out device-filter)]\n    (when feedback-device\n      (controllers/clear-beat-feedback! (:metronome *show*) feedback-device channel kind note))\n    (case kind\n      :control (amidi/remove-control-mapping device-filter channel note f)\n      :note (amidi/remove-note-mapping device-filter channel note f))\n    nil))\n\n(defn add-midi-control-to-shift-mapping\n  \"Sets up a controller pad or button to act as a shift button which\n  can be used to modify other mappings. The shift state is entered\n  whenever the specified note (when `kind` is `:note`) or\n  controller-change (when `kind` is `:control`) message is received\n  with a non-zero velocity (or control value) on the specified\n  `channel`. The shift state is ended whenever a matching note-off or\n  controller-change message with velocity zero is received.\n\n  The device to be mapped is identified by `device-filter`. The first\n  input port which matches using [[filter-devices]] will be used.\n\n  Afterglow will attempt to provide feedback by lighting the pad or\n  button when it is held down by sending note on/off or control-change\n  values to the same controller. The note velocities or control values\n  used can be changed by passing in different values with\n  `:feedback-on` and `:feedback-off`, and this behavior can be\n  suppressed entirely by passing `false` with `:feedback-on`.\n\n  Returns a map containing an entry `:state` whose value is a function\n  that can be called to check the state of the shift button, returning\n  `true` whenever it is held down. There are other entries in the map\n  which are used for the mapping's own purposes. Pass the entire map\n  to [[remove-midi-control-to-shift-mapping]] if you ever want to stop\n  the MIDI control or note from acting like a shift button.\"\n  [device-filter channel kind note & {:keys [feedback-on feedback-off]\n                                      :or {feedback-on 127 feedback-off 0}}]\n  {:pre [(have? #{:control :note} kind) (have? some? device-filter)\n         (have? integer? channel) (have? #(<= 0 % 15) channel) (have? integer? note) (have? #(<= 0 % 127) note)\n         (have? #(or (not %) (and (integer? %) (<= 0 % 127))) feedback-on)\n         (have? integer? feedback-off) (have? #(<= 0 % 127) feedback-off)]}\n  (let [feedback-device (when feedback-on (amidi/find-midi-out device-filter))\n        state (atom false)\n        midi-handler (fn [message]\n                       (reset! state (and (pos? (:velocity message))\n                                          (or (= :control kind)\n                                              (= :note-on (:command message)))))\n                       (when feedback-device\n                         (if (= :control kind)\n                           (midi/midi-control feedback-device note (if @state feedback-on feedback-off) channel)\n                           (if @state\n                             (midi/midi-note-on feedback-device note feedback-on channel)\n                             (midi/midi-note-off feedback-device note channel)))))]\n    (case kind\n      :control (amidi/add-control-mapping device-filter channel note midi-handler)\n      :note (amidi/add-note-mapping device-filter channel note midi-handler))\n    (with-meta\n      {:state (fn [] @state)\n       :handler midi-handler\n       :clear-handler (fn []\n                        (when feedback-device\n                          (if (= :control kind)\n                            (midi/midi-control feedback-device note feedback-off channel)\n                            (midi/midi-note-off feedback-device note channel))))}\n      {:type :midi-shift-mapping})))\n\n(defn remove-midi-control-to-shift-mapping\n  \"Undoes the effect of [[add-midi-control-to-tempo-mapping]]. You\n  must pass the value that was returned by that function as the\n  argument `mapping`.\"\n  [device-filter channel kind note mapping]\n  {:pre [(have? #{:control :note} kind) (have? some? device-filter)\n         (have? integer? channel) (have? #(<= 0 % 15) channel) (have? integer? note) (have? #(<= 0 % 127) note)\n         (have? #(= (type %) :midi-shift-mapping) mapping)]}\n  (case kind\n    :control (amidi/remove-control-mapping device-filter channel note (:handler mapping))\n    :note (amidi/remove-note-mapping device-filter channel note (:handler mapping)))\n  ((:clear-handler mapping))\n  nil)\n"
  },
  {
    "path": "src/afterglow/controllers.clj",
    "content": "(ns afterglow.controllers\n  \"Provides shared services for all controller implementations.\"\n  {:author \"James Elliott\"}\n  (:require [overtone.at-at :as at-at]\n            [overtone.midi :as midi]\n            [afterglow.midi :as amidi]\n            [afterglow.rhythm :as rhythm]\n            [taoensso.timbre :as timbre]\n            [taoensso.truss :as truss :refer [have have! have?]])\n  (:import [java.util.concurrent LinkedBlockingDeque]))\n\n(defonce\n  ^{:doc \"Provides thread scheduling for all controller user interface updates.\"}\n  pool\n  (at-at/mk-pool))\n\n(def minimum-bpm\n  \"The lowest BPM value which controllers are allowed to set.\"\n  20)\n\n(def maximum-bpm\n  \"The highest BPM value which controllers are allowed to set.\"\n  200)\n\n(defonce ^:private ^{:doc \"The queue used to serialize auto-binding\n  attempts, so that only one happens at a time, without backing up the\n  main MIDI event processing queue. Although we allocate a capacity of\n  100 elements, it is expected that the queue will be empty most of\n  the time, and only collect an input port or two when a new device is\n  connected, and all input ports briefly when [[auto-bind]] is\n  invoked.\"}\n  bind-queue\n  (LinkedBlockingDeque. 100))\n\n(declare bind-to-show)\n\n(defonce ^:private ^{:doc \"The thread used to run [[bind-bottleneck]]\n  and serialize the auto-binding of potential controllers that have\n  been found.\"}\n  auto-bind-thread\n  (atom nil))\n\n(defn- match-input-output-pair\n  \"Given a MIDI input or output port, returns a device filter that\n  will match both that port and the corresponding output port.\n  Trickier than it sounds because on Windows, when there are multiple\n  ports for a given device, the inputs and outputs are assigned names\n  that differ from each other, and the descriptions never match.\"\n  [port-in]\n  [port-in  ; We always match the input port\n   (if (clojure.string/starts-with? (clojure.string/lower-case (System/getProperty \"os.name\")) \"windows\")\n     (fn [port]  ; On Windows only look at the name, and transform as needed\n       (= (:name port) (clojure.string/replace-first (:name port-in) \"MIDIIN\" \"MIDIOUT\")))\n     (fn [port]  ; On other platforms, look for matching names and descriptions\n       (and (= (:name port) (:name port-in))\n            (= (:description port) (:description port-in)))))])\n\n(defn- bind-bottleneck\n  \"Takes potential auto-bind devices from the incoming queue one by\n  one and tries binding to them. This is used to make sure that we are\n  only trying one device at a time, taking as long as it needs,\n  without backing up the main MIDI event handler thread.\n\n  Entries on the cue are a tuple containing the device which has been\n  identified as a potential new controller port, the show to which it\n  should be bound if it turns out to be suitable, and any optional\n  arguments which should be passed along to [[bind-to-show]].\n\n  If the special flag value `:done` is passed as the third element in\n  the tuple, it signals the loop to end, because auto-binding has been\n  canceled.\"\n  []\n  (loop [[device show args] (.take bind-queue)]\n    (when device\n      (timbre/info \"Attempting auto-binding to potential controller\" device args)\n      (try\n        (apply bind-to-show (concat [show (match-input-output-pair device)]\n                                    (flatten (seq args))))\n        (catch Throwable t\n          (timbre/error t \"Problem binding to controller\"))))\n\n    ;; Wait for the next candidate device, unless we have been told to end\n    (when-not (= args :done)\n      (recur (.take bind-queue))))\n  (swap! auto-bind-thread (constantly nil)))\n\n(defn- start-auto-bind-thread\n  \"Creates the thread used to serialize auto-bind attempts.\"\n  [old-thread]\n  (or old-thread\n      (doto (Thread. bind-bottleneck \"auto-bind bottleneck\")\n        (.setDaemon true)\n        (.start))))\n\n(defonce ^{:private true\n           :doc \"Lists all the built-in controller implementations\n           that need to be loaded, so they can register their\n           recognizers. This needs to happen after the namespace\n           itself loads, to avoid circular dependency issues. Once\n           that is done, this atom will be set to `nil`. Functions\n           like [[bind-to-show]] and [[auto-bind]] which rely on\n           controller implementations being registered must call\n           [[load-built-in-controllers]] to ensure this has\n           happened.\"}\n  built-in-controllers\n  (atom '[afterglow.controllers.ableton-push afterglow.controllers.ableton-push-2\n          afterglow.controllers.launchpad-pro afterglow.controllers.launchpad-mk2\n          afterglow.controllers.launchpad-mini]))\n\n(defn- load-built-in-controllers\n  \"Makes sure that the namespaces defining the grid controllers that\n  Afterglow supports natively have been loaded. Because of circular\n  dependency issues, this has to wait until after the namespace itself\n  has been loaded. Functions like [[bind-to-show]] and [[auto-bind]]\n  which rely on controller implementations need to call this function\n  to ensure loading has occurred. After the first call, the list of\n  namespaces will be replaced by `nil`, so it will no longer do\n  anything.\"\n  []\n  (swap! built-in-controllers\n         (fn [namespaces]\n           (doseq [n namespaces]\n             (require n)))))\n\n(defonce\n  ^{:private true\n    :doc \"Protect protocols against namespace reloads\"}\n  _PROTOCOLS_\n  (do\n(defprotocol IGridController\n  \"A controller which provides an interface for a section of the cue)\n  grid, and which can be linked to the web interface so they scroll in\n  unison.\"\n  (display-name [this]\n  \"Returns the name by which the controller can be identified in\n  user interfaces.\")\n  (controller [this]\n    \"Returns the underlying controller implementation, in case the show can\n  do fancier things with certain kinds of controllers.\")\n  (physical-height [this]\n  \"Returns the height of the cue grid on the controller.\")\n  (physical-width [this]\n  \"Returns the width of the cue grid on the controller.\")\n  (current-bottom [this] [this y]\n  \"Returns the cue grid row currently displayed at the bottom of the\n  controller, or sets it.\")\n  (current-left [this] [this x]\n  \"Returns the cue grid column currently displayed at the left of\n  the controller, or sets it.\")\n  (add-move-listener [this f]\n  \"Registers a function that will be called whenever the controller's\n  viewport on the overall cue grid is moved, or the controller is\n  deactivated. The function will be called with two arguments, the\n  controller and a keyword which will be either :move or :deactivated.\n  In the latter case, the function will never be called again.\")\n  (remove-move-listener [this f]\n  \"Unregisters a move listener function so it will no longer be\n  called when the controller's origin is moved.\"))\n\n(defprotocol IOverlay\n  \"An activity which takes over part of the user interface\n  while it is active.\"\n  (captured-controls [this]\n  \"Returns the MIDI control-change events that will be consumed by\n  this overlay while it is active, a set of integers.\")\n  (captured-notes [this]\n  \"Returns the MIDI note events that will be consumed by this overlay\n  while it is active, a set of integers.\")\n  (adjust-interface [this snapshot]\n  \"Set values for the next frame of the controller interface, however\n  that may be done; return a falsey value if the overlay is finished\n  and should be removed. The `snapshot` is\n  an [[afterglow.rhythm/ISnapshot]] that specifies the instant in\n  musical time at which the interface is being rendered, so this\n  overlay can be drawn in sync with the rest of the interface.\")\n  (handle-control-change [this message]\n  \"Called when a MIDI control-change event matching the\n  captured-controls lists has been received. Return a truthy value if\n  the overlay has consumed the event, so it should not be processed\n  further. If the special value `:done` is returned, it further\n  indicates the overlay is finished and should be removed.\")\n  (handle-note-on [this message]\n  \"Called when a MIDI note-on event matching the captured-notes lists\n  has been received. Return a truthy value if the overlay has consumed\n  the event, so it should not be processed further. If the special\n  value `:done` is returned, it further indicates the overlay is\n  finished and should be removed.\")\n  (handle-note-off [this message]\n  \"Called when a MIDI note-off event matching the captured-notes lists\n  has been received. Return a truthy value if the overlay has consumed\n  the event, so it should not be processed further. If the special\n  value `:done` is returned, it further indicates the overlay is\n  finished and should be removed.\")\n  (handle-aftertouch [this message]\n  \"Called when a MIDI aftertouch event matching the captured-notes\n  lists has been received. Return a truthy value if the overlay has\n  consumed the event, so it should not be processed further. If the\n  special value `:done` is returned, it further indicates the overlay\n  is finished and should be removed.\")\n  (handle-pitch-bend [this message]\n  \"Called when a MIDI pitch-bend event has been received. Return a\n  truthy value if the overlay has consumed the event, so it should not\n  be processed further. If the special value `:done` is returned, it\n  further indicates the overlay is finished and should be\n  removed.\"))))\n\n(defn cue-grid\n  \"Return a two dimensional arrangement for launching and monitoring\n  cues, suitable for both a web interface and control surfaces with a\n  pad grid. Cues are laid out with (0, 0) being the bottom left\n  corner. The width of the grid is the highest x coordinate of a cue,\n  and the height is the highest y coordinate.\"\n  []\n  (with-meta\n    {:dimensions (ref [0 0])\n\n     ;; For now using a sparse grid in the form of a map whose keys are\n     ;; the cue coordinates, and whose values are the cues. If performance\n     ;; dictates, can change to nested vectors or something else later.\n     :cues (ref {})\n\n     ;; Also track any non-grid controllers which have bound controls or\n     ;; notes to cues and want feedback as they activate and deactivate.\n     ;; A nested set of maps: The first key is a tuple of the grid coordinates.\n     ;; The next map is keyed by the tuple [MidiDevice channel note kind]\n     ;; identifying where the feedback should be sent, and the values\n     ;; are a tuple of [feedback-on feedback-off device disconnect-handler],\n     ;; the MIDI values to send as feedback when the cue turns on or off,\n     ;; the overtone.midi :midi-device map corresponding to the MidiDevice\n     ;; object (for convenience in sending messages), and the handler function\n     ;; that was registered to clear the feedback in case the device ever got\n     ;; disconnected. It is included so that it can be unregistered if the user\n     ;; explicitly cancels the feedback.\n\n     :midi-feedback (ref {})\n\n     ;; Also allow arbitrary functions to be called when cues change state.\n     :fn-feedback (ref {})\n\n     ;; Track saved cue variables to be reapplied the next time the cue is run.\n     ;; A map indexed in the same way as :cues, whose values are the map of\n     ;; variable keys and values.\n     :saved-vars (ref {})\n     }\n    {:type :cue-grid}))\n\n(defn cue-at\n  \"Find the cue, if any, at the specified coordinates.\"\n  [grid x y]\n  (get @(:cues grid) [x y]))\n\n(defn grid-dimensions\n  \"Return the current dimensions of the cue grid.\"\n  [grid]\n  @(:dimensions grid))\n\n(defn grid-width\n  \"Return the current width of the cue grid.\"\n  [grid]\n  (get (grid-dimensions grid) 0))\n\n(defn grid-height\n  \"Return the current height of the cue grid.\"\n  [grid]\n  (get (grid-dimensions grid) 1))\n\n(defn clear-cue!\n  \"Removes any cue which existed at the specified coordinates in the\n  cue grid. If one was there, updates the grid dimensions if needed.\n  Also clears any variables that were saved for that cue.\"\n  [grid x y]\n  {:pre [(have? integer? x) (have? integer? y) (have? #(not (neg? %)) x) (have? #(not (neg? %)) y)\n         (have? #(= (type %) :cue-grid) grid)]}\n  (dosync\n   (when (some? (get @(:cues grid) [x y]))\n     (alter (:cues grid) dissoc [x y])\n     (when (or (= x (grid-width grid)) (= y (grid-height grid)))\n       (ref-set (:dimensions grid) (reduce (fn [[width height] [x y]]\n                                             [(max width x) (max height y)])\n                                           [0 0] (keys @(:cues grid)))))\n     (alter (:saved-vars grid) dissoc [x y]))))\n\n(defn set-cue!\n  \"Puts the supplied cue at the specified coordinates in the cue grid.\n  Replaces any cue which formerly existed at that location, and clears\n  any variables that might have been saved for it. If `cue` is nil,\n  delegates to clear-cue!\"\n  [grid x y cue]\n  {:pre [(have? integer? x) (have? integer? y) (have? #(not (neg? %)) x) (have? #(not (neg? %)) y)\n         (have? #(= (type %) :cue-grid) grid)]}\n  (if (nil? cue)\n    (clear-cue! grid x y)\n    (dosync\n     (alter (:cues grid) assoc [x y] cue)\n     (alter (:saved-vars grid) dissoc [x y])\n     (ref-set (:dimensions grid) [(max x (grid-width grid)) (max y (grid-height grid))]))))\n\n(defn save-cue-vars!\n  \"Save a set of variable starting values to be applied when launching\n  a cue. If there is no cue at the specified grid location, nothing\n  will be saved.\"\n  [grid x y vars]\n  (dosync\n   (when (some? (get (ensure (:cues grid)) [x y]))\n         (alter (:saved-vars grid) assoc [x y] vars))))\n\n(defn clear-saved-cue-vars!\n  \"Remove any saved starting values assigned to the cue at the\n  specified grid location.\"\n  [grid x y]\n  (dosync\n   (alter (:saved-vars grid) dissoc [x y])))\n\n(defn cue-vars-saved-at\n  \"Return the saved starting values, if any, assigned to the cue at\n  the specified grid location.\"\n  [grid x y]\n  (get @(:saved-vars grid) [x y]))\n\n(defn clear-cue-feedback!\n  \"Ceases sending the specified non-grid MIDI controller feedback\n  events when the cue grid location activates or deactivates,\n  returning the feedback values that had been in place if there were\n  any.\"\n  [grid x y device channel kind note]\n  {:pre [(have? integer? x) (have? integer? y) (have? #(not (neg? %)) x) (have? #(not (neg? %)) y)\n         (have? #(= (type %) :midi-device) device) (have? #(= (type %) :cue-grid) grid)\n         (have? #{:control :note} kind)]}\n  (dosync\n   (let [entry (get (ensure (:midi-feedback grid)) [x y])\n         former (get entry [(:device device) channel note kind])\n         [_ _ _ disconnect-handler] former]\n     (alter (:midi-feedback grid) assoc [x y] (dissoc entry [(:device device) channel note kind]))\n     (when (some? disconnect-handler)\n       (amidi/remove-disconnected-device-handler! device disconnect-handler))\n     former)))\n\n(defn add-cue-feedback!\n  \"Arranges for the specified non-grid MIDI controller to receive\n  feedback events when the cue grid location activates or\n  deactivates.\"\n  [grid x y device channel kind note & {:keys [on off] :or {on 127 off 0}}]\n  {:pre [(have? integer? x) (have? integer? y) (have? #(not (neg? %)) x) (have? #(not (neg? %)) y)\n         (have? #(= (type %) :midi-device) device) (have? #(= (type %) :cue-grid))\n         (have? #{:control :note} kind) (have? integer? on) (have? integer? off)\n         (have? #(<= 0 % 127) on) (have? #(<= 0 % 127) off)]}\n  (letfn [(disconnect-handler []\n            (clear-cue-feedback! grid x y device channel kind note))]\n    (amidi/add-disconnected-device-handler! device disconnect-handler)\n    (dosync\n     (alter (:midi-feedback grid) assoc-in [[x y] [(:device device) channel note kind]]\n            [on off device disconnect-handler])))\n  nil)\n\n(defn add-cue-fn!\n  \"Arranges for the supplied function to be called when the cue grid\n  location activates or deactivates. It will be called with three\n  arguments: the first, a keyword identifying the state to which the\n  cue has transitioned, either `:started`, `:ending`, or `:ended`, the\n  keyword with which the cue created an effect in the show, and the\n  unique numeric ID assigned to the effect when it was started. The\n  last two argumetnts can be used with [[end-effect!]] and its\n  `:when-id` argument to avoid accidentally ending a different cue.\"\n  [grid x y f]\n  {:pre [(have? integer? x) (have? integer? y) (have? #(not (neg? %)) x) (have? #(not (neg? %)) y)\n         (have? ifn? f) (have? #(= (type %) :cue-grid) grid)]}\n  (dosync\n   ;; Consider putting the actual cue as the value, and logging a warning and ending the feedback\n   ;; if a different cue gets stored there? Probabyl not.\n   (alter (:fn-feedback grid) assoc-in [[x y] f] true))\n  nil)\n\n(defn clear-cue-fn!\n  \"Ceases calling the supplied function when the cue grid location\n  activates or deactivates.\"\n  [grid x y f]\n  {:pre [(have? integer? x) (have? integer? y) (have? #(not (neg? %)) x) (have? #(not (neg? %)) y)\n         (have? #(ifn? %) f) (have? #(= (type %) :cue-grid) grid)]}\n  (dosync\n   (let [entry (get (ensure (:fn-feedback grid)) [x y])]\n     (alter (:fn-feedback grid) assoc [x y] (dissoc entry f))))\n  nil)\n\n(defn activate-cue!\n  \"Records the fact that the cue at the specified grid coordinates was\n  activated in a show, and assigned the specified `id`, which can be\n  used later to determine whether the same cue is still running. If\n  `id` is `nil`, the cue is deactivated rather than activated.\n\n  Sends appropriate MIDI feedback events to any non-grid controllers\n  which have requested them for that cue, so they can update their\n  interfaces appropriately, then calls any registered functions that\n  want updates about the cue state letting them know it has started,\n  its effect keyword, and the `id` of the effect that was created\n  or ended.\"\n  [grid x y id]\n  {:pre [(have? integer? x) (have? integer? y) (have? #(not (neg? %)) x) (have? #(not (neg? %)) y)\n         (have? #(= (type %) :cue-grid) grid)]}\n  (dosync\n   (when-let [cue (cue-at grid x y)]\n     (let [former-id (:active-id cue)]\n       (dosync  ;; Update the active-id value in the cue\n        (alter (:cues grid) assoc [x y] (if (some? id)\n                                          (assoc cue :active-id id)\n                                          (dissoc cue :active-id))))\n       (doseq [[[_ channel note kind] feedback] (get @(:midi-feedback grid) [x y])]\n         (let [[on-feedback off-feedback device] feedback\n               velocity (if (some? id) on-feedback off-feedback)]\n           (if (= :control kind)\n             (midi/midi-control device note velocity channel)\n             (if (some? id)\n               (midi/midi-note-on device note velocity channel)\n               (midi/midi-note-off device note channel)))))\n       (doseq [[f _] (get @(:fn-feedback grid) [x y])]\n         (when (some? former-id)\n             (f :ended (:key cue) former-id))\n         (when (some? id)\n           ;; Delay :started notifications so watchers can recognize the ID that\n           ;; show/add-effect-from-cue-grid! is about to return to them.\n           (at-at/after 1 #(f :started (:key cue) id) pool)))))))\n\n(defn report-cue-ending\n  \"Calls any registered functions that want updates about the cue\n  state to inform them it has begun to gracefully end, its effect\n  keyword, and the `id` of the effect that is ending.\"\n  [grid x y id]\n  {:pre [(have? integer? x) (have? integer? y) (have? #(not (neg? %)) x) (have? #(not (neg? %)) y)\n         (have? #(= (type %) :cue-grid) grid)]}\n  (when-let [cue (cue-at grid x y)]\n    (doseq [[f _] (get @(:fn-feedback grid) [x y])]\n      (f :ending (:key cue) id))))\n\n(defn value-for-velocity\n  \"Given a cue variable which has been configured to respond to MIDI\n  velocity, and the velocity of a MIDI message affecting\n  it (presumably either Note On or Aftertouch / Poly Pressure),\n  calculate the value which should be assigned to that variable.\"\n  [v velocity]\n  (let [low (or (:velocity-min v) (:min v) 0)\n        high (or (:velocity-max v) (:max v) 100)\n        range (- high low)]\n    (+ low (* (/ velocity 127) range))))\n\n(defn starting-vars-for-velocity\n  \"Given a cue and the velocity of the MIDI message which is causing\n  it to start, gather all cue variables which have been configured to\n  respond to MIDI velocity, and assign their initial values based on\n  the velocity of the MIDI message. Returns a map suitable for use\n  with the `:var-overrides` argument to\n  [[show/add-effect-from-cue-grid!]].\"\n  [cue velocity]\n  (reduce (fn [result v] (if (:velocity v)\n                           (assoc result (keyword (:key v)) (value-for-velocity v velocity))\n                           result))\n          {} (:variables cue)))\n\n(defn create-overlay-state\n  \"Return the state information needed to manage user-interface\n  overlays implementing the [[IOverlay]] protocol. Controllers\n  implementing this protocol will need to pass this object to the\n  functions that manipulate and invoke overlays.\"\n  []\n  (atom {:next-id 0\n         :overlays (sorted-map)}))\n\n(defn add-overlay\n  \"Add a temporary overlay to the interface. The `state` argument must\n  be a value created by [[create-overlay-state]], and `overlay` an\n  implementation of the [[IOverlay]] protocol to be added as the most\n  recent overlay to that state. The optional keyword argument\n  `:priority` can be used to modify the sorting order of overlays,\n  which is that more recent ones run later, so they get the last word\n  when it comes to rendering. The default priority is `0`.\"\n  [state overlay & {:keys [priority] :or {priority 0}}]\n  (swap! state (fn [old-state]\n                 (let [id (:next-id old-state)\n                       overlays (:overlays old-state)]\n                   (assoc old-state :next-id (inc id) :overlays (assoc overlays [priority id] overlay))))))\n\n(defn add-control-held-feedback-overlay\n  \"Builds a simple overlay which just adds something to the user\n  interface until a particular control (identified by `control-num`)\n  is released, and adds it to the controller. The overlay will end\n  when a control-change message with value 0 is sent to the specified\n  control number. Other than that, all it does is call the supplied\n  function every time the interface is being updated, passing it the\n  metronome snapshot which represents the moment at which the\n  interface is being drawn. If the function returns a falsey value,\n  the overlay will be ended.\n\n  As with [[add-overlay]], `state` must be a value created\n  by [[create-overlay-state]] and tracked by the controller.\"\n  [state control-num f]\n  (add-overlay state\n               (reify IOverlay\n                 (captured-controls [this] #{control-num})\n                 (captured-notes [this] #{})\n                 (adjust-interface [this snapshot] (f snapshot))\n                 (handle-control-change [this message]\n                   (when (zero? (:velocity message))\n                     :done))\n                 (handle-note-off [this message])\n                 (handle-note-on [this message])\n                 (handle-aftertouch [this message]))))\n\n(defn run-overlays\n  \"Add any contributions from interface overlays, removing them if they\n  report being finished. Most recent and higher priority overlays run\n  last, having the opportunity to override older ones. `state` must be\n  a value created by [[create-overlay-state]] and tracked by the\n  controller. The `snapshot` is an [[afterglow.rhythm/ISnapshot]] that\n  captures the instant in time at which the interface is being\n  rendered, and is passed in to the overlay so it can be rendered in\n  sync with all other interface elements.\"\n  [state snapshot]\n  (doseq [[k overlay] (:overlays @state)]\n      (when-not (adjust-interface overlay snapshot)\n        (swap! state update-in [:overlays] dissoc k))))\n\n(defn overlay-handled?\n  \"See if there is an interface overlay active which wants to consume\n  this message; if so, send it, and see if the overlay consumes it.\n  Returns truthy if an overlay consumed the message, and it should not\n  be given to anyone else. `state` must be a value created\n  by [[create-overlay-state]] and tracked by the controller.\n\n  More recent (and higher priority) overlays get the first chance to\n  decide if they want to consume the message, so the overlay list is\n  traversed in reverse order.\"\n  [state message]\n  (case (:command message)\n    (:note-on :note-off :poly-pressure)\n    (some (fn [[k overlay]]\n            (when (contains? (captured-notes overlay) (:note message))\n              (let [result (case (:command message)\n                             :note-on (handle-note-on overlay message)\n                             :note-off (handle-note-off overlay message)\n                             :poly-pressure (handle-aftertouch overlay message))]\n                (when (= result :done)\n                  (swap! state update-in [:overlays] dissoc k))\n                result)))\n          (rseq (:overlays @state)))\n\n    :control-change\n    (some (fn [[k overlay]]\n            (when (contains? (captured-controls overlay) (:note message))\n              (let [result (handle-control-change overlay message)]\n                (when (= result :done)\n                  (swap! state update-in [:overlays] dissoc k))\n                result)))\n          (seq (:overlays @state)))\n\n    :pitch-bend\n    (some (fn [[k overlay]]\n            (let [result (handle-pitch-bend overlay message)]\n              (when (= result :done)\n                (swap! state update-in [:overlays] dissoc k))\n              result))\n          (seq (:overlays @state)))\n\n    ;; Nothing we process\n    false))\n\n(defonce ^{:private true\n           :doc \"Keeps track of all controller elements that should\n  receive beat feedback. A map whose keys are a tuple of [midi-device\n  channel note kind], and whose values are [metronome on-value\n  off-value device-map disconnect-handler].\"}\n  beat-feedback\n  (atom {}))\n\n(defonce ^{:private true\n           :doc \"When any devices are requesting beat feedback, contains\n  a task which sends their MIDI messages.\"}\n  beat-task\n  (atom nil))\n\n(def beat-refresh-interval\n  \"How often, in milliseconds, are the controllers requesting beat\n  feedback refreshed.\"\n  (/ 1000 30))\n\n(defonce ^{:private true\n           :doc \"Keeps track of the most recent marker seen for each\n  beat mapping, so we can tell if this is a new beat.\"}\n  last-marker\n  (atom {}))\n\n(defn- new-beat?\n  \"Returns true if the metronome is reporting a different marker\n  position than the last time this function was called.\"\n  [entry marker]\n  (when (not= marker (get @last-marker entry))\n    (swap! last-marker assoc entry marker)))\n\n(defn- give-beat-feedback\n  \"Called periodically to send feedback to non-grid controllers\n  requesting flashes driven by metronome beats.\"\n  []\n  (doseq [[entry [metronome on off device]] @beat-feedback]\n    (let [[_ channel note kind] entry\n          marker (rhythm/metro-marker metronome)\n          bright (or (new-beat? entry marker) (< (rhythm/metro-beat-phase metronome) 0.15))]\n      (if (= :control kind)\n        (midi/midi-control device note (if bright on off) channel)\n        (if bright\n          (midi/midi-note-on device note on channel)\n          (midi/midi-note-off device note channel))))))\n\n(defn- update-beat-task\n  \"Checks whether the beat refresh task is currently needed (if there\n  are any controllers registered to receive beat feedback), whether it\n  is currently running, and starts or ends it accordingly.\"\n  []\n  (swap! beat-task (fn [current]\n                     (if (empty? @beat-feedback)\n                       (when current (at-at/kill current) nil)  ; Should not be running; kill if it was.\n                       (or current  ; Should be running, return if it is, or start it.\n                           (at-at/every beat-refresh-interval give-beat-feedback pool\n                                        :desc \"Metronome beat feedback update\"))))))\n\n(defn clear-beat-feedback!\n  \"Ceases flashing the specified non-grid MIDI controller element\n  on beats of the specified metronome.\"\n  [metronome device channel kind note]\n  {:pre [(have? #(satisfies? rhythm/IMetronome %) metronome)\n         (have? #(= (type %) :midi-device) device) (have? #{:control :note} kind)]}\n  (let [entry [(:device device) channel note kind]\n        [_ _ off _ disconnect-handler] (get @beat-feedback entry)]\n    (swap! beat-feedback dissoc entry)\n    (update-beat-task)\n    (when (some? disconnect-handler)\n      (amidi/remove-disconnected-device-handler! device disconnect-handler))\n    (when off ; We were giving feedback, make sure we leave the LED in an off state\n      (if (= :control kind)\n                (midi/midi-control device note off channel)\n                (midi/midi-note-off device note channel))))\n  nil)\n\n(defn add-beat-feedback!\n  \"Arranges for the specified non-grid MIDI controller to receive\n  feedback events to make a particular LED flash on each beat of\n  the specified metronome.\"\n  [metronome device channel kind note & {:keys [on off] :or {on 127 off 0}}]\n  {:pre [(have? #(satisfies? rhythm/IMetronome %) metronome)\n         (have? #(= (type %) :midi-device) device)\n         (have? #{:control :note} kind) (have? integer? on) (have? integer? off)\n         (have? #(<= 0 % 127) on) (have? #(<= 0 % 127) off)]}\n  (clear-beat-feedback! metronome device channel kind note)  ; In case there was an already in effect\n  (letfn [(disconnect-handler []\n            (clear-beat-feedback! metronome device channel kind note))]\n    (amidi/add-disconnected-device-handler! device disconnect-handler)\n    (swap! beat-feedback assoc [(:device device) channel note kind]\n           [metronome on off device disconnect-handler]))\n  (update-beat-task)\n  nil)\n\n(defn identify\n  \"Sends a MIDI Device Inquiry message to the specified device and\n  returns the response, waiting for up to a second, and trying up to\n  three times if no response is received in that second. If the third\n  attempt fails, returns `nil`.\"\n  [port-in port-out]\n  (let [result (promise)\n        handler (fn [msg] (deliver result msg))]\n    (try\n      (amidi/add-sysex-mapping port-in handler)\n      (loop [attempts 0]\n        (overtone.midi/midi-sysex port-out [240 126 127 6 1 247])\n        (let [found (deref result 1000 nil)]\n          (or found (when (< attempts 2) (recur (inc attempts))))))\n      (finally (amidi/remove-sysex-mapping port-in handler)))))\n\n(defmulti bind-to-show-impl\n  \"Establish a rich user-interface binding on a supported grid\n  controller for `show`. A multimethod which selects the appropriate\n  implementation based on passing the value returned by [[identify]]\n  to all functions registered in [[recognizers]]. The port used to\n  receive MIDI messages from the controller is passed as `port-in`,\n  and the port used to send messages to it is passed as `port-out`.\n\n  New controller binding implementations simply need to define an\n  appropriate implementation of this multimethod, and add their\n  recognition function to [[recognizers]].\n\n  All rich controller binding implementations should honor the\n  `:display-name` and `:refresh-interval` optional keyword arguments\n  described in [[bind-to-show]]. They may also support\n  additional optional keyword arguments specific to the details of\n  their implementation, which the caller can supply when they know\n  they are binding to such a controller.\"\n  (fn [kind show port-in port-out recognizer-result & args]\n    kind))\n\n(defonce ^{:doc \"A map whose keywords are dispatch values registered\n  with [[bind-to-show-impl]] and whose values are functions which are\n  called with three arguments: The [[identify]] response for a\n  controller and the MIDI input and output ports it registered. The\n  recognizer functions examine the device's [[identify]] response and\n  ports, if the device is recognized as a controller which is\n  supported by the particular binding implementation associated with\n  the dispatch keyword, return the binding information needed by their\n  controller implementations to complete a binding to that device. In\n  other words, non-`nil` responses mean the corresponding dispatch\n  value, function result, and input and output ports should be used\n  with [[bind-to-show-impl]] to establish a binding with that\n  controller.\n\n  New controller binding implementations simply need to add an\n  appropriate implementation of that multimethod, and register their\n  recognition function in this map.\"}\n  recognizers (atom {}))\n\n(defonce ^{:doc \"Controllers which are currently bound to shows must\n  register themselves here. All controllers in this set will be passed\n  to [[deactivate]] when [[deactivate-all]] is called, and when the\n  JVM is shutting down, to gracefully terminate those bindings.\"\n           :private true}\n  active-bindings-atom (atom #{}))\n\n(defn add-active-binding\n  \"Registers a controller which has been bound to a show, and which\n  should be deactivated when [[deactivate-all]] is called or the JVM\n  is shutting down, to gracefully clean up the binding.\"\n  [controller]\n  {:pre [(have? some? controller) (have? keyword? (type controller))]}\n  (swap! active-bindings-atom conj controller))\n\n(defn remove-active-binding\n  \"Removes a controller from the set of active bindings, so it will no\n  longer be deactivated when [[deactivate-all]] is called or the JVM\n  is shutting down.\"\n  [controller]\n  {:pre [(have? some? controller) (have? keyword? (type controller))]}\n  (swap! active-bindings-atom disj controller))\n\n(defn active-bindings\n  \"Returns the set of controllers which are currently bound to\n  shows.\"\n  []\n  @active-bindings-atom)\n\n(defn- already-bound?\n  \"Checks whether the specified input port is associated with any\n  currently active controller binding.\"\n  [port-in]\n  (some (partial amidi/same-device? port-in) (map :port-in (active-bindings))))\n\n(defn bind-to-show\n  \"Establish a rich user-interface binding on a supported grid\n  controller for `show`.\n\n  To locate the controller that you want to bind to, you need to\n  supply a `device-filter` which uniquely matches the ports to be used\n  to communicate with it. The values returned\n  by [[afterglow.midi/open-inputs-if-needed!]]\n  and [[afterglow.midi/open-outputs-if-needed!]] will be searched, and\n  the first port that matches with [[filter-devices]] will be used.\n  There must be both an input and output matching the filter for the\n  binding to succeed.\n\n  The controller binding implementation chosen will be determined by\n  calling [[identify]] with the ports found, and seeing which member\n  of [[recognizers]] recognizes the result and returns a non-null\n  value. The corresponding dispatch key will be used with the result\n  value to call [[bind-to-show-impl]] with the ports and other\n  arguments, and it will do the appropriate things to work with the\n  controller that was found.\n\n  All rich controller binding implementations accept a couple of\n  standard optional keyword arguments to adjust their behavior. The\n  controller will be identified in the user interface (for the\n  purposes of linking it to the web cue grid) with a default name\n  based on its type (for example \\\"Ableton Push\\\"). If you would like\n  to use a different name (for example, if you are lucky enough to\n  have more than one Push), you can pass in a custom value after\n  the optional keyword argument `:display-name`.\n\n  If you want the user interface to be refreshed at a different rate\n  than the default for the controller type, pass your desired number\n  of milliseconds after `:refresh-interval`.\n\n  If you are binding to a specific controller type whose mapping\n  accepts other optional keyword arguments, you can include them as\n  well, and they will be passed on to the binding implementation\n  function.\n\n  If the controller was bound, the binding will be returned, and you\n  can later call [[deactivate]] with it. If the binding failed, `nil`\n  will be returned, and there will be messages explaining why in the\n  log file.\"\n  [show device-filter & {:keys [auto-binding] :as args}]\n  {:pre [(some? show) (some? device-filter)]}\n  (load-built-in-controllers)  ; Make sure controller implementations are registered\n  (let [port-in  (amidi/find-midi-in device-filter false)\n        port-out (amidi/find-midi-out device-filter false)\n        ident (when (every? some? [port-in port-out]) (identify port-in port-out))]\n    (if (already-bound? port-in)\n      (timbre/info \"Not binding controller to show, it already has an active binding:\" port-in)\n      (if ident\n        (loop [candidates (seq @recognizers)]\n          (if (seq candidates)\n            (let [[dispatch recognizer] (first candidates)]\n              (if-let [recognizer-result (recognizer ident port-in port-out)]\n                (let [args (vec (flatten (seq (dissoc args :auto-binding))))]\n                  (timbre/info \"Binding controller type\" dispatch \"to\" port-in \"with args\" args)\n                  (apply bind-to-show-impl (concat [dispatch show port-in port-out recognizer-result]\n                                                   args)))\n                (recur (rest candidates))))\n            (when-not auto-binding\n              (timbre/warn \"Unrecognized controller\" (amidi/describe-device-filter device-filter)))))\n        (when-not auto-binding\n          (timbre/warn \"Unable to find rich controller\" (amidi/describe-device-filter device-filter)))))))\n\n(defmulti deactivate\n  \"Deactivates a controller binding established by [[bind-to-show]].\n   If `:disconnected` is passed with a\n  `true` value, it means that the controller has already been removed\n  from the MIDI environment, so no effort will be made to clear its\n  display or take it out of User mode.\n\n  The implementation of this multimethod is chosen by using the\n  `:type` key in the `controller` map as the dispatch value, so rich\n  controller implementations simply need to register their own\n  implementations appropriately when their namespaces are loaded.\"\n  (fn [controller & {:keys [disconnected] :or {disconnected false}}]\n    (type controller)))\n\n(defn deactivate-all\n  \"Deactivates all controller bindings which are currently active.\n  This will be registered as a shutdown hook to be called when the\n  Java environment is shutting down, to clean up gracefully.\"\n  []\n  (doseq [controller @active-bindings-atom]\n    (deactivate controller)))\n\n(defonce ^{:doc \"Deactivates any registered controller bindings when\n  Java is shutting down.\"\n           :private true}\n  shutdown-hook\n  (let [hook (Thread. deactivate-all)]\n    (.addShutdownHook (Runtime/getRuntime) hook)\n    hook))\n\n(defonce ^{:doc \"The MIDI new device handler which will inspect all\n  new devices when [[auto-bind]] is active. `nil` if [[auto-bind]] has\n  never been enabled, or [[cancel-auto-bind]] has been called.\"\n           :private true}\n  auto-bind-handler (atom nil))\n\n(defn auto-bind\n  \"Watches for a recognized grid controller to be connected, and as\n  soon as it is, binds it to the specified show\n  using [[bind-to-show]]. If that controller ever gets disconnected,\n  it will be re-bound once it reappears.\n\n  If you would like to limit the controllers that Afterglow will\n  automatically bind to, you may supply a filter with the optional\n  keyword argument `:device-filter` which uniquely matches the MIDI\n  ports used by the devices you want to be auto-bound. The values\n  returned by [[afterglow.midi/open-inputs-if-needed!]]\n  and [[afterglow.midi/open-outputs-if-needed!]] will be searched, and\n  any pair of identically-named ports that are accepted by your\n  `:device-filter` with [[filter-devices]] will be bound if they are\n  attached to a controller type that Afterglow knows how to work with.\n\n  The controller binding implementation chosen will be determined by\n  calling [[identify]] with the ports found, and seeing which member\n  of [[recognizers]] recognizes the result and returns a dispatch\n  value. That value will be used to call [[bind-to-show-impl]] with the\n  ports and other arguments, and it will do the appropriate things to\n  work with the controller that was found.\n\n  If you are watching for a specific controller type whose mapping\n  accepts other optional keyword arguments, you can include them as\n  well, and they will be passed along to [[bind-to-show]] when it is\n  detected.\n\n  All rich controller binding implementations accept a couple of\n  standard optional keyword arguments to adjust their behavior. The\n  controller will be identified in the user interface (for the\n  purposes of linking it to the web cue grid) with a default name\n  based on its type (for example \\\"Ableton Push\\\"). If you would like\n  to use a different name (for example, if you are lucky enough to\n  have more than one Push), you can pass in a custom value after\n  the optional keyword argument `:display-name`.\n\n  If you want the user interface to be refreshed at a different rate\n  than the default for the controller type, pass your desired number\n  of milliseconds after `:refresh-interval`.\n\n  Controllers which perform their own startup animation, or which need\n  to be given extra time to become ready after their ports appear in\n  the MIDI environment can look for the optional keyword argument\n  `:new-connection` to indicate the device has just been connected,\n  and react appropriately.\"\n  [show & {:keys [device-filter] :as args}]\n  {:pre [(have? some? show)]}\n  (load-built-in-controllers)  ; Make sure controller implementations are registered\n  (swap! auto-bind-thread start-auto-bind-thread)  ; Make sure the auto-bind thread is running\n  (letfn [(connection-handler\n            ([device]\n             (connection-handler device true))\n            ([device new-connection]\n             (when (and (pos? (:sources device))  ; Respond only to input ports, since controllers will have both\n                        (seq (amidi/filter-devices device-filter [device]))  ; Apply any user-desired filter\n                        (not (already-bound? device)))  ; Ignore devices that already have active bindings\n               ;; Looks good, queue it for an auto-bind attempt\n               (.add bind-queue [device show (merge (dissoc args :device-filter)\n                                                    {:auto-binding   true\n                                                     :new-connection new-connection})]))))]\n\n    ;; See if any eligible controller seems to already be connected, and if so, try bind to it right away.\n    (doseq [found (amidi/filter-devices device-filter (amidi/open-inputs-if-needed!))]\n      (when-not (already-bound? found) (connection-handler found false)))\n\n    ;; Set up to bind when connected in future, in the process shutting down any former auto-binding\n    ;; that was in place.\n    (swap! auto-bind-handler (fn [former-handler]\n                               (when former-handler\n                                 (amidi/remove-new-device-handler! former-handler))\n                               connection-handler))\n    (amidi/add-new-device-handler! connection-handler)))\n\n(defn cancel-auto-bind\n  \"Stop any [[auto-bind]] which may be in effect.\"\n  []\n  (swap! auto-bind-handler (fn [former-handler]  ; Stop noticing new device connections\n                             (when former-handler\n                               (amidi/remove-new-device-handler! former-handler))\n                             nil))\n  (.add bind-queue [nil nil :done]))  ; Tell the auto-bind thread to shut down\n"
  },
  {
    "path": "src/afterglow/core.clj",
    "content": "(ns afterglow.core\n  \"This is the main class for running Afterglow as a self-contained JAR application.\n  When you are learning and experimenting in your REPL, the main\n  namespace you want to be using is afterglow.examples\"\n  (:require [afterglow.fixtures.qxf :as qxf]\n            [afterglow.init]\n            [afterglow.version :as version]\n            [afterglow.web.handler :refer [app]]\n            [afterglow.web.session :as session]\n            [clojure.java.browse :as browse]\n            [clojure.tools.cli :refer [parse-opts]]\n            [clojure.tools.nrepl.server :as nrepl]\n            [environ.core :refer [env]]\n            [ola-clojure.ola-client :as ola-client]\n            [org.httpkit.server :as http-kit]\n            [overtone.osc :as osc]\n            [selmer.parser :as parser]\n            [taoensso.timbre.appenders.3rd-party.rotor :as rotor]\n            [taoensso.timbre :as timbre])\n  (:import [java.net InetAddress]\n           [org.deepsymmetry.beatlink DeviceFinder])\n  (:gen-class))\n\n(defonce ^{:doc \"Holds the running web UI server, if there is one, for later shutdown.\"}\n  web-server (atom nil))\n\n(defonce ^{:doc \"Holds the running OSC server, if there is one, for later shutdown.\"}\n  osc-server (atom nil))\n\n(defonce ^{:doc \"Holds the future which is cleaning up expired web sessions, if any.\"}\n  session-cleaner (atom nil))\n\n(defonce ^{:doc \"Holds the running REPL server, if there is one, for later shutdown.\"}\n  nrepl-server (atom nil))\n\n(defn- create-appenders\n  \"Create a set of appenders which rotate the file at the specified path.\"\n  [path]\n  {:rotor (rotor/rotor-appender {:path path\n                                 :max-size 100000\n                                 :backlog 5})})\n\n(defonce ^{:private true\n           :doc \"The default log appenders, which rotate between files\n           in a logs subdirectory.\"}\n  appenders (atom (create-appenders \"logs/afterglow.log\")))\n\n(defn- init-logging-internal\n  \"Performs the actual initialization of the logging environment,\n  protected by the delay below to insure it happens only once.\"\n  []\n  (timbre/set-config!\n   ;; See http://ptaoussanis.github.io/timbre/taoensso.timbre.html#var-*config* for more details.\n   {:min-level :info ; #{:trace :debug :info :warn :error :fatal :report}\n    :enabled?  true\n\n    :middleware [] ; (fns [data]) -> ?data, applied left->right\n\n    :timestamp-opts {:pattern  \"yyyy-MMM-dd HH:mm:ss\"\n                     :locale   :jvm-default\n                     :timezone (java.util.TimeZone/getDefault)}\n\n    :output-fn timbre/default-output-fn ; (fn [data]) -> string\n    })\n\n  ;; Install the desired log appenders\n  (timbre/merge-config!\n   {:appenders @appenders})\n\n  ;; Disable Selmer's template cache in development mode\n  (when (Boolean/valueOf (env :dev)) (parser/cache-off!)))\n\n(defonce ^{:private true\n           :doc \"Used to ensure log initialization takes place exactly once.\"}\n  initialized (delay (init-logging-internal)))\n\n(defn init-logging\n  \"Set up the logging environment for Afterglow. Called by main when invoked\n  as a jar, and by the examples namespace when brought up in a REPL for exploration,\n  and by extensions such as afterglow-max which host Afterglow in Cycling '74's Max.\"\n  ([] ;; Resolve the delay, causing initialization to happen if it has not yet.\n   @initialized)\n  ([appenders-map] ;; Override the default appenders, then initialize as above.\n   (reset! appenders appenders-map)\n   (init-logging)))\n\n(defn- valid-host?\n  \"Check whether a string represents a valid host name.\"\n  [name]\n  (try\n    (InetAddress/getByName name)\n    true\n    (catch Exception e\n      false)))\n\n(defn- println-err\n  \"Prints objects to stderr followed by a newline.\"\n  [& more]\n  (binding [*out* *err*]\n    (apply println more)))\n\n(def ^:private log-file-error\n  \"Holds the validation failure message if the log file argument was\n  not acceptable.\"\n  (atom nil))\n\n(defn- bad-log-arg\n  \"Records a validation failure message for the log file argument, so\n  a more specific diagnosis can be given to the user. Returns false to\n  make it easy to invoke from the validation function, to indicate\n  that validation failed after recording the reason.\"\n  [& messages]\n  (reset! log-file-error (clojure.string/join \" \" messages))\n  false)\n\n(defn- valid-log-file?\n  \"Check whether a string identifies a file that can be used for logging.\"\n  [path]\n  (let [f (clojure.java.io/file path)\n        dir (or (.getParentFile f) (.. f (getAbsoluteFile) (getParentFile)))]\n    (if (.exists f)\n      (cond  ; The file exists, so make sure it is writable and a plain file\n        (not (.canWrite f)) (bad-log-arg \"Cannot write to log file\")\n        (.isDirectory f) (bad-log-arg \"Requested log file is actually a directory\")\n        ;; Requested existing file looks fine, make sure we can roll over\n        :else (or (.canWrite dir)\n                  (bad-log-arg \"Cannot create rollover log files in directory\" (.getPath dir))))\n      ;; The requested file does not exist, make sure we can create it\n      (if (.exists dir)\n        (and (or (.isDirectory dir)\n                 (bad-log-arg \"Log directory is not a directory:\" (.getPath dir)))\n             (or (.canWrite dir) ; The parent directory exists, make sure we can write to it\n                 (bad-log-arg \"Cannot create log file in directory\" (.getPath dir))))\n        (or (.mkdirs dir) ; The parent directory doesn't exist, make sure we can create it\n          (bad-log-arg \"Cannot create log directory\" (.getPath dir)))))))\n\n(def cli-options\n  \"The command-line options supported by Afterglow.\"\n  [[\"-w\" \"--web-port PORT\" \"Port number for web UI\"\n    :default (or (when-let [default (env :web-port)] (Integer/parseInt default)) 16000)\n    :parse-fn #(Integer/parseInt %)\n    :validate [#(< 0 % 0x10000) \"Must be a number between 0 and 65536\"]]\n   [\"-n\" \"--no-browser\" \"Don't launch web browser\"]\n   [\"-o\" \"--osc-port PORT\" \"Port number for OSC server\"\n    :default (or (when-let [default (env :osc-port)] (Integer/parseInt default)) 16001)\n    :parse-fn #(Integer/parseInt %)\n    :validate [#(< 0 % 0x10000) \"Must be a number between 0 and 65536\"]]\n   [\"-r\" \"--repl-port PORT\" \"Port number for REPL, if desired\"\n    :default (env :repl-port)\n    :parse-fn #(Integer/parseInt %)\n    :validate [#(< 0 % 0x10000) \"Must be a number between 0 and 65536\"]]\n   [\"-l\" \"--log-file PATH\" \"File into which log is written\"\n    :default (or (env :log-file) \"logs/afterglow.log\")\n    :validate [valid-log-file? @log-file-error]]\n   [\"-H\" \"--olad-host HOST\" \"Host name or address of OLA daemon\"\n    :default (or (env :olad-host) \"localhost\")\n    :validate [valid-host? \"Must be a valid host name\"]]\n   [\"-P\" \"--olad-port PORT\" \"Port number OLA daemon listens on\"\n    :default (or (when-let [default (env :olad-port)] (Integer/parseInt default)) 9010)\n    :parse-fn #(Integer/parseInt %)\n    :validate [#(< 0 % 0x10000) \"Must be a number between 0 and 65536\"]]\n   [\"-q\" \"--convert-qxf PATH\" \"Convert QLC+ fixture file and exit\"]\n   [\"-h\" \"--help\" \"Display help information and exit\"]])\n\n(defn usage\n  \"Print message explaining command-line invocation options.\"\n  [options-summary]\n  (clojure.string/join\n   \\newline\n   [(str (version/title) \" \" (version/tag) \", a live-coding environment for light shows.\")\n    (str \"Usage: \" (version/title) \" [options] [init-file ...]\")\n    \"  Any init-files specified as arguments will be loaded at startup,\"\n    \"  in the order they are given, before creating any embedded servers.\"\n    \"\"\n    \"Options:\"\n    options-summary\n    \"\"\n    \"If you translate a QLC+ fixture definition file, Afterglow will try to write\"\n    \"its version in the same directory, but won't overwrite an existing file.\"\n    \"\"\n    \"If you do not explicitly specify a log file, and Afterglow cannot write to\"\n    \"the default log file path, logging will be silently suppressed.\"\n    \"\"\n    \"Please see https://github.com/Deep-Symmetry/afterglow for more information.\"]))\n\n(defn error-msg\n  \"Format an error message related to command-line invocation.\"\n  [errors]\n  (str \"The following errors occurred while parsing your command:\\n\\n\"\n       (clojure.string/join \\newline errors)))\n\n(defn exit\n  \"Terminate execution with a message to the command-line user.\"\n  [status msg]\n  (if (zero? status)\n    (println msg)\n    (println-err msg))\n  (System/exit status))\n\n(defn start-web-server\n  \"Start the embedded web UI server on the specified port. If a truthy\n  value is supplied for browser, opens a web browser window on the\n  newly launched server. If the server was already running, logs a\n  warning. Either way, makes sure the background thread which cleans\n  up expired sessions is running.\"\n  ([port]\n   (start-web-server port false))\n  ([port browser]\n   (swap! web-server #(if %\n                        (timbre/warn \"Not starting web server because it is already running.\")\n                        (do\n                          (.start (DeviceFinder/getInstance)) ; The web UI wants to know about DJ Link devices\n                          (http-kit/run-server app {:port port}))))\n\n   ;;Start the expired session cleanup job if needed\n   (swap! session-cleaner #(or % (session/start-cleanup-job!)))\n\n   ;; Launch the browser if requested\n   (when browser (browse/browse-url (str \"http://localhost:\" port)))))\n\n(defn start-osc-server\n  \"Start the embedded OSC server on the specified port.\"\n  [port]\n  (when @osc-server (throw (IllegalStateException. \"OSC server is already running.\")))\n  (reset! osc-server (osc/osc-server port \"Afterglow\")))\n\n(defn stop-osc-server\n  \"Shut down the embedded OSC server if it is running.\"\n  []\n  #_(osc/zero-conf-off)\n  (try\n    (swap! osc-server (fn [server]\n                        (when server\n                          (osc/osc-rm-all-listeners server)\n                          (osc/osc-rm-all-handlers server)\n                          (osc/osc-close server)\n                          nil)))\n    (catch Throwable t\n      (timbre/error t \"failed to shut down OSC server\"))))\n\n(defn start-nrepl\n  \"Start a network REPL for debugging or remote control.\"\n  [port]\n  (try\n    (swap! nrepl-server #(do (when % (nrepl/stop-server %)) (nrepl/start-server :port port)))\n    (timbre/info \"nREPL server started on port\" port)\n    (catch Throwable t\n      (timbre/error t \"failed to start nREPL\"))))\n\n(defn stop-servers\n  \"Shut down the embedded web UI, OSC and NREPL servers.\"\n  []\n  (timbre/info \"shutting down embedded servers...\")\n  (swap! web-server #(do (when % (% :timeout 100)) nil))\n  (stop-osc-server)\n  (swap! nrepl-server #(do (when % (nrepl/stop-server %)) nil))\n  (swap! session-cleaner #(do (when % (future-cancel %)) nil))\n  (timbre/info \"shutdown complete!\"))\n\n(defn -main\n  \"The entry point when invoked as a jar from the command line. Parse options\n  and start servers on the appropriate ports.\"\n  [& args]\n  (let [{:keys [options arguments errors summary]} (parse-opts args cli-options)]\n\n    ;; Handle help, error conditions, and fixture definition translation\n    (cond\n      (:help options) (exit 0 (usage summary))\n      errors (exit 1 (str (error-msg errors) \"\\n\\n\" (usage summary)))\n      (:convert-qxf options) (let [[status message] (qxf/convert-qxf (:convert-qxf options))]\n                               (exit status message)))\n\n    ;; Set up the logging environment\n    (reset! appenders (create-appenders (:log-file options)))\n    (init-logging)\n\n    ;; Load any requested initialization files\n    (doseq [f arguments]\n      (try\n        (timbre/info \"Loading init-file\" f)\n        (binding [*ns* (the-ns 'afterglow.init)]\n          (load-file f))\n        (catch Throwable t\n          (timbre/error t \"Problem loading init-file\" f)\n          (println-err \"Failed to load init-file\" f)\n          (println-err (.getMessage t))\n          (println-err \"See\" (:log-file options) \"for stack trace.\")\n          (System/exit 1))))\n\n    ;; Set up embedded servers\n    (.addShutdownHook (Runtime/getRuntime) (Thread. stop-servers))\n    (reset! ola-client/olad-host (:olad-host options))\n    (when-not (#{\"localhost\" \"127.0.0.1\"} @ola-client/olad-host) (ola-client/use-buffered-channel))\n    (reset! ola-client/olad-port (:olad-port options))\n    (timbre/info \"Will find OLA daemon on host\" @ola-client/olad-host \", port\" @ola-client/olad-port)\n    (start-web-server (:web-port options) (not (:no-browser options)))\n    (timbre/info \"Web UI server on port:\" (:web-port options))\n    (start-osc-server (:osc-port options))\n    (timbre/info \"OSC server on port:\" (:osc-port options))\n    (when-let [port (:repl-port options)]\n      (start-nrepl port)\n      (timbre/info \"nrepl server on port:\" port))\n\n    (timbre/info \"Startup complete:\" (version/title) (version/tag))))\n"
  },
  {
    "path": "src/afterglow/coremidi4j.clj",
    "content": "(ns afterglow.coremidi4j\n  (:import [uk.co.xfactorylibrarians.coremidi4j CoreMidiDeviceProvider CoreMidiNotification]))\n\n(defn add-environment-change-handler\n  \"Arranges for the supplied function to be called whenever the MIDI\n  environment changes, in other words when a MIDI device is added or\n  removed. This namespace can only be loaded if\n  the [CoreMIDI4J](https://github.com/DerekCook/CoreMidi4J) extension\n  is present in the Java extensions directory.\n\n  Returns `true` if the handler was added, or `false` if the\n  CoreMIDI4J extension was unable to load its native library, and so\n  is inactive.\"\n  [f]\n  (when (CoreMidiDeviceProvider/isLibraryLoaded)\n    (CoreMidiDeviceProvider/addNotificationListener\n     (reify CoreMidiNotification (midiSystemUpdated [this] (f))))\n    true))\n"
  },
  {
    "path": "src/afterglow/dj_link.clj",
    "content": "(ns afterglow.dj-link\n  \"Provides synchronization with equipment sending Pioneer Pro DJ Link\n  packets on the local network, such as Pioneer Nexus mixers and players,\n  using the beat-link library.\"\n  (:require [afterglow.midi :refer [IClockSync sync-start sync-stop sync-status]]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.util :refer [unsign]]\n            [overtone.at-at :refer [now]]\n            [taoensso.timbre :as timbre])\n  (:import [java.net InetAddress DatagramPacket DatagramSocket]\n           [java.util.regex Pattern]\n           [org.deepsymmetry.beatlink DeviceFinder BeatFinder VirtualCdj Beat]))\n\n(defonce ^{:private true\n           :doc \"Holds the set of active synced metronomes, and a map\n  that tracks the most recent beat received from a given IP address.\"}\n  state (atom {:synced-metronomes #{}\n               :beats-seen {}}))\n\n(def beat-finder\n  \"The class that tracks beats being played.\"\n  (BeatFinder/getInstance))\n\n(def virtual-cdj\n  \"The class that gathers detailed player status information.\"\n  (VirtualCdj/getInstance))\n\n(def device-finder\n  \"The class that monitors the presence of devices on the DJ Link\n  network.\"\n  (DeviceFinder/getInstance))\n\n(defn shut-down\n  \"Shut down the beat-link library.\"\n  []\n  (.stop beat-finder)\n  (.stop virtual-cdj)\n  (.stop device-finder))\n\n(defn- apply-beat-to-synced-metronomes\n  \"When a beat notification is received, this function is called to\n  update any synced metronomes attached to the device announcing the\n  beat.\"\n  [beat]\n  (swap! state assoc-in [:beats-seen (.getAddress beat)] beat)\n  (doseq [listener (:synced-metronomes @state)]\n    ;; TODO: Handle :master as a special virtual source?\n    ;; TODO: Adjust for latency, and only nudge when our phase is outside our skew tolerance, like beat-link-trigger\n    ;;       does (that uses a value of 0.0166 of a beat).\n    ;; TODO: Redesign this to take advantage of the massive improvements in understanding the protocol we've achieved\n    ;;       since it was written, for example using the TimeFinder so we can react to tempo changes in between beats.\n    (when (= (:address (:source listener)) (.getAddress beat))\n      (rhythm/metro-bpm (:metronome listener) (.getEffectiveTempo beat))\n      (if (= (:level listener) :bar)\n        (rhythm/metro-bar-phase (:metronome (/ (dec (.getBeatWithinBar beat)) 4)))\n        (rhythm/metro-beat-phase (:metronome listener) 0))\n      (dosync\n       (alter (:sync-count listener) inc)))))\n\n;; Register our beat handler with the beat-link library\n(defonce ^:private beat-listener\n  (reify org.deepsymmetry.beatlink.BeatListener\n    (newBeat [this beat]\n      (apply-beat-to-synced-metronomes beat))))\n(.addBeatListener beat-finder beat-listener)\n\n(defn start\n  \"Activate all the components of the beat-link library.\n  Runs in the background, since it can take a while to give up if\n  there are no DJ Link devices on the network.\"\n  []\n  (future\n    (try\n      (.start device-finder)\n      (.start virtual-cdj)\n      (.start beat-finder)\n      (catch Exception e\n        (timbre/warn e \"Failed while trying to set up beat-finder DJ-Link integration.\")\n        (shut-down)))))\n\n;; A simple object which supports syncing a metronome to Pro DJ Link beats\n;; received from a particular source, optionally honoring the beat-within-bar\n(defrecord UDPSync\n [metronome source sync-count level]\n  IClockSync\n  (sync-start [this]\n    (start)\n    (dosync\n     (ref-set sync-count 0))\n    (swap! state update-in [:synced-metronomes] conj this))\n  (sync-stop [this]\n    (swap! state update-in [:synced-metronomes] disj this)\n    (dosync\n     (ref-set sync-count nil)))\n  (sync-status [this]\n    (dosync\n     (ensure sync-count)\n     (let [latest-beat (get-in @state [:beats-seen (:address source)])\n           latest-time (if (some? latest-beat) (.getTimestamp latest-beat) 0)\n           running (some? @sync-count)\n           current (and running (<= (- (now) latest-time) 1500))]\n       {:type :dj-link,\n        :current current\n        :level level\n        :source source\n        :status (cond\n                  (not running)\n                  \"Stopped.\"\n\n                  (or (nil? latest-beat) (zero? @sync-count))\n                  (str \"Not playing? No DJ Link beats received from \" (:name source) \".\")\n\n                  (not current)\n                  (str \"Stalled? No beats received in \" (- (now) latest-time) \"ms.\")\n\n                  :else\n                  (str \"Running. \" @sync-count \" beats received.\"))}))))\n\n;; Suppress uninformative auto-generated documentation entries.\n(alter-meta! #'->UDPSync assoc :no-doc true)\n(alter-meta! #'map->UDPSync assoc :no-doc true)\n\n(defn current-dj-link-sources\n  \"Returns the set of potential Pro DJ Link synchronization sources\n  which are currently visible on the network, summarized as maps\n  containing the device name, player number, and IP address.\"\n  []\n  (when-not (.isRunning device-finder)\n    (start))\n  (set (for [device (.getCurrentDevices device-finder)]\n         {:name (.getName device)\n          :player (.getNumber device)\n          :address (.getAddress device)})))\n\n(defn filter-sources\n  \"Return a set of only those sources whose name matches the specified\n  pattern. name-filter can either be a Pattern, or a string which will\n  be turned into a pattern which matches in a case-insensitive way\n  anywhere in the name.\"\n  [name-filter]\n  (if (or (nil? name-filter) (and (string? name-filter) (clojure.string/blank? name-filter)))\n    (current-dj-link-sources)\n    (let [pattern (if (= (class name-filter) Pattern)\n                    name-filter\n                    (Pattern/compile (Pattern/quote (str name-filter)) Pattern/CASE_INSENSITIVE))]\n      (filter #(re-find pattern (:name %)) (current-dj-link-sources)))))\n\n(defn find-source-by-name\n  \"Looks up a source with a name that matches the specified pattern.\n  name-filter can either be a Pattern, or a string which will be\n  turned into a pattern which matches in a case-insensitive way\n  anywhere in the name. Returns the single matching source found, or\n  throws an exception.\"\n  [name-filter]\n  (let [result (filter-sources name-filter)]\n    (case (count result)\n      1 (first result)\n      0 (throw (Exception. (str \"No DJ Link source found matching \" name-filter)))\n      (throw (Exception. (str \"More than one DJ Link source matches \" name-filter))))))\n\n(defn find-source\n  \"Makes sure the supplied DJ Link source is current and valid.\n  Returns it, or throws an exception.\"\n  [source]\n  (or ((current-dj-link-sources) source)\n      (throw (Exception. \"Not a valid DJ Link source:\" source))))\n\n(defn sync-to-dj-link\n  \"Returns a sync function that will cause the beats-per-minute\n  setting of the supplied metronome to track the values received from\n  the specified DJ Link transmitter on the local network. The sync\n  source can be specified either as a map that would be returned from\n  [[current-dj-link-sources]], or a regex `Pattern`, or a simple\n  string, which will be converted into a case-insensitve pattern\n  matching anywhere in the source name. This method is intended for\n  use with\n  [[show/sync-to-external-clock]].\n\n  If `sync-bars?` is passed with a `true` value, then synchronization\n  will honor the beat-within-bar information coming from the DJ Link\n  device. Otherwise, sync will be at the beat level only.\"\n  ([dj-link-source]\n   (sync-to-dj-link dj-link-source false))\n  ([dj-link-source sync-bars?]\n   (fn [^afterglow.rhythm.Metronome metronome]\n     (let [source (if (map? dj-link-source)\n                    (find-source dj-link-source)\n                    (find-source-by-name dj-link-source))\n           sync-handler (UDPSync. metronome source (ref nil) (if sync-bars? :bar :beat))]\n       (sync-start sync-handler)\n       sync-handler))))\n"
  },
  {
    "path": "src/afterglow/effects/channel.clj",
    "content": "(ns afterglow.effects.channel\n  \"Effects pipeline functions for working with individual DMX channels.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as channels]\n            [afterglow.controllers :as ct]\n            [afterglow.effects.params :as params]\n            [afterglow.effects :as fx :refer [always-active end-immediately]]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show-context :refer [*show*]]\n            [afterglow.util :refer [ubyte]]\n            [clojure.math.numeric-tower :as math]\n            [com.evocomputing.colors :refer [clamp-percent-float clamp-unit-float clamp-rgb-int]])\n  (:import (afterglow.effects Assigner Effect)))\n\n(defn apply-channel-value\n  \"A function which sets the DMX buffer value(s) for a channel, supporting fine channels\n  as well (in which there is a high and low byte), using any fractional part of the value\n  to determine the fine channel value if one is present.\n\n  Also supports inverted channels (as needed for some fixtures which\n  have inverted dimmers). Such channels are specified by containing an\n  `:inverted-from` key which specifies the DMX value at which\n  inversion occurs. If the entire DMX range is inverted, in other\n  words 0 represents the highest value and 255 the lowest,\n  `:inverted-from` will be present with the value `0`. For dimmers\n  which are still black at zero, but which leap to full brightness at\n  1 then dim as the value grows towards 255, `:inverted-from` will be\n  present with the value `1`. Non-inverted channels will lack the key\n  entirely.\"\n  [buffers channel value]\n  (when-let [levels (get buffers (:universe channel))]\n    (let [adjusted-value (if-let [pivot (:inverted-from channel)]\n                           (if (< value pivot)\n                             value\n                             (- 255 (- value pivot)))\n                           value)]\n      (if-let [fine-index (:fine-index channel)]\n        (do\n          (aset-byte levels (:index channel) (ubyte adjusted-value))\n          (aset-byte levels fine-index (ubyte (math/round (* 255 (- adjusted-value (int adjusted-value)))))))\n        (aset-byte levels (:index channel) (ubyte (math/round adjusted-value)))))))\n\n(defn build-channel-assigner\n  \"Returns an assigner which applies the specified assignment function to the supplied channel.\"\n  [channel f]\n  (Assigner. :channel [(:universe channel) (:address channel)] channel f))\n\n(defn build-raw-channel-assigners\n  \"Returns a list of assigners which apply a channel assignment\n  function to all the supplied channels.\"\n  [channels f]\n  (map #(build-channel-assigner % f) channels))\n\n(defn build-fixed-channel-effect\n  \"Returns an effect which simply assigns a fixed value to all the\n  supplied channels. If htp? is true, applies\n  highest-takes-precedence (i.e. compares the value to the previous\n  assignment for the channel, and lets the highest value remain).\"\n  [name level channels & {:keys [htp?]}]\n  (let [f (if htp?\n            (fn [show snapshot target previous-assignment]\n              (max level (or (params/resolve-param previous-assignment show snapshot (:head target)) 0)))\n            (fn [show snapshot target previous-assignment] level))\n        assigners (build-raw-channel-assigners channels f)]\n    (Effect. name always-active (fn [show snapshot] assigners) end-immediately)))\n\n(defn channel-effect\n  \"Returns an effect which assigns a dynamic value to all the supplied\n  channels. If `level is a keyword, it will be looked up as a show\n  variable. If `htp?` is true, applies highest-takes-precedence (i.e.\n  compares the value to the previous assignment for the channel, and\n  lets the highest value remain).\"\n  [effect-name level channels & {:keys [htp?]}]\n  {:pre [(some? effect-name) (some? *show*) (sequential? channels)]}\n  (let [level (params/bind-keyword-param level Number 0)\n        f (if htp?\n            ;; We need to resolve any dynamic parameters at this point so we can apply the\n            ;; highest-take-precedence rule.\n            (fn [show snapshot target previous-assignment]\n              (max (clamp-rgb-int (params/resolve-param level show snapshot (:head target)))\n                   (or (clamp-rgb-int (params/resolve-param previous-assignment show snapshot (:head target))) 0)))\n            ;; We can defer resolution to the final DMX calculation stage.\n            (fn [show snapshot target previous-assignment]\n              level))\n        assigners (build-raw-channel-assigners channels f)]\n    (Effect. effect-name always-active (fn [show snapshot] assigners) end-immediately)))\n\n(defn raw-channel-effect\n  \"Returns an effect which simply calls a function to obtain the\n  current level for all the supplied channels, runs forever, and ends\n  immediately when requested.\"\n  [effect-name f channels]\n  {:pre [(some? effect-name) (ifn? f) (sequential? channels)]}\n  (let [assigners (build-raw-channel-assigners channels f)]\n    (Effect. effect-name always-active (fn [show snapshot] assigners) end-immediately)))\n\n;; Resolves the assignment of a level to a single DMX channel.\n(defmethod fx/resolve-assignment :channel [assignment show snapshot buffers]\n  ;; Resolve in case it is frame dynamic\n  (let [resolved (clamp-rgb-int (params/resolve-param (:value assignment) show snapshot (:head (:target assignment))))]\n    (apply-channel-value buffers (:target assignment) resolved)))\n\n;; Fades between two assignments to a channel; often you won't want to do this, especially for\n;; multi-function channels, so fade effects should probably default to excluding channel assigners\n;; unless the show developer has explicitly requested them.\n(defmethod fx/fade-between-assignments :channel [from-assignment to-assignment fraction show snapshot]\n  (cond (<= fraction 0) from-assignment\n        (>= fraction 1) to-assignment\n        ;; We are blending, so we need to resolve any remaining dynamic parameters now, and make sure\n        ;; fraction really does only range between 0 and 1.\n        :else (let [head (:head (:target from-assignment))\n                    from-resolved (clamp-rgb-int (params/resolve-param (or (:value from-assignment) 0)\n                                                                       show snapshot head))\n                    to-resolved (clamp-rgb-int (params/resolve-param (or (:value to-assignment) 0)\n                                                                     show snapshot head))\n                    fraction (clamp-unit-float fraction)]\n                (merge from-assignment {:value (+ (* fraction to-resolved) (* (- 1.0 fraction) from-resolved))}))))\n\n(defn build-head-function-assigner\n  \"Returns a function assigner which applies the specified assignment\n  function to the channels of the provided head or fixture which\n  implement the specified named function. The head or fixture\n  must (directly) have a channel implementing the named function.\"\n  [function head assign-f]\n  (Assigner. :function [(:id head) (keyword function)] head assign-f))\n\n(defn build-head-function-assigners\n  \"Returns a list of function assigners type which apply an assignment\n  function to the channel of all the supplied heads or fixtures which\n  implement the specified named function. Each head or fixture\n  must (directly) have a channel implementing the named function.\"\n  [function heads assign-f]\n  (map #(build-head-function-assigner function % assign-f) heads))\n\n(defn build-head-parameter-function-assigner\n  \"Returns an function assigner which applies a parameter to the\n  channel of the supplied head or fixture which implements the\n  specified named function. If the parameter is not frame-dynamic, it\n  gets resolved when creating this assigner. Otherwise, resolution is\n  deferred to frame rendering time. The head or fixture\n  must (directly) have a channel implementing the named function.\"\n  [function head param show snapshot]\n  (let [resolved (params/resolve-unless-frame-dynamic param show snapshot head)]\n    (build-head-function-assigner\n     function head (fn [show snapshot target previous-assignment] resolved))))\n\n(defn build-head-parameter-function-assigners\n  \"Returns a list of assigners which apply a parameter to the\n  channel(s) of the supplied heads or fixtures which implement the\n  specified named function. Each head or fixture must (directly) have\n  a channel implementing the named function.\"\n  [function heads param show]\n  (let [snapshot (rhythm/metro-snapshot (:metronome show))]\n    (map #(build-head-parameter-function-assigner function % param show snapshot) heads)))\n\n(defn find-heads-with-function\n  \"Returns all heads of the supplied fixtures which have a channel\n  that implements the specified function.\"\n  [function fixtures]\n  (filter #(some #{(keyword function)} (keys (:function-map %))) (channels/expand-heads fixtures)))\n\n(defn function-effect\n  \"Returns an effect which assigns a dynamic value to all channels of\n  the supplied fixtures or heads which have a range that implements\n  the specified function. (Functions are a way for fixtures to use the\n  same DMX channel to do multiple things, allocating ranges of values\n  to get more dense use from a smaller number of channel allocations.)\n  The `function` argument is the keyword by which the function\n  information will be found for the supplied `fixtures`. The actual\n  value sent for the channel associated with `function` for each\n  fixture will be calculated by treating `level` as a percentage of\n  the way between the lowest and highest DMX values assigned to that\n  named function for the fixture. The name displayed for the effect in\n  user interfaces is determined by `effect-name`.\n\n  If `:htp?` is passed with a `true` value, applies\n  highest-takes-precedence (i.e. compares the value to the previous\n  assignment for the channels implementing the function, and lets the\n  highest value remain).\n\n  If you have multiple effects trying to control different functions\n  which use the same channel, you are unlikely to get the results you\n  want. Hopefully the fixture designers chose how to share channels\n  wisely, avoiding this pitfall.\"\n  [effect-name function level fixtures & {:keys [htp?]}]\n  {:pre [(some? *show*) (some? effect-name) (some? function) (sequential? fixtures)]}\n  (let [level (params/bind-keyword-param level Number 50)\n        function (keyword function)\n        heads (find-heads-with-function function fixtures)\n        f (if htp?\n            ;; We need to resolve any dynamic parameters at this point so we can apply the\n            ;; highest-take-precedence rule.\n            (fn [show snapshot target previous-assignment]\n              (max (params/resolve-param level show snapshot target)\n                   (or (params/resolve-param previous-assignment show snapshot target) 0)))\n            ;; We can defer parameter resolution until the final DMX level assignment stage.\n            (fn [show snapshot target previous-assignment]\n              level))\n        assigners (build-head-function-assigners function heads f)]\n    (Effect. effect-name always-active (fn [show snapshot] assigners) end-immediately)))\n\n(defn function-value-scaler\n  \"Converts a named function value from an arbitrary range to a\n  percentage along that range. Designed to be partially applied in a\n  fixture definition, so [[function-percentage-to-dmx]] can pass the\n  value being resolved as the last parameter.\"\n  [range-min range-max value]\n  {:pre [(< range-min range-max)]}\n  (if (< value range-min)\n    0\n    (if (> value range-max)\n      100\n      (* (- value range-min) (/ 100 (- range-max range-min))))))\n\n(defn function-percentage-to-dmx\n  \"Given a percentage value and a named function specfication which\n  identifies a range of DMX channel values, scales the percentage into\n  that range. If the function spec has a value scaler function\n  attached to it (via the key `:scale-fn`), call that with the value\n  to get the percentage before scaling it to the DMX range.\"\n  [percent function-spec]\n  (let [range (- (:end function-spec) (:start function-spec))\n        scaler (:scale-fn function-spec)\n        percent (clamp-percent-float (if (ifn? scaler)\n                                       (scaler percent)\n                                       percent))]\n    (math/round (+ (:start function-spec) (* (/ percent 100) range)))))\n\n;; Resolves the assignment of a level to a named function on a head or fixture.\n(defmethod fx/resolve-assignment :function [assignment show snapshot buffers]\n  ;; Resolve in case it is frame dynamic\n  (let [target (:target assignment)\n        resolved (params/resolve-param (:value assignment) show snapshot target)\n        [_ function-key] (:target-id assignment)\n        [channel function-spec] (function-key (:function-map target))]\n    (apply-channel-value buffers channel (function-percentage-to-dmx resolved function-spec))))\n\n;; Fades between two assignments to a function. Because different functions often share the same channel,\n;; this will only fade when both the from and to assignment are non-nil, meaning this function is active\n;; both before and after the fade. Otherwise, it will just switch at the midpoint, so that chases which\n;; want to move between activations of different functions on the same channel can do so at the correct\n;; point in time.\n(defmethod fx/fade-between-assignments :function [from-assignment to-assignment fraction show snapshot]\n  (cond (<= fraction 0) from-assignment\n        (>= fraction 1) to-assignment\n        (some nil? [(:value to-assignment) (:value from-assignment)]) (if (< fraction 0.5)\n                                                                        from-assignment\n                                                                        to-assignment)\n        ;; We are blending, so we need to resolve any remaining dynamic parameters now, and make sure\n        ;; fraction really does only range between 0 and 1.\n        :else (let [target (:target from-assignment)\n                    from-resolved (clamp-percent-float\n                                   (params/resolve-param (:value from-assignment) show snapshot target))\n                    to-resolved (clamp-percent-float (params/resolve-param (:value to-assignment) show snapshot target))\n                    fraction (clamp-unit-float fraction)]\n                (merge from-assignment {:value (+ (* fraction to-resolved) (* (- 1.0 fraction) from-resolved))}))))\n"
  },
  {
    "path": "src/afterglow/effects/color.clj",
    "content": "(ns afterglow.effects.color\n  \"Effects pipeline functions for working with color assignments to\n  fixtures and heads.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as channels]\n            [afterglow.effects :as fx]\n            [afterglow.effects.channel :as chan-fx]\n            [afterglow.effects.oscillators :as osc]\n            [afterglow.effects.params :as params]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show-context :refer [*show*]]\n            [afterglow.util :as util]\n            [clojure.math.numeric-tower :as math]\n            [com.evocomputing.colors :as colors]\n            [taoensso.timbre :as timbre]\n            [taoensso.tufte :as tufte])\n  (:import (afterglow.effects Assigner Effect)))\n\n(defn htp-merge\n  \"Helper function for assigners that want to use\n  highest-takes-priority blending for RGB colors. Returns a color\n  that contains the highest red component from the two input colors,\n  the highest green component, and the highest blue component.\"\n  [previous current]\n  (if (some? previous)\n    (let [red (max (colors/red previous) (colors/red current))\n          green (max (colors/green previous) (colors/green current))\n          blue (max (colors/blue previous) (colors/blue current))]\n      (colors/create-color :r red :g green :b blue))\n    current))\n\n(defn build-htp-color-assigner\n  \"Returns an assigner that applies highest-takes-precedence color\n  mixing of a dynamic color parameter to the supplied head or fixture.\n  If the parameter is not frame-dynamic, it gets resolved when\n  creating this assigner. Otherwise, resolution is deferred to frame\n  rendering time. At that time, both the previous assignment and the\n  current parameter are resolved, and the red, green, and blue values\n  of the color are set to whichever of the previous and current\n  assignment held the highest.\"\n  [head param show snapshot]\n  (let [resolved (params/resolve-unless-frame-dynamic param show snapshot head)]\n    (fx/build-head-assigner :color head\n                            (fn [show snapshot target previous-assignment]\n                              (if (some? previous-assignment)\n                                (let [current (params/resolve-param resolved show snapshot head)\n                                      previous (params/resolve-param previous-assignment show snapshot head)]\n                                  (htp-merge previous current))\n                                resolved)))))\n\n(defn build-htp-color-assigners\n  \"Returns a list of assigners which apply highest-takes-precedence\n  color mixing to all the supplied heads or fixtures.\"\n  [heads param show]\n  (let [snapshot (rhythm/metro-snapshot (:metronome show))]\n    (map #(build-htp-color-assigner % param show snapshot) heads)))\n\n(defn color-effect\n  \"Returns an effect which assigns a color parameter to all heads of\n  the fixtures supplied when invoked. If `:include-color-wheels?` is\n  passed with a `true` value, then fixtures which use color wheels are\n  included, otherwise only color-mixing fixtures are included. If\n  `:htp?` is passed with a `true` value, highest-takes-precedence\n  assignment is used with the red, green, and blue color values to\n  blend this color with any previous color that might have been\n  assigned to the affected fixtures.\"\n  [name color fixtures & {:keys [include-color-wheels? htp?]}]\n  {:pre [(some? *show*) (some? name) (sequential? fixtures)]}\n  (params/validate-param-type color :com.evocomputing.colors/color)\n  (let [heads (channels/find-rgb-heads fixtures include-color-wheels?)\n        assigners (if htp?\n                    (build-htp-color-assigners heads color *show*)\n                    (fx/build-head-parameter-assigners :color heads color *show*))]\n    (Effect. name fx/always-active (fn [show snapshot] assigners) fx/end-immediately)))\n\n;;; Multimethod implementations to support color effects\n\n;; Resolves the assignment of a color to a fixture or a head,\n;; performing color mixing with any color component channels found in\n;; the target head. If color wheel heads were included in the cue, will\n;; find the closest matching hue on the wheel, as long as it is within\n;; tolerance. The default tolerance is 60 degrees around the hue wheel,\n;; which is very lenient. If you want to tighten that up, you can set a\n;; lower value in the show variable :color-wheel-hue-tolerance. The\n;; saturation must also be at least 40% for the color wheel to be\n;; considered; that minimum can be adjusted by setting a value in the\n;; show variable :color-wheel-min-saturation.\n(defmethod fx/resolve-assignment :color [assignment show snapshot buffers]\n  ;; Resolve in case assignment is still frame dynamic\n  (let [target (:target assignment)\n        resolved (params/resolve-param (:value assignment) show snapshot target)\n        color-key (keyword (str \"color-\" (:id target)))]\n    ;; Start with RGB mixing\n    (doseq [c (filter #(= (:color %) :red) (:channels target))]\n      (chan-fx/apply-channel-value buffers c (colors/red resolved)))\n    (doseq [c (filter #(= (:color %) :green) (:channels target))]\n      (chan-fx/apply-channel-value buffers c (colors/green resolved)))\n    (doseq [c (filter #(= (:color %) :blue) (:channels target))]\n      (chan-fx/apply-channel-value buffers c (colors/blue resolved)))\n    (swap! (:movement *show*) #(assoc-in % [:current color-key] resolved))\n    ;; Expermental: Does this work well in bringing in the white channel?\n    (when-let [whites (filter #(= (:color %) :white) (:channels target))]\n      (let [l (/ (colors/lightness resolved) 100)\n            s (/ (colors/saturation resolved) 100)\n            s-scale (if (< l 0.5) 1.0 (- 1.0 (* 2.0 (- l 0.5))))\n            level (* 255.0 l (- 1.0 (* s s-scale)))]\n        (doseq [c whites]\n          (chan-fx/apply-channel-value buffers c level))))\n    ;; Even more experimental: Support other arbitrary color channels\n    (doseq [c (filter :hue (:channels target))]\n      (let [as-if-red (colors/adjust-hue resolved (- (:hue c)))]\n        (chan-fx/apply-channel-value buffers c (colors/red as-if-red))))\n    ;; Finally, see if there is a color wheel color close enough to select\n    (when (and (seq (:color-wheel-hue-map target))\n               (>= (colors/saturation resolved) (:color-wheel-min-saturation @(:variables show) 40)))\n      (let [found (util/find-closest-key (:color-wheel-hue-map target) (colors/hue resolved))\n            [channel function-spec] (get (:color-wheel-hue-map target) found)]\n        (when (< (math/abs (- (colors/hue resolved) found)) (:color-wheel-hue-tolerance @(:variables show) 60))\n          (chan-fx/apply-channel-value buffers channel (chan-fx/function-percentage-to-dmx 50 function-spec)))))))\n\n(def ^:private default-color\n  \"The color to mix with when fading from a non-assignment.\"\n  (colors/create-color :black))\n\n(defn- blackened-color\n  \"Determine the color to fade to when one side of a fade is nil;\n  return the fully darkened version of the other color in the fade, if\n  there is one, or a default black if both were nil.\"\n  [color]\n  (if color (colors/darken color 100.0) default-color))\n\n(defn fade-colors\n  \"Calculate a weighted HSL blend between two colors, which may be\n  dynamic parameters, and where nil is considered to be a fully\n  darkened version of the other side of the fade.\"\n  [from to fraction show snapshot target]\n  ;; Resolve any remaining dynamic parameters now, and make sure fraction really\n  ;; does only range between 0 and 1, then convert it to the percentage wanted by\n  ;; the colors library.\n  (let [from (params/resolve-param from show snapshot target)\n        to (params/resolve-param to show snapshot target)\n        weight (* 100 (colors/clamp-unit-float fraction))]\n    ;; Weight goes in the opposite direction you might expect, so the following order works:\n    (colors/mix-hsl (or to (blackened-color from)) (or from (blackened-color to)) weight)))\n\n;; Fades between two color assignments to a fixture or head.\n(defmethod fx/fade-between-assignments :color [from-assignment to-assignment fraction show snapshot]\n  (cond (<= fraction 0) from-assignment\n        (>= fraction 1) to-assignment\n        :else (merge from-assignment {:value (fade-colors (:value from-assignment) (:value to-assignment) fraction\n                                                          show snapshot (:target from-assignment))})))\n\n;;; Effects which transform other color effects\n\n(defn build-saturation-transformation\n  \"Creates a color transformation for use with [[transform-colors]]\n  which changes the saturation based on a variable parameter. If no\n  parameter is supplied, the default is to use an oscillated parameter\n  based on [[sawtooth]] with `:down?` set to `true` so the color is\n  fully saturated at the start of the beat, and fully desaturated by\n  the end. A different pattern can be created by supplying a different\n  parameter with the `:param` optional keyword argument.\"\n  [& {:keys [param] :or {param (osc/build-oscillated-param (osc/sawtooth :down? true) :max 100)}}]\n  (fn [color show snapshot head]\n    (let [saturation (colors/clamp-percent-float (params/resolve-param param show snapshot head))]\n      (colors/create-color {:h (colors/hue color) :s saturation :l (colors/lightness color)}))))\n\n(defn transform-colors\n  \"Creates an effect which modifies any effect that is currently\n  assigning a color to the supplied fixtures. Needs to be assigned a\n  higher priority than any effects it should transform, so that it\n  will run after them. The actual transformation is implemented by a\n  function which takes a color, show, snapshot, and head, and returns\n  a transformed color. This function is specified with the\n  `:transform-fn` optional keyword argument; if none is specified,\n  [[build-saturation-transformation]] is called with no arguments to\n  create one which causes the saturation of the color to range from\n  full at the start of each beat to none at the end.\n\n  If the optional keyword argument `:beyond-server` is passed with a\n  Beyond server (as returned by [[beyond-server]]), any color being\n  sent to that integrated laser show using [[laser-color-effect]] will\n  also be transformed.\"\n  [fixtures & {:keys [transform-fn beyond-server] :or {transform-fn (build-saturation-transformation)\n                                                       beyond-server nil}}]\n  (let [heads (channels/find-rgb-heads fixtures)\n        f (fn [show snapshot target previous-assignment]  ;; Assigners for regular light colors; have heads\n            (tufte/p ::transform-colors\n                     (when-let [resolved (params/resolve-param previous-assignment show snapshot target)]\n                       (transform-fn resolved show snapshot target))))\n        lf (when beyond-server\n             (fn [show snapshot target previous-assignment]  ;; Assigner for laser show colors; no head\n               (tufte/p ::transform-colors\n                        (when-let [resolved (params/resolve-param previous-assignment show snapshot)]\n                          (transform-fn resolved show snapshot nil)))))\n        assigners (concat (fx/build-head-assigners :color heads f)\n                          (when beyond-server\n                            [(Assigner. :beyond-color (:id beyond-server) beyond-server lf)]))]\n    (Effect. \"Transform Colors\" fx/always-active (fn [show snapshot] assigners) fx/end-immediately)))\n"
  },
  {
    "path": "src/afterglow/effects/cues.clj",
    "content": "(ns afterglow.effects.cues\n  \"Cues provide a user interface for controlling effects, by\n  associating them with cells in a cue grid so they can be easily\n  triggered and monitored, either through a physical grid controller,\n  or the web show control interface. They also provide a way of\n  binding cue variables to effect parameters, which can enable\n  controller interfaces to adjust them, and of tying those variables\n  to velocity and pressure sensitivity on physical grid controllers\n  which have such capabilities.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.controllers :as controllers]\n            [afterglow.effects :as fx]\n            [afterglow.effects.channel :as chan]\n            [afterglow.effects.params :as params]\n            [afterglow.midi :as midi]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [*show* with-show]]\n            [afterglow.util :as util]\n            [taoensso.timbre :as timbre])\n  (:import (afterglow.effects Effect)))\n\n(defn cue\n  \"Creates a cue for managing in a cue grid. `show-key` will be used\n  as the effect keyword when the cue is triggered to add it to a show,\n  ending any existing effect that was using that key. `effect-fn` is a\n  function that will be called to obtain the effect to be started and\n  monitored when this cue is triggered. It will be passed a map\n  allowing lookup of any temporary variables introduced by the\n  cue (see the `:variables` parameter below).\n\n  If supplied, `:short-name` identifies a compact, user-oriented name\n  to be displayed in the web interface or controller display (if it\n  has one) to help identify the cue, which can be helpful if the name\n  of the underlying effect is ambiguous or overly long.\n\n `:color` requests that the web interface and control surfaces draw\n  the cue using the specified color rather than the default white to\n  help the user identify it. This is only a request, as not all\n  control surfaces support all (or any) colors. The color is passed\n  to [[interpret-color]], so it can be specified in a variety of ways.\n  If omitted, a default color of white is used.\n\n  `:color-fn`, if present, is a function that will be called to\n  determine the current color to be used in user interfaces for cues\n  that have variable colors. This function will be called with the\n  cue, the currently-running effect launched by that cue (if any), as\n  returned by [[show/find-effect]], the show, and metronome snapshot\n  representing the time at which the user interface is being updated.\n  If it returns a value, that will be used rather than the static\n  color in `:color`. If it returns `nil`, `:color` is used instead. As\n  with `:color`, the presence of this function is only a request, not\n  all user interfaces support dynamic cue colors.\n\n  `:end-keys` introduces a sequence of keywords identifying other\n  effects which should be ended whenever this one is started. This\n  allows a set of grid cues to be set up as mutually exclusive, even\n  if they use different keywords within the show for other reasons.\n\n  `:priority` assigns a sorting priority to the effect. If not\n  assigned, a default priority of zero is used. The effect will be\n  added to the show after any effects of equal or lower priority, but\n  before any with higher priority. Effects are run in order, and later\n  effects can override earlier ones if they are trying to affect the\n  same things, so a higher priority and more recent effect wins.\n\n  If `:held` is passed with a true value, then the cue will be active\n  only as long as the corresponding pad or button on the control\n  surface is held down, for controllers which support this feature.\n  This can be useful for very intense cues like strobes. Show\n  operators can override the `:held` flag by holding down the `Shift`\n  key when triggering the cue on interfaces which have `Shift` keys,\n  like the web interface and Ableton Push.\n\n  To support controllers with animated graphical displays like the\n  Push 2, a visualizer creation function can be passed with the\n  optional keyword argument `:visualizer`. This function will be\n  called when the controller wants to draw a visualization of the\n  progression of the cue over time, and will be passed two arguments,\n  the cue's `var-map` (see below), and the `show` in which the cue is\n  running. The function must return another function, which takes a\n  metronome snapshot, and returns a value between 0 and 1 representing\n  some meaningful numerical summary of the cue state at that time. It\n  will be used to draw a moving strip chart of the cue's activity\n  around the current moment on the display. The example dimmer\n  oscillator cues like [[make-sine-dimmer-cue]] show how this can be\n  used to good effect.\n\n  `:variables` introduces a list of variable bindings for the cue,\n  each of which is a map with the following keys:\n\n  * `:key` identifies the variable that is being bound by the cue (for easy\n    adjustment in the user interface while the cue is running). If it is\n    a string rather than a keyword, it identifies a temporary variable\n    which need exist only for the duration of the cue. The actual name\n    will be assigned when the cue is activated. In order for `effect-fn`\n    to be able to access the correct variable, it is passed a map\n    whose keys are keywords made from the string `:key` values supplied\n    in the `:variables` list, and whose values are the actual keyword\n    of the corresponding temporary show variable created for the cue.\n\n  * `:name`, if present, gives the name by which the variable should be\n    displayed in the user interface for adjusting it. If not specified,\n    the name of `:key` is used.\n\n  * `:short-name`, if present, is a shorter version of the name which\n    can be used in interfaces with limited space.\n\n  * `:min` specifies the minimum value to which the variable can be set.\n    If not supplied, zero is assumed.\n\n  * `:max` specifies the maximum value to which the variable can be set.\n    If not supplied, 100 is assumed.\n\n  * `:start` specifies the value to assign to the variable at the\n    start of the cue, if any. It can be a simple value, a keyword which\n    will be replaced by the current value of a show variable by the same\n    name when the cue begins, or a function which will be called to\n    obtain a value for the variable.\n\n  * `:type` identifies the type of the variable, to help formatting\n    its display. Supported values are `:integer`, `:double`, and\n    `:color`. Other types may be supported in the future. If omitted or\n    unrecognized, `:double` is assumed.\n\n  * `:centered` supplied with a true value requests that the gauge\n    displayed when adjusting this variable's value be like a pan\n    gauge, showing deviation from a central value, for interfaces\n    which support this.\n\n  * `:resolution` specifies the smallest amount by which the variable\n     will be incremented or decremented when the user adjusts it using\n     a continuous encoder on a physical controller. If not specified the\n     resolution is up to the controller, but 1/256 of the range from\n     `:min` to `:max` is a recommended default implementation, since that\n     allows access to the full DMX parameter space for channel-oriented\n     values.\n\n  * `:velocity` accompanied by a true value enables the variable to be\n     set by strike pressure and adjusted by aftertouch pressure while the\n     pad which launched the cue is held down on pressure-sensitive\n     controllers.\n\n  * `:velocity-min` and `:velocity-max` specify the range into\n     which MIDI velocity and aftertouch values will be mapped, if they are present.\n     Otherwise the standard `:min` and `:max` values will be used.\"\n  [show-key effect-fn & {:keys [variables short-name color color-fn end-keys priority held visualizer]\n                         :or {short-name (:name (show/get-cue-effect effect-fn variables)) color :white priority 0}}]\n  {:pre [(some? show-key) (ifn? effect-fn) (satisfies? fx/IEffect (show/get-cue-effect effect-fn variables))\n         (or (nil? color-fn) (ifn? color-fn)) (or (nil? visualizer) (ifn? visualizer))]}\n  (merge {:name (name short-name)\n          :key (keyword show-key)\n          :effect effect-fn\n          :priority priority\n          :held held\n          :color (params/interpret-color (if (keyword? color) (name color) color))\n          :end-keys (vec end-keys)\n          :variables (vec variables)}\n         (when color-fn {:color-fn color-fn})\n         (when visualizer {:visualizer visualizer})))\n\n(defn function-cue\n  \"Creates a cue that applies the specified function to the supplied\n  fixtures or heads. Automatically adds a temporary variable for\n  adjusting the function value if the function is not fixed over its\n  range. `show-key` will be used as the effect keyword when the cue is\n  triggered to add it to a show, ending any existing effect that was\n  using that key. `function` identifies the fixture function to be\n  activated by this cue, and `fixtures` lists the fixtures and heads\n  can which should be affected (though only fixtures and heads which\n  implement the specified function will actually participate).\n\n  Passing a value for `:effect-name` sets the name for the effect\n  created by this cue. If none is provided, the name of the function\n  is used.\n\n  If supplied, `:short-name` identifies a compact, user-oriented name\n  to be displayed in the web interface or controller display (if it\n  has one) to help identify the cue, which can be helpful if the name\n  of the underlying effect is ambiguous or overly long.\n\n  `:color` requests that the web interface and control surfaces draw\n  the cue using the specified color rather than the default white to\n  help the user identify it. This is only a request, as not all\n  control surfaces support all (or any) colors. The color is passed\n  to [[interpret-color]], so it can be specified in a variety of ways.\n\n  `:level` can be used to set the initial level for functions which\n  have a variable effect over their range. Such functions will be\n  automatically assigned a variable parameter which can be used to\n  adjust the level while the cue runs, and which will be visible in\n  the web interface and on controllers which support adjusting cue\n  parameters. Function levels are expressed as a percentage, which is\n  mapped onto the range of DMX values which are assigned to the\n  function in the fixture definition. Functions with no variable\n  effect will ignore `:level` and will not be assigned variables for\n  adjustment.\n\n  If `:htp` is passed a true value, the created effect applies\n  highest-takes-precedence (i.e. compares the value to the previous\n  assignment for the channels implementing the function, and lets the\n  highest value remain). See [[channel/function-effect]] for more\n  details about the underlying effect.\n\n  `:end-keys` introduces a sequence of keywords identifying other\n  effects which should be ended whenever this one is started. This\n  allows a set of grid cues to be set up as mutually exclusive, even\n  if they use different keywords within the show for other reasons.\n\n  `:priority` assigns a sorting priority to the effect. If not\n  assigned, a default priority of zero is used. The effect will be\n  added to the show after any effects of equal or lower priority, but\n  before any with higher priority. Effects are run in order, and later\n  effects can override earlier ones if they are trying to affect the\n  same things, so a higher priority and more recent effect wins.\n\n  If `:held` is passed with a true value, then the cue will be active\n  only as long as the corresponding pad or button on the control\n  surface is held down, for controllers which support this feature.\n  This can be useful for very intense cues like strobes. Show\n  operators can override the `:held` flag by holding down the `Shift`\n  key when triggering the cue on interfaces which have `Shift` keys,\n  like the web interface and Ableton Push.\n\n  If the function being controlled has a variable effect, and thus a\n  cue variable is being introduced to adjust it, `:velocity`,\n  `:velocity-min`, and `:velocity-max` will be used when creating\n  that variable, allowing it to be controlled by strike and aftertouch\n  pressure on control surfaces which support that feature, as described\n  in [[cue]].\"\n  [show-key function fixtures & {:keys [level htp? effect-name short-name color color-fn end-keys priority held\n                                        velocity velocity-min velocity-max]\n                                 :or {color :white level 0 priority 0}}]\n  (let [function (keyword function)\n        heads (chan/find-heads-with-function function fixtures)\n        specs (map second\n                   (map function\n                        (map :function-map\n                             (afterglow.effects.channel/find-heads-with-function function (show/all-fixtures)))))\n        effect-name (or effect-name (:label (first specs)) (name function))\n        short-name (or short-name effect-name)\n        variable? (some #(= (:range %) :variable) specs)]\n    (if variable?\n      ;; Introduce a variable for conveniently adjusting the function level\n      (let [label (or (:var-label (first specs)) \"Level\")]\n        (cue show-key (fn [var-map] (chan/function-effect effect-name function (params/bind-keyword-param\n                                                                                (:level var-map level) Number level)\n                                                          fixtures :htp? htp?))\n             :short-name short-name\n             :color color\n             :color-fn color-fn\n             :end-keys end-keys\n             :priority priority\n             :held held\n             :variables [(merge {:key \"level\" :min 0 :max 100 :start level :name label}\n                                (when velocity {:velocity velocity})\n                                (when velocity-min {:velocity-max velocity-min})\n                                (when velocity-max {:velocity-max velocity-max}))]))\n      ;; It's a fixed function, no variable required\n      (cue show-key (fn [_] (chan/function-effect effect-name function (params/bind-keyword-param level Number 0)\n                                                  fixtures :htp? htp?))\n           :short-name short-name\n           :color color\n           :color-fn color-fn\n           :end-keys end-keys\n           :priority priority\n           :held held))))\n\n;; TODO: A compound function cue which takes a vector of functions\n;;       and htp/velocity/level/var-label-overrides and builds a\n;;       single effect.\n\n(defn compound-cues-effect\n  \"Creates an effect which launches the specified cues from the grid,\n  stays running as long as they are, and ends them all when it is\n  asked to end. Takes a list of three-element tuples identifying the x\n  and y coordinates within the cue grid of the subordinate cues to\n  launch, and an optional map of cue variable overrides, which can be\n  used to change the initial values of any temporary variables\n  introduced by that cue.\"\n  [name show cues]\n  (let [running (filter identity (for [[x y overrides] cues]\n                                   (with-show show\n                                     (when-let [id (show/add-effect-from-cue-grid! x y :var-overrides overrides)]\n                                       [id (:key (controllers/cue-at (:cue-grid show) x y))]))))]\n    (Effect. name\n             (fn [show snapshot]  ; We are still running if any of the nested effects we launched are.\n               (with-show show\n                 (some (fn [[id k]]\n                         (when-let [effect (show/find-effect k)]\n                           (= (:id effect) id)))\n                       running)))\n             (fn [show snapshot] nil)  ; We do not assign any values; only the nested effects do.\n             (fn [show snapshot]  ; Tell all our launched effects to end.\n               (with-show show\n                 (doseq [[id k] running]\n                   (show/end-effect! k :when-id id)))))))\n\n\n(defn code-cue\n  \"Creates a cue that runs an arbitrary chunk of Clojure code instead\n  of starting an effect, for example to reset the metronome if the\n  controller mapping doesn't have a dedicated button for doing that.\n\n  The `code` argument must be a function that takes two arguments. It\n  will be called with the show and metronome snapshot when the cue is\n  started, and should return immediately, because this takes place on\n  the effect rendering pipeline, so any lengthy operations must be\n  performed on another thread. The effect won't do anything else after\n  calling `code` once, but the cue is configured to keep it\n  \\\"running\\\" until you let go of that grid controller pad, so you can\n  see visual feedback that it ran.\n\n  The `label` argument is a string which is used to identify the cue\n  in the cue grid.\n\n  The optional keyword argument `:color` requests that the web\n  interface and control surfaces draw the cue using the specified\n  color rather than the default white to help the user identify it.\n  This is only a request, as not all control surfaces support all (or\n  any) colors. The color is passed to [[interpret-color]], so it can\n  be specified in a variety of ways.\"\n  [code label & {:keys [color] :or {color :white}}]\n  {:pre [(ifn? code) (string? label)]}\n  (cue ::code-cue (fn [_] (fx/code code)) :short-name label :color color :held true))\n\n(defn find-cue-variable-keyword\n  \"Finds the keyword by which a cue variable is accessed; it may be\n  directly bound to a show variable, or may be a temporary variable\n  introduced for the cue, whose name needs to be looked up in the\n  running effect's variable map. If a temporary variable, the id of\n  the effect which is expected to be running for the cue must be\n  passed with `:when-id`, and this id must match the id of the actual\n  effect currently running under that key, or `nil` will be returned.\n\n  If a show is passed with the `:show` optional keyword argument, the\n  effect is looked up in that show. Otherwise, it is looked up in the\n  default show.\"\n  [cue var-spec & {:keys [show when-id]}]\n  (if show\n    (with-show show\n      (find-cue-variable-keyword cue var-spec :when-id when-id))\n    (let [effect (show/find-effect (:key cue))]\n      (if (keyword? (:key var-spec))\n        (when (or (nil? when-id) (= when-id (:id effect)))\n          (:key var-spec))\n        (when (and (some? effect) (= when-id (:id effect)))\n          ((keyword (:key var-spec)) (:variables effect)))))))\n\n(defn get-cue-variable\n  \"Finds the current value of the supplied cue variable, which may be\n  directly bound to a show variable, or may be a temporary variable\n  introduced for the cue, whose name needs to be looked up in the\n  running effect's variable map. If a temporary variable, the id of\n  the effect which is expected to be running for the cue must be\n  passed with `:when-id`, and this id must match the id of the actual\n  effect currently running under that key, or `nil` will be returned.\n\n  Permanent variables associated with the cue can always be retrieved by\n  omitting `:with-id`. If you want to only get the variable when a\n  particular effect is running, however, you can do so by passing in\n  that effect's id with `:with-id`, and the same restriction will then\n  be applied as is for temporary variables.\n\n  If a show is passed with the `:show` optional keyword argument, the\n  effect is looked up in that show. Otherwise, it is looked up in the\n  default show.\"\n  [cue var-spec & {:keys [show when-id]}]\n  (if show\n    (with-show show\n      (get-cue-variable cue var-spec :when-id when-id))\n    (when-let [k (find-cue-variable-keyword cue var-spec :when-id when-id)]\n      (util/normalize-cue-variable-value var-spec (show/get-variable k)))))\n\n(defn set-cue-variable!\n  \"Sets the current value of the supplied cue variable, which may be\n  directly bound to a show variable, or may be a temporary variable\n  introduced for the cue, whose name needs to be looked up in the\n  running effect's variable map. If a temporary variable, the id of\n  the effect which is expected to be running for the cue must be\n  passed with `:when-id`, and this id must match the id of the actual\n  effect currently running under that key, or nothing will be set.\n\n  Permanent variables associated with the cue can always be set by\n  omitting `:with-id`. If you want to only affect the variable when a\n  particular effect is running, however, you can do so by passing in\n  that effect's id with `:with-id`, and the same restriction will then\n  be applied as is for temporary variables.\n\n  If a show is passed with the `:show` optional keyword argument, the\n  effect is looked up in that. Otherwise, it is looked up in the\n  default show.\"\n  [cue var-spec value & {:keys [show when-id]}]\n  (if show\n    (with-show show\n      (set-cue-variable! cue var-spec value :when-id when-id))\n    (when-let [k (find-cue-variable-keyword cue var-spec :when-id when-id)]\n      (show/set-variable! k value))))\n\n(defn snapshot-cue-variables\n  \"Returns a map containing the keys and current values of all\n  variables used by the specified cue, which is suitable for saving via\n  [[save-cue-vars!]]. The id of the effect currently running the cue\n  must be passed as `when-id` to ensure that the cue is still running.\n  If it is not running (or ends while the variable values are being\n  looked up), `nil` is returned.\n\n  If a show is passed with the `:show` optional keyword argument, the\n  effect is looked up in that show. Otherwise, it is looked up in the\n  default show.\"\n  [cue when-id & {:keys [show]}]\n  {:pre [(some? when-id)]}\n  (if show\n    (with-show show\n      (snapshot-cue-variables cue when-id))\n    (let [result (map (fn [v]\n                        [(keyword (:key v)) (get-cue-variable cue v :when-id when-id)])\n                      (:variables cue))]\n      (when (= when-id (:id (show/find-effect (:key cue))))\n        (into {} result)))))\n\n(defn add-midi-to-cue-mapping\n  \"Cause the specified cue from the [[*show*]] cue grid to be\n  triggered by receipt of the specified note (when `kind` is `:note`)\n  or controller-change (when `kind` is `:control`) message with a\n  non-zero velocity or control value. This allows generic MIDI\n  controllers, which do not have enough pads or feedback capabilities\n  to act as a full grid controller like the Ableton Push, to still\n  provide a physical means of triggering cues.\n\n  The device to be mapped is identified by `device-filter`. The first\n  input port which matches using [[filter-devices]] will be used.\n\n  The desired cue is identified by passing in its `x` and `y`\n  coordinates within the show cue grid.\n\n  Afterglow will attempt to provide feedback about the progress of the\n  cue by sending note on/off or control-change values to the same\n  controller when the cue starts and ends. The note velocities or\n  control values used can be changed by passing in different values\n  with `:feedback-on` and `:feedback-off`, and this behavior can be\n  suppressed entirely by passing `false` with `:feedback-on`.\n\n  If the controller is pressure-sensitive and you would like to have\n  the velocity information passed on to any cue variables which are\n  configured to respond to it, pass `true` with `:use-velocity`. This\n  is the default assumed if `:use-velocity` is omitted, and also\n  enables responsiveness to aftertouch (polyphonic key pressure)\n  messages, which can adjust the cue variable for as long as you are\n  holding down the key or pad, if your controller sends them (and\n  `kind` is `:note`).\n\n  If the controller is not pressure-sensitive, and you would like to\n  have the cue react as if it was pressed with a particular velocity,\n  you can pass a number from `0` to `127` with `:use-velocity`.\n  Whenever the cue is activated, it will be activated with the\n  specified velocity. If you pass `:use-velocity` with `false`, the\n  cue will be activated with a default velocity. In any of these cases\n  where `use-velocity` is not `true`, no attempt will be made to\n  respond to aftertouch messages.\n\n  Afterglow assumes the control is momentary, meaning it sends a note\n  off (or control value of 0) as soon as it is released, and a second\n  press will be used to end the cue unless the cue uses the `:held`\n  modifier to indicate it should be ended when the button is released.\n  If your controller does not have momentary buttons and already\n  requires a second press to turn off the note or control value, pass\n  `false` with `:momentary?` and Afterglow will always end cues when\n  it receives a control value of 0, even if cues are not marked as\n  `:held`.\n\n  Returns the cue-triggering function which can be passed\n  to [[remove-midi-to-cue-mapping]] if you ever want to stop the MIDI\n  control or note from affecting the cue in the future.\"\n  [device-filter channel kind note x y & {:keys [feedback-on feedback-off use-velocity momentary?]\n                                             :or {feedback-on 127 feedback-off 0 use-velocity true momentary? true}}]\n  {:pre [(some? *show*) (#{:control :note} kind) (some? device-filter) (integer? channel) (<= 0 channel 15)\n         (integer? note) (<= 0 note 127) (integer? x) (<= 0 x) (integer? y) (<= 0 y)\n         (or (not feedback-on) (and (integer? feedback-on) (<= 0 feedback-on 127)))\n         (integer? feedback-off) (<= 0 feedback-off 127)\n         (or (true? use-velocity) (false? use-velocity) (and (integer? use-velocity) (<= 0 use-velocity 127)))]}\n  (let [show *show*  ; Bind so we can pass it to update functions running on another thread\n        feedback-device (when feedback-on (midi/find-midi-out device-filter))\n        our-id (atom nil)  ; Track when we have created an effect\n        midi-handler (fn [msg]\n                       (with-show show\n                         ;; See if the cue exists and is running\n                         (let [[cue active] (show/find-cue-grid-active-effect show x y)\n                               velocity (:velocity msg)\n                               aftertouch-handler (fn [msg]\n                                                    (with-show show\n                                                      (doseq [v (:variables cue)]\n                                                        (when (:velocity v)\n                                                          (set-cue-variable!\n                                                           cue v (controllers/value-for-velocity v (:velocity msg))\n                                                           :when-id @our-id)))))]\n                           (when cue\n                             (if (and (pos? velocity) (not= (:command msg) :note-off))\n                               ;; Control or note has been pressed\n                               (if (and active (not (:held cue)))\n                                 (show/end-effect! (:key cue))\n                                 (let [effective-velocity (if (true? use-velocity) velocity use-velocity)]\n                                   (if use-velocity\n                                     (reset! our-id (show/add-effect-from-cue-grid! x y :velocity effective-velocity))\n                                     (reset! our-id (show/add-effect-from-cue-grid! x y)))\n                                   (when (and (true? use-velocity) (= kind :note))\n                                     (midi/add-aftertouch-mapping device-filter channel note aftertouch-handler))))\n                               ;; Control has been released\n                               (when (some? @our-id)\n                                 (when (and (true? use-velocity) (= kind :note))\n                                   (midi/remove-aftertouch-mapping device-filter channel note aftertouch-handler))\n                                 (when (or (:held cue) (not momentary?))\n                                   (show/end-effect! (:key cue) :when-id @our-id)\n                                   (reset! our-id nil))))))))]\n    (when feedback-device  ; Set up to give feedback as cue activation changes\n      (controllers/add-cue-feedback! (:cue-grid show) x y feedback-device channel kind note\n                                     :on feedback-on :off feedback-off)\n      (let [[cue active] (show/find-cue-grid-active-effect show x y)]  ; Was already active, so reflect that\n        (when active (case kind\n                      :control (overtone.midi/midi-control feedback-device note feedback-on channel)\n                      :note (overtone.midi/midi-note-on feedback-device note feedback-on channel)))))\n    (case kind\n      :control (midi/add-control-mapping device-filter channel note midi-handler)\n      :note (midi/add-note-mapping device-filter channel note midi-handler))\n    midi-handler))\n\n(defn add-midi-control-to-cue-mapping\n  \"Deprecated in favor of the more accurately\n  named [[add-midi-to-cue-mapping]].\"\n  {:deprecated \"0.2.0\"}\n  [device-filter channel kind note x y & {:keys [feedback-on feedback-off use-velocity momentary?]\n                                          :or {feedback-on 127 feedback-off 0 use-velocity true momentary? true}}]\n  (add-midi-to-cue-mapping device-filter channel kind note x y :feedback-on feedback-on :feedback-off feedback-off\n                           :use-velocity use-velocity :momentary? momentary?))\n\n(defn remove-midi-to-cue-mapping\n  \"Stop triggering the specified cue from the [[*show*]] cue grid upon\n  receipt of the specified note or controller-change message. The\n  desired cue is identified by passing in its `x` and `y` coordinates\n  within the show cue grid. `f` is the handler function that was\n  returned by [[add-midi-to-cue-mapping]] when the mapping was\n  established.\"\n  [device-filter channel kind note x y f]\n  {:pre [(some? *show*) (#{:control :note} kind) (some? device-filter) (integer? channel) (<= 0 channel 15)\n         (integer? note) (<= 0 note 127) (integer? x) (<= 0 x) (integer? y) (<= 0 y) (ifn? f)]}\n  (let [feedback-device (first (midi/filter-devices device-filter (midi/open-outputs-if-needed!)))\n        feedback (when feedback-device\n                   (controllers/clear-cue-feedback! (:cue-grid *show*) x y feedback-device channel kind note))]\n    (when feedback  ; We had been giving feedback, see if we need to turn it off\n      (let [[cue active] (show/find-cue-grid-active-effect *show* x y)]\n        (when active (case kind\n                       :control (overtone.midi/midi-control feedback-device note (second feedback) channel)\n                       :note (overtone.midi/midi-note-on feedback-device note (second feedback) channel))))))\n  (case kind\n    :control (midi/remove-control-mapping device-filter channel note f)\n    :note (midi/remove-note-mapping device-filter channel note f)))\n\n(defn remove-midi-control-to-cue-mapping\n  \"Deprecated in favor of the more accurately named\n  [[remove-midi-to-cue-mapping]].\"\n  {:deprecated \"0.2.0\"}\n  [device-filter channel kind note x y f]\n  (remove-midi-to-cue-mapping device-filter channel kind note x y f))\n\n(defn current-cue-color\n  \"Given a cue, an active effect map, and a metronome snapshot\n  representing the moment for which the user interface is being\n  rendered, return the color with which the cue should be rendered on\n  a cue grid. If the cue is not currently running, `active` should be\n  `nil`. Handles the delegation to the cue's dynamic color function if\n  one has been assigned. Useful dynamic color functions are built\n  by [[color-fn-from-cue-var]] and [[color-fn-from-param]].\"\n  [cue active show snapshot]\n  (if-let [f (:color-fn cue)]\n    (or (f cue active show snapshot) (:color cue))\n    (:color cue)))\n\n(defn color-fn-from-cue-var\n  \"Builds a dynamic cue color function which reports the color of a\n  cue based on the content of a cue variable, given the cue variable\n  map.\n\n  When the cue is running, we look up the value of the specified cue\n  variable, and return that. If the variable is `nil`, the non-dynamic\n  cue color is returned.\n\n  When the cue is not running, we try to look up the saved value for\n  the variable if the cue's `x` and `y` grid coordinates were\n  supplied. If a saved value can be found for the variable, that color\n  is returned. Failing that, we check whether the variable is a\n  permanent show variable, which we can look up even when the cue is\n  not running. If so, and the variable has a non-`nil` value, we\n  return that color. Again, if all else fails, we return the\n  non-dynamic cue color.\"\n  ([var-spec]\n   (color-fn-from-cue-var var-spec nil nil))\n  ([var-spec x y]\n   (fn [cue active show _]\n     (let [candidates (if active\n                        [(get-cue-variable cue var-spec :show show :when-id (:id active)) (:color cue)]\n                        (let [saved (when (every? some? [x y])\n                                      ((keyword (:key var-spec)) (controllers/cue-vars-saved-at (:cue-grid show) x y)))\n                              permanent (when (and (nil? saved) (keyword? (:key var-spec)))\n                                          (get-cue-variable cue var-spec :show show :when-id (:id active)))]\n                          [saved permanent (:color cue)]))]\n       (some #(when (some? %) %) candidates)))))\n\n(defn color-fn-from-param\n  \"Builds a dynamic cue color function which reports the color of a\n  cue based on the value of a dynamic parameter. If the parameter\n  evaluates to `nil`, the non-dynamic cue color is returned.\"\n  [param]\n  (params/validate-param-type param :com.evocomputing.colors/color)\n  (fn [cue active show snapshot]\n    (or (params/evaluate param show snapshot nil) (:color cue))))\n\n(defmacro apply-merging-var-map\n  \"Call the specified function merging all keys and values from the\n  supplied cue variable map to the end of the provided argument list.\n  Useful when creating an effect with optional keyword arguments whose\n  values are being set by cue variables bound to the appropriate\n  keys.\"\n  [var-map f & args] `(apply ~f ~@args (apply concat ~var-map)))\n"
  },
  {
    "path": "src/afterglow/effects/dimmer.clj",
    "content": "(ns afterglow.effects.dimmer\n  \"Effects pipeline functions for working with dimmer channels for\n  fixtures and heads. Dimmer effects are always tied to a _master_\n  chain, which can scale back the maximum allowable value for that\n  dimmer channel, as a percentage. Unless otherwise specified, the\n  dimmer cue will be attached to the show grand master, but you can\n  create other masters to adjust the brightness of groups of fixtures,\n  perhaps because they are intrinsically brighter, or to adjust the\n  balance of lighting for artistic reasons. Secondary masters can be\n  chained to each other, and are always chained to the show grand\n  master, so turning that down will dim the entire show; setting it to\n  zero will black out the show.\n\n  This master scaling capability is so useful that you will almost\n  always want a prominent fader on a MIDI controller tied to the show\n  grand master, and possibly others to secondary masters.\n  [[show/add-midi-control-to-master-mapping]] makes that easy,\n  especially for the grand master, and for submasters stored in show\n  variables, which can be referred to by their keywords.\n\n  Some fixtures have damping functions that slow down their dimmer\n  response, so you may not get the kind of coordination you would like\n  from oscillated dimmer cues. A potential workaround is to use the\n  dimmer channels as a maximum brightness level to allow tweaking the\n  overall brightness of an effect, and using the lightness attribute\n  of a color cue to create time-varying brightness effects.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as channels]\n            [afterglow.effects.channel :as chan-fx]\n            [afterglow.effects.params :as params]\n            [afterglow.effects :as fx :refer [always-active end-immediately]]\n            [afterglow.rhythm :refer [metro-snapshot]]\n            [afterglow.show-context :refer [*show*]]\n            [afterglow.util :refer [valid-dmx-value?]]\n            [com.evocomputing.colors :as colors :refer [clamp-percent-float\n                                                        clamp-rgb-int]]\n            [taoensso.timbre :as timbre])\n  (:import (afterglow.effects Effect)))\n\n(defn- assign-level\n  \"Assigns a dimmer level to the channel.\"\n  [level channel]\n  (assoc channel :value level))\n\n(defn dimmer-channel?\n  \"Returns true if the supplied channel is a dimmer.\"\n  [c]\n  (= (:type c) :dimmer))\n\n(defn gather-dimmer-channels\n  \"Finds all channels in the supplied fixture list which are dimmers,\n  even if they are inside heads.\"\n  [fixtures]\n  (let [heads (channels/extract-heads-with-some-matching-channel fixtures dimmer-channel?)]\n    (channels/extract-channels heads dimmer-channel?)))\n\n(defn gather-partial-dimmer-function-heads\n  \"Find all heads in the supplied fixture list which contain\n  multipurpose channels that are partially used for dimming,\n  rather than full dedicated dimmer channels.\"\n  [fixtures]\n  (filter #(when-let [dimmer (:dimmer (:function-map %))]\n             (not= :dimmer (:type (first dimmer))))\n          (channels/expand-heads fixtures)))\n\n(defn gather-no-dimmer-rgb-heads\n  \"Finds all the RGB heads from the supplied fixture list which have\n  no dimmer capability at either the head or fixture level. These\n  heads are suitable for creating virtual dimmer effects when\n  desired.\"\n  [fixtures]\n  (let [no-dimmers (filter #(not (:dimmer (set (mapcat keys (map :function-map (channels/expand-heads [%]))))))\n                           fixtures)]\n    (channels/find-rgb-heads no-dimmers)))\n\n(defonce\n  ^{:private true\n    :doc \"Protect protocols against namespace reloads\"}\n  _PROTOCOLS_\n  (do\n(defprotocol IDimmerMaster\n  \"A chainable limiter of dimmer cues.\"\n  (master-set-level [master new-level]\n  \"Set the level of this master, as a percentage from 0 to 100. Any\n  value less than 100 will cause the dimmer cues attached to this\n  master to have their levels scaled back by that amount. If there are\n  any parent masters attached to this one, they may further scale back\n  the value in turn.\")\n  (master-get-level [master]\n  \"Get the level of this master, as a percentage from 0 to 100. Any\n  value less than 100 will cause the dimmer cues attached to this\n  master to have their levels scaled back by that amount. If there are\n  any parent masters attached to this one, they may further scale back\n  the value in turn.\")\n  (master-scale [master value]\n  \"Scale down the value being sent to a dimmer according to this\n  master level, and any parent masters associated with it.\"))))\n\n(defrecord Master [level parent]\n  IDimmerMaster\n  (master-set-level [master new-level]\n    (reset! level (clamp-percent-float new-level)))\n  (master-get-level [master]\n    @level)\n  (master-scale [master value]\n    (let [scaled (* value (/ @level 100))]\n      (if (some? parent)\n        (master-scale parent scaled)\n        scaled))))\n\n(defn master\n  \"Create a master for scaling dimmer cues. If you set its level to\n  less than 100 (interpreted as a percentage), all dimmer cues created\n  with this master will be scaled back appropriately. If you supply a\n  parent master, it will get a chance to scale them back as well. If\n  you don't, the show's grand master is used as the parent master.\"\n  [show & {:keys [level parent] :or {level 100 parent (:grand-master show)}}]\n  (let [initial-level (atom (clamp-percent-float level))]\n    (Master. initial-level parent)))\n\n(defn- build-parameterized-dimmer-effect\n  \"Returns an effect which assigns a dynamic value to all the supplied\n  dimmers (which are broken into three lists: full dedicated dimmer\n  channels, heads that have a dimmer function on a multipurpose\n  channel, and RGB heads with no dimmer at all that should be assigned\n  a virtual dimmer effect).\n\n  If `htp?` is true, applies highest-takes-precedence (i.e. compares\n  the value to the previous assignment for the channel, and lets the\n  highest value remain).\n\n  All dimmer cues are associated with a master chain which can scale\n  down the values to which they are set. If none is supplied when\n  creating the dimmer cue, the show's grand master is used.\"\n  [name level show full-channels function-heads virtual-heads htp? master]\n  (params/validate-param-type master Master)\n  (let [full-f (if htp?  ; Assignment function for dedicated dimmer channels\n                 (fn [show snapshot target previous-assignment]\n                   (clamp-rgb-int (max (master-scale master (params/resolve-param level show snapshot target))\n                                       (or (params/resolve-param previous-assignment show snapshot target) 0))))\n                 (fn [show snapshot target previous-assignment]\n                   (clamp-rgb-int (master-scale master (params/resolve-param level show snapshot target)))))\n        full-assigners (chan-fx/build-raw-channel-assigners full-channels full-f)\n        func-f (if htp?  ; Assignment function for dimmer functions on multipurpose channels\n                 ;; We must scale dimmer level from 0-255 to 0-100, since function effects use percentages.\n                 (fn [show snapshot target previous-assignment]\n                   (max (/ (master-scale master (params/resolve-param level show snapshot target)) 2.55)\n                        (or (params/resolve-param previous-assignment show snapshot target) 0)))\n                 (fn [show snapshot target previous-assignment]\n                   (/ (master-scale master (params/resolve-param level show snapshot target)) 2.55)))\n        func-assigners (chan-fx/build-head-function-assigners :dimmer function-heads func-f)\n        virtual-f (fn [show snapshot target previous-assignment]\n                    (when previous-assignment\n                      (let [resolved (params/resolve-param previous-assignment show snapshot target)\n                            fraction (/ (master-scale master (params/resolve-param level show snapshot target)) 255)]\n                        (colors/create-color :h (colors/hue resolved)\n                                             :s (colors/saturation resolved)\n                                             :l (clamp-percent-float (* (colors/lightness resolved) fraction))\n                                             :a (colors/alpha resolved)))))\n        virtual-assigners (fx/build-head-assigners :color virtual-heads virtual-f)]\n    (Effect. name always-active\n             (fn [show snapshot] (concat full-assigners func-assigners virtual-assigners))\n             end-immediately)))\n\n(defn dimmer-effect\n  \"Returns an effect which assigns a dynamic value to all the supplied\n  dimmers. If a `true` value is passed for `:htp?`, applies\n  _highest-takes-precedence_ (i.e. compares the value to the previous\n  assignment for the channel, and lets the highest value remain).\n\n  All dimmer cues are associated with a [[master]] chain which can\n  scale down the values to which they are set. If none is supplied\n  when creating the dimmer cue, the show's grand master is used.\n\n  Dimmers are either a channel fully dedicated to dimming, identified\n  by the channel `:type` of `:dimmer`, or a dimmer function range\n  defined over only part of a multi-purpose channel, where the\n  function `:type` is `:dimmer`, and the channel `:type` must be\n  something else. A single head cannot have both types of dimmer,\n  since a function can only exist on one channel in a given head.\n\n  If you have any fixtures that are capable of RGB color mixing, but\n  lack dedicated dimmer channels, you can have this effect simulate a\n  dimmer channel for those fixtures by passing a `true` value with\n  `add-virtual-dimmers?`. The virtual dimmer works by modifying any\n  color effect that has already run for those fixtures, to reduce the\n  brightness of the color being assigned. To do that, this dimmer\n  effect needs to run at a higher effect priority than any color\n  effect you want it to modify, so be sure to add it to your show with\n  an appropriate priority value. Virtual dimmers are incompatible with\n  hightest-takes-precedence dimming, because there is no actual\n  previous dimmer value for them to work with, so you cannot use both\n  `htp?` and `add-virtual-dimmers` at the same time.\"\n  [level fixtures & {:keys [htp? master effect-name add-virtual-dimmers?]\n                     :or {htp? true master (:grand-master *show*)}}]\n  {:pre [(some? *show*) (not (and htp? add-virtual-dimmers?))]}\n  (let [level (params/bind-keyword-param level Number 255)\n        master (params/bind-keyword-param master Master (:grand-master *show*))]\n    (let [full-channels (gather-dimmer-channels fixtures)\n          function-heads (gather-partial-dimmer-function-heads fixtures)\n          virtual-heads (when add-virtual-dimmers? (gather-no-dimmer-rgb-heads fixtures))\n          snapshot (metro-snapshot (:metronome *show*))\n          level (params/resolve-unless-frame-dynamic level *show* snapshot)\n          master (params/resolve-param master *show* snapshot)  ; Can resolve now; value is inherently static.\n          label (if (params/param? level) \"<dynamic>\" level)]\n      (build-parameterized-dimmer-effect (or effect-name (str \"Dimmers=\" label (when htp? \" (HTP)\")))\n                                         level *show* full-channels function-heads virtual-heads htp? master))))\n"
  },
  {
    "path": "src/afterglow/effects/fun.clj",
    "content": "(ns afterglow.effects.fun\n  \"A collection of neat effects that are both useful in shows, and\n  examples of how to create such things.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as channels]\n            [afterglow.effects :as fx]\n            [afterglow.effects.channel :as chan-fx]\n            [afterglow.effects.color :as color-fx]\n            [afterglow.effects.dimmer :as dimmer-fx]\n            [afterglow.effects.movement :as movement]\n            [afterglow.effects.oscillators :as osc]\n            [afterglow.effects.params :as params]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [*show* with-show]]\n            [afterglow.transform :as transform]\n            [clojure.math.numeric-tower :as math]\n            [com.evocomputing.colors :as colors]\n            [taoensso.timbre :as timbre]\n            [taoensso.tufte :as tufte])\n  (:import (afterglow.effects Effect)\n           (afterglow.effects.dimmer Master)\n           (afterglow.rhythm Metronome)\n           (javax.vecmath Point3d Vector3d)\n           (javax.media.j3d Transform3D)))\n\n(def default-down-beat-color\n  \"The default color for [[metronome-effect]] to flash on the down\n  beats.\"\n  (colors/lighten (colors/create-color :red) 20))\n\n(def default-other-beat-color\n  \"The default color for [[metronome-effect]] to flash on beats that\n  are not down beats.\"\n  (colors/darken (colors/create-color :yellow) 30))\n\n(defn metronome-effect\n  \"Returns an effect which flashes the supplied fixtures to the beats\n  of the show metronome, emphasizing the down beat, which is a great\n  way to test and understand metronome synchronization. The color of\n  the flashes can be controlled by the `:down-beat-color` and\n  `:other-beat-color` optional keyword arguments (defaulting to red\n  with lightness 70, and yellow with lightness 20, respectively).\n\n  This is no longer as useful as it used to be before there were\n  metronome adjustment interfaces in the Ableton Push and then web\n  interfaces, but is still an example of how to write a metronome\n  driven effect, and can be synchronized to metronomes other than the\n  default show metronome by passing them in with optional keyword\n  argument `:metronome`.\"\n  [fixtures & {:keys [down-beat-color other-beat-color metronome]\n               :or {down-beat-color default-down-beat-color\n                    other-beat-color default-other-beat-color\n                    metronome (:metronome *show*)}}]\n  {:pre [(some? *show*)]}\n  (let [down-beat-color (params/bind-keyword-param\n                         down-beat-color :com.evocomputing.colors/color default-down-beat-color)\n        other-beat-color (params/bind-keyword-param\n                          other-beat-color :com.evocomputing.colors/color default-other-beat-color)\n        metronome (params/bind-keyword-param metronome Metronome (:metronome *show*))]\n    (params/validate-param-type down-beat-color :com.evocomputing.colors/color)\n    (params/validate-param-type other-beat-color :com.evocomputing.colors/color)\n    (params/validate-param-type metronome Metronome)\n    (let [heads (channels/find-rgb-heads fixtures)\n          running (atom true)\n          ;; Need to use the show metronome as a snapshot to resolve our metronome parameter first\n          metronome (params/resolve-param metronome *show* (rhythm/metro-snapshot (:metronome *show*)))\n          snapshot (rhythm/metro-snapshot metronome)\n          down-beat-color (params/resolve-unless-frame-dynamic down-beat-color *show* snapshot)\n          other-beat-color (params/resolve-unless-frame-dynamic other-beat-color *show* snapshot)\n          local-snapshot (atom nil)  ; Need to set up a snapshot at start of each run for all assigners\n          f (fn [show snapshot target previous-assignment]\n              (tufte/p ::metronome-effect\n                       (let [raw-intensity (* 2 (- (/ 1 2) (rhythm/snapshot-beat-phase @local-snapshot 1)))\n                             intensity (if (neg? raw-intensity) 0 raw-intensity)\n                             base-color (if (rhythm/snapshot-down-beat? @local-snapshot)\n                                          (params/resolve-param down-beat-color show @local-snapshot)\n                                          (params/resolve-param other-beat-color show @local-snapshot))]\n                         (colors/create-color {:h (colors/hue base-color)\n                                               :s (colors/saturation base-color)\n                                               :l (* (colors/lightness base-color) intensity)}))))\n          assigners (fx/build-head-assigners :color heads f)]\n      (Effect. \"Metronome\"\n               (fn [show snapshot]  ;; Continue running until the end of a measure\n                 ;; Also need to set up the local snapshot based on our private metronome\n                 ;; for the assigners to use.\n                 (reset! local-snapshot (rhythm/metro-snapshot metronome))\n                 (or @running (< (rhythm/snapshot-bar-phase @local-snapshot) 0.9)))\n               (fn [show snapshot] assigners)\n               (fn [snow snapshot]  ;; Arrange to shut down at the end of a measure\n                 (reset! running false))))))\n\n(def default-sparkle-color\n  \"The default color for the [[sparkle]] effect.\"\n  (colors/create-color \"white\"))\n\n(defn- remove-finished-sparkles\n  \"Filters out any sparkles that were created longer ago than the fade\n  time. `sparkles` is a map from head to the timestamp at which the\n  sparkle was created.\"\n  [sparkles show snapshot fade-time]\n  (tufte/p ::remove-finished-sparkles\n           (let [now (:instant snapshot)\n                 fade-time (params/resolve-param fade-time show snapshot)]\n             (reduce\n              (fn [result [where creation-time]]\n                (if (< (- now creation-time) fade-time)\n                  (assoc result where creation-time)\n                  result))\n              {}\n              sparkles))))\n\n;; TODO: add off-beat-penalty that slopes the chance downwards as the beat passes,\n;; same for off-bar-penalty, so can prioritize beats and bars, perhaps pass an oscillator\n;; so they can be scaled in time too. Eventually allow randomization of fade time and perhaps\n;; hue and peak brightness, with control over how much they vary?\n(defn sparkle\n  \"A random sparkling effect like a particle generator over the\n  supplied fixture heads.\n\n  As each frame of DMX values generated, each participating fixture\n  head has a chance of being assigned a sparkle (this chance is\n  controlled by the optional keyword parameter `:chance`). Once a\n  sparkle has been created, it will fade out over the number of\n  milliseconds specified by the optional keyword parameter\n  `:fade-time`. The initial color of each sparkle can be changed with\n  the optional keyword parameter `:color`. All parameters may be\n  dynamic, including show variables with the standard shorthand of\n  passing the variable name as a keyword.\"\n  [fixtures & {:keys [color chance fade-time] :or {color default-sparkle-color chance 0.001 fade-time 500}}]\n  {:pre [(some? *show*)]}\n  (let [color (params/bind-keyword-param color :com.evocomputing.colors/color default-sparkle-color)\n        chance (params/bind-keyword-param chance Number 0.001)\n        fade-time (params/bind-keyword-param fade-time Number 500)]\n    (let [heads (channels/find-rgb-heads fixtures)\n          running (atom true)\n          sparkles (atom {})  ; A map from head to creation timestamp for active sparkles\n          snapshot (rhythm/metro-snapshot (:metronome *show*))\n          ;; TODO: These should be per-head in case they are spatial.\n          color (params/resolve-unless-frame-dynamic color *show* snapshot)\n          chance (params/resolve-unless-frame-dynamic chance *show* snapshot)\n          fade-time (params/resolve-unless-frame-dynamic fade-time *show* snapshot)]\n      (Effect. \"Sparkle\"\n              (fn [show snapshot]\n                ;; Continue running until all existing sparkles fade\n                (swap! sparkles remove-finished-sparkles show snapshot fade-time)\n                (or @running (seq @sparkles)))\n              (fn [show snapshot]\n                (tufte/p ::sparkle\n                         ;; See if we create any new sparkles (unless we've been asked to end).\n                         (when @running\n                           (doseq [head heads]\n                             (let [chance (params/resolve-param chance show snapshot head)]\n                               (when (< (rand) chance)\n                                 (swap! sparkles assoc head (:instant snapshot))))))\n                         ;; Build assigners for all active sparkles.\n                         (let [now (:instant snapshot)]\n                           (for [[head creation-time] @sparkles]\n                             (let [color (params/resolve-param color show snapshot head)\n                                   fade-time (max 10 (params/resolve-param fade-time show snapshot head))\n                                   fraction (/ (- now creation-time) fade-time)\n                                   faded (colors/darken color (* fraction (colors/lightness color)))]\n                               (fx/build-head-assigner :color head\n                                                       (fn [show snapshot _target previous-assignment]\n                                                         (color-fx/htp-merge (params/resolve-param previous-assignment\n                                                                                                   show snapshot head)\n                                                                             faded))))))))\n              (fn [_show _snapshot]\n                ;; Arrange to shut down once all existing sparkles fade out.\n                (reset! running false))))))\n\n(defn dimmer-sparkle\n  \"A variation of the [[sparkle]] effect which uses dimmer channels,\n  instead of RGB color mixing, for fixtures that lack such capability.\n  Note that some fixtures may have dimmers that do not respond quickly\n  enough for this to work well; you will have to try it and see.\n\n  As each frame of DMX values generated, each participating fixture\n  head has a chance of being assigned a sparkle (this chance is\n  controlled by the optional keyword parameter `:chance`). Once a\n  sparkle has been created, it will fade out over the number of\n  milliseconds specified by the optional keyword parameter\n  `:fade-time`.\n\n  As with other [dimmer\n  effects]({{guide-url}}effects.html#dimmer-effects), the maximum\n  level to which the dimmer can be set is limited by a dimmer master\n  chain. You can pass one in explicitly with `:master`. If you do not,\n  the show's grand master is used.\n\n  By default this effect ignores fixtures that can perform RGB color\n  mixing, because you are better off using the regular [[sparkle]]\n  effect with them. But if for some reason you want it to affect their\n  dimmers as well, you can pass a `true` value with\n  `:include-rgb-fixtures?`.\"\n  [fixtures & {:keys [chance fade-time master include-rgb-fixtures?]\n               :or   {chance 0.001 fade-time 500 master (:grand-master *show*) include-rgb-fixtures? false}}]\n  {:pre [(some? *show*)]}\n  (let [chance    (params/bind-keyword-param chance Number 0.001)\n        fade-time (params/bind-keyword-param fade-time Number 500)\n        master    (params/bind-keyword-param master Master (:grand-master *show*))\n        fixtures  (if include-rgb-fixtures? fixtures (remove channels/has-rgb-heads? fixtures))]\n    (let [full-channels  (dimmer-fx/gather-dimmer-channels fixtures)\n          function-heads (dimmer-fx/gather-partial-dimmer-function-heads fixtures)\n          running        (atom true)\n          full-sparkles  (atom {}) ; Map from channel to creation time for active sparkles on full-dimmer channels\n          func-sparkles  (atom {}) ; Map from head to creation time for active sparkles on partial-dimmer channels\n          snapshot       (rhythm/metro-snapshot (:metronome *show*))\n          chance         (params/resolve-unless-frame-dynamic chance *show* snapshot)\n          fade-time      (params/resolve-unless-frame-dynamic fade-time *show* snapshot)\n          master         (params/resolve-unless-frame-dynamic master *show* snapshot)]\n      (Effect. \"Dimmer Sparkle\"\n              (fn [show snapshot]\n                ;; Continue running until all existing sparkles fade\n                (swap! full-sparkles remove-finished-sparkles show snapshot fade-time)\n                (swap! func-sparkles remove-finished-sparkles show snapshot fade-time)\n                (or @running (seq @full-sparkles) (seq @func-sparkles)))\n              (fn [show snapshot]\n                (tufte/p ::dimmer-sparkle\n                         ;; See if we create any new sparkles (unless we've been asked to end).\n                         (when @running\n                           (let [chance (params/resolve-param chance show snapshot)]\n                             (doseq [chan full-channels]\n                               (when (< (rand) chance)\n                                 (swap! full-sparkles assoc chan (:instant snapshot))))\n                             (doseq [head function-heads]\n                               (when (< (rand) chance)\n                                 (swap! func-sparkles assoc head (:instant snapshot))))))\n                         ;; Build assigners for all active sparkles.\n                         (let [now       (:instant snapshot)\n                               fade-time (max 10 (params/resolve-param fade-time show snapshot))]\n                           (concat\n                            (for [[chan creation-time] @full-sparkles]\n                              (let [fraction (/ (- now creation-time) fade-time)\n                                    faded    (- 255 (* fraction 255))]  ; Fade from maximum dimmer level\n                                (chan-fx/build-channel-assigner\n                                 chan\n                              (fn [_show _snapshot _target previous-assignment]\n                                (colors/clamp-rgb-int (max (dimmer-fx/master-scale master faded)\n                                                           (or previous-assignment 0)))))))\n                            (for [[head creation-time] @func-sparkles]\n                              (let [fraction (/ (- now creation-time) fade-time)\n                                    faded    (- 100 (* fraction 100))]  ; Functions use % rather than DMX values\n                                (chan-fx/build-head-function-assigner\n                                 head\n                                 (fn [_show _snapshot _target previous-assignment]\n                                   (colors/clamp-percent-float (max (dimmer-fx/master-scale master faded)\n                                                                    (or previous-assignment 0)))))))))))\n              (fn [_show _snapshot]\n                ;; Arrange to shut down once all existing sparkles fade out.\n                (reset! running false))))))\n\n(defn strobe\n  \"A compound effect which sets dimmers to the level determined by the\n  show variable `:strobe-dimmers` (defaulting to 255), assigns a color\n  based on the show variables `:strobe-hue` (with a default of 277,\n  purple) `:strobe-saturation` (with a default of 100), and the\n  specified `lightness` (which may be a dynamic parameter), with a\n  default of 100, which would white out the hue until it was lowered.\n  The effect then sets the fixtures' strobe channel to the specified\n  `level`, which may also be a dynamic parameter.\n\n  This is designed to be run as a high priority queue, ideally while\n  held and with aftertouch adjusting a cue-introduced variable for\n  `level` (which is used to control the strobe function of the\n  affected fixtures, setting the strobe speed, and defaults to a\n  middle value). The global strobe color can be adjusted via the show\n  variables, either by aftertouch or by another effect with no assigners,\n  like [[adjust-strobe]].\"\n  [name fixtures level lightness]\n  {:pre [(some? *show*)]}\n  (let [level-param (params/bind-keyword-param level Number 50)\n        lightness-param (params/bind-keyword-param lightness Number 100)\n        hue-param (params/bind-keyword-param :strobe-hue Number 277)\n        saturation-param (params/bind-keyword-param :strobe-saturation Number 100)\n        dimmer-param (params/bind-keyword-param :strobe-dimmers Number 255)\n        dimmers (dimmer-fx/dimmer-effect dimmer-param fixtures)\n        color (color-fx/color-effect \"strobe color\"\n                                     (params/build-color-param :h hue-param :s saturation-param :l lightness-param)\n                                     fixtures :include-color-wheels? true)  ; :htp true tends to wash out right away\n        function (chan-fx/function-effect \"strobe level\" :strobe level-param fixtures)]\n    (Effect. name fx/always-active\n             (fn [show snapshot] (concat\n                                  (fx/generate dimmers show snapshot)\n                                  (fx/generate color show snapshot)\n                                  (fx/generate function show snapshot)))\n             (fn [show snapshot]\n               (fx/end dimmers show snapshot)\n               (fx/end color show snapshot)\n               (fx/end function show snapshot)))))\n\n;; TODO: Consider getting rid of this and moving these variables to the strobe\n;;       effect itself once the Push interface allow access to more\n;;       than the first two cue variables?\n(defn adjust-strobe\n  \"An auxiliary effect which creates no assigners to directly affect\n  lights, but adjusts show variables used by the [[strobe]] effect. It\n  is designed to be run as a parallel cue to offer the user controls\n  for adjusting the hue and saturation of any active strobes.\"\n  []\n  {:pre [(some? *show*)]}\n  (let [saved-hue (show/get-variable :strobe-hue)\n        saved-saturation (show/get-variable :strobe-saturation)]\n    (when-not saved-saturation (show/set-variable! :strobe-saturation 100))\n    (when-not saved-hue (show/set-variable! :strobe-hue 277))\n\n    (Effect. \"Strobe Adjust\" fx/always-active\n            (fn [show snapshot] nil)\n            (fn [show snapshot]\n              (show/set-variable! :strobe-hue saved-hue)\n              (show/set-variable! :strobe-saturation saved-saturation)\n              true))))\n\n(defn strobe-2\n  \"An updated version of [[strobe]] which takes advantage of the new\n  ability to use color variables with rich user interfaces on the web\n  and Ableton Push. A compound effect which sets dimmers to the level\n  determined by the show variable `:strobe-dimmers` (defaulting to\n  255), assigns a color based on the show variable\n  `:strobe-color` (with a default of a fully-saturated purple), and\n  the specified `lightness` (which may be a dynamic parameter), with a\n  default of 100, which would white out the hue until it was lowered.\n  The effect then sets the fixtures' strobe channel to the specified\n  `level`, which may also be a dynamic parameter.\n\n  This is designed to be run as a high priority queue, ideally while\n  held and with aftertouch adjusting a cue-introduced variable for\n  `level` (which is used to control the strobe function of the\n  affected fixtures, setting the strobe speed, and defaults to a\n  middle value). The global strobe color can be adjusted via the show\n  variables, either by aftertouch or by another effect with no assigners,\n  like [[adjust-strobe]].\"\n  [name fixtures level lightness]\n  {:pre [(some? *show*)]}\n  (let [level-param (params/bind-keyword-param level Number 50)\n        lightness-param (params/bind-keyword-param lightness Number 100)\n        color-param (params/bind-keyword-param :strobe-color :com.evocomputing.colors/color\n                                               (colors/create-color :purple))\n        dimmer-param (params/bind-keyword-param :strobe-dimmers Number 255)\n        dimmers (dimmer-fx/dimmer-effect dimmer-param fixtures)\n        color (color-fx/color-effect \"strobe color\"\n                                     (params/build-color-param :color color-param :l lightness-param)\n                                     fixtures :include-color-wheels? true)  ; :htp true tends to wash out right away\n        function (chan-fx/function-effect \"strobe level\" :strobe level-param fixtures)]\n    (Effect. name fx/always-active\n             (fn [show snapshot] (concat\n                                  (fx/generate dimmers show snapshot)\n                                  (fx/generate color show snapshot)\n                                  (fx/generate function show snapshot)))\n             (fn [show snapshot]\n               (fx/end dimmers show snapshot)\n               (fx/end color show snapshot)\n               (fx/end function show snapshot)))))\n\n(def default-color-cycle\n  \"The default list of colors to cycle through for\n  the [[color-cycle-chase]].\"\n  [(colors/create-color :red)\n   (colors/create-color :orange)\n   (colors/create-color :yellow)\n   (colors/create-color :green)\n   (colors/create-color :cyan)\n   (colors/create-color :blue)\n   (colors/create-color :purple)\n   (colors/create-color :white)])\n\n(defn transition-during-down-beat\n  \"A transition phase function which causes the color cycle transition\n  to occur during the down beat of each bar. See [[color-cycle-chase]]\n  for how this is used.\"\n  [snapshot]\n  (if (rhythm/snapshot-down-beat? snapshot)\n    (rhythm/snapshot-beat-phase snapshot)  ; Transition is occuring\n    1.0))  ; Transition is complete\n\n;; TODO: Create no-assigner effects which set color lists and\n;;       transition functions in show variables; the latter\n;;       should also have a variable to set the number of beats\n;;       over which the transition takes place. This will allow\n;;       a panel of composable wipe effects!\n(defn color-cycle-chase\n  \"Returns an effect which moves through a color cycle over a period\n  of time (by default changing each bar of a phrase), performing a\n  transition as a new color is introduced, using the specified\n  distance measure to determine when each light starts to participate.\n  By default the transition occurs over the down beat (first beat)\n  of the bar. See below for how these defaults can be changed.\n\n  The distance measure supplied as the second argument is a function\n  which accepts a fixture or head and returns a nonnegative value\n  which controls the point during the transition when that head will\n  change from the old color to the new color. A fixture returning a\n  value of 0 will change as soon as transition has started, and the\n  fixture(s) that return the largest value will change when the\n  transition ends. A value halfway between zero and the largest value\n  would mean the color of that fixture or head would change exactly at\n  the midpoint of the transition. Many interesting looking\n  transtitions can be created using distance measures constructed by\n  calling [[afterglow.transform/build-distance-measure]], as is done\n  by [[iris-out-color-cycle-chase]] and several examples which follow\n  it. There are lots of other kinds of functions which can created,\n  though; at the opposite extreme you can do completely arbitrary\n  things like assigning each head a random \\\"distance\\\" when the\n  effect is created.\n\n  The sequence of colors which are cycled through can be changed by\n  passing in a vector with `:color-cycle`. Each value in the vector\n  can either be a color object, or a dynamic parameter which resolves\n  to a color object when the effect is running. As ususal, you can\n  bind to show variables containing a color by passing the variable\n  names as keywords within the vector.\n\n  When the effect is being rendered, the current color index within\n  `:color-cycle` is determined by calling a function with the snapshot\n  obtained from the show metronome at the start of the rendering\n  frame. The default\n  function, [[afterglow.rhythm/snapshot-bar-within-phrase]], will\n  assign a different color for each bar of a phrase. (If there are not\n  enough colors in `:color-cycle` the cycle is repeated as necessary.)\n  You can pass another index function with `:color-index-function` to\n  change how and when the cycle is traversed.\n\n  The function supplied with `:transition-phase-function` determines\n  precisely when the transition takes place and how quickly it occurs.\n  It is also called with the show metronome snapshot, and if the value\n  it returns is less than zero, the transition is considered not to\n  have started yet, and no fixtures will be assigned the current\n  color. Values between zero and one mean the transition is in\n  progress, and lights whose distance measure divided by the largest\n  distance measure is less than or equal to the current phase will\n  change color. Once the transition phase reaches one (or greater),\n  the transition is complete, and all lights will be assigned the\n  color associated with the current cycle index. The default\n  transition phase function, [[transition-during-down-beat]], causes\n  the transition to be spread over the down beat of each bar.\n  Passing [[rhythm/snapshot-bar-phase]] instead would spread the\n  transition over the entire bar, so that transitions would be feeding\n  right into each other. Other possibilities are limited only by your\n  imagination. The transition can run backwards; it can pause or\n  reverse directions multiple times; it does not even necessarily have\n  to happen only once during each index value. This means that if you\n  want to reverse the direction of a transition which lasts for the\n  entire duration of a cycle index value, you can do it by reversing\n  either the distance measure or the phase function, whichever is\n  easier. (If the transition is shorter than the time over which the\n  `:color-index-function` changes, you will want to reverse the\n  distance measure rather than the phase function, because otherwise\n  the order in which the colors appear will be strange.)\n\n  To give your running effect a meaningful name within user\n  interfaces, pass a short and descriptive value with `:effect-name`.\"\n  [fixtures measure & {:keys [color-cycle color-index-function transition-phase-function effect-name]\n                       :or {color-cycle default-color-cycle\n                            color-index-function rhythm/snapshot-bar-within-phrase\n                            transition-phase-function transition-during-down-beat\n                            effect-name \"Phrase Color Cycle\"}}]\n  {:pre [(some? *show*)]}\n  (let [max-distance (transform/max-distance measure (channels/find-rgb-heads fixtures))\n        previous-color (atom nil)\n        current-index (atom nil)\n        current-color (atom nil)\n        color-cycle (map (fn [arg default]\n                           (params/bind-keyword-param arg :com.evocomputing.colors/color default))\n                         color-cycle default-color-cycle)]\n    (doseq [arg color-cycle]\n      (params/validate-param-type arg :com.evocomputing.colors/color))\n    (let [heads (channels/find-rgb-heads fixtures)\n          ending (atom nil)\n          color-cycle (map #(params/resolve-unless-frame-dynamic % *show* (rhythm/metro-snapshot (:metronome *show*)))\n                           color-cycle)\n          f (fn [_show snapshot target _previous-assignment]\n              (tufte/p ::color-cycle-chase-effect\n                       ;; Determine whether this head is covered by the current state of the transition\n                       (let [transition-progress (transition-phase-function snapshot)]\n                         (cond\n                           (< transition-progress 0.0) @previous-color\n                           (>= transition-progress 1.0) @current-color\n                           :else (if (>= transition-progress (/ (measure target) max-distance))\n                                   @current-color\n                                   @previous-color)))))\n          assigners (fx/build-head-assigners :color heads f)]\n      (Effect. effect-name\n               (fn [show snapshot]  ;; Continue running until the next color would appear\n                 ;; Is it time to grab the next color?\n                 (when (not= (color-index-function snapshot) @current-index)\n                   (reset! current-index (color-index-function snapshot))\n                   (reset! previous-color @current-color)\n                   (reset! current-color\n                           (params/resolve-param (nth (cycle color-cycle) (dec @current-index))\n                                                 show snapshot)))\n                 (or (nil? @ending) (= @current-index @ending)))\n               (fn [show snapshot] assigners)\n               (fn [snow snapshot]\n                 (or (nil? @current-index)  ; We never got started--show stopped? End right away.\n                     (do  ; Arrange to shut down when the next color starts to appear.\n                       (reset! ending @current-index)\n                       nil)))))))\n\n(defn iris-out-color-cycle-chase\n  \"Returns an effect which changes the color of a group of fixture\n  heads on the down beat of each bar of a phrase, expanding the color\n  from the center of the show x-y plane outwards during the down beat.\n\n  Unless otherwise specified by passing an explicit pair of x and y\n  coordinates with `:center` (e.g. `:center [0.0 0.0]`), the starting\n  point of the transition will be the x-y center of the bounding box\n  of the fixtures participating in it (the smallest box containing all\n  of their heads).\n\n  You can change the colors used, and when transitions occur, by\n  overriding the default values associated with the optional keyword\n  arguments `:color-cycle`, `:color-index-function`, and\n  `:transition-phase-function`. For details about how these are\n  interpreted, see [[color-cycle-chase]] which is used to implement\n  this chase.\"\n  [fixtures & {:keys [center color-cycle color-index-function transition-phase-function effect-name]\n               :or {color-cycle default-color-cycle\n                    color-index-function rhythm/snapshot-bar-within-phrase\n                    transition-phase-function transition-during-down-beat\n                    effect-name \"Iris Out\"}}]\n  {:pre [(some? *show*)]}\n  (let [center (or center (vals (select-keys (transform/calculate-bounds fixtures) [:center-x :center-y])))\n        measure (transform/build-distance-measure (first center) (second center) 0 :ignore-z true)]\n    (color-cycle-chase fixtures measure :color-cycle color-cycle :color-index-function color-index-function\n                       :transition-phase-function transition-phase-function :effect-name effect-name)))\n\n(defn wipe-right-color-cycle-chase\n  \"Returns an effect which changes color on the down beat of each bar\n  of a phrase, wiping the color from left to right across the show x\n  axis.\n\n  You can change the colors used, and when transitions occur, by\n  overriding the default values associated with the optional keyword\n  arguments `:color-cycle`, `:color-index-function`, and\n  `:transition-phase-function`. For details about how these are\n  interpreted, see [[color-cycle-chase]] which is used to implement\n  this chase.\"\n  [fixtures & {:keys [color-cycle color-index-function transition-phase-function effect-name]\n               :or {color-cycle default-color-cycle\n                    color-index-function rhythm/snapshot-bar-within-phrase\n                    transition-phase-function transition-during-down-beat\n                    effect-name \"Wipe Right\"}}]\n  {:pre [(some? *show*)]}\n  (let [measure (transform/build-distance-measure (:min-x (transform/calculate-bounds fixtures)) 0 0\n                                                  :ignore-y true :ignore-z true)]\n    (color-cycle-chase fixtures measure :color-cycle color-cycle :color-index-function color-index-function\n                       :transition-phase-function transition-phase-function :effect-name effect-name)))\n\n(defn- pick-new-value\n  \"Helper function for random-beat-number-param to pick a new random\n  value with a minimum difference from the former value.\"\n  [old-value min range min-change]\n  (loop [new-value (+ min (rand range))]\n    (if (or (nil? old-value)\n            (>= (math/abs (- new-value old-value)) min-change))\n      new-value\n      (recur (+ min (rand range))))))\n\n(defn random-beat-number-param\n  \"Returns a dynamic number parameter which gets a new random value on each beat.\"\n  [& {:keys [min max min-change] :or {min 0 max 255 min-change 0}}]\n  {:pre [(some? *show*)]}\n  (let [min (params/bind-keyword-param min Number 0)\n        max (params/bind-keyword-param max Number 255)\n        min-change (params/bind-keyword-param min-change Number 0)\n        last-beat (ref nil)\n        last-value (ref nil)]\n    (if-not (some params/param? [min max min-change])\n      ;; Optimize the simple case of all constant parameters\n      (let [range (- max min)\n            eval-fn (fn [_ snapshot]\n                      ;; TODO support min-change\n                      (dosync (when (not= @last-beat (:beat snapshot))\n                                (ref-set last-beat (:beat snapshot))\n                                (alter last-value pick-new-value min range min-change))\n                              @last-value))]\n        (when-not (pos? range)\n          (throw (IllegalArgumentException. \"min must be less than max\")))\n        (when-not (< min-change (/ range 3))\n          (throw (IllegalArgumentException. \"min-change must be less 1/3 the range\")))\n        (reify params/IParam\n          (evaluate [this show snapshot _] (eval-fn show snapshot))\n          (frame-dynamic? [this] true)\n          (result-type [this] Number)\n          (resolve-non-frame-dynamic-elements [this _ _ _] this)))  ; Nothing to resolve, return self\n      ;; Support the general case where we have an incoming variable parameter\n      (let [eval-fn (fn [show snapshot]\n                      (let [min (params/resolve-param min show snapshot)\n                            max (params/resolve-param max show snapshot)\n                            min-change (params/resolve-param min-change show snapshot)\n                            range (- max min)]\n                        ;; TODO support min-change\n                        (if (neg? range)\n                          (do\n                            (timbre/error \"Random beat number parameters min > max, returning max.\")\n                            max)\n                          (if (< min-change (/ range 3))\n                              (dosync (when (not= @last-beat (:beat snapshot))\n                                        (ref-set last-beat (:beat snapshot))\n                                        (alter last-value pick-new-value min range min-change))\n                                      @last-value)\n                              (do\n                                (timbre/error \"Random beat number min-change > 1/3 range, returning max.\")\n                                max)))))]\n        (reify params/IParam\n          (evaluate [this show snapshot _] (eval-fn show snapshot))\n          (frame-dynamic? [this] true)\n          (result-type [this] Number)\n          (resolve-non-frame-dynamic-elements [this show snapshot head]\n            (with-show show\n              (random-beat-number-param :min (params/resolve-unless-frame-dynamic min show snapshot head)\n                                        :max (params/resolve-unless-frame-dynamic max show snapshot head)\n                                        :min-change (params/resolve-unless-frame-dynamic\n                                                     min-change show snapshot head)))))))))\n\n(defn- build-aim-fan-point\n  \"Create a dynamic parameter which computes the aim point for a\n  fixture in an [[aim-fan]] effect.\"\n  [x y z x-scale y-scale]\n  (reify params/IParam\n    (evaluate [this show snapshot head]\n      (let [x (params/resolve-param x show snapshot head)\n            y (params/resolve-param y show snapshot head)\n            z (params/resolve-param z show snapshot head)\n            dx (- (:x head) x)\n            dy (- (:y head) y)\n            x-scale (params/resolve-param x-scale show snapshot head)\n            y-scale (params/resolve-param y-scale show snapshot head)]\n        (Point3d. (+ (:x head) (* dx x-scale)) (+ (:y head) (* dy y-scale)) z)))\n    (frame-dynamic? [this]\n      (boolean (some params/frame-dynamic-param? [x y z x-scale y-scale])))\n    (result-type [this] Point3d)\n    (resolve-non-frame-dynamic-elements [this show snapshot head]\n      (let [x (params/resolve-unless-frame-dynamic x show snapshot head)\n            y (params/resolve-unless-frame-dynamic y show snapshot head)\n            z (params/resolve-unless-frame-dynamic z show snapshot head)\n            x-scale (params/resolve-unless-frame-dynamic x-scale show snapshot head)\n            y-scale (params/resolve-unless-frame-dynamic y-scale show snapshot head)]\n        (build-aim-fan-point x y z x-scale y-scale)))))\n\n(defn aim-fan\n  \"Creates an aim effect which aims the lights outward around a\n  reference point specified by `:x`, `:y`, and `:z`, which defaults\n  to `(0, 0, 5)`, by first aiming the lights at the reference point,\n  and then adding on the distance within the x-y plane from the\n  fixture to that point, multiplied by `:x-scale` and `:y-scale`,\n  which each default to `1`. A scale of `0` would aim the lights\n  straight forward. Positive values fan them out, while negative\n  values overshoot the reference point in the other direction, fanning\n  them in. All parameters other than `fixtures` can be dynamic or\n  keywords, which will be bound to show variables.\n\n  You can override the default effect name of Aim Fan by passing in\n  another with `:effect-name`.\"\n  [fixtures & {:keys [x y z x-scale y-scale effect-name]\n               :or {x 0.0 y 0.0 z 5.0 x-scale 1.0 y-scale 1.0 effect-name \"Aim Fan\"}}]\n  (let [x (params/bind-keyword-param x Number 0.0)\n        y (params/bind-keyword-param y Number 0.0)\n        z (params/bind-keyword-param z Number 5.0)\n        x-scale (params/bind-keyword-param x-scale Number 1.0)\n        y-scale (params/bind-keyword-param y-scale Number 1.0)]\n    (movement/aim-effect effect-name (build-aim-fan-point x y z x-scale y-scale) fixtures)))\n\n(defn- build-twirl-vector\n  \"Create a dynamic parameter which computes the direction vector for\n  a fixture in a [[twirl]] effect.\"\n  [x y z radius osc]\n  (reify params/IParam\n    (evaluate [this show snapshot head]\n      (let [reference-point (Point3d. (params/resolve-param x show snapshot head)\n                                      (params/resolve-param y show snapshot head)\n                                      (params/resolve-param z show snapshot head))\n            head-point (Point3d. (:x head) (:y head) (:z head))\n            displacement (Point3d. 0.0 (params/resolve-param radius show snapshot head) 0.0)\n            angle (* transform/two-pi (osc/evaluate osc show snapshot head))\n            rotation (Transform3D.)]\n        (.rotZ rotation angle)\n        (.transform rotation displacement)\n        (.add head-point displacement)\n        (.sub head-point reference-point)\n        #_(timbre/info \"head-point\" head-point \"reference-point\" reference-point)\n        (Vector3d. head-point)))\n    (frame-dynamic? [this]\n      true)\n    (result-type [this] Vector3d)\n    (resolve-non-frame-dynamic-elements [this show snapshot head]\n      (let [x (params/resolve-unless-frame-dynamic x show snapshot head)\n            y (params/resolve-unless-frame-dynamic y show snapshot head)\n            z (params/resolve-unless-frame-dynamic z show snapshot head)\n            radius (params/resolve-unless-frame-dynamic radius show snapshot head)\n            osc (params/resolve-unless-frame-dynamic osc show snapshot head)]\n        (build-twirl-vector x y z radius osc)))))\n\n(defn twirl\n  \"Creates a direction movement effect which aims the lights outward\n  from a point specified by `:x`, `:y`, and `:z`, which defaults\n  to `(0, 0, -2)`, then displaces the front of that vector by a\n  distance of `:radius` in the _x-y_ plane (defaulting to `0.25`) in a\n  direction which rotates around the plane driven by a sawtooth\n  oscillator which defaults to a complete revolution every four beats,\n  but whose beat ratio can be adjusted by the parameters `:beats` and\n  `:cycles`, and whose phase is spread across the _x_ axis as a\n  spatial parameter over all fixtures. All parameters other than\n  `fixtures` can be dynamic or keywords, which will be bound to show\n  variables.\n\n  You can override the default effect name of Twirl by passing in\n  another with `:effect-name`.\"\n  [fixtures & {:keys [x y z radius beats cycles effect-name]\n               :or {x 0.0 y 0.0 z -2.0 radius 0.25 beats 4 cycles 1 effect-name \"Twirl\"}}]\n  (let [x (params/bind-keyword-param x Number 0.0)\n        y (params/bind-keyword-param y Number 0.0)\n        z (params/bind-keyword-param z Number -2.0)\n        radius (params/bind-keyword-param radius Number 0.25)\n        beats (params/bind-keyword-param beats Number 4)\n        cycles (params/bind-keyword-param cycles Number 1)\n        osc (osc/sawtooth :interval-ratio (params/build-param-formula Number #(/ %1 %2) beats cycles)\n                          :phase (params/build-spatial-param fixtures :x :max 1.0))]\n    (movement/direction-effect effect-name (build-twirl-vector x y z radius osc) fixtures)))\n\n(defn bloom\n  \"An effect which causes a color (which defaults to white) to spread\n  from a point across a set of lights, controlled by a fraction from 0\n  to 1. The spread is defined by a distance measure (as created\n  by [[build-distance-measure]]), which defaults to a sphere starting\n  at the origin. For efficiency, the measure cannot be frame dynamic,\n  and is evaluated when the effect is created.\"\n  [fixtures & {:keys [color fraction measure]\n               :or {color (colors/create-color :white)\n                    fraction 0\n                    measure (transform/build-distance-measure 0 0 0)}}]\n    (let [color (params/bind-keyword-param color :com.evocomputing.colors/color (colors/create-color :white))\n          fraction (params/bind-keyword-param fraction Number 0)\n          measure (params/resolve-param (params/bind-keyword-param measure :afterglow.transform/distance-measure\n                                                                   (transform/build-distance-measure 0 0 0))\n                                        *show* (rhythm/metro-snapshot (:metronome *show*)))\n          heads (channels/find-rgb-heads fixtures)\n          furthest (transform/max-distance measure heads)\n          f (fn [show snapshot target previous-assignment]\n              (let [fraction (params/resolve-param fraction show snapshot target)\n                    distance (measure target)]\n                (if (<= distance (* furthest fraction))\n                  color\n                  previous-assignment)))\n          assigners (fx/build-head-assigners :color heads f)]\n      (apply fx/scene \"Bloom\"\n             (concat [(Effect. \"Bloom color\"\n                               fx/always-active\n                               (fn [show snapshot] assigners)\n                               fx/end-immediately)]\n                     (for [fixture fixtures]\n                       (let [distance (measure fixture)\n                             level (params/build-param-formula Number\n                                                               (fn [fraction]\n                                                                 (if (<= distance (* furthest fraction))\n                                                                   255\n                                                                   0))\n                                    fraction)]\n                         (dimmer-fx/dimmer-effect level [fixture])))))))\n\n(defn- remove-finished-flakes\n  \"Filters out any flakes that were created longer ago than the\n  configured duration. `flakes` is a map from head to a tuple\n  containing the step value after which the flake will end, followed\n  by color and potentially aim information.\"\n  [flakes show snapshot step]\n  (tufte/p ::remove-finished-flakes\n           (let [now (math/round (params/resolve-param step show snapshot))]\n             (reduce\n              (fn [result [where info]]\n                (let [final-step (first info)]\n                  (if (<= now final-step)\n                    (assoc result where info)\n                    result)))\n              {}\n              flakes))))\n\n(defn- add-flakes\n  \"Create new flakes of a shared random color and individual random\n  durations for each of the supplied heads.\"\n  [heads show snapshot current-step min-duration max-duration min-saturation]\n  (let [hue (rand 360)]\n    (into {}\n          (map (fn [head]\n                 (let [min-duration (max 0 (math/round (params/resolve-param min-duration show snapshot head)))\n                       max-duration (max min-duration\n                                         (math/round (params/resolve-param max-duration show snapshot head)))\n                       duration (+ min-duration (rand-int (inc (- max-duration min-duration))))\n                       min-saturation (colors/clamp-percent-float\n                                       (params/resolve-param min-saturation show snapshot head))\n                       saturation (colors/clamp-percent-float (+ min-saturation (rand (- 100.0001 min-saturation))))]\n                   [head [(+ current-step duration) (colors/create-color :h hue :s saturation :l 50)]]))\n               heads))))\n\n(defn- aim-flakes\n  \"Chooses a random point at which the newly-created flakes shoule be\n  aimed.\"\n  [flakes show snapshot min-x max-x min-y max-y min-z max-z]\n  (let [min-x (params/resolve-param min-x show snapshot)\n        max-x (params/resolve-param max-x show snapshot)\n        x (+ min-x (rand (- max-x min-x)))\n        min-y (params/resolve-param min-y show snapshot)\n        max-y (params/resolve-param max-y show snapshot)\n        y (+ min-y (rand (- max-y min-y)))\n        min-z (params/resolve-param min-z show snapshot)\n        max-z (params/resolve-param max-z show snapshot)\n        z (+ min-z (rand (- max-z min-z)))\n        point (Point3d. x y z)]\n    (into {} (for [[head info] flakes]\n               [head (conj info point)]))))\n\n;; TODO: add ability to fade out over a configurable number of beats.\n(defn confetti\n  \"A random color effect, which assigns a new random color to a random\n  selection of the supplied fixture heads each time a step parameter\n  changes value. That color lasts a random number of steps.\n\n  The step parameter defaults to one which changes each beat, buy you\n  can supply your own with the optional keyword argument `:step`. Its\n  value will be rounded to the nearest integer when checking for\n  changes, so fades are ignored.\n\n  The minimum and maximum number of heads to assign colors on each\n  step default to 1 and 4, and can be adjusted with `:min-added` and\n  `:max-added`. The minimum and maximum number of steps that each\n  assignment will last default to 4 and 8, and can be adjusted with\n  `:min-duration` and `:max-duration`.\n\n  By default, colors chosen are always fully saturated, but you can\n  pass a percentage with `:min-saturation` and a random saturation\n  value between that and 100% will be chosen for each head.\n\n  When generating a new set of confetti flakes, if more than one head\n  is chosen, they will all be assigned a color of the same hue, but\n  may each get individual random saturations. The duration of the\n  flake on each head will also be individually randomly assigned.\n\n  In addition to assigning colors, flakes can also aim the lights at a\n  particular point. To activate this, pass a `true` value with\n  `:aim?`. By default the aiming points will be randomly generated to\n  be on the floor from half a meter to five meters in front of the\n  rig, and with _x_ values ranging from -5 to 5 meters, but you can\n  adjust the space from which they are chosen by passing values with\n  `:min-x`, `:max-x`, `:min-y`, `:max-y`, `:min-z`, and `max-z`.\n\n  All parameters after `fixtures` may be dynamic, including show\n  variables with the standard shorthand of passing the variable name\n  as a keyword. Since `step`, `:min-added`, `:max-added`, `aim?`, and\n  the boundaries of the aiming space are not associated with a\n  specific head, they cannot be spatial parameters. The other\n  parameters can be, however, so saturations and durations can vary\n  over the ligthing rig.\"\n  [fixtures & {:keys [step min-added max-added min-duration max-duration min-saturation\n                      aim? min-x max-x min-y max-y min-z max-z]\n               :or {step (params/build-step-param)\n                    min-added 1 max-added 4 min-duration 2 max-duration 4 min-saturation 100.0\n                    aim? false min-x -5.0 max-x 5.0 min-y 0.0 max-y 0.0 min-z 0.5 max-z 5.0}}]\n  {:pre [(some? *show*)]}\n  (let [step (params/bind-keyword-param step Number (params/build-step-param))\n        min-added (params/bind-keyword-param min-added Number 1)\n        max-added (params/bind-keyword-param max-added Number 4)\n        min-duration (params/bind-keyword-param min-duration Number 2)\n        max-duration (params/bind-keyword-param max-duration Number 4)\n        min-saturation (params/bind-keyword-param min-saturation Number 100.0)\n        min-x (params/bind-keyword-param min-x Number -5.0)\n        max-x (params/bind-keyword-param max-x Number 5.0)\n        min-y (params/bind-keyword-param min-y Number 0.0)\n        max-y (params/bind-keyword-param max-y Number 0.0)\n        min-z (params/bind-keyword-param min-z Number 0.5)\n        max-z (params/bind-keyword-param max-z Number 5.0)]\n    (let [heads (channels/find-rgb-heads fixtures true)\n          running (ref true)\n          current-step (ref nil)\n          flakes (ref {}) ; A map from head to [creation-step color] for active flakes\n          snapshot (rhythm/metro-snapshot (:metronome *show*))\n          min-added (params/resolve-unless-frame-dynamic min-added *show* snapshot)\n          max-added (params/resolve-unless-frame-dynamic max-added *show* snapshot)\n          min-x (params/resolve-unless-frame-dynamic min-x *show* snapshot)\n          max-x (params/resolve-unless-frame-dynamic max-x *show* snapshot)\n          min-y (params/resolve-unless-frame-dynamic min-y *show* snapshot)\n          max-y (params/resolve-unless-frame-dynamic max-y *show* snapshot)\n          min-z (params/resolve-unless-frame-dynamic min-z *show* snapshot)\n          max-z (params/resolve-unless-frame-dynamic max-z *show* snapshot)]\n      (Effect. \"Confetti\"\n               (fn [show snapshot]\n                 ;; Continue running until all existing flakes fade\n                 (dosync\n                  (alter flakes remove-finished-flakes show snapshot step)\n                  (or @running (seq @flakes))))\n               (fn [show snapshot]\n                 (tufte/p ::confetti\n                          ;; See how many flakes to create (unless we've been asked to end).\n                          (dosync\n                           (when @running\n                             (let [now (math/round (params/resolve-param step show snapshot))]\n                               (when (not= now @current-step)\n                                 (ref-set current-step now)\n                                 (let [min-added (max 0 (math/round (params/resolve-param min-added show snapshot)))\n                                       max-added (max min-added (math/round\n                                                                 (params/resolve-param max-added show snapshot)))\n                                       add (+ min-added (rand-int (inc (- max-added min-added))))\n                                       new-flakes (add-flakes (take add (shuffle heads)) show snapshot\n                                                              now min-duration max-duration min-saturation)\n                                       aimed-flakes (if aim?\n                                                      (aim-flakes new-flakes show snapshot\n                                                                  min-x max-x min-y max-y min-z max-z)\n                                                      new-flakes)]\n                                   (alter flakes merge aimed-flakes)))))\n                           ;; Build assigners for all active flakes.\n                           (concat (for [[head [_ color]] @flakes]\n                                     (fx/build-head-assigner :color head (fn [_ _ _ _] color)))\n                                   (when aim?\n                                     (filter identity\n                                             (for [[head [_ _ point]] @flakes]\n                                               (when (seq (movement/find-moving-heads [head]))\n                                                 (fx/build-head-assigner :aim head (fn [_ _ _ _] point))))))))))\n               (fn [_show _snapshot]\n                 ;; Stop making new sparkles and arrange to shut down once all existing ones fade out.\n                 (dosync (ref-set running false)))))))\n\n(def default-pinstripe-colors\n  \"The set of colors that will be used by a pinstripe effect if no\n  `:colors` parameter is supplied.\"\n  [(colors/create-color :red) (colors/create-color :white)])\n\n(defn- gather-stripes\n  \"Gathers heads into the groups that will be assigned particular\n  colors by the pinstripes effect.\"\n  [heads group-fn num-colors]\n  (let [head-groups (partition-all num-colors (sort-by #(:x (first %)) (vals (group-by group-fn (sort-by :x heads)))))\n        stripe-groups (for [_i (range num-colors)] [])]\n    (loop [remaining-groups head-groups\n           result stripe-groups]\n      (let [current-group (first remaining-groups)\n            remaining-groups (rest remaining-groups)\n            result (map concat result (concat current-group (repeat [])))]\n        (if (empty? remaining-groups)\n          result\n          (recur remaining-groups result))))))\n\n;; TODO: Consider :include-color-wheels? arg, but they lag so definitely default to no.\n(defn pinstripes\n  \"A color effect which divides the lights into alternating columns by\n  their _x_ positions (with configurable tolerance, defaulting to\n  requiring exact equality), and assigns a color to each column. The\n  colors rotate according to a step parameter.\n\n  The step parameter defaults to one which changes abruptly on each\n  beat, but you can supply your own with the optional keyword argument\n  `:step`. Fades between colors can be achieved by passing a step\n  parameter that fades.\n\n  The tolerance used when grouping the heads into stripes is\n  controlled by the optional parameter `:tolerance`, which defaults to\n  zero, meaning the heads must have the exact same _x_ value to get\n  assigned to the same stripe. The assignment of heads into stripes is\n  done when the effect is created, so if the tolerance changes after\n  that, it will have no effect.\n\n  The colors themselves are passed as a sequence with `:colors` and\n  default to red and white. The list of colors you supply can be of\n  any length. Although the colors within the list themselves can be\n  dynamic parameters, the conntent of the list is evaluated when the\n  effect is created, so the number of colors and the color parameters\n  themselves are fixed at that time.\n\n  The `:step`, `:tolerance`, and `:colors` parameters may be dynamic,\n  (and may be bound to show variables using the standard shorthand of\n  passing the variable name as a keyword). Since `:step` and\n  `:tolerance` are not associated with a specific head, they cannot be\n  a spatial parameters. The colors can be, however, so for example\n  saturations can vary over the rig.\"\n  [fixtures & {:keys [step tolerance colors]\n               :or {step (params/build-step-param)\n                    tolerance 0\n                    colors default-pinstripe-colors}}]\n  {:pre [(some? *show*)]}\n  (let [step (params/bind-keyword-param step Number (params/build-step-param))\n        tolerance (params/bind-keyword-param tolerance Number 0)\n        colors (params/bind-keyword-param colors java.util.List default-pinstripe-colors)]\n    (let [heads (channels/find-rgb-heads fixtures false)\n          snapshot (rhythm/metro-snapshot (:metronome *show*))\n          tolerance (params/resolve-param tolerance *show* snapshot)\n          colors (map #(params/bind-keyword-param % :com.evocomputing.colors/color (colors/create-color :white))\n                      (params/resolve-param colors *show* snapshot))\n          group-fn (if (< tolerance 0.00001) :x #(math/round (/ (:x %) tolerance)))\n          stripes (gather-stripes heads group-fn (count colors))\n          chases (map (fn [i stripe-heads]\n                        (let [effects (map (fn [color]\n                                             (color-fx/color-effect \"pin color\" color stripe-heads))\n                                           colors)\n                              pin-step (params/build-param-formula Number #(- % i) step)]\n                          (fx/chase \"Pinstripe\" effects pin-step :beyond :loop)))\n                      (range) stripes)]\n      (apply fx/scene \"Pinstripes\" chases))))\n"
  },
  {
    "path": "src/afterglow/effects/movement.clj",
    "content": "(ns afterglow.effects.movement\n  \"Effects pipeline functions for working with direction assignments\n  to fixtures and heads.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as channels]\n            [afterglow.effects.channel :as chan-fx]\n            [afterglow.effects.params :as params]\n            [afterglow.effects :as fx]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show-context :refer [*show*]]\n            [afterglow.transform :as transform]\n            [clojure.math.numeric-tower :as math]\n            [com.evocomputing.colors :as colors]\n            [taoensso.timbre :as timbre :refer [debug]])\n  (:import [afterglow.effects Assigner Effect]\n           [javax.media.j3d Transform3D]\n           [javax.vecmath Point3d Vector3d Vector2d]))\n\n(defn find-moving-heads\n  \"Returns all heads of the supplied fixtures which are capable of\n  movement, in other words they have either a pan or tilt channel.\"\n  [fixtures]\n  (filter #(pos? (count (filter #{:pan :tilt} (map :type (:channels %))))) (channels/expand-heads fixtures)))\n\n(defn direction-effect\n  \"Returns an effect which assigns a direction parameter (most easily\n  created by [[build-direction-param]]) to all moving heads of the\n  fixtures supplied when invoked. The direction is a vector in the\n  frame of reference of the show, so standing in the audience facing\n  the show, `x` increases to the left, `y` away from the ground, and\n  `z` towards the audience. If an [[aim-effect]] is simultaneously\n  running on the same fixture, it will win and override whatever this\n  effect was trying to do, because it runs later. However, if\n  a [[pan-tilt-effect]] is running, it will run before this one, so\n  this one will win.\"\n  [name direction fixtures]\n  {:pre [(some? name) (some? *show*) (sequential? fixtures)]}\n  (params/validate-param-type direction Vector3d)\n  (let [heads (find-moving-heads fixtures)\n        assigners (fx/build-head-parameter-assigners :direction heads direction *show*)]\n    (Effect. name fx/always-active (fn [_show _snapshot] assigners) fx/end-immediately)))\n\n;; Resolves the assignment of a direction to a fixture or a head.\n(defmethod fx/resolve-assignment :direction [assignment show snapshot buffers]\n  ;; Resolve in case assignment is still frame dynamic\n  (let [target (:target assignment)\n        direction (params/resolve-param (:value assignment) show snapshot target)\n        direction-key (keyword (str \"pan-tilt-\" (:id target)))\n        former-values (direction-key (:previous @(:movement *show*)))\n        [pan tilt] (transform/direction-to-dmx target direction former-values)]\n    (debug \"Direction resolver pan:\" pan \"tilt:\" tilt)\n    (doseq [c (filter #(= (:type %) :pan) (:channels target))]\n      (chan-fx/apply-channel-value buffers c pan))\n    (doseq [c (filter #(= (:type %) :tilt) (:channels target))]\n      (chan-fx/apply-channel-value buffers c tilt))\n    (swap! (:movement *show*) #(assoc-in % [:current direction-key] [pan tilt]))))\n\n(defn current-rotation\n  \"Given a head and DMX pan and tilt values, calculate a\n  transformation that represents the current orientation of the head\n  as compared to the default orientation of facing directly towards\n  the positive Z axis.\"\n  [head pan tilt]\n  (let [rotation (Transform3D. (:rotation head))]\n    (when-let [pan-scale (:pan-half-circle head)]\n      (let [dmx-pan (/ (- pan (:pan-center head)) pan-scale)\n            adjust (Transform3D.)]\n        (.rotY adjust (* Math/PI dmx-pan))\n        (.mul rotation adjust)))\n    (when-let [tilt-scale (:tilt-half-circle head)]\n      (let [dmx-tilt (/ (- tilt (:tilt-center head) tilt-scale))\n            adjust (Transform3D.)]\n        (.rotX adjust (* Math/PI dmx-tilt))\n        (.mul rotation adjust)))\n    rotation))\n\n(defn default-direction\n  \"Determine the default aiming vector for a head, in other words the\n  direction it aims when sent zero values for its DMX pan and tilt\n  channels.\"\n  [head]\n  (let [rotation (current-rotation head 0 0)\n        direction (Vector3d. 0 0 1)]\n    (.transform rotation direction)\n    direction))\n\n;; Fades between two direction assignments. A nil assignment is interpreted as the direction the head will face\n;; when it is sent zero values for its pan and tilt channels, so that a fade to or from nothing looks right.\n(defmethod fx/fade-between-assignments :direction [from-assignment to-assignment fraction show snapshot]\n  (cond (<= fraction 0) from-assignment\n        (>= fraction 1) to-assignment\n        ;; We are blending, so we need to resolve any remaining dynamic parameters now, and make sure\n        ;; fraction really does only range between 0 and 1.\n        :else (let [target (:target from-assignment)\n                    default (default-direction target)\n                    from-resolved (Vector3d. (params/resolve-param (or (:value from-assignment) default)\n                                                                   show snapshot target))\n                    to-resolved (Vector3d.  (params/resolve-param (or (:value to-assignment) default)\n                                                                  show snapshot target))\n                    fraction (colors/clamp-unit-float fraction)]\n                (.scale to-resolved fraction)\n                (.scaleAdd from-resolved (- 1.0 fraction) to-resolved)\n                (.normalize from-resolved)\n                (merge from-assignment {:value from-resolved}))))\n\n(defn aim-effect\n  \"Returns an effect which assigns an aim parameter (most easily\n  created by [[build-aim-param]]) to all moving heads of the fixtures\n  supplied when invoked. The direction is a point in the frame of\n  reference of the show, so standing in the audience facing the show,\n  `x` increases to the left, `y` away from the ground, and `z` towards\n  the audience, and the origin is the center of the show. If\n  a [[pan-tilt-effect]] or [[direction-effect]] is simultaneously\n  running on the same fixture, this effect will win and override\n  whatever the other effect was trying to do, because this one runs\n  later.\"\n  [name target-point fixtures]\n  {:pre [(some? name) (some? *show*) (sequential? fixtures)]}\n  (params/validate-param-type target-point Point3d)\n  (let [heads (find-moving-heads fixtures)\n        assigners (fx/build-head-parameter-assigners :aim heads target-point *show*)]\n    (Effect. name fx/always-active (fn [show snapshot] assigners) fx/end-immediately)))\n\n;; Resolves the assignment of an aiming point to a fixture or a head.\n(defmethod fx/resolve-assignment :aim [assignment show snapshot buffers]\n  ;; Resolve in case assignment is still frame dynamic\n  (let [target (:target assignment)\n        target-point (params/resolve-param (:value assignment) show snapshot target)\n        direction-key (keyword (str \"pan-tilt-\" (:id target)))\n        former-values (direction-key (:previous @(:movement *show*)))\n        [pan tilt] (transform/aim-to-dmx target target-point former-values)]\n    (debug \"Aim resolver pan:\" pan \"tilt:\" tilt)\n    (doseq [c (filter #(= (:type %) :pan) (:channels target))]\n      (chan-fx/apply-channel-value buffers c pan))\n    (doseq [c (filter #(= (:type %) :tilt) (:channels target))]\n      (chan-fx/apply-channel-value buffers c tilt))\n    (swap! (:movement *show*) #(assoc-in % [:current direction-key] [pan tilt]))))\n\n;; Fades between two aim assignments. A nil assignment is interpreted as a point in the direction the head will\n;; aim when it is sent zero values for its pan and tilt channels, so that a fade to or from nothing looks right.\n(defmethod fx/fade-between-assignments :aim [from-assignment to-assignment fraction show snapshot]\n  (cond (<= fraction 0) from-assignment\n        (>= fraction 1) to-assignment\n        ;; We are blending, so we need to resolve any remaining dynamic parameters now, and make sure\n        ;; fraction really does only range between 0 and 1.\n        :else (let [target (:target from-assignment)\n                    dir (default-direction target)\n                    default (Point3d. (+ (:x target) (.x dir))\n                                      (+ (:y target) (.y dir))\n                                      (+ (:z target) (.z dir)))\n                    from-resolved (Point3d. (params/resolve-param (or (:value from-assignment) default)\n                                                                  show snapshot target))\n                    to-resolved (Point3d.  (params/resolve-param (or (:value to-assignment) default)\n                                                                 show snapshot target))\n                    fraction (colors/clamp-unit-float fraction)]\n                (.scale to-resolved fraction)\n                (.scaleAdd from-resolved (- 1.0 fraction) to-resolved)\n                (merge from-assignment {:value from-resolved}))))\n\n(defn pan-tilt-effect\n  \"Returns an effect which assigns a pan/tilt parameter (most easily\n  created by [[build-pan-tilt-param]]) to all moving heads of the\n  fixtures supplied when invoked. The pan and tilt values represent\n  angles in the frame of reference of the show, telling how far the\n  head should move away from facing directly along the `z`\n  axis. (see [show space]({{guide-url}}show_space.html) for a diagram\n  of the axes).\n\n  If a [[direction-effect]] or [[aim-effect]] is simultaneously\n  running on the same fixture, they will win and override whatever\n  this effect was trying to do, because they run later.\n\n  If you simply want to set the pan or tilt channels of some fixtures\n  to specific values, without regard to the orientation at which the\n  fixture was hung with respect to show space, you want to use a lower\n  level [[function-effect]] with the `:pan` or `:tilt` keyword, rather\n  than this effect.\"\n  [name pan-tilt fixtures]\n  {:pre [(some? name) (some? *show*) (sequential? fixtures)]}\n  (params/validate-param-type pan-tilt Vector2d)\n  (let [heads (find-moving-heads fixtures)\n        assigners (fx/build-head-parameter-assigners :pan-tilt heads pan-tilt *show*)]\n    (Effect. name fx/always-active (fn [show snapshot] assigners) fx/end-immediately)))\n\n;; Resolves the assignment of pan/tilt angles to a fixture or a head.\n(defmethod fx/resolve-assignment :pan-tilt [assignment show snapshot buffers]\n  ;; Resolve in case assignment is still frame dynamic\n  (let [target (:target assignment)\n        pan-tilt (params/resolve-param (:value assignment) show snapshot target)\n        direction (params/vector-from-pan-tilt (.x pan-tilt) (.y pan-tilt))\n        direction-key (keyword (str \"pan-tilt-\" (:id target)))\n        former-values (direction-key (:previous @(:movement *show*)))\n        [pan tilt] (transform/direction-to-dmx target direction former-values)]\n    (debug \"Pan/Tilt resolver pan:\" pan \"tilt:\" tilt)\n    (doseq [c (filter #(= (:type %) :pan) (:channels target))]\n      (chan-fx/apply-channel-value buffers c pan))\n    (doseq [c (filter #(= (:type %) :tilt) (:channels target))]\n      (chan-fx/apply-channel-value buffers c tilt))\n    (swap! (:movement *show*) #(assoc-in % [:current direction-key] [pan tilt]))))\n\n;; Fades between two pan/tilt assignments. A nil assignment is interpreted facing directly out into the\n;; audience. It might be nice to get fancier and have nil mean the direction the head would aim when\n;; it is sent zero values for its pan and tilt channels, so that a fade to or from nothing looks right,\n;; but because of the way that pan and tilt values are chosen to optimize wide-range movements, the\n;; head might still spin around anyway when the fade starts, so that might not be worth the effort.\n(defmethod fx/fade-between-assignments :pan-tilt [from-assignment to-assignment fraction show snapshot]\n  (cond (<= fraction 0) from-assignment\n        (>= fraction 1) to-assignment\n        ;; We are blending, so we need to resolve any remaining dynamic parameters now, and make sure\n        ;; fraction really does only range between 0 and 1.\n        :else (let [target (:target from-assignment)\n                    ;; Here's where we would calculate a default angle based on the head orientation and\n                    ;; DMX response, if we decide that is worth it.\n                    default (Vector2d. 0.0 0.0)\n                    from-resolved (Vector2d. (params/resolve-param (or (:value from-assignment) default)\n                                                                   show snapshot target))\n                    to-resolved (Vector2d.  (params/resolve-param (or (:value to-assignment) default)\n                                                                  show snapshot target))\n                    fraction (colors/clamp-unit-float fraction)]\n                (.scale to-resolved fraction)\n                (.scaleAdd from-resolved (- 1.0 fraction) to-resolved)\n                (merge from-assignment {:value from-resolved}))))\n"
  },
  {
    "path": "src/afterglow/effects/oscillators.clj",
    "content": "(ns afterglow.effects.oscillators\n  \"Provide a variety of waveforms at frequencies related to the show metronome to\n  facilitate building visually and musically pleasing effects.\"\n  (:require [afterglow.effects.params :as params]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show-context :refer [*show* with-show]]\n            [afterglow.util :as util]\n            [taoensso.timbre :as timbre])\n    (:import [afterglow.rhythm Metronome]))\n\n(defonce\n  ^{:private true\n    :doc \"Protect protocols against namespace reloads\"}\n  _PROTOCOLS_\n  (do\n(defprotocol IOscillator\n  \"A waveform generator for building effects that vary at\n  frequencies related to a show metronome.\"\n  (evaluate [this show snapshot head]\n  \"Determine the value of this oscillator at a given moment of the\n  show. In addition to the metronome snapshot, the show and (if\n  applicable) fixture head must be passed in case any oscillator\n  configuration arguments rely\n  on [dynamic]({{guide-url}}parameters.html)\n  or [spatial]({{guide-url}}parameters.html#spatial-parameters)\n  parameters.\")\n  (resolve-non-frame-dynamic-elements [this show snapshot head]\n  \"Called when an effect is created using this oscillator. Returns a\n  version of itself where any non frame-dynamic input parameters have\n  been resolved.\"))\n(defprotocol IVariableShape\n  \"Shape functions which can change over time (depending on the value\n  of dynamic parameters) use this protocol rather than being a simple\n  function, so they can get the context needed for evaluating their\n  dynamic parameters.\"\n  (value-for-phase [this phase show snapshot head]\n  \"Calculate the value of the oscillator's waveform at the specified\n  phase, with support for resolving dynamic parameters that it may\n  depend on. `phase` ranges from `0` to `1`, and so must the return\n  value from this function.\")\n  (simplify-unless-frame-dynamic [this show snapshot head]\n  \"If none of the dynamic parameters used by the shape function are\n  dynamic to the level of individual frames, return a simple shape\n  function based on their current values which can replace this\n  variable shape function but run faster. Otherwise returns\n  itself.\"))))\n\n(defn- adjust-phase\n  \"Helper function to offset a phase by a given amount. Phases range from [0.0-1.0).\"\n  [^Double phase ^Double offset]\n  (let [sum (+ phase offset)]\n    (- sum (long sum))))\n\n(defn- build-base-phase-fn\n  \"Constructs the phase-generating function for an oscillator which\n  has fixed parameters, arranging for it to do as little work as\n  possible.\"\n  [interval interval-ratio]\n  (if (util/float= interval-ratio 1)\n    ;; Most efficient case, we can use the phase information directly in the snapshot\n    (case interval\n      :beat (fn [^afterglow.rhythm.MetronomeSnapshot snapshot] (.beat-phase snapshot))\n      :bar (fn [^afterglow.rhythm.MetronomeSnapshot snapshot] (.bar-phase snapshot))\n      :phrase (fn [^afterglow.rhythm.MetronomeSnapshot snapshot] (.phrase-phase snapshot)))\n    ;; Must calculate enhanced phase based on the interval ratio\n    (case interval\n      :beat (fn [^afterglow.rhythm.MetronomeSnapshot snapshot] (rhythm/snapshot-beat-phase snapshot interval-ratio))\n      :bar (fn [^afterglow.rhythm.MetronomeSnapshot snapshot] (rhythm/snapshot-bar-phase snapshot interval-ratio))\n      :phrase (fn [^afterglow.rhythm.MetronomeSnapshot snapshot]\n                (rhythm/snapshot-phrase-phase snapshot interval-ratio)))))\n\n(defn- build-adjusted-phase-fn\n  \"Constructs the function which uses the oscillator phase function to\n  calculate a base phase, then offsets that with a fixed phase\n  parameter. If the phase offset is zero, simply returns the function\n  that calculates the unadjusted phase.\"\n  [base-fn phase]\n  (if (util/float= phase 0.0)\n    base-fn\n    (fn [^afterglow.rhythm.MetronomeSnapshot snapshot] (adjust-phase (base-fn snapshot) phase))))\n\n(defn- fixed-oscillator\n  \"Build an optimized version of an oscillator which can be used when\n  none of its configuration parameters are dynamic parameters.\n  See [[build-oscillator]] for details about the parameters.\"\n  [shape-fn interval interval-ratio phase]\n  (let [base-phase-fn (build-base-phase-fn interval interval-ratio)\n        adjusted-phase-fn (build-adjusted-phase-fn base-phase-fn phase)]\n    (reify IOscillator\n      (evaluate [this _ snapshot _]\n        (shape-fn (adjusted-phase-fn snapshot)))\n      (resolve-non-frame-dynamic-elements [this _ _ _]  ; Already resolved\n        this))))\n\n(defn- simple-oscillator\n  \"Build an oscillator which has at least one dynamic parameter, but\n  whose shape function does not use any. See [[build-oscillator]] for\n  details about the parameters.\"\n  [shape-fn interval interval-ratio phase]\n  (reify IOscillator\n    (evaluate [this show snapshot head]\n      (let [interval (params/resolve-param interval show snapshot head)\n            interval-ratio (params/resolve-param interval-ratio show snapshot head)\n            phase (params/resolve-param phase show snapshot head)\n            base-phase-fn (build-base-phase-fn interval interval-ratio)\n            adjusted-phase-fn (build-adjusted-phase-fn base-phase-fn phase)]\n        (shape-fn (adjusted-phase-fn snapshot))))\n    (resolve-non-frame-dynamic-elements [this show snapshot head]\n      (if (not-any? params/frame-dynamic-param? [interval interval-ratio phase])\n        ;; Can now resolve and optimize\n        (let [interval (params/resolve-param interval show snapshot head)\n              interval-ratio (params/resolve-param interval-ratio show snapshot head)\n              phase (params/resolve-param phase show snapshot head)]\n          (fixed-oscillator shape-fn interval interval-ratio phase))\n        ;; Can't optimize, there is at least one frame-dynamic parameter, so return self\n        this))))\n\n(defn- variable-oscillator\n  \"Build an oscillator whose shape function relies on dynamic\n  parameters. See [[build-oscillator]] for details about the\n  parameters.\"\n  [shape-fn interval interval-ratio phase]\n  (reify IOscillator\n    (evaluate [this show snapshot head]\n      (let [interval (params/resolve-param interval show snapshot head)\n            interval-ratio (params/resolve-param interval-ratio show snapshot head)\n            phase (params/resolve-param phase show snapshot head)\n            base-phase-fn (build-base-phase-fn interval interval-ratio)\n            adjusted-phase-fn (build-adjusted-phase-fn base-phase-fn phase)]\n        (value-for-phase shape-fn (adjusted-phase-fn snapshot) show snapshot head)))\n    (resolve-non-frame-dynamic-elements [this show snapshot head]\n      (let [shape-fn (simplify-unless-frame-dynamic shape-fn show snapshot head)]\n        (if (ifn? shape-fn)  ; The function simplified and no longer depends on dynamic parameters; we can optimize\n          (if (not-any? params/frame-dynamic-param? [interval interval-ratio phase])\n            ;; No parameters are frame-dynamic, can resolve and optimize all the way to a fixed oscillator\n            (let [interval (params/resolve-param interval show snapshot head)\n                  interval-ratio (params/resolve-param interval-ratio show snapshot head)\n                  phase (params/resolve-param phase show snapshot head)]\n              (fixed-oscillator shape-fn interval interval-ratio phase))\n            ;; Can't fully optimize, there is at least one frame-dynamic parameter, so return a simple oscillator\n            (simple-oscillator shape-fn interval interval-ratio phase))\n          ;; Can't optimize at all, shape-fn is frame-dynamic, so return self\n          this)))))\n\n(defn build-oscillator\n  \"Returns an oscillator which generates a waveform relative to the\n  phase of the current beat, bar, or phrase. The shape of the wave is\n  determined by the first argument, `shape-fn`.\n\n  In the simplest case, `shape-fn` is a function that takes a single\n  argument, the curent phase of the oscillator, which ranges from `0`\n  to `1`, and returns what the value fo the oscillator should be at\n  that phase in its waveform. The value returned by `shape-fn` must\n  also range from `0` to `1`.\n\n  If the shape of the oscillator needs to be able to change over time\n  depending on the value of a [dynamic\n  parameter]({{guide-url}}parameters.html), then `shape-fn` will\n  instead implement [[IVariableShape]] in order to be able to resolve\n  those parameters.\n\n  All of the standard oscillators provided by Afterglow are built in\n  this way. For example, an upwards-sloping sawtooth wave would be\n  created by passing a `shape-fn` that simply returns its argument:\n\n  ```\n  (build-oscillator (fn [phase] phase))\n   ```\n\n  For examples of how to generate other kinds of waveforms, view the\n  source for [[sine]], [[square]], and [[triangle]].\n\n  With no additional arguments, the waveform is defined by calling\n  `shape-fn` with a phase argument that ramps upward from `0` to `1`\n  over the course of each beat.\n\n  Passing the value `:bar` or `:phrase` with the optional keyword\n  argument `:interval` makes the wave cycle over a bar or phrase\n  instead.\n\n  Supplying a value with `:interval-ratio` will run the oscillator at\n  the specified fraction or multiple of the chosen interval (beat,\n  bar, or phrase), and supplying a `:phase` will offset the oscillator\n  from the underlying metronome phase by that amount. (See the\n  [documentation]({{guide-url}}oscillators.html#sawtooth-oscillators)\n  for an expanded explanation illustrated with graphs.)\n\n  The arguments after `shape-fn` can be [dynamic\n  parameters]({{guide-url}}parameters.html).\"\n  [shape-fn & {:keys [interval interval-ratio phase] :or {interval :beat interval-ratio 1 phase 0.0}}]\n  {:pre [(or (ifn? shape-fn) (satisfies? IVariableShape shape-fn))]}\n  (params/validate-param-type interval clojure.lang.Keyword)\n  (let [interval-ratio (params/bind-keyword-param interval-ratio Number 1)\n        phase (params/bind-keyword-param phase Number 0)]\n    (if (and (not-any? params/param? [interval interval-ratio phase]) (ifn? shape-fn))\n      (fixed-oscillator shape-fn interval interval-ratio phase)  ; Optimized case with no dynamic inputs\n      ;; We have a variable parameter or variable shape function; need to do a bit more work\n      (if (ifn? shape-fn)\n        (simple-oscillator shape-fn interval interval-ratio phase)\n        (variable-oscillator shape-fn interval interval-ratio phase)))))\n\n(defn- build-fixed-sawtooth-shape-fn\n  \"Returns the shape function for a sawtooth wave in a fixed direction.\"\n  [down?]\n  (if down?\n    (fn [phase] (- 1.0 phase))\n    (fn [phase] phase)))\n\n(defn sawtooth\n  \"Returns an oscillator which generates a sawtooth wave relative to\n  the phase of the current beat, bar, or phrase. With no arguments, it\n  creates a sawtooth wave that ramps upward from `0` to `1` over the\n  course of each beat.\n\n  Passing `true` with `:down?` creates an inverse sawtooth wave (one\n  that ramps downward from `1` to `0` over the course of the interval).\n\n  Passing the value `:bar` or `:phrase` with the optional keyword\n  argument `:interval` makes the wave cycle over a bar or phrase\n  instead.\n\n  Supplying a value with `:interval-ratio` will run the oscillator at\n  the specified fraction or multiple of the chosen interval (beat,\n  bar, or phrase), and supplying a `:phase` will offset the oscillator\n  from the underlying metronome phase by that amount. (See the\n  [documentation]({{guide-url}}oscillators.html#sawtooth-oscillators)\n  for an expanded explanation illustrated with graphs.)\n\n  The arguments can be [dynamic\n  parameters]({{guide-url}}parameters.html).\"\n  [& {:keys [down? interval interval-ratio phase] :or {down? false interval :beat interval-ratio 1 phase 0.0}}]\n  (let [down? (params/bind-keyword-param down? Boolean false)\n        shape-fn (if (params/param? down?)\n                   (reify IVariableShape  ; The shape function changes based on the dynamic value of down?\n                     (value-for-phase [this phase show snapshot head]\n                       (let [down? (params/resolve-param down? show snapshot head)]\n                         (if down? (- 1.0 phase) phase)))\n                     (simplify-unless-frame-dynamic [this show snapshot head]\n                       (if (params/frame-dynamic-param? down?)\n                         this  ; Can't simplify, we depend on a frame-dynamic parameter\n                         (let [down? (params/resolve-param [down? show snapshot head])]  ; Can simplify\n                           (build-fixed-sawtooth-shape-fn down?)))))\n                   ;; The shape function depends on the fixed value of down?, so can be finalized now\n                   (build-fixed-sawtooth-shape-fn down?))]\n    (build-oscillator shape-fn :interval interval :interval-ratio interval-ratio :phase phase)))\n\n(defn triangle\n  \"Returns an oscillator which generates a triangle wave relative to\n  the phase of the current beat, bar, or phrase. With no arguments, it\n  creates a triangle wave that ramps upward from `0` to `1` over the\n  first half of each beat, then back down to `0` through the end of\n  the beat.\n\n  Passing the value `:bar` or `:phrase` with the optional keyword\n  argument `:interval` makes the wave cycle over a bar or phrase\n  instead.\n\n  Supplying a value with `:interval-ratio` will run the oscillator at\n  the specified fraction or multiple of the chosen interval (beat,\n  bar, or phrase), and supplying a `:phase` will offset the oscillator\n  from the underlying metronome phase by that amount. (See the\n  [documentation]({{guide-url}}oscillators.html#triangle-oscillators)\n  for an expanded explanation illustrated with graphs.)\n\n  All the arguments can be [dynamic\n  parameters]({{guide-url}}parameters.html).\"\n  [& {:keys [interval interval-ratio phase] :or {interval :beat interval-ratio 1 phase 0.0}}]\n  (build-oscillator (fn [phase]\n                      (if (< phase 0.5)\n                        (* phase 2.0)\n                        (- 2.0 (* phase 2.0)))) :interval interval :interval-ratio interval-ratio :phase phase))\n\n(defn- build-fixed-square-shape-fn\n  \"Returns the shape function for a square wave with a fixed width.\"\n  [width]\n  (when-not  (<= 0.0 width 1.0)\n    (throw (IllegalArgumentException. \"width must fall between 0.0 and 1.0\")))\n  (fn [phase]\n    (if (< phase width) 1.0 0.0)))\n\n(defn square\n  \"Returns an oscillator which generates a square wave relative to the\n  phase of the current beat, bar, or phrase. With no arguments, it\n  creates a square wave that starts at `1` at the start of each beat,\n  and drops to `0` at the midpoint.\n\n  Specifying a value with `:width` adjusts how much of the time the\n  wave is _on_ (high); the default is `0.5`, lower values cause it to\n  turn off sooner, larger values later. In any case the width must be\n  within the range `0.0` to `1.0`. A value of zero means the\n  oscillator is always off, and a value of one means it is always on.\n\n  Passing the value `:bar` or `:phrase` with the optional keyword\n  argument `:interval` makes the wave cycle over a bar or phrase\n  instead.\n\n  Supplying a value with `:interval-ratio` will run the oscillator at\n  the specified fraction or multiple of a beat, and supplying a\n  `:phase` will offset the oscillator from the underlying metronome\n  phase by that amount. (See the\n  [documentation]({{guide-url}}oscillators.html#square-oscillators)\n  for an expanded explanation illustrated with graphs.)\n\n  The arguments can be [dynamic\n  parameters]({{guide-url}}parameters.html).\"\n  [& {:keys [width interval interval-ratio phase] :or {width 0.5 interval :beat interval-ratio 1 phase 0.0}}]\n  (let [width (params/bind-keyword-param width Number 0.5)\n        shape-fn (if (params/param? width)\n                   (reify IVariableShape  ; The shape function changes based on the dynamic value of width\n                     (value-for-phase [this phase show snapshot head]\n                       (let [width (params/resolve-param width show snapshot head)]\n                         (when-not (<= 0.0 width 1.0)\n                           (throw (IllegalArgumentException. \"width must fall between 0.0 and 1.0\")))\n                         (if (< phase width) 1.0 0.0)))\n                     (simplify-unless-frame-dynamic [this show snapshot head]\n                       (if (params/frame-dynamic-param? width)\n                         this  ; Can't simplify, we depend on a frame-dynamic parameter\n                         (let [width (params/resolve-param [width show snapshot head])]  ; Can simplify\n                           (build-fixed-square-shape-fn width)))))\n                   ;; The shape function depends on the fixed value of width, so can be finalized now\n                   (build-fixed-square-shape-fn width))]\n    (build-oscillator shape-fn :interval interval :interval-ratio interval-ratio :phase phase)))\n\n(defn sine\n  \"Returns an oscillator which generates a sine wave relative to the\n  phase of the current beat, bar, or phrase. With no arguments, it\n  creates a sine wave that curves upward from `0` to `1` over the\n  first half of each beat, then back down to `0` through the end of\n  the beat.\n\n  Passing the value `:bar` or `:phrase` with the optional keyword\n  argument `:interval` makes the wave cycle over a bar or phrase\n  instead.\n\n  Supplying a value with `:interval-ratio` will run the oscillator at\n  the specified fraction or multiple of th chosen interval (beat, bar,\n  or phrase), and supplying a `:phase` will offset the oscillator from\n  the underlying metronome phase by that amount.\n  (See the\n  [documentation]({{guide-url}}oscillators.html#sine-oscillators)\n  for an expanded explanation illustrated with graphs.)\n\n  All the arguments can be [dynamic\n  parameters]({{guide-url}}parameters.html).\"\n  [& {:keys [interval interval-ratio phase] :or {interval :beat interval-ratio 1 phase 0.0}}]\n  (let [two-pi (* 2.0 Math/PI)]\n    (build-oscillator (fn [phase]\n                        (let [adjusted-phase (- phase 0.25)]\n                          (+ 0.5 (* 0.5 (Math/sin (* two-pi adjusted-phase))))))\n                      :interval interval :interval-ratio interval-ratio :phase phase)))\n\n(defn- evaluate-oscillator\n  \"Handles the calculation of an oscillator based on dynamic parameter\n  values for at least one of min and max.\"\n  [show params-snapshot head min max osc osc-snapshot]\n  (let [min (params/resolve-param min show params-snapshot head)\n        max (clojure.core/max min (params/resolve-param max show params-snapshot head))  ; Avoid impossible case\n        range (- max min)]\n    (+ min (* range (evaluate osc show osc-snapshot head)))))\n\n(defn build-oscillated-param\n  \"Returns a number parameter that is driven by\n  an [oscillator]({{guide-url}}oscillators.html).\n  By default will be frame-dynamic, since it oscillates, but if you\n  pass a `false` value for `:frame-dynamic`, the value will be fixed\n  once it is assigned to an effect, acting like a random number\n  generator with the oscillator's range. If you don't specify a\n  `:metronome` to use, the\n  main [metronome]({{guide-url}}metronomes.html)\n  in [[*show*]] will be used.\n\n  The values returned by the oscillator will be mapped onto the range\n  from 0 to 255. If you would like to use a different range, you can\n  pass in alternate numbers with the optional keyword arguments `:min`\n  and `:max`. If the values you supply result in a maximum that is\n  less than or equal to the minimum, the oscillated parameter will be\n  stuck at the value you gave with `:min`.\"\n  [osc & {:keys [min max metronome frame-dynamic] :or {min 0 max 255 frame-dynamic true}}]\n  {:pre [(some? *show*) (satisfies? IOscillator osc)]}\n  (let [min (params/bind-keyword-param min Number 0)\n        max (params/bind-keyword-param max Number 255)\n        metronome (params/bind-keyword-param metronome Metronome (:metronome *show*))]\n    (if (not-any? params/param? [min max metronome])\n      ;; Optimize the simple case of all constant parameters\n      (let [max (clojure.core/max min max)  ; Handle case where min > max\n            range (- max min)\n            dyn (boolean frame-dynamic)\n            eval-fn (if (some? metronome)\n                      (fn [show snapshot head]\n                        (let [osc-snapshot (rhythm/metro-snapshot metronome (:instant snapshot))]\n                          (+ min (* range (evaluate osc show osc-snapshot head)))))\n                      (fn [show snapshot head] (+ min (* range (evaluate osc show snapshot head)))))\n            resolve-fn (fn [show snapshot head]\n                         (with-show show\n                           (build-oscillated-param (resolve-non-frame-dynamic-elements osc show snapshot head)\n                                                   :min (params/resolve-unless-frame-dynamic min show snapshot head)\n                                                   :max (params/resolve-unless-frame-dynamic max show snapshot head)\n                                                   :metronome (params/resolve-unless-frame-dynamic metronome show\n                                                                                                   snapshot head)\n                                                   :frame-dynamic frame-dynamic)))]\n        (reify params/IParam\n          (params/evaluate [this show snapshot head]\n            (eval-fn show snapshot head))\n          (params/frame-dynamic? [this]\n            dyn)\n          (params/result-type [this]\n            Number)\n          (params/resolve-non-frame-dynamic-elements [this show snapshot head]\n            (resolve-fn show snapshot head))))\n      ;; Support the general case where we have an incoming variable parameter\n      (let [dyn (boolean frame-dynamic)\n            eval-fn (if (some? metronome)\n                      (fn [show snapshot head]\n                        (let [local-metronome (params/resolve-param metronome show snapshot head)\n                              osc-snapshot (rhythm/metro-snapshot local-metronome (:instant snapshot))]\n                          (evaluate-oscillator show snapshot head min max osc osc-snapshot)))\n                      (fn [show snapshot head]\n                        (evaluate-oscillator show snapshot head min max osc snapshot)))\n            resolve-fn (fn [show snapshot head]\n                         (with-show show\n                           (build-oscillated-param (resolve-non-frame-dynamic-elements osc show snapshot head)\n                                                   :min (params/resolve-unless-frame-dynamic min show snapshot head)\n                                                   :max (params/resolve-unless-frame-dynamic max show snapshot head)\n                                                   :metronome (params/resolve-unless-frame-dynamic\n                                                               metronome show snapshot head)\n                                                   :frame-dynamic dyn)))]\n        (reify params/IParam\n          (params/evaluate [this show snapshot head]\n            (eval-fn show snapshot head))\n          (params/frame-dynamic? [this]\n            dyn)\n          (params/result-type [this]\n            Number)\n          (params/resolve-non-frame-dynamic-elements [this show snapshot head]\n            (resolve-fn show snapshot head)))))))\n"
  },
  {
    "path": "src/afterglow/effects/params.clj",
    "content": "(ns afterglow.effects.params\n  \"A general mechanism for passing dynamic parameters to effect\n  functions and assigners allowing for dynamic values to be computed\n  either when an effect creates its assigners, or when the assigners\n  are resolving DMX values. Parameters can be calculated based on the\n  show metronome snapshot, show variables (which can be bound to OSC\n  and MIDI mappings), and other, not-yet-imagined things.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as chan]\n            [afterglow.rhythm :as rhythm :refer [metro-snapshot]]\n            [afterglow.show-context :refer [*show* with-show]]\n            [afterglow.util :as util]\n            [clojure.math.numeric-tower :as math]\n            [com.evocomputing.colors :as colors]\n            [taoensso.timbre :as timbre :refer [error]])\n  (:import [afterglow.rhythm MetronomeSnapshot]\n           [javax.media.j3d Transform3D]\n           [javax.vecmath Point3d Vector3d Vector2d]))\n\n(defonce\n  ^{:private true\n    :doc \"Protect protocols against namespace reloads\"}\n  _PROTOCOLS_\n  (do\n(defprotocol IParam\n  \"A dynamic parameter which gets evaluated during the run of a light\n  show, with access to the show and its metronome snapshot.\"\n  (evaluate [this show snapshot head]\n  \"Determine the value of this parameter at a given moment (identified\n  by `snapshot`) of the `show`. If the parameter is being evaluated\n  for a specific fixture head, that will be passed in `head`. If no\n  fixure context is available, `head` will be `nil`.\")\n  (frame-dynamic? [this]\n  \"If `true`, this parameter varies at every frame of the show, and\n  must be invoked by effect assigners for each frame of DMX data\n  generated. If `false`, the value can be determined at the time an\n  effect is created, and passed as a constant to the assigners.\")\n  (result-type [this]\n  \"The type of value that will be returned when this parameter is\n  resolved.\")\n  (resolve-non-frame-dynamic-elements [this show snapshot head]\n  \"Called when an effect is created using this parameter. If the\n  parameter is not frame-dynamic, this function should return the\n  parameter's final resolution to a constant of the type returned by\n  `result-type`; otherwise, it should return a version of the\n  parameter where any of its own non frame-dynamic input parameters\n  have been resolved.\n\n  If the parameter is being evaluated for a specific fixture head,\n  that will be passed in `head`. If no fixure context is available,\n  `head` will be `nil`.\"))))\n\n\n(defn check-type\n  \"Ensure that a parameter is of a particular type, or that it\n  satisfies IParam and, when evaluated, returns that type, throwing an\n  exception otherwise. Used by the validate-param-type macros to do\n  the actual type checking.\"\n  [value type-expected name]\n  {:pre [(some? value) (some? type-expected) (some? name)]}\n  (cond (class? type-expected)\n        (when-not (or (instance? type-expected value)\n                      (and (satisfies? IParam value)  (.isAssignableFrom type-expected (result-type value))))\n          (throw (IllegalArgumentException. (str \"Variable \" name \" must be of type \" type-expected))))\n\n        (keyword? type-expected)\n        (when-not (or (= type-expected (type value))\n                      (and (satisfies? IParam value) (= type-expected (result-type value))))\n          (throw (IllegalArgumentException. (str \"Variable \" name \" must be of type \" type-expected))))\n\n        :else\n        (throw (IllegalArgumentException. (str \"Do not know how to check for type \" type-expected))))\n  value)  ;; Return the value if it validated\n\n(defmacro validate-param-type\n  \"Ensure that a parameter satisfies a predicate, or that it satisfies\n  [[IParam]] and, when evaluated, returns a type that passes that predicate,\n  throwing an exception otherwise.\"\n  ([value type-expected]\n   (let [arg value]\n     `(check-type ~value ~type-expected ~(str arg))))\n  ([value type-expected name]\n   `(check-type ~value ~type-expected ~name)))\n\n(defmacro validate-optional-param-type\n  \"Ensure that a parameter, if not `nil`, satisfies a predicate, or that\n  it satisfies [[IParam]] and, when evaluated, returns a type that passes\n  that predicate, throwing an exception otherwise.\"\n  ([value type-expected]\n   (let [arg value]\n     `(validate-optional-param-type ~value ~type-expected ~(str arg))))\n  ([value type-expected name]\n   `(when (some? ~value) (check-type ~value ~type-expected ~name))))\n\n(defn param?\n  \"Checks whether the argument is an [[IParam]].\"\n  [arg]\n  (satisfies? IParam arg))\n\n(defn resolve-param\n  \"Takes an argument which may be a raw value, or may be an [[IParam]].\n  If it is the latter, evaluates it and returns the resulting value,\n  recursively resolving again if we still have an [[IParam]].\n  Otherwise just returns the value that was passed in.\"\n  ([arg show snapshot]\n   (resolve-param arg show snapshot nil))\n  ([arg show snapshot head]\n   (if (satisfies? IParam arg)\n     (recur (evaluate arg show snapshot head) show snapshot head)\n     arg)))\n\n(defn frame-dynamic-param?\n  \"Checks whether the argument is an [[IParam]] which is dynamic to\n  the frame level.\"\n  [arg]\n  (and (satisfies? IParam arg) (frame-dynamic? arg)))\n\n(defn resolve-unless-frame-dynamic\n  \"If the first argument is an [[IParam]] which is not dynamic all the\n  way to the frame level, return the result of resolving it now. If it\n  is dynamic to the frame level, ask it to resolve any non\n  frame-dynamic elements. Otherwise return it unchanged. If `head` is\n  supplied, and the parameter can use it at resolution time, then pass\n  it along.\"\n  ([arg show snapshot]\n   (resolve-unless-frame-dynamic arg show snapshot nil))\n  ([arg show snapshot head]\n   {:pre [(some? show)]}\n   (if (satisfies? IParam arg)\n     (if-not (frame-dynamic? arg)\n       (resolve-param arg show snapshot head)\n       (resolve-non-frame-dynamic-elements arg show snapshot head))\n     arg)))\n\n(defn build-variable-param\n  \"Create a dynamic parameter whose value is determined by the value\n  held in a variable of [[*show*]] at the time evaluation is\n  performed. Unless `:frame-dynamic` is passed a false value, this\n  evaluation will happen every frame.\n\n  If no type-compatible value is found in the show variable, a default\n  value is returned. That will be the number zero, unless otherwise\n  specified by `:default`. The type expected (and returned) by this\n  parameter will be numeric, unless a different value is passed for\n  `:type`, (in which case a new type-compatible `:default` value must\n  be specified).\n\n  If `:transform-fn` is supplied, it will be called with the value of\n  the variable and its return value will be used as the value of the\n  dynamic parameter. It must return a compatible type or its result\n  will be discarded.\"\n  [variable & {:keys [frame-dynamic type default transform-fn] :or {frame-dynamic true\n                                                                    type          Number\n                                                                    default       0}}]\n  {:pre [(some? *show*)]}\n  (validate-param-type default type)\n  (let [key     (keyword variable)\n        eval-fn (fn [show] (if (nil? transform-fn)\n                             (let [candidate (get @(:variables show) key default)]\n                               (try\n                                 (validate-param-type candidate type)\n                                 candidate\n                                 (catch Throwable _\n                                   (error (str \"Unable to use value of variable \" key \", value \" candidate\n                                               \" is not of type \" type \". Using default \" default))\n                                   default)))\n                             (let [candidate (get @(:variables show) key default)]\n                               (try\n                                 (validate-param-type candidate type)\n                                 (let [transformed (transform-fn candidate)]\n                                   (try\n                                     (validate-param-type transformed type)\n                                     transformed\n                                     (catch Throwable _\n                                       (error (str \"Unable to use transform-fn result for variable \" variable\n                                                   \", value \" transformed \" is not of type \" type\n                                                   \". Using untransformed value \" candidate))\n                                       candidate)))\n                                 (catch Throwable _\n                                   (error (str \"Unable to use value of variable \" key \", value \" candidate\n                                               \" is not of type \" type \". Using default \" default))\n                                   default)))))]\n    (reify IParam\n      (evaluate [_this show _ _]\n        (eval-fn show))\n      (frame-dynamic? [_this]\n        frame-dynamic)\n      (result-type [_this]\n        type)\n      (resolve-non-frame-dynamic-elements [this _ _ _]  ; Nothing to resolve, return self\n        this))))\n\n(defn bind-keyword-param*\n  \"Helper function that does the work of the [[bind-keyword-param]]\n  macro, which passes it the name of the parameter being bound for\n  nice error messages.\"\n  [param type-expected default param-name]\n  (when (some? param)\n    (if (keyword? param)\n      (build-variable-param param :type type-expected :default default)\n      ;; No keyword to bind to, just validate\n      (validate-param-type param type-expected param-name))))\n\n(defmacro bind-keyword-param\n  \"If an input to a dynamic parameter has been passed as a keyword,\n  treat that as a reference to a variable in [[*show*]]. If that variable\n  currently holds a dynamic parameter, try to bind it directly (throw\n  an exception if the types do not match). Otherwise, build a new\n  variable param to bind to future values of that show variable, and\n  return that, logging a warning if the current value (if any) of the\n  show variable is of an incompatible type for the parameter being\n  bound. If the input parameter is not a keyword, simply validate its\n  type.\"\n  ([value type-expected default]\n   (let [arg value]\n     `(bind-keyword-param* ~value ~type-expected ~default ~(str arg))))\n  ([value type-expected default param-name]\n   `(bind-keyword-param* ~value ~type-expected ~default ~param-name)))\n\n\n(defn- ensure-valid-interval\n  \"Make sure the desired interval is one of the valid keywords,\n  `:beat`, `:bar`, or `:phrase`. If not, log a warning and return\n  `:beat` as the value to use instead.\"\n  [interval]\n  (or (#{:beat :bar :phrase} interval)\n      (do (timbre/warn \"Unrecognized interval keyword\" interval \"using :beat instead\") :beat)))\n\n(defn- ensure-valid-fade-curve\n  \"Make sure the desired fade curve is one of the valid keywords,\n  `:linear` or `:sine`. If not, log a warning and return `:linear` as\n  the value to use instead.\"\n  [curve]\n  (or (#{:linear :sine} curve)\n      (do (timbre/warn \"Unrecognized fade curve keyword\" curve \"using :linear instead\") :linear)))\n\n(defn- fixed-step-param\n  \"Build an optimized version of a step parameter which can be used\n  when none of its configuration parameters are dynamic parameters.\n  See [[build-step-param]] for details about the parameters.\"\n  [interval interval-ratio fade-fraction fade-curve starting]\n  (let [interval (ensure-valid-interval interval)\n        fade-fraction (colors/clamp-unit-float fade-fraction)\n        fade-curve (ensure-valid-fade-curve fade-curve)\n        phase-key (keyword (str (name interval) \"-phase\"))\n        origin (dec (+ (interval starting) (math/round (phase-key starting))))\n        step-fn (if (= interval-ratio 1) ; Calculate base step level to be faded\n                    (fn [_ marker] marker) ; Simple, no beat ratio\n                    (fn [snapshot marker]\n                      (let [phase (phase-key snapshot)\n                            phased-marker (if (util/float= phase 0.0) marker (+ marker phase))]\n                        (inc (Math/floor (/ (dec phased-marker) interval-ratio))))))\n        phase-fn (if (= interval-ratio 1) ; Calculate phase of current step being faded\n                   (fn [snapshot _] (phase-key snapshot)) ; Simple, no beat ratio\n                   (fn [snapshot marker] (rhythm/enhanced-phase marker (phase-key snapshot) interval-ratio)))\n        fade-in (/ fade-fraction 2) ; Phase at which we are done fading in\n        fade-out (- 1 (/ fade-fraction 2)) ; Phase at which we start fading out\n        eval-fn (cond\n                  (util/float= fade-fraction 0)\n                  step-fn ; No fading required, use the basic step function\n\n                  (and (util/float= fade-fraction 1) (= fade-curve :linear))\n                  (fn [snapshot marker] ; Fade linearly through entire step\n                    (let [step (step-fn snapshot marker)]\n                      (+ (- step 0.5) (phase-fn snapshot marker))))\n\n                  :else\n                  (case fade-curve\n                    :linear (fn [snapshot marker]\n                              (let [step (step-fn snapshot marker)\n                                    phase (phase-fn snapshot marker)]\n                                (cond\n                                  (< phase fade-in) (- step (* 0.5 (/ (- fade-in phase) fade-in)))\n                                  (> phase fade-out) (+ step (* 0.5 (/ (- phase fade-out) fade-in)))\n                                  :else step)))\n                    :sine (fn [snapshot marker]\n                            (let [step (step-fn snapshot marker)\n                                  phase (phase-fn snapshot marker)]\n                              (cond\n                                (< phase fade-in)\n                                (let [fade-phase (/ phase fade-in)]\n                                  (+ step (/ (dec (Math/cos (* Math/PI (+ (/ fade-phase 2) 1.5)))) 2)))\n\n                                (> phase fade-out)\n                                (let [fade-phase (/ (- phase fade-out) fade-in)]\n                                  (+ step (/ (inc (Math/cos (* Math/PI (inc (/ fade-phase 2))))) 2)))\n\n                                :else\n                                step)))))]\n    (reify IParam\n      (evaluate [_this _ snapshot _]\n        (let [marker (- (interval snapshot) origin)]\n          (eval-fn snapshot marker)))\n      (frame-dynamic? [_this]\n        true)\n      (result-type [_this]\n        Number)\n      (resolve-non-frame-dynamic-elements [this _ _ _]  ; Nothing to resolve, always frame-dynamic\n        this))))\n\n(defn build-step-param\n  \"Returns a number parameter that increases over time, ideal for\n  convenient control\n  of [chases]({{guide-url}}effects.html#chases).\n\n  With no arguments, the parameter will evaluate to one at the beat\n  closest when it was created, and will increase by one for each beat\n  that passes, with no fades (fractional states).\n\n  The optional keyword argument `:interval` can be supplied with the\n  value `:bar` or `:phrase` to change the timing so that it instead\n  relates to bars or phrases. Supplying a value with `:interval-ratio`\n  will run the step parameter at the specified fraction or multiple of\n  the chosen interval (beat, bar, or phrase), as illustrated in\n  the [Ratios]({{guide-url}}oscillators.html#ratios)\n  section of the Oscillator documentation.\n\n  If fading between steps is desired, the optional keyword argument\n  `:fade-fraction` can be supplied with a non-zero value (up to but no\n  greater than `1`). This specifies what fraction of each interval is\n  involved in fading to or from the next value.\n\n  > See the graphs in the Step Parameters\n  > [documentation]({{guide-url}}parameters.html#step-parameters)\n  > for a visual illustration of how these parameters work.\n\n  A fade fraction of `0` provides the default behavior of an instant\n  jump between values with no fading. A fade fraction of `1` means\n  that each value continually fades into the next, and is never\n  steady. A fade fraction of `0.5` would mean that the value is stable\n  half the time, and fading for the other half: during the middle of\n  the interval, the value is steady at its assigned value; once the\n  final quarter of the interval begins, the value starts fading up,\n  reaching the halfway point as the interval ends, and the fade\n  continues through the first quarter of the next interval, finally\n  stabilizing for the next middle section. Smaller fade fractions mean\n  shorter periods of stability and slower fades, while larger\n  fractions yield longer periods of steady values, and quicker fades.\n\n  A smoother look can be obtained by using a sine curve to smooth the\n  start and end of each fade, by passing the optional keyword argument\n  `:fade-curve` with the value `:sine`. (Again, see\n  the [graphs]({{guide-url}}parameters.html#step-parameters)\n  to get a visual feel for what this does.)\n\n  If the timing should start at an instant other than when the step\n  parameter was created, a metronome snapshot containing the desired\n  start point can be passed with the optional keyword argument\n  `:starting`.\n\n  All incoming parameters may\n  be [dynamic]({{guide-url}}parameters.html).\n  Step parameters are always frame-dynamic.\"\n  [& {:keys [interval interval-ratio fade-fraction fade-curve starting]\n      :or {interval :beat interval-ratio 1 fade-fraction 0 fade-curve :linear\n           starting (when *show* (metro-snapshot (:metronome *show*)))}}]\n  {:pre [(some? *show*)]}\n  (validate-param-type interval clojure.lang.Keyword)\n  (validate-param-type fade-curve clojure.lang.Keyword)\n  (let [interval-ratio (bind-keyword-param interval-ratio Number 1)\n        fade-fraction (bind-keyword-param fade-fraction Number 0)\n        starting (bind-keyword-param starting MetronomeSnapshot (when *show* (metro-snapshot (:metronome *show*))))]\n    (if (not-any? param? [interval interval-ratio fade-fraction fade-curve starting])\n      (fixed-step-param interval interval-ratio fade-fraction fade-curve starting)  ; No dynamic params, can optimize\n      (reify IParam  ; Must build dynamic version\n        (evaluate [_this show snapshot head]\n          ;; Build and delegate to a one-time-use fixed step parameter based on the current values of our parameters\n          (let [interval (resolve-param interval show snapshot head)\n                interval-ratio (resolve-param interval-ratio show snapshot head)\n                fade-fraction (resolve-param fade-fraction show snapshot head)\n                fade-curve (resolve-param fade-curve show snapshot head)\n                starting (resolve-param starting show snapshot head)\n                current-version (fixed-step-param interval interval-ratio fade-fraction fade-curve starting)]\n            (evaluate current-version show snapshot head)))\n        (frame-dynamic? [_this]\n          true)\n        (result-type [_this]\n          Number)\n        (resolve-non-frame-dynamic-elements [this show snapshot head]\n          (if (not-any? frame-dynamic? [interval interval-ratio fade-fraction fade-curve starting])\n            ;; None of our arguments are frame-dynamic, so we can now optimize to a fixed step parameter\n            (let [interval (resolve-param interval show snapshot head)\n                  interval-ratio (resolve-param interval-ratio show snapshot head)\n                  fade-fraction (resolve-param fade-fraction show snapshot head)\n                  fade-curve (resolve-param fade-curve show snapshot head)\n                  starting (resolve-param starting show snapshot head)]\n              (fixed-step-param interval interval-ratio fade-fraction fade-curve starting))\n            this))))))  ; We have frame dynamic inputs, so we need to stay fully dynamic\n\n(defn interpret-color\n  \"Accept a color as either\n  a [jolby/colors](https://github.com/jolby/colors) object,\n  an [[IParam]] which will produce a color, a keyword, which will be\n  bound to a show variable by the caller, or a string which is passed\n  to the jolby/colors `create-color` function.\"\n  [color]\n  (cond (string? color)\n        (colors/create-color color)\n\n        (keyword? color)\n        color\n\n        (= (type color) :com.evocomputing.colors/color)\n        color\n\n        (satisfies? IParam color)\n        color\n\n        :else\n        (throw (IllegalArgumentException. (str \"Unable to interpret color parameter:\" color)))))\n\n  (def ^:private default-color \"The default color for build-color-param.\"\n    (colors/create-color [0 0 0]))\n\n(defn build-color-param\n  \"Returns a dynamic color parameter. If supplied, `:color` is passed\n  to [[interpret-color]] to establish the base color to which other\n  arguments are applied. The default base color is black, in the form\n  of all zero values for `r`, `g`, `b`, `h`, `s`, and `l`. To this\n  base it will then assign values passed in for individual color\n  parameters.\n\n  All incoming parameter values may be literal or dynamic, and may be\n  keywords, which will be dynamically bound to variables\n  in [[*show*]].\n\n  Not all parameter combinations make sense, of course: you will\n  probably want to stick with either some of `:h`, `:s`, and `:l`, or\n  some of `:r`, `:g`, and `:b`. If values from both are supplied, the\n  `:r`, `:g`, and/or `:b` assignments will occur first, then then any\n  `:h`, `:s`, and `:l` assignments will be applied to the resulting\n  color.\n\n  Finally, if any adjustment values have been supplied for hue,\n  saturation or lightness, they will be added to the corresponding\n  values (rotating around the hue circle, clamped to the legal range\n  for the others).\n\n  If you do not specify an explicit value for `:frame-dynamic`, this\n  color parameter will be frame dynamic if it has any incoming\n  parameters which themselves are.\"\n  [& {:keys [color r g b h s l adjust-hue adjust-saturation adjust-lightness frame-dynamic]\n      :or {color default-color frame-dynamic :default}}]\n  {:pre [(some? *show*)]}\n  (let [c (bind-keyword-param (interpret-color color) :com.evocomputing.colors/color default-color \"color\")\n        r (bind-keyword-param r Number 0)\n        g (bind-keyword-param g Number 0)\n        b (bind-keyword-param b Number 0)\n        h (bind-keyword-param h Number 0)\n        s (bind-keyword-param s Number 0)\n        l (bind-keyword-param l Number 0)\n        adjust-hue (bind-keyword-param adjust-hue Number 0)\n        adjust-saturation (bind-keyword-param adjust-saturation Number 0)\n        adjust-lightness (bind-keyword-param adjust-lightness Number 0)]\n    (if (not-any? param? [c r g b h s l adjust-hue adjust-saturation adjust-lightness])\n      ;; Optimize the degenerate case of all constant parameters\n      (let [result-color (atom c)]\n        (when (seq (filter identity [r g b]))\n          (let [red (when r (colors/clamp-rgb-int (math/round r)))\n                green (when g (colors/clamp-rgb-int (math/round g)))\n                blue (when b (colors/clamp-rgb-int (math/round b)))]\n            (swap! result-color #(colors/create-color {:r (or red (colors/red %))\n                                                       :g (or green (colors/green %))\n                                                       :b (or blue (colors/blue %))\n                                                       :a (colors/alpha %)}))))\n        (when (seq (filter identity [h s l]))\n          (let [hue (when h (colors/clamp-hue (double h)))\n                saturation (when s (colors/clamp-percent-float (double s)))\n                lightness (when l (colors/clamp-percent-float (double l)))]\n            (swap! result-color #(colors/create-color {:h (or hue (colors/hue %))\n                                                       :s (or saturation (colors/saturation %))\n                                                       :l (or lightness (colors/lightness %))}))))\n        (when adjust-hue\n          (swap! result-color #(colors/adjust-hue % (double adjust-hue))))\n        (when adjust-saturation\n          (swap! result-color #(colors/saturate % (double adjust-saturation))))\n        (when adjust-lightness\n          (swap! result-color #(colors/lighten % (double adjust-lightness))))\n        @result-color)\n      ;; Handle the general case of some dynamic parameters\n      (let [dyn (if (= :default frame-dynamic)\n                  ;; Default means incoming args control how dynamic we should be\n                  (boolean (some frame-dynamic-param?\n                                 [color r g b h s l adjust-hue adjust-saturation adjust-lightness]))\n                  ;; We were given an explicit value for frame-dynamic\n                  (boolean frame-dynamic))\n            eval-fn (fn [show snapshot head]\n                      (let [result-color (atom (resolve-param c show snapshot head))]\n                        (when (seq (filter identity [r g b]))\n                          (let [red (when r (colors/clamp-rgb-int\n                                             (math/round (resolve-param r show snapshot head))))\n                                green (when g (colors/clamp-rgb-int\n                                               (math/round (resolve-param g show snapshot head))))\n                                blue (when b ((colors/clamp-rgb-int\n                                               (math/round (resolve-param b show snapshot head)))))]\n                            (swap! result-color #(colors/create-color {:r (or red (colors/red %))\n                                                                       :g (or green (colors/green %))\n                                                                       :b (or blue (colors/blue %))\n                                                                       :a (colors/alpha %)}))))\n                        (when (seq (filter identity [h s l]))\n                          (let [hue (when h (colors/clamp-hue (double (resolve-param h show snapshot head))))\n                                saturation (when s (colors/clamp-percent-float\n                                                    (double (resolve-param s show snapshot head))))\n                                lightness (when l (colors/clamp-percent-float\n                                                   (double (resolve-param l show snapshot head))))]\n                            (swap! result-color #(colors/create-color {:h (or hue (colors/hue %))\n                                                                       :s (or saturation (colors/saturation %))\n                                                                       :l (or lightness (colors/lightness %))}))))\n                                (when adjust-hue\n                                  (swap! result-color\n                                         #(colors/adjust-hue % (double (resolve-param adjust-hue show snapshot head)))))\n                                (when adjust-saturation\n                                  (swap! result-color #(colors/saturate % (double (resolve-param adjust-saturation\n                                                                                                 show snapshot head)))))\n                                (when adjust-lightness\n                                  (swap! result-color\n                                         #(colors/lighten % (double (resolve-param\n                                                                     adjust-lightness show snapshot head)))))\n                                @result-color))\n            resolve-fn (fn [show snapshot head]\n                         (with-show show\n                           (build-color-param :color (resolve-unless-frame-dynamic c show snapshot head)\n                                              :r (resolve-unless-frame-dynamic r show snapshot head)\n                                              :g (resolve-unless-frame-dynamic g show snapshot head)\n                                              :b (resolve-unless-frame-dynamic b show snapshot head)\n                                              :h (resolve-unless-frame-dynamic h show snapshot head)\n                                              :s (resolve-unless-frame-dynamic s show snapshot head)\n                                              :l (resolve-unless-frame-dynamic l show snapshot head)\n                                              :adjust-hue (resolve-unless-frame-dynamic adjust-hue show snapshot head)\n                                              :adjust-saturation (resolve-unless-frame-dynamic\n                                                                  adjust-saturation show snapshot head)\n                                              :adjust-lightness (resolve-unless-frame-dynamic\n                                                                 adjust-lightness show snapshot head)\n                                              :frame-dynamic dyn)))]\n        (reify IParam\n          (evaluate [_this show snapshot head]\n            (eval-fn show snapshot head))\n          (frame-dynamic? [_this]\n            dyn)\n          (result-type [_this]\n            :com.evocomputing.colors/color)\n          (resolve-non-frame-dynamic-elements [_this show snapshot head]\n            (resolve-fn show snapshot head)))))))\n\n(defn build-direction-param\n  \"Returns a dynamic direction parameter for use\n  with [[direction-effect]]. If no arguments are supplied, returns a\n  static direction facing directly out towards the audience. Keywords\n  `:x`, `:y`, and `:z` can be used to specify a vector in the [frame\n  of reference]({{guide-url}}show_space.html) of the light show.\n\n  All incoming parameter values may be literal or dynamic, and may be\n  keywords, which will be dynamically bound to variables\n  in [[*show*]].\n\n  If you do not specify an explicit value for `:frame-dynamic`, this\n  direction parameter will be frame dynamic if it has any incoming\n  parameters which themselves are.\"\n  [& {:keys [x y z frame-dynamic] :or {x 0 y 0 z 1 frame-dynamic :default}}]\n  {:pre [(some? *show*)]}\n  (let [x (bind-keyword-param x Number 0)\n        y (bind-keyword-param y Number 0)\n        z (bind-keyword-param z Number 1)]\n    (if (not-any? param? [x y z])\n      ;; Optimize the degenerate case of all constant parameters\n      (Vector3d. x y z)\n      ;; Handle the general case of some dynamic parameters\n      (let [dyn (if (= :default frame-dynamic)\n                  ;; Default means incoming args control how dynamic we should be\n                  (boolean (some frame-dynamic-param? [x y z]))\n                  ;; We were given an explicit value for frame-dynamic\n                  (boolean frame-dynamic))\n            eval-fn (fn [show snapshot head]\n                      (Vector3d. (resolve-param x show snapshot head)\n                                 (resolve-param y show snapshot head)\n                                 (resolve-param z show snapshot head)))\n            resolve-fn (fn [show snapshot head]\n                         (with-show show\n                           (build-direction-param :x (resolve-unless-frame-dynamic x show snapshot head)\n                                                  :y (resolve-unless-frame-dynamic y show snapshot head)\n                                                  :z (resolve-unless-frame-dynamic z show snapshot head)\n                                                  :frame-dynamic dyn)))]\n        (reify IParam\n          (evaluate [_this show snapshot head]\n            (eval-fn show snapshot head))\n          (frame-dynamic? [_this]\n            dyn)\n          (result-type [_this]\n            Vector3d)\n          (resolve-non-frame-dynamic-elements [_this show snapshot head]\n            (resolve-fn show snapshot head)))))))\n\n(defn build-direction-transformer\n  \"Returns a dynamic direction parameter for use\n  with [[direction-effect]] which evaluates an incoming direction\n  parameter and transforms it according to a `Transform3D`\n  parameter.\n\n  All incoming parameter values may be literal or dynamic, and may be\n  keywords, which will be dynamically bound to variables\n  in [[*show*]].\n\n  If you do not specify an explicit value for `:frame-dynamic`, this\n  direction parameter will be frame dynamic if it has any incoming\n  parameters which themselves are.\"\n  [direction transform & {:keys [frame-dynamic] :or {frame-dynamic :default}}]\n  {:pre [(some? *show*)]}\n  (let [direction  (bind-keyword-param direction Vector3d (Vector3d. 0 0 1))\n        transform  (bind-keyword-param transform Transform3D (Transform3D.))\n        dyn        (if (= :default frame-dynamic)\n                     ;; Default means incoming args control how dynamic we should be\n                     (boolean (some frame-dynamic-param? [direction transform]))\n                     ;; We were given an explicit value for frame-dynamic\n                     (boolean frame-dynamic))\n        eval-fn    (fn [show snapshot head]\n                     (let [result (Vector3d. (resolve-param direction show snapshot head))]\n                       (.transform (resolve-param transform show snapshot head) result)\n                    result))\n        resolve-fn (fn [show snapshot head]\n                     (with-show show\n                       (build-direction-transformer (resolve-unless-frame-dynamic direction show snapshot head)\n                                                    (resolve-unless-frame-dynamic transform show snapshot head)\n                                                    :frame-dynamic dyn)))]\n    (reify IParam\n      (evaluate [_this show snapshot head]\n        (eval-fn show snapshot head))\n      (frame-dynamic? [_this]\n        dyn)\n      (result-type [_this]\n        Vector3d)\n      (resolve-non-frame-dynamic-elements [_this show snapshot head]\n        (resolve-fn show snapshot head)))))\n\n(defn- make-radians\n  \"If an angle was not already radians, convert it from degrees to\n  radians.\"\n  [angle radians]\n  (if radians\n    angle\n    (* (/ angle 180) Math/PI)))\n\n(defn vector-from-pan-tilt\n  \"Convert a pan and tilt value (angles in radians away from facing\n  directly out towards the audience) to the corresponding aiming\n  vector.\"\n  [pan tilt]\n  (let [euler (Vector3d. tilt pan 0)\n        rotation (Transform3D.)\n        direction (Vector3d. 0.0 0.0 1.0)]\n    (.setEuler rotation euler)\n    (.transform rotation direction)\n    direction))\n\n(defn build-direction-param-from-pan-tilt\n  \"An alternative to [[build-direction-param]] for cases in which\n  angles are more convenient than a vector, but when you still want to\n  use a [[direction-effect]], probably because you want to be able to\n  fade to or from another direction-effect. (In cases where you don't\n  need to do that, it is simpler to use a [[pan-tilt-effect]]\n  with [[build-pan-tilt-param]] and actually have the effect work with\n  pan and tilt angles, the way most lighting software does.)\n\n  Returns a dynamic direction parameter specified in terms of pan and\n  tilt angles away from facing directly out towards the audience. If\n  no arguments are supplied, returns a static direction facing\n  directly out towards the audience. Keywords `:pan` and `:tilt` can\n  be used to specify angles to turn around the Y and X axes\n  respectively\n  (see [show space]({{guide-url}}show_space.html) for a diagram of\n  these axes). For human friendliness, the angles are assumed to be in\n  degrees unless keyword `:radians` is supplied with a true value.\n\n  The values passed for `:pan` and `:tilt` may be dynamic, or may be\n  keywords, which will be dynamically bound to variables\n  in [[*show*]].\n\n  If you do not specify an explicit value for `:frame-dynamic`, the\n  resulting direction parameter will be frame dynamic if it has any\n  incoming parameters which themselves are.\"\n  [& {:keys [pan tilt radians frame-dynamic] :or {pan 0 tilt 0 frame-dynamic :default}}]\n  {:pre [(some? *show*)]}\n  (let [pan (bind-keyword-param pan Number 0)\n        tilt (bind-keyword-param tilt Number 0)]\n    (if (not-any? param? [pan tilt])\n      ;; Optimize the degenerate case of all constant parameters\n      (vector-from-pan-tilt (make-radians pan radians) (make-radians tilt radians))\n      ;; Handle the general case of some dynamic parameters\n      (let [dyn (if (= :default frame-dynamic)\n                  ;; Default means incoming args control how dynamic we should be\n                  (boolean (some frame-dynamic-param? [pan tilt]))\n                  ;; We were given an explicit value for frame-dynamic\n                  (boolean frame-dynamic))\n            eval-fn (fn [show snapshot head]\n                      (vector-from-pan-tilt (make-radians (resolve-param pan show snapshot head) radians)\n                                            (make-radians (resolve-param tilt show snapshot head) radians)))\n            resolve-fn (fn [show snapshot head]\n                         (with-show show\n                           (build-direction-param-from-pan-tilt\n                            :pan (resolve-unless-frame-dynamic pan show snapshot head)\n                            :tilt (resolve-unless-frame-dynamic tilt show snapshot head)\n                            :radians radians\n                            :frame-dynamic dyn)))]\n        (reify IParam\n          (evaluate [_this show snapshot head]\n            (eval-fn show snapshot head))\n          (frame-dynamic? [_this]\n            dyn)\n          (result-type [_this]\n            Vector3d)\n          (resolve-non-frame-dynamic-elements [_this show snapshot head]\n            (resolve-fn show snapshot head)))))))\n\n(defn build-pan-tilt-param\n  \"Returns a dynamic pan/tilt parameter for use with [[pan-tilt-effect]],\n  specified in terms of pan and tilt angles away from facing directly\n  out towards the audience. If no arguments are supplied, returns a\n  static orientation facing directly out towards the audience.\n  Keywords `:pan` and `:tilt` can be used to specify angles to turn\n  around the Y and X axes respectively\n  (see [show space]({{guide-url}}show_space.html) for a diagram of\n  these axes). For human friendliness, the angles are assumed to be in\n  degrees unless keyword `:radians` is supplied with a true value.\n\n  The values passed for `:pan` and `:tilt` may be dynamic, or may be\n  keywords, which will be dynamically bound to variables\n  in [[*show*]].\n\n  If you do not specify an explicit value for `:frame-dynamic`, the\n  resulting pan/tilt parameter will be frame dynamic if it has any\n  incoming parameters which themselves are.\n\n  Note that if you want to be able to fade the effect you are creating\n  to or from a [[direction-effect]], you need to create a\n  direction-effect rather than a pan-tilt-effect, and you can instead\n  use [[build-direction-param-from-pan-tilt]] to set its direction.\"\n  [& {:keys [pan tilt radians frame-dynamic] :or {pan 0 tilt 0 frame-dynamic :default}}]\n  {:pre [(some? *show*)]}\n  (let [pan (bind-keyword-param pan Number 0)\n        tilt (bind-keyword-param tilt Number 0)]\n    (if (not-any? param? [pan tilt])\n      ;; Optimize the degenerate case of all constant parameters\n      (Vector2d. (make-radians pan radians) (make-radians tilt radians))\n      ;; Handle the general case of some dynamic parameters\n      (let [dyn (if (= :default frame-dynamic)\n                  ;; Default means incoming args control how dynamic we should be\n                  (boolean (some frame-dynamic-param? [pan tilt]))\n                  ;; We were given an explicit value for frame-dynamic\n                  (boolean frame-dynamic))\n            eval-fn (fn [show snapshot head]\n                      (Vector2d. (make-radians (resolve-param pan show snapshot head) radians)\n                                 (make-radians (resolve-param tilt show snapshot head) radians)))\n            resolve-fn (fn [show snapshot head]\n                         (with-show show\n                           (build-pan-tilt-param :pan (resolve-unless-frame-dynamic pan show snapshot head)\n                                                 :tilt (resolve-unless-frame-dynamic tilt show snapshot head)\n                                                 :radians radians\n                                                 :frame-dynamic dyn)))]\n        (reify IParam\n          (evaluate [_this show snapshot head]\n            (eval-fn show snapshot head))\n          (frame-dynamic? [_this]\n            dyn)\n          (result-type [_this]\n            Vector2d)\n          (resolve-non-frame-dynamic-elements [_this show snapshot head]\n            (resolve-fn show snapshot head)))))))\n\n(defn build-aim-param\n  \"Returns a dynamic aiming parameter for use with [[aim-effect]].\n  If no arguments are supplied, returns a static direction aiming\n  towards a spot on the floor two meters towards the audience from the\n  center of the light show. Keywords `:x`, `:y`, and `:z` can be used\n  to specify a target point in the [frame of\n  reference]({{guide-url}}show_space.html)\n  of the light show.\n\n  All incoming parameter values may be literal or dynamic, and may be\n  keywords, which will be dynamically bound to variables\n  in [[*show*]].\n\n  If you do not specify an explicit value for `:frame-dynamic`, this\n  aim parameter will be frame dynamic if it has any incoming\n  parameters which themselves are.\"\n  [& {:keys [x y z frame-dynamic] :or {x 0 y 0 z 2 frame-dynamic :default}}]\n  {:pre [(some? *show*)]}\n  (let [x (bind-keyword-param x Number 0)\n        y (bind-keyword-param y Number 0)\n        z (bind-keyword-param z Number 2)]\n    (if (not-any? param? [x y z])\n      ;; Optimize the degenerate case of all constant parameters\n      (Point3d. x y z)\n      ;; Handle the general case of some dynamic parameters\n      (let [dyn (if (= :default frame-dynamic)\n                  ;; Default means incoming args control how dynamic we should be\n                  (boolean (some frame-dynamic-param? [x y z]))\n                  ;; We were given an explicit value for frame-dynamic\n                  (boolean frame-dynamic))\n            eval-fn (fn [show snapshot head]\n                      (Point3d. (resolve-param x show snapshot head)\n                                (resolve-param y show snapshot head)\n                                (resolve-param z show snapshot head)))\n            resolve-fn (fn [show snapshot head]\n                         (with-show show\n                           (build-aim-param :x (resolve-unless-frame-dynamic x show snapshot head)\n                                            :y (resolve-unless-frame-dynamic y show snapshot head)\n                                            :z (resolve-unless-frame-dynamic z show snapshot head)\n                                            :frame-dynamic dyn)))]\n        (reify IParam\n          (evaluate [_this show snapshot head]\n            (eval-fn show snapshot head))\n          (frame-dynamic? [_this]\n            dyn)\n          (result-type [_this]\n            Point3d)\n          (resolve-non-frame-dynamic-elements [_this show snapshot head]\n            (resolve-fn show snapshot head)))))))\n\n(defn build-aim-transformer\n  \"Returns a dynamic aiming parameter for use with [[aim-effect]]\n  which evaluates an incoming aiming parameter and transforms it\n  according to a `Transform3D` parameter.\n\n  All incoming parameter values may be literal or dynamic, and may be\n  keywords, which will be dynamically bound to variables\n  in [[*show*]].\n\n  If you do not specify an explicit value for `:frame-dynamic`, this\n  aim parameter will be frame dynamic if it has any incoming\n  parameters which themselves are.\"\n  [aim transform & {:keys [frame-dynamic] :or {frame-dynamic :default}}]\n  {:pre [(some? *show*)]}\n  (let [aim        (bind-keyword-param aim Point3d (Point3d. 0 0 2))\n        transform  (bind-keyword-param transform Transform3D (Transform3D.))\n        dyn        (if (= :default frame-dynamic)\n                     ;; Default means incoming args control how dynamic we should be\n                     (boolean (some frame-dynamic-param? [aim transform]))\n                     ;; We were given an explicit value for frame-dynamic\n                     (boolean frame-dynamic))\n        eval-fn    (fn [show snapshot head]\n                     (let [result (Point3d. (resolve-param aim show snapshot head))]\n                       (.transform (resolve-param transform show snapshot head) result)\n                       result))\n        resolve-fn (fn [show snapshot head]\n                     (with-show show\n                       (build-aim-transformer (resolve-unless-frame-dynamic aim show snapshot head)\n                                              (resolve-unless-frame-dynamic transform show snapshot head)\n                                              :frame-dynamic dyn)))]\n    (reify IParam\n      (evaluate [_this show snapshot head]\n        (eval-fn show snapshot head))\n      (frame-dynamic? [_this]\n        dyn)\n      (result-type [_this]\n        Point3d)\n      (resolve-non-frame-dynamic-elements [_this show snapshot head]\n        (resolve-fn show snapshot head)))))\n\n(defn- scale-spatial-result\n  \"Map an individual spatial parameter function result into the range\n  desired for all results, given the smallest result value, the size\n  of the range in which all result values fell, the start of the\n  desired output range, and the size of the desired output range.\"\n  [value smallest value-range start target-range]\n  (if (zero? value-range)\n    (+ start (/ target-range 2))  ; All values are the same, map to middle of range\n    (+ start (* target-range (/ (- value smallest) value-range)))))\n\n(defn- build-spatial-eval-fn\n  \"Create the function which evaluates a dynamic spatial parameter for\n  a given point in show time. If any of the parameters are dynamic,\n  they must be evaluated each time. Otherwise we can precompute them\n  now, for fast lookup as each DMX frame is rendered. If scaling is\n  requested, scale the results so they fall in the specified range.\"\n  [results scaling start target-range]\n  (if (not-any? param? (vals results))\n    ;; Optimize the case of all constant results\n    (let [precalculated (if scaling\n                          (let [smallest (apply min (vals results))\n                                largest (apply max (vals results))\n                                value-range (- largest smallest)]\n                            (reduce (fn [altered-map [k v]]\n                                      (assoc altered-map k (scale-spatial-result\n                                                            v smallest value-range start target-range)))\n                                    {} results))\n                          results)]\n      (fn [_show _snapshot head] (get precalculated (:id head) start))) ; Return min value if no head match\n\n    ;; Handle the general case of some dynamic results\n    (fn [show snapshot head]\n      (if scaling  ; Need to resolve all heads in order to scale the requested value appropriately\n        (let [resolved (reduce (fn [altered-map [k v]]\n                                 (assoc altered-map k (resolve-param v show snapshot head)))\n                               {} results)\n              smallest (apply min (vals resolved))\n              largest (apply max (vals resolved))\n              value-range (- largest smallest)]\n          (scale-spatial-result (get resolved (:id head) smallest) smallest value-range start target-range))\n        ;; Not scaling, only need to resolve the parameter for the specific head requested\n        (resolve-param (get results (:id head) start) show snapshot head)))))\n\n(defn build-spatial-param\n  \"Returns a dynamic number parameter related to the physical\n  arrangement of the supplied fixtures or heads. First the heads of\n  any fixtures passed in `fixtures-or-heads` are included. Then\n  function `f` is called for all fixtures or heads, passing in the\n  fixture or head. It must return a literal number or dynamic number\n  parameter.\n\n  If you pass a value with either `:max` or `:min` as optional keyword\n  parameters, this activates result scaling. (If you pass only a\n  `:max` value, `:min` defaults to zero; if you pass only `:min`, then\n  `:max` defaults to 255. If you pass neither, scaling is not\n  performed, and the results from `f` are returned unchanged.)\n  With scaling active, when it comes time to evaluate this spatial\n  parameter, any dynamic number parameters are evaluated, and the\n  resulting numbers are scaled as a group (after evaluating `f` for\n  every participating head or fixture) so they fall within the\n  range from `:start` to `:end`, inclusive.\n\n  Useful things that `f` can do include calculating the distance of\n  the head from some point, either in 3D or along an axis, its angle\n  from some line, and so on. These can allow the creation of lighting\n  gradients across all or part of a show. Spatial parameters make\n  excellent building blocks\n  for [color](#var-build-color-param), [direction](#var-build-direction-param)\n  and [aim](#var-build-aim-param) parameters, as shown in the [effect\n  examples]({{guide-url}}effects.html#spatial-effects).\n\n  If you do not specify an explicit value for `:frame-dynamic`, this\n  spatial parameter will be frame dynamic if any values returned by\n  `f` are dynamic parameters which themselves are frame dynamic.\"\n  [fixtures-or-heads f & {:keys [min max frame-dynamic] :or {frame-dynamic :default}}]\n  {:pre [(some? *show*) (sequential? fixtures-or-heads) (ifn? f)\n         (or (nil? min) (number? min)) (or (nil? max) (number? max)) (< (or min 0) (or max 255))]}\n  (let [heads (chan/expand-heads fixtures-or-heads)\n        results (zipmap (map :id heads)\n                        (map #(bind-keyword-param (f %) Number nil \"spatial-param function result\") heads))\n        scaling (or min max)\n        min (or min 0)\n        max (or max 255)\n        target-range (math/abs (- min max))]\n    (doseq [v (vals results)] (check-type v Number \"spatial-param function result\"))\n    (let [dyn (if (= :default frame-dynamic)\n                ;; Default means results of head function control how dynamic to be\n                (boolean (some frame-dynamic-param? (vals results)))\n                ;; We were given an explicit value for frame-dynamic-param\n                (boolean frame-dynamic))\n          eval-fn (build-spatial-eval-fn results scaling min target-range)\n          resolve-fn (fn [show snapshot head]\n                       (with-show show\n                         (let [resolved (reduce (fn [altered-map [k v]]\n                                                  (assoc altered-map k (resolve-unless-frame-dynamic\n                                                                        v show snapshot head)))\n                                                {} results)\n                               resolved-eval-fn (build-spatial-eval-fn resolved scaling min target-range)]\n                           (reify IParam\n                             (evaluate [_this show snapshot head]\n                               (resolved-eval-fn show snapshot head))\n                             (frame-dynamic? [_this]\n                               dyn)\n                             (result-type [_this]\n                               Number)\n                             (resolve-non-frame-dynamic-elements [this _ _ _]\n                               this)))))] ; Already resolved\n      (reify IParam\n        (evaluate [_this show snapshot head]\n          (eval-fn show snapshot head))\n        (frame-dynamic? [_this]\n          dyn)\n        (result-type [_this]\n          Number)\n        (resolve-non-frame-dynamic-elements [_this show snapshot head]\n          (resolve-fn show snapshot head))))))\n\n(defn build-param-formula\n  \"A helper function to create a dynamic parameter that involves some\n  sort of calculation based on the values of another group of dynamic\n  parameters. The result type reported by the resulting parameter will\n  be `param-type`.\n\n  Whenever the parameter's value is needed, it will evaluate all of\n  the parameters passed as `input-params`, and call `calc-fn` with\n  their current values, returning its result, which must have the type\n  specified by `param-type`.\n\n  The compound dynamic parameter will be frame dynamic if any of its\n  input parameters are.\"\n  [param-type calc-fn & input-params]\n  (reify IParam\n    (evaluate [_this show snapshot head]\n      (apply calc-fn (map #(resolve-param % show snapshot head) input-params)))\n    (frame-dynamic? [_this] (some frame-dynamic-param? input-params))\n    (result-type [_this]\n      param-type)\n    (resolve-non-frame-dynamic-elements [_this show snapshot head]\n      (apply build-param-formula param-type calc-fn\n             (map #(resolve-unless-frame-dynamic % show snapshot head) input-params)))))\n\n;; TODO: some kind of random parameter?\n"
  },
  {
    "path": "src/afterglow/effects/show_variable.clj",
    "content": "(ns afterglow.effects.show-variable\n  \"Virtual effects which set a value in a show variable while they\n  are running. Pair well with [[conditional-effect]] to modify the\n  behavior of scenes based on the activation of other cues.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.effects :as fx]\n            [afterglow.effects.params :as params]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [with-show]]\n            [clojure.set :as set])\n  (:import [afterglow.effects Effect Assigner]))\n\n(defn- empty-buffer\n  \"Empty the frame buffer of the specified show binding in\n  preparation for generating a new frame of the light show.\"\n  [frame-buffer last-frame]\n  (dosync\n   (ref-set last-frame @frame-buffer)\n   (ref-set frame-buffer {})))\n\n(defn- send-buffer\n  \"Update the associated show variable bindings based on differences\n  between what has been generated during this frame of the Afterglow\n  light show and the previous one, if any.\"\n  [show frame-buffer last-frame]\n  (with-show show\n    (let [previous-vars (set (keys @last-frame))\n          current-vars (set (keys @frame-buffer))]\n      ;; Restore the values of any variables which are no longer being affected.\n      (doseq [v (set/difference previous-vars current-vars)]\n        (let [[orig-val _] (get @last-frame v)]\n          (show/set-variable! v orig-val)))\n      ;; Set any variables that are newly assigned, or whose assignment value has changed.\n      (doseq [v current-vars]\n        (let [[_ new-val] (get @frame-buffer v)]\n          (when (or (not (previous-vars v))\n                    (not= new-val (get-in @last-frame [v 1])))\n            (show/set-variable! v new-val)))))))\n\n(defn bind\n  \"Establishes the association with the show, so that effects created\n  based on this structure will be able to set variables in the show.\"\n  [binding]\n  (with-show (:show binding)\n    (show/add-empty-buffer-fn! (:empty-fn binding))\n    (show/add-send-buffer-fn! (:send-fn binding))))\n\n(defn create-for-show\n  \"Creates the structures needed for adjusting variables in a show,\n  and establishes the binding to the show.\"\n  [show]\n  (let [frame-buffer (ref nil)\n        last-frame   (ref nil)\n        empty-fn     #(empty-buffer frame-buffer last-frame)\n        send-fn      #(send-buffer show frame-buffer last-frame)\n        binding      {:show         show\n                      :frame-buffer frame-buffer\n                      :last-frame   last-frame\n                      :empty-fn     empty-fn\n                      :send-fn      send-fn\n                      :no-resolve   (atom #{})}]\n    (bind binding)\n    binding))\n\n(defn unbind\n  \"Removes the association with the show. Once this has been called,\n  effects created based on this structure will no longer have any\n  effect on the variables of the show.\"\n  [binding]\n  (with-show (:show binding)\n    (show/clear-empty-buffer-fn! (:empty-fn binding))\n    (show/clear-send-buffer-fn! (:send-fn binding))))\n\n;; TODO: Could add effect which explictly expects numbers, so they can be faded, for example.\n(defn variable-effect\n  \"An effect which sets the show variable with the specified key to\n  match the parameter passed in, and restores its original value when\n  ended. Often combined with [[conditional-effect]] to enable\n  cross-effect relationships.\n\n  By default this effect will be named \\\"Set \\\" followed by the name\n  of the show variable passed in `k`, but you can give it a more\n  meaningful title to appear in the effects list using the optional\n  keyword argument `:name`.\n\n  Any dynamic parameter passed in `v` will be resolved to its\n  underlying value, (at the level of each frame at which the effect is\n  active if the parameter is frame-dynamic). If you don't want this to\n  happen (because you want to use this effect to store the dynamic\n  parameter itself in a show variable, for use by other effects), pass\n  the optional keyword argument `:resolve?` along with a `false`\n  value.\"\n  [binding k v & {:keys [name resolve?] :or {name     (str \"Set \" (clojure.core/name k))\n                                             resolve? true}}]\n  (Effect. name\n           fx/always-active\n           (fn [show snapshot]\n             (when-not resolve? (swap! (:no-resolve binding) conj k))\n             (let [resolved (if resolve? (params/resolve-unless-frame-dynamic v show snapshot) v)]\n               [(Assigner. :show-variable (keyword k) binding\n                            (fn [_show _snapshot _target _previous-assignment] resolved))]))\n           (fn [_show _snapshot]\n             (swap! (:no-resolve binding) disj k)\n             true)))\n\n;; Tell Afterglow about our assigners and the order in which they should be run.\n(show/set-extension-resolution-order! :afterglow.show-variable [:show-variable])\n\n;; Set up the resolution handler for the show variable assigner.\n(defmethod fx/resolve-assignment :show-variable [assignment show snapshot _]\n  (let [target    (:target assignment) ; Find the binding associated with this assignment.\n        target-id (:target-id assignment)\n        ;; Resolve the assignment value in case it is still frame dynamic.\n        resolved  (if (contains? @(:no-resolve target) target-id)\n                    (:value assignment)\n                    (params/resolve-param (:value assignment) show snapshot target))]\n    ;; Store it in our frame buffer so it can be set when the lights are being updated.\n    (dosync\n     (let [original-value (if-let [earlier-assignment (target-id @(:last-frame target))]\n                            (get earlier-assignment 0)\n                            (with-show (:show target)\n                              (show/get-variable target-id)))]\n       (alter (:frame-buffer target) assoc target-id [original-value resolved])))))\n"
  },
  {
    "path": "src/afterglow/effects.clj",
    "content": "(ns afterglow.effects\n  \"Support functions for building the effects pipeline.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.effects.params :as params]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show-context :refer [*show*]]\n            [afterglow.util :as util]\n            [clojure.math.numeric-tower :as math]\n            [taoensso.timbre :as timbre]\n            [taoensso.tufte :as tufte])\n  (:import [afterglow.rhythm MetronomeSnapshot]))\n\n(defonce\n  ^{:private true\n    :doc \"Protect protocols against namespace reloads\"}\n  _PROTOCOLS_\n  (do\n(defprotocol IAssigner\n  \"Assign some attribute (color, direction, channel value) to an\n  element of a light show at a given point in time. Any previous\n  assignment to this element will be supplied as an argument, and may\n  be tweaked or ignored as needs dictate. The target will be a subtree\n  of the show's fixtures, currently either a head or channel, or\n  something defined by an extension to the rendering loop..\"\n  (assign [this show ^MetronomeSnapshot snapshot target previous-assignment]\n  \"Calculate the value the `show` element `target` should have at the\n  moment in time represented by `snapshot`. The `previous-assignment`\n  value is available order to support blending,\n  highest-takes-priority, and other types of assignment which can be\n  influenced by assigners which have run earlier (because they are\n  associaed with effects running at lower priority or which started\n  earlier). Returns a value appropriate for the kind of assignment,\n  e.g. color object, channel value.\n\n  See the [Assigner\n  documentation]({{guide-url}}rendering_loop.html#assigners)\n  for more discussion.\"))\n\n;; At each DMX frame generation, we will run through all the effects and ask them if they are still\n;; active. If not, they will be removed from the list of active effects. For the remaining ones,\n;; we obtain a list of assignments they want to make, and handle them as described above.\n(defprotocol IEffect\n  \"The effect is the basic building block of an Afterglow light show.\n  It generates a list of assignments that should be in effect at a\n  given moment in the show. It can end on its own, or be asked to end.\n  When asked, it may end immediately, or after some final activity,\n  such as a fade. See [The Effect\n  Lifecycle]({{guide-url}}effects.html#the-effect-lifecycle)\n  for more discussion.\"\n  (still-active? [this show snapshot]\n  \"An inquiry about whether this effect is finished, and can be\n  cleaned up. A `false` return value will remove the effect from the\n  show.\")\n  (generate [this show snapshot]\n  \"List the asignments needed to implement the desired effect at this\n  moment in time. Must return a sequence of\n  `afterglow.effects.Assigner` objects which will be merged into the\n  current frame based on their kind, target, and the effect's\n  priority. If the effect currently has nothing to contribute, it may\n  return an empty sequence.\")\n  (end [this show snapshot]\n  \"The effect has been asked to end. It should arrange to finish as\n  soon as possible; return `true` if it can end immediately, and it\n  will be removed from the show. Otherwise it will be allowed to\n  continue running as it performs its graceful shutdown\n  until [[still-active?]] returns `false`. If the user asks to end the\n  effect a second time during this process, however, it will simply be\n  removed from the show at that time.\"))))\n\n;; See https://afterglow-guide.deepsymmetry.org/afterglow/rendering_loop.html#assigners\n;;\n;; Afterglow runs through the list of effects in priority order; each will spit out some\n;; number of assigners, which are a tuple identifying what is to be assigned, and a function\n;; that can do the assigning, when provided with the show and current metronome snapshot:\n(defrecord Assigner [^clojure.lang.Keyword kind target-id target ^clojure.lang.IFn f]\n  IAssigner\n  (assign [this show snapshot target previous-assignment]\n    (f show snapshot target previous-assignment)))\n\n;; We will gather these into a map, whose keys are the assigner kind, and whose values, in turn, are\n;; maps of assigners of that kind. Each key in the inner map is a target ID for which values are\n;; to be assigned, and the values are the priority-ordered list of assigners to run on that target.\n;; On each DMX frame we will run through these lists in parallel, and determine the final assignment\n;; value which results for each target:\n(defrecord Assignment [^clojure.lang.Keyword kind target-id target value])\n\n;; Finally, once that is done, the resulting assignments will be\n;; resolved to DMX values by calling:\n(defmulti resolve-assignment\n  \"Translates an attribute assignment (e.g. color, direction, channel\n  value) for an element of a light show to the actual DMX values that\n  will implement it. Since the value of the assignment may still be a\n  dynamic parameter, the show and snapshot might be needed to resolve\n  it.\"\n  (fn [assignment show snapshot buffers]\n    (:kind assignment)))\n\n;; The effect is the basic building block of a light show. It has a name, which can appear in\n;; the user interface for interacting with the effect, and three functions which are called\n;; with the show and current metronome snapshot, as specified by the IEffect interface above.\n(defrecord Effect [^String name ^clojure.lang.IFn active-fn\n                   ^clojure.lang.IFn gen-fn ^clojure.lang.IFn end-fn]\n  IEffect\n  (still-active? [this show snapshot]\n    (active-fn show snapshot))\n  (generate [this show snapshot]\n    (gen-fn show snapshot))\n  (end [this show snapshot]\n    (end-fn show snapshot)))\n\n(defn always-active\n  \"An implementation of [[still-active?]] which simply always returns\n  `true`, useful for effects which run until you ask them to end.\"\n  [show snapshot]\n  true)\n\n(defn end-immediately\n  \"An implementation of [[end]] which just reports that the effect\n  is now finished by returning `true`. Useful for effects which can\n  simply be removed as soon as they are asked to end.\"\n  [show snapshot]\n  true)\n\n(defn build-head-assigner\n  \"Returns an assigner of the specified type which applies the\n  specified assignment function to the provided head or fixture.\"\n  [kind head f]\n  (Assigner. kind (:id head) head f))\n\n(defn build-head-assigners\n  \"Returns a list of assigners of the specified type which apply an\n  assignment function to all the supplied heads or fixtures.\"\n  [kind heads f]\n  (map #(build-head-assigner kind % f) heads))\n\n(defn build-head-parameter-assigner\n  \"Returns an assigner of the specified kind which applies a parameter\n  to the supplied head or fixture. If the parameter is not\n  frame-dynamic, it gets resolved when creating this assigner.\n  Otherwise, resolution is deferred to frame rendering time.\"\n  [kind head param show snapshot]\n  (let [resolved (params/resolve-unless-frame-dynamic param show snapshot head)]\n    (build-head-assigner kind head (fn [show snapshot target previous-assignment] resolved))))\n\n(defn build-head-parameter-assigners\n  \"Returns a list of assigners of the specified kind which apply a\n  parameter to all the supplied heads or fixtures.\"\n  [kind heads param show]\n  (let [snapshot (rhythm/metro-snapshot (:metronome show))]\n    (map #(build-head-parameter-assigner kind % param show snapshot) heads)))\n\n(defn scene\n  \"Create an effect which combines multiple effects into one.\n\n  Scenes are a way to group a list of effects to run as a single\n  effect. All of their assigners are combined into a single list, in\n  the order in which the effects were added to the scene. Because of\n  the way Afterglow evaluates assigners, that means that if any\n  constituent effects try to assign to the same target, the later ones\n  will have a chance to override or blend with the earlier ones.\"\n  [scene-name & effects]\n  (let [active (atom effects)]\n    (Effect. scene-name\n             (fn [show snapshot]\n               (swap! active (fn [fx] (filterv #(still-active? % show snapshot) fx)))\n               (boolean (seq @active)))\n             (fn [show snapshot] (mapcat #(generate % show snapshot) @active))\n             (fn [show snapshot]\n               (swap! active (fn [fx] (filterv #(not (end % show snapshot)) fx)))\n               (empty? @active)))))\n\n(defonce ^{:private true\n           :doc \"We can reuse a single blank effect, shared by everyone who\n  needs it, since it does nothing and never changes.\"}\n  blank-effect (Effect. \"Blank\"\n                        always-active\n                        (fn [show snapshot]\n                          [])\n                        end-immediately))\n\n(defn blank\n  \"Create an effect which does nothing. This can be useful, for\n  example, when you want to use [[fade]] to fade into an effect from a\n  state where there was simply nothing happening (or where earlier and\n  lower-priority effects can show through). If you want the blank\n  effect to have a particular name, for example you are using it to\n  set shared cue variables, you can pass a string argument.\"\n  ([]\n   blank-effect)\n  ([effect-name]\n   (Effect. effect-name\n            always-active\n            (fn [show snapshot]\n              [])\n            end-immediately)))\n\n(defn code\n  \"An effect which simply calls a function, then ends immediately,\n  to allow arbitrary code to be easily run from the cue grid, for\n  example to reset the metronome if the controller mapping doesn't\n  have a dedicated button for that.\n\n  `f` must be a function which takes two arguments. It will be called\n  with the show and metronome snapshot a single time, when the effect\n  is first launched. It must return immediately, because this is\n  taking place on the effect rendering pipeline, so any lengthy\n  operations must be performed on another thread.\n\n  The effect stays running until asked to end, so that grid\n  controllers can give visual feedback that it was started, but it\n  doesn't do anyting more after calling the function once when it\n  starts.\"\n  [f]\n  {:pre [(ifn? f)]}\n  (let [ran (atom false)]\n    (Effect. \"Code\"\n             (fn [show snapshot]\n               (swap! ran (fn [current]\n                            (or current (do (f show snapshot) true)))))\n             (fn [show snapshot]\n               [])  ; No assigners to return\n             end-immediately)))\n\n(defmulti fade-between-assignments\n  \"Calculates an intermediate value between two attribute assignments\n  of the same kind (e.g. color, direction, channel value) for an\n  element of a light show. Most code will not call this directly, and\n  will instead use the higher-level [[fade-assignment]] function to\n  help set it up, or simply use a full-blown [[fade]] effect. This is\n  the low-level mechanism which performs the fade calculations by\n  dispatching to an appropriate implementation based on the `:kind`\n  value of `from-assignment`, and it requires both `from-assignment`\n  and `to-assignment` to be non-`nil` instances of\n  `afterglow.effects.Assignment` of the same `:kind`.\n\n  The amount contributed by each assignment\n  is controlled by `fraction`, which can range from `0` (or less),\n  meaning that only `from-assignment` is considered, to `1` (or\n  greater), meaning that `to-assignment` is simply returned.\n  Intermediate values will ideally result in a blend between the two\n  assignments, with `0.5` representing an equal contribution from\n  each. Since the value of the assignments may still be dynamic\n  parameters, the show and snapshot might be needed to resolve them in\n  order to calculate the blended value. Some kinds of assignment may\n  not support blending, in which case the default implementation will\n  simply switch from `from-assignment` to `to-assignment` once\n  `fraction` reaches `0.5`.\"\n  (fn [from-assignment to-assignment fraction show snapshot]\n    (:kind from-assignment)))\n\n;; Provide a basic fallback implementation for assignment types which do not support blending.\n;; This will switch from the first to the second assignment once fraction crosses the halfway\n;; point.\n(defmethod fade-between-assignments :default [from-assignment to-assignment fraction _ _]\n  (if (util/float< fraction 0.5)\n    from-assignment\n    to-assignment))\n\n(defn fade-assignment\n  \"Calculates an intermediate value between two attribute assignments\n  of the same kind (e.g. color, direction, channel value) for an\n  element of a light show. The values of `from-assignment` and\n  `to-assignment` may either be instances of\n  `afterglow.effects.Assignment` of the same `:kind`, or they may be\n  `nil`, to indicate that the attribute is being faded to or from\n  nothing. This function does the preparation and valiation needed in\n  order to delegate safely to [[fade-between-assignments]] by\n  promoting `nil` values to empty assignments of the appropriate\n  `:kind` affecting the same target.\n\n  The amount contributed by each assignment is controlled by\n  `fraction`, which can range from `0` (or less), meaning that only\n  `from-assignment` is considered, to `1` (or greater), meaning that\n  `to-assignment` is simply returned. Intermediate values will ideally\n  result in a blend between the two assignments, with `0.5`\n  representing an equal contribution from each. Since the value of the\n  assignments may still be dynamic parameters, the show and snapshot\n  might be needed to resolve them in order to calculate the blended\n  value. Some kinds of assignment may not support blending, in which\n  case the default implementation will simply switch from\n  `from-assignment` to `to-assignment` once `fraction` reaches `0.5`.\"\n  [from-assignment to-assignment fraction show snapshot]\n  {:pre [(or (nil? from-assignment) (instance? Assignment from-assignment))\n         (or (nil? to-assignment) (instance? Assignment to-assignment))\n         (or (nil? from-assignment) (nil? to-assignment)\n             (and (= (:kind from-assignment) (:kind to-assignment))\n                   (= (:target-id from-assignment) (:target-id to-assignment))))]}\n  (when (or from-assignment to-assignment) ; Return nil unless there is anything to fade\n    (let [from (or from-assignment (map->Assignment (merge to-assignment {:value nil})))\n          to (or to-assignment (map->Assignment (merge from-assignment {:value nil})))]\n      (fade-between-assignments from to fraction show snapshot))))\n\n(defn conditional-effect\n  \"Create an effect which makes the output of another effect\n  conditional on whether a parameter has a non-zero value. Very useful\n  when combined with [[variable-effect]] which can set that value to\n  turn parts of a scene on or off independently. When `condition` has\n  the value `0`, this effect does nothing; when `condition` has any\n  other value, this effect behaves exactly like the effect passed in\n  as `effect`.\"\n  [effect-name condition effect]\n  {:pre [(some? *show*) (some? effect-name) (satisfies? IEffect effect)]}\n  (params/validate-param-type condition Number)\n  (let [snapshot (rhythm/metro-snapshot (:metronome *show*))\n        condition (params/resolve-unless-frame-dynamic condition *show* snapshot)]\n    ;; Could optimize for a non-dymanic condition, but that seems unlikely to be useful.\n    (Effect. effect-name\n             always-active\n             (fn [show snapshot]\n               (let [v (params/resolve-param condition show snapshot)]\n                 (when-not (zero? v)\n                   (generate effect show snapshot))))\n             end-immediately)))\n\n(defn- group-assigners\n  \"Organize a sequence of assigners into a map whose keys are a tuple\n  of the assigner's `:kind` and `:target-id` and, whose values are all\n  of the assigners with that type and target, in the same order in\n  which they were found in the original sequence.\"\n  [assigners]\n  (reduce (fn [results assigner]\n            (update results [(:kind assigner) (:target-id assigner)] (fnil conj []) assigner))\n          {} assigners))\n\n(defn run-assigners\n  \"Returns the final assignment value that results from iterating over\n  an assigner list that was gathered for a particular kind and target\n  ID, feeding each intermediate result to the next assigner in the\n  chain.\"\n  ([show snapshot assigners]\n   (run-assigners show snapshot assigners nil))\n  ([show snapshot assigners previous-assignment]\n   (tufte/p ::run-assigners\n            (when (seq assigners)\n              (let [{:keys [kind target-id target]} (first assigners)\n                    assignment (reduce (fn [result assigner]\n                                         (assign assigner show snapshot target result))\n                                       previous-assignment assigners)]\n                (Assignment. kind target-id target assignment))))))\n\n(defn- with-default-assignment\n  \"If the current assignment is empty, but there was a previous\n  assignment value, turn it into an actual assignment based on the\n  supplied template.\"\n  [assignment template previous-assignment]\n  (or assignment\n      (when previous-assignment (map->Assignment (assoc template :value previous-assignment)))))\n\n(defn- generate-fade\n  \"For each assigner kind and target generated by either the from or\n  to effect, create a new assigner that will run through the list of\n  assigners of that kind/target for both sides, then fade between the\n  resulting assignments.\"\n  [from-effect to-effect fraction show snapshot]\n  (let [from-groups (group-assigners (generate from-effect show snapshot))\n                         to-groups (group-assigners (generate to-effect show snapshot))\n                         keys (set (concat (keys from-groups) (keys to-groups)))]\n                     (map (fn [k]\n                            (let [from-assigners (get from-groups k)\n                                  to-assigners (get to-groups k)\n                                  template (or (first from-assigners) (first to-assigners))\n                                  f (fn [show snapshot target previous-assignment]\n                                      (let [from (with-default-assignment\n                                                   (run-assigners show snapshot from-assigners previous-assignment)\n                                                   template previous-assignment)\n                                            to (with-default-assignment\n                                                 (run-assigners show snapshot to-assigners previous-assignment)\n                                                 template previous-assignment)]\n                                        (:value (fade-assignment from to fraction show snapshot))))]\n                              (map->Assigner (assoc template :f f))))\n                          keys)))\n\n(defn- update-still-active\n  \"For compound effects which track an ordered list of effects,\n  update the vector of which are still running by\n  calling [[still-active?]] for any which are not yet known to have\n  ended.\"\n  [active-vec effects show snapshot]\n  (vec (map (fn [previously-active effect]\n              (and previously-active (boolean (still-active? effect show snapshot))))\n            active-vec effects)))\n\n(defn- end-still-active\n  \"For compound effects which track an ordered list of effects,\n  ask any which are marked as still running to end, and update\n  the active vector based on their response.\"\n  [active-vec effects show snapshot]\n  (vec (map (fn [previously-active effect]\n              (and previously-active (not (end effect show snapshot))))\n            active-vec effects)))\n\n(defn fade\n  \"Create an effect which fades between two other effects as the value\n  of a parameter changes from zero to one. When `phase` is `0` (or\n  less), this effect simply acts as if it were `from-effect`. When\n  `phase` is `1` (or greater), this effect acts like `to-effect`. For\n  values of `phase` between `0` and `1`, a proportional linear blend\n  between `from-effect` and `to-effect` is created, so that at `0.5`\n  each effect contributes the same amount.\n\n  Of course `phase` can be a dynamic parameter; interesting results\n  can be obtained with oscillated and variable parameters. And either\n  or both of the effects being faded between can be a scene, grouping\n  many other effects.\n\n  One of the effects may also be [[blank]], which allows the other\n  effect to be faded into or out of existence. When fading to or from\n  a blank effect, the fade allows any previous or lower-priority\n  effects to pass through as it approaches the blank effect. The same\n  is true when fading between effects that do not include all the same\n  fixtures, or affect different aspects of fixtures.\"\n  [fade-name from-effect to-effect phase]\n  {:pre [(some? *show*) (some? fade-name) (satisfies? IEffect from-effect) (satisfies? IEffect to-effect)]}\n  (params/validate-param-type phase Number)\n  (let [snapshot (rhythm/metro-snapshot (:metronome *show*))\n        phase (params/resolve-unless-frame-dynamic phase *show* snapshot)\n        active (atom [true true])]\n    ;; Could optimize for a non-dymanic phase, but that seems unlikely to be useful.\n    (Effect. fade-name\n             (fn [show snapshot]  ; We are still active if either effect is\n               (some true? (swap! active update-still-active [from-effect to-effect] show snapshot)))\n             (fn [show snapshot]\n               (let [v (params/resolve-param phase show snapshot)\n                     from-active (if (@active 0) from-effect blank-effect)\n                     to-active (if (@active 1) to-effect blank-effect)]\n                 (cond\n                   (util/float<= v 0.0) (generate from-active show snapshot)\n                   (util/float>= v 1.0) (generate to-active show snapshot)\n                   :else\n                   (generate-fade from-active to-active v show snapshot))))\n             (fn [show snapshot]  ; Ask any remaining active effects to end, record and report results\n               (every? false? (swap! active end-still-active [from-effect to-effect] show snapshot))))))\n\n(defn- bounce-if-needed\n  \"If a chanse is operating in bounce mode, expand the vector of\n  effects (or their activity states) to include a reflection of the\n  middle values, so that looping over the expanded list would have the\n  same effect as bouncing back and forth in the original list.\"\n  [mode values]\n  (vec (if (= mode :bounce) (concat values (butlast (reverse (butlast values)))) values)))\n\n(defn- find-chase-element\n  \"Look up the effect within a chase corresponding to a given position.\n  If the chase is looping, takes the index modulo the number of\n  elements; otherwise, if it falls outside the range of elements,\n  returns a [[blank]] effect. If an actual effect is found, but it is\n  no longer active, return a blank effect instead.\"\n  [position effects active looping?]\n  (let [position (if looping? (mod position (count effects)) position)\n        i (int (math/floor position))]\n    (if (get active i false) (get effects i blank-effect) blank-effect)))\n\n(defn chase\n  \"Create an effect which moves through a list of other effects based\n  on the value of a `position` parameter. When `position` is `1`, the\n  first effect in `effects` is used, `2` results in the second effect,\n  and so on. Intermediate values produce a [[fade]] between the\n  corresponding effects. The interpretation of values less than one or\n  greater than the number of effects in `effects` depends on the value\n  passed with the optional keyword argument `:beyond`. The default\n  behavior (when `:beyond` is omitted or passed with `:blank`) is to\n  treat any numbers outside the range of elements in `effects` as if\n  they refer to [[blank]] effects. This makes it easy to fade into the\n  first effect by having `position` grow from `0` to `1`, and to fade\n  out of the last effect by having `position` grow from the number of\n  elements in `effects` towards the next integer, at which point the\n  final effect will be fully faded out. In this mode, when `position`\n  resolves to a value less than zero, or greater than the number of\n  effects in `effects` plus one, the chase will end. So a chase which\n  fades in, fades between its effects, fades out, and ends, can be\n  implemented by simply passing in a variable parameter for `position`\n  which smoothly grows from zero as time goes on.\n\n  Of course `position` needs to be a dynamic parameter for the chase\n  to progress over time; [[build-step-param]] is designed to\n  conveniently create parameters for controlling chases in time with\n  the show metronome. They can also be controlled by a dial on a\n  physical controller that is bound to a show variable.\n\n  Passing a value of `:loop` with the optional keyword argument\n  `:beyond` causes the chase to treat `effects` as if it was an\n  infinite list of copies of itself, so once the final effect is\n  reached, the chase begins fading into the first effect again, and so\n  on. Similarly, if `position` drops below `1`, the chase starts\n  fading in to the final effect. In this mode the chase continues\n  until all of its underlying effects have ended (either on their own,\n  or because they were asked to end by the operator), or `position`\n  resolves to `nil`, which kills it instantly.\n\n  Finally, passing `:bounce` with `:beyond` is similar to `:loop`,\n  except that every other repetition of the list of effects is\n  traversed in reverse order. In other words, if `position` keeps\n  growing steadily in value, and there are three effects in `effects`,\n  with a `:beyond` value of `:loop` you will see them in the order 1\n  &rarr; 2 &rarr; 3 &rarr; 1 &rarr; 2 &rarr; 3 &rarr; 1&hellip; while\n  a value of `:bounce` would give you 1 &rarr; 2 &rarr; 3 &rarr; 2\n  &rarr; 1 &rarr; 2 &rarr; 3 &rarr; 2&hellip;.\n\n  Any element of `effects` can be a [[scene]], grouping many other\n  effects, or [[blank]], which will temporarily defer to whatever else\n  was happening before the chase was activated.\"\n  [chase-name effects position & {:keys [beyond] :or {beyond :blank}}]\n  {:pre [(some? *show*) (some? chase-name) (sequential? effects) (every? (partial satisfies? IEffect) effects)\n         (#{:blank :loop :bounce} beyond)]}\n  (params/validate-param-type position Number)\n  ;; Could optimize for a non-frame-dynamic position, but that is unlikely to ever occur.\n  (let [looping? (not= beyond :blank)\n        bounced-effects (bounce-if-needed beyond effects)\n        active (atom (vec (repeat (count effects) true)))]\n    (Effect. chase-name\n             (fn [show snapshot]\n               ;; Run as long as position does not resolve to nil, or fall outside a non-looped chase,\n               ;; and the underlying effects are still running.\n               (let [v (params/resolve-param position show snapshot)]\n                 (and (some? v)\n                      (or looping? (<= 0 v (inc (count bounced-effects))))\n                      (some true? (swap! active update-still-active effects show snapshot)))))\n             (fn [show snapshot]\n               (let [v (dec (params/resolve-param position show snapshot))\n                     fraction (- v (math/floor v))\n                     bounced-active (bounce-if-needed beyond @active)\n                     first-effect (find-chase-element v bounced-effects bounced-active looping?)]\n                 (if (util/float= 0 fraction)\n                   ;; We're positioned precisely at one effect; just generate it\n                   (generate first-effect show snapshot)\n                    ;; We are in between effects, so fade them together\n                   (let [next-effect (find-chase-element (inc v) bounced-effects bounced-active looping?)]\n                     (generate-fade first-effect next-effect fraction show snapshot)))))\n             (fn [show snapshot]  ; Ask any remaining active effects to end, record and report results\n               (every? false? (swap! active end-still-active effects show snapshot))))))\n\n(defn wrap-fade-in-out\n  \"Create an effect which achieves the common goal of having another\n  effect fade in when it starts, and then fade out again when it is\n  asked to end.\n\n  By default the fade-in and fade-out both occur smoothly over a\n  single beat, but you can adjust this by passing values for `step-in`\n  and `step-out`. Each of these should be maps of arguments that will\n  be merged on top of the default value `{:fade-fraction 1.0}` and\n  then passed as arguments to [[build-step-param]]. The arguments you\n  will most likely want to use are `:interval` (to fade over a bar or\n  phrase), or `:interval-ratio` to fade in over fractional or multiple\n  beats/bars/phrases.\"\n  [effect-name effect & {:keys [step-in step-out]}]\n  {:pre [(some? *show*) (some? effect-name) (satisfies? IEffect effect)]}\n  (let [step-in  (flatten (seq (merge {:fade-fraction 1.0} step-in)))\n        step-out (flatten (seq (merge {:fade-fraction 1.0} step-out)))\n        position (params/build-param-formula Number #(- % 0.5) (apply params/build-step-param step-in))\n        state    (atom {:fade (fade (str effect-name \" fade in\") blank-effect effect position)})]\n    (Effect. effect-name\n             (fn [show snapshot]\n               ;; Run until we've been asked to end and reached the end of the fade-out\n               (let [current @state]\n                 (or (not (:ending current))\n                     (< (params/resolve-param (:ending current) show snapshot) 1.0))))\n             (fn [show snapshot]\n               ;; While running, we just generate the current fade (which will be our fade-in until asked to end).\n               (generate (:fade @state) show snapshot))\n             (fn [_show _snapshot]\n               ;; When we are asked to end, we build and switch to our fade-out, and store the associated step\n               ;; parameter as `:ending` in our state, so the still-running check can tell we are ending, and\n               ;; use the step parameter to tell when we have faded out, and thus finished.\n               (let [position (params/build-param-formula Number #(- % 0.5) (apply params/build-step-param step-out))]\n                 (swap! state assoc :fade (fade (str effect-name \" fade out\") effect blank-effect position)\n                        :ending position)\n                 false)))))\n"
  },
  {
    "path": "src/afterglow/examples.clj",
    "content": "(ns afterglow.examples\n  \"Show some simple ways to use Afterglow, and hopefully inspire\n  exploration.\" {:author \"James Elliott\"}\n  (:require [afterglow.beyond :as beyond]\n            [afterglow.channels :as chan]\n            [afterglow.controllers :as ct]\n            [afterglow.controllers.tempo]\n            [afterglow.core :as core]\n            [afterglow.effects :as fx]\n            [afterglow.effects.channel :as chan-fx]\n            [afterglow.effects.color :as color-fx]\n            [afterglow.effects.cues :as cues]\n            [afterglow.effects.dimmer :refer [dimmer-effect master-set-level]]\n            [afterglow.effects.fun :as fun]\n            [afterglow.effects.movement :as move]\n            [afterglow.effects.oscillators :as oscillators]\n            [afterglow.effects.params :as params]\n            [afterglow.effects.show-variable :as var-fx]\n            [afterglow.fixtures]\n            [afterglow.fixtures.american-dj :as adj]\n            [afterglow.fixtures.blizzard :as blizzard]\n            [afterglow.fixtures.chauvet :as chauvet]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [*show* with-show set-default-show!]]\n            [afterglow.transform :as tf]\n            [amalloy.ring-buffer :refer [ring-buffer]]\n            [clojure.math.numeric-tower :as math]\n            [clojure.set :as set]\n            [clojure.string :as str]\n            [com.evocomputing.colors :as colors :refer [color-name create-color hue adjust-hue]]\n            [overtone.osc :as osc]\n            [taoensso.timbre :as timbre])\n  (:import [afterglow.effects Effect]\n           [javax.media.j3d Transform3D]\n           [javax.vecmath Point3d Vector3d]))\n\n(defonce ^{:doc \"Allows commands to be sent to the instance of\n  Pangolin Beyond running alongside this light show, in order to\n  affect laser cues.\"}\n  laser-show\n  #_(afterglow.beyond/beyond-server \"172.16.1.255\" 16062)\n  (afterglow.beyond/beyond-server \"172.30.228.255\" 16062))\n\n(defonce ^{:doc \"Holds the sample show if it has been created,\n  so it can be unregistered if it is being re-created.\"}\n  sample-show\n  (atom nil))\n\n(defn patch-lighting-rig\n  \"An example of how to patch a whole group of lights with a\n  parameterized location. We mount our lights on our lighting rig in\n  standard positions, so knowing the position of the rig and the\n  height to which it has been adjusted allows us to figure out where\n  all the lights are on it.\n\n  For the moment the orientation of the rig defines the orientation of\n  the show, and the origins of the show axes are the spot on the floor\n  underneath the center of the horizontal truss. The _z_ axis\n  increases towards the audience from that point.\n\n  Because the height of the rig can be adjusted, you can pass in a\n  value with `:y` to set the height of the center of the lower bar on\n  the horizontal truss. If omitted a default height of 62.5 inches is\n  used, which is approximately the height of the bar when the\n  extension poles are collapsed for load-in and strike.\n\n  We try to hang blades 1-4 at an angle of 72.5 degrees leaning towards\n  the audience, and blade 5 sags to about 101 degrees but if any angle\n  ends up being off and difficult to correct, it can be passed in with\n  `:blade-1-angle` through `:blade-5-angle` The actual mounting height\n  of blade 5, if it differs from 4 inches can be passed with\n  `:blade-5-height`.\n\n  Fixture numbers are assigned stage left to stage right (looking at\n  the lights from behind the rig), except for blade 5, which is an\n  extra which is sometimes placed in the middle.\n\n  It would be possible to extend this function to support positioning\n  and rotating the truss within show space, now that `patch-fixture`\n  allows you to pass in a transformation matrix. But until that\n  complexity is needed, this simpler approach seems practical. The\n  truss is the main component of our show, so having it be at the\n  origin makes sense.\"\n  [& {:keys [universe y blade-1-angle blade-2-angle blade-3-angle blade-4-angle blade-5-angle blade-5-height]\n      :or {universe 1 y (tf/inches 62.5)\n           blade-1-angle (tf/degrees 80.7) blade-2-angle (tf/degrees 76.4)\n           blade-3-angle (tf/degrees 77.6) blade-4-angle (tf/degrees 76.5)\n           blade-5-angle (tf/degrees 99) blade-5-height (tf/inches 4)}}]\n\n  ;; Torrent F3 moving head effect spots\n  (show/patch-fixture! :torrent-1 (blizzard/torrent-f3) universe 1\n                       :x (tf/inches 50) :y (+ y (tf/inches -14))\n                       :x-rotation (tf/degrees 180)\n                       :y-rotation (tf/degrees -90))\n  (show/patch-fixture! :torrent-2 (blizzard/torrent-f3) universe 17\n                       :x (tf/inches -50) :y (+ y (tf/inches -14))\n                       :x-rotation (tf/degrees 180)\n                       :y-rotation (tf/degrees -90))\n\n  ;; Hex IRC mini RGBAW+UV pars\n  (show/patch-fixture! :hex-1 (chauvet/slimpar-hex3-irc) universe 129\n                       :x (tf/inches 51.5) :y (+ y (tf/inches 15)))\n  (show/patch-fixture! :hex-2 (chauvet/slimpar-hex3-irc) universe 145\n                       :x (tf/inches -51.5) :y (+ y (tf/inches 15)))\n\n  ;; Blade moving-head RGBA pinspots\n  (show/patch-fixture! :blade-1 (blizzard/blade-rgbw :15-channel :version-2 true :hung (tf/inches 12)) universe 270\n                       :x (tf/inches 37) :y y\n                       :relative-rotations [[:y-rotation (tf/degrees 90)]\n                                            [:z-rotation blade-4-angle]])\n  (show/patch-fixture! :blade-2 (blizzard/blade-rgbw :15-channel :hung (tf/inches 12)) universe 240\n                       :x (tf/inches 20.5) :y (+ y (tf/inches 9))\n                       :relative-rotations [[:y-rotation (tf/degrees 90)]\n                                            [:z-rotation blade-2-angle]])\n  (show/patch-fixture! :blade-3 (blizzard/blade-rgbw :15-channel :hung (tf/inches 12)) universe 225\n                       :x (tf/inches -21) :y (+ y (tf/inches 9))\n                       :relative-rotations [[:y-rotation (tf/degrees 90)]\n                                            [:z-rotation blade-1-angle]])\n  (show/patch-fixture! :blade-4 (blizzard/blade-rgbw :15-channel :hung (tf/inches 12)) universe 255\n                       :x (tf/inches -37) :y y\n                       :relative-rotations [[:y-rotation (tf/degrees 90)]\n                                            [:z-rotation blade-3-angle]])\n  (show/patch-fixture! :blade-5 (blizzard/blade-rgbw :15-channel :version-2 true :hung (tf/inches 12)) universe 285\n                       :y (+ y blade-5-height)\n                       :relative-rotations [[:y-rotation (tf/degrees 90)]\n                                            [:z-rotation blade-5-angle]])\n\n  ;; Snowball RGBA moonflower effect\n  (show/patch-fixture! :snowball (blizzard/snowball) universe 33\n                       :x (tf/inches 6.5) :y (+ y (tf/inches 15)))\n\n  ;; Hypnotic RGB web effect diffraction pattern laser\n  (show/patch-fixture! :hyp-rgb (adj/hypnotic-rgb) universe 45\n                       :y (+ y (tf/inches -5)))\n\n  ;; These last two can be patched as generic dimmers instead if you want them to respond to dimmer cues,\n  ;; although they can only be on or off:\n\n  ;; LED UV bar\n  (show/patch-fixture! :eco-uv (afterglow.fixtures/generic-switch) universe 61)\n\n  ;; LED colored water effect\n  (show/patch-fixture! :h2o-led (afterglow.fixtures/generic-switch) universe 62))\n\n(def rig-height\n  \"The height of the center of the bottom horizontal truss bar of the\n  main lighting rig as set up in the current venue.\"\n  2.18)\n\n(def stage-wall\n  \"The location of the wall behind the rig on the show Z axis.\"\n  -0.42)\n\n(def house-rear-wall\n  \"The location of the wall behind the audience on the show Z axis.\"\n  12.9)\n\n(def left-wall\n  \"The location of the house left wall on the show X axis.\"\n  -5.89)\n\n(def right-wall\n  \"The location of the house right wall on the show X axis.\"\n  5.67)\n\n(def ceiling\n  \"The location of the ceiling on the show Y axis.\"\n  3.6)\n\n(defonce ^{:doc \"Allow us to send messages to an OSC interface like TouchOSC.\"}\n  osc-client\n  (atom nil))\n\n(def ipad-address\n  \"The IP address of the iPad that will be used with OSC.\"\n  \"172.16.42.3\")\n\n;; TODO: This kind of binding and tracking should be moved into an osc support namespace.\n(defonce ^{:doc \"Keep track of any OSC cue bindings we have set up,\n  so we can clear them out before re-creating the show.\"}\n  osc-cue-bindings\n  (atom #{}))\n\n(defn add-osc-cue-binding\n  \"Set up a binding so the state of a cue gets communicated via OSC,\n  and record that we did that so it can be cleaned up later. Then set\n  up so that incoming OSC messages can start and end that cue.\"\n  [x y path]\n  (let [binding (fn [state _ _]\n                  (case state\n                    :started (osc/osc-send @osc-client path 1)\n                    :ended (osc/osc-send @osc-client path 0)\n                    nil))]\n    (swap! osc-cue-bindings conj [x y binding path])\n    (ct/add-cue-fn! (:cue-grid *show*) x y binding))\n\n  (osc/osc-handle @core/osc-server path\n                  (fn [msg]\n                    (let [[cue active] (show/find-cue-grid-active-effect *show* x y)]\n                      (when cue\n                        (if (pos? (first (:args msg)))\n                          (if (and active (not (:held cue)))\n                            (show/end-effect! (:key cue))\n                            (show/add-effect-from-cue-grid! x y))\n                          (when (and active (:held cue))\n                            (show/end-effect! (:key cue)))))))))\n\n(defn clear-osc-cue-bindings\n  \"Clear out any OSC cue bindings which have been established.\"\n  []\n  (doseq [[x y f path] @osc-cue-bindings]\n    (ct/clear-cue-fn! (:cue-grid *show*) x y f)\n    (osc/osc-handle @core/osc-server path\n                    (fn [_msg] :done)))\n  (reset! osc-cue-bindings #{}))\n\n(defonce ^{:doc \"Keep track of any OSC var bindings we have set up,\n  so we can clear them out before re-creating the show.\"}\n  osc-var-bindings\n  (atom #{}))\n\n(defn add-osc-var-binding\n  \"Arrange to send an OSC message whenever the value of a show\n  variable changes, and record that we did that so it can be cleaned\n  up later. Then set things up so incoming OSC messages update the\n  value of that variable.\n\n  If you need to do anything more complicated than send a message with\n  the raw value of the variable, or update the variable with the raw\n  first value from the incoming OSC message, you can pass your own\n  functions with the optional keyword arguments `:send-fn` and\n  `:receive-fn`. `:send-fn` will be called with the keyword\n  identifying the variable that has changed, and its new value.\n  `:receive-fn` will be called with the incoming OSC message.\n\n  If you want this binding to not affect reception of messages on the\n  OSC path (for example because you have another variable binding set\n  up which processes these messages, since they contain values for\n  multiple show variables), then pass `:none` as the value for\n  `:receive-fn`.\"\n  [var-key path & {:keys [send-fn receive-fn]}]\n  (let [have-receiver (not= receive-fn :none)\n        binding (or send-fn\n                    (fn [_ v]\n                      (osc/osc-send @osc-client path v)))]\n    (swap! osc-var-bindings conj [var-key binding path have-receiver])\n    (show/add-variable-set-fn! var-key binding)\n\n    (when have-receiver\n      (osc/osc-handle @core/osc-server path\n                      (or receive-fn\n                          (fn [msg]\n                            (show/set-variable! var-key (first (:args msg)))))))))\n\n(defn clear-osc-var-bindings\n  \"Clear out any OSC var bindings which have been established.\"\n  []\n  (doseq [[k f path have-receiver] @osc-var-bindings]\n    (show/clear-variable-set-fn! k f)\n    (when have-receiver (osc/osc-handle @core/osc-server path\n                                        (fn [_msg] :done))))\n  (reset! osc-var-bindings #{}))\n\n(declare make-cues)\n\n(defn use-sample-show\n  \"Set up a sample show for experimenting with Afterglow. By default\n  it will create the show to use universe 1, but if you want to use a\n  different universe (for example, a dummy universe on ID 0, because\n  your DMX interface isn't handy right now), you can override that by\n  supplying a different ID after `:universe`.\n\n  Usually we run our shows on a single universe, but sometimes we\n  connect the Weather System fixtures to an extra universe, and wire\n  them separately from the main lighting rig. When we do that, we can\n  pass the extra universe ID in after `:extra-universe`.\n\n  If you have an instance of Pangolin Beyond running a laser show that\n  you want to control as well, pass a true value with `:add-beyond?`.\n  If you don't want to experiment with Open Sound Control, you can\n  pass a false value with `:add-osc?`.\"\n  [& {:keys [universe extra-universe add-beyond? add-osc?] :or {universe       1\n                                                                extra-universe universe\n                                                                add-osc?       true}}]\n  ;; Since this class is an entry point for interactive REPL usage,\n  ;; make sure a sane logging environment is established.\n  (core/init-logging)\n\n  ;; Create, or re-create the show, on the chosen OLA universe, for demonstration\n  ;; purposes. Make it the default show so we don't need to wrap everything below\n  ;; in a (with-show sample-show ...) binding\n  (set-default-show! (swap! sample-show (fn [s]\n                                          (when s\n                                            (show/unregister-show s)\n                                            (with-show s\n                                              (show/stop!)\n                                              (show/blackout-show)))\n                                          (show/show :universes (distinct [universe extra-universe])\n                                                     :description \"Sample Show\"))))\n\n  ;; Throw a couple of fixtures in there to play with. For better fun, use\n  ;; fixtures and addresses that correspond to your actual hardware. We always\n  ;; have a main universe for our main rig, and sometimes attach the other\n  ;; fixtures to their own universe if that turns out to be easier to wire.\n  (patch-lighting-rig :universe universe :y rig-height\n                      :blade-3-angle (tf/degrees 71.2) :blade-4-angle (tf/degrees 78.7))\n  (show/patch-fixture! :ws-1 (blizzard/weather-system) extra-universe 161\n                       :x 2.2 :y 1.33 :z -1.1 :y-rotation 0.0)\n  (show/patch-fixture! :ws-2 (blizzard/weather-system) extra-universe 187\n                       :x -2.2 :y 1.33 :z -1.1 :y-rotation 0.0)\n  #_(show/patch-fixture! :puck-1 (blizzard/puck-fab5) universe 97 :x (tf/inches -76) :y (tf/inches 8) :z (tf/inches 52))\n  #_(show/patch-fixture! :puck-2 (blizzard/puck-fab5) universe 113 :x (tf/inches -76) :y (tf/inches 8) :z (tf/inches 40))\n\n  (when add-osc?\n    ;; Turn on the OSC server, and clear any variable and cue bindings that might have been around from previous runs.\n    (when (nil? @core/osc-server)\n      (core/start-osc-server 16010))\n    (clear-osc-var-bindings)\n    (clear-osc-cue-bindings))\n\n  ;; Enable cues whose purpose is to set show variable values while they run.\n  (let [var-binder (atom (var-fx/create-for-show *show*))]\n\n    ;; Enable communication with the Beyond laser show\n    (when add-beyond? (beyond/bind-to-show laser-show *show*))\n\n    ;; Create a bunch of example cues\n    (make-cues var-binder add-beyond? add-osc?))\n\n  ;; Automatically bind the show to any compatible grid controllers that are connected now\n  ;; or in the future.\n  (ct/auto-bind *show*)\n\n  ;; Return the symbol through which the show can be accessed, rather than the value itself,\n  ;; which is huge and causes issues for some REPL environments.\n  '*show*)\n\n(defn global-color-effect\n  \"Make a color effect which affects all lights in the sample show.\n  This became vastly more useful once I implemented dynamic color\n  parameters. Can include only a specific set of lights by passing\n  them with :fixtures\"\n  [color & {:keys [include-color-wheels? fixtures effect-name] :or {fixtures (show/all-fixtures)}}]\n  (try\n    (let [[c desc] (cond (= (type color) :com.evocomputing.colors/color)\n                       [color (color-name color)]\n                       (and (params/param? color)\n                            (= (params/result-type color) :com.evocomputing.colors/color))\n                       [color \"variable\"]\n                       :else\n                       [(create-color color) color])]\n      (color-fx/color-effect (or effect-name (str \"Global \" desc)) c fixtures\n                             :include-color-wheels? include-color-wheels?))\n    (catch Exception e\n      (throw (Exception. (str \"Can't figure out how to create color from \" color) e)))))\n\n(defn global-dimmer-effect\n  \"Return an effect that sets all the dimmers in the sample rig.\n  Originally this had to be to a static value, but now that dynamic\n  parameters exist, it can vary in response to a MIDI mapped show\n  variable, an oscillator, or the location of the fixture. You can\n  override the default name by passing in a value with :effect-name\"\n  [level & {:keys [effect-name add-virtual-dimmers?]}]\n  (let [htp? (not add-virtual-dimmers?)]\n    (dimmer-effect level (show/all-fixtures) :effect-name effect-name :htp? htp?\n                   :add-virtual-dimmers? add-virtual-dimmers?)))\n\n(defn fiat-lux\n  \"Start simple with a cool blue color from all the lights.\"\n  []\n  (show/add-effect! :all-color (global-color-effect \"slateblue\" :include-color-wheels? true))\n  (show/add-effect! :dimmers (global-dimmer-effect 255))\n  (show/add-effect! :torrent-shutter\n                    (afterglow.effects.channel/function-effect\n                     \"Torrents Open\" :shutter-open 50 (show/fixtures-named \"torrent\"))))\n\n;; Get a little fancier with a beat-driven fade\n;; (show/add-effect! :dimmers (global-dimmer-effect\n;;   (oscillators/build-oscillated-param (oscillators/sawtooth))))\n\n;; To actually start the effects above (although only the last one assigned to any\n;; given keyword will still be in effect), uncomment or evaluate the next line:\n;; (show/start!)\n\n(defn sparkle-test\n  \"Set up a sedate rainbow fade and then layer on a sparkle effect to test\n  effect mixing.\"\n  []\n  (let [hue-param (oscillators/build-oscillated-param (oscillators/sawtooth :interval :phrase) :max 360)]\n    (show/add-effect! :all-color\n                      (global-color-effect\n                       (params/build-color-param :s 100 :l 50 :h hue-param)))\n    (show/add-effect! :sparkle\n                      (fun/sparkle (show/all-fixtures) :chance 0.05 :fade-time 50))))\n\n(defn mapped-sparkle-test\n  \"A verion of the sparkle test that creates a bunch of MIDI-mapped\n  show variables to adjust parameters while it runs.\"\n  []\n  (show/add-midi-control-to-var-mapping \"Slider\" 0 16 :sparkle-hue :max 360)\n  (show/add-midi-control-to-var-mapping \"Slider\" 0 0 :sparkle-lightness :max 100.0)\n  (show/add-midi-control-to-var-mapping  \"Slider\" 0 17 :sparkle-fade :min 10 :max 2000)\n  (show/add-midi-control-to-var-mapping  \"Slider\" 0 1 :sparkle-chance :max 0.3)\n  (let [hue-param (oscillators/build-oscillated-param (oscillators/sawtooth :interval :phrase) :max 360)\n        sparkle-color-param (params/build-color-param :s 100 :l :sparkle-lightness :h :sparkle-hue)]\n    (show/add-effect! :all-color\n                      (global-color-effect\n                       (params/build-color-param :s 100 :l 50 :h hue-param)))\n    (show/add-effect! :sparkle\n                      (fun/sparkle (show/all-fixtures) :color sparkle-color-param\n                                   :chance :sparkle-chance :fade-time :sparkle-fade))))\n\n;; Temporary for working on light aiming code\n\n(defn add-pan-tilt-controls\n  []\n  (show/add-midi-control-to-var-mapping \"Slider\" 0 0 :tilt :max 255.99)\n  (show/add-midi-control-to-var-mapping \"Slider\" 0 16 :pan :max 255.99)\n  (show/add-effect!\n   :pan-torrent (afterglow.effects.channel/channel-effect\n                 \"Pan Torrent\"\n                 :pan\n                 (chan/extract-channels (chan/expand-heads (show/fixtures-named :torrent)) #(= (:type %) :pan))))\n  (show/add-effect!\n   :tilt-torrent (afterglow.effects.channel/channel-effect\n                  \"Tilt Torrent\"\n                  :tilt\n                  (chan/extract-channels (chan/expand-heads (show/fixtures-named :torrent)) #(= (:type %) :tilt)))))\n\n(defn add-xyz-controls\n  []\n  (show/add-midi-control-to-var-mapping \"Slider\" 0 4 :x)\n  (show/add-midi-control-to-var-mapping \"Slider\" 0 5 :y)\n  (show/add-midi-control-to-var-mapping \"Slider\" 0 6 :z)\n  (show/add-effect! :position\n                    (move/direction-effect\n                     \"Pointer\" (params/build-direction-param :x :x :y :y :z :z) (show/all-fixtures)))\n  #_(show/add-effect! :position\n                    (move/aim-effect\n                     \"Aimer\" (params/build-aim-param :x :x :y :y :z :z) (show/all-fixtures)))\n  (show/set-variable! :y 2.6416))  ; Approximate height of ceiling\n\n(defn osc-demo\n  \"Early experiments with using OSC to control shows. This should grow\n  into a well-defined API, with integration to show variables, cue\n  grids, and the like.\"\n  []\n  (when (nil? @core/osc-server) (core/start-osc-server 16010))\n\n  (let [left (tf/inches -88)\n        right (tf/inches 86)\n        width (- right left)\n        front (tf/inches -21)\n        rear (tf/inches 295)\n        depth (- rear front)\n        height 3]\n    (osc/osc-handle @core/osc-server \"/1/aim-a\"\n                    (fn [msg]\n                      (show/set-variable! :aim-group-a-x (+ left (* width (first (:args msg)))))\n                      (show/set-variable! :aim-group-a-z (+ front (* depth (second (:args msg)))))\n                      #_(timbre/info msg)))\n    (osc/osc-handle @core/osc-server \"/1/aim-a-y\"\n                    (fn [msg]\n                      (show/set-variable! :aim-group-a-y (* height (first (:args msg))))\n                      #_(timbre/info msg)))\n    (osc/osc-handle @core/osc-server \"/1/aim-b\"\n                    (fn [msg]\n                      (show/set-variable! :aim-group-b-x (+ left (* width (first (:args msg)))))\n                      (show/set-variable! :aim-group-b-z (+ front (* depth (second (:args msg)))))\n                      #_(timbre/info msg)))\n    (osc/osc-handle @core/osc-server \"/1/aim-b-y\"\n                    (fn [msg]\n                      (show/set-variable! :aim-group-b-y (* height (first (:args msg))))\n                      #_(timbre/info msg))))\n  (osc/osc-handle @core/osc-server \"/1/sparkle\" (fn [msg]\n                                                (if (pos? (first (:args msg)))\n                                                  (show/add-effect! :sparkle (fun/sparkle (show/all-fixtures)\n                                                                                          :chance 0.1\n                                                                                          :fade-time 100))\n                                                  (show/end-effect! :sparkle))))\n  #_(osc/osc-listen @core/osc-server (fn [msg] (timbre/info msg)) :debug)\n  #_(osc/zero-conf-on)\n  (show/set-variable! :x 0)\n  (show/set-variable! :y 2.6416) ; Approximate height of ceiling\n  (show/set-variable! :z 0)\n  (show/add-effect! :position\n                    (move/aim-effect\n                     \"Aimer\" (params/build-aim-param :x :x :y :y :z :z) (show/all-fixtures))))\n\n(defn osc-shutdown\n  \"Shut down osc server and clean up.\"\n  []\n  (clear-osc-var-bindings)\n  (clear-osc-cue-bindings)\n  (core/stop-osc-server)\n  (swap! osc-client #(when % (osc/osc-close %) nil)))\n\n(defn make-color-cue\n  \"Create a cue-grid entry which establishes a global color effect,\n  given a named color. Also set up a cue color parameter so the color\n  can be tweaked in the Web UI or on the Ableton Push, and changes\n  can be saved to persist between invocations.\"\n  [color-name x y & {:keys [include-color-wheels? held fixtures effect-key effect-name priority]\n                     :or   {fixtures    (show/all-fixtures)\n                            effect-key  :color\n                            effect-name (str \"Color \" color-name)\n                            priority    0}}]\n  (let [color     (create-color color-name)\n        color-var {:key \"color\" :type :color :start color :name \"Color\"}\n        cue       (cues/cue effect-key\n                            (fn [var-map]\n                              (global-color-effect (params/bind-keyword-param (:color var-map)\n                                                                              :com.evocomputing.colors/color\n                                                                              color)\n                                                   :effect-name effect-name\n                                                   :fixtures fixtures\n                                                   :include-color-wheels? include-color-wheels?))\n                            :priority priority\n                            :held held\n                            :color color\n                            :color-fn (cues/color-fn-from-cue-var color-var x y)\n                            :variables [color-var])]\n    (show/set-cue! x y cue)))\n\n(defn- name-torrent-gobo-cue\n  \"Come up with a summary name for one of the gobo cues we are\n  creating that is concise but meaningful on a controller interface.\"\n  [prefix function]\n  (let [simplified (str/replace (name function) #\"^gobo-fixed-\" \"\")\n        simplified (str/replace simplified #\"^gobo-moving-\" \"m/\")\n        spaced (str/replace simplified \"-\" \" \")]\n    (str (str/upper-case (name prefix)) \" \" spaced)))\n\n(defn- make-torrent-gobo-cues\n  \"Create cues for the fixed and moving gobo options, stationary and\n  shaking. Takes up half a page, with the top left at the coordinates\n  specified.\"\n  [prefix fixtures top left]\n  ;; Make cues for the stationary and shaking versions of all fixed gobos\n  (doseq [_ (map-indexed (fn [i v]\n                           (let [blue (create-color :blue)\n                                 x (if (< i 8) left (+ left 2))\n                                 y (if (< i 8) (- top i) (- top i -1))\n                                 cue-key (keyword (str (name prefix) \"-gobo-fixed\"))]\n                             (show/set-cue! x y (cues/function-cue cue-key (keyword v) fixtures :color blue\n                                                                   :short-name (name-torrent-gobo-cue prefix v)))\n                             (let [function (keyword (str (name v) \"-shake\"))]\n                               (show/set-cue! (inc x) y (cues/function-cue\n                                                         cue-key function fixtures :color blue\n                                                         :short-name (name-torrent-gobo-cue prefix function))))))\n                         [\"gobo-fixed-mortar\" \"gobo-fixed-4-rings\" \"gobo-fixed-atom\" \"gobo-fixed-jacks\"\n                          \"gobo-fixed-saw\" \"gobo-fixed-sunflower\" \"gobo-fixed-45-adapter\"\n                          \"gobo-fixed-star\" \"gobo-fixed-rose-fingerprint\"])])\n  ;; Make cues for the stationary and shaking versions of all rotating gobos\n  (doseq [_ (map-indexed (fn [i v]\n                           (let [green (create-color :green)\n                                 cue-key (keyword (str (name prefix) \"-gobo-moving\"))]\n                             (show/set-cue! (+ left 2) (- top i)\n                                            (cues/function-cue cue-key (keyword v) fixtures :color green\n                                                               :short-name (name-torrent-gobo-cue prefix v)))\n                             (let [function (keyword (str (name v) \"-shake\"))]\n                               (show/set-cue! (+ left 3) (- top i)\n                                              (cues/function-cue\n                                               cue-key function fixtures :color green\n                                               :short-name (name-torrent-gobo-cue prefix function))))))\n                         [\"gobo-moving-rings\" \"gobo-moving-color-swirl\" \"gobo-moving-stars\"\n                          \"gobo-moving-optical-tube\" \"gobo-moving-magenta-bundt\"\n                          \"gobo-moving-blue-mega-hazard\" \"gobo-moving-turbine\"])]))\n\n(defn make-strobe-cue\n  \"_This is no longer used in the sample cue set, but is left as an\n  example in case you want to create a strobe cue that depends only on\n  numeric parameters, rather than the newer color parameter\n  capabilities._\n\n  Create a cue which strobes a set of fixtures as long\n  as the cue pad is held down, letting the operator adjust the\n  lightness of the strobe color by varying the pressure they are\n  applying to the pad on controllers which support pressure\n  sensitivity, and having the base strobe color depend on a set of\n  shared numeric show variable.\"\n  [name fixtures x y]\n  (show/set-cue! x y\n                 (cues/cue (keyword (str \"strobe-\" (clojure.string/replace (clojure.string/lower-case name) \" \" \"-\")))\n                           (fn [var-map] (fun/strobe (str \"Strobe \" name) fixtures\n                                                     (:level var-map 50) (:lightness var-map 100)))\n                           :color :purple\n                           :held true\n                           :priority 100\n                           :variables [{:key \"level\" :min 0 :max 100 :start 100 :name \"Level\"}\n                                       {:key \"lightness\" :min 0 :max 100 :name \"Lightness\" :velocity true}])))\n\n(def white\n  \"The color to flash strobe cues to identify them as such.\"\n  (create-color :white))\n\n(defn make-strobe-cue-2\n  \"Create a cue which strobes a set of fixtures as long as the cue pad\n  is held down, letting the operator adjust the lightness of the\n  strobe color by varying the pressure they are applying to the pad on\n  controllers which support pressure sensitivity, and having the base\n  strobe color depend on a shared show color variable. On controllers\n  which support it, the color of the cue pad will be also driven by\n  this shared color variable, with a white flicker to emphasize them\n  as strobing cues.\"\n  [name fixtures x y]\n  (when-not (= (type (show/get-variable :strobe-color)) :com.evocomputing.colors/color)\n    ;; If the default strobe color has not yet been established, set it to purple.\n    (show/set-variable! :strobe-color (create-color :purple)))\n  (let [color-var {:key :strobe-color :type :color :name \"Strobe Color\"}]\n    (show/set-cue! x y\n                   (cues/cue (keyword (str \"strobe-\" (clojure.string/replace (clojure.string/lower-case name) \" \" \"-\")))\n                             (fn [var-map] (fun/strobe-2 (str \"Strobe \" name) fixtures\n                                                         (:level var-map 50) (:lightness var-map 100)))\n                             :color :purple\n                             :color-fn (fn [cue _active _show snapshot]\n                                         (if (> (rhythm/snapshot-beat-phase snapshot 0.5) 0.7)\n                                           white\n                                           (or (show/get-variable :strobe-color)\n                                               (:color cue))))\n                             :held true\n                             :priority 100\n                             :variables [{:key \"level\" :min 0 :max 100 :start 100 :name \"Level\"}\n                                         {:key \"lightness\" :min 0 :max 100 :name \"Lightness\" :velocity true}\n                                         color-var]))))\n\n(def light-groups\n  \"The named groupings of lights to build rows of effects in the cue grid.\"\n  [:torrent :blade :ws :hex :puck :snowball])\n\n(defn group-end-keys\n  \"Helper function to produce a vector of effect keywords to end all\n  effects running on light groups with a given suffix.\"\n  [effect-suffix]\n  (mapv #(keyword (str (name %) \"-\" effect-suffix)) light-groups))\n\n(defn build-group-cue-elements\n  \"Helper function which builds the common variables needed to create\n  a cue which runs on either all lights or a named group of lights.\"\n  [group effect-suffix name-suffix]\n  (let [effect-key (or (when group (keyword (str (name group) \"-\" effect-suffix)))\n                       (keyword effect-suffix))\n        fixtures (or (when group (show/fixtures-named group))\n                     (show/all-fixtures))\n        end-keys (or (when group [(keyword effect-suffix)])\n                     (group-end-keys effect-suffix))\n        effect-name (str (case group\n                           nil \"All\"\n                           :ws \"WS\"\n                           (clojure.string/capitalize (name group)))\n                         \" \" (clojure.string/capitalize name-suffix))]\n    [effect-key fixtures end-keys effect-name]))\n\n(defn make-dimmer-cue\n  \"Creates a cue which lets the operator adjust the dimmer level of a\n  group of fixtures. Group will be one of the values\n  in [[light-groups]], or `nil` if the cue should affect all lights.\"\n  [group x y color]\n  (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group \"dimmers\" \"dimmers\")]\n    (show/set-cue! x y\n                   (cues/cue effect-key\n                             (fn [var-map] (dimmer-effect\n                                            (params/bind-keyword-param (:level var-map 255) Number 255)\n                                            fixtures :effect-name effect-name))\n                             :variables [{:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}]\n                             :color color :end-keys end-keys))))\n\n(defn build-ratio-param\n  \"Creates a dynamic parameter for setting the beat ratio of one of\n  the dimmer oscillator cues in [[make-cues]] by forming the ratio of\n  the cue variables introduced by the cue. This allows the show\n  operator to decide over how many beats the oscillator runs, and how\n  many times it cycles in that interval.\n\n  Expects the cue's variable map to contain entries `:beats` and\n  `:cycles` which will form the numerator and denominator of the\n  ratio. If any entry is missing, a default value of `1` is used\n  for it.\"\n  [var-map]\n  (let [beats-param (params/bind-keyword-param (:beats var-map) Number 1)\n        cycles-param (params/bind-keyword-param (:cycles var-map) Number 1)]\n    (params/build-param-formula Number #(/ %1 %2) beats-param cycles-param)))\n\n(defn- make-sawtooth-dimmer-param\n  \"Creates the sawtooth oscillated parameter used by\n  `make-sawtooth-dimmer-cue` for both the actual effect and its\n  visualizer.\"\n  [var-map]\n  (oscillators/build-oscillated-param (oscillators/sawtooth :down? (:down var-map)\n                                                            :interval-ratio (build-ratio-param var-map)\n                                                            :phase (:phase var-map))\n                                      :min (:min var-map) :max (:max var-map)))\n\n(defn make-sawtooth-dimmer-cue\n  \"Create a cue which applies a sawtooth oscillator to the dimmers of\n  the specified group of fixtures, with cue variables to adjust the\n  oscillator parameters.\"\n  [group x y color]\n  (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group \"dimmers\" \"saw\")]\n    (show/set-cue! x y\n                   (cues/cue effect-key\n                             (fn [var-map] (dimmer-effect (make-sawtooth-dimmer-param var-map) fixtures\n                                            :effect-name effect-name))\n                             :color color\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                         {:key \"down\" :type :boolean :start true :name \"Down?\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"phase\" :min 0 :max 1 :start 0 :name \"Phase\"}\n                                         {:key \"min\" :min 0 :max 255 :start 0 :name \"Min\"}\n                                         {:key \"max\" :min 0 :max 255 :start 255 :name \"Max\"}]\n                             :visualizer (fn [var-map show]\n                                           (let [p (make-sawtooth-dimmer-param var-map)]\n                                             (fn [snapshot]\n                                               (/ (params/evaluate p show snapshot nil) 255.0))))\n                             :end-keys end-keys))))\n\n(defn- make-triangle-dimmer-param\n  \"Creates the triangle oscillated parameter used by\n  `make-triangle-dimmer-cue` for both the actual effect and its\n  visualizer.\"\n  [var-map]\n  (oscillators/build-oscillated-param (oscillators/triangle :interval-ratio (build-ratio-param var-map)\n                                                            :phase (:phase var-map))\n                                      :min (:min var-map) :max (:max var-map)))\n\n(defn make-triangle-dimmer-cue\n  \"Create a cue which applies a triangle oscillator to the dimmers of\n  the specified set of fixtures, with cue variables to adjust the\n  oscillator parameters.\"\n  [group x y color]\n  (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group \"dimmers\" \"triangle\")]\n    (show/set-cue! x y\n                   (cues/cue effect-key\n                             (fn [var-map] (dimmer-effect (make-triangle-dimmer-param var-map) fixtures\n                                                          :effect-name effect-name))\n                             :color color\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"phase\" :min 0 :max 1 :start 0 :name \"Phase\"}\n                                         {:key \"min\" :min 0 :max 255 :start 0 :name \"Min\"}\n                                         {:key \"max\" :min 0 :max 255 :start 255 :name \"Max\"}]\n                             :visualizer (fn [var-map show]\n                                           (let [p (make-triangle-dimmer-param var-map)]\n                                             (fn [snapshot]\n                                               (/ (params/evaluate p show snapshot nil) 255.0))))\n                             :end-keys end-keys))))\n\n(defn- make-sine-dimmer-param\n  \"Creates the sine oscillated parameter used by\n  `make-sine-dimmer-cue` for both the actual effect and its\n  visualizer.\"\n  [var-map]\n  (oscillators/build-oscillated-param (oscillators/sine :interval-ratio (build-ratio-param var-map)\n                                                        :phase (:phase var-map))\n                                      :min (:min var-map) :max (:max var-map)))\n\n(defn make-sine-dimmer-cue\n  \"Create a cue which applies a sine oscillator to the dimmers of the\n  specified set of fixtures, with cue variables to adjust the\n  oscillator parameters.\"\n  [group x y color]\n  (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group \"dimmers\" \"sine\")]\n    (show/set-cue! x y\n                   (cues/cue effect-key\n                             (fn [var-map] (dimmer-effect (make-sine-dimmer-param var-map) fixtures\n                                                          :effect-name effect-name))\n                             :color color\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"phase\" :min 0 :max 1 :start 0 :name \"Phase\"}\n                                         {:key \"min\" :min 0 :max 255 :start 1 :name \"Min\"}\n                                         {:key \"max\" :min 0 :max 255 :start 255 :name \"Max\"}]\n                             :visualizer (fn [var-map show]\n                                           (let [p (make-sine-dimmer-param var-map)]\n                                             (fn [snapshot]\n                                               (/ (params/evaluate p show snapshot nil) 255.0))))\n                             :end-keys end-keys))))\n\n(defn- make-square-dimmer-param\n  \"Creates the square oscillated parameter used by\n  `make-square-dimmer-cue` for both the actual effect and its\n  visualizer.\"\n  [var-map]\n  (oscillators/build-oscillated-param (oscillators/square :interval-ratio (build-ratio-param var-map)\n                                                          :width (:width var-map)\n                                                          :phase (:phase var-map))\n                                      :min (:min var-map) :max (:max var-map)))\n\n(defn make-square-dimmer-cue\n  \"Create a cue which applies a square oscillator to the dimmers of\n  the specified set of fixtures, with cue variables to adjust the\n  oscillator parameters.\"\n  [group x y color]\n  (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group \"dimmers\" \"square\")]\n    (show/set-cue! x y\n                   (cues/cue effect-key\n                             (fn [var-map] (dimmer-effect (make-square-dimmer-param var-map) fixtures\n                                                          :effect-name effect-name))\n                             :color color\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                         {:key \"width\" :min 0 :max 1 :start 0.5 :name \"Width\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"phase\" :min 0 :max 1 :start 0 :name \"Phase\"}\n                                         {:key \"min\" :min 0 :max 255 :start 0 :name \"Min\"}\n                                         {:key \"max\" :min 0 :max 255 :start 255 :name \"Max\"}]\n                             :visualizer (fn [var-map show]\n                                           (let [p (make-square-dimmer-param var-map)]\n                                             (fn [snapshot]\n                                               (/ (params/evaluate p show snapshot nil) 255.0))))\n                             :end-keys end-keys))))\n\n(defn x-phase\n  \"Return a value that ranges from zero for the leftmost fixture in a\n  show to 1 for the rightmost, for staggering the phase of an\n  oscillator in making a can-can chase.\"\n  [head _show]\n  (let [dimensions @(:dimensions *show*)]\n    (/ (- (:x head) (:min-x dimensions)) (- (:max-x dimensions) (:min-x dimensions)))))\n\n(defn try-laser-cues\n  \"Create some cues that integrate Pangolin Beyond. Assumes sample\n  show has been created, and takes the beyond server to work with as\n  an argument.\"\n  [server]\n  (beyond/bind-to-show server *show*)\n  (let [hue-bar (oscillators/build-oscillated-param  ; Spread a rainbow across a bar of music\n                 (oscillators/sawtooth :interval :bar) :max 360)\n        hue-param (params/build-color-param :s :rainbow-saturation :l 50 :h hue-bar)]\n    (show/set-cue! 0 1\n                   (cues/cue :all-color (fn [_] (fx/scene \"Rainbow with laser\" (global-color-effect hue-param)\n                                                          (beyond/laser-color-effect server hue-param)))\n                             :short-name \"Rainbow Bar Fade\"\n                             :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                          :type :integer}])))\n  (show/set-cue! 2 7 (cues/cue :beyond-cue-1-1 (fn [_] (beyond/cue-effect server 1 1)) :short-name \"Beyond 1 1\"))\n  (show/set-cue! 3 7 (cues/cue :beyond-cue-1-2 (fn [_] (beyond/cue-effect server 1 2)) :short-name \"Beyond 1 2\"))\n  (show/set-cue! 6 7 (cues/function-cue :snowball-sound :sound-active (show/fixtures-named \"snowball\") :color :cyan)))\n\n(defonce ^{:doc \"A step parameter for controlling example chase cues.\n  Change it to experiment with other kinds of timing and fades.\"}\n  step-param\n  (atom nil))\n\n(defn- build-focus-oscillator\n  \"Returns a cue which oscillates a fixture's focus between a minimum\n  and minimum value using a sine oscillator with cue variables to\n  adjust the range and the oscillator's parameters.\"\n  [effect-key effect-name fixtures]\n  (cues/cue effect-key\n            (fn [var-map] (afterglow.effects.channel/function-effect\n                           effect-name :focus\n                           (oscillators/build-oscillated-param\n                            (oscillators/sine :interval-ratio (build-ratio-param var-map) :phase (:phase var-map))\n                            :min (:min var-map) :max (:max var-map))\n                           fixtures))\n            :color (create-color :yellow)\n            :variables [{:key \"min\" :min 0 :max 100 :start 0 :name \"Min\"}\n                        {:key \"max\" :min 0 :max 100 :start 100 :name \"Max\"}\n                        {:key \"beats\" :min 1 :max 32 :type :integer :start 4 :name \"Beats\"}\n                        {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                        {:key \"phase\" :min 0 :max 1 :start 0 :name \"Phase\"}]))\n\n(defn make-main-color-dimmer-cues\n  \"Creates a page of cues that assign dimmers and colors to the\n  lights. This is probably going to be assigned as the first page, but\n  can be moved by passing non-zero values for `page-x` and `page-y`.\n  If Beyond laser show integration is desired, `add-beyond?` will be\n  `true`. Similarly, if Open Sound Control integration is desired,\n  `add-osc?` will be `true`.\"\n  [page-x page-y add-beyond? add-osc?]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)\n        rig-left (:x (first (show/fixtures-named :hex-2)))\n        rig-right (:x (first (show/fixtures-named :hex-1)))\n        rig-width (- rig-right rig-left)\n        hue-bar (oscillators/build-oscillated-param  ; Spread a rainbow across a bar of music\n                 (oscillators/sawtooth :interval :bar) :max 360)\n        desat-beat (oscillators/build-oscillated-param  ; Desaturate a color as a beat progresses\n                    (oscillators/sawtooth :down? true) :max 100)\n        hue-gradient (params/build-spatial-param  ; Spread a rainbow across the light grid\n                      (show/all-fixtures)\n                      (fn [head] (- (:x head) (:min-x @(:dimensions *show*)))) :max 360)\n        rig-hue-gradient (params/build-spatial-param  ; Spread a rainbow across just the main rig, repeating\n                          (show/all-fixtures)         ; beyond that, irrespective of other lights' positions.\n                          (fn [head] (colors/clamp-hue (* 360 (/ (- (:x head) rig-left) rig-width)))))\n        hue-z-gradient (params/build-spatial-param  ; Spread a rainbow across the light grid front to back\n                        (show/all-fixtures)\n                        (fn [head] (- (:z head) (:min-z @(:dimensions *show*)))) :max 360)]\n\n    ;; Bottom row assigns colors, first to all fixtures, and then (at a higher priority, so they can\n    ;; run a the same time as the first, and locally override it) individual fixture groups.\n    (make-color-cue \"white\" x-base y-base :include-color-wheels? true\n                    :fixtures (show/all-fixtures) :effect-key :all-color :effect-name \"Color all\")\n    (doall (map-indexed (fn [i group]\n                          (make-color-cue \"white\" (+ x-base (inc i)) y-base :include-color-wheels? true\n                                          :fixtures (show/fixtures-named group)\n                                          :effect-key (keyword (str (name group) \"-color\"))\n                                          :effect-name (str \"Color \" (name group))\n                                          :priority 1))\n                        light-groups))\n\n    ;; Some special/fun cues\n    (show/set-variable! :rainbow-saturation 100)\n    (show/set-cue! x-base (inc y-base)\n                   (let [color-param (params/build-color-param :s :rainbow-saturation :l 50 :h hue-bar)]\n                     (cues/cue :all-color (fn [_] (global-color-effect color-param))\n                               :color-fn (cues/color-fn-from-param color-param)\n                               :short-name \"Rainbow Bar Fade\"\n                               :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                            :type :integer}])))\n    (show/set-cue! (inc x-base) (inc y-base)\n                   (cues/cue :all-color (fn [_] (global-color-effect\n                                                 (params/build-color-param :s :rainbow-saturation :l 50\n                                                                           :h rig-hue-gradient)\n                                                 :include-color-wheels? true))\n                             :short-name \"Rainbow Rig\"\n                             :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                          :type :integer}]))\n    (show/set-cue! (+ x-base 2) (inc y-base)\n                   (let [color-param (params/build-color-param :s :rainbow-saturation :l 50 :h hue-gradient\n                                                               :adjust-hue hue-bar)]\n                     (cues/cue :all-color (fn [_] (global-color-effect color-param))\n                               :color-fn (cues/color-fn-from-param color-param)\n                               :short-name \"Rainbow Grid+Bar\"\n                               :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                            :type :integer}])))\n    (show/set-cue! (+ x-base 3) (inc y-base) ; Desaturate the rainbow as each beat progresses\n                   (let [color-param (params/build-color-param :s desat-beat :l 50 :h hue-gradient\n                                                               :adjust-hue hue-bar)]\n                     (cues/cue :all-color (fn [_] (global-color-effect color-param))\n                               :color-fn (cues/color-fn-from-param color-param)\n                               :short-name \"Rainbow Pulse\")))\n\n    (show/set-cue! (+ x-base 4) (inc y-base)\n                   (cues/cue :transform-colors (fn [_] (color-fx/transform-colors (show/all-fixtures)))\n                             :priority 1000))\n\n    (show/set-cue! (+ x-base 5) (inc y-base)\n                   (cues/cue :all-color (fn [_] (global-color-effect\n                                                 (params/build-color-param :s 100 :l 50 :h hue-z-gradient)\n                                                 :include-color-wheels? true))\n                             :short-name \"Z Rainbow Grid\"))\n    (when add-beyond?\n      (show/set-cue! (+ x-base 6) (inc y-base)\n                     (let [color-param (params/build-color-param :s :rainbow-saturation :l 50 :h hue-bar)]\n                       (cues/cue :all-color (fn [_] (fx/scene \"Rainbow with laser\" (global-color-effect color-param)\n                                                              (beyond/laser-color-effect laser-show color-param)))\n                                 :color-fn (cues/color-fn-from-param color-param)\n                                 :short-name \"Rainbow with Laser\"\n                                 :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                              :type :integer}]))))\n    (show/set-cue! (+ x-base 7) (inc y-base)\n                   (let [color-param (params/build-color-param :s 100 :l 50 :h hue-gradient\n                                                               :adjust-hue hue-bar)]\n                     (cues/cue :all-color (fn [_] (global-color-effect color-param\n                                                                       :fixtures (show/fixtures-named \"blade\")))\n                               :color-fn (cues/color-fn-from-param color-param)\n                               :short-name \"Rainbow Blades\")))\n\n    #_(show/set-cue! (+ x-base 7) (+ y-base 7)\n                     (cues/function-cue :strobe-all :strobe (show/all-fixtures) :effect-name \"Raw Strobe\"))\n\n\n    ;; The fun sparkle cue, and a binding so TouchOSC can control it and show its state\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/cue :sparkle (fn [var-map]\n                                        (cues/apply-merging-var-map var-map fun/sparkle (show/all-fixtures)))\n                             :held true\n                             :priority 100\n                             :variables [{:key \"chance\" :min 0.0 :max 0.4 :start 0.05 :velocity true}\n                                         {:key \"fade-time\" :name \"Fade\" :min 1 :max 2000 :start 50 :type :integer}]))\n    (when add-osc?\n      (add-osc-cue-binding (+ x-base 7) (+ y-base 2) \"/1/sparkle\"))\n\n    ;; Dimmer cues to turn on and set brightness of groups of lights\n    (make-dimmer-cue nil x-base (+ y-base 2) :yellow)\n    (doall (map-indexed (fn [i group] (make-dimmer-cue group (+ x-base (inc i)) (+ y-base 2) :yellow)) light-groups))\n\n    ;; Dimmer oscillator cues: Sawtooth\n    (make-sawtooth-dimmer-cue nil x-base (+ y-base 3) :yellow)\n    (doall (map-indexed (fn [i group]\n                          (make-sawtooth-dimmer-cue group (+ x-base (inc i)) (+ y-base 3) :orange)) light-groups))\n\n    ;; Dimmer oscillator cues: Triangle\n    (make-triangle-dimmer-cue nil x-base (+ y-base 4) :orange)\n    (doall (map-indexed (fn [i group]\n                          (make-triangle-dimmer-cue group (+ x-base (inc i)) (+ y-base 4) :red)) light-groups))\n\n    ;; Dimmer oscillator cues: Sine\n    (make-sine-dimmer-cue nil x-base (+ y-base 5) :cyan)\n    (doall (map-indexed (fn [i group]\n                          (make-sine-dimmer-cue group (+ x-base (inc i)) (+ y-base 5) :blue)) light-groups))\n\n    ;; Dimmer oscillator cues: Square\n    (make-square-dimmer-cue nil x-base (+ y-base 6) :cyan)\n    (doall (map-indexed (fn [i group]\n                          (make-square-dimmer-cue group (+ x-base (inc i)) (+ y-base 6) :green)) light-groups))\n\n    ;; Strobe cues\n    (make-strobe-cue-2 \"All\" (show/all-fixtures) x-base (+ y-base 7))\n    (make-strobe-cue-2 \"Torrents\" (show/fixtures-named \"torrent\") (inc x-base) (+ y-base 7))\n    (make-strobe-cue-2 \"Blades\" (show/fixtures-named \"blade\") (+ x-base 2) (+ y-base 7))\n    (make-strobe-cue-2 \"Weather Systems\" (show/fixtures-named \"ws\") (+ x-base 3) (+ y-base 7))\n    (make-strobe-cue-2 \"Hexes\" (show/fixtures-named \"hex\") (+ x-base 4) (+ y-base 7))\n    (make-strobe-cue-2 \"Pucks\" (show/fixtures-named \"puck\") (+ x-base 5) (+ y-base 7))\n    (make-strobe-cue-2 \"Snowball\" (show/fixtures-named \"snowball\") (+ x-base 6) (+ y-base 7))\n\n    (let [color-var {:key :strobe-color :type :color :name \"Strobe Color\"}]\n      (show/set-cue! (+ x-base 7) (+ y-base 7) (cues/cue :strobe-color (fn [_] (fx/blank \"Strobe Color\"))\n                                                         :color :purple\n                                                         :color-fn (cues/color-fn-from-cue-var color-var)\n                                                         :variables [color-var])))\n\n    ;; This was the old way of adjusting strobe cues with only numeric parameters. The above\n    ;; cue shows how to do it with the newer color parameter approach.\n    #_(show/set-cue! (+ x-base 7) (+ y-base 6)\n                     (cues/cue :adjust-strobe (fn [_] (fun/adjust-strobe))\n                               :color :purple\n                               :variables [{:key :strobe-hue :min 0 :max 360 :name \"Hue\" :centered true}\n                                           {:key :strobe-saturation :min 0 :max 100 :name \"Saturatn\"}]))))\n\n(defn make-torrent-cues\n  \"Create a page of cues for configuring aspects of the Torrent F3s\n  and another to its right for their gobo selection.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)]\n    (show/set-cue! x-base (+ y-base 7)\n                   (cues/function-cue :torrent-shutter :shutter-open (show/fixtures-named \"torrent\")))\n    (show/set-cue! (inc x-base) (+ y-base 7)\n                   (cues/function-cue :torrent-reset :motor-reset (show/fixtures-named \"torrent\")\n                                      :color (create-color :red) :held true))\n\n    (show/set-cue! (+ x-base 6) (+ y-base 7)\n                   (cues/function-cue :t1-focus :focus (show/fixtures-named \"torrent-1\") :effect-name \"Torrent 1 Focus\"\n                                      :color (create-color :yellow)))\n    (show/set-cue! (+ x-base 7) (+ y-base 7)\n                   (cues/function-cue :t2-focus :focus (show/fixtures-named \"torrent-2\") :effect-name \"Torrent 2 Focus\"\n                                      :color (create-color :yellow)))\n    (show/set-cue! (+ x-base 4) (+ y-base 7)\n                   (build-focus-oscillator :t1-focus \"Torrent 1 Focus Sine\" (show/fixtures-named \"torrent-1\")))\n    (show/set-cue! (+ x-base 5) (+ y-base 7)\n                   (build-focus-oscillator :t2-focus \"Torrent 2 Focus Sine\" (show/fixtures-named \"torrent-2\")))\n    (show/set-cue! (+ x-base 6) (+ y-base 6)\n                   (cues/function-cue :t1-prism :prism-clockwise (show/fixtures-named \"torrent-1\") :level 100\n                                      :effect-name \"T1 Prism Spin CW\" :color (create-color :orange)))\n    (show/set-cue! (+ x-base 7) (+ y-base 6)\n                   (cues/function-cue :t2-prism :prism-clockwise (show/fixtures-named \"torrent-2\") :level 100\n                                      :effect-name \"T2 Prism Spin CW\" :color (create-color :orange)))\n    (show/set-cue! (+ x-base 6) (+ y-base 5)\n                   (cues/function-cue :t1-prism :prism-in (show/fixtures-named \"torrent-1\")\n                                      :effect-name \"T1 Prism In\" :color (create-color :orange)))\n    (show/set-cue! (+ x-base 7) (+ y-base 5)\n                   (cues/function-cue :t2-prism :prism-in (show/fixtures-named \"torrent-2\")\n                                      :effect-name \"T2 Prism In\" :color (create-color :orange)))\n    (show/set-cue! (+ x-base 6) (+ y-base 4)\n                   (cues/function-cue :t1-prism :prism-counterclockwise (show/fixtures-named \"torrent-1\")\n                                      :effect-name \"T1 Prism Spin CCW\" :color (create-color :orange)))\n    (show/set-cue! (+ x-base 7) (+ y-base 4)\n                   (cues/function-cue :t2-prism :prism-counterclockwise (show/fixtures-named \"torrent-2\")\n                                      :effect-name \"T2 Prism Spin CCW\" :color (create-color :orange)))\n    (show/set-cue! (+ x-base 6) (+ y-base 3)\n                   (cues/function-cue :t1-gobo-fixed :gobo-fixed-clockwise (show/fixtures-named \"torrent-1\")\n                                      :effect-name \"T1 Fixed Gobos Swap CW\" :color (create-color :blue)))\n    (show/set-cue! (+ x-base 7) (+ y-base 3)\n                   (cues/function-cue :t2-gobo-fixed :gobo-fixed-clockwise (show/fixtures-named \"torrent-2\")\n                                      :effect-name \"T2 Fixed Gobos Swap CW\" :color (create-color :blue)))\n    (show/set-cue! (+ x-base 6) (+ y-base 2)\n                   (cues/function-cue :t1-gobo-moving :gobo-moving-clockwise (show/fixtures-named \"torrent-1\")\n                                      :effect-name \"T1 Moving Gobos Swap CW\" :color (create-color :green)))\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/function-cue :t2-gobo-moving :gobo-moving-clockwise (show/fixtures-named \"torrent-2\")\n                                      :effect-name \"T2 Moving Gobos Swap CW\" :color (create-color :green)))\n    (show/set-cue! (+ x-base 6) (inc y-base)\n                   (cues/function-cue :t1-gobo-rotation :gobo-rotation-clockwise (show/fixtures-named \"torrent-1\")\n                                      :effect-name \"T1 Spin Gobo CW\" :color (create-color :cyan) :level 100))\n    (show/set-cue! (+ x-base 7) (inc y-base)\n                   (cues/function-cue :t2-gobo-rotation :gobo-rotation-clockwise (show/fixtures-named \"torrent-2\")\n                                      :effect-name \"T2 Spin Gobo CW\" :color (create-color :cyan) :level 100))\n    (show/set-cue! (+ x-base 6) y-base\n                   (cues/function-cue :t1-gobo-rotation :gobo-rotation-counterclockwise\n                                      (show/fixtures-named \"torrent-1\")\n                                      :effect-name \"T1 Spin Gobo CCW\" :color (create-color :cyan)))\n    (show/set-cue! (+ x-base 7) y-base\n                   (cues/function-cue :t2-gobo-rotation :gobo-rotation-counterclockwise\n                                      (show/fixtures-named \"torrent-2\")\n                                      :effect-name \"T2 Spin Gobo CCW\" :color (create-color :cyan)))\n\n    ;; Some compound cues\n    (show/set-cue! x-base y-base\n                   (cues/cue :star-swirl (fn [_] (cues/compound-cues-effect\n                                                  \"Star Swirl\" *show* [[(+ x-base 8) (+ y-base 4)]\n                                                                       [(+ x-base 10) (inc y-base)]\n                                                                       [(+ x-base 6) (+ y-base 7) {:level 60}]\n                                                                       [(+ x-base 6) y-base {:level 25}]]))))\n\n    (make-torrent-gobo-cues :t1 (show/fixtures-named \"torrent-1\") (+ y-base 7) (+ x-base 8))\n    (make-torrent-gobo-cues :t2 (show/fixtures-named \"torrent-2\") (+ y-base 7) (+ x-base 12))))\n\n(defn build-cross-scene\n  \"Create a scene which sets the color of one light, and aims it just\n  below and in front of another.\"\n  [move-key reference-key color]\n  (fx/scene \"Cross scene\"\n            (move/aim-effect \"Cross\" (javax.vecmath.Point3d. (:x (first (show/fixtures-named reference-key))) 0.0 0.2)\n                             (show/fixtures-named move-key))\n            (color-fx/color-effect \"Cross color\" color (show/fixtures-named move-key) :include-color-wheels? true)))\n\n(defn crossover-chase\n  \"Create a sequential chase which gradually takes over all the moving\n  heads from whatever they were doing, changes their colors, and makes\n  them cross in an interesting pattern. By default, stages of the\n  chase advance on every beat, but you can adjust that by passing in a\n  different value for with the optional keyword argument `:beats`. To\n  add a fade between stages, pass a non-zero value (up to 1, which\n  means continually fade) with `:fade-fraction`.\n\n  The color used during the crossover stages defaults to red, but you\n  can pass a different color object to use with `:cross-color`.\"\n  [& {:keys [beats fade-fraction cross-color end-color]\n      :or {beats 1 fade-fraction 0 cross-color (colors/create-color :red) end-color (colors/create-color :yellow)}}]\n  (let [beats (params/bind-keyword-param beats Number 1)\n        fade-fraction (params/bind-keyword-param fade-fraction Number 0)\n        cross-color (params/bind-keyword-param cross-color :com.evocomputing.colors/color (colors/create-color :red))\n        end-color (params/bind-keyword-param end-color :com.evocomputing.colors/color (colors/create-color :yellow))\n        cross-elements [(build-cross-scene :blade-3 :blade-2 cross-color)\n                        (build-cross-scene :blade-2 :blade-3 cross-color)\n                        (build-cross-scene :blade-4 :blade-1 cross-color)\n                        (build-cross-scene :blade-1 :blade-4 cross-color)\n                        (build-cross-scene :torrent-2 :torrent-1 cross-color)\n                        (build-cross-scene :torrent-1 :torrent-2 cross-color)]]\n    (fx/chase \"Crossover\"\n              (concat (for [i (range 1 (inc (count cross-elements)))]\n                        (apply fx/scene (str \"Crossover Scene \" i) (take i cross-elements)))\n                      [(fx/scene \"Crossover End\"\n                                 (move/aim-effect \"Cross End Point\" (Point3d. 0.0 0.0 2.5)\n                                                  (concat (show/fixtures-named \"blade\")\n                                                          (show/fixtures-named \"torrent\")))\n                                 (color-fx/color-effect \"Cross End color\" end-color\n                                                        (concat (show/fixtures-named \"blade\")\n                                                                (show/fixtures-named \"torrent\"))\n                                                        :include-color-wheels? true))\n                       (fx/blank)])\n              (params/build-step-param :interval-ratio beats :fade-fraction fade-fraction) :beyond :loop)))\n\n(defn circle-chain\n  \"Create a chase that generates a series of circles on either the\n  floor or the ceiling, causing a single head to trace out each, and\n  passing them along from head to head.\n\n  The number of bars taken to trace out each circle defaults to 2 and\n  can be adjusted by passing a different value with the optional\n  keyword argument `:bars`. The radius of each circle defaults to one\n  meter, and can be adjusted with `:radius`. If you want each head to\n  be tracing a different position in its circle, you can pass a value\n  between zero and one with `:stagger`.\"\n  [fixtures ceiling? & {:keys [bars radius stagger] :or {bars 2 radius 1.0 stagger 0.0}}]\n  (let [bars (params/bind-keyword-param bars Number 2)\n        radius (params/bind-keyword-param radius Number 1.0)\n        stagger (params/bind-keyword-param stagger Number 0.0)\n        snapshot (rhythm/metro-snapshot (:metronome *show*))\n        bars (params/resolve-unless-frame-dynamic bars *show* snapshot)\n        radius (params/resolve-unless-frame-dynamic radius *show* snapshot)\n        stagger (params/resolve-unless-frame-dynamic stagger *show* snapshot)\n        step (params/build-step-param :interval :bar :interval-ratio bars)\n        phase-osc (oscillators/sawtooth :interval :bar :interval-ratio bars)\n        width (- right-wall left-wall)\n        front (if ceiling? 0.5 stage-wall)  ; The blades can't reach behind the rig\n        depth (- house-rear-wall front)\n        y (if ceiling? ceiling 0.0)\n        heads (sort-by :x (move/find-moving-heads fixtures))\n        points (ref (ring-buffer (count heads)))\n        running (ref true)\n        current-step (ref nil)]\n    ;; It would also be possible to build this using a scene with fomula parameters to create\n    ;; the aiming points, but it is slightly more concise and direct to drop to implementing\n    ;; the lower-level effect interface. If this is too deep for your current stage of Afterglow\n    ;; learning, ignore it until you are ready to dig deeper into the rendering pipeline.\n    (Effect. \"Circle Chain\"\n             (fn [_show _snapshot]\n               ;; Continue running until all circles are finished\n               (dosync\n                (or @running (seq @points))))\n             (fn [show snapshot]\n               (dosync\n                (let [now (math/round (params/resolve-param step show snapshot))\n                      phase (oscillators/evaluate phase-osc show snapshot nil)\n                      stagger (params/resolve-param stagger show show snapshot)\n                      head-phases (map #(* stagger %) (range))]\n                  (when (not= now @current-step)\n                    (ref-set current-step now)\n                    (if @running  ;; Either add a new circle, or just drop the oldest\n                      (alter points conj (Point3d. (+ left-wall (rand width)) y (+ front (rand depth))))\n                      (alter points pop)))\n                  (map (fn [head point head-phase]\n                         (let [radius (params/resolve-param radius show snapshot head)\n                               theta (* 2.0 Math/PI (+ phase head-phase))\n                               head-point (Point3d. (+ (.x point) (* radius (Math/cos theta)))\n                                                    (.y point)\n                                                    (+ (.z point) (* radius (Math/sin theta))))]\n                           (fx/build-head-parameter-assigner :aim head head-point show snapshot)))\n                       heads @points head-phases))))\n             (fn [_show _snapshot]\n                 ;; Stop making new circles, and shut down once all exiting ones have ended.\n                 (dosync (ref-set running false))))))\n\n(defn make-ambient-cues\n  \"Create a page of cues for controlling lasers, and ambient effects\n  like the H2O LED and black light. Also adds copies of the important\n  cue for opening Torrent shutters and resetting their motors.\n\n  Also holds cues for turning on sound active mode when the show\n  operator wants to let things take care of themselves for a while,\n  and doesn't mind losing the ability to control show brightness via\n  dimmer masters.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)]\n\n    (show/set-cue! x-base (+ y-base 7)\n                   (cues/function-cue :torrent-shutter :shutter-open (show/fixtures-named \"torrent\")))\n    (show/set-cue! (inc x-base) (+ y-base 7)\n                   (cues/function-cue :torrent-reset :motor-reset (show/fixtures-named \"torrent\")\n                                      :color (create-color :red) :held true))\n\n    ;; Various ultraviolet options. Start by defining the pair of effects needed to turn the hex fixtures on\n    ;; in full UV mode.\n    (let [hex-uv-fx [(chan-fx/function-effect \"Hex UV\" :uv 100 (show/fixtures-named \"hex\"))\n                     (dimmer-effect 255 (show/fixtures-named \"hex\")\n                                    :effect-name \"Hex Dimmers for UV\")]]\n      (show/set-cue! (+ x-base 2) y-base\n                     (cues/cue :hex-uv (fn [_] (apply fx/scene \"Hex UV\" hex-uv-fx))\n                               :color :purple :end-keys [:uv]))\n\n      (show/set-cue! (inc x-base) y-base\n                     (cues/function-cue :eco-uv :on (show/fixtures-named :eco-uv)\n                                        :color :purple :effect-name \"Eco UV Bar\" :end-keys [:uv]))\n\n      (show/set-cue! x-base y-base\n                     (cues/cue :uv (fn [_]\n                                     (apply fx/scene \"All UV\"\n                                            (conj hex-uv-fx\n                                                  (chan-fx/function-effect \"Eco UV Bar\" :on 100\n                                                                           (show/fixtures-named :eco-uv)))))\n                               :color :purple :end-keys [:eco-uv :hex-uv])))\n\n    ;; Turn on the H2O LED\n    (show/set-cue! (+ x-base 7) y-base\n                   (cues/function-cue :h2o-led :on (show/fixtures-named :h2o-led) :effect-name \"H2O LED\"))\n\n    ;; Control the Hypnotic RGB Laser\n    (show/set-cue! x-base (+ y-base 2)\n                   (cues/function-cue :hypnotic-beam :beam-red (show/fixtures-named \"hyp-rgb\")\n                                      :color :red :effect-name \"Hypnotic Red\"))\n    (show/set-cue! (inc x-base) (+ y-base 2)\n                   (cues/function-cue :hypnotic-beam :beam-green (show/fixtures-named \"hyp-rgb\")\n                                      :color :green :effect-name \"Hypnotic Green\"))\n    (show/set-cue! (+ x-base 2) (+ y-base 2)\n                   (cues/function-cue :hypnotic-beam :beam-blue (show/fixtures-named \"hyp-rgb\")\n                                      :color :blue :effect-name \"Hypnotic Blue\"))\n    (show/set-cue! (+ x-base 3) (+ y-base 2)\n                   (cues/function-cue :hypnotic-beam :beam-red-green (show/fixtures-named \"hyp-rgb\")\n                                      :color :yellow :effect-name \"Hypnotic Red Green\"))\n    (show/set-cue! (+ x-base 4) (+ y-base 2)\n                   (cues/function-cue :hypnotic-beam :beam-red-blue (show/fixtures-named \"hyp-rgb\")\n                                      :color :purple :effect-name \"Hypnotic Red Blue\"))\n    (show/set-cue! (+ x-base 5) (+ y-base 2)\n                   (cues/function-cue :hypnotic-beam :beam-green-blue (show/fixtures-named \"hyp-rgb\")\n                                      :color :cyan :effect-name \"Hypnotic Green Blue\"))\n    (show/set-cue! (+ x-base 6) (+ y-base 2)\n                   (cues/function-cue :hypnotic-beam :beam-red-green-blue (show/fixtures-named \"hyp-rgb\")\n                                      :color :white :effect-name \"Hypnotic Red Green Blue\"))\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/function-cue :hypnotic-beam :beam-all-random (show/fixtures-named \"hyp-rgb\")\n                                      :color :white :effect-name \"Hypnotic Random\"))\n    (show/set-cue! (+ x-base 6) (+ y-base 3)\n                   (cues/function-cue :hypnotic-spin :beams-ccw (show/fixtures-named \"hyp-rgb\")\n                                      :color :cyan :effect-name \"Hypnotic Rotate CCW\" :level 50))\n    (show/set-cue! (+ x-base 7) (+ y-base 3)\n                   (cues/function-cue :hypnotic-spin :beams-cw (show/fixtures-named \"hyp-rgb\")\n                                      :color :cyan :effect-name \"Hypnotic Rotate Clockwise\" :level 50))\n\n    ;; Sound active mode for groups of lights\n    (show/set-cue! (+ x-base 2) (+ y-base 7)\n                   (cues/cue :blade-sound\n                             (fn [var-map]\n                               (fx/scene \"Blade Sound\"\n                                         (chan-fx/function-effect\n                                          \"sound on\" :sound-active (:level var-map) (show/fixtures-named \"blade\"))\n                                         (dimmer-effect (:dimmer var-map) (show/fixtures-named \"blade\"))))\n                             :color :orange\n                             :variables [{:key \"level\" :min 1 :max 100 :type :integer :start 50 :name \"Level\"}\n                                         {:key \"dimmer\" :min 0 :max 255 :type :integer :start 255 :name \"Dimmer\"}]))\n    (show/set-cue! (+ x-base 4) (+ y-base 7)\n                   (cues/cue :hex-sound\n                             (fn [var-map]\n                               (fx/scene \"Hex Sound\"\n                                         (chan-fx/function-effect\n                                          \"sound on\" :sound-active (:level var-map) (show/fixtures-named \"hex\"))\n                                         (dimmer-effect (:dimmer var-map) (show/fixtures-named \"hex\"))))\n                             :color :orange\n                             :variables [{:key \"level\" :min 1 :max 100 :type :integer :start 50 :name \"Level\"}\n                                         {:key \"dimmer\" :min 0 :max 255 :type :integer :start 255 :name \"Dimmer\"}]))\n    (show/set-cue! (+ x-base 5) (+ y-base 7)\n                   (cues/function-cue :puck-sound :sound-active (show/fixtures-named \"puck\")\n                                      :color :orange :effect-name \"Puck Sound\"))\n    (show/set-cue! (+ x-base 6) (+ y-base 7)\n                   (cues/function-cue :snowball-sound :sound-active (show/fixtures-named \"snowball\")\n                                      :color :orange :effect-name \"Snowball Sound\" :end-keys [:snowball-pos]))\n\n    ;; A couple other snowball cues\n    (show/set-cue! (+ x-base 6) (+ y-base 6)\n                   (cues/function-cue :snowball-pos :beams-moving (show/fixtures-named \"snowball\")\n                                      :effect-name \"Snowball Moving\" :color :yellow :end-keys [:snowball-sound]))\n    (show/set-cue! (+ x-base 6) (+ y-base 5)\n                   (cues/function-cue :snowball-pos :beams-fixed (show/fixtures-named \"snowball\")\n                                      :effect-name \"Snowball Fixed\" :end-keys [:snowball-sound]))))\n\n(defn can-can\n  \"A effect that moves the blades like they are in a kick line.\"\n  [& {:keys [bars cycles stagger spread pan-min pan-max tilt-min tilt-max]\n      :or {bars 1 cycles 1 stagger 0 spread 0 pan-min 0 pan-max 0 tilt-min -100 tilt-max 100}}]\n  (let [bars (params/bind-keyword-param bars Number 1)\n        cycles (params/bind-keyword-param cycles Number 1)\n        stagger (params/bind-keyword-param stagger Number 0)\n        spread (params/bind-keyword-param spread Number 0)\n        pan-min (params/bind-keyword-param pan-min Number 0)\n        pan-max (params/bind-keyword-param pan-max Number 0)\n        tilt-min (params/bind-keyword-param tilt-min Number -30)\n        tilt-max (params/bind-keyword-param tilt-max Number 30)\n        pan-ratio (params/build-param-formula Number #(/ (* 4 %1) %2) bars cycles)\n        tilt-ratio (params/build-param-formula Number #(/ %1 %2) bars cycles)\n        fx (for [head [{:key :blade-1 :phase 0.0 :pan-offset 2}\n                       {:key :blade-2 :phase 0.2 :pan-offset 1}\n                       {:key :blade-3 :phase 0.6 :pan-offset -1}\n                       {:key :blade-4 :phase 0.8 :pan-offset -2}\n                       {:key :blade-5 :phase 0.4 :tilt-offset 10}]]\n             (let [head-phase (params/build-param-formula Number #(* % (:phase head 0)) stagger)\n                   tilt-osc (oscillators/sine :interval :bar :interval-ratio tilt-ratio :phase head-phase)\n                   head-tilt-min (params/build-param-formula Number #(+ % (:tilt-offset head 0)) tilt-min)\n                   head-tilt-max (params/build-param-formula Number #(+ % (:tilt-offset head 0)) tilt-max)\n                   tilt-param (oscillators/build-oscillated-param tilt-osc :min head-tilt-min\n                                                                  :max head-tilt-max)\n                   pan-osc (oscillators/sine :interval :bar :interval-ratio pan-ratio :phase head-phase)\n                   head-pan-min (params/build-param-formula Number #(+ %1 (* (:pan-offset head 0) %2))\n                                                            pan-min spread)\n                   head-pan-max (params/build-param-formula Number #(+ %1 (* (:pan-offset head 0) %2))\n                                                            pan-max spread)\n                   pan-param (oscillators/build-oscillated-param pan-osc :min head-pan-min\n                                                                 :max head-pan-max)\n                   direction (params/build-pan-tilt-param :pan pan-param :tilt tilt-param)]\n               (move/pan-tilt-effect \"can can element\" direction (show/fixtures-named (:key head)))))]\n    (apply fx/scene \"Can Can\" fx)))\n\n;; TODO: It looks like this and the can-can chase are just lissajous genrators with different\n;;       values for A and B and delta. So consider pulling that part into a function both can\n;;       use.\n(defn torrent-8\n  \"A effect that moves the torrents in a figure 8.\"\n  [& {:keys [bars cycles stagger spread pan-min pan-max tilt-min tilt-max]\n      :or {bars 1 cycles 1 stagger 0 spread 0 pan-min -45 pan-max 45 tilt-min 0 tilt-max 45}}]\n  (let [bars (params/bind-keyword-param bars Number 1)\n        cycles (params/bind-keyword-param cycles Number 1)\n        stagger (params/bind-keyword-param stagger Number 0)\n        spread (params/bind-keyword-param spread Number 0)\n        pan-min (params/bind-keyword-param pan-min Number -45)\n        pan-max (params/bind-keyword-param pan-max Number 45)\n        tilt-min (params/bind-keyword-param tilt-min Number 0)\n        tilt-max (params/bind-keyword-param tilt-max Number 45)\n        pan-ratio (params/build-param-formula Number #(/ (* 2 %1) %2) bars cycles)\n        tilt-ratio (params/build-param-formula Number #(/ %1 %2) bars cycles)\n        fx (for [head [{:key :torrent-1 :phase 0.0 :pan-offset 1}\n                       {:key :torrent-2 :phase 0.5 :pan-offset -1}]]\n             (let [head-phase (params/build-param-formula Number #(+ 0.25 (* % (:phase head 0))) stagger)\n                   tilt-osc (oscillators/sine :interval :bar :interval-ratio tilt-ratio :phase head-phase)\n                   tilt-param (oscillators/build-oscillated-param tilt-osc :min tilt-min :max tilt-max)\n                   pan-osc (oscillators/sine :interval :bar :interval-ratio pan-ratio :phase head-phase)\n                   head-pan-min (params/build-param-formula Number #(+ (if (zero? (:phase head)) %1 (- %2))\n                                                                       (* (:pan-offset head 0) %3))\n                                                            pan-min pan-max spread)\n                   head-pan-max (params/build-param-formula Number #(+ (if (zero? (:phase head)) %1 (- %2))\n                                                                       (* (:pan-offset head 0) %3))\n                                                            pan-max pan-min spread)\n                   pan-param (oscillators/build-oscillated-param pan-osc\n                                                                 :min head-pan-min\n                                                                 :max head-pan-max)\n                   direction (params/build-pan-tilt-param :pan pan-param :tilt tilt-param)]\n               (move/pan-tilt-effect \"t8 element\" direction (show/fixtures-named (:key head)))))]\n    (apply fx/scene \"Torrent 8\" fx)))\n\n(defn dimmer-sweep\n  \"An effect which uses an oscillator to move a bar of light across a\n  group of fixtures. The width of the bar, maximum dimmer level, and\n  whether the level should fade from the center of the bar to the\n  edge, can be controlled with optional keyword arguments.\"\n  [fixtures osc & {:keys [width level fade] :or {width 0.1 level 255 fade false}}]\n  (let [width (params/bind-keyword-param width Number 0.1)\n        level (params/bind-keyword-param level Number 255)\n        fade (params/bind-keyword-param fade Boolean false)\n        min-x (apply min (map :x fixtures))\n        max-x (apply max (map :x fixtures))\n        position (oscillators/build-oscillated-param osc :min min-x :max max-x)]\n    (apply fx/scene \"Dimmer Sweep\"\n           (for [fixture fixtures]\n             (let [fixture-level (params/build-param-formula\n                                  Number\n                                  (fn [position width level fade]\n                                    (let [range (/ width 2)\n                                          distance (math/abs (- position (:x fixture)))]\n                                      (if (> distance range)\n                                        0\n                                        (if fade\n                                          (* level (/ (- range distance) range))\n                                          level))))\n                                  position width level fade)]\n               (dimmer-effect fixture-level [fixture]))))))\n\n(defn make-movement-cues\n  \"Create a page of with some large scale and layered movement\n  effects. And miscellany which I'm not totally sure what to do with\n  yet.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)]\n\n    ;; Some dimmer sweeps\n    (let [dimmer-sweep-fixtures (concat (show/fixtures-named :torrent) (show/fixtures-named :blade)\n                                        (show/fixtures-named :hex))]\n      (show/set-cue! x-base y-base\n                     (cues/cue :dimmers\n                               (fn [var-map] (cues/apply-merging-var-map\n                                              var-map dimmer-sweep  dimmer-sweep-fixtures\n                                              (oscillators/sawtooth :down? (:down var-map)\n                                                                    :interval-ratio (build-ratio-param var-map))))\n                               :color :red :short-name \"Sawtooth Sweep\"\n                               :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                           {:key \"down\" :type :boolean :start true :name \"Down?\"}\n                                           {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                           {:key \"width\" :min 0 :max 1 :start 0.1 :name \"Width\"}\n                                           {:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}\n                                           {:key \"fade\" :type :boolean :start false :name \"Fade?\"}]))\n\n      (show/set-cue! x-base (inc y-base)\n                     (cues/cue :dimmers\n                               (fn [var-map] (cues/apply-merging-var-map\n                                              var-map dimmer-sweep dimmer-sweep-fixtures\n                                              (oscillators/triangle :interval-ratio (build-ratio-param var-map))))\n                               :color :red :short-name \"Triangle Sweep\"\n                               :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                           {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                           {:key \"width\" :min 0 :max 1 :start 0.25 :name \"Width\"}\n                                           {:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}\n                                           {:key \"fade\" :type :boolean :start false :name \"Fade?\"}])))\n\n    (show/set-cue! (inc x-base) y-base\n                   (cues/cue :blade-dimmers\n                             (fn [var-map] (cues/apply-merging-var-map\n                                            var-map dimmer-sweep  (show/fixtures-named :blade)\n                                            (oscillators/sawtooth :down? (:down var-map)\n                                                                  :interval-ratio (build-ratio-param var-map))))\n                             :color :red :short-name \"Blade Saw Sweep\"\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                         {:key \"down\" :type :boolean :start true :name \"Down?\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"width\" :min 0 :max 1 :start 0.1 :name \"Width\"}\n                                         {:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}\n                                         {:key \"fade\" :type :boolean :start false :name \"Fade?\"}]))\n\n    (show/set-cue! (inc x-base) (inc y-base)\n                   (cues/cue :blade-dimmers\n                             (fn [var-map] (cues/apply-merging-var-map\n                                            var-map dimmer-sweep (show/fixtures-named :blade)\n                                            (oscillators/triangle :interval-ratio (build-ratio-param var-map))))\n                               :color :red :short-name \"Blade Triangle Sweep\"\n                               :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                           {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                           {:key \"width\" :min 0 :max 1 :start 0.25 :name \"Width\"}\n                                           {:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}\n                                           {:key \"fade\" :type :boolean :start false :name \"Fade?\"}]))\n\n    (show/set-cue! (inc x-base) (+ 2 y-base)\n                   (cues/cue :blade-dimmers\n                             (fn [var-map]\n                               (let [step (params/build-step-param :interval-ratio (build-ratio-param var-map)\n                                                                   :fade-fraction (:fade-fraction var-map))]\n                                 (fx/chase \"Blade Cross\"\n                                           (map #(dimmer-effect (:level var-map) (show/fixtures-named %))\n                                                [:blade-1 :blade-3 :blade-2 :blade-4])\n                                           step :beyond :loop)))\n                               :color :red :short-name \"Blade Cross\"\n                               :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 1 :name \"Beats\"}\n                                           {:key \"cycles\" :min 1 :max 10 :type :integer :start 4 :name \"Cycles\"}\n                                           {:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}\n                                           {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}]))\n\n    ;; A fun pressure-sensitive dimmer spread effect\n    (show/set-cue! x-base (+ y-base 2)\n                   (cues/cue :bloom (fn [var-map]\n                                      (cues/apply-merging-var-map\n                                       var-map fun/bloom (show/all-fixtures)\n                                       :measure (tf/build-distance-measure 0 rig-height 0 :ignore-z true)))\n                             :variables [{:key \"color\" :type :color :start (colors/create-color :white)\n                                          :name \"Color\"}\n                                         {:key \"fraction\" :min 0 :max 1 :start 0 :velocity true}]\n                             :held true :priority 1000 :color :purple))\n\n    (show/set-cue! (+ x-base 2) (inc y-base)\n                   (cues/cue :movement (fn [var-map]\n                                         (cues/apply-merging-var-map var-map fun/aim-fan\n                                                                     (concat (show/fixtures-named \"blade\")\n                                                                             (show/fixtures-named \"torrent\"))))\n                             :variables [{:key \"x-scale\" :min -5 :max 5 :start 1 :name \"X Scale\"}\n                                         {:key \"y-scale\" :min -10 :max 10 :start 5 :name \"Y Scale\"}\n                                         {:key \"z\" :min 0 :max 20 :start 4}\n                                       {:key \"y\" :min -10 :max 10 :start rig-height}\n                                       {:key \"x\" :min -10 :max 10 :start 0.0}]\n                           :color :blue :end-keys [:move-blades :move-torrents]))\n\n    (show/set-cue! (+ x-base 2) (+ y-base 2)\n                   (cues/cue :movement (fn [var-map]\n                                         (cues/apply-merging-var-map var-map fun/twirl\n                                                                     (concat (show/fixtures-named \"blade\")\n                                                                             (show/fixtures-named \"torrent\"))))\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 8 :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"radius\" :min 0 :max 10 :start 0.25 :name \"Radius\"}\n                                         {:key \"z\" :min -10 :max 10 :start -1.0}\n                                         {:key \"y\" :min -10 :max 10 :start rig-height}\n                                         {:key \"x\" :min -10 :max 10 :start 0.0}]\n                             :color :green :end-keys [:move-blades :move-torrents]))\n\n    (show/set-cue! (inc x-base) (+ y-base 3)\n                   (cues/cue :move-torrents\n                             (fn [var-map] (cues/apply-merging-var-map var-map torrent-8))\n                             :variables [{:key \"bars\" :name \"Bars\" :min 1 :max 8 :type :integer :start 2}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 8 :type :integer :start 1}\n                                         {:key \"stagger\" :name \"Stagger\" :min 0 :max 4 :start 0}\n                                         {:key \"spread\" :name \"Spread\" :min -45 :max 45\n                                          :centered true :resolution 0.25 :start 0}\n                                         {:key \"pan-min\" :name \"Pan min\" :min -180 :max 180\n                                          :centered true :resolution 0.5 :start -75}\n                                         {:key \"pan-max\" :name \"Pan max\" :min -180 :max 180\n                                          :centered true :resolution 0.5 :start 90}\n                                         {:key \"tilt-min\" :name \"Tilt min\" :min -180 :max 180\n                                          :centered true :resolution 0.5 :start -10}\n                                         {:key \"tilt-max\" :name \"Tilt max\" :min -180 :max 180\n                                          :centered true :resolution 0.5 :start 75}]\n                             :color :yellow :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 3) (+ y-base 3)\n                   (cues/cue :move-blades\n                             (fn [var-map] (cues/apply-merging-var-map var-map can-can))\n                             :variables [{:key \"bars\" :name \"Bars\" :min 1 :max 8 :type :integer :start 1}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 8 :type :integer :start 1}\n                                         {:key \"stagger\" :name \"Stagger\" :min 0 :max 4 :start 0.5}\n                                         {:key \"spread\" :name \"Spread\" :min -45 :max 45\n                                          :centered true :resolution 0.25 :start 0}\n                                         {:key \"pan-min\" :name \"Pan min\" :min -180 :max 180\n                                          :centered true :resolution 0.5 :start 0}\n                                         {:key \"pan-max\" :name \"Pan max\" :min -180 :max 180\n                                          :centered true :resolution 0.5 :start 0}\n                                         {:key \"tilt-min\" :name \"Tilt min\" :min -180 :max 180\n                                          :centered true :resolution 0.5 :start -60}\n                                         {:key \"tilt-max\" :name \"Tilt max\" :min -180 :max 180\n                                          :centered true :resolution 0.5 :start 100}]\n                             :color :yellow :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 3) (+ y-base 4)\n                   (cues/cue :blade-circles\n                             (fn [var-map] (cues/apply-merging-var-map var-map circle-chain\n                                                                       (show/fixtures-named :blade) true))\n                             :variables [{:key \"bars\" :name \"Bars\" :min 1 :max 8 :type :integer :start 2}\n                                         {:key \"radius\" :name \"Radius\" :min 0.1 :max 2\n                                          :resolution 0.1 :start 1.0}\n                                         {:key \"stagger\" :name \"Stagger\" :min 0 :max 2 :start 0\n                                          :resolution 0.1}]\n                             :short-name \"Blade Circles\" :color :green :priority 4))\n\n    (show/set-cue! (inc x-base) (+ y-base 4)\n                   (cues/cue :torrent-circles\n                             (fn [var-map] (cues/apply-merging-var-map var-map circle-chain\n                                                                       (show/fixtures-named :torrent) false))\n                             :variables [{:key \"bars\" :name \"Bars\" :min 1 :max 8 :type :integer :start 2}\n                                         {:key \"radius\" :name \"Radius\" :min 0.1 :max 2\n                                          :resolution 0.1 :start 1.0}\n                                         {:key \"stagger\" :name \"Stagger\" :min 0 :max 2 :start 0\n                                          :resolution 0.1}]\n                             :short-name \"Torrent Circles\" :color :green :priority 4))\n\n    ;; A chase which overlays on other movement cues, gradually taking over the lights\n    (show/set-cue! (+ x-base 2) (+ y-base 5)\n                   (cues/cue :crossover (fn [var-map] (cues/apply-merging-var-map var-map crossover-chase))\n                             :variables [{:key \"beats\" :min 1 :max 8 :start 2 :type :integer :name \"Beats\"}\n                                         {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}\n                                         {:key \"cross-color\" :type :color :start (colors/create-color :red)\n                                          :name \"X Color\"}\n                                         {:key \"end-color\" :type :color :start (colors/create-color :yellow)\n                                          :name \"End Color\"}]\n                             :color :cyan :priority 5))\n\n    ;; Some color cycle chases\n    (show/set-cue! x-base (+ y-base 7)\n                   (cues/cue :all-color (fn [_] (fun/iris-out-color-cycle-chase (show/all-fixtures)))))\n    (show/set-cue! (inc x-base) (+ y-base 7)\n                   (cues/cue :all-color\n                             (fn [_] (fun/wipe-right-color-cycle-chase\n                                      (show/all-fixtures)\n                                      :transition-phase-function rhythm/snapshot-bar-phase))))\n    (show/set-cue! (+ x-base 2) (+ y-base 7)\n                   (cues/cue :all-color (fn [_] (fun/wipe-right-color-cycle-chase\n                                                 (show/all-fixtures)\n                                                 :color-index-function rhythm/snapshot-beat-within-phrase\n                                                 :transition-phase-function rhythm/snapshot-beat-phase\n                                                 :effect-name \"Wipe Right Beat\"))))\n\n    (show/set-cue! x-base (+ y-base 6)\n                   (cues/cue :confetti\n                             (fn [var-map]\n                               (let [beats (params/bind-keyword-param (:beats var-map) Number 2)\n                                     cycles (params/bind-keyword-param (:cycles var-map ) Number 1)\n                                     step-ratio (params/build-param-formula Number #(/ %1 %2) beats cycles)\n                                     step (params/build-step-param :interval-ratio step-ratio)]\n                                 (cues/apply-merging-var-map var-map\n                                                             fun/confetti (show/all-fixtures)\n                                                             :step step)))\n                             :variables [{:key \"beats\" :min 1 :max 8 :start 2 :type :integer :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 8 :start 1 :type :integer :name \"Cycles\"}\n                                         {:key \"min-added\" :min 0 :max 20 :start 1 :type :integer :name \"Min Add\"}\n                                         {:key \"max-added\" :min 1 :max 20 :start 4 :type :integer :name \"Max Add\"}\n                                         {:key \"min-duration\" :min 1 :max 16 :start 1 :type :integer :name \"Min Last\"}\n                                         {:key \"max-duration\" :min 1 :max 16 :start 4 :type :integer :name \"Max Last\"}\n                                         {:key \"min-saturation\" :min 0 :max 100 :start 100 :name \"Min Sat\"}]\n                             :color :orange :priority 5))\n    (show/set-cue! (inc x-base) (+ y-base 6)\n                   (cues/cue :confetti\n                             (fn [var-map]\n                               (let [beats (params/bind-keyword-param (:beats var-map) Number 2)\n                                     cycles (params/bind-keyword-param (:cycles var-map ) Number 1)\n                                     step-ratio (params/build-param-formula Number #(/ %1 %2) beats cycles)\n                                     step (params/build-step-param :interval-ratio step-ratio)]\n                                 (cues/apply-merging-var-map var-map\n                                                             fun/confetti (show/all-fixtures)\n                                                             :step step :aim? true)))\n                             :variables [{:key \"beats\" :min 1 :max 8 :start 2 :type :integer :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 8 :start 1 :type :integer :name \"Cycles\"}\n                                         {:key \"min-added\" :min 0 :max 20 :start 1 :type :integer :name \"Min Add\"}\n                                         {:key \"max-added\" :min 1 :max 20 :start 4 :type :integer :name \"Max Add\"}\n                                         {:key \"min-duration\" :min 1 :max 16 :start 1 :type :integer :name \"Min Last\"}\n                                         {:key \"max-duration\" :min 1 :max 16 :start 4 :type :integer :name \"Max Last\"}\n                                         {:key \"min-saturation\" :min 0 :max 100 :start 100 :name \"Min Sat\"}]\n                             :color :orange :priority 5 :short-name \"Confetti Dance\"))\n\n    (show/set-cue! (+ x-base 5) y-base\n                   (cues/cue :pinstripes\n                             (fn [var-map]\n                               (let [step-ratio (build-ratio-param var-map)\n                                     step (params/build-step-param :interval-ratio step-ratio\n                                                                   :fade-fraction (:fade-fraction var-map))\n                                     colors [(:color-1 var-map) (:color-2 var-map)]]\n                                 (fun/pinstripes (set/difference\n                                                  (set (show/all-fixtures))\n                                                  (set (show/fixtures-named :snowball)))\n                                                 :step step :colors colors)))\n                             :variables [{:key \"beats\" :name \"Beats\" :min 1 :max 32 :type :integer :start 1}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 16 :type :integer :start 1}\n                                         {:key \"color-1\" :type :color :start (colors/create-color :red)\n                                          :name \"Color 1\"}\n                                         {:key \"color-2\" :type :color :start (colors/create-color :white)\n                                          :name \"Color 2\"}\n                                         {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}]\n                             :color :yellow))\n\n    (show/set-cue! (+ x-base 5) (inc y-base)\n                   (cues/cue :pinstripes\n                             (fn [var-map]\n                               (let [step-ratio (build-ratio-param var-map)\n                                     step (params/build-step-param :interval-ratio step-ratio\n                                                                   :fade-fraction (:fade-fraction var-map))\n                                     colors [(:color-1 var-map) (:color-2 var-map) (:color-3 var-map)]]\n                                 (fun/pinstripes (clojure.set/difference\n                                                  (set (show/all-fixtures))\n                                                  (set (show/fixtures-named :snowball)))\n                                                 :step step :colors colors)))\n                             :variables [{:key \"beats\" :name \"Beats\" :min 1 :max 32 :type :integer :start 1}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 16 :type :integer :start 1}\n                                         {:key \"color-1\" :type :color :start (colors/create-color :red)\n                                          :name \"Color 1\"}\n                                         {:key \"color-2\" :type :color :start (colors/create-color :white)\n                                          :name \"Color 2\"}\n                                         {:key \"color-3\" :type :color :start (colors/create-color :blue)\n                                          :name \"Color 3\"}\n                                         {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}]\n                             :color :orange :short-name \"Pin 3\"))\n\n    (show/set-cue! (+ x-base 5) (+ 2 y-base)\n                   (cues/cue :pinstripes\n                             (fn [var-map]\n                               (let [step-ratio (build-ratio-param var-map)\n                                     step (params/build-step-param :interval-ratio step-ratio\n                                                                   :fade-fraction (:fade-fraction var-map))\n                                     colors [(:color-1 var-map) (:color-2 var-map)\n                                             (:color-3 var-map) (:color-4 var-map)]]\n                                 (fun/pinstripes (clojure.set/difference\n                                                  (set (show/all-fixtures))\n                                                  (set (show/fixtures-named :snowball)))\n                                                 :step step :colors colors)))\n                             :variables [{:key \"beats\" :name \"Beats\" :min 1 :max 32 :type :integer :start 1}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 16 :type :integer :start 1}\n                                         {:key \"color-1\" :type :color :start (colors/create-color :yellow)\n                                          :name \"Color 1\"}\n                                         {:key \"color-2\" :type :color :start (colors/create-color :purple)\n                                          :name \"Color 2\"}\n                                         {:key \"color-3\" :type :color :start (colors/create-color :white)\n                                          :name \"Color 3\"}\n                                         {:key \"color-4\" :type :color :start (colors/create-color :cyan)\n                                          :name \"Color 4\"}\n                                         {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}]\n                             :color :orange :short-name \"Pin 4\"))\n\n    ;; Some macro-based chases\n    (show/set-cue! (+ x-base 7) (inc y-base)\n                   (cues/cue :move-torrents\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Torrent Nod\" *show*\n                                      [[17 15 {:pan-min 90.0 :pan-max 179.0 :pan-bars 2 :pan-phase 0.0\n                                               :tilt-min 148.0 :tilt-max 255.0 :tilt-bars 1, :tilt-phase 0.0}]\n                                       [16 15 {:pan-min 77.0 :pan-max 164.0 :pan-bars 2 :pan-phase 0.0\n                                               :tilt-min 148.0 :tilt-max 255.0, :tilt-bars 1, :tilt-phase 0.0}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/cue :move-torrents\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Torrent Cross Nod\" *show*\n                                      [[16 15 {:pan-min 77.0, :pan-max 164.0, :pan-bars 2, :pan-phase 0.5,\n                                               :tilt-min 148.0, :tilt-max 255.0, :tilt-bars 1, :tilt-phase 0.25}]\n                                       [17 15 {:pan-min 90.0, :pan-max 179.0, :pan-bars 2, :pan-phase 0.0,\n                                               :tilt-min 148.0, :tilt-max 255.0, :tilt-bars 1, :tilt-phase 0.0}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 6) (inc y-base)\n                   (cues/cue :move-blades\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Sync Can Can\" *show*\n                                      [[22 15 {:pan-min 39.0, :pan-max 39.0, :pan-bars 1, :pan-phase 0.0,\n                                               :tilt-min 73.0, :tilt-max 248.0, :tilt-bars 1, :tilt-phase 0.0}]\n                                       [21 15 {:pan-min 42.0, :pan-max 42.0, :pan-bars 1, :pan-phase 0.0,\n                                               :tilt-min 0.0, :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.0}]\n                                       [20 15 {:pan-min 42.0, :pan-max 42.0, :pan-bars 1, :pan-phase 0.0,\n                                               :tilt-min 0.0, :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.0}]\n                                       [19 15 {:pan-min 42.0, :pan-max 42.0, :pan-bars 1, :pan-phase 0.0,\n                                               :tilt-min 0.0, :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.0}]\n                                       [18 15 {:pan-min 42.0, :pan-max 42.0, :pan-bars 1, :pan-phase 0.0,\n                                               :tilt-min 0.0, :tilt-max 216.0, :tilt-bars 1, :tilt-phase 0.0}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 6) (+ y-base 2)\n                   (cues/cue :move-blades\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Spread Can Can\" *show*\n                                      [[18 15 {:pan-min 42.0, :pan-max 42.0, :pan-bars 1, :pan-phase 0.0,\n                                               :tilt-min 0.0, :tilt-max 216.0, :tilt-bars 1, :tilt-phase 0.0}]\n                                       [19 15 {:pan-min 42.0, :pan-max 42.0, :pan-bars 1, :pan-phase 0.0,\n                                               :tilt-min 0.0, :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.2}]\n                                       [20 15 {:pan-min 42.0, :pan-max 42.0, :pan-bars 1, :pan-phase 0.0,\n                                               :tilt-min 0.0, :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.4}]\n                                       [21 15 {:pan-min 42.0, :pan-max 42.0, :pan-bars 1, :pan-phase 0.0,\n                                               :tilt-min 0.0, :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.6}]\n                                       [22 15 {:pan-min 39.0, :pan-max 39.0, :pan-bars 1, :pan-phase 0.0,\n                                               :tilt-min 73.0, :tilt-max 248.0, :tilt-bars 1, :tilt-phase 0.8}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 6) (+ y-base 3)\n                   (cues/cue :move-blades\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Swing Can Can\" *show*\n                                      [[22 15 {:pan-min 24.0, :pan-max 64.0, :pan-bars 4, :pan-phase 0.0,\n                                               :tilt-min 73.0, :tilt-max 248.0, :tilt-bars 1, :tilt-phase 0.8}]\n                                       [21 15 {:pan-min 24.0, :pan-max 64.0, :pan-bars 4, :pan-phase 0.0,\n                                               :tilt-min 0.0, :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.6}]\n                                       [20 15 {:pan-min 23.0, :pan-max 64.0, :pan-bars 4, :pan-phase 0.0,\n                                               :tilt-min 0.0, :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.4}]\n                                       [19 15 {:pan-min 23.0, :pan-max 64.0, :pan-bars 4, :pan-phase 0.0,\n                                               :tilt-min 0.0, :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.2}]\n                                       [18 15 {:pan-min 23.0, :pan-max 64.0, :pan-bars 4, :pan-phase 0.0,\n                                               :tilt-min 0.0, :tilt-max 216.0, :tilt-bars 1, :tilt-phase 0.0}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 6) (+ y-base 7)\n                   (cues/cue :center-rebel\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Center Rebel\" *show*\n                                      [[22 15 {:pan-min 12.0, :pan-max 64.0, :pan-bars 4, :pan-phase 0.0,\n                                               :tilt-min 56.0, :tilt-max 182.0, :tilt-bars 1, :tilt-phase 0.8}]]))))\n\n    (show/set-cue! (+ x-base 6) (+ y-base 6)\n                   (cues/cue :move-blades\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Slow Ceiling LR\" *show*\n                                      [[18 15 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.0,\n                                               :tilt-min 170.0, :tilt-max 170.0, :tilt-bars 1, :tilt-phase 0.0}]\n                                       [19 15 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.0,\n                                               :tilt-min 170.0, :tilt-max 170.0, :tilt-bars 1, :tilt-phase 0.2}]\n                                       [20 15 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.0,\n                                               :tilt-min 170.0, :tilt-max 170.0, :tilt-bars 1, :tilt-phase 0.4}]\n                                       [21 15 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.0,\n                                               :tilt-min 170.0, :tilt-max 170.0, :tilt-bars 1, :tilt-phase 0.6}]\n                                       [22 15 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.0,\n                                               :tilt-min 230.0, :tilt-max 230.0, :tilt-bars 1, :tilt-phase 0.8}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 6) (+ y-base 5)\n                   (cues/cue :move-blades\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Slow Scan LR\" *show*\n                                      [[22 15 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.0,\n                                               :tilt-min 182.0, :tilt-max 182.0, :tilt-bars 1, :tilt-phase 0.8}]\n                                       [21 15 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.4,\n                                               :tilt-min 130.0, :tilt-max 130.0, :tilt-bars 1, :tilt-phase 0.6}]\n                                       [20 15 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.8,\n                                               :tilt-min 130.0, :tilt-max 130.0, :tilt-bars 1, :tilt-phase 0.4}]\n                                       [19 15 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.2,\n                                               :tilt-min 130.0, :tilt-max 130.0, :tilt-bars 1, :tilt-phase 0.2}]\n                                       [18 15 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.6,\n                                               :tilt-min 162.0, :tilt-max 162.0, :tilt-bars 1, :tilt-phase 0.0}]]))\n                             :end-keys [:movement]))))\n\n(defn- aim-cue-var-key\n  \"Determine the cue variable key value to use for a variable being\n  created for an aim cue page cue. `base-name` is the name that will\n  be used for the variable if it is not part of a group of cues\n  sharing variables; if `shared-prefix` is not blank then the variable\n  key will refer to a show variable with that prefix identifying which\n  group it belongs to.\"\n  [base-name shared-prefix]\n  (if (clojure.string/blank? shared-prefix)\n    (name base-name)\n    (keyword (str \"aim-group-\" shared-prefix \"-\" (name base-name)))))\n\n(defn- build-aim-cue\n  \"Build an aim cue for the mutiplexable fixture aiming page.\"\n  [fixture-key shared-prefix transform? color]\n  (let [isolated? (clojure.string/blank? shared-prefix)]\n    (cues/cue (keyword (str \"aim-\" (name fixture-key)))\n              (fn [var-map]\n                (let [base-aim (if isolated?\n                                 (cues/apply-merging-var-map var-map params/build-aim-param)\n                                 (params/build-aim-param :x (aim-cue-var-key \"x\" shared-prefix)\n                                                         :y (aim-cue-var-key \"y\" shared-prefix)\n                                                         :z (aim-cue-var-key \"z\" shared-prefix)))\n                      aim-param (if transform?\n                                  (params/build-aim-transformer base-aim\n                                                                (keyword (str \"aim-group-\" shared-prefix \"-transform\")))\n                                  base-aim)]\n                  (move/aim-effect (str \"Aim \" (name fixture-key)\n                                        (when-not isolated?\n                                          (str \" (Group \" (clojure.string/upper-case shared-prefix)\n                                               (when transform? \" flip\") \")\")))\n                                   aim-param (show/fixtures-named fixture-key))))\n              :variables [(merge {:key (aim-cue-var-key \"x\" shared-prefix) :name \"X\" :min -20.0 :max 20.0\n                                  :centered true :resolution 0.05}\n                                 (when isolated? {:start 0.0}))\n                          (merge {:key (aim-cue-var-key \"y\" shared-prefix) :name \"Y\" :min -20.0 :max 20.0\n                                  :centered true :resolution 0.05}\n                                 (when isolated? {:start 0.0}))\n                          (merge {:key (aim-cue-var-key \"z\" shared-prefix) :name \"Z\" :min -20.0 :max 20.0\n                                  :centered true :resolution 0.05}\n                                 (when isolated? {:start 2.0}))]\n              :color color :priority 1)))\n\n(defn make-main-aim-cues\n  \"Create a page of cues for aiming lights in particular points,\n  individually and in groups. If `add-osc?` is true, make them\n  controllable over Open Sound Control.\"\n  [page-x page-y var-binder add-osc?]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)\n        fixtures [:torrent-1 :torrent-2 :blade-1 :blade-2 :blade-3 :blade-4]\n        transform (Transform3D.)\n        width (- right-wall left-wall)\n        depth (- house-rear-wall stage-wall)]\n\n    ;; Set up default shared aiming coordinates\n    (show/set-variable! :aim-group-a-x 0.0)\n    (show/set-variable! :aim-group-a-y 0.0)\n    (show/set-variable! :aim-group-a-z 2.0)\n    (show/set-variable! :aim-group-b-x 0.0)\n    (show/set-variable! :aim-group-b-y 0.0)\n    (show/set-variable! :aim-group-b-z 2.0)\n\n    (when add-osc?\n      ;; Set up OSC bindings so Touch OSC can control these cues in a powerful way with XY pads.\n      (add-osc-var-binding :aim-group-a-x \"/1/aim-a\"\n                           :send-fn (fn [_ v]\n                                      (osc/osc-send @osc-client \"/1/aim-a\"\n                                                    (/ (- v left-wall) width)\n                                                    (/ (- (show/get-variable :aim-group-a-z) stage-wall) depth)))\n                           :receive-fn (fn [msg]\n                                         (show/set-variable! :aim-group-a-x\n                                                             (+ left-wall (* width (first (:args msg)))))\n                                         (show/set-variable! :aim-group-a-z\n                                                             (+ stage-wall (* depth (second (:args msg)))))))\n      (add-osc-var-binding :aim-group-a-z \"/1/aim-a\"\n                           :send-fn (fn [_ v]\n                                      (osc/osc-send @osc-client \"/1/aim-a\"\n                                                    (/ (- (show/get-variable :aim-group-a-x) left-wall) width)\n                                                    (/ (- v stage-wall) depth)))\n                           :receive-fn :none)\n\n      (add-osc-var-binding :aim-group-a-y \"/1/aim-a-y\"\n                           :send-fn (fn [_ v]\n                                      (osc/osc-send @osc-client \"/1/aim-a-y\" (/ v ceiling)))\n                           :receive-fn (fn [msg]\n                                         (show/set-variable! :aim-group-a-y (* ceiling (first (:args msg))))))\n\n      (add-osc-var-binding :aim-group-b-x \"/1/aim-b\"\n                           :send-fn (fn [_ v]\n                                      (osc/osc-send @osc-client \"/1/aim-b\"\n                                                    (/ (- v left-wall) width)\n                                                    (/ (- (show/get-variable :aim-group-b-z) stage-wall) depth)))\n                           :receive-fn (fn [msg]\n                                         (show/set-variable! :aim-group-b-x\n                                                             (+ left-wall (* width (first (:args msg)))))\n                                         (show/set-variable! :aim-group-b-z\n                                                             (+ stage-wall (* depth (second (:args msg)))))))\n      (add-osc-var-binding :aim-group-b-z \"/1/aim-b\"\n                           :send-fn (fn [_ v]\n                                      (osc/osc-send @osc-client \"/1/aim-b\"\n                                                    (/ (- (show/get-variable :aim-group-b-x) left-wall) width)\n                                                    (/ (- v stage-wall) depth)))\n                           :receive-fn :none)\n\n      (add-osc-var-binding :aim-group-b-y \"/1/aim-b-y\"\n                           :send-fn (fn [_ v]\n                                      (osc/osc-send @osc-client \"/1/aim-b-y\" (/ v ceiling)))\n                           :receive-fn (fn [msg]\n                                         (show/set-variable! :aim-group-b-y (* ceiling (first (:args msg)))))))\n\n    ;; Set up default transformation of a reflection over the Y axis\n    (.setScale transform (Vector3d. -1.0 1.0 1.0))\n    (show/set-variable! :aim-group-a-transform transform)\n    (show/set-variable! :aim-group-b-transform transform)\n\n    (loop [fixtures fixtures\n           index 0]\n      (when (seq fixtures)\n        (let [fixture (first fixtures)]\n          ;; Disconnected individual aim cues\n          (show/set-cue! (+ x-base index) y-base (build-aim-cue fixture nil false :white))\n\n          ;; Group A untransformed aim cues\n          (show/set-cue! (+ x-base index) (inc y-base) (build-aim-cue fixture \"a\" false :red))\n          (when add-osc?\n            (add-osc-cue-binding (+ x-base index) (inc y-base) (str \"/1/aim-\" (name fixture) \"-a\")))\n\n          ;; Group A transformed aim cues\n          (show/set-cue! (+ x-base index) (+ y-base 2) (build-aim-cue fixture \"a\" true :orange))\n          (when add-osc?\n            (add-osc-cue-binding (+ x-base index) (+ y-base 2) (str \"/1/flip-\" (name fixture) \"-a\")))\n\n          ;; Group B untransformed aim cues\n          (show/set-cue! (+ x-base index) (+ y-base 3) (build-aim-cue fixture \"b\" false :blue))\n          (when add-osc?\n            (add-osc-cue-binding (+ x-base index) (+ y-base 3) (str \"/1/aim-\" (name fixture) \"-b\")))\n\n          ;; Group B transformed aim cues\n          (show/set-cue! (+ x-base index) (+ y-base 4) (build-aim-cue fixture \"b\" true :cyan))\n          (when add-osc?\n            (add-osc-cue-binding (+ x-base index) (+ y-base 4) (str \"/1/flip-\" (name fixture) \"-b\"))))\n        (recur (rest fixtures) (inc index))))\n\n    ;; Transformation modifiers for group A\n    (show/set-cue! (+ x-base 7) (inc y-base)\n                   (cues/cue :aim-group-a-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. 1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :aim-group-a-transform transform)))\n                             :color :cyan :short-name \"Group A flip Y\"))\n    (when add-osc?\n      (add-osc-cue-binding (+ x-base 7) (inc y-base) \"/1/flip-a-y\"))\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/cue :aim-group-a-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. -1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :aim-group-a-transform transform)))\n                             :color :cyan :short-name \"Group A flip XY\"))\n    (when add-osc?\n      (add-osc-cue-binding (+ x-base 7) (+ y-base 2) \"/1/flip-a-xy\"))\n\n    ;; Transformation modifiers for group B\n    (show/set-cue! (+ x-base 7) (+ y-base 3)\n                   (cues/cue :aim-group-b-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. 1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :aim-group-b-transform transform)))\n                             :color :orange :short-name \"Group B flip Y\"))\n    (when add-osc?\n      (add-osc-cue-binding (+ x-base 7) (+ y-base 3) \"/1/flip-b-y\"))\n    (show/set-cue! (+ x-base 7) (+ y-base 4)\n                   (cues/cue :aim-group-b-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. -1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :aim-group-b-transform transform)))\n                             :color :orange :short-name \"Group B flip XY\"))\n    (when add-osc?\n      (add-osc-cue-binding (+ x-base 7) (+ y-base 4) \"/1/flip-b-xy\"))))\n\n(defn- direction-cue-var-key\n  \"Determine the cue variable key value to use for a variable being\n  created for an direction cue page cue. `base-name` is the name that\n  will be used for the variable if it is not part of a group of cues\n  sharing variables; if `shared-prefix` is not blank then the variable\n  key will refer to a show variable with that prefix identifying which\n  group it belongs to.\"\n  [base-name shared-prefix]\n  (if (clojure.string/blank? shared-prefix)\n    (name base-name)\n    (keyword (str \"direction-group-\" shared-prefix \"-\" (name base-name)))))\n\n(defn- build-direction-cue\n  \"Build a direction cue for the mutiplexable fixture direction page.\"\n  [fixture-key shared-prefix transform? color]\n  (let [isolated? (clojure.string/blank? shared-prefix)]\n    (cues/cue (keyword (str \"dir-\" (name fixture-key)))\n              (fn [var-map]\n                (let [base-direction (if isolated?\n                                       (cues/apply-merging-var-map var-map params/build-direction-param-from-pan-tilt)\n                                       (params/build-direction-param-from-pan-tilt\n                                        :pan (direction-cue-var-key \"pan\" shared-prefix)\n                                        :tilt (direction-cue-var-key \"tilt\" shared-prefix)))\n                      direction-param (if transform?\n                                        (params/build-direction-transformer\n                                         base-direction (keyword (str \"direction-group-\" shared-prefix \"-transform\")))\n                                        base-direction)]\n                  (move/direction-effect (str \"P/T \" (name fixture-key)\n                                              (when-not isolated?\n                                                (str \" (Group \" (clojure.string/upper-case shared-prefix)\n                                                     (when transform? \" flip\") \")\")))\n                                         direction-param (show/fixtures-named fixture-key))))\n              :variables [(merge {:key (direction-cue-var-key \"pan\" shared-prefix) :name \"Pan\" :min -180.0 :max 180.0\n                                  :centered true :resolution 0.5}\n                                 (when isolated? {:start 0.0}))\n                          (merge {:key (direction-cue-var-key \"tilt\" shared-prefix) :name \"Tilt\" :min -180.0 :max 180.0\n                                  :centered true :resolution 0.5}\n                                 (when isolated? {:start 0.0}))]\n              :color color :priority 1)))\n\n(defn- build-pan-tilt-osc-cue\n  \"Build a raw pan/tilt oscillator cue.\"\n  [fixture-key]\n  (cues/cue (keyword (str \"p-t-\" (name fixture-key)))\n            (fn [var-map]\n              (let [pan-osc (oscillators/sine :interval :bar :interval-ratio (:pan-bars var-map)\n                                              :phase (:pan-phase var-map))\n                    pan-param (oscillators/build-oscillated-param pan-osc :min (:pan-min var-map)\n                                                                  :max (:pan-max var-map))\n                    tilt-osc (oscillators/sine :interval :bar :interval-ratio (:tilt-bars var-map)\n                                               :phase (:tilt-phase var-map))\n                    tilt-param (oscillators/build-oscillated-param tilt-osc :min (:tilt-min var-map)\n                                                                   :max (:tilt-max var-map))]\n                (fx/scene (str \"P/T \" (name fixture-key))\n                          (chan-fx/channel-effect\n                           \"pan\" pan-param\n                           (chan/extract-channels (chan/expand-heads\n                                                   (show/fixtures-named fixture-key))\n                                                  #(= (:type %) :pan)))\n                          (chan-fx/channel-effect\n                           \"tilt\" tilt-param\n                           (chan/extract-channels (chan/expand-heads (show/fixtures-named fixture-key))\n                                                  #(= (:type %) :tilt))))))\n            :variables [{:key \"pan-min\" :name \"Pan min\" :min 0 :max 255\n                         :centered true :resolution 0.5 :start 0}\n                        {:key \"pan-max\" :name \"Pan max\" :min 0 :max 255\n                         :centered true :resolution 0.5 :start 255}\n                        {:key \"pan-bars\" :name \"Pan bars\" :min 1 :max 16\n                         :type :integer :start 1}\n                        {:key \"pan-phase\" :name \"Pan phase\" :min 0.0 :max 1.0 :start 0.0}\n                        {:key \"tilt-min\" :name \"Tilt min\" :min 0 :max 255\n                         :centered true :resolution 0.5 :start 0}\n                        {:key \"tilt-max\" :name \"Tilt max\" :min 0 :max 255\n                         :centered true :resolution 0.5 :start 255}\n                        {:key \"tilt-bars\" :name \"Tilt bars\" :min 1 :max 16\n                         :type :integer :start 1}\n                        {:key \"tilt-phase\" :name \"Tilt phase\" :min 0.0 :max 1.0 :start 0.0}]\n            :color :green :priority 1))\n\n(defn make-main-direction-cues\n  \"Create a page of cues for aiming lights in particular directions,\n  individually and in groups.\"\n  [page-x page-y var-binder]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)\n        fixtures [:torrent-1 :torrent-2 :blade-1 :blade-2 :blade-3 :blade-4]\n        transform (Transform3D.)]\n\n    ;; Set up default shared direction coordinates\n    (show/set-variable! :direction-group-a-pan 0.0)\n    (show/set-variable! :direction-group-a-tilt 0.0)\n    (show/set-variable! :direction-group-b-pan 0.0)\n    (show/set-variable! :direction-group-b-tilt 0.0)\n\n    ;; Set up default transformation of a reflection over the Y axis\n    (.setScale transform (Vector3d. -1.0 1.0 1.0))\n    (show/set-variable! :direction-group-a-transform transform)\n    (show/set-variable! :direction-group-b-transform transform)\n\n    (loop [fixtures fixtures\n           index 0]\n      (when (seq fixtures)\n        (let [fixture (first fixtures)]\n          ;; Disconnected individual direction cues\n          (show/set-cue! (+ x-base index) y-base (build-direction-cue fixture nil false :white))\n\n          ;; Group A untransformed direction cues\n          (show/set-cue! (+ x-base index) (inc y-base) (build-direction-cue fixture \"a\" false :blue))\n          ;; Group A transformed direction cues\n          (show/set-cue! (+ x-base index) (+ y-base 2) (build-direction-cue fixture \"a\" true :cyan))\n\n          ;; Group B untransformed direction cues\n          (show/set-cue! (+ x-base index) (+ y-base 3) (build-direction-cue fixture \"b\" false :red))\n          ;; Group B transformed direction cues\n          (show/set-cue! (+ x-base index) (+ y-base 4) (build-direction-cue fixture \"b\" true :orange))\n\n          ;; Raw pan/tilt oscillated cues\n          (show/set-cue! (+ x-base index) (+ y-base 7) (build-pan-tilt-osc-cue fixture)))\n        (recur (rest fixtures) (inc index))))\n\n    ;; Transformation modifiers for group A\n    (show/set-cue! (+ x-base 7) (inc y-base)\n                   (cues/cue :direction-group-a-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. 1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :direction-group-a-transform transform)))\n                             :color :cyan :short-name \"Group B flip Y\"))\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/cue :direction-group-a-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. -1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :direction-group-a-transform transform)))\n                             :color :cyan :short-name \"Group B flip XY\"))\n\n    ;; Transformation modifiers for group B\n    (show/set-cue! (+ x-base 7) (+ y-base 3)\n                   (cues/cue :direction-group-b-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. 1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :direction-group-b-transform transform)))\n                             :color :orange :short-name \"Group B flip Y\"))\n    (show/set-cue! (+ x-base 7) (+ y-base 4)\n                   (cues/cue :direction-group-b-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. -1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :direction-group-b-transform transform)))\n                             :color :orange :short-name \"Group B flip XY\"))))\n\n(defn make-cues\n  \"Create a bunch of example cues for experimentation. If Beyond laser\n  show integration is desired, `add-beyond?` will be `true`. If Open\n  Sound Control integration is desired, `add-osc?` will be `true`.\"\n  [var-binder add-beyond? add-osc?]\n  (when add-osc?\n    ;; Create an OSC client that so cues can send their state to TouchOSC.\n    (when (nil? @osc-client)\n      (reset! osc-client (osc/osc-client ipad-address 9000)))\n\n    ;; Clean up any OSC cue bindings which previously existed.\n    (clear-osc-cue-bindings))\n\n  ;; Fill in some cue pages\n  (make-main-color-dimmer-cues 0 0 add-beyond? add-osc?)  ; Creates a sigle 8x8 page at the origin\n  (make-torrent-cues 0 2)  ; Creates 2 8x8 pages: two pages up from the origin, and the next page to the right\n  (make-ambient-cues 1 0)  ; Creates a single 8x8 page to the right of the origin\n  (make-movement-cues 0 1)  ; Creates an 8x8 page above the origin\n  (make-main-aim-cues 1 1 var-binder add-osc?)  ; Creates an 8x8 page above the ambient cues\n  (make-main-direction-cues 2 1 var-binder)  ; Creates an 8x8 page to the right of that\n\n  ;; Not sure what to do with the rest of this yet! Move or discard...\n  ;; For now they are hardcoded to appear on the page above the origin.\n\n  ;; Some basic moving head chases\n  #_(let [triangle-phrase (oscillators/build-oscillated-param ; Move back and forth over a phrase\n                         (oscillators/triangle :interval :phrase) :min -90 :max 90)\n        staggered-triangle-bar (params/build-spatial-param ; Bounce over a bar, staggered across grid x\n                                (show/all-fixtures)\n                                (fn [head]\n                                  (oscillators/build-oscillated-param\n                                   (oscillators/triangle :interval :bar :phase (x-phase head *show*))\n                                   :min -90 :max 0)))\n        can-can-dir (params/build-direction-param-from-pan-tilt :pan triangle-phrase :tilt staggered-triangle-bar)\n        can-can-p-t (params/build-pan-tilt-param :pan triangle-phrase :tilt staggered-triangle-bar)]\n    (show/set-cue! 0 9 (cues/cue :movement (fn [_]\n                                             (move/direction-effect \"Can Can\" can-can-dir (show/all-fixtures)))))\n    (show/set-cue! 1 9 (cues/cue :movement (fn [_]\n                                             (move/pan-tilt-effect \"P/T Can Can\" can-can-p-t (show/all-fixtures))))))\n\n  #_(show/set-cue! 3 8 (cues/function-cue :blade-speed :movement-speed (show/fixtures-named \"blade\")\n                                        :color :purple :effect-name \"Slow Blades\"))\n\n  ;; Some fades\n  #_(show/set-cue! 0 12 (cues/cue :color-fade (fn [var-map]\n                                              (fx/fade \"Color Fade\"\n                                                       (global-color-effect :red :include-color-wheels? true)\n                                                       (global-color-effect :green :include-color-wheels? true)\n                                                       (params/bind-keyword-param (:phase var-map 0) Number 0)))\n                                :variables [{:key \"phase\" :min 0.0 :max 1.0 :start 0.0 :name \"Fade\"}]\n                                :color :yellow))\n\n  #_(show/set-cue! 1 12 (cues/cue :fade-test (fn [var-map]\n                                             (fx/fade \"Fade Test\"\n                                                      (fx/blank)\n                                                      (global-color-effect :blue :include-color-wheels? true)\n                                                      (params/bind-keyword-param (:phase var-map 0) Number 0)))\n                                :variables [{:key \"phase\" :min 0.0 :max 1.0 :start 0.0 :name \"Fade\"}]\n                                :color :cyan))\n\n  #_(show/set-cue! 2 12\n                 (cues/cue :fade-test-2 (fn [var-map]\n                                          (fx/fade \"Fade Test 2\"\n                                                   (move/direction-effect\n                                                    \"p/t\" (params/build-direction-param-from-pan-tilt :pan 0 :tilt 0)\n                                                    (show/fixtures-named \"torrent\"))\n                                                   (move/direction-effect\n                                                    \"p/t\" (params/build-direction-param-from-pan-tilt :pan 0 :tilt 0)\n                                                    (show/fixtures-named \"blade\"))\n                                                   (params/bind-keyword-param (:phase var-map 0) Number 0)))\n                           :variables [{:key \"phase\" :min 0.0 :max 1.0 :start 0.0 :name \"Fade\"}]\n                           :color :red))\n\n  #_(show/set-cue! 3 12 (cues/cue :fade-test-3 (fn [var-map]\n                                               (fx/fade \"Fade Test P/T\"\n                                                        (move/pan-tilt-effect\n                                                         \"p/t\" (params/build-pan-tilt-param :pan 0 :tilt 0)\n                                                         (show/fixtures-named \"torrent\"))\n                                                        (move/pan-tilt-effect\n                                                         \"p/t\" (params/build-pan-tilt-param :pan 0 :tilt 0)\n                                                         (show/fixtures-named \"blade\"))\n                                                        (params/bind-keyword-param (:phase var-map 0) Number 0)))\n                                :variables [{:key \"phase\" :min 0.0 :max 1.0 :start 0.0 :name \"Fade\"}]\n                                :color :orange))\n\n  #_(show/set-cue! 0 13\n                 (cues/cue :chase (fn [var-map]\n                                    (fx/chase \"Chase Test\"\n                                              [(global-color-effect :red :include-color-wheels? true)\n                                               (global-color-effect :green :fixtures (show/fixtures-named \"hex\"))\n                                               (global-color-effect :blue :include-color-wheels? true)]\n                                              (params/bind-keyword-param (:position var-map 0) Number 0)\n                                              :beyond :bounce))\n                           :variables [{:key \"position\" :min -0.5 :max 10.5 :start 0.0 :name \"Position\"}]\n                           :color :purple))\n\n  ;; Set up an initial value for our step parameter\n  #_(reset! step-param (params/build-step-param :fade-fraction 0.3 :fade-curve :sine))\n\n  #_(show/set-cue! 1 13\n                 (cues/cue :chase (fn [var-map]\n                                    (fx/chase \"Chase Test 2\"\n                                              [(global-color-effect :red :fixtures (show/fixtures-named \"hex\"))\n                                               (global-color-effect :green :fixtures (show/fixtures-named \"blade\"))\n                                               (global-color-effect :blue :fixtures (show/fixtures-named \"hex\"))\n                                               (global-color-effect :white :fixtures (show/all-fixtures))]\n                                              @step-param :beyond :loop))\n                           :color :magenta))\n  #_(show/set-cue!\n 7 0\n (cues/cue :dimmer\n           (fn [var-map]\n             (fx/wrap-fade-in-out \"Fade Test\"\n                                  (dimmer-effect (params/bind-keyword-param (:level var-map 255) Number 255)\n                                                 (show/fixtures-named :ws))\n                                  :step-in {:interval-ratio 2}\n                                  :step-out {:interval-ratio (/ 1 2)}))\n           :variables [{:key \"level\" :min 0 :max 255 :start 255}])))\n\n(defn use-chris-show\n  \"Set up the show laid out for Chris. By default it will create the\n  show to use universe 1, but if you want to use a different\n  universe (for example, a dummy universe on ID 0, because your DMX\n  interface isn't handy right now), you can override that by supplying\n  a different ID after :universe.\"\n  [& {:keys [universe] :or {universe 1}}]\n  ((requiring-resolve 'afterglow.shows.chris/use-chris-show) :universe universe))\n"
  },
  {
    "path": "src/afterglow/fixtures/american_dj.clj",
    "content": "(ns afterglow.fixtures.american-dj\n  \"Definitions for fixtures provided by [American DJ](http://adj.com).\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as chan]))\n\n(defn hypnotic-rgb\n  \"[Hypnotic RGB Laser](http://www.adj.com/hypnotic-rgb). Red, green,\n  and blue lasers with a web-like diffraction grating providing very\n  pretty effects for the price.\"\n  []\n  {:name \"American DJ Hypnotic RGB Laser\"\n   :channels [(chan/functions :control 1 0 nil 8 \"Beam Red\" 38 \"Beam Red Green\" 68 \"Beam Green\"\n                              98 \"Beam Green Blue\" 128 \"Beam Blue\" 158 \"Beam Red Blue\" 188 \"Beam Red Green Blue\"\n                              218 \"Beam All Random\" 248 :sound-active)\n              (chan/functions :control 2 0 nil\n                              10 {:type :beams-ccw\n                                  :var-label \"CCW (fast->slow)\"\n                                  :range :variable}\n                              121 nil\n                              135 {:type :beams-cw\n                                   :var-label \"CW (slow->fast)\"\n                                   :range :variable}\n                              246 nil)]})\n"
  },
  {
    "path": "src/afterglow/fixtures/blizzard.clj",
    "content": "(ns afterglow.fixtures.blizzard\n  \"Definitions for fixtures provided by [Blizzard\n  Lighting](https://www.blizzardpro.com/).\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as chan]\n            [afterglow.effects.channel :as chan-fx]\n            [afterglow.fixtures.qxf :refer [sanitize-name]]))\n\n(defn- build-gobo-entries\n  \"Create a series of function map entries describing the gobos\n  available on one of the Torrent gobo wheels, in a format suitable\n  for passing to [[chan/functions]]. `moving?` is `true` to generate\n  entries for the moving gobo wheel, `false` for the fixed gobo wheel.\n  `shake?` is `true` when generating entries for ranges which shake\n  the gobo at variable speeds, `false` if the gobo is being projected\n  in a static position. `names` is the list of gobo names to expand\n  into corresponding function map entries.\"\n  [moving? shake? names]\n  (map (fn [entry]\n         (let [prefix (str \"gobo-\" (if moving? \"moving-\" \"fixed-\"))\n               type-key (keyword (sanitize-name (str prefix entry (when shake? \" shake\"))))\n               label (str \"Gobo\" (when moving? \"M\") \" \" entry (when shake? \" shake\"))]\n           (merge {:type type-key\n                   :label label\n                   :range (if shake? :variable :fixed)}\n                  (when shake? {:var-label \"Shake Speed\"}))))\n       names))\n\n(defn torrent-f3\n  \"Torrent F3 moving head effects spotlight. The default patching\n  orientation is sitting on its feet with the LCD and control panel\n  right side up and facing the audience. In this orientation, at a pan\n  of 0, the beam is straight into the audience.\n\n  The origin of the light is, as for all moving heads, at the\n  intersection of the pan and tilt axes. That is the point that you\n  need to reference when patching the fixture and telling Afterglow\n  where it has been hung within [show\n  space]({{guide-url}}show_space.html). The\n  image below shows this default orientation, and the axes, for the\n  fixture. If it is hung with this side of the base facing the\n  audience, right side up, then you do not need to specify any\n  rotations when you patch it. Otherwise, tell Afterglow how far it\n  has been rotated around each of the axes when hanging:\n\n  ![F3 axes]({{guide-url}}_images/F3.png)\n\n  The center pan value (aimed straight at the audience when hung in\n  the default orientation described above), is defined as 85.5, half a\n  revolution around from that, so that it has room to move in both\n  directions from its resting point. It takes a change of -85.5 in the\n  pan channel to rotate a half circle counterclockwise around the Y\n  axis.\n\n  At the center pan setting of 85.5, the center tilt value is 25,\n  aiming the head straight out at the audience. At this position, it\n  takes a change of -203 in the tilt channel to rotate a half circle\n  counterclockwise around the X axis. (In other words, it can only\n  tilt a little counterclockwise from here, but can flip right over in\n  the clockwise direction.)\n\n  If you are wondering why you are getting no light from a torrent,\n  note that you need to explicitly set the shutter to open before the\n  dimmer has any effect. Try something like:\n\n```clojure\n(show/add-effect! :torrent-shutter\n  (afterglow.effects.channel/function-effect\n    \\\"Torrents Open\\\" :shutter-open 50\n    (show/fixtures-named \\\"torrent\\\")))\n```\"\n  []\n  {:channels [(chan/pan 1 2) (chan/tilt 3 4)\n              (chan/functions :color 5 0 \"Color Wheel Open\"\n                              (range 16 128 16) (chan/color-wheel-hue [\"red\" \"blue\" \"green\" \"yellow\"\n                                                                       \"magenta\" \"cyan\" \"orange\"])\n                              128 {:type :color-clockwise\n                                   :label \"Color Wheel Clockwise (fast->slow)\"\n                                   :var-label \"CW (fast->slow)\"\n                                   :range :variable}\n                              190 \"Color Stop\" 194 {:type :color-counterclockwise\n                                                    :label \"Color Wheel Counterclockwise (slow->fast)\"\n                                                    :var-label \"CCW (fast->slow)\"\n                                                    :range :variable})\n              (let [gobo-names [\"Rings\" \"Color Swirl\" \"Stars\" \"Optical Tube\" \"Magenta Bundt\"\n                                \"Blue MegaHazard\" \"Turbine\"]]\n                (chan/functions :gobo-moving 6\n                                (range 0 80 10) (build-gobo-entries true false (concat [\"Open\"] gobo-names))\n                                (range 80 220 20) (build-gobo-entries true true gobo-names)\n                                220 {:type :gobo-moving-clockwise\n                                     :label \"Clockwise Speed\"\n                                     :var-label \"CW Speed\"\n                                     :range :variable}))\n              (chan/functions :gobo-rotation 7 0 nil\n                              4 {:type :gobo-rotation-clockwise\n                                 :label \"Gobo Rotation Clockwise (fast->slow)\"\n                                 :var-label \"CW (fast->slow)\"\n                                 :range :variable}\n                              128 \"gobo-rotation-stop\"\n                              132 {:type :gobo-rotation-counterclockwise\n                                   :label \"Gobo Rotation Counterlockwise (slow->fast)\"\n                                   :var-label \"CCW (slow->fast)\"\n                                   :range :variable})\n              (let [gobo-names [\"Mortar\" \"4 Rings\" \"Atom\" \"Jacks\" \"Saw\" \"Sunflower\" \"45 Adapter\"\n                                \"Star\" \"Rose/Fingerprint\"]]\n                (chan/functions :gobo-fixed 8\n                                (range 0 100 10) (build-gobo-entries false false (concat [\"Open\"] gobo-names))\n                                (range 100 208 12) (build-gobo-entries false true gobo-names)\n                                208 {:type :gobo-fixed-clockwise\n                                     :label \"Clockwise Speed\"\n                                     :var-label \"CW Speed\"\n                                     :range :variable}))\n              (chan/functions :shutter 9 0 \"Shutter Closed\" 32 \"Shutter Open\"\n                              64 {:type :strobe\n                                  :scale-fn (partial chan-fx/function-value-scaler 14 100)\n                                  :label \"Strobe (1.4Hz->10Hz)\"\n                                  :range :variable}\n                              96 \"Shutter Open 2\" 128 :pulse-strobe 160 \"Shutter Open 3\"\n                              192 :random-strobe\n                              224 \"Shutter Open 4\")\n              (chan/dimmer 10)\n              (chan/focus 11)\n              (chan/functions :prism 12 0 \"Prism Out\" 6 \"Prism In\"\n                              128 {:type :prism-clockwise\n                                   :label \"Prism Clockwise (fast->slow)\"\n                                   :var-label \"CW (fast->slow)\"\n                                   :range :variable}\n                              190 \"Prism Stop\"\n                              194 {:type :prism-counterclockwise\n                                   :label \"Prism Counterclockwsie (slow->fast)\"\n                                   :var-label \"CCW (slow->fast)\"\n                                   :range :variable})\n              (chan/functions :pan-tilt-speed 13 0 \"Pan/Tilt Speed Normal\"\n                              1 :pan-tilt-speed-slow\n                              226 \"Blackout When Head Moving\"\n                              236 \"Blackout When Wheels Changing\"\n                              246 nil)\n              (chan/functions :control 14 0 \"Normal Color Change Mode\"\n                              20 \"Split Colors Possible\" 30 \"Split Colors and Gobos\"\n                              40 nil 80 \"Motor Reset\" (range 100 255 20) \"Program\")]\n   :name \"Blizzard Torrent F3\"\n   :pan-center 85.5 :pan-half-circle -85.5 :tilt-center 25 :tilt-half-circle -203})\n\n(defn blade-rgbw\n  \"[Blade\n  RGBW](https://www.blizzardpro.com/products/blade-rgbw)\n  moving head. The default patching orientation is sitting on its feet\n  with the LCD and control panel right side up and facing the\n  audience. In this orientation, at a pan of 0, the beam is straight\n  into the audience.\n\n  The origin of the light is, as for all moving heads, at the\n  intersection of the pan and tilt axes. That is the point that you\n  need to reference when patching the fixture and telling Afterglow\n  where it has been hung within [show\n  space]({{guide-url}}show_space.html). The\n  image below shows this default orientation, and the axes, for the\n  fixture. If it is hung with this side of the base facing the\n  audience, right side up, then you do not need to specify any\n  rotations when you patch it. Otherwise, tell Afterglow how far it\n  has been rotated around each of the axes when hanging:\n\n  ![Blade axes]({{guide-url}}_images/Blade.png)\n\n  If you are hanging the light at an odd angle, or for any reason it\n  is harder to measure the exact axis location given where where you\n  are hanging it, you can supply an optional argument `:hung` after\n  the `mode` argument, containing the distance in meters from the\n  origin in the photo to the point at which it was hung (the center of\n  the bar it is clamped to), and Afterglow will calculate where the\n  head is based on that distance and the orientation at which you\n  reported it hung. With the standard clamp mount and a standard\n  O-clamp that distance seems to be twelve inches.\n\n  The center pan value (aimed straight at the audience when hung in\n  the default orientation described above), is defined as 84, a half\n  revolution around from that, so that it has room to move in both\n  directions from its resting point. It takes a change of +84 in the\n  pan channel to rotate a half circle counterclockwise around the Y\n  axis.\n\n  At the center pan setting of 84, the center tilt value is 8, aiming\n  the head straight out at the audience. At this position, it takes a\n  change of -214 in the tilt channel to rotate a half circle\n  counterclockwise around the X axis. (In other words, it can\n  essentially only tilt clockwise from here.)\n\n  This fixture can be configured to use either 11 or 15 DMX channels.\n  If you do not specify a mode when patching it, `:15-channel` is\n  assumed; you can pass a value of `:11-channel` for `mode` if you are\n  using it that way.\n\n  The way these fixtures respond to pan and tilt values seems to have\n  changed in a major revision in 2015. If you have a more recent\n  model, you can pass a `true` value with the optional keyword\n  argument `:version-2` after `mode`, in which case the center pan\n  value is 82, the center tilt value is 25, and it takes a change of\n  -230 in the tilt channel to rotate half a circle counterclockwise\n  around the Y axis.\"\n  ([]\n   (blade-rgbw :15-channel))\n  ([mode & {:keys [hung version-2] :or {hung 0}}]\n   (let [[pan-center pan-half-circle tilt-center tilt-half-circle] (if version-2 [82 84 25 -230] [84 84 8 -214])]\n     (assoc (case mode\n              :15-channel {:channels [(chan/fine-channel :movement-speed 5\n                                                         :function-name \"Movement Speed (fast->slow)\")\n                                      (chan/fine-channel :custom-color 10)\n                                      (chan/functions :strobe 11 0 nil\n                                                      1 {:type :strobe\n                                                         :scale-fn (partial chan-fx/function-value-scaler 18 100)\n                                                         :label \"Strobe (1.8Hz->10Hz)\"\n                                                         :range :variable})\n                                      (chan/dimmer 12)\n                                      (chan/functions :control 13\n                                                      0 :linear-dimming 26 :fade-step-increase\n                                                      51 :color-macros 91 :color-fade-in-out\n                                                      131 :color-snap 171 :color-fade\n                                                      211 :auto 251 :sound-active)]\n                           :heads [{:channels [(chan/pan 1 3) (chan/tilt 2 4)\n                                               (chan/color 6 :red) (chan/color 7 :green)\n                                               (chan/color 8 :blue) (chan/color 9 :white)]\n                                    :y hung\n                                    :pan-center pan-center :pan-half-circle pan-half-circle\n                                    :tilt-center tilt-center :tilt-half-circle tilt-half-circle}]}\n              :11-channel {:channels [(chan/fine-channel :movement-speed 5\n                                                         :function-name \"Movement Speed (fast->slow)\")\n                                      (chan/dimmer 10) (chan/fine-channel :custom-color 11)]\n                           :heads [{:channels [(chan/pan 1 3) (chan/tilt 2 4)\n                                               (chan/color 6 :red) (chan/color 7 :green)\n                                               (chan/color 8 :blue) (chan/color 9 :white)]\n                                    :y hung\n                                    :pan-center pan-center :pan-half-circle pan-half-circle\n                                    :tilt-center tilt-center :tilt-half-circle tilt-half-circle}]})\n            :name \"Blizzard Blade RGBW\"\n            :mode mode))))\n\n;; TODO: Someday play with channels 13 and 14 more to see if there is anything worth modeling.\n;;       Not urgent, though, the main point of Afterglow is custom effects using raw colors and\n;;       motions. Also unimplemented is the whole concept of Fiture ID, but that would require\n;;       major support throughout Afterglow. Wait until people using overpopulated DMX networks\n;;       ask for it...\n\n(defn puck-fab5\n  \"[Puck\n  Fab5](https://web.archive.org/web/20140209181145/http://blizzardlighting.com/index.php?option=com_k2&view=item&id=172:the-puck-fab5™&Itemid=151)\n  RGBAW LED.\n\n\n  This fixture can be configured to use either 3, 5 or 12 DMX\n  channels. If you do not specify a mode when patching it,\n  `:12-channel` is assumed; you can pass a value of `:3-channel` or\n  `:5-channel` for `mode` if you are using it that way.\n\n  When you pass a mode, you can also control whether the amber channel\n  is mixed in when creating colors by passing a boolean value with\n  `:mix-amber`. The default is `true`.\"\n  ([]\n   (puck-fab5 :12-channel))\n  ([mode & {:keys [mix-amber] :or {mix-amber true}}]\n   (assoc (case mode\n            :3-channel {:channels [(chan/dimmer 1)\n                                   (chan/functions :strobe 2\n                                                    0 nil\n                                                    16 {:type :strobe\n                                                        :scale-fn (partial chan-fx/function-value-scaler 8 100)\n                                                        :label \"Strobe (0.8Hz->10Hz)\"\n                                                        :range :variable})\n                                   (chan/functions :control 3\n                                                   0 \"R\" 5 \"G\" 9 \"B\" 13 \"A\" 17 \"W\" 21 \"RG\" 25 \"RB\" 29 \"RA\" 32 \"RW\"\n                                                   36 \"GB\" 40 \"GA\" 44 \"GW\" 48 \"BA\" 52 \"BW\" 56 \"AW\" 60 \"BAW\" 63 \"GAW\"\n                                                   67 \"GBW\" 71 \"GBA\" 75 \"RAW\" 79 \"RBW\" 83 \"RBA\" 87 \"RGW\" 91 \"RGA\"\n                                                   94 \"RGB\" 98 \"RGBA\" 102 \"RGBW\" 106 \"RGAW\" 110 \"RBAW\" 114 \"GBAW\"\n                                                   118 \"RGBAW\" 121 {:type :chase :label \"Chase (slow->fast)\"\n                                                                    :range :variable})] }\n            :5-channel {:channels [(chan/color 1 :red) (chan/color 2 :green) (chan/color 3 :blue)\n                                   (chan/color 4 :amber :hue (when mix-amber 45))\n                                   (chan/color 5 :white)]}\n            :12-channel {:channels [(chan/dimmer 1)\n                                    (chan/functions :strobe 2\n                                                    0 nil\n                                                    16 {:type :strobe\n                                                        :scale-fn (partial chan-fx/function-value-scaler 8 100)\n                                                        :label \"Strobe (0.8Hz->10Hz)\"\n                                                        :range :variable})\n                                    (chan/color 3 :red) (chan/color 4 :green) (chan/color 5 :blue)\n                                    (chan/color 6 :amber :hue (when mix-amber 45))\n                                    (chan/color 7 :white)\n                                    (chan/functions :control 8 0 :color-snap)\n                                    (chan/functions :control 9 0 nil\n                                                    16 {:type :snap-speed :label \"Snap speed (slow->fast)\"\n                                                        :range :variable})\n                                    (chan/functions :control 10 0 :color-fade)\n                                    (chan/functions :control 11 0 nil\n                                                    16 {:type :fade-speed :label \"Fade speed (slow->fast)\"\n                                                        :range :variable})\n                                    (chan/functions :control 12 0 nil\n                                                    128 {:type :sound-active :var-label \"Sensitivity\"\n                                                         :range :variable})]})\n          :name \"Blizzard Puck Fab5\"\n          :mode mode)))\n\n(def ^:private ws-head-offsets\n  \"The X-axis positions of the eight weather system heads\"\n  [-0.406 -0.305 -0.191 -0.083 0.083 0.191 0.305 0.406])\n\n(defn- ws-head\n  \"Creates a head definition for one head of the Weather System\"\n  [index]\n  {:channels [(chan/color (+ 2 (* 3 index)) :red)\n              (chan/color (+ 3 (* 3 index)) :green)\n              (chan/color (+ 4 (* 3 index)) :blue)]\n   :x (get ws-head-offsets index)})\n\n(defn weather-system\n  \"[Weather\n  System](https://web.archive.org/web/20230206072442/https://www.blizzardpro.com/products/weather-system)\n  8-fixture LED bar. Even though this fixture does not move, it is\n  important to patch it at the correct orientation, so Afterglow can\n  properly reason about the spatial relationships between the eight\n  individual heads.\n\n  The fixture origin is right between the fourth and fifth head, at\n  the level of the lenses. The default orientation is with the bar\n  parallel to the X axis, and the LED display and sockets all facing\n  away from the audience.\n\n  ![Weather System axes]({{guide-url}}_images/WeatherSystem.jpg)\n\n  This fixture can be configured to use either 7 or 26 DMX channels.\n  If you do not specify a mode when patching it, `:26-channel` is\n  assumed; you can pass a value of `:7-channel` for `mode` if you are\n  using it that way.\"\n  ([]\n   (weather-system :26-channel))\n  ([mode]\n   (assoc (case mode\n            :7-channel {:channels [(chan/dimmer 1) (chan/color 2 :red) (chan/color 3 :green) (chan/color 4 :blue)\n                                   (chan/functions :control 5\n                                                   0 nil 8 \"Red\" 16 \"Yellow\" 24 \"Green\" 32 \"Cyan\" 40 \"Blue\"\n                                                   48 \"Purple\" 56 \"White\" (range 64 232 8) \"Program\"\n                                                   232 \"Sound Active\")\n                                   (chan/fine-channel :mic-sensitivity 6)\n                                   (chan/functions :strobe 7 0 nil\n                                                   11 {:type :strobe\n                                                       :scale-fn (partial chan-fx/function-value-scaler 6.6 100)\n                                                       :label \"Strobe (0.66Hz->10Hz)\"\n                                                       :range :variable})]}\n            :26-channel {:channels [(chan/dimmer 1)\n                                    (chan/functions :strobe 26\n                                                    0 nil\n                                                    11 {:type :strobe\n                                                        :scale-fn (partial chan-fx/function-value-scaler 6.6 100)\n                                                        :label \"Strobe (0.66Hz->10Hz)\"\n                                                        :range :variable})]\n                         :heads (map ws-head (range 8))})\n          :name \"Blizzard Weather System\"\n          :mode mode)))\n\n(defn- snowbank-head\n  \"Creates a head definition for one head of the Snowbank.\"\n  [index]\n  ;; TODO: Actually implement! The snowbank has two rows of heads, that scan in opposite orders, and\n  ;;       project forward different amounts. But it has not been worth mapping them for our own fixture,\n  ;;       because it has too many failed LED channels. So we only use it in 7-channel mode as a blinder\n  ;;       generally aimed at the ceiling. For now, just cheating and pretending the heads are arranged\n  ;;       the same as for a Weather System\n  (ws-head index))\n\n(defn snowbank\n  \"[Snow\n  Bank](https://web.archive.org/web/20230204191858/https://www.blizzardpro.com/products/snowbank)\n  RGB Blinder / LED Pixel Effect.\"\n  ([]\n   (snowbank :26-channel))\n  ([mode]\n   (assoc (case mode\n            :7-channel {:channels [(chan/dimmer 1) (chan/color 2 :red) (chan/color 3 :green) (chan/color 4 :blue)\n                                   (chan/functions :control 5\n                                                   0 nil 8 \"Red\" 16 \"Yellow\" 24 \"Green\" 32 \"Cyan\" 40 \"Blue\"\n                                                   48 \"Purple\" 56 \"White\" (range 64 232 8) \"Program\"\n                                                   232 :sound-active)\n                                   (chan/functions :speed 6 0 nil 64 :speed)\n                                   (chan/functions :strobe 7 0 nil\n                                                   11 {:type :strobe\n                                                       :label \"Strobe (?->?Hz)\"\n                                                       :range :variable})]}\n            :26-channel {:channels [(chan/dimmer 1)\n                                    (chan/functions :strobe 26\n                                                    0 nil\n                                                    11 {:type :strobe\n                                                        :label \"Strobe (?->?Hz)\"\n                                                        :range :variable})]\n                         :heads (map snowbank-head (range 8))})\n          :name \"Blizzard Snowbank\"\n          :mode mode)))\n\n(defn snowball\n  \"[Snowball](https://www.blizzardpro.com/products/snowball-rgbw)\n  multi-beam moonflower effect light.\"\n  []\n  {:name \"Blizzard Snowball\"\n   :channels [(chan/dimmer 1) (chan/color 2 :red) (chan/color 3 :green) (chan/color 4 :blue) (chan/color 5 :white)\n              (chan/functions :strobe 6 0 nil\n                              17 {:type :strobe\n                                  :label \"Strobe (?->?Hz)\"\n                                  :range :variable})\n              (chan/functions :control 7 0 :color-macros)\n              (chan/functions :control 8\n                              0 {:type :beams-fixed\n                                 :var-label \"Beam Position\"\n                                 :range :variable}\n                              128 {:type :beams-moving\n                                   :var-label \"Move Speed\"\n                                   :range :variable})\n              (chan/functions :control 9 0 nil\n                              128 {:type :sound-active :var-label \"Sensitivity\" :range :variable})]})\n\n(defn pixellicious\n  \"4x40 LED pixel tile in 480 channel mode. The default orientation is\n  facing the audience, with the long axis parallel to the X axis, and\n  the controls and LED panel right-side up on the back side.\"\n  []\n  {:name \"Blizzard Pixellicious\"\n   :channels []\n   :heads (for [i (range 160)]\n            (let [x (+ (* (rem i 40) 0.025) -0.5)\n                  y (+ (* (quot i 40) -0.025) 0.05)\n                  c (+ (* i 3) 1)]\n              {:channels [(chan/color c :red)\n                          (chan/color (inc c) :green)\n                          (chan/color (+ 2 c) :blue)]\n               :x x :y y}))})\n\n(defn pixellicious-2\n  \"12x12 LED pixel tile in 432 channel mode.\"\n  []\n  {:name \"Blizzard Pixellicious2\"\n   :channels []\n   :heads (for [i (range 144)]\n            (let [x (+ (* (rem i 12) 0.025) -0.15)\n                  y (+ (* (quot i 12) 0.025) -0.15)\n                  c (+ (* i 3) 1)]\n              {:channels [(chan/color c :red)\n                          (chan/color (inc c) :green)\n                          (chan/color (+ 2 c) :blue)]\n               :x x :y y}))})\n"
  },
  {
    "path": "src/afterglow/fixtures/chauvet.clj",
    "content": "(ns afterglow.fixtures.chauvet\n  \"Models for fixtures provided by [Chauvet Lighting](http://www.chauvetlighting.com).\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as chan]\n            [afterglow.effects.channel :as chan-fx]\n            [afterglow.fixtures.qxf :refer [sanitize-name]]))\n\n(defn- build-gobo-entries\n  \"Build a list of gobo wheel function entries. If `shake?` is `true`,\n  they are a variable range which sets the shake speed. The individual\n  gobo names are in `names`.\"\n  [shake? names]\n  (map (fn [entry]\n         (let [label (str \"Gobo \" entry (when shake? \" shake\"))\n               type-key (keyword (sanitize-name label))]\n           (merge {:type type-key\n                   :label label\n                   :range (if shake? :variable :fixed)}\n                  (when shake? {:var-label \"Shake Speed\"}))))\n       names))\n\n(defn color-strip\n  \"[ColorStrip](https://www.chauvetdj.com/products/colorstrip/) LED fixture.\n  Also works with the ColorStrip Mini.\n\n  This was created by Afterglow from the QLC+ Fixture Definintion\n  (.qxf) file, and revised by James Elliott.\n\n  The original fixture defintition was created by JL Griffin\n  using Q Light Controller version 3.1.0.\n\n  QLC+ Fixture Type: Color Changer.\"\n  []\n  {:channels [(chan/functions :control 1\n                              0 \"Blackout\"\n                              10 \"Red\"\n                              20 \"Green\"\n                              30 \"Blue\"\n                              40 \"Yellow\"\n                              50 \"Magenta\"\n                              60 \"Cyan\"\n                              70 \"White\"\n                              (range 80 139 10) \"Auto Change\"\n                              (range 140 209 10) \"Color Chase\"\n                              210 \"RGB Control\"\n                              220 \"Chase Fade\"\n                              230 \"Auto Run\")\n              (chan/color 2 :red)\n              (chan/color 3 :green)\n              (chan/color 4 :blue)]\n   :name \"Chauvet ColorStrip\"})\n\n(defn geyser-rgb\n  \"[Geyser RGB](https://www.chauvetdj.com/products/geyser-rgb/)\n  illuminated effect fogger.\"\n  []\n  {:channels [(chan/functions :fog 1\n                              0 nil\n                              10 \"Fog\")\n              (chan/color 2 :red)\n              (chan/color 3 :green)\n              (chan/color 4 :blue)\n              (chan/functions :control 5\n                              0 nil\n                              10 :color-mixing)\n              (chan/functions :control 6\n                              0 nil\n                              10 :auto-speed)\n              (chan/functions :strobe 7\n                              0 nil\n                              10 :strobe)\n              (chan/dimmer 8)]\n   :name \"Chauvet Geyser RGB\"})\n\n(defn gig-bar-2\n  \"[GigBAR 2](https://www.chauvetdj.com/products/gigbar-2/) mobile DJ\n  lighting system. Even though this fixture does not move, if you want\n  to have its RGB pars participate in spatial effects, it is important\n  to patch it at the correct location and orientation, so Afterglow\n  can properly reason about the spatial relationships between the\n  heads. If you have rearranged the pods from their default\n  configuration, you will want to edit the head definitions\n  appropriately.\n\n  The fixture origin is in between the two center (par) pods, at the\n  center of the support pole, and centered vertically with the lenses\n  of the Par lights. The default orientation is with the pod mounting\n  bar parallel to the X axis, and the LED display and sockets all\n  facing away from the audience.\n\n  This fixture can be patched to use 3, 11, or 23 DMX channels. If you\n  do not specify a mode when patching it, `:23-channel` is assumed;\n  you can pass a value of `:3-channel` or `:11-channel` for `mode` if\n  you are using it that way.\n\n  This was created by Afterglow from the QLC+ Fixture Definintion\n  (.qxf) file, and revised by James Elliott.\n\n  The original fixture defintition was created by Freasy using Q Light\n  Controller Plus version 4.11.0. QLC+ Fixture Type: Effect.\n\n  When you pass a mode, you can also control whether the UV channels\n  are mixed in when creating colors by passing a boolean value with\n  `:mix-uv`. The default is `true`.\"\n  ([]\n   (gig-bar-2 :23-channels))\n  ([mode & {:keys [mix-uv] :or {mix-uv true}}]\n   (merge {:name \"GigBAR 2\"\n           :mode mode}\n          (case mode\n            :3-channels\n            {:channels [(chan/functions :led-operation 1\n                                        0 nil\n                                        10 {:type  :led-auto-mixed-mode-1\n                                            :label \"Auto 1 fast>slow\"\n                                            :range :variable}\n                                        120 {:type  :led-auto-mixed-mode-2\n                                             :label \"Auto 2 fast>slow\"\n                                             :range :variable}\n                                        230 {:type  :led-sound-mixed-mode-1\n                                             :label \"Sound 1\"\n                                             :range :fixed}\n                                        235 {:type  :led-sound-active\n                                             :label \"Sound 2\"\n                                             :range :fixed}\n                                        240 {:type  :led-show-setting\n                                             :label \"Show, chan 2+3\"\n                                             :range :fixed})\n                        (chan/functions :operation 2\n                                        0 {:type  :blackout\n                                           :label \"Blackout\"\n                                           :range :fixed}\n                                        10 {:type  :pars-only\n                                            :label \"Pars only\"\n                                            :range :fixed}\n                                        20 {:type  :derby-only\n                                            :label \"Derby only\"\n                                            :range :fixed}\n                                        30 {:type  :laser-only\n                                            :label \"Laser only\"\n                                            :range :fixed}\n                                        40 {:type  :strobes-only\n                                            :label \"Strobes only\"\n                                            :range :fixed}\n                                        50 {:type  :auto-pars-derby\n                                            :label \"Auto pars derby\"\n                                            :range :fixed}\n                                        60 {:type  :operation-pars-laser\n                                            :label \"Auto pars laser\"\n                                            :range :fixed}\n                                        70 {:type  :operation-auto-pars-and-strobes-only\n                                            :label \"Auto pars strobes\"\n                                            :range :fixed}\n                                        80 {:type  :auto-derby-laser\n                                            :label \"Auto derby laser only\"\n                                            :range :fixed}\n                                        90 {:type  :auto-strobes-derby\n                                            :label \"Auto strobes derby only\"\n                                            :range :fixed}\n                                        100 {:type  :pars-derby-laser\n                                             :label \"Pars, derby, laser\"\n                                             :range :fixed}\n                                        110 {:type  :pars-derby-strobes\n                                             :label \"Pars, derby, strobes\"\n                                             :range :fixed}\n                                        120 {:type  :pars-laser-strobes\n                                             :label \"Pars, laser, strobes\"\n                                             :range :fixed}\n                                        130 {:type  :derby-laser-strobes\n                                             :label \"Derby, laser, strobes\"\n                                             :range :fixed}\n                                        140 {:type  :par-sound-active\n                                             :label \"Par Sound\"\n                                             :range :fixed}\n                                        150 {:type  :derby-sound-active\n                                             :label \"Derby Sound\"\n                                             :range :fixed}\n                                        160 {:type  :laser-sound-active\n                                             :label \"Laser Sound\"\n                                             :range :fixed}\n                                        170 {:type  :strobe-sound-active\n                                             :label \"Strobe Sound\"\n                                             :range :fixed}\n                                        180 {:type  :par-derby-sound-active\n                                             :label \"Par, Derby Sound\"\n                                             :range :fixed}\n                                        190 {:type  :par-laser-sound-active\n                                             :label \"Par, Laser Sound\"\n                                             :range :fixed}\n                                        200 {:type  :par-strobe-sound-active\n                                             :label \"Par, Strobe Sound\"\n                                             :range :fixed}\n                                        210 {:type  :derby-laser-sound-active\n                                             :label \"Derby, Laser Sound\"\n                                             :range :fixed}\n                                        220 {:type  :derby-strobe-sound-active\n                                             :label \"Derby, Strobe Sound\"\n                                             :range :fixed}\n                                        230 {:type  :pars-derby-laser-sound-active\n                                             :label \"Par, Derby, Laser Sound\"\n                                             :range :fixed}\n                                        240 {:type  :pars-derby-strobes-sound-active\n                                             :label \"Par, Derby, Strobe Sound\"\n                                             :range :fixed}\n                                        245 {:type  :pars-laser-strobes-sound-active\n                                             :label \"Par, Laser, Strobe Sound\"\n                                             :range :fixed}\n                                        250 {:type  :derby-laser-strobes-sound-active\n                                             :label \"Derby, Laser, Strobe Sound\"\n                                             :range :fixed})\n                        (chan/fine-channel :auto-speed 3\n                                           :function-name \"Auto Speed\"\n                                           :var-label \"Auto Speed\")]}\n            :11-channels\n            {:channels [(chan/color 1 :red)\n                        (chan/color 2 :green)\n                        (chan/color 3 :blue)\n                        (chan/color 4 :uv :label \"UV\" :hue (when mix-uv 270))\n                        (chan/functions :pars-and-derby-strobe-controls 5\n                                        0 {:type  :dimmer\n                                           :label \"Pars+Derbys Dimmer\"\n                                           :range :variable}\n                                        128 {:type  :pars-derby-strobe-speed\n                                             :label \"Pars+Derbys Strobe Speed\"\n                                             :range :variable}\n                                        240 {:type  :pars-derby-sound-strobe\n                                             :label \"Pars+Derbys Sound Strobe\"\n                                             :range :variable}\n                                        250 {:type  :pars-derby-full-strobe\n                                             :label \"Pars+Derbys Full Strobe\"\n                                             :range :fixed})\n                        (chan/functions :derby-motor-rotation 6\n                                        0 nil\n                                        5 {:type  :derby-clockwise\n                                           :label \"Derby CW, slow>fast\"\n                                           :range :variable}\n                                        128 nil\n                                        134 {:type  :derby-counter-clockwise\n                                             :label \"Derby CCW, slow>fast\"\n                                             :range :variable})\n                        (chan/functions :red-laser-controls 7\n                                        0 nil\n                                        5 {:type  :red-laser-on\n                                           :label \"Red laser on\"\n                                           :range :fixed}\n                                        55 {:type  :red-laser-strobe-speed\n                                            :label \"Red laser strobe speed\"\n                                            :range :variable})\n                        (chan/functions :green-laser-controls 8\n                                        0 nil\n                                        5 {:type  :green-laser-on\n                                           :label \"Green laser on\"\n                                           :range :fixed}\n                                        55 {:type  :green-laser-strobe-speed\n                                            :label \"Green laser strobe speed\"\n                                            :range :variable})\n                        (chan/functions :laser-movement-speed 9\n                                        0 nil\n                                        5 {:type  :laser-clockwise\n                                           :label \"Laser CW, slow>fast\"\n                                           :range :variable}\n                                        128 nil\n                                        134 {:type  :laser-counter-clockwise\n                                             :label \"Laser CCW, slow>fast\"\n                                             :range :variable})\n                        (chan/functions :white-strobe 10  ; Cannot be used at the same time as 11\n                                        0 {:type  :dimmer\n                                           :label \"White strobe dimmer\"\n                                           :range :variable}\n                                        55 {:type  :white-strobe-speed\n                                            :label \"White strobe speed\"\n                                            :range :variable})\n                        (chan/functions :uv-strobe 11  ; Cannot be used at the same time as 10\n                                        0 {:type  :dimmer\n                                           :label \"UV strobe dimmer\"\n                                           :range :variable}\n                                        55 {:type  :uv-strobe-speed\n                                            :label \"UV strobe speed\"\n                                            :range :variable})]}\n            ;; TODO: Split 23-channels into individual heads, to be patched separately, for better semantic fit.\n            :23-channels\n            {:channels [(chan/functions :strobe-patterns 20\n                                        0 {:type  :strobe-auto-1\n                                           :label \"Strobe Auto 1\"\n                                           :range :fixed}\n                                        10 {:type  :strobe-auto-2\n                                            :label \"Strobe Auto 2\"\n                                            :range :fixed}\n                                        30 {:type  :strobe-auto-3\n                                            :label \"Strobe Auto 3\"\n                                            :range :fixed}\n                                        50 {:type  :strobe-auto-4\n                                            :label \"Strobe Auto 4\"\n                                            :range :fixed}\n                                        70 {:type  :strobe-auto-5\n                                            :label \"Strobe Auto 5\"\n                                            :range :fixed}\n                                        90 {:type  :strobe-auto-6\n                                            :label \"Strobe Auto 6\"\n                                            :range :fixed}\n                                        110 {:type  :strobe-auto-7\n                                             :label \"Strobe Auto 7\"\n                                             :range :fixed}\n                                        130 {:type  :strobe-auto-8\n                                             :label \"Strobe Auto 8\"\n                                             :range :fixed}\n                                        150 {:type  :strobe-auto-9\n                                             :label \"Strobe Auto 9\"\n                                             :range :fixed}\n                                        170 {:type  :strobe-auto-10\n                                             :label \"Strobe Auto 10\"\n                                             :range :fixed}\n                                        190 {:type  :strobe-speed\n                                             :label \"Strobe Speed\"\n                                             :range :variable}\n                                        210 {:type  :strobe-sound-active\n                                             :label \"Strobe Sound\"\n                                             :range :variable})\n                        (chan/fine-channel :strobe-speed 23\n                                           :function-name \"Strobe Speed Slow to Fast\"\n                                           :var-label \"Strobe Slow>Fast\")]\n             :heads    [{:x 0.5 :y -0.05 :z 0 ; TODO: Measure and fine-tune location\n                         :channels [(chan/functions :derby-control 11\n                                                    0 nil\n                                                    25 {:type  :derby-red\n                                                        :label \"Derby 1 Red\"\n                                                        :range :variable}\n                                                    50 {:type  :derby-green\n                                                        :label \"Derby 1 Green\"\n                                                        :range :variable}\n                                                    75 {:type  :derby-blue\n                                                        :label \"Derby 1 Blue\"\n                                                        :range :variable}\n                                                    100 {:type  :derby-red-green\n                                                         :label \"Derby 1 RG\"\n                                                         :range :variable}\n                                                    125 {:type  :derby-red-blue\n                                                         :label \"Derby 1 RB\"\n                                                         :range :variable}\n                                                    150 {:type  :derby-green-blue\n                                                         :label \"Derby 1 GB\"\n                                                         :range :variable}\n                                                    175 {:type  :derby-red-green-blue\n                                                         :label \"Derby 1 RGB\"\n                                                         :range :variable}\n                                                    200 {:type  :derby-auto-single-colors\n                                                         :label \"Derby 1 Auto (1 color)\"\n                                                         :range :variable}\n                                                    225 {:type  :derby--auto-two-colors\n                                                         :label \"Derby 1 Auto (2 colors)\"\n                                                         :range :variable})\n                                    (chan/functions :derby-strobe-speed 12\n                                                    0 nil\n                                                    10 {:type  :strobe\n                                                        :label \"Derby 1 Strobe, 0-30Hz\"\n                                                        :range :variable}  ; TODO: add scale-fn?\n                                                    240 {:type  :strobe-sound\n                                                         :label \"Derby 1 Strobe Sound\"\n                                                         :range :variable})\n                                    (chan/functions :derby-rotation 13\n                                                    0 nil\n                                                    5 {:type  :derby-clockwise-slow-to-fast\n                                                       :label \"Derby 1 CW Slow>Fast\"\n                                                       :range :variable}\n                                                    128 nil\n                                                    134 {:type  :derby-counter-clockwise-slow-to-fast\n                                                         :label \"Derby 1 CCW Slow>Fast\"\n                                                         :range :variable})]}\n                        {:x 0.2 :y 0 :z 0 ; TODO: Measure and fine-tune location\n                         :channels [(chan/color 1 :red)\n                                    (chan/color 2 :green)\n                                    (chan/color 3 :blue)\n                                    (chan/color 4 :uv :label \"UV\" :hue (when mix-uv 270))\n                                    (chan/functions :par-dimmer-strobe 5\n                                                    0 {:type  :dimmer\n                                                       :label \"Par 1 Dimmer\"\n                                                       :range :variable}\n                                                    128 {:type  :strobe\n                                                         :label \"Par 1 Strobe Slow>Fast\"\n                                                         :range :variable}\n                                                    240 {:type  :strobe-sound\n                                                         :label \"Par 1 Strobe Sound\"\n                                                         :range :variable}\n                                                    250 {:type  :full-on\n                                                         :label \"Par 1 RGB 100%\"\n                                                         :range :fixed})]}\n                        {:x        -0.2 :y 0 :z 0 ; TODO: Measure and fine-tune location\n                         :channels [(chan/color 6 :red)\n                                    (chan/color 7 :green)\n                                    (chan/color 8 :blue)\n                                    (chan/color 9 :uv :label \"UV\" :hue (when mix-uv 270))\n                                    (chan/functions :par-dimmer-strobe 10\n                                                    0 {:type  :dimmer\n                                                       :label \"Par 2 Dimmer\"\n                                                       :range :variable}\n                                                    128 {:type  :strobe\n                                                         :label \"Par 2 Strobe Slow>Fast\"\n                                                         :range :variable}\n                                                    240 {:type  :strobe-sound\n                                                         :label \"Par 2 Strobe sound\"\n                                                         :range :variable}\n                                                    250 {:type  :full-on\n                                                         :label \"Par 2 RGB 100%\"\n                                                         :range :fixed})]}\n                        {:x -0.5 :y -0.05 :z 0 ; TODO: Measure and fine-tune location\n                         :channels [(chan/functions :derby-control 14\n                                                    0 nil\n                                                    25 {:type  :derby-red\n                                                        :label \"Derby 2 Red\"\n                                                        :range :variable}\n                                                    50 {:type  :derby-green\n                                                        :label \"Derby 2 Green\"\n                                                        :range :variable}\n                                                    75 {:type  :derby-blue\n                                                        :label \"Derby 2 Blue\"\n                                                        :range :variable}\n                                                    100 {:type  :derby-red-green\n                                                         :label \"Derby 2 RG\"\n                                                         :range :variable}\n                                                    125 {:type  :derby-red-blue\n                                                         :label \"Derby 2 RB\"\n                                                         :range :variable}\n                                                    150 {:type  :derby-green-blue\n                                                         :label \"Derby 2 GB\"\n                                                         :range :variable}\n                                                    175 {:type  :derby-red-green-blue\n                                                         :label \"Derby 2 RGB\"\n                                                         :range :variable}\n                                                    200 {:type  :derby-auto-single-colors\n                                                         :label \"Derby 2 Auto (1 color)\"\n                                                         :range :variable}\n                                                    225 {:type  :derby-auto-tfwo-colors\n                                                         :label \"Derby 2 Auto (2 colors)\"\n                                                         :range :variable})\n                                    (chan/functions :derby-strobe-speed 15\n                                                    0 nil\n                                                    10 {:type  :derby-strobe-rate-strobe-0-30-hz\n                                                        :label \"Derby 2 Strobe, 0-30Hz\"\n                                                        :range :variablepar-2-rgb-100}\n                                                    240 {:type  :derby-strobe-rate-strobe-to-sound\n                                                         :label \"Derby 2 Strobe Sound\"\n                                                         :range :variable})\n                                    (chan/functions :derby-rotation 16\n                                                    0 nil\n                                                    5 {:type  :derby-rotation-rotate-clockwise-slow-to-fast\n                                                       :label \"Derby 2 CW Slow>Fast\"\n                                                       :range :variable}\n                                                    128 nil\n                                                    134 {:type  :derby-rotation-rotate-counter-clockwise-slow-to-fast\n                                                         :label \"Derby 2 CCW Slow>Fast\"\n                                                         :range :variable})]}\n                        {:x 0.0 :y 0.25 :z 0 ; TODO: Measure and fine-tune location\n                         :channels [(chan/functions :laser-color 17\n                                                    0 nil\n                                                    40 {:type  :laser-red-on\n                                                        :label \"Laser Red\"\n                                                        :range :variable}\n                                                    80 {:type  :laser-green-on\n                                                        :label \"Laser Green\"\n                                                        :range :variable}\n                                                    120 {:type  :laser-red-green-on\n                                                         :label \"Laser RG\"\n                                                         :range :variable}\n                                                    160 {:type  :laser-red-on-green-strobe\n                                                         :label \"Laser RGs\"\n                                                         :range :variable}\n                                                    200 {:type  :laser-green-on-red-strobe\n                                                         :label \"Laser RsG\"\n                                                         :range :variable}\n                                                    240 {:type  :laser-red-green-alternate-strobe\n                                                         :label \"Laser RsGs\"\n                                                         :range :variable})\n                                    (chan/functions :laser-strobe 18\n                                                    0 nil\n                                                    10 {:type  :laser-strobe-strobe-speed-slow-to-fast\n                                                        :label \"Laser Strobe Slow>Fast\"\n                                                        :range :variable}\n                                                    240 {:type  :laser-strobe-strobe-to-sound\n                                                         :label \"Laser Strobe Sound\"\n                                                         :range :variable})\n                                    (chan/functions :laser-pattern 19\n                                                    0 nil\n                                                    5 {:type  :laser-clockwise-slow-to-fast\n                                                       :label \"Laser CW Slow>Fast\"\n                                                       :range :variable}\n                                                    128 nil\n                                                    134 {:type  :laser-counter-clockwise-slow-to-fast\n                                                         :label \"Laser CCW Slow>Fast\"\n                                                         :range :variable})]}\n                        {:x        0 :y 0.2 :z 0 ; TODO: Measure and fine-tune height?\n                         :channels [(chan/dimmer 21)]}  ; White strobe, cannot be used with channel 22\n                        {:x        0 :y 0.0 :z 0 ; TODO: Measure and fine-tune height?\n                         :channels [(chan/dimmer 22)]}]}))))  ; UV strobe, cannot be used with channel 21``\n\n(defn hurricane-1800-flex\n  \"[Hurricane 1800\n  Flex](https://www.chauvetdj.com/products/hurricane-1800-flex/)\n  fogger.\"\n  []\n  {:channels [(chan/functions :fog 1\n                              0 nil\n                              6 \"Fog\")]\n   :name \"Chauvet Hurricane 1800 Flex\"})\n\n(defn intimidator-scan-led-300\n  \"[Intimidator Scan LED\n  300](https://www.chauvetdj.com/products/intimidator-scan-led-300/)\n  compact scanner.\n\n  This fixture can be configured to use either 8 or 11 DMX channels.\n  If you do not specify a mode when patching it, `:11-channel` is\n  assumed; you can pass a value of `:8-channel` for `mode` if you are\n  using it that way.\n\n  The standard orientation to hang this fixture is with the Chauvet\n  logo and LED upright and facing the audience, but tilted up and away\n  from them at a 45 degree angle.\n\n  This was created by Afterglow from the QLC+ Fixture Definintion\n  (.qxf) file, and heavily revised by James Elliott.\n\n  The original fixture defintition was created by Craig Cudmore\n  using Q Light Controller Plus version 4.7.0 GIT.\n\n  QLC+ Fixture Type: Scanner.\"\n  ([]\n   (intimidator-scan-led-300 :11-channel))\n  ([mode]\n   (let [gobo-names [\"Pink Dots\" \"Purple Bubbles\" \"45 Adapter\" \"Nested Rings\" \"Rose\" \"Triangles\" \"Galaxy\"]]\n     (letfn [(build-color-wheel [channel]\n               (chan/functions :color channel\n                               0 \"Color Wheel Open\"\n                               7 (chan/color-wheel-hue \"yellow\")\n                               14 \"Color Wheel Pink\"\n                               21 (chan/color-wheel-hue \"green\")\n                               28 \"Color Wheel Peachblow\"\n                               35 \"Color Wheel Light Blue\"\n                               42 \"Color Wheel Kelly\"\n                               49 (chan/color-wheel-hue \"red\")\n                               56 (chan/color-wheel-hue \"blue\")\n                               64 \"Color Wheel White + Yellow\"\n                               71 \"Color Wheel Yellow + Pink\"\n                               78 \"Color Wheel Pink + Green\"\n                               85 \"Color Wheel Green + Peachblow\"\n                               92 \"Color Wheel Peachblow + Blue\"\n                               99 \"Color Wheel Blue + Kelly\"\n                               106 \"Color Wheel Kelly + Red\"\n                               113 \"Color Wheel Red + Blue\"\n                               120 \"Color Wheel Blue + White\"\n                               128 {:type :color-clockwise\n                                    :label \"Color Wheel Clockwise (slow->fast)\"\n                                    :var-label \"CW (slow->fast)\"\n                                    :range :variable}\n                               192 {:type :color-counterclockwise\n                                    :label \"Color Wheel Counterclockwise (slow->fast)\"\n                                    :var-label \"CCW (slow->fast)\"\n                                    :range :variable}))\n             (build-shutter [channel]\n               (chan/functions :shutter channel\n                               0 \"Shutter Closed\"\n                               4 \"Shutter Open\"\n                               8 {:type :strobe\n                                  :label \"Strobe\"\n                                  :range :variable}\n                               216 \"Shutter Open 2\"))\n             (build-gobo-wheel [channel]\n               (chan/functions :gobo channel\n                               (range 0 63 8) (build-gobo-entries false (concat [\"Open\"] gobo-names))\n                               (range 64 119 8) (build-gobo-entries true (reverse gobo-names))\n                               120 \"Gobo Open 2\"\n                               128 {:type :gobo-clockwise\n                                    :label \"Gobo Clockwise Speed\"\n                                    :var-label \"CW Speed\"\n                                    :range :variable}\n                               192 {:type :gobo-counterclockwise\n                                    :label \"Gobo Counterclockwise Speed\"\n                                    :var-label \"CCW Speed\"\n                                    :range :variable}))\n             (build-gobo-rotation [channel]\n               (chan/functions :gobo-rotation channel\n                               0 nil\n                               16 {:type :gobo-rotation-counterclockwise\n                                   :label \"Gobo Rotation Counterlockwise (slow->fast)\"\n                                   :var-label \"CCW (slow->fast)\"\n                                   :range :variable}\n                               128 {:type :gobo-rotation-clockwise\n                                    :label \"Gobo Rotation Clockwise (slow->fast)\"\n                                    :var-label \"CW (slow->fast)\"\n                                    :range :variable}\n                               240 :gobo-bounce))]\n       (merge {:name \"Chauvet Intimidator Scan LED 300\"\n               :pan-center 128 :pan-half-circle -256\n               :tilt-center 0 :tilt-half-circle -1024\n               :mode mode}\n              (case mode\n                :11-channel\n                {:channels [(chan/pan 1)\n                            (chan/tilt 2)\n                            (build-color-wheel 3)\n                            (build-shutter 4)\n                            (chan/dimmer 5)\n                            (build-gobo-wheel 6)\n                            (build-gobo-rotation 7)\n                            (chan/functions :prism 8\n                                            0 \"Prism Out\"\n                                            4 \"Prism In\")\n                            (chan/focus 9)\n                            (chan/functions :control 10\n                                            8 \"Blackout while moving Pan/Tilt\"\n                                            16 \"Disable Blackout while moving Pan/Tilt\"\n                                            24 \"Blackout while moving Color Wheel\"\n                                            32 \"Disable Blackout while moving Color Wheel\"\n                                            40 \"Blackout while moving Gobo Wheel\"\n                                            48 \"Disable Blackout while moving Gobo Wheel\"\n                                            56 \"Fast Movement\"\n                                            64 \"Disable Fast Movement\"\n                                            88 \"Disable all Blackout while moving\"\n                                            96 \"Reset Pan/Tilt\"\n                                            104 nil\n                                            112 \"Reset Color Wheel\"\n                                            120 \"Reset Gobo Wheel\"\n                                            128 nil\n                                            136 \"Reset Prism\"\n                                            144 \"Reset Focus\"\n                                            152 \"Reset All\"\n                                            160 nil)\n                            (chan/functions :control 11\n                                            0 nil\n                                            (range 8 135 16) \"Program\"\n                                            (range 136 255 16) :sound-active)]}\n                :8-channel\n                {:channels [(chan/pan 1)\n                            (chan/tilt 2)\n                            (build-color-wheel 3)\n                            (build-shutter 4)\n                            (build-gobo-wheel 5)\n                            (build-gobo-rotation 6)\n                            (chan/functions :prism 7\n                                            0 \"Prism Out\"\n                                            4 \"Prism In\")\n                            (chan/focus 8)]}))))))\n\n(defn intimidator-spot-led-150\n  \"[Intimidator Spot LED\n  150](https://www.chauvetdj.com/products/intimidator-spot-led-150/)\n  moving yoke.\n\n  This fixture can be configured to use either 6 or 11 DMX channels.\n  If you do not specify a mode when patching it, `:11-channel` is\n  assumed; you can pass a value of `:6-channel` for `mode` if you are\n  using it that way.\n\n  The standard orientation for this fixture is hung with the Chauvet\n  label and LED indicator upside-down and facing towards the audience.\n\n  This was created by Afterglow from the QLC+ Fixture Definintion\n  (.qxf) file, and heavily revised by James Elliott.\n\n  The original fixture defintition was created by Tavon Markov\n  using Q Light Controller Plus version 4.8.3 GIT.\n\n  QLC+ Fixture Type: Moving Head.\"\n  ([]\n   (intimidator-spot-led-150 :11-channel))\n  ([mode]\n   (let [gobo-names [\"Quotes\" \"Warp Spots\" \"4 Dots\" \"Sail Swirl\" \"Starburst\" \"Star Field\" \"Optical Tube\"\n                     \"Sun Swirl\" \"Star Echo\"]]\n     (letfn [(build-color-wheel [channel]\n               (chan/functions :color channel\n                               0 \"Color Wheel Open\"\n                               (range 6 47 6) (chan/color-wheel-hue [\"yellow\" \"magenta\" \"green\" \"red\"\n                                                                     \"cyan\" \"orange\" \"blue\"])\n                               48 \"Color Wheel Light Green\"\n                               54 (chan/color-wheel-hue 45 :label \"Color Wheel Amber\")\n                               64 \"Color Wheel White + Yellow\"\n                               70 \"Color Wheel Yellow + Magenta\"\n                               76 \"Color Wheel Magenta + Green\"\n                               82 \"Color Wheel Green + Red\"\n                               88 \"Color Wheel Red + Cyan\"\n                               94 \"Color Wheel Cyan + Orange\"\n                               100 \"Color Wheel Orange + Blue\"\n                               106 \"Color Wheel Blue + Light Green\"\n                               112 \"Color Wheel Light Green + Amber\"\n                               118 \"Color Wheel Amber + White\"\n                               128 {:type :color-clockwise\n                                    :label \"Color Wheel Clockwise (fast->slow)\"\n                                    :var-label \"CW (fast->slow)\"\n                                    :range :variable}\n                               192 {:type :color-counterclockwise\n                                    :label \"Color Wheel Counterclockwise (slow->fast)\"\n                                    :var-label \"CCW (fast->slow)\"\n                                    :range :variable}))\n             (build-shutter [channel]\n               (chan/functions :shutter channel\n                               0 \"Shutter Closed\"\n                               4 \"Shutter Open\"\n                               8 {:type :strobe\n                                  :label \"Strobe (0-20Hz)\"\n                                  :scale-fn (partial chan-fx/function-value-scaler 0 200)\n                                  :range :variable}\n                               216 \"Shutter Open 2\"))\n             (build-gobo-wheel [channel]\n               (chan/functions :gobo channel\n                               (range 0 63 6) (build-gobo-entries false (concat [\"Open\"] gobo-names))\n                               (range 64 121 6) (build-gobo-entries true (reverse gobo-names))\n                               122 \"Gobo Open 2\"\n                               128 {:type :gobo-clockwise\n                                    :label \"Gobo Clockwise Speed\"\n                                    :var-label \"CW Speed\"\n                                    :range :variable}\n                               192 {:type :gobo-counterclockwise\n                                    :label \"Gobo Counterclockwise Speed\"\n                                    :var-label \"CCW Speed\"\n                                    :range :variable}))]\n       (merge {:name \"Chauvet Intimidator Spot LED 150\"\n               :pan-center 170 :pan-half-circle -85\n               :tilt-center 42 :tilt-half-circle 192\n               :mode mode}\n              (case mode\n                :11-channel\n                {:channels [(chan/pan 1 3)\n                            (chan/tilt 2 4)\n                            (chan/fine-channel :pan-tilt-speed 5\n                                               :function-name \"Pan / Tilt Speed\"\n                                               :var-label \"P/T fast->slow\")\n                            (build-color-wheel 6)\n                            (build-shutter 7)\n                            (chan/dimmer 8)\n                            (build-gobo-wheel 9)\n                            (chan/functions :control-functions 10\n                                            0 nil\n                                            8 \"Blackout while moving Pan/Tilt\"\n                                            28 \"Blackout while moving Gobo Wheel\"\n                                            48 \"Disable blackout while Pan/Tilt / moving Gobo Wheel\"\n                                            68 \"Blackout while moving Color Wheel\"\n                                            88 \"Disable blackout while Pan/Tilt / moving Color Wheel\"\n                                            108 \"Disable blackout while moving Gobo/Color Wheel\"\n                                            128 \"Diable blackout while moving all options\"\n                                            148 \"Reset Pan\"\n                                            168 \"Reset Tilt\"\n                                            188 \"Reset Color Wheel\"\n                                            208 \"Reset Gobo Wheel\"\n                                            228 \"Reset All Channels\"\n                                            248 nil)\n                            (chan/functions :movement-macros 11\n                                            0 nil\n                                            (range 8 135 16) \"Program\"\n                                            (range 136 255 16) \"Sound Active\")]}\n                :6-channel\n                {:channels [(chan/pan 1)\n                            (chan/tilt 2)\n                            (build-color-wheel 3)\n                            (build-shutter 4)\n                            (chan/dimmer 5)\n                            (build-gobo-wheel 6)]}))))))\n\n(defn kinta-x\n  \"[Kinta\n  X](https://www.chauvetdj.com/news/kinta-x-becomes-an-led-powerhouse/)\n  derby effect.\"\n  []\n  {:channels [(chan/functions :control 1\n                              0 \"LEDs off\"\n                              15 \"LEDs on\"\n                              101 \"Auto\")\n              (chan/functions :rotation 2\n                              0 nil\n                              1 :counter-clockwise\n                              86 :clockwise\n                              171 :back-and-forth)]\n   :name \"Chauvet Kinta X\"})\n\n(defn led-techno-strobe\n  \"[LED Techno Strobe](https://www.chauvetdj.com/products/led-techno-strobe/)\n  strobe light.\"\n  []\n  {:channels [(chan/functions :control 1\n                              0 \"Intensity Control\"\n                              (range 30 209 30) \"Program\"\n                              210 :sound-active)\n              (chan/functions :strobe 2 0 nil\n                              1 :strobe)  ; TODO: Measure speed, add scale-fn\n              (chan/dimmer 3 :inverted-from 1)]\n   :name \"Chauvet LED Techno Strobe\"})\n\n(defn led-techno-strobe-rgb\n  \"[LED Techno Strobe RGB](https://www.chauvetdj.com/products/led-techno-strobe-rgb/)\n  color mixing strobe light.\n\n  This was created by Afterglow from the QLC+ Fixture Definintion\n  (.qxf) file, and revised by James Elliott.\n\n  The original fixture defintition was created by Davey D\n  using Q Light Controller Plus version 4.6.0.\n\n  QLC+ Fixture Type: Color Changer.\"\n  []\n  {:channels [(chan/functions :control 1\n                              0 \"RGB Control\"\n                              (range 25 224 25) \"Program\"\n                              225 :sound-active)\n              (chan/color 2 :red)\n              (chan/color 3 :green)\n              (chan/color 4 :blue)\n              (chan/functions :strobe 5 0 nil\n                              1 :strobe)  ; TODO: Measure speed, add scale-fn\n              (chan/dimmer 6 :inverted-from 0)]\n   :name \"Chauvet LED Techno Strobe RGB\"})\n\n(defn scorpion-storm-fx-rgb\n  \"[Scorpion Storm FX RGB](https://www.chauvetdj.com/products/scorpion-storm-fx-rgb/)\n   grid effect laser.\n\n  This fixture can be patched to use either 7 or 2 DMX channels. If\n  you do not specify a mode when patching it, `:7-channel` is assumed;\n  you can pass a value of `:2-channel` for `mode` if you are using it\n  that way. Although there are two different modes in which you can\n  patch it, its behavior is controlled by the value you send in\n  channel 1: If that value is between `0` and `50`, the laser responds\n  to all 7 channels as described by `:7-channel` mode; if channel 1 is\n  set to `51` or higher, it looks only at the first two channels, as\n  described by `:2-channel` mode.\n\n  This was created by Afterglow from the QLC+ Fixture Definintion\n  (.qxf) file, and revised by James Elliott.\n\n  The original fixture defintition was created by Frédéric Combe\n  using Q Light Controller Plus version 5.0.0 GIT.\n\n  QLC+ Fixture Type: Laser.\"\n  ([]\n   (scorpion-storm-fx-rgb :7-channel))\n  ([mode]\n   (merge {:name \"Chauvet Scorpion Storm FX RGB\"\n           :mode mode}\n          (case mode\n                :7-channel\n                {:channels [(chan/functions :control 1\n                                            0 \"DMX Mode\"\n                                            51 nil)\n                            (chan/functions :control 2\n                                            0 \"Blackout\"\n                                            5 \"Beam Red\"\n                                            16 \"Beam Green\"\n                                            26 \"Beam Blue\"\n                                            36 \"Beam Red Green\"\n                                            46 \"Beam Blue Green\"\n                                            56 \"Beam Red Blue\"\n                                            66 \"Beam Red Green Blue\"\n                                            76 \"Beam Red, Strobe Green\"\n                                            86 \"Beam Green, Strobe Blue\"\n                                            96 \"Beam Blue, Strobe Red\"\n                                            106 \"Alternate Red/Green\"\n                                            116 \"Alternate Green/Blue\"\n                                            126 \"Alternate Red/Blue\"\n                                            136 \"Beam Red Green, Strobe Blue\"\n                                            146 \"Beam Green Blue, Strobe Red\"\n                                            156 \"Beam Red Blue, Strobe Green\"\n                                            166 \"Beam Blue, Strobe Red Green\"\n                                            176 \"Beam Red, Strobe Green Blue\"\n                                            186 \"Beam Green, Strobe Red Blue\"\n                                            196 \"Beam Blue, Alternate Red/Green\"\n                                            206 \"Beam Red, Alternate Green/Blue\"\n                                            216 \"Beam Green, Alternate Red/Blue\"\n                                            226 \"Alternate Red/Green/Blue\")\n                            (chan/functions :strobe 3\n                                            0 nil\n                                            5 :strobe\n                                            255 \"Strobe Sound Active\")\n                            (chan/functions :control 4\n                                            0 \"Motor 1 Stop\"\n                                            5 :motor-1-clockwise\n                                            128 \"Motor 1 Stop 2\"\n                                            134 :motor-1-counterclockwise)\n                            (chan/functions :control 5\n                                            0 nil\n                                            5 :stutter-motor-1-mode-1\n                                            57 :stutter-motor-1-mode-2\n                                            113 :stutter-motor-1-mode-3\n                                            169 :stutter-motor-1-mode-4)\n                            (chan/functions :control 6\n                                            0 \"Motor 2 Stop\"\n                                            5 :motor-2-clockwise\n                                            128 \"Motor 2 Stop 2\"\n                                            134 :motor-2-counterclockwise)\n                            (chan/functions :control 7\n                                            0 nil\n                                            5 :stutter-motor-2-mode-1\n                                            57 :stutter-motor-2-mode-2\n                                            113 :stutter-motor-2-mode-3\n                                            169 :stutter-motor-2-mode-4)]}\n                :2-channel\n                {:channels [(chan/functions :control 1\n                                            0 nil\n                                            51 \"Auto fast\"\n                                            101 \"Auto slow\"\n                                            151 :sound-active\n                                            201 \"Random program\")\n                            (chan/functions :control 2\n                                            0 \"Beam Red\"\n                                            37 \"Beam Green\"\n                                            73 \"Beam Blue\"\n                                            109 \"Beam Red Green\"\n                                            145 \"Beam Green Blue\"\n                                            181 \"Beam Red Blue\"\n                                            217 \"Beam Red Green Blue\")]}))))\n\n(defn scorpion-storm-rgx\n  \"[Scorpion Storm RGX](https://www.chauvetdj.com/news/the-x-stands-for-extras-in-the-new-scorpion-storm-rgx/)\n  grid effect laser.\"\n  []\n  {:channels [(chan/functions :control 1\n                                       0 \"DMX Mode\"\n                                       20 \"Auto Fast Red\"\n                                       40 \"Auto Slow Red\"\n                                       60 \"Auto Fast Green\"\n                                       80 \"Auto Slow Green\"\n                                       100 \"Auto Fast Red Green\"\n                                       120 \"Auto Slow Red Green\"\n                                       140 :sound-active-red\n                                       160 :sound-active-green\n                                       180 :sound-active\n                                       200 \"Random\")\n                       (chan/functions :control 2\n                                       0 \"Blackout\"\n                                       5 \"Beam Red\"\n                                       29 \"Beam Green\"\n                                       57 \"Beam Red Green\"\n                                       85 \"Strobe Green\"\n                                       113 \"Strobe Red\"\n                                       141 \"Beam Red, Strobe Green\"\n                                       169 \"Beam Green, Strobe Red\"\n                                       198 \"Strobe Red Green\"\n                                       225 \"Alternate Red/Green\")\n                       (chan/functions :strobe 3\n                                       0 nil\n                                       5 :strobe\n                                       255 \"Strobe Sound Active\")\n                       (chan/functions :control 4\n                                       0 \"Stop\"\n                                       5 :beams-clockwise\n                                       128 \"Stop 2\"\n                                       134 :beams-counterclockwise)]\n   :name \"Chauvet Scorpion Storm RGX\"})\n\n(defn q-spot-160\n  \"Q Spot 160 moving yoke.\n\n  This fixture can be configured to use either 9 or 12 DMX channels.\n  If you do not specify a mode when patching it, `:12-channel` is\n  assumed; you can pass a value of `:9-channel` for `mode` if you are\n  using it that way.\n\n  The standard hanging orientation is with the Chauvet label and LED\n  panel upside-down and facing the house-right wall (the positive X\n  axis direction).\"\n  ([]\n   (q-spot-160 :12-channel))\n  ([mode]\n   (let [gobo-names [\"Splat\" \"Spot Sphere\" \"Fanned Squares\" \"Box\" \"Bar\" \"Blue Starburst\" \"Perforated Pink\"]]\n     (letfn [(build-color-wheel [channel]\n               (chan/functions :color channel\n                               0 \"Color Wheel Open\"\n                               (range 15 59 15) (chan/color-wheel-hue [\"red\" \"yellow\" \"green\"])\n                               60 \"Color Wheel pink\"\n                               (range 75 119 15) (chan/color-wheel-hue [\"blue\" \"orange\" \"magenta\"])\n                               120 \"Color Wheel Light Blue\"\n                               135 \"Color Wheel Light Green\"\n                               150 {:type :color-clockwise\n                                    :label \"Color Wheel Clockwise (slow->fast)\"\n                                    :var-label \"CW (slow->fast)\"\n                                    :range :variable}))\n             (build-shutter [channel]\n               (chan/functions :shutter channel\n                               0 \"Shutter Closed\"\n                               32 \"Shutter Open\"\n                               64 :strobe\n                               96 \"Shutter Open 2\"\n                               128 :pulse-strobe\n                               160 \"Shutter Open 3\"\n                               192 :random-strobe\n                               224 \"Shutter Open 4\"))\n             (build-gobo-wheel [channel]\n               (chan/functions :gobo channel\n                               (range 0 79 10) (build-gobo-entries false (concat [\"Open\"] gobo-names))\n                               (range 80 219 20) (build-gobo-entries true (reverse gobo-names))\n                               220 {:type :gobo-scroll\n                                    :label \"Gobo Scroll\"\n                                    :var-label \"Scroll Speed\"\n                                    :range :variable}))\n             (build-gobo-rotation [channel]\n               (chan/functions :gobo-rotation channel\n                               0 nil\n                               3 {:type :gobo-rotation-clockwise\n                                  :label \"Gobo Rotation Clockwise (slow->fast)\"\n                                  :var-label \"CW (slow->fast)\"\n                                  :range :variable}\n                               129 \"Gobo Rotation Stop\"\n                               133 {:type :gobo-rotation-counterclockwise\n                                    :label \"Gobo Rotation Counterlockwise (slow->fast)\"\n                                    :var-label \"CCW (slow->fast)\"\n                                    :range :variable}))\n             (build-control-channel [channel]\n               (chan/functions :control channel\n                               0 nil\n                               20 \"Blackout while moving Pan/Tilt\"\n                               40 \"Disable Blackout while moving Pan/Tilt\"\n                               60 \"Auto 1\"\n                               80 \"Auto 2\"\n                               100 \"Sound Active 1\"\n                               120 \"Sound Active 2\"\n                               140 \"Custom\"\n                               160 \"Test\"\n                               180 nil\n                               200 \"Reset\"\n                               220 nil))]\n       (merge {:name \"Chauvet Q Spot 160\"\n               :pan-center 85 :pan-half-circle 85\n               :tilt-center 218 :tilt-half-circle -180\n               :mode mode}\n              (case mode\n                :12-channel\n                {:channels [(chan/pan 1 2)\n                            (chan/tilt 3 4)\n                            (chan/fine-channel :pan-tilt-speed 5\n                                               :function-name \"Pan / Tilt Speed\"\n                                               :var-label \"P/T fast->slow\")\n                            (build-color-wheel 6)\n                            (build-gobo-wheel 7)\n                            (build-gobo-rotation 8)\n                            (chan/functions :prism 9 0 \"Prism Out\" 128 \"Prism In\")\n                            (chan/dimmer 10)\n                            (build-shutter 11)\n                            (build-control-channel 12)]}\n                :9-channel\n                {:channels [(chan/pan 1)\n                            (chan/tilt 2)\n                            (build-color-wheel 3)\n                            (build-gobo-wheel 4)\n                            (build-gobo-rotation 5)\n                            (chan/functions :prism 6 0 \"Prism Out\" 128 \"Prism In\")\n                            (chan/dimmer 7)\n                            (build-shutter 8)\n                            (build-control-channel 9)]}))))))\n\n(defn slimpar-hex3-irc\n  \"[SlimPAR HEX 3 IRC](https://www.chauvetdj.com/products/slimpar-hex-3-irc/)\n  six-color low-profile LED PAR.\n\n  This fixture can be configured to use either 6, 8 or 12 DMX\n  channels. If you do not specify a mode when patching it,\n  `:12-channel` is assumed; you can pass a value of `:6-channel` or\n  `:8-channel` for `mode` if you are using it that way.\n\n  When you pass a mode, you can also control whether the amber and UV\n  channels are mixed in when creating colors by passing a boolean\n  value with `:mix-amber` and `:mix-uv`. The default for each is\n  `true`.\"\n  ([]\n   (slimpar-hex3-irc :12-channel))\n  ([mode & {:keys [mix-amber mix-uv] :or {mix-amber true mix-uv true}}]\n   (assoc (case mode\n            :12-channel {:channels [(chan/dimmer 1) (chan/color 2 :red) (chan/color 3 :green) (chan/color 4 :blue)\n                                    (chan/color 5 :amber :hue (when mix-amber 45)) (chan/color 6 :white)\n                                    (chan/color 7 :uv :label \"UV\" :hue (when mix-uv 270))\n                                    (chan/functions :strobe 8 0 nil\n                                                    11 {:type :strobe\n                                                        :scale-fn (partial chan-fx/function-value-scaler 0.87 25)\n                                                        :label \"Strobe (0.87Hz->25Hz)\"})\n                                    (chan/functions :color-macros 9 0 nil 16 :color-macros)\n                                    (chan/functions :control 10 0 nil (range 11 200 50) \"Program\"\n                                                    201 :sound-active-6-color 226 :sound-active)\n                                    (chan/functions :program-speed 11 0 :program-speed)\n                                    (chan/functions :dimmer-mode 12 0 \"Dimmer Mode Manual\" 52 \"Dimmer Mode Off\"\n                                                    102 \"Dimmer Mode Fast\" 153 \"Dimmer Mode Medium\"\n                                                    204 \"Dimmer Mode Slow\")]}\n            :8-channel {:channels [(chan/dimmer 1) (chan/color 2 :red) (chan/color 3 :green) (chan/color 4 :blue)\n                                   (chan/color 5 :amber :hue (when mix-amber 45)) (chan/color 6 :white)\n                                   (chan/color 7 :uv :label \"UV\" :hue (when mix-uv 270))\n                                   (chan/functions :strobe 8 0 nil\n                                                   11 {:type :strobe\n                                                       :scale-fn (partial chan-fx/function-value-scaler 0.87 25)\n                                                       :label \"Strobe (0.87Hz->25Hz)\"})]}\n            :6-channel {:channels [(chan/color 1 :red) (chan/color 2 :green) (chan/color 3 :blue)\n                                   (chan/color 4 :amber :hue (when mix-amber 45)) (chan/color 5 :white)\n                                   (chan/color 6 :uv :label \"UV\" :hue (when mix-uv 270))]})\n          :name \"Chauvet SlimPAR Hex 3 IRC\"\n          :mode mode)))\n"
  },
  {
    "path": "src/afterglow/fixtures/qxf.clj",
    "content": "(ns afterglow.fixtures.qxf\n  \"Functions to work with Fixture Definition Files from\n  the [QLC+](http://www.qlcplus.org/) open-source lighting controller\n  project. While these do not contain all of the information Afterglow\n  needs to fully control a fixture with its geometric reasoning, they\n  can form a good starting point and save you a lot of tedious\n  capability translation. You can find the available `.qxf` files\n  on [Github](https://github.com/mcallegari/qlcplus/tree/master/resources/fixtures).\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.web.layout]  ; To set up the Selmer template path\n            [camel-snake-kebab.core :as csk]\n            [clojure.data.zip.xml :as zip-xml]\n            [clojure.java.io :as io]\n            [clojure.xml :as xml]\n            [clojure.zip :as zip]\n            [selmer.filter-parser :refer [compile-filter-body]]\n            [selmer.filters :as filters]\n            [selmer.parser :as parser]\n            [taoensso.timbre :as timbre]))\n\n(defn sanitize-name\n  \"Removes non-alphanumeric characters in a string, then turns it into\n  a suitable Clojure identifier.\"\n  [s]\n  (-> s\n      (clojure.string/replace #\"[^a-zA-Z0-9]+\" \" \")\n      csk/->kebab-case))\n\n(filters/add-filter! :kebab csk/->kebab-case)\n(filters/add-filter! :sanitize sanitize-name)\n\n(defn- define-color-channel\n  \"If the supplied channel specification map is a recognizable color\n  channel, emit a function which defines it at the specified offset.\"\n  [specs offset fine-offset]\n  (when (and (= \"Intensity\" (:group specs)) (:color specs))\n    (let [color (keyword (sanitize-name (:color specs)))]\n      (str \"(chan/color \" offset \" \" color\n           (when fine-offset (str \" :fine-offset \" fine-offset)) \")\"\n           (when-not (#{:red :green :blue :white} color) \"  ; TODO: add :hue key if you want to color mix this\")))))\n\n(defn- define-dimmer-channel\n  \"If the supplied channel specification map seems to be a dimmer\n  channel, emit a function which defines it at the specified offsets.\"\n  [specs offset fine-offset]\n  (when (and (= \"Intensity\" (:group specs)) (re-find #\"(?i)dimmer\" (:name specs)))\n    (str \"(chan/dimmer \" offset (when fine-offset (str \" :fine-offset \" fine-offset)) \")\")))\n\n(defn- define-named-channel\n  \"If the supplied channel specification map seems to be another type\n  we have a special name for, emit a function which defines it at the\n  specified offsets.\"\n  [specs offset fine-offset type-name]\n  (when (re-find (re-pattern (str \"(?i)\" type-name)) (:name specs))\n    (str \"(chan/\" type-name \" \" offset (when fine-offset (str \" \" fine-offset)) \")\")))\n\n(defn- define-pan-tilt-channel\n  \"If the supplied channel specification map seems to be a pan or tilt\n  channel, emit a function which defines it at the specified offsets.\"\n  [specs offset fine-offset]\n  (when (#{\"Pan\" \"Tilt\"} (:group specs))\n    (str \"(chan/\" (clojure.string/lower-case (:group specs)) \" \" offset\n         (when fine-offset (str \" \" fine-offset)) \")\")))\n\n(defn- define-single-function-channel\n  \"If the supplied channel specification map contains a single\n  function using the entire range, emit a function which defines it at\n  the specified offsets. If it is one of the special kinds of channels\n  we recognize, use the corresponding generator.\"\n  [specs offset fine-offset]\n  (let [caps (:capabilities specs)]\n    (when (and (= 1 (count caps)) (zero? (:min (first caps))) (= 255 (:max (first caps))))\n      (or (define-color-channel specs offset fine-offset)\n          (define-dimmer-channel specs offset fine-offset)\n          (define-pan-tilt-channel specs offset fine-offset)\n          (some (partial define-named-channel specs offset fine-offset) [\"focus\" \"frost\" \"iris\" \"zoom\"])\n          (str \"(chan/fine-channel \" (keyword (sanitize-name (:name specs))) \" \" offset\n               (when fine-offset (str \" :fine-offset \" fine-offset))\n               \"\\n                                 :function-name \\\"\" (:name specs)\n               \"\\\"\\n                                 :var-label \\\"\" (:label (first caps)) \"\\\")\")))))\n\n(defn- check-capabilities\n  \"Makes sure a capability list is sorted in increasing order and has\n  no gaps, adding nil sections for any unused ranges, and adding\n  trailing numbers to make all labels unique if needed.\"\n  [caps]\n  (loop [remaining (sort-by :min caps)\n         last-end -1\n         labels {}\n         result []]\n    (if (empty? remaining)\n      (if (< last-end 255)  ; Fill in final gap\n        (conj result {:min (inc last-end) :max 255})\n        result)\n      (let [current (first remaining)\n            adjusted (if (< (inc last-end) (:min current))  ; Fill in a gap in capabilities\n                       (conj result {:min (inc last-end) :max (dec (:min current))})\n                       result)\n            label (:label current)\n            label-count (when label (inc (get labels (:label current) 0)))\n            unique (if (and label (> label-count 1))\n                     (assoc current :label (str label \" \" label-count))\n                     current)\n            updated-labels (if label (assoc labels label label-count) labels)]\n        (recur (rest remaining) (:max current) updated-labels (conj adjusted unique))))))\n\n(defn- expand-capability\n  \"Returns an Afterglow function specification corresponding to a\n  QLC+ capability range.\"\n  [cap prefix]\n  (str \"\\n\" (clojure.string/join (repeat 30 \" \")) (:min cap)\n       (if (some? (:label cap))\n         (str \" {:type \" (keyword (sanitize-name (str prefix (:label cap))))\n              \"\\n\" (clojure.string/join (repeat (+ 32 (count (str (:min cap)))) \" \")) \":label \\\"\" (:label cap)\n              \"\\\"\\n\" (clojure.string/join (repeat (+ 32 (count (str (:min cap)))) \" \")) \":range :variable}\")\n         \" nil\")))\n\n(defn- define-channel\n  \"Generates a function call which defines the specified\n  channel (given its specification map), at the specified offsets.\"\n  [specs offset fine-offset]\n  (or (define-single-function-channel specs offset fine-offset)\n      (str \"(chan/functions \" (keyword (sanitize-name (:name specs))) \" \" offset\n           (clojure.string/join (for [c (check-capabilities (:capabilities specs))]\n                                  (expand-capability c (str (:name specs) \" \")))) \")\")))\n\n(defn- channel-tag\n  \"A Selmer custom tag that generates a channel definition at a\n  specified offset and optional fine-offset, looking up the channel\n  specification by name.\"\n  [args context-map]\n  (let [[chan-expr] args\n        chan-fn (compile-filter-body chan-expr false)\n        [offset channel-name fine-offset] (chan-fn context-map)\n        found (filter #(= channel-name (:name %)) (:channels context-map))]\n    (case (count found)\n      0 (throw (IllegalStateException. (str \"Could not find a channel named \" channel-name)))\n      1 (define-channel (first found) offset fine-offset)\n      (throw (IllegalStateException. (str \"Found more than one channel named \" channel-name))))))\n\n(parser/add-tag! :channel channel-tag)\n\n(defn- qxf-creator->map\n  \"Builds a map containing the creator information from a QLC+ fixture\n  definition.\"\n  [creator]\n  {:name (zip-xml/xml1-> creator :Name zip-xml/text)\n   :version (zip-xml/xml1-> creator :Version zip-xml/text)\n   :author (zip-xml/xml1-> creator :Author zip-xml/text)})\n\n(defn- qxf-capability->map\n  \"Builds a map containing a channel specification from a QLC+ fixture\n  definition.\"\n  [c]\n  {:min (Integer/valueOf (zip-xml/attr c :Min))\n   :max (Integer/valueOf (zip-xml/attr c :Max))\n   :label (zip-xml/text c)})\n\n(defn- qxf-channel->map\n  \"Builds a map containing a channel specification from a QLC+ fixture\n  definition.\"\n  [ch]\n  (let [color (zip-xml/xml1-> ch :Colour zip-xml/text)]\n    (merge {:name (zip-xml/attr ch :Name)\n            :group (zip-xml/xml1-> ch :Group zip-xml/text)\n            :byte (Integer/valueOf (zip-xml/attr (zip-xml/xml1-> ch :Group) :Byte))\n            :capabilities (mapv qxf-capability->map (zip-xml/xml-> ch :Capability))}\n           (when color {:color color}))))\n\n(defn- qxf-channnel-assigment->vector\n  \"Builds a vector containing the offset at which a channel exists in\n  a mode and the channel name. Offsets are one-based, to parallel\n  fixture manuals. In other words, the DMX address assigned to the\n  fixture corresponds to offset 1, the next address to offset 2, and\n  so on.\"\n  [a]\n  [(inc (Integer/parseInt (zip-xml/attr a :Number))) (zip-xml/text a)])\n\n(defn- qxf-head->vector\n  \"Builds a vector containing the channel offsets belonging to a\n  single head.\"\n  [h]\n  (mapv #(inc (Integer/parseInt %)) (zip-xml/xml-> h :Channel zip-xml/text)))\n\n(defn- qxf-mark-pan-tilt\n  \"Adds flags to a fixture or head when its channel map includes pan\n  or tilt channels.\"\n  [channel-specs h]\n  (let [groups (set (map :group (map #(get channel-specs (second %)) (:channels h))))]\n    (merge h\n           (when (groups \"Pan\") {:has-pan-channel true})\n           (when (groups \"Tilt\") {:has-tilt-channel true}))))\n\n(defn- potential-pair?\n  \"Check whether a pair of channel specs could potentially be a pair\n  controlling two bytes of the same value. Since QLC+ doesn't make\n  this explicit the way Afterglow does, be conservative.\"\n  [spec-1 spec-2]\n  (and\n   (not= spec-1 spec-2)\n   (not= (:byte spec-1) (:byte spec-2))\n   (= (:group spec-1) (:group spec-2))\n   (case (:group spec-1)\n     (\"Pan\" \"Tilt\") true\n     \"Intensity\" (or (= (:color spec-1) (:color spec-2))\n                     (and (re-find #\"(?i)dimmer\" (:name spec-1))\n                          (re-find #\"(?i)dimmer\" (:name spec-2))))\n     false)))\n\n\n(defn- paired-channel\n  \"Try to identify a channel which is paired as two bytes controlling\n  a single value. Since QLC+ does not make this explicit the way\n  Afterglow does, we can't be certain, so be a bit conservative. If\n  we find a single potential match, return its name.\"\n  [name related-specs]\n  (let [specs (get related-specs name)\n        candidates (filter (partial potential-pair? specs) (vals related-specs))]\n    (when (= 1 (count candidates))\n      (:name (first candidates)))))\n\n(defn- merge-fine-channels\n  \"Try to identify any channels which are paired as two bytes\n  controlling a single value. QLC+ does not make this explicit, like\n  Afterglow does, so this is not going to be perfect. Takes the map of\n  all channel specifications found in the QXF file, as well as the set\n  which are being mapped in the current mode and perhaps head; that\n  narrowing of focus can hopefully reduce ambiguity.\"\n  [channel-specs channels]\n  (let [relevant-specs (select-keys channel-specs (map second channels))\n        offsets (into {} (for [[offset name] channels] [name offset]))\n        merged (filter identity (for [[offset name] channels]\n                                  (if-let [paired-name (paired-channel name relevant-specs)]\n                                    (let [specs (get relevant-specs name)]\n                                      (when (zero? (:byte specs))\n                                        [offset name (get offsets paired-name)]))\n                                    [offset name])))]\n    (vec (sort-by first merged))))\n\n(defn- qxf-process-heads\n  \"Extracts any head-specific channels from a QLC+ mode, given a\n  sequence of Head nodes and the vector of mode channel assignments,\n  then tries to merge any fine channels found in the resulting smaller\n  channel groupings.\"\n  ([heads channel-map channel-specs]\n   ;; Kick off recursive arity with an empty response vector\n   (qxf-process-heads heads channel-map channel-specs []))\n\n  ([remaining-heads remaining-channel-map channel-specs results]\n   ;; Recursive head processing\n   (if (empty? remaining-heads)\n     [results (merge-fine-channels channel-specs remaining-channel-map)] ; Finished, return results\n     ;; Process the next head\n     (loop [head-channel-numbers (sort (qxf-head->vector (first remaining-heads)))\n            head-channel-result []\n            channels-left remaining-channel-map]\n       (if (empty? head-channel-numbers)  ; Finished processing this head\n         (let [merged-channels (merge-fine-channels channel-specs head-channel-result)]\n           (qxf-process-heads (rest remaining-heads) channels-left channel-specs\n                              (conj results (qxf-mark-pan-tilt channel-specs {:channels merged-channels}))))\n         (let [current (first head-channel-numbers)]\n           (recur (rest head-channel-numbers)\n                  (conj head-channel-result [current (get channels-left current)])\n                  (dissoc channels-left current))))))))\n\n(defn- qxf-mode->map\n  \"Builds a map containing a mode specification from a QLC+ fixture\n  definition. Currently ignores the Physical documentation.\"\n  [channel-specs m]\n  (let [channel-specs (into {} (for [spec channel-specs]  ; Turn specs into a map for efficient searching\n                                 [(:name spec) spec]))\n        all-channels (mapv qxf-channnel-assigment->vector (zip-xml/xml-> m :Channel))\n        channel-map (into {} all-channels)\n        [heads other-channels] (qxf-process-heads (zip-xml/xml-> m :Head) channel-map channel-specs)]\n    (qxf-mark-pan-tilt channel-specs {:name (zip-xml/attr m :Name)\n                                      :channels other-channels\n                                      :heads heads})))\n\n(defn translate-definition\n  \"Converts a map read by [[convert-qxf]] into an Afterglow fixture\n  definition.\"\n  [qxf]\n  (parser/render-file \"fixture-definition.clj.template\" qxf))\n\n(defn parse-qxf\n  \"Read a fixture definition file in the format (.qxf) used by\n  [QLC+](http://www.qlcplus.org/), and create a map from which it can\n  conveniently be translated into an Afterglow fixture definition.\"\n  [source]\n  (let [doc (xml/parse source)\n        root (zip/xml-zip doc)\n        expected-xml #{\"http://qlcplus.sourceforge.net/FixtureDefinition\" \"http://www.qlcplus.org/FixtureDefinition\"}]\n    (when-not (= (:tag doc) :FixtureDefinition)\n      (throw (Exception. \"Root element is not FixtureDefinition\")))\n    (when-not (expected-xml (get-in doc [:attrs :xmlns]))\n      (throw (Exception.  \"File does not use a supported XML Namespace, expecting one of:\"\n                          (clojure.string/join \", \" expected-xml))))\n    (let [channels (mapv qxf-channel->map (zip-xml/xml-> root :Channel))]\n      {:creator (qxf-creator->map (zip-xml/xml1-> root :Creator))\n       :manufacturer (zip-xml/text (zip-xml/xml1-> root :Manufacturer))\n       :model (zip-xml/text (zip-xml/xml1-> root :Model))\n       :type (zip-xml/text (zip-xml/xml1-> root :Type))\n       :channels channels\n       :modes (mapv (partial qxf-mode->map channels) (zip-xml/xml-> root :Mode))\n       :has-pan-tilt (some? (some #(#{\"Pan\" \"Tilt\"} (:group %)) channels))\n       :open-curly \"{\"})))\n\n(defn convert-qxf\n  \"Read a fixture definition file in the format (.qxf) used by\n  [QLC+](http://www.qlcplus.org/), and write a Clojure file based on\n  it that can be used as the starting point of an Afterglow fixture\n  definition. Returns an exit status and message for the user.\"\n  [path]\n  (let [source (.getCanonicalFile (io/file path))\n        qxf (parse-qxf source)\n        dest (io/file (.getParent source) (str (csk/->kebab-case (:model qxf)) \".clj\"))]\n    (cond\n      (.exists dest) [1 (str \"Will not replace existing file \" (.getCanonicalPath dest))]\n      (not (.canWrite (.getParentFile dest))) [1 (str \"Cannot write to \" (.getCanonicalPath dest))]\n      :else (do\n              (spit dest (translate-definition qxf))\n              [0 (str \"Translated fixture definition written to \" (.getCanonicalPath dest))]))))\n\n;; These functions were used to help analyze the contents of all QLC+ fixture definitions.\n;; They are left here in case the format changes or expands in the future and they become\n;; useful again, either directly, or as examples.\n\n(def ^:private qlc-fixtures-path\n  \"The directory in which all the QLC+ fixture definitions can be found. You will need to set this.\"\n  \"/Users/jim/git/qlcplus/resources/fixtures\")\n\n(defn- qlc-fixture-definitions\n  \"Returns a sequence of all QLC+ fixture definitions.\"\n  []\n  (let [files (file-seq (clojure.java.io/file qlc-fixtures-path))]\n    (filter #(.endsWith (.getName %) \".qxf\") files)))\n\n(defn- qlc-fixture-channel-values\n  \"Returns the set of distinct values found under a particular keyword\n  in any channel in a fixture definition.\"\n  [k f]\n  (reduce conj #{} (map k (:channels (parse-qxf f)))))\n\n(defn- qlc-gather-groups\n  \"Find all the different channel group values in the QLC fixture\n  definitions.\"\n  []\n  (let [files (file-seq (clojure.java.io/file qlc-fixtures-path))]\n    (reduce clojure.set/union (map (partial qlc-fixture-channel-values :group) (qlc-fixture-definitions)))))\n\n(defn- qlc-gather-bytes\n  \"Find all the different channel byte values in the QLC fixture\n  definitions.\"\n  []\n  (let [files (file-seq (clojure.java.io/file qlc-fixtures-path))]\n    (reduce clojure.set/union (map (partial qlc-fixture-channel-values :byte) (qlc-fixture-definitions)))))\n"
  },
  {
    "path": "src/afterglow/fixtures.clj",
    "content": "(ns afterglow.fixtures\n  \"Utility functions common to fixture definitions.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as chan]))\n\n(defn- build-function-map\n  \"Gathers all the functions defined on the channels a fixture or head\n  into a map indexed by the function name which references the channel\n  and function specs.\"\n  [fixture-or-head]\n  (into {} (apply concat (for [c (:channels fixture-or-head)]\n                           (for [f (:functions c)]\n                             [(:type f) [c f]])))))\n\n(defn index-functions\n  \"Associates function maps with the fixture and all its heads, for\n  easy lookup by function-oriented effects.\"\n  [fixture]\n  (update-in (assoc fixture :function-map (build-function-map fixture))\n             [:heads]\n             #(map (fn [head] (assoc head :function-map (build-function-map head))) %)))\n\n(defn- build-color-wheel-hue-map\n  \"Gathers all functions which assign a color wheel hue on a fixture\n  or head into a sorted map indexed by the hue which references the\n  channel and function specs.\"\n  [fixture-or-head]\n  (into (sorted-map) (apply concat (for [c (:channels fixture-or-head)]\n                                     (for [f (filter :color-wheel-hue (:functions c))]\n                                       [(:color-wheel-hue f) [c f]])))))\n\n(defn index-color-wheel-hues\n  \"Associates color wheel hue maps with the fixture and all its heads,\n  for easy lookup when assigning color at the end of a color effect\n  chain.\"\n  [fixture]\n  (update-in (assoc fixture :color-wheel-hue-map (build-color-wheel-hue-map fixture))\n             [:heads]\n             #(map (fn [head] (assoc head :color-wheel-hue-map (build-color-wheel-hue-map head))) %)))\n\n(defn printable\n  \"Strips a mapped fixture (or fixture list) of keys which make it a pain to print,\n  such as the back links from the heads to the entire fixture, and the function\n  maps.\"\n  [fixture-or-fixture-list]\n  (if (sequential? fixture-or-fixture-list)\n    (map (fn [fixture] (update-in (dissoc fixture :function-map) [:heads]\n                                  #(map (fn [head] (dissoc head :fixture :function-map)) %)))\n         fixture-or-fixture-list)\n    (printable [fixture-or-fixture-list])))\n\n(defn visualizer-relevant\n \"Returns all the fixtures or heads which might appear in the\n visualizer. If the fixture or head has an  explicit\n :visualizer-visible boolean, that is honored, otherwise it is assumed\n that fixtures without heads are themselves relevant, while for\n fixtures with heads, only the heads are relevant.\"\n [fixtures-or-heads]\n (mapcat #(if-let [heads (seq (:heads %))]\n         (concat (visualizer-relevant heads)\n                 (when (:visualizer-visible %) [%]))\n         (when (:visualizer-visible % true) [%]))\n      fixtures-or-heads))\n\n(defn generic-dimmer\n  \"A fixture definition where a single channel controls the power level\n  of a socket to which an incandescent light source can be connected.\n  If you are using a product such as the [Chauvet\n  DMX-4](https://www.chauvetdj.com/products/dmx-4/), its channels can\n  be patched as four of these, or four [[generic-switch]], or some\n  combination.\"\n  []\n  {:channels [(chan/dimmer 1)]\n   :name \"Generic dimmer\"})\n\n(defn generic-switch\n  \"A fixture definition where a single channel turns on or off the power\n  at a socket to which an incandescent light source or other\n  non-DMX-enabled equipment can be connected. If you are using a\n  product such as the [Chauvet\n  DMX-4](https://www.chauvetdj.com/products/dmx-4/), its channels can\n  be patched as four of these, or four [[generic-dimmer]], or some\n  combination.\"\n  []\n  {:channels [(chan/functions :switch 1 0 \"off\" 1 nil 255 \"on\")]\n   :name \"Generic switch\"})\n"
  },
  {
    "path": "src/afterglow/init.clj",
    "content": "(ns afterglow.init\n  \"This namespace is the context in which any init-files specified on\n  the command line will be loaded during startup, in case they forget\n  to establish their own namespaces.\"\n  (:require [afterglow.show-context :refer [*show* set-default-show!]]))\n"
  },
  {
    "path": "src/afterglow/midi.clj",
    "content": "(ns afterglow.midi\n  \"Handles MIDI communication, including syncing a show metronome to MIDI clock pulses.\"\n  (:require [clojure.reflect]\n            [afterglow.rhythm :as rhythm]\n            [amalloy.ring-buffer :refer [ring-buffer]]\n            [clojure.math.numeric-tower :as math]\n            [overtone.at-at :refer [now]]\n            [overtone.midi :as midi]\n            [taoensso.timbre :as timbre])\n  (:import [java.io InputStream]\n           [java.util.concurrent LinkedBlockingDeque]\n           [java.util.regex Pattern]\n           [javax.sound.midi MidiDevice MidiDevice$Info MidiUnavailableException]))\n\n(def ^:private max-clock-intervals\n  \"How many MIDI clock pulses and interval averages should be kept\n  around for BPM calculation?\"\n  30)\n\n(def ^:private min-clock-intervals\n  \"How many MIDI clock pulses are needed in order to start attempting\n  BPM calculation?\"\n  12)\n\n(def ^:private max-clock-lag\n  \"How many ms is too long to wait between MIDI clock pulses?\"\n  150)\n\n(def ^:private max-tempo-taps\n  \"How many tempo taps should be kept around for averaging?\"\n  4)\n\n(def ^:private max-tempo-tap-lag\n  \"How long is too long for a tap to be considered part of\n  establishing a tempo?\"\n  2000)\n\n(defonce ^{:private true\n           :doc \"All currently available MIDI input ports, as a map\n  whose keys are the implementing `javax.sound.midi.MidiDevice` and\n  whose values are the corresponding `:midi-device` map returned by\n  `overtone.midi`.\"}\n  midi-inputs (atom {}))\n\n(defonce ^{:private true\n           :doc \"All currently available MIDI output ports, as a map\n  whose keys are the implementing `javax.sound.midi.MidiDevice` and\n  whose values are the corresponding `:midi-device` map returned by\n  `overtone.midi`.\"}\n  midi-outputs (atom {}))\n\n(defonce ^{:private true\n           :doc \"Functions to be called when a new device appears in\n  the MIDI environment. They will be passed a single argument, the\n  `:midi-device` map from `overtone.midi` representing the new\n  device.\"} new-device-handlers\n  (atom #{}))\n\n(defn same-device?\n  \"Checks whether two `:midi-device` maps seem to refer to the same\n  device, in a slightly more efficient way than comparing the entire\n  map.\"\n  [a b]\n  (= (:info a) (:info b)))\n\n(defn add-new-device-handler!\n  \"Add a function to be called whenever a new device appears in the\n  MIDI environment. It will be passed a single argument, the\n  `:midi-device` map from `overtone.midi` representing the new device.\n  It must return quickly so as not to stall the delay of other MIDI\n  events; lengthy operations must be performed on another thread.\"\n  [f]\n  {:pre [(ifn? f)]}\n  (swap! new-device-handlers conj f))\n\n(defn remove-new-device-handler!\n  \"Stop calling the specified function to be called whenever a new\n  device appears in the MIDI environment.\"\n  [f]\n  {:pre [(ifn? f)]}\n  (swap! new-device-handlers disj f))\n\n(defonce ^{:private true\n           :doc \"Functions to be called when a device disappears from\n  the MIDI environment. Keys are the `javax.sound.midi.MidiDevice`\n  whose departure is of interest, and values are a set of functions to\n  be called if and when that device ceases to exist. They will be\n  called with no arguments.\"}\n  disconnected-device-handlers (atom {}))\n\n(defn add-disconnected-device-handler!\n  \"Add a function to be called whenever the specified device\n  disappears from the MIDI environment. The `device` argument is a\n  `:midi-device` map from `overtone.midi` representing device whose\n  removal is of interest. The function must return quickly so as not\n  to stall the delay of other MIDI events; lengthy operations must be\n  performed on another thread.\"\n  [device f]\n  {:pre [(= (type device) :midi-device) (ifn? f)]}\n  (swap! disconnected-device-handlers #(update-in % [(:info device)] clojure.set/union #{f})))\n\n(defn remove-disconnected-device-handler!\n  \"No longer call the specified function if specified device\n  disappears from the MIDI environment. The `device` argument is a\n  `:midi-device` map from `overtone.midi` representing device whose\n  removal is no longer of interest.\"\n  [device f]\n  {:pre [(= (type device) :midi-device) (ifn? f)]}\n  (swap! disconnected-device-handlers #(update-in % [(:info device)] disj f)))\n\n(defonce ^:private ^{:doc \"The queue used to hand MIDI events from the\n  extension thread to our world, since there seem to be classloader\n  compatibility issues, and the Java3d classes are not available to\n  threads that are directly dispatching MIDI events. Although we\n  allocate a capacity of 100 elements, it is expected that the queue\n  will be drained much more quickly than events arrive, and so it will\n  almost always be empty.\n\n  It's possible this queue is no longer necessary since embedding\n  CoreMidi4j into Afterglow directly, rather than using it as an\n  extension, but it may still be true that the CoreMidi4j threads have\n  an inadequate classloader, and we are also using the queue to report\n  MIDI environment changes, and... it works, so for now I'm leaving it\n  alone.\"}\n  midi-queue\n  (LinkedBlockingDeque. 100))\n\n(defonce ^:private ^{:doc \"The thread used to hand MIDI events from\n  the extension thread to our world, since there seem to be\n  classloader compatibility issues, and the Java3d classes are not\n  available to threads that are directly dispatching MIDI events.\"}\n  midi-transfer-thread\n  (atom nil))\n\n(defonce ^{:private true\n           :doc \"The metronomes which are being synced to MIDI clock\n  pulses. A map whose keys are the `MidiDevice.Info` on which clock\n  pulses are being received, and whose values are in turn maps whose\n  keys are the metronomes being synced to pulses from that device, and\n  whose values are the sync function to call when each pulse is\n  received.\"}\n  synced-metronomes (atom {}))\n\n(defonce ^{:private true\n           :doc \"Functions to be called when MIDI Controller Change\n  messages arrive from particular input ports. A set of nested maps\n  whose keys are the `MidiDevice.Info` on which the message should\n  be watched for, the channel to watch, and the controller number to\n  watch for. The values are sets of functions to be called with each\n  matching message.\"}\n  control-mappings (atom {}))\n\n(defonce ^{:private true\n           :doc \"Functions to be called when MIDI Note messages arrive\n  from particular input ports. A set of nested maps whose keys are the\n  `MidiDevice.Info` on which the message should be watched for, the\n  channel to watch, and the note number to watch for. The values are\n  sets of functions to be called with each matching message.\"}\n  note-mappings (atom {}))\n\n(defonce ^{:private true\n           :doc \"Functions to be called when MIDI Aftertouch\n  (polyphonic key pressure) messages arrive from particular input\n  ports. A set of nested maps whose keys are the `MidiDevice.Info`\n  on which the message should be watched for, the channel to watch,\n  and the note number to watch for. The values are sets of functions\n  to be called with each matching message.\"}\n  aftertouch-mappings (atom {}))\n\n(defonce ^{:private true\n           :doc \"Functions to be called when MIDI System Exclusive\n  messages arrive from particular input ports. A map whose keys are\n  the `MidiDevice.Info` on which the message should be watched for.\n  The values are sets of functions to be called with each matching\n  message.\"} sysex-mappings (atom {}))\n\n(defonce ^{:private true\n           :doc \"Functions to be called when any MIDI message is\n  received from a specific device. A map whose keys are the\n  `MidiDevice.Info` on which the message should be watched for, and\n  whose values are sets of functions to be called with each matching\n  message.\"}\n  device-mappings (atom {}))\n\n(defonce ^{:private true\n           :doc \"Functions to be called when any MIDI message at all\n  is received.\"}\n  global-handlers (atom #{}))\n\n(defn add-global-handler!\n  \"Add a function to be called whenever any MIDI message is received.\n  The function will be called with the message, and must return\n  quickly, so as to not block delivery to other recipients.\"\n  [f]\n  {:pre [(ifn? f)]}\n  (swap! global-handlers conj f))\n\n(defn remove-global-handler!\n  \"Remove a function that was being called whenever any MIDI message is\n  received.\"\n  [f]\n  (swap! global-handlers disj f))\n\n(defn- run-message-handler\n  \"Invokes a registered MIDI message handler function with an incoming\n  message that has been identified as appropriate to send to it. If an\n  exception is thrown during that invocation, responds appropriately,\n  including shutting down the message handler thread if it was\n  interrupted. This is done by setting the `running` atom to `false`.\"\n  [handler msg running]\n  (try\n    ;; TODO: This is not really safe because if the handler blocks it ties up all future\n    ;;       MIDI dispatch. Should do in a future with a timeout? Don't want to use a million\n    ;;       threads for this either, so a core.async channel approach is probably best.\n    ;;\n    (handler msg)\n    (catch InterruptedException e\n      (timbre/info \"MIDI event handler thread interrupted, shutting down.\")\n      (reset! running false)\n      (reset! midi-transfer-thread nil))\n    (catch Throwable t\n      (timbre/error t \"Problem running MIDI event handler.\"))))\n\n(defn- clock-message-handler\n  \"Invoked whenever any midi input device being managed receives a\n  clock message. Checks whether there are any metronomes being synced\n  to that device, and if so, passes along the event.\"\n  [msg running]\n  (doseq [handler (vals (get @synced-metronomes (:info (:device msg))))]\n    (when @running\n      (run-message-handler handler msg running))))\n\n(defn- cc-message-handler\n  \"Invoked whenever any midi input device being managed receives a\n  control change message. Checks whether there are any handlers (such\n  as for launching cues or mapping show variables) attached to it, and\n  if so, calls them.\"\n  [msg running]\n  (doseq [handler (get-in @control-mappings [(:info (:device msg)) (:channel msg) (:note msg)])]\n    (when @running\n      (run-message-handler handler msg running))))\n\n(defn- note-message-handler\n  \"Invoked whenever any midi input device being managed receives a\n  note message. Checks whether there are any handlers (such as for\n  launching cues or mapping show variables) attached to it, and if so,\n  calls them.\"\n  [msg running]\n  (doseq [handler (get-in @note-mappings [(:info (:device msg)) (:channel msg) (:note msg)])]\n    (when @running\n      (run-message-handler handler msg running))))\n\n(defn- aftertouch-message-handler\n  \"Invoked whenever any midi input device being managed receives an\n  aftertouch (polyphonic key pressure) message. Checks whether there\n  are any handlers attached to it, and if so, calls them.\"\n  [msg running]\n  (doseq [handler (get-in @aftertouch-mappings [(:info (:device msg)) (:channel msg) (:note msg)])]\n    (when @running\n      (run-message-handler handler msg running))))\n\n(defn- sysex-message-handler\n  \"Invoked whenever any midi input device being managed receives a\n  System Exclusive message. Checks whether there are any handlers\n  attached to it, and if so, calls them.\"\n  [msg running]\n  (doseq [handler (get-in @sysex-mappings [(:info (:device msg))])]\n    (when @running\n      (run-message-handler handler msg running))))\n\n(defonce\n  ^{:private true\n    :doc \"Keeps track of devices sending MIDI clock pulses so they can\n  be offered as synchronization sources. Also notes when they seem to\n  be sending the additional beat phase information provided by the\n  Afterglow Traktor controller mapping. Holds a set of nested maps\n  whose top-level keys are the `MidiDevice.info` on which clock pulses\n  have been detected, and whose second-level keys can include\n  `:timing-clock`, which will store the timestamp of the most-recently\n  received clock pulse from that device, `:master`, which will store\n  the number of the Traktor deck which was most recently identified as\n  the Tempo Master if we are getting messages which seem like they\n  could come from the Traktor Afterglow mapping, and\n  `:traktor-beat-phase` which will contain the timestamp of the most\n  recent value we have received which seems to correct to Traktor beat\n  phase information coming from the Traktor Afterglow mapping.\"}\n  clock-sources (atom {}))\n\n(defn- check-for-traktor-beat-phase\n  \"Examines an incoming MIDI message to see if it seems to be coming\n  from the Afterglow Traktor controller mapping, providing beat grid\n  information. If so, makes a note of that fact so the clock source\n  can be reported as offering this extra feature.\"\n  [msg device-key]\n  (when (= (:command msg) :control-change)\n    (let [controller (:note msg)]\n      (cond (and (get @clock-sources device-key) (zero? controller) (< (:velocity msg) 5))\n            (swap! clock-sources assoc-in [device-key :master] (:velocity msg))\n\n            (= controller (get-in @clock-sources [device-key :master]))\n            (swap! clock-sources assoc-in [device-key :traktor-beat-phase] (now))))))\n\n(defn- watch-for-clock-sources\n  \"Examines an incoming MIDI message to see if its source is a\n  potential source for MIDI clock synchronization.\"\n  [msg]\n  (let [device-key (:info (:device msg))]\n    (when (= (:status msg) :timing-clock)\n      (swap! clock-sources assoc-in [device-key :timing-clock] (now)))\n    (check-for-traktor-beat-phase msg device-key)))\n\n(defn mac?\n  \"Return true if we seem to be running on a Mac.\"\n  []\n  (re-find #\"Mac\" (System/getProperty \"os.name\")))\n\n(defn mmj-device?\n  \"Checks whether a MIDI device was returned by the Humatic mmj\n  MIDI extension.\"\n  [device]\n  (re-find #\"humatic\" (str (:device device))))\n\n(defn mmj-installed?\n  \"Return true if the Humatic mmj MIDI extension is present.\"\n  []\n  (some mmj-device? (overtone.midi/midi-devices)))\n\n(defn cm4j-device?\n  \"Checks whether a MIDI device was returned by the CoreMIDI4J MIDI\n  extension.\"\n  [device]\n  (re-find #\"uk\\.co\\.xfactorylibrarians\\.coremidi4j\" (str (:device device))))\n\n(defn cm4j-installed?\n  \"Return true if the CoreMIDI4J MIDI extension is present.\"\n  []\n  (some cm4j-device? (overtone.midi/midi-devices)))\n\n(def midi-port-filter\n  \"Contains a filter which selects midi inputs and outputs we actually\n  want to use. The first time the value is dereferenced, a filter\n  appropriate to the current environment will be created, and that\n  filter will be returned whenever the value is dereferenced again.\n\n  * If this is a Mac, and the CoreMIDI4J MIDI extension is present and\n    working, the filter will accept only its devices.\n\n  * Otherwise, if the Humatic MMJ extension is operating (also on a\n    Mac), the filter which will accept only MMJ's versions of ports\n    which it offers in parallel with the standard implementation, but\n    will accept the standard SPI's implementation of ports which MMJ\n    does not offer.\n\n  * Otherwise, the filter accepts all ports.\"\n  (delay\n   (cond\n     (and (mac?) (cm4j-installed?))\n     cm4j-device?  ;; Only use devices provided by CoreMIDI4J if it is installed.\n\n     (and (mac?) (mmj-installed?))\n     (fn [device]\n       (let [mmj-descriptions (set (map :description (filter mmj-device? (overtone.midi/midi-sources))))]\n         (or (mmj-device? device)\n             ;; MMJ returns devices whose descriptions match the names of the\n             ;; broken devices returned by the broken Java MIDI implementation.\n             ;; But it does not wrap all devices, e.g. the Traktor Virtual Output,\n             ;; so we need to only screen out devices which are supported.\n             ;; MMJ support is only left in place to support Java 6 environments,\n             ;; in particular Max/MSP, where CoreMIDI4J is not available.\n             (not (mmj-descriptions (:name device))))))\n\n     :else\n     identity)))\n\n(defn- incoming-message-handler\n  \"Attached to all midi input devices we manage. Puts the message on a\n  queue so it can be processed by one of our own threads, which have\n  access to all the classes that Afterglow needs.\"\n  [msg]\n  (try\n    (.add midi-queue msg)\n    (catch Throwable t\n      (timbre/error t \"Problem trasferring MIDI event to queue\"))))\n\n(defn- connect-midi-in\n  \"Open a MIDI input device, add it to the map of known inputs, and\n  cause it to send its events to our event distribution handler.\"\n  [device]\n  (let [opened (midi/midi-in device)]\n    (timbre/info \"Opened MIDI input:\" opened)\n    (swap! midi-inputs assoc (:info opened) opened)\n    (midi/midi-handle-events opened incoming-message-handler incoming-message-handler)\n    opened))\n\n(defn- connect-midi-out\n  \"Open a MIDI output device and add it to the map of known outputs.\"\n  [device]\n  (let [opened (midi/midi-out device)]\n    (timbre/info \"Opened MIDI output:\" opened)\n    (swap! midi-outputs assoc (:info opened) opened)\n    opened))\n\n(defn- environment-changed\n  \"Called when the MIDI environment has changed, as long\n  as [CoreMIDI4J](https://github.com/DerekCook/CoreMidi4J) is\n  installed. Processes any devices which have appeared or\n  disappeared.\"\n  []\n  (try\n    (.add midi-queue :environment-changed)\n    (catch Throwable t\n      (timbre/error t \"Problem adding MIDI environment change to queue\"))))\n\n(declare ensure-threads-running)\n\n(defn open-inputs-if-needed!\n  \"Make sure the MIDI input ports are open and ready to distribute events.\n  Returns the `:midi-device` maps returned by `overtone.midi`\n  representing the opened inputs.\"\n  []\n  (ensure-threads-running)\n  ;; Don't rescan in an MMJ environment because its device objects are different on each scan,\n  ;; and the midi environment can't change under MMJ anyway.\n  (when (or (empty? @midi-inputs) (not mac?) (not (mmj-installed?)))\n    (doseq [input (filter @midi-port-filter (midi/midi-sources))]\n      (when-not (get @midi-inputs (:info input))\n        (try\n          (let [connected (connect-midi-in input)]\n            (doseq [handler @new-device-handlers]\n              (handler connected)))\n          (catch MidiUnavailableException e)  ; If we can't have it, give up gracefully\n          (catch Throwable t\n            (timbre/error t \"Unable to connect MIDI input\" input))))))\n  (vals @midi-inputs))\n\n(defn open-outputs-if-needed!\n  \"Make sure the MIDI output ports are open and ready to receive events.\n  Returns the `:midi-device` maps returned by `overtone.midi`\n  representing the opened outputs.\"\n  []\n  (ensure-threads-running)\n  ;; Don't rescan in an MMJ environment because its device objects are different on each scan,\n  ;; and the midi environment can't change under MMJ anyway.\n  (when (or (empty? @midi-outputs) (not mac?) (not (mmj-installed?)))\n    (doseq [output (filter @midi-port-filter (midi/midi-sinks))]\n      (when-not (get @midi-outputs (:info output))\n        (try\n          (let [connected (connect-midi-out output)]\n               (doseq [handler @new-device-handlers]\n                 (handler connected)))\n          (catch MidiUnavailableException e)  ; If we can't have it, give up gracefully\n          (catch Throwable t\n            (timbre/error t \"Unable to connect MIDI output\" output))))))\n  (vals @midi-outputs))\n\n(defn- lost-midi-in\n  \"Called when a device in our list of inputs no longer exists in the\n  MIDI environment. Removes it from all lists of mappings, synced\n  metronomes, handlers, etc. and closes it.\"\n  [vanished]\n  {:pre [(= (type vanished) :midi-device)]}\n  (let [device-key (:info vanished)]\n    (swap! midi-inputs dissoc device-key)\n    (swap! synced-metronomes dissoc device-key)\n    (swap! device-mappings dissoc device-key)\n    (swap! control-mappings dissoc device-key)\n    (swap! note-mappings dissoc device-key)\n    (swap! aftertouch-mappings dissoc device-key)\n    (swap! sysex-mappings dissoc device-key)\n    (swap! clock-sources dissoc device-key)\n    (swap! disconnected-device-handlers dissoc device-key)\n    (.close (:device vanished)))\n  (timbre/info \"Lost contact with MIDI input: \" vanished))\n\n(defn- lost-midi-out\n  \"Called when a device in our list of outputs no longer exists in the\n  MIDI environment. Removes it from all lists of outputs, and closes\n  it.\"\n  [vanished]\n  {:pre [(= (type vanished) :midi-device)]}\n  (let [device-key (:info vanished)]\n    (swap! midi-outputs dissoc device-key)\n    (swap! disconnected-device-handlers dissoc device-key)\n    (.close (:device vanished)))\n  (timbre/info \"Lost contact with MIDI output: \" vanished))\n\n(defn scan-midi-environment\n  \"Called either periodically to check for changes, or, if CoreMidi4J\n  is installed, proactively in response to a reported change in the\n  MIDI environment. Updates our notion of what MIDI devices are\n  available, and notifies registered listeners of any changes.\n\n  Also sets up the thread used to process incoming MIDI events if that\n  is not already running, and arranges for this function to be called\n  as needed to keep up with future changes in the MIDI environment.\"\n  []\n  ;; Clean up devices which are no longer present, notifying registered listeners of their departure.\n  (doseq [device (clojure.set/difference (set (keys @midi-inputs))\n                                         (set (map :info (filter @midi-port-filter (midi/midi-sources)))))]\n    (doseq [handler (get @disconnected-device-handlers device)]\n      (handler))\n    (lost-midi-in (get @midi-inputs device)))\n  (doseq [device (clojure.set/difference (set (keys @midi-outputs))\n                                         (set (map :info (filter @midi-port-filter (midi/midi-sinks)))))]\n    (doseq [handler (get @disconnected-device-handlers device)]\n      (handler))\n    (lost-midi-out (get @midi-outputs device)))\n\n  ;; Open and configure any newly available devices.\n  (open-inputs-if-needed!)\n  (open-outputs-if-needed!))\n\n(defn- handle-environment-changed\n  \"Called when we had an event posted to the MIDI event queue telling\n  us that the environment has changed, i.e. a device has been added or\n  removed. Update our notion of the environment state accordingly.\"\n  []\n  (timbre/info \"MIDI Environment changed!\")\n  (scan-midi-environment))\n\n(defn- delegated-message-handler\n  \"Takes incoming MIDI events from the incoming queue on a thread with\n  access to all Afterglow classes. Fields incoming MIDI messages,\n  looks for registered interest in them (metronome sync, variable\n  mappings, etc.) and dispatches to the appropriate specific handler.\"\n  []\n  (let [running (atom true)]\n    (loop [msg (.take midi-queue)]\n      (when msg\n        (if (= msg :environment-changed)\n          (handle-environment-changed)  ; Not an actual MIDI message, handle specially\n          (do  ; Process a normal MIDI message\n            ;; First call the global message handlers\n            (doseq [handler @global-handlers]\n              (when @running\n                (run-message-handler handler msg running)))\n\n            ;; Then call any registered port listeners for the port on which it arrived\n            (doseq [handler (get-in @device-mappings [(:info (:device msg))])]\n              (when @running\n                (run-message-handler handler msg running)))\n\n            ;; Then call specific message handlers that match\n            (when @running\n              (cond (#{:timing-clock :start :stop} (:status msg))\n                    (clock-message-handler msg running)\n\n                    (= 0xf0 (:status msg))\n                    (sysex-message-handler msg running)\n\n                    :else\n                    (case (:command msg)\n                      :control-change (do (cc-message-handler msg running)\n                                          (clock-message-handler msg running)) ; Might be Traktor beat phase message\n                      (:note-on :note-off) (note-message-handler msg running)\n                      :poly-pressure (aftertouch-message-handler msg running)\n                      nil)))\n\n            ;; Finally, keep track of any MIDI clock messages we have seen so the\n            ;; user can be informed of them as potential sync sources.\n            (run-message-handler watch-for-clock-sources msg running))))\n\n      ;; If we have not been shut down, do it all again for the next message.\n      (when @running (recur (.take midi-queue))))))\n\n(defn- start-handoff-thread\n  \"Creates the thread used to deliver MIDI events when needed.\"\n  [old-thread]\n  (or old-thread\n      (doto (Thread. delegated-message-handler \"MIDI event handoff\")\n        (.setDaemon true)\n        (.start))))\n\n(defonce ^{:doc \"How often should we scan for changes in the MIDI\n  environment (devices that have been disconnected, or new devices\n  which have connected). This is used only\n  when [CoreMIDI4J](https://github.com/DerekCook/CoreMidi4J) is not\n  installed, sine CoreMIDI4J gives us proactive notification of\n  changes to the MIDI environment. The value is in milliseconds, so\n  the default means to check every two seconds. Changes to this value\n  will take effect after the next scan completes.\"}\n  scan-interval (atom  2000))\n\n(defonce ^:private ^{:doc \"The thread, if any, which periodically\n  checks for changes in the MIDI environment when CoreMIDI4J is not\n  installed to let us know about them proactively. If CoreMIDI4J is in\n  use, this will be set to `:environment-changed` rather than an\n  actual thread, since none need be created.\"}\n  scan-thread (atom nil))\n\n(defn- periodic-scan-handler\n  \"Rescans the MIDI environment at intervals defined\n  by [[scan-interval]]. Used when CoreMIDI4J is not installed to\n  arrange for such scans to happen when the environment actually has\n  changed.\"\n  []\n  (let [running (atom true)]\n    (loop []\n      (try\n        (Thread/sleep @scan-interval)\n        (scan-midi-environment)\n        (catch InterruptedException e\n          (timbre/info \"MIDI periodic MIDI environment scan thread interrupted, shutting down.\")\n          (reset! running false)\n          (reset! scan-thread nil))\n        (catch Throwable t\n          (timbre/error t \"Problem running periodic MIDI scan thread.\")))\n      ;; If we have not been shut down, do it all again.\n      (when @running (recur)))))\n\n(defn- start-scan-thread\n  \"If there is no existing value in `old-thread`, Checks\n  whether [CoreMIDI4J](https://github.com/DerekCook/CoreMidi4J) is\n  installed and working, and if so, register our notification handler\n  to let us know when the MIDI environment changes, and return the\n  value `:environment-changed`. If, on the other hand, MMJ is\n  installed, we are in a context where the environment cannot change,\n  and if we try to close devices, the VM will crash, so we simply\n  return the value `:stop`. Otherwise we create, start, and return a\n  thread to periodically scan for such changes.\"\n  [old-thread]\n  (or old-thread\n      (cond\n        (and (clojure.reflect/resolve-class (.getContextClassLoader (Thread/currentThread))\n                                            'uk.co.xfactorylibrarians.coremidi4j.CoreMidiNotification)\n             ;; It's safe to load the namespace; see if the library can give us proactive notifications\n             (do (require '[afterglow.coremidi4j])\n                 ((resolve 'afterglow.coremidi4j/add-environment-change-handler) environment-changed)))\n        :environment-changed\n\n        (and (mac?) (mmj-installed?))\n        :stop\n\n        :else\n        (doto (Thread. periodic-scan-handler \"MIDI environment change scanner\")  ; Need to poll\n          (.setDaemon true)\n          (.start)))))\n\n(defn- ensure-threads-running\n  \"Starts the threads needed by the afterglow MIDI implementation, if\n  they are not already running.\"\n  []\n  (swap! midi-transfer-thread start-handoff-thread)\n  (swap! scan-thread start-scan-thread))\n\n(defn- tap-handler\n  \"Called when a tap tempo event has occurred for a tap tempo handler\n  created for a metronome. Set the beat phase of that metronome to\n  zero, and if this occurred close enough in time to the last tap,\n  update the ring buffer in which we are collecting timestamps, and if\n  we have enough, calculate a BPM value and update the associated\n  metronome. If there has been too much of a lag, reset the ring\n  buffer.\"\n  [buffer metronome]\n  (let [timestamp (now)]\n    (rhythm/metro-beat-phase metronome 0)      ; Regardless, mark the beat\n    (if (and (some? (last @buffer))\n             (< (- timestamp (last @buffer)) max-tempo-tap-lag))\n      ;; We are considering this part of a series of taps.\n      (do\n        (swap! buffer conj timestamp)\n        (when (> (count @buffer) 2)\n          (let [passed (- timestamp (peek @buffer))\n                intervals (dec (count @buffer))\n                mean (/ passed intervals)]\n            (rhythm/metro-bpm metronome (double (/ 60000 mean))))))\n      ;; This tap was isolated, but may start a new series.\n      (reset! buffer (conj (ring-buffer max-tempo-taps) timestamp))))\n  nil)\n\n(defn create-tempo-tap-handler\n  \"Returns a function which implements a simple tempo-tap algorithm on\n  the supplied metronome.\"\n  [metronome]\n  (let [buffer (atom (ring-buffer max-tempo-taps))]\n    (fn [] (tap-handler buffer metronome))))\n\n(defonce\n  ^{:private true\n    :doc \"Protect protocols against namespace reloads\"}\n  _PROTOCOLS_\n  (do\n(defprotocol IClockSync\n  \"A simple protocol for our clock sync object, allowing it to be\n  started and stopped, and the status checked.\"\n  (sync-start [this] \"Start synchronizing your metronome.\")\n  (sync-stop [this] \"Stop synchronizing your metronome.\")\n  (sync-status [this]\n  \"Report on how well synchronization is working. Returns a map with\n  keys `:type` (a keyword that uniquely identifies the kind of sync in\n  effect, currently chosen from `:manual`, `:midi`, and `:dj-link`),\n  `:current` (true if sync appears to be working at the present time),\n  `:level` (a keyword that indicates how strong of a sync is being\n  performed; `:bpm` means basic BPM following, `:beat` adds tracking\n  of beat locations, `:bar` adds tracking of bar starts (down beats),\n  and `:phrase` would add tracking of phrase starts, if any sync\n  mechanism ever offers that), and `:status`, which is a human-oriented\n  summmary of the status.\"))))\n\n(defn interval-to-bpm\n  \"Given an interval between MIDI clock pulses in milliseconds,\n  calculate the implied beats per minute value, to the nearest\n  hundredth of a beat.\"\n  [interval]\n  (/ (math/round (double (/ 6000000 (* interval 24)))) 100.0))\n\n(defn bpm-to-interval\n  \"Given a BPM, calculate the interval between MIDI clock pulses in\n  milliseconds.\"\n  [bpm]\n  (/ 2500.0 bpm))\n\n(defn std-dev\n  \"Calculate the standard deviation of a set of samples.\"\n  ([samples]\n   (let [n (count samples)\n         mean (/ (reduce + samples) n)]\n     (std-dev samples n mean)))\n  ([samples n mean]\n   (let [intermediate (map #(Math/pow (- %1 mean) 2) samples)]\n     (Math/sqrt (/ (reduce + intermediate) n))))) \n\n(def abs-tolerance\n  \"If we are going to adjust the BPM, the adjustment we are going to\n  make needs to represent at least this many milliseconds per MIDI\n  clock tick (to reduce jitter).\"\n  0.005)\n\n(def dev-tolerance\n  \"If we are going to adjust the BPM, the adjustment must be at least\n  this many times the standard deviation in observed clock pulse\n  timings, so we can avoid jitter due to unstable timing.\"\n  2.2)\n\n(defn- sync-handler\n  \"Called whenever a MIDI message is received for a synced metronome.\n  If it is a clock pulse, update the ring buffer in which we are\n  collecting timestamps, and if we have enough, calculate a BPM value\n  and update the associated metronome.\"\n  [msg timestamps means metronome traktor-info]\n  (dosync\n   (ensure traktor-info)\n   (case (:status msg)\n     :timing-clock (let [timestamp (now)]  ; Ordinary clock pulse\n                     (alter timestamps conj timestamp)\n                     (when (> (count @timestamps) 1)\n                       (let [passed (- timestamp (peek @timestamps))\n                             intervals (dec (count @timestamps))\n                             mean (/ passed intervals)]\n                         (alter means conj mean)\n                         (when (>= (count @means) min-clock-intervals)\n                           (let [num-means (count @means)\n                                 mean-mean (/ (apply + @means) num-means)\n                                 dev (std-dev @means num-means mean-mean)\n                                 implied (bpm-to-interval (rhythm/metro-bpm metronome))\n                                 adjustment (math/abs (- implied mean-mean))]\n                             (when (> adjustment (max abs-tolerance (* dev-tolerance dev)))\n                               (rhythm/metro-bpm metronome (interval-to-bpm mean-mean))))))))\n     (:start :stop) (do (ref-set timestamps (ring-buffer max-clock-intervals)) ; Clock is being reset\n                        (ref-set means (ring-buffer max-clock-intervals)))\n     :control-change (when (and (some? @traktor-info) (< (:note msg) 5))  ; Traktor beat phase update\n                       (when (zero? (:note msg))  ; Switching the current master deck\n                         (alter traktor-info assoc :master (:velocity msg)))\n                       (when (= (:master @traktor-info) (:note msg))  ; Beat phase for master deck, use it\n                         (let [target-phase (/ (- (:velocity msg) 64) 127)]\n                           ;; Only move when we are towards the middle of a beat, to make it more subtle\n                           (when (< 0.2 target-phase 0.8) \n                             (rhythm/metro-beat-phase metronome target-phase)))\n                         (alter traktor-info assoc :last-sync (now))))\n     nil)))\n\n(defn- add-synced-metronome\n  [midi-clock-source metronome f]\n  {:pre [(= (type midi-clock-source) :midi-device) (satisfies? rhythm/IMetronome metronome) (ifn? f)]}\n  (swap! synced-metronomes #(assoc-in % [(:info midi-clock-source) metronome] f)))\n\n(defn- remove-synced-metronome\n  [midi-clock-source metronome]\n  {:pre [(= (type midi-clock-source) :midi-device)]}\n  (swap! synced-metronomes #(update-in % [(:info midi-clock-source)] dissoc metronome)))\n\n(defn- traktor-beat-phase-current\n  \"Checks whether our clock is being synced to ordinary MIDI clock, or\n  enhanced Traktor beat phase using the custom Afterglow Traktor\n  controller mapping.\"\n  [traktor-info]\n  (dosync\n   (and (some? traktor-info)\n        (< (- (now) (:last-sync traktor-info 0)) 100))))\n\n;; A simple object which holds the values necessary to establish a link between an external\n;; source of MIDI clock messages and the metronome driving the timing of a light show.\n(defrecord ClockSync [metronome midi-clock-source timestamps means traktor-info] \n    IClockSync\n    (sync-start [this]\n      (add-synced-metronome midi-clock-source metronome\n                            (fn [msg] (sync-handler msg timestamps means metronome traktor-info))))\n    (sync-stop [this]\n      (remove-synced-metronome midi-clock-source metronome))\n    (sync-status [this]\n      (dosync\n       (ensure timestamps)\n       (ensure traktor-info)\n       (let [n (count @timestamps)\n             lag (when (pos? n) (- (now) (last @timestamps)))\n             current (and (= n max-clock-intervals)\n                          (< lag 100))\n             traktor-current (traktor-beat-phase-current @traktor-info)]\n         {:type (if traktor-current :traktor-beat-phase :midi)\n          :current current\n          :level (if traktor-current :beat :bpm)\n          :source midi-clock-source\n          :status (cond\n                    (empty? @timestamps) \"Inactive, no clock pulses have been received.\"\n                    (not current) (str \"Stalled? \" (if (< n max-clock-intervals)\n                                                     (str \"Clock pulse buffer has \" n \" of \"\n                                                          max-clock-intervals \" pulses in it.\")\n                                                     (str \"Last clock pulse received \" lag \"ms ago.\")))\n                    :else \"Running, clock pulse buffer is full and current.\")}))))\n\n(defn describe-device-filter\n  \"Returns a description of a filter used to narrow down MIDI devices,\n  if one was supplied, or the empty string if none was.\"\n  [device-filter]\n  (cond\n    (or (nil? device-filter) (and (string? device-filter) (clojure.string/blank? device-filter)))\n    \"\"\n\n    (instance? Pattern device-filter)\n    (str \"with a name or description matching \" (with-out-str (clojure.pprint/write-out device-filter)) \" \")\n\n    (or (instance? javax.sound.midi.MidiDevice device-filter)\n        (instance? javax.sound.midi.MidiDevice$Info device-filter))\n    (format \"provided by %s \" device-filter)\n\n    (= (type device-filter) :midi-device)\n    (describe-device-filter (:info device-filter))\n\n    (vector? device-filter)\n    (clojure.string/join \"or \" (map describe-device-filter device-filter))\n\n    (ifn? device-filter)\n    (format \"returning true when passed to %s \" device-filter)\n\n    :else\n    (str \"with a name or description matching \\\"\" device-filter \"\\\" \")))\n\n(defn filter-devices\n  \"Return only those devices matching the supplied `device-filter`.\n\n  The elements of `devices` must all be `:midi-device` maps as\n  returned by `overtone.midi`.\n\n  If `device-filter` is `nil` or an empty\n  string, `devices` is returned unfiltered. Otherwise it can be one of\n  the following things:\n\n  * A `java.util.regex.Pattern`, which will be matched against each\n  device name and description. If either match succeeds, the device\n  will be included in the results.\n\n  * A `String`, which will be turned into a `Pattern` which matches in\n  a case-insensitive way, as above. So if the device name or filter\n  contains the string, ignoring case, the device will be included.\n\n  * A `javax.sound.midi.MidiDevice` instance, which will match only\n  the device that it implements.\n\n  * A `javax.sound.midi.MidiDevice.Info` instance, which will match\n  only the device it describes.\n\n  * A `:midi-device` map, which will match only itself.\n\n  * A `vector` of device filters, which will match any device that\n  matches any filter.\n\n  * A function, which will be called with each device, and the device\n  will be included if the function returns a `true` value.\n\n  Anything else will be converted to a string and matched as above.\"\n  [device-filter devices]\n  (cond\n    (or (nil? device-filter) (and (string? device-filter) (clojure.string/blank? device-filter)))\n    devices\n\n    (instance? javax.sound.midi.MidiDevice device-filter)\n    (filter #(= (:device %) device-filter) devices)\n\n    (instance? javax.sound.midi.MidiDevice$Info device-filter)\n    (filter #(= (:info %) device-filter) devices)\n\n    (= (type device-filter) :midi-device)\n    (filter #(= (:info %) (:info device-filter)) devices)\n\n    (vector? device-filter)\n    (filter (fn [device] (some seq (map #(filter-devices % [device]) device-filter))) devices)\n\n    (ifn? device-filter)\n    (filter device-filter devices)\n\n    :else\n    (let [pattern (if (instance? Pattern device-filter)\n                    device-filter\n                    (Pattern/compile (Pattern/quote (str device-filter)) Pattern/CASE_INSENSITIVE))]\n      (filter #(or (re-find pattern (:name %1))\n                   (re-find pattern (:description %1)))\n              devices))))\n\n(defn current-clock-sources\n  \"Returns the set of MIDI input ports which are currently delivering\n  MIDI clock messages.\"\n  []\n  (when (empty? @midi-inputs)\n    (open-inputs-if-needed!)\n    (Thread/sleep 300)) ; Give the clock watcher a chance to spot messages\n  (set (for [[k v] @clock-sources]\n         (when (< (- (now) (:timing-clock v)) 300) (get @midi-inputs k)))))\n\n(defn current-traktor-beat-phase-sources\n  \"Returns the set of MIDI input ports which are currently delivering\n  beat phase information in the format provided by the Afterglow\n  Traktor controller mapping.\"\n  []\n  (set (for [[k v] @clock-sources]\n         (when (< (- (now) (:traktor-beat-phase v 0)) 300) (get @midi-inputs k)))))\n\n(defn sync-to-midi-clock\n  \"Returns a sync function that will cause the beats-per-minute\n  setting of the supplied metronome to track the MIDI clock messages\n  received from the named MIDI source. This is intended for use with\n  [[afterglow.show/sync-to-external-clock]].\n\n  The `device-filter` argument is only needed if there is more than\n  one connected device sending MIDI clock messages when this function\n  is invoked; it will be used to filter the eligible devices\n  using [[filter-devices]]. An exception will be thrown if there is\n  not exactly one matching eligible MIDI clock source.\"\n  ([]\n   (sync-to-midi-clock nil))\n  ([device-filter]\n   (let [result (filter-devices device-filter (current-clock-sources))]\n     (case (count result)\n       0 (throw (IllegalArgumentException. (str \"No MIDI clock sources \" (describe-device-filter device-filter)\n                                                \"were found.\")))\n\n       1 (fn [^afterglow.rhythm.Metronome metronome]\n           (let [sync-handler (ClockSync. metronome (first result) (ref (ring-buffer max-clock-intervals))\n                                          (ref (ring-buffer max-clock-intervals))\n                                          (ref {:master (get-in @clock-sources [(:info (first result))\n                                                                                :master])}))]\n             (sync-start sync-handler)\n             sync-handler))\n\n       (throw (IllegalArgumentException. (str \"More than one MIDI clock source \" (describe-device-filter device-filter)\n                                              \"was found.\")))))))\n\n(defn identify-mapping\n  \"Report on the next MIDI control or note message received, to aid in\n  setting up a mapping to a button, fader, or knob. Call this, then\n  twiddle the knob, press the button, or move the fader, and see what\n  Afterglow received. Pass a timeout in ms to control how long it will\n  wait for a message (the default is ten seconds). This is an upper\n  limit; if a message is received before the timeout, it will be\n  reported immediately.\"\n  ([]\n   (identify-mapping 10000))\n  ([timeout]\n   (open-inputs-if-needed!)\n   (let [result (promise)\n         message-finder (fn [msg]\n                          (when (#{:note-on :note-off :control-change} (:command msg))\n                            (deliver result msg)))]\n     (try\n       (add-global-handler! message-finder)\n       (let [found (deref result timeout nil)]\n         (when found\n           (assoc (select-keys found [:command :channel :note :velocity])\n                  :device (select-keys (:device found) [:name :description]))))\n       (finally (remove-global-handler! message-finder))))))\n\n;; TODO: apply to all matching input sources? Along with remove, and control, note & aftertouch messages?\n(defn add-device-mapping\n  \"Register a handler function `f` to be called whenever any MIDI\n  message is received from the specified device. Any subsequent MIDI\n  message which matches will be passed to `f` as its single argument.\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\"\n  [device-filter f]\n  {:pre [(ifn? f)]}\n  (let [result (filter-devices device-filter (open-inputs-if-needed!))]\n    (when (empty? result)\n      (throw (IllegalArgumentException. (str \"No MIDI sources \" (describe-device-filter device-filter) \"were found.\"))))\n    (swap! device-mappings #(update-in % [(:info (first result))] clojure.set/union #{f}))))\n\n(defn remove-device-mapping\n  \"Unregister a handler previously registered with\n  [[add-device-mapping]].\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\"\n  [device-filter f]\n  (let [result (filter-devices device-filter (open-inputs-if-needed!))]\n    (when (empty? result)\n      (throw (IllegalArgumentException. (str \"No MIDI sources \" (describe-device-filter device-filter) \"were found.\"))))\n    (swap! device-mappings #(update-in % [(:info (first result))] disj f))))\n\n(defn add-control-mapping\n  \"Register a handler function `f` to be called whenever a MIDI\n  controller change message is received from the specified device, on\n  the specified `channel` and `controller` number. Any subsequent MIDI\n  message which matches will be passed to `f` as its single argument.\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\"\n  [device-filter channel control-number f]\n  {:pre [(ifn? f)]}\n  (let [result (filter-devices device-filter (open-inputs-if-needed!))]\n    (when (empty? result)\n      (throw (IllegalArgumentException. (str \"No MIDI sources \" (describe-device-filter device-filter) \"were found.\"))))\n    (swap! control-mappings #(update-in % [(:info (first result)) (int channel) (int control-number)]\n                                        clojure.set/union #{f}))))\n\n(defn remove-control-mapping\n  \"Unregister a handler previously registered with\n  [[add-control-mapping]].\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\"\n  [device-filter channel control-number f]\n  (let [result (filter-devices device-filter (open-inputs-if-needed!))]\n    (when (empty? result)\n      (throw (IllegalArgumentException. (str \"No MIDI sources \" (describe-device-filter device-filter) \"were found.\"))))\n    (swap! control-mappings #(update-in % [(:info (first result)) (int channel) (int control-number)]\n                                        disj f))))\n\n(defn add-note-mapping\n  \"Register a handler function `f` to be called whenever a MIDI note\n  message is received from the specified device, on the specified\n  `channel` and `note` number. Any subsequent MIDI message which\n  matches will be passed to `f` as its single argument.\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\"\n  [device-filter channel note f]\n  {:pre [(ifn? f)]}\n  (let [result (filter-devices device-filter (open-inputs-if-needed!))]\n    (when (empty? result)\n      (throw (IllegalArgumentException. (str \"No MIDI sources \" (describe-device-filter device-filter) \"were found.\"))))\n    (swap! note-mappings #(update-in % [(:info (first result)) (int channel) (int note)]\n                                     clojure.set/union #{f}))))\n\n(defn remove-note-mapping\n  \"Unregister a handler previously registered\n  with [[add-note-mapping]].\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\"\n  [device-filter channel note f]\n  (let [result (filter-devices device-filter (open-inputs-if-needed!))]\n    (when (empty? result)\n      (throw (IllegalArgumentException. (str \"No MIDI sources \" (describe-device-filter device-filter) \"were found.\"))))\n    (swap! note-mappings #(update-in % [(:info (first result)) (int channel) (int note)] disj f))))\n\n(defn add-aftertouch-mapping\n  \"Register a handler function `f` to be called whenever a MIDI\n  aftertouch (polyphonic key pressure) message is received from the\n  specified device, on the specified `channel` and `note` number. Any\n  subsequent MIDI message which matches will be passed to `f` as its\n  single argument.\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\"\n  [device-filter channel note f]\n  {:pre [(ifn? f)]}\n  (let [result (filter-devices device-filter (open-inputs-if-needed!))]\n    (when (empty? result)\n      (throw (IllegalArgumentException. (str \"No MIDI sources \" (describe-device-filter device-filter) \"were found.\"))))\n    (swap! aftertouch-mappings #(update-in % [(:info (first result)) (int channel) (int note)]\n                                           clojure.set/union #{f}))))\n\n(defn remove-aftertouch-mapping\n  \"Unregister a handler previously registered\n  with [[add-aftertouch-mapping]].\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\"\n  [device-filter channel note f]\n  (let [result (filter-devices device-filter (open-inputs-if-needed!))]\n    (when (empty? result)\n      (throw (IllegalArgumentException. (str \"No MIDI sources \" (describe-device-filter device-filter) \"were found.\"))))\n    (swap! aftertouch-mappings #(update-in % [(:info (first result)) (int channel) (int note)] disj f))))\n\n(defn add-sysex-mapping\n  \"Register a handler function `f` to be called whenever a MIDI System\n  Exclusive message is received from the specified device. Any\n  subsequent MIDI message which matches will be passed to `f` as its\n  single argument.\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\"\n  [device-filter f]\n  {:pre [(ifn? f)]}\n  (let [result (filter-devices device-filter (open-inputs-if-needed!))]\n    (when (empty? result)\n      (throw (IllegalArgumentException. (str \"No MIDI sources \" (describe-device-filter device-filter) \"were found.\"))))\n    (swap! sysex-mappings #(update-in % [(:info (first result))] clojure.set/union #{f}))))\n\n(defn remove-sysex-mapping\n  \"Unregister a handler previously registered\n  with [[add-sysex-mapping]].\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\"\n  [device-filter f]\n  (let [result (filter-devices device-filter (open-inputs-if-needed!))]\n    (when (empty? result)\n      (throw (IllegalArgumentException. (str \"No MIDI sources \" (describe-device-filter device-filter) \"were found.\"))))\n    (swap! sysex-mappings #(update-in % [(:info (first result))] disj f))))\n\n(defn watch-for\n  \"Watches for a device that matches\n  `device-filter` (using [[filter-devices]]). If it is present when\n  this function is called, or whenever a matching device is connected\n  in the future (as long as none already was), `found-fn` will be\n  called, with no arguments. This is useful for setting up MIDI\n  mappings to the device whenever it is present. If the device is\n  disconnected and later reconnected, `found-fn` will be called again,\n  so those bindings can be counted on to be present whenver the device\n  is available.\n\n  If there is any cleanup that you need to perform when the device is\n  disconnected, you can pass the optional keyword argument `:lost-fn`\n  along with a function to be called (also with no arguments) whenever\n  a device reported by `found-fn` has disappeared. You do not need to\n  use `:lost-fn` to clean up MIDI bindings created by `found-fn`,\n  because Afterglow automatically cleans up any MIDI bindings for\n  devices which have been disconnected. But if you have your own data\n  structures or state that you want to update, you can use `:lost-fn`\n  to do that.\n\n  In order to give the newly-attached device time to stabilize before\n  trying to send messages to it, `watch-for` waits for a second after\n  it is seen before calling `found-fn`. If your device needs more (or\n  less) time to stabilize, you can pass a number of milliseconds after\n  the optional keyword argument `:sleep-time` to configure this delay.\n\n  The return value of `watch-for` is a function that you can call to\n  cancel the watcher if you no longer need it.\"\n  [device-filter found-fn & {:keys [lost-fn sleep-time] :or {sleep-time 1000}}]\n  {:pre [(ifn? found-fn) (or (nil? lost-fn) (ifn? lost-fn)) (number? sleep-time)]}\n  (let [found (atom false)]\n    (letfn [(disconnection-handler []\n              (when lost-fn (lost-fn))\n              (reset! found false))\n            (connection-handler [device]\n              (when (and (seq (filter-devices device-filter [device])) (compare-and-set! found false true))\n                (timbre/info \"watch-for found device\" (describe-device-filter device-filter))\n                (future\n                  (Thread/sleep sleep-time)\n                  (found-fn))\n                (add-disconnected-device-handler! device disconnection-handler)))\n            (cancel-handler []\n              (remove-new-device-handler! connection-handler))]\n\n      ;; See if the specified device seems to already be connected, and if so, bind to it right away.\n      (when-let [match (first (filter-devices device-filter (concat (open-inputs-if-needed!)\n                                                                    (open-outputs-if-needed!))))]\n        (connection-handler match))\n\n      ;; Set up to bind when connected in the future\n      (add-new-device-handler! connection-handler)\n\n      ;; Return the function that will cancel this watcher\n      cancel-handler)))\n\n(defn find-midi-in\n  \"Find the first MIDI input port matching the specified\n  `device-filter` using [[filter-devices]], or throw an exception if\n  no matches can be found. The exception can be suppressed by passing\n  a false value for the optional second argument `required`.\"\n  ([device-filter]\n   (find-midi-in device-filter true))\n  ([device-filter required]\n   (let [result (filter-devices device-filter (open-inputs-if-needed!))]\n     (if (empty? result)\n       (when required\n         (throw (IllegalArgumentException. (str \"No MIDI inputs \" (describe-device-filter device-filter)\n                                                \"were found.\"))))\n       (first result)))))\n\n(defn find-midi-out\n  \"Find the first MIDI output port matching the specified\n  `device-filter` using [[filter-devices]], or throw an exception if\n  no matches can be found. The exception can be suppressed by passing\n  a false value for the optional second argument `required`.\"\n  ([device-filter]\n   (find-midi-out device-filter true))\n  ([device-filter required]\n   (let [result (filter-devices device-filter (open-outputs-if-needed!))]\n     (if (empty? result)\n       (when required\n         (throw (IllegalArgumentException. (str \"No MIDI outputs \" (describe-device-filter device-filter)\n                                                \"were found.\"))))\n       (first result)))))\n"
  },
  {
    "path": "src/afterglow/rhythm.clj",
    "content": "(ns afterglow.rhythm\n  \"Functions to help work with musical time, evolved from the original\n  version in [Overtone](https://github.com/overtone/overtone/blob/master/src/overtone/music/rhythm.clj).\"\n {:author \"Jeff Rose, James Elliott\"}\n (:require [clojure.math.numeric-tower :refer [round floor]]\n           [overtone.at-at :refer [now]]))\n\n;; TODO: This should be swapped out for the version in Electro,\n;; https://github.com/Deep-Symmetry/electro\n;; https://github.com/Deep-Symmetry/electro/blob/main/src/main/java/org/deepsymmetry/electro/Metronome.java\n;; so there is a single shared notion of musical time between Afterglow and Beat Link.\n\n(defonce\n  ^{:private true\n    :doc \"Protect protocols against namespace reloads.\"}\n  _PROTOCOLS_\n  (do\n(defprotocol IMetronome\n  \"A time-keeping tool for music-related systems.\"\n\n  (metro-start [metro] [metro start-beat]\n  \"Returns the start time of the metronome. Also restarts the\n  metronome at `start-beat` if given.\")\n\n  (metro-bar-start [metro start-bar]\n  \"Restarts the metronome at `start-bar`, keeping the beat phase\n  unchanged in case it is being synced to an external source.\")\n\n  (metro-phrase-start [metro start-phrase]\n  \"Restarts the metronome at `start-phrase`, keeping the beat phase\n  unchanged in case it is being synced to an external source.\")\n\n  (metro-adjust [metro ms]\n  \"Adds a number of milliseconds to the start time of the metronome.\")\n\n  (metro-tick [metro]\n  \"Returns the duration of one beat in milleseconds.\")\n\n  (metro-tock [metro]\n  \"Returns the duration of one bar in milliseconds.\")\n\n  (metro-ding [metro]\n  \"Returns the duration of one phrase in milliseconds.\")\n\n  (metro-beat [metro] [metro beat]\n  \"Returns the current beat number or the timestamp (in milliseconds) of the\n  given `beat`.\")\n\n  (metro-beat-phase [metro] [metro phase]\n  \"Returns the distance traveled into the current beat as a phase\n  number ranging from [0.0, 1.0), or adjusts the phase to match the\n  one supplied.\")\n\n  (metro-bar [metro] [metro bar]\n  \"Returns the current bar number or the timestamp (in milliseconds) of\n  the given `bar`.\")\n\n  (metro-bar-phase [metro] [metro phase]\n  \"Returns the distance traveled into the current bar as a phase\n  number ranging from [0.0, 1.0), or adjusts the phase to match the\n  one supplied.\")\n\n  (metro-phrase [metro] [metro phrase]\n  \"Returns the current phrase number or the timestamp (in milliseconds)\n  of the given `phrase`.\")\n\n  (metro-phrase-phase [metro] [metro phase]\n  \"Returns the distance traveled into the current phrase as a phase\n  number ranging from [0.0, 1.0), or adjusts the phase to match the\n  one supplied.\")\n\n  (metro-bpb [metro] [metro new-bpb]\n  \"Get the current beats per bar or change it to `new-bpb`\")\n\n  (metro-bpp [metro] [metro new-bpp]\n  \"Get the current bars per phrase, or change it to `new-bpp`\")\n\n  (metro-bpm [metro] [metro new-bpm]\n  \"Get the current bpm or change the bpm to `new-bpm`.\")\n\n  (metro-snapshot [metro] [metro instant]\n  \"Take a snapshot of the current beat, bar, phrase, and phase state.\n  If `instant` is supplied, calculates a snapshot for the\n  corresponding time rather than the current time.\")\n\n  (metro-marker [metro]\n  \"Returns the current time as `\\\"phrase.bar.beat\\\"`\")\n\n  (metro-add-bpm-watch [metro key f]\n  \"Register a function to be called whenever the metronome's BPM\n  changes. The `key` and `function` arguments are the same as found in\n  [clojure.core/add-watch](http://clojuredocs.org/clojure.core/add-watch),\n  and in fact are passed on to it.\")\n\n  (metro-remove-bpm-watch [metro key]\n  \"Stop calling the function which was registered with the specified\n  `key`.\"))\n\n(defprotocol ISnapshot\n  \"A snapshot to support a series of beat and phase calculations with\n  respect to a given instant in time. Used by Afterglow so that all\n  phase computations performed when updating a frame of DMX data have\n  a consistent sense of when they are being run, to avoid, for\n  example, half the lights acting as if they are at the very end of a\n  beat while the rest are at the beginning of the next beat, due to a\n  fluke in timing as their evaluation occurs over time. Snapshots also\n  extend the notions of beat phase to enable oscillators with\n  frequencies that are fractions or multiples of a beat.\"\n\n  (snapshot-beat-phase [snapshot] [snapshot beat-ratio]\n  \"Determine the metronome's phase at the time of the snapshot with\n  respect to a multiple or fraction of beats. Calling this with a\n  `beat-ratio` of 1 (the default if not provided) is equivalent\n  to [[metro-beat-phase]], calling with a `beat-ratio` equal\n  to [[metro-bpb]] is equivalent to [[metro-bar-phase]], 1/2\n  oscillates twice as fast as 1, 3/4 oscillates 4 times every three\n  beats... Phases range from [0-1).\")\n\n  (snapshot-bar-phase [snapshot] [snapshot bar-ratio]\n  \"Determine the metronome's phase at the time of the snapshot with\n  respect to a multiple or fraction of bars. Calling this with a\n  `bar-ratio` of 1 (the default if not provided) is equivalent\n  to [[metro-bar-phase]], calling with a `bar-ratio` equal\n  to [[metro-bpp]] is equivalent to [[metro-phrase-phase]], 1/2\n  oscillates twice as fast as 1, 3/4 oscillates 4 times every three\n  bars... Phases range from [0-1).\")\n\n  (snapshot-beat-within-bar [snapshot]\n  \"Returns the beat number within the snapshot relative to the start\n  of the bar: The down beat is 1, and the range goes up to the value\n  returned by [[metro-bpb]] for the metronome.\")\n\n  (snapshot-beat-within-phrase [snapshot]\n  \"Returns the beat number within the snapshot relative to the start\n  of the phrase: The first beat is 1, and the range goes up to the\n  values returned by\n  [[metro-bpb]] times [[metro-bpp]] for the metronome.\")\n\n  (snapshot-down-beat? [snapshot]\n  \"True if the current beat at the time of the snapshot was the first\n  beat in its bar.\")\n\n  (snapshot-phrase-phase [snapshot] [snapshot phrase-ratio]\n  \"Determine the metronome's phase at the time of the snapshot with\n  respect to a multiple or fraction of phrases. Calling this with a\n  `phrase-ratio` of 1 (the default if not provided) is equivalent\n  to [[metro-phrase-phase]], 1/2 oscillates twice as fast as 1, 3/4\n  oscillates 4 times every three bars... Phases range from [0-1).\")\n\n  (snapshot-bar-within-phrase [snapshot]\n  \"Returns the bar number within the snapshot relative to the start of\n  the phrase: Ranges from 1 to the value returned by [[metro-bpp]] for\n  the metronome.\")\n\n  (snapshot-phrase-start? [snapshot]\n  \"True if the current beat at the time of the snapshot wass the first\n  beat in its phrase.\")\n\n  (snapshot-marker [snapshot]\n  \"Returns the time represented by the snapshot as\n  `\\\"phrase.bar.beat`\"))))\n\n;; Rhythm\n\n;; * a resting heart rate is 60-80 bpm\n;; * around 150 induces an excited state\n\n;; A rhythm system should let us refer to time in terms of rhythmic units\n;; like beat, bar, measure, and it should convert these units to real time\n;; units (ms) based on the current BPM and signature settings.\n\n(defn beat-ms\n  \"Convert `b` beats to milliseconds at the given `bpm`.\"\n  [b bpm] (* (/ 60000 bpm) b))\n\n(defn marker-number\n  \"Helper function to calculate the beat, bar, or phrase number in\n  effect at a given `instant` (in milliseconds), given a starting\n  point (`start`, also in milliseconds), and the `interval` (also in\n  milliseconds) between beats, bars, or phrases.\"\n  [instant start interval]\n  (inc (long (Math/floor (/ (- instant start) interval)))))\n\n(defn marker-phase\n  \"Helper function to calculate the beat, bar, or phrase phase at a\n  given `instant` (in millseconds), given a `start` time (also in\n  milliseconds) and `interval` (in milliseconds) between beats, bars,\n  or phrases.\"\n  [instant start interval]\n  (let [marker-ratio (/ (- instant start) interval)]\n    (- (double marker-ratio) (Math/floor marker-ratio))))\n\n(defn enhanced-phase\n  \"Calculate a phase with respect to multiples or fractions of a\n  marker (beat, bar, or phrase), given the `phase` with respect to\n  that marker, the number of that `marker`, and the desired ratio. A\n  `desired-ratio` of 1 returns the phase unchanged; 1/2 oscillates\n  twice as fast, 3/4 oscillates 4 times every three markers...\"\n  [marker phase desired-ratio]\n  (let [r (rationalize desired-ratio)\n          numerator (if (ratio? r) (numerator r) r)\n          denominator (if (ratio? r) (denominator r) 1)\n          base-phase (if (> numerator 1)\n                       (/ (+ (mod (dec marker) numerator) phase) numerator)\n                       phase)\n          adjusted-phase (* base-phase denominator)]\n      (- (double adjusted-phase) (long adjusted-phase))))\n\n(defrecord MetronomeSnapshot [start bpm bpb bpp instant beat bar phrase beat-phase bar-phase phrase-phase]\n  ISnapshot\n\n  (snapshot-beat-phase [snapshot]\n    (snapshot-beat-phase snapshot 1))\n\n  (snapshot-beat-phase [snapshot beat-ratio]\n    (enhanced-phase beat beat-phase beat-ratio))\n\n  (snapshot-bar-phase [snapshot]\n    (snapshot-bar-phase snapshot 1))\n\n  (snapshot-bar-phase [snapshot bar-ratio]\n    (enhanced-phase bar bar-phase bar-ratio))\n\n  (snapshot-beat-within-bar [snapshot]\n    (let [beat-size (/ 1 bpb)]\n      (inc (int (floor (/ (snapshot-bar-phase snapshot 1) beat-size))))))\n\n  (snapshot-beat-within-phrase [snapshot]\n    (let [beat-size (/ 1 bpb bpp)]\n      (inc (int (floor (/ (snapshot-phrase-phase snapshot 1) beat-size))))))\n\n  (snapshot-down-beat? [snapshot]\n    (let [beat-size (/ 1 bpb)]\n      (zero? (floor (/ (snapshot-bar-phase snapshot 1) beat-size)))))\n\n  (snapshot-phrase-phase [snapshot phrase-ratio]\n    (enhanced-phase phrase phrase-phase phrase-ratio))\n\n  (snapshot-bar-within-phrase [snapshot]\n    (let [bar-size (/ 1 bpp)]\n      (inc (int (floor (/ (snapshot-phrase-phase snapshot 1) bar-size))))))\n\n  (snapshot-phrase-start? [snapshot]\n    (let [bar-size (/ 1 bpp)]\n      (zero? (floor (/ (snapshot-phrase-phase snapshot 1) bar-size)))))\n\n  (snapshot-marker [snapshot]\n    (str (:phrase snapshot) \".\" (snapshot-bar-within-phrase snapshot) \".\" (snapshot-beat-within-bar snapshot))))\n\n(defn normalize-phase\n  \"Makes sure a phase value is in the range [0.0,1.0)\"\n  [phase]\n  (if (neg? phase)\n    (inc (- phase (long phase)))\n    (- phase (long phase))))\n\n(defrecord Metronome [start bpm bpb bpp]\n  IMetronome\n\n  (metro-start [metro] @start)\n\n  (metro-start [metro start-beat]\n    (dosync\n     (ensure bpm)\n     (let [new-start (- (now) (round (* (dec start-beat) (metro-tick metro))))]\n       (ref-set start new-start))))\n\n  (metro-bar-start [metro start-bar]\n    (dosync\n     (ensure bpm)\n     (ensure bpb)\n     (let [phase         (metro-beat-phase metro)\n           shift         (* (metro-tick metro) (if (> phase 0.5) (dec phase) phase))\n           new-bar-start (round (- (now) shift (* (dec start-bar) (metro-tock metro))))]\n       (ref-set start new-bar-start))))\n\n  (metro-phrase-start [metro start-phrase]\n    (dosync\n     (ensure bpm)\n     (ensure bpb)\n     (ensure bpp)\n     (let [phase            (metro-beat-phase metro)\n           shift            (* (metro-tick metro) (if (> phase 0.5) (dec phase) phase))\n           new-phrase-start (round (- (now) shift (* (dec start-phrase) (metro-ding metro))))]\n       (ref-set start new-phrase-start))))\n\n  (metro-adjust [metro ms]\n    (dosync\n     (alter start + ms)))\n\n  (metro-tick [metro] (beat-ms 1 @bpm))\n\n  (metro-tock [metro] (dosync\n                       (ensure bpm)\n                       (ensure bpb)\n                       (beat-ms @bpb @bpm)))\n\n  (metro-ding [metro] (dosync\n                       (ensure bpm)\n                       (ensure bpb)\n                       (ensure bpp)\n                       (beat-ms (* @bpb @bpp) @bpm)))\n\n  (metro-beat [metro] (dosync\n                       (ensure start)\n                       (ensure bpm)\n                       (marker-number (now) @start (metro-tick metro))))\n\n  (metro-beat [metro b] (dosync\n                         (ensure start)\n                         (ensure bpm)\n                         (+ (* (dec b) (metro-tick metro)) @start)))\n\n  (metro-beat-phase [metro]\n    (dosync\n     (ensure start)\n     (ensure bpm)\n     (marker-phase (now) @start (metro-tick metro))))\n\n  (metro-beat-phase [metro phase]\n    (dosync\n     (ensure bpm)\n     (let [delta (- (normalize-phase phase) (metro-beat-phase metro))\n           shift (round (* (metro-tick metro) (if (> delta 0.5) (dec delta)\n                                                  (if (< delta -0.5) (inc delta) delta))))]\n       (alter start - shift))))\n\n  (metro-bar [metro]\n    (dosync\n     (ensure start)\n     (ensure bpm)\n     (ensure bpb)\n     (marker-number (now) @start (metro-tock metro))))\n\n  (metro-bar [metro b]\n    (dosync\n     (ensure start)\n     (ensure bpm)\n     (ensure bpb)\n     (+ (* (dec b) (metro-tock metro)) @start)))\n\n  (metro-bar-phase [metro]\n    (dosync\n     (ensure start)\n     (ensure bpm)\n     (ensure bpb)\n     (marker-phase (now) @start (metro-tock metro))))\n\n  (metro-bar-phase [metro phase]\n    (dosync\n     (ensure bpm)\n     (ensure bpb)\n     (let [delta (- (normalize-phase phase) (metro-bar-phase metro))\n           shift (round (* (metro-tock metro) (if (> delta 0.5) (dec delta)\n                                                  (if (< delta -0.5) (inc delta) delta))))]\n       (alter start - shift))))\n\n  (metro-phrase [metro]\n    (dosync\n     (ensure start)\n     (ensure bpm)\n     (ensure bpb)\n     (ensure bpp)\n     (marker-number (now) @start (metro-ding metro))))\n\n  (metro-phrase [metro p]\n    (dosync\n     (ensure start)\n     (ensure bpm)\n     (ensure bpb)\n     (ensure bpp)\n     (+ (* (dec p) (metro-ding metro)) @start)))\n\n  (metro-phrase-phase [metro]\n    (dosync\n     (ensure start)\n     (ensure bpm)\n     (ensure bpb)\n     (ensure bpp)\n     (marker-phase (now) @start (metro-ding metro))))\n\n  (metro-phrase-phase [metro phase]\n    (dosync\n     (ensure bpm)\n     (ensure bpb)\n     (ensure bpp)\n     (let [delta (- (normalize-phase phase) (metro-phrase-phase metro))\n           shift (round (* (metro-ding metro) (if (> delta 0.5) (dec delta)\n                                                  (if (< delta -0.5) (inc delta) delta))))]\n       (alter start - shift))))\n\n  (metro-bpm [metro] @bpm)\n\n  (metro-bpm [metro new-bpm]\n    (dosync\n     (let [instant   (now)\n           cur-beat  (marker-number instant @start (metro-tick metro))\n           cur-phase (marker-phase instant @start (metro-tick metro))\n           new-tick  (beat-ms 1 new-bpm)\n           new-start (round (- instant (* new-tick (+ (dec cur-beat) cur-phase))))]\n       (ref-set start new-start)\n       (ref-set bpm new-bpm)))\n    [:bpm new-bpm])\n\n  (metro-bpb [metro] @bpb)\n\n  (metro-bpb [metro new-bpb]\n    (dosync\n     (ensure bpm)\n     (let [cur-bar   (metro-bar metro)\n           new-tock  (beat-ms new-bpb @bpm)\n           new-start (- (now) (* new-tock (dec cur-bar)))\n           phase     (metro-beat-phase metro) ; Preserve beat phase\n           shift     (* (metro-tick metro) phase)]\n       (ref-set start (round (- new-start shift)))\n       (ref-set bpb new-bpb))))\n\n  (metro-bpp [metro] @bpp)\n\n  (metro-bpp [metro new-bpp]\n    (dosync\n     (ensure bpm)\n     (ensure bpb)\n     (let [cur-phrase (metro-phrase metro)\n           new-ding   (beat-ms (* @bpb new-bpp) @bpm)\n           new-start  (- (now) (* new-ding (dec cur-phrase)))\n           phase      (metro-bar-phase metro) ; Preserve beat & bar phase\n           shift      (* (metro-tock metro) phase)]\n       (ref-set start (round (- new-start shift)))\n       (ref-set bpp new-bpp))))\n\n  (metro-snapshot [metro]\n    (metro-snapshot metro (now)))\n\n  (metro-snapshot [metro instant]\n    (dosync\n     (ensure start)\n     (ensure bpm)\n     (ensure bpb)\n     (ensure bpp)\n     (let [beat         (marker-number instant @start (metro-tick metro))\n           bar          (marker-number instant @start (metro-tock metro))\n           phrase       (marker-number instant @start (metro-ding metro))\n           beat-phase   (marker-phase instant @start (metro-tick metro))\n           bar-phase    (marker-phase instant @start (metro-tock metro))\n           phrase-phase (marker-phase instant @start (metro-ding metro))]\n       (MetronomeSnapshot. @start @bpm @bpb @bpp instant beat bar phrase beat-phase bar-phase phrase-phase))))\n\n  (metro-marker [metro]\n    (snapshot-marker (metro-snapshot metro)))\n\n  (metro-add-bpm-watch [metro key f]\n    (add-watch bpm key f))\n\n  (metro-remove-bpm-watch [metro key]\n    (remove-watch bpm key)))\n\n(defn metronome\n  \"A metronome is a beat management tool. Tell it what BPM you want,\n  and it will compute beat, bar, and phrase timestamps accordingly.\n  See the [[IMetronome]] interface for full details.\"\n  [bpm & {:keys [bpb bpp] :or {bpb 4 bpp 8}}]\n  (let [start (ref (now))\n        bpm (ref bpm)\n        bpb (ref bpb)\n        bpp (ref bpp)]\n    (Metronome. start bpm bpb bpp)))\n"
  },
  {
    "path": "src/afterglow/show.clj",
    "content": "(ns afterglow.show\n  \"Encapsulates a synchronized light show, executing a varying\n  collection of effects with output to a number of DMX universes.\n  Assumes control of the assigned universes, so only one show at a\n  time should be assigned a given universe. Of course, you can stack\n  as many effects as you'd like in that show.\n\n  The effects are maintained in a priority queue, with higher-priority\n  effects running after lower-priority ones, so they can adjust or\n  simply replace the channel assignments established by earlier\n  effects. Some may choose to implement traditional channel-oriented\n  highest-takes-prority or latest-takes-priority semantics, others do\n  more sophisticated color blending or position averageing. The\n  default priority when adding an effect is zero, but you can assign\n  it any integer, and it will be inserted into the queue after any\n  existing effects with the same priority.\n\n  All effects are assigned a keyword when they are added, and adding a\n  new effect with the same key as an existing effect will replace the\n  former one.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as chan]\n            [afterglow.controllers :as controllers]\n            [afterglow.effects :as fx]\n            [afterglow.effects.channel]\n            [afterglow.effects.color]\n            [afterglow.effects.dimmer :refer [master master-set-level]]\n            [afterglow.effects.movement]\n            [afterglow.effects.params :refer [bind-keyword-param resolve-param]]\n            [afterglow.fixtures :as fixtures]\n            [afterglow.midi :as midi]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show-context :refer [*show* with-show]]\n            [afterglow.transform :as transform]\n            [afterglow.version :as version]\n            [afterglow.util :as util]\n            [amalloy.ring-buffer :refer [ring-buffer]]\n            [clojure.math.numeric-tower :as math]\n            [clojure.stacktrace :refer [root-cause]]\n            [com.climate.claypoole :as cp]\n            [ola-clojure.ola-service :as ola]\n            [overtone.at-at :as at-at]\n            overtone.midi\n            [taoensso.timbre :as timbre :refer [error]]\n            [taoensso.tufte :as tufte])\n  (:import [afterglow.effects Effect Assignment]\n           afterglow.effects.dimmer.Master\n           afterglow.rhythm.Metronome\n           com.google.protobuf.ByteString))\n\n(defonce ^{:doc \"How often should frames of DMX data be sent out; this\n  should be a supported frame rate for your interface. The default\n  here is 40 Hz, forty frames per second.\"}\n  default-refresh-interval\n  (/ 1000 40))\n\n(defonce ^:private ^{:doc \"If the last attempt to send a message to\n  the OLA server failed, this will contain a description of the problem.\"}\n  ola-failure\n  (atom nil))\n\n(defn ola-failure-description\n  \"If the last attempt to communicate with the OLA daemon failed,\n  returns a description of the problem, otherwise returns nil.\"\n  []\n  @ola-failure)\n\n(def resolution-order\n  \"The order in which assigners should be evaluated, by type key.\n  Multi-channel assignments are resolved before individual ones.\"\n  [:color :pan-tilt :direction :aim :channel :function])\n\n(defonce ^:private ^{:doc \"Keeps track of the resolution orders for\n  extensions which have been registered to the frame rendering loop.\n  Keys are the unique keyword identifying the extension, perhaps a\n  keyword created from its namespace, and values are a vector of the\n  keywords identifying the new assigner types contributed by the\n  extension. These must also be globally unique, and so should\n  probably have a prefix related to the extension name.\n\n  Even if an extension adds only one new assigner type, that must be\n  provided in a vector here in order for Afterglow to run the\n  assigners.\"}\n  extension-resolution-orders\n  (atom {}))\n\n(defn set-extension-resolution-order!\n  \"A system wanting to extend the Afterglow rendering loop to support\n  new kinds of assigners must call this function to register its new\n  unique assigner types, and the order in which they should be run.\n\n  The first argument `extension-key` is a unique keyword identifying\n  the extension, for example a keyword created from its namespace\n  name. The second argument is a vector containing all the keywords\n  which identify the new assigner types which are implemented by the\n  extension. These must also be globally unique, and should probably\n  have a prefix related to the exension name.\n\n  Even if the extension adds only a single new assigner type, that\n  must be passed as a single-element vector in `order` so that\n  Afterglow knows to look for and run its assigners.\"\n  [extension-key order]\n  {:pre [(keyword? extension-key) (sequential? order) (every? keyword? order)]}\n  (swap! extension-resolution-orders assoc extension-key order))\n\n(defn- group-assigners\n  \"Organize a sequence of assigners into a nested map whose first keys\n  are assigner's `:kind`, containing inner maps keyed on `:target-id`,\n  whose values are all of the assigners with that type and target, in\n  the same order in which they were found in the original sequence.\"\n  [assigners]\n  (reduce (fn [results assigner]\n            (update-in results [(:kind assigner) (:target-id assigner)] (fnil conj []) assigner))\n          {} assigners))\n\n(defn- gather-assigners\n  \"Collect all of the assigners that are in effect at the current\n  moment in the show, organized by type and the unique ID of the\n  element they affect, sorted in priority order under those keys.\"\n  [show snapshot]\n  (tufte/p ::gather-assigners\n           (group-assigners (apply concat (cp/pmap @(:pool show) #(fx/generate % show snapshot)\n                                                   (:effects @(:active-effects show)))))))\n\n(declare end-effect!)\n\n(def ^:private frame-count-for-load\n  \"The number of frames to keep track of for calculating the current\n  load on the show.\"\n  30)\n\n(defn- update-stats\n  \"Update the count of how many frames have been sent, total and\n  average time computing them, and warn if the most recent one took\n  longer than the frame interval.\"\n  [stats scheduled refresh-interval]\n  (let [duration (- (at-at/now) scheduled)\n        total-time (+ duration (:total-time stats 0))\n        frames-sent (inc (:frames-sent stats 0))\n        average-duration (double (/ total-time frames-sent))\n        recent (:recent stats (ring-buffer 30))\n        discarding (if (< (count recent) frame-count-for-load) 0 (- (peek recent)))\n        recent (conj recent duration)\n        recent-total (+ (:recent-total stats 0) duration discarding)\n        recent-average (double (/ recent-total (count recent)))]\n    (when (> duration refresh-interval)\n      (taoensso.timbre/warn \"Frame took\" duration \"ms to generate, refresh interval is\" refresh-interval \"ms.\"))\n    (assoc stats :total-time total-time :frames-sent frames-sent :average-duration average-duration\n           :recent recent :recent-total recent-total :recent-average recent-average)))\n\n(defn current-load\n  \"Returns a sense of how much headroom there is running the current\n  effects, in the form of the fraction of the available refresh\n  interval that was used calculating and sending the last several\n  frames.\"\n  []\n  {:pre [(some? *show*)]}\n  (/ (:recent-average @(:statistics *show*) 0) (:refresh-interval *show*)))\n\n(defn- response-handler\n  \"Called by the OLA communication library to report on the result of\n  our request to update DMX data for a show universe.\"\n  [result]\n  (if (:response result)\n    (reset! ola-failure nil)  ; All went well\n    (reset! ola-failure (merge {:description (:failed result)}\n                               (when (:cause result)\n                                 {:cause (str (root-cause (:cause result)))})))))\n\n(defn- clear-dmx-buffers\n  \"Clear the DMX universe buffers in preparation for generating a new\n  frame.\"\n  [show buffers]\n  (cp/pdoseq @(:pool show) [^bytes levels (vals buffers)] (java.util.Arrays/fill levels (byte 0))))\n\n(defn- clear-extension-buffers\n  \"Tell any registered extensions to clear their buffers in\n  preparation for generating a new frame.\"\n  [show]\n  (cp/pdoseq @(:pool show) [f @(:empty-buffer-fns show)] (f)))\n\n(defn- clean-finished-effects\n  \"See if any effects now consider themselves finished, and remove\n  them from the active functions prior to generating the current\n  frame.\"\n  [show snapshot]\n  (let [active @(:active-effects show)\n        indexed (cp/pmap @(:pool show) vector (range) (:effects active))]\n    (cp/pdoseq @(:pool show) [[index effect] indexed]\n               (when-not (fx/still-active? effect show snapshot)\n                 (let [fx-meta (get (:meta active) index)]\n                   (end-effect! (:key fx-meta) :force true :when-id (:id fx-meta)))))))\n\n(defn- send-dmx-buffers\n  \"Once a frame has been calculated, send the DMX universe buffers to\n  the OLA daemon.\"\n  [show buffers]\n  (cp/pdoseq @(:pool show) [universe (keys buffers)]\n             (let [^bytes levels (get buffers universe)]\n               (ola/UpdateDmxData {:universe universe :data (ByteString/copyFrom levels)} response-handler))))\n\n(defn- send-extension-buffers\n  \"Once a frame has been calculated, tell any registered extensions to\n  send out their updates.\"\n  [show]\n  (cp/pdoseq @(:pool show) [f @(:send-buffer-fns show)] (f)))\n\n;; TODO: Since we are already using core.async elsewhere, it would be nice to\n;;       simplify and use its pipeline mechanism here instead of Claypoole, and\n;;       remove that dependency (and conceptual complexity) from the project.\n;;       The final lectures in the Tim Baldridge class show an example of how\n;;       to do that.\n(defn- send-frame\n  \"Calculate and send a single frame of DMX values for the universes\n  and effects run by a show. Arguments are the show being rendered,\n  the DMX buffers for its universes, and the metronome snapshot\n  reflecting the current instant, for effects to reference.\n\n  If any extension functions have been registered (for custom assigner\n  types which do not result in DMX data, such as the\n  Pangolin [[beyond-server]] laser show integration), they are called\n  at the appropriate points.\"\n  [show buffers snapshot]\n  (tufte/p ::clear-buffers\n           (let [dmx-future (cp/future @(:pool show) (clear-dmx-buffers show buffers))\n                 extensions-future (cp/future @(:pool show) (clear-extension-buffers show))]\n             @dmx-future @extensions-future))\n  (tufte/p ::clean-finished-effects\n           (clean-finished-effects show snapshot))\n  (let [all-assigners (gather-assigners show snapshot)]\n    (doseq [kind (concat resolution-order (apply concat (vals @extension-resolution-orders)))]\n      (tufte/p (keyword \"afterglow.show\" (name kind))\n               (cp/pdoseq @(:pool show) [assigners (vals (get all-assigners kind))]\n                          (let [assignment (fx/run-assigners show snapshot assigners nil)]\n                            (when (some? (:value assignment)) ; If assigner returned nil value, it wants to be skipped\n                              (tufte/p ::resolve-value (fx/resolve-assignment assignment show snapshot buffers))))))))\n  (tufte/p ::send-frame-data\n        (let [dmx-future (cp/future @(:pool show) (send-dmx-buffers show buffers))\n              extensions-future (cp/future @(:pool show) (send-extension-buffers show))]\n          @dmx-future @extensions-future))\n  (swap! (:movement show) #(dissoc (assoc % :previous (:current %)) :current))\n  (swap! (:statistics show) update-stats (:instant snapshot) (:refresh-interval show)))\n\n(defn add-frame-fn!\n  \"Arranges for the supplied function to be called when the Afterglow\n  rendering loop is going to sleep prior to rendering the next frame\n  of lighting effects. The function will be given the metronome\n  snapshot that will be in effect when the next frame gets rendered,\n  so that it can preconfigure anything needed for the rendering\n  process. This is used, for example, to\n  allow [afterglow-max](https://github.com/Deep-Symmetry/afterglow-max#afterglow-max)\n  patchers to set show variables for the next frame, since they cannot\n  be queried directly during the rendering process.\"\n  [f]\n  {:pre [(some? *show*) (ifn? f)]}\n  (swap! (:frame-fns *show*) conj f)\n  nil)\n\n(defn clear-frame-fn!\n  \"Ceases calling the supplied function from the rendering loop.\"\n  [f]\n  {:pre [(some? *show*) (ifn? f)]}\n  (swap! (:frame-fns *show*) disj f)\n  nil)\n\n(defn add-empty-buffer-fn!\n  \"Arranges for the supplied function to be called when the Afterglow\n  rendering loop is clearing its DMX buffers in order to calculate a\n  frame of lighting effects. The function must take no arguments.\n\n  This is how custom assigner types which do not result in DMX data,\n  such as the Pangolin [[beyond-server]] laser show integration,\n  register their extension functions to participate in the rendering\n  loop.\"\n  [f]\n  {:pre [(some? *show*) (ifn? f)]}\n  (swap! (:empty-buffer-fns *show*) conj f)\n  nil)\n\n(defn clear-empty-buffer-fn!\n  \"Ceases calling the supplied function during the buffer clearing\n  phase of the rendering loop.\"\n  [f]\n  {:pre [(some? *show*) (ifn? f)]}\n  (swap! (:empty-buffer-fns *show*) disj f)\n  nil)\n\n(defn add-send-buffer-fn!\n  \"Arranges for the supplied function to be called when the Afterglow\n  rendering loop is sending the DMX data for a frame of lighting\n  effects. The function must take no arguments.\n\n  This is how custom assigner types which do not result in DMX data,\n  such as the Pangolin [[beyond-server]] laser show integration,\n  register their extension functions to participate in the rendering\n  loop.\"\n  [f]\n  {:pre [(some? *show*) (ifn? f)]}\n  (swap! (:send-buffer-fns *show*) conj f)\n  nil)\n\n(defn clear-send-buffer-fn!\n  \"Ceases calling the supplied function during the data sending phase\n  of the rendering loop.\"\n  [f]\n  {:pre [(some? *show*) (ifn? f)]}\n  (swap! (:send-buffer-fns *show*) disj f)\n  nil)\n\n(defn- rendering-loop\n  \"The loop that calculate and sends frames of DMX values for the\n  universes and effects run by this show, as described in\n  [The Rendering\n  Loop]({{guide-url}}rendering_loop.html#the-rendering-loop).\n  This runs forever, and so is executed on a future by [[start!]] and\n  the future is canceled by [[stop!]].\"\n  [show buffers]\n  (loop [snapshot (rhythm/metro-snapshot (:metronome show))\n         still-running (atom true)]\n    (try\n      (send-frame show buffers snapshot)\n      (catch Throwable t\n        (if (instance? java.lang.InterruptedException t)\n          (reset! still-running false)  ; Just means the show was stopped\n          (error t \"Problem trying to run cues\"))))\n    (when (and @still-running @(:pool show))  ; We have not been shut down\n      (let [ended (at-at/now)\n            duration (- ended (:instant snapshot))\n            sleep-time (math/round (max 1 (- (:refresh-interval show) duration)))\n            next-frame-snapshot (rhythm/metro-snapshot (:metronome show) (+ ended sleep-time))]\n        (doseq [f @(:frame-fns show)]\n          (try\n            (f next-frame-snapshot)\n            (catch Throwable t\n              (error t \"Problem trying to call frame-notification function\"))))\n        (Thread/sleep sleep-time)\n        (when @(:pool show) (recur next-frame-snapshot still-running))))))\n\n(defonce ^{:doc \"Keeps track of all running shows.\"\n           :private true}\n  active-shows\n  (atom #{}))\n\n(defn stop!\n  \"Shuts down and removes the scheduled task which is sending DMX\n  values for [[*show*]], and cleans up the show's thread pool.\"\n  []\n  {:pre [(some? *show*)]}\n  (swap! (:task *show*) #(do (when % (future-cancel %)) nil))\n  (swap! (:pool *show*) #(do (when % (cp/shutdown %)) nil))\n  (swap! active-shows disj *show*)\n  @(:statistics *show*))\n\n(defn- create-buffers\n  \"Create the map of universe IDs to byte arrays used to calculate DMX\n  values for universes managed by the specified show.\"\n  [show]\n  (into {} (for [universe (:universes show)] [universe (byte-array 512)])))\n\n(defn running?\n  \"Returns an indication of whether the show is currently generating and\n  sending values to its associated lighting universes.\"\n  []\n  {:pre [(some? *show*)]}\n  (some? @(:task *show*)))\n\n(defn start!\n  \"Starts (or restarts) a scheduled task to calculate and send DMX\n  values to the universes controlled by [[*show*]] at the\n  appropriate refresh rate.\"\n  []\n  {:pre [(some? *show*)]}\n  (stop!)\n  (swap! active-shows conj *show*)\n  (let [buffers (create-buffers *show*)]\n    (swap! (:pool *show*) #(or % (cp/threadpool (cp/ncpus) :name (str \"show-\" (:id *show*)))))\n    (swap! (:task *show*) #(do (when % (future-cancel %))\n                               (future (rendering-loop *show* buffers)))))\n  nil)\n\n(defonce ^{:doc \"Used to give each show a unique ID, for registering\n  its MIDI event handlers, etc.\"\n           :private true}\n  show-counter\n  (atom 0))\n\n(defonce ^{:doc \"Holds the registered shows, if any, for display in the web server.\"}\n  shows (atom {}))\n\n(defn register-show\n  \"Add a show to the list of available shows in the web interface.\"\n  [show description]\n  {:pre [(= (type show) :show)]}\n  (swap! shows assoc (:id show) [show description]))\n\n(defn unregister-show\n  \"Remove a show from the list of available shows in the web interface.\"\n  [show]\n  {:pre [(= (type show) :show)]}\n  (swap! shows dissoc (:id show)))\n\n;; TODO: Should some of these atoms be refs and use dosync?\n(defn show\n  \"Create a show coordinator to calculate and send DMX values to the\n  specified universe(s), with a [[rhythm/metronome]] to coordinate\n  timing. The metronome to use can be specified with the optional\n  keyword argument `:base-metronome`; otherwise, a new metronome is\n  created for the show, with a starting `bpm` of 120.\n\n  Values are computed and sent at a fixed refresh interval (in\n  milliseconds), which defaults to a frame rate of thirty times per\n  second, but can be specified using the optional keyword argument\n  `:refresh-interval`.\n\n  If a description is supplied with the `:description` argument, the\n  show will be registered under that description for the user to\n  choose in the embedded web interface. If you recreate the show\n  because you are in the process of working out its details, be sure\n  to unregister the old version (with [[unregister-show]]) first, or\n  you will end up with multiple shows with the same description in the\n  web interface. There is an example of how to handle this\n  automatically at the start\n  of [[afterglow.examples/use-sample-show]] (click the `view source`\n  link below the description to see the `sample-show` atom and `swap!`\n  invocation within `set-default-show!` it uses to make sure there is\n  only ever one version registered).\n\n  If `grid-controller-listener` is supplied, it will be called\n  whenever a grid controller is registered to the show with the\n  arguments `:register` and the `IGridController` implementation, and\n  whenever one is unregistered with the arguments `:unregister` and\n  the implementation.\"\n  [& {:keys [universes base-metronome refresh-interval description grid-controller-listener]\n      :or   {universes [1] base-metronome (rhythm/metronome 120) refresh-interval default-refresh-interval}}]\n  {:pre [(sequential? universes) (pos? (count universes)) (every? integer? universes) (not-any? neg? universes)\n         (satisfies? rhythm/IMetronome base-metronome) (number? refresh-interval) (pos? refresh-interval)]}\n  (let [result (with-meta\n                 {:id                       (swap! show-counter inc)\n                  :metronome                base-metronome\n                  :sync                     (atom nil)\n                  :refresh-interval         refresh-interval\n                  :universes                (set universes)\n                  :next-id                  (atom 0)\n                  :active-effects           (atom {:effects []\n                                                   :indices {}\n                                                   :meta    []\n                                                   :ending  #{}})\n                  :variables                (atom {})\n                  :grand-master             (master nil) ; Only the grand master can have no show, or parent.\n                  :fixtures                 (atom {})\n                  :movement                 (atom {})    ; Used to smooth head motion between frames\n                  :statistics               (atom { :afterglow-version (version/tag) :afterglow-title (version/title)})\n                  :dimensions               (atom {})\n                  :grid-controllers         (atom #{})\n                  :grid-controller-listener grid-controller-listener\n                  :frame-fns                (atom #{})\n                  :empty-buffer-fns         (atom #{})\n                  :send-buffer-fns          (atom #{})\n                  :task                     (atom nil)\n                  :pool                     (atom nil)\n                  :cue-grid                 (controllers/cue-grid)}\n                 {:type :show})]\n    (when-not (clojure.string/blank? description)\n      (register-show result description))\n    result))\n\n(defn blackout-universe\n  \"Sends zero to every channel of the specified universe. Will be\n  quickly overwritten if there are any active shows transmitting to\n  that universe.\"\n  [universe]\n  {:pre [(some? universe)]}\n  (let [levels (byte-array 512)]\n    (ola/UpdateDmxData {:universe universe :data (ByteString/copyFrom levels)} nil)))\n\n(defn blackout-show\n  \"Sends zero to every channel of every universe associated\n  with [[*show*]]. Will quickly be overwritten if the show is running\n  and there are any active effects, so this is mostly useful when a\n  show has been suspended and you want to darken the lights it left\n  on.\"\n  []\n  {:pre [(some? *show*)]}\n  (doseq [universe (:universes *show*)]\n    (blackout-universe universe)))\n\n(defn stop-all!\n  \"Stops all running shows. Afterglow registers a shutdown hook to\n  call this when the Java environment is shutting down, to clean up\n  gracefully.\"\n  []\n  (doseq [s @active-shows]\n    (with-show s\n      (stop!)\n      (blackout-show))))\n\n(defonce ^{:doc \"Cleans up any running shows when Java is shutting down.\"\n           :private true}\n  shutdown-hook\n  (let [hook (Thread. stop-all!)]\n    (.addShutdownHook (Runtime/getRuntime) hook)\n    hook))\n\n(defn sync-to-external-clock\n  \"Stops or sarts synchronizing the show metronome attached\n  to [[*show*]] with an external clock source. Pass it a function\n  which takes the metronome and binds it to the source, returning a\n  ClockSync object which will be stored with the show, so\n  synchronization can later be stopped if desired. Calling this stops\n  any synchronization that was formerly in effect, and calling it with\n  no sync-fn argument simply leaves it stopped.\n\n  Functions useful to pass to this include [[midi/sync-to-midi-clock]]\n  and [[dj-link/sync-to-dj-link]].\"\n  ([]\n   (sync-to-external-clock nil))\n  ([sync-fn]\n   {:pre [(some? *show*)]}\n   (swap! (:sync *show*) (fn [former-sync]\n                           (when former-sync (midi/sync-stop former-sync))\n                           (when sync-fn (sync-fn (:metronome *show*)))))))\n\n(defn sync-status\n  \"Checks what kind of synchronization is in effect for [[*show*]],\n  and reports on how it seems to be working.\"\n  []\n  {:pre [(some? *show*)]}\n  (if-let [sync-in-effect @(:sync *show*)]\n    (midi/sync-status sync-in-effect)\n    {:type :manual}))\n\n(defn add-variable-set-fn!\n  \"Arranges for the supplied function to be called when the the show\n  variable with the specified keyword is set. The function will be\n  called with two arguments: the keyword, and the new value which is\n  being set.\"\n  [key f]\n  {:pre [(some? *show*) (ifn? f)]}\n  (swap! (:variables *show*) assoc-in [\"set-fn\" (keyword key) f] true)\n  nil)\n\n(defn clear-variable-set-fn!\n  \"Ceases calling the supplied function when the show variable with\n  the specified keyword is set.\"\n  [key f]\n  {:pre [(some? *show*) (ifn? f)]}\n  (swap! (:variables *show*) (fn [vars]\n                               (let [key (keyword key)\n                                     entry (dissoc (get-in vars [\"set-fn\" key]) f)]\n                                 (if (empty? entry)\n                                   (update-in vars [\"set-fn\"] dissoc key)\n                                   (assoc-in vars [\"set-fn\" key] entry)))))\n  nil)\n\n(defn set-variable!\n  \"Set a value for a variable associated with [[*show*]].\"\n  [key newval]\n  {:pre [(some? *show*) (some? key)]}\n  (let [key (keyword key)]\n    (swap! (:variables *show*) #(if (some? newval)\n                                  (assoc % key newval)\n                                  (dissoc % key)))\n    ;; Call any functions which registered an interest in changes to the variable's value\n    (doseq [[f _] (get-in @(:variables *show*) [\"set-fn\" key])]\n      (f key newval))))\n\n(defn get-variable\n  \"Get the value of a variable associated with [[*show*]].\"\n  [key]\n  {:pre [(some? key)]}\n  ((keyword key) @(:variables *show*)))\n\n(defn add-midi-control-to-var-mapping\n  \"Cause the specified `variable` in [[*show*]] to be updated by any\n  MIDI controller-change messages from the specified device sent on\n  the specified `channel` and `control-number`.\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\n\n  If `:min` and/or `:max` are specified, the normal MIDI range from 0\n  to 127 will be scaled to the supplied range instead.\n\n  If `:transform-fn` is specified, it will be called with the MIDI\n  value (after scaling, if any was specified), and its return value\n  will be stored in the variable.\n\n  Returns a MIDI mapping function which can be passed\n  to [[remove-control-mapping]] if you later want to stop the variable\n  from responding to these MIDI messages.\"\n  [device-filter channel control-number variable & {:keys [min max transform-fn] :or {min 0 max 127}}]\n  {:pre [(some? *show*) (some? device-filter) (integer? channel) (<= 0 channel 15)\n         (integer? control-number) (<= 0 control-number 127) (some? variable)\n         (number? min) (number? max) (not= min max) (or (nil? transform-fn) (ifn? transform-fn))]}\n  (let [show *show*  ; Bind so we can pass it to update function running on another thread\n        scale-fn (cond\n                   (and (zero? min) (= max 127))\n                   (fn [midi-val] midi-val)\n\n                   (< min max)\n                   (let [range (- max min)]\n                     (fn [midi-val] (double (+ min (/ (* midi-val range) 127)))))\n\n                   :else\n                   (let [range (- min max)]\n                     (fn [midi-val] (double (+ max (/ (* midi-val range) 127))))))\n        calc-fn (apply comp (filter identity [transform-fn scale-fn]))\n        update-fn (fn [msg]\n                    (with-show show\n                      (set-variable! variable (calc-fn (:velocity msg)))))]\n    (midi/add-control-mapping device-filter channel control-number update-fn)\n    update-fn))\n\n(defn remove-midi-control-to-var-mapping\n  \"Deprecated: There is no reason to use this function, it is simpler\n  to call [[remove-control-mapping]] directly.\n\n  Cease updating the specified variable in [[*show*]] when the\n  specified MIDI controller-change messages are received. `f` is the\n  function that was returned by [[add-midi-control-to-var-mapping]]\n  when this relationship was created.\"\n  {:deprecated \"0.2.0\"}\n  [device-filter channel control-number variable f]\n  {:pre [(some? *show*) (some? device-filter) (integer? channel) (<= 0 channel 15)\n         (integer? control-number) (<= 0 control-number 127) (some? variable)]}\n  (midi/remove-control-mapping device-filter channel control-number f))\n\n(defn add-midi-control-to-master-mapping\n  \"Cause the specified [[dimmer/master]] in [[*show*]] to be updated\n  by any MIDI controller-change messages from the specified device\n  sent on the specified `channel` and `control-number`.\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\n\n  If `:min` and/or `:max` are specified, they will be used instead of\n  the normal master range of 0 to 100. If given, both `:min` and\n  `:max` must be valid percentages (in the range 0 to 100). If no\n  `:master` is supplied, the show's grand master is mapped. If the\n  value supplied with `:master` is a keyword, it is resolved as a show\n  variable containing a dimmer master.\n\n  Returns a MIDI mapping function which can be passed\n  to [[remove-control-mapping]] if you later want to stop the\n  dimmer master from being affected by these MIDI messages.\"\n  [device-filter channel control-number & {:keys [master min max] :or {master (:grand-master *show*) min 0 max 100}}]\n  {:pre [(some? *show*) (some? device-filter) (number? min) (number? max) (not= min max)\n         (<= 0 min 100) (<= 0 max 100)\n         (integer? channel) (<= 0 channel 15) (integer? control-number) (<= 0 control-number 127)]}\n  (let [bound (bind-keyword-param master Master (:grand-master *show*))\n        master (resolve-param bound *show* (rhythm/metro-snapshot (:metronome *show*)))\n        calc-fn (if (< min max)\n                  (let [range (- max min)]\n                    (fn [midi-val] (double (+ min (/ (* midi-val range) 127)))))\n                  (let [range (- min max)]\n                    (fn [midi-val] (double (+ max (/ (* midi-val range) 127))))))\n        update-fn (fn [msg] (master-set-level master (calc-fn (:velocity msg))))]\n    (midi/add-control-mapping device-filter channel control-number update-fn)\n    update-fn))\n\n(defn remove-midi-control-to-master-mapping\n  \"Deprecated: There is no reason to use this function, it is simpler\n  to call [[remove-control-mapping]] directly.\n\n  Cease updating the specified [[dimmer/master]] when the specified\n  MIDI controller-change messages are received. `f` is the function\n  that was returned by [[add-midi-control-to-master-mapping]] when\n  this relationship was established.\"\n  {:deprecated \"0.2.0\"}\n  [device-filter channel control-number f & {:keys [master] :or {master (:grand-master *show*)}}]\n  {:pre [(some? *show*) (some? device-filter) (integer? channel) (<= 0 channel 15)\n         (integer? control-number) (<= 0 control-number 127)]}\n  (midi/remove-control-mapping device-filter channel control-number f))\n\n(defn- add-midi-control-metronome-mapping\n  \"Helper function to perform some action on a metronome when a\n  control-change message with non-zero value is received from the\n  specified device, `channel`, and `control-number`.\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\n\n  Returns a MIDI mapping function which can be passed\n  to [[remove-control-mapping]] if you later want to stop the\n  metronome from being affected by these MIDI messages.\"\n  [device-filter channel control-number metronome mapped-fn]\n  {:pre [(some? *show*) (some? device-filter) (integer? channel) (<= 0 channel 15)\n         (integer? control-number) (<= 0 control-number 127) (ifn? mapped-fn)]}\n  (let [bound (bind-keyword-param metronome Metronome (:metronome *show*))\n        metronome (resolve-param bound *show* (rhythm/metro-snapshot (:metronome *show*)))\n        update-fn (fn [msg] (when (pos? (:velocity msg)) (mapped-fn metronome)))]\n    (midi/add-control-mapping device-filter channel control-number update-fn)\n    update-fn))\n\n(defn add-midi-control-metronome-reset-mapping\n  \"Cause a metronome to be reset to beat 1, bar 1, phrase 1 when a\n  control-change message with non-zero value is received from the\n  specified `device`, `channel`, and `control-number`.\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\n\n  If keyword parameter `:metronome` is supplied, its value can either\n  be a [[rhythm/metronome]] object, or a keyword naming a show\n  variable containing such an object. If not supplied, the main\n  metronome attached to [[*show*]] is mapped.\n\n  Returns a MIDI mapping function which can be passed\n  to [[remove-control-mapping]] if you later want to stop the\n  metronome from being affected by these MIDI messages.\"\n  [device-filter channel control-number & {:keys [metronome] :or {metronome (:metronome *show*)}}]\n  (add-midi-control-metronome-mapping device-filter channel control-number metronome\n                                      #(rhythm/metro-start % 1)))\n\n(defn remove-midi-control-metronome-mapping\n  \"Deprecated: There is no reason to use this function, it is simpler\n  to call [[remove-control-mapping]] directly.\n\n  Stop affecting a metronome when the specified MIDI\n  controller-change messages are received. This undoes the effect of\n  any of [[add-midi-control-metronome-reset-mapping]],\n  [[add-midi-control-metronome-align-bar-mapping]], and\n  [[add-midi-control-metronome-align-phrase-mapping]].\n\n  If keyword parameter `:metronome` is supplied, its value can either\n  be a [[rhythm/metronome]] object, or a keyword naming a show\n  variable containing such an object. If not supplied, the main\n  metronome attached to [[*show*]] is mapped.\n\n  `f` is the function that was returned\n  by [[add-midi-control-metronome-reset-mapping]],\n  [[add-midi-control-metronome-align-bar-mapping]], or\n  [[add-midi-control-metronome-align-phrase-mapping]] when this\n  relationship was established.\"\n  {:deprecated \"0.2.0\"}\n  [device-filter channel control-number f & {:keys [metronome] :or {metronome (:metronome *show*)}}]\n  {:pre [(some? *show*) (some? device-filter) (integer? channel) (<= 0 channel 15)\n         (integer? control-number) (<= 0 control-number 127)]}\n  (midi/remove-control-mapping device-filter channel control-number f))\n\n(defn add-midi-control-metronome-align-bar-mapping\n  \"Adjust a metronome so the closest beat is considered the first in\n  the current measure, without moving the beat, when a control-change\n  message with non-zero value is received from the specified device,\n  `channel`, and `control-number`.\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\n\n  If keyword parameter `:metronome` is supplied, its value can either\n  be a [[rhythm/metronome]] object, or a keyword naming a show\n  variable containing such an object. If not supplied, the main\n  metronome attached to [[*show*]] is unmapped.\n\n  Returns a MIDI mapping function which can be passed\n  to [[remove-control-mapping]] if you later want to stop the\n  metronome from being affected by these MIDI messages.\"\n  [device-filter channel control-number & {:keys [metronome] :or {metronome (:metronome *show*)}}]\n  (add-midi-control-metronome-mapping device-filter channel control-number metronome\n                                      #(rhythm/metro-bar-start % (rhythm/metro-bar %))))\n\n(defn add-midi-control-metronome-align-phrase-mapping\n  \"Adjust a metronome so the closest beat is considered the first in\n  the current phrase, without moving the beat, when a control-change\n  message with non-zero value is received from the specified device,\n  `channel`, and `control-number`.\n\n  The first MIDI input source whose device matches the\n  `device-filter` (using [[filter-devices]]) will be chosen.\n\n  If keyword parameter `:metronome` is supplied, its value can either\n  be a [[rhythm/metronome]] object, or a keyword naming a show\n  variable containing such an object. If not supplied, the main\n  metronome attached to [[*show*]] is mapped.\n\n  Returns a MIDI mapping function which can be passed\n  to [[remove-control-mapping]] if you later want to stop the\n  metronome from being affected by these MIDI messages.\"\n  [device-filter channel control-number & {:keys [metronome] :or {metronome (:metronome *show*)}}]\n  (add-midi-control-metronome-mapping device-filter channel control-number metronome\n                                      #(rhythm/metro-phrase-start % (rhythm/metro-phrase %))))\n\n(defn find-effect\n  \"Looks up the specified effect keyword in the list of active effects\n  for [[*show*]]. Returns a map of the effect metadata, with the\n  effect itself under the key `:effect`. If the effect is in the\n  process of ending, the keyword `:ending` will have a `true` value.\"\n  [key]\n  {:pre [(some? *show*) (some? key)]}\n  (when-let [index (get (:indices @(:active-effects *show*)) (keyword key))]\n    (assoc (get (:meta @(:active-effects *show*)) index)\n           :effect (get (:effects @(:active-effects *show*)) index)\n           :ending ((:ending @(:active-effects *show*)) (keyword key)))))\n\n(defn- vec-remove\n  \"Remove the element at the specified index from the collection.\"\n  [coll pos]\n  (vec (concat (subvec coll 0 pos) (subvec coll (inc pos)))))\n\n(defn- remove-key\n  \"Helper function which removes a key from the map of keys to indices, and decrements any\n  indices whose value was equal to or greater than that of the key being removed.\"\n  [m key index]\n  (into {} (for [[k v] (dissoc m key)] [k (if (>= v index) (dec v) v)])))\n\n(defn- remove-effect-internal\n  \"Helper function which removes the effect with the specified key\n  from the priority list structure maintained for the show.\"\n  [active-effects key]\n  (if-let [index (get (:indices active-effects) key)]\n    {:effects (vec-remove (:effects active-effects) index)\n     :indices (remove-key (:indices active-effects) key index)\n     :meta (vec-remove (:meta active-effects) index)\n     :ending (disj (:ending active-effects) key)}\n    active-effects))\n\n(defn- find-insertion-index\n  \"Determines where in the priority list an effect with the specified\n  priority should be inserted: Starting at the end, look backwards for\n  a priority that is equal to or less than the value being inserted,\n  since later effects take priority over earlier ones.\"\n  [coll priority]\n  (loop [pos (count coll)]\n    (cond (zero? pos)\n          pos\n          (<= (:priority (get coll (dec pos))) priority)\n          pos\n          :else\n          (recur (dec pos)))))\n\n(defn- vec-insert\n  \"Helper function which inserts an item at a specified index in a vector.\"\n  [coll pos item]\n  (let [pieces (split-at pos coll)]\n    (apply conj (vec (first pieces)) item (vec (fnext pieces)))))\n\n(defn- insert-key\n  \"Helper function which adds a new key to the map of keys to indices, and increments any\n  indices whose value was equal to or greater than that of the key being inserted.\"\n  [m key index]\n  (assoc (into {} (for [[k v] m] [k (if (>= v index) (inc v) v)]))\n         key index))\n\n(defn- cue-variable-keyword\n  \"Finds the keyword by which a cue variable is accessed given\n  its var-map.\"\n  [var-spec var-map]\n  (if (keyword? (:key var-spec))\n    (:key var-spec)\n    ((keyword (:key var-spec)) var-map)))\n\n(defn- cue-variable-val\n  \"Looks up the value of a cue variable so its starting value can be\n  recorded for the editing interface.\"\n  [var-spec var-map]\n  (when-let [k (cue-variable-keyword var-spec var-map)]\n    (util/normalize-cue-variable-value var-spec (get-variable k))))\n\n(defn- starting-variable-values\n  \"Record the cue variable values at the start of the effect, so\n  editing interfaces can offer a save button if they change.\"\n  [cue var-map]\n  (when (seq (:variables cue))\n    (into {} (map (fn [v]\n                    [(keyword (:key v)) (cue-variable-val v var-map)])\n                  (:variables cue)))))\n\n(defn- add-effect-internal\n  \"Helper function which adds an effect with a specified key and priority to the priority\n  list structure maintained for the show, replacing any existing effect with the same key.\n  Tracks the effect instance id, cue-grid source, and variable binding map as metadata.\"\n  [active-effects key f priority id from-cue x y var-map]\n  (let [base (remove-effect-internal active-effects key)\n        index (find-insertion-index (:meta base) priority)]\n    {:effects (vec-insert (:effects base) index f)\n     :indices (insert-key (:indices base) key index)\n     :meta (vec-insert (:meta base) index (merge {:key key :priority priority :id id\n                                                  :started (rhythm/metro-snapshot (:metronome *show*))}\n                                                 (when from-cue {:cue from-cue})\n                                                 (when x {:x x}) (when y {:y y})\n                                                 (when var-map {:variables var-map})\n                                                 (when-let [starting-vars (starting-variable-values from-cue var-map)]\n                                                   {:starting-vars starting-vars})))\n     :ending (:ending base)}))\n\n(defn add-effect!\n  \"Add an effect to the active set which are affecting DMX outputs\n  for [[show-context/*show*]]. If no priority is specified, zero is\n  used. This effect is added after all existing effects with equal or\n  lower priority, and replaces any existing effect with the same key.\n  Since the effects are executed in order, ones which come later will\n  win when setting DMX values for the same channel if that channel\n  uses latest-takes-priority mode; for channels using highest-takes\n  priority, the order does not matter. Effects can also use more\n  sophisticated strategies for adjusting the results of earlier\n  effects, but the later one always gets to decide what to do.\n\n  Returns the unique id assigned to this particular effect activation,\n  so that user interfaces can detect whether it is still active.\n\n  The `:from-cue` keyword argument is used, along with `:x` and `:y`,\n  to keep track of effects which were launched from the cue grid, to\n  help provide feedback on control surfaces and in the web interface.\n  `:var-map` is used to supply a map of variable bindings associated\n  with the cue, also for use by interfaces which support them.\"\n  [key effect & {:keys [priority from-cue x y var-map] :or {priority 0}}]\n  {:pre [(some? *show*) (some? key) (instance? Effect effect) (integer? priority)]}\n  (let [key (keyword key)\n        id (swap! (:next-id *show*) inc)]\n    (swap! (:active-effects *show*) #(add-effect-internal % key effect priority id from-cue x y var-map))\n    id))\n\n(defn- clean-cue-temporary-variables\n  \"Removes any temporary variables which were introduced for an effect\n  which has ended.\"\n  [var-map]\n  (doseq [k (vals var-map)]\n    (set-variable! k nil)))\n\n(defn end-effect!\n  \"Shut down an effect that is running in [[*show*]]. Unless a `true`\n  value is passed for `:force`, this is done by asking the effect to\n  end (and waiting until it reports completion); forcibly stopping it\n  simply immediately removes it from the show. If an id is specified\n  with `:when-id`, the effect will only be ended if the id of the\n  currently-running effect matches the one supplied. If it was created\n  from a cue grid, notify any controllers that might be tracking the\n  cue state.\"\n  [key & {:keys [force when-id]}]\n  {:pre [(some? *show*) (some? key)]}\n  (let [key (keyword key)\n        found (find-effect key)\n        effect (:effect found)]\n    ;; Make sure the effect is actually running, and if the caller cares, is the right instance\n    (when (and effect (or (nil? when-id) (= (:id found) when-id)))\n      ;; See if it should be forcibly or gently ended\n      (if (or force (:ending found) (fx/end effect *show* (rhythm/metro-snapshot (:metronome *show*))))\n        (do  ; Actually ended (perhaps by force)\n          (when (every? #(% found) [:cue :x :y])\n            (controllers/activate-cue! (:cue-grid *show*) (:x found) (:y found) nil))\n          (swap! (:active-effects *show*) #(remove-effect-internal % key))\n          (clean-cue-temporary-variables (:variables found)))\n        (do  ; Starting to end gracefully\n          (when (every? #(% found) [:cue :x :y])\n            (controllers/report-cue-ending (:cue-grid *show*) (:x found) (:y found) (:id found)))\n          (swap! (:active-effects *show*) #(update-in % [:ending] conj key)))))))\n\n(defn clear-effects!\n  \"Remove all effects currently active in [[*show*]], leading to a\n  blackout state in all controlled universes (if the show is running)\n  until new effects are added.\"\n  []\n  {:pre [(some? *show*)]}\n  (doseq [k (map :key (:meta @(:active-effects *show*)))]\n    (end-effect! k :force true)))\n\n(defn- resolve-initial-value\n  \"Determines how to interpret an initial value assigned to a cue\n  variable. If it is a keyword, looks up the value of the show\n  variable with the same name. If it is a function, calls it to obtain\n  the value. Otherwise returns the value unchanged.\"\n  [initial-value]\n  (cond (keyword? initial-value)\n        (get-variable initial-value)\n\n        (fn? initial-value)\n        (initial-value)\n\n        :else\n        initial-value))\n\n(defn- introduce-cue-variables\n  \"Creates any temporary variable parameters specified by the cue\n  variable list, and returns the var-map that the effect creation\n  function will need to be able to find them in the show.\n\n  Also initializes any variables that have `:start` values configured\n  for them in the cue, whether or not they are temporary. These\n  initial values can be overridden by the values passed in\n  `var-overrides` as described in <<add-effect-from-cue-grid!>>.\"\n  [var-map x y var-overrides]\n  (reduce (fn [result v]\n            (let [initial-value (or ((keyword (:key v)) var-overrides) (resolve-initial-value (:start v)))]\n              (if (string? (:key v))\n                ;; Needs to be introduced as a temp variable; set it and accumulate into result.\n                (let [temp-var (keyword (str \"cue-temp-\" x \"-\" y \"-\" (:key v)))]\n                  (when initial-value\n                    (set-variable! temp-var initial-value))\n                  (assoc result (keyword (:key v)) temp-var))\n                ;; Not a temp variable, just set starting value if needed, leave result unchanged.\n                (do\n                  (when initial-value\n                    (set-variable! (:key v) initial-value))\n                  result)))) {} var-map))\n\n(defn add-effect-from-cue-grid!\n  \"Finds the cue, if any, at the specified grid coordinates, and\n  activates its effect with the designated key and priority, after\n  ending any effects whose keys are specified in the cue's\n  `:end-keys`. Returns the id of the new effect, or nil if no cue was\n  found.\n\n  Any cue variables which are configured to be responsive to MIDI\n  velocity will be set according to the velocity value passed in with\n  `:velocity`. If no velocity is specified, then a default velocity of\n  `127` is assumed.\n\n  A map of variable keywords to values can be supplied with\n  `:var-overrides`, and the corresponding value will be used rather\n  than the `:start` value specified in the cue for that variable when\n  it is introduced as a cue variable. This is used by compound cues to\n  launch their nested cues with customized values, and by\n  [afterglow-max](https://github.com/Deep-Symmetry/afterglow-max) to start\n  cues with alternate values if its patchers have been configured to\n  do so. If a `:var-override` is specified for a variable which is\n  also configured as velocity sensitive, the override will win.\"\n  [x y & {:keys [velocity var-overrides] :or {velocity 127}}]\n  {:pre [(some? *show*) (number? velocity) (<= 0 velocity 127)]}\n  (when-let [cue (controllers/cue-at (:cue-grid *show*) x y)]\n    (doseq [k (:end-keys cue)]\n      (end-effect! k))\n    (let [saved-vars (controllers/cue-vars-saved-at (:cue-grid *show*) x y)\n          velocity-vars (controllers/starting-vars-for-velocity cue velocity)\n          var-map (introduce-cue-variables (:variables cue) x y (merge saved-vars velocity-vars var-overrides))\n          id (add-effect! (:key cue) ((:effect cue) var-map)\n                          :priority (:priority cue) :from-cue cue :x x :y y :var-map var-map)]\n      (controllers/activate-cue! (:cue-grid *show*) x y id)\n      id)))\n\n(defn get-cue-effect\n  \"Sets up a cue as though it is about to run, in order to test that\n  its effect function returns an effect. Used in validating the cue\n  when it is created.\"\n  [effect-fn var-map]\n  (let [vars (introduce-cue-variables var-map \"x\" \"y\" nil)\n        effect (effect-fn vars)]\n    (clean-cue-temporary-variables vars)\n    effect))\n\n;; TODO: Now that grid controllers are actively informed of cues ending,\n;;       the code that checks for matching IDs and send end events may\n;;       no longer be needed.\n(defn find-cue-grid-active-effect\n  \"Find the cue at a particular cue grid location. If it is marked as\n  active, check whether there is still an effect running under that\n  key with the same id. If so, return a vector containing both the cue\n  and the effect. If not, mark the cue as inactive, and return a\n  vector containing the cue and nil. If no cue was found at all,\n  simply returns nil.\"\n  [show x y]\n  {:pre [(= (type show) :show)]}\n  (when-let [cue (controllers/cue-at (:cue-grid show) x y)]\n    (let [effect-found (find-effect (:key cue))\n          active (when (:active-id cue)\n                   (if (and effect-found (= (:id effect-found) (:active-id cue)))\n                     effect-found\n                     (do (controllers/activate-cue! (:cue-grid show) x y nil)\n                         nil)))]\n      [cue active])))\n\n(defn clear-cue!\n  \"Removes any cue which existed at the specified coordinates in the\n  default show's cue grid, by delegating\n  to [[afterglow.controllers/clear-cue!]] (see that function for\n  details).\"\n  [x y]\n  (controllers/clear-cue! (:cue-grid *show*) x y))\n\n(defn set-cue!\n  \"Puts the supplied cue at the specified coordinates in the default\n  show's cue grid, by delegating\n  to [[afterglow.controllers/set-cue!]] (see that function for\n  details).\"\n  [x y cue]\n  (controllers/set-cue! (:cue-grid *show*) x y cue))\n\n(defn- address-map-internal\n  \"Helper function which returns a sorted map whose keys are all\n  addresses in use in a given universe within a fixture map, and whose\n  values are the fixture key using that universe address.\"\n  [fixtures universe]\n  (reduce (fn [addr-map [k v]] (if (= universe (:universe (first (:channels v))))\n                                 (into addr-map (for [address (chan/all-addresses [v])]\n                                                  [address (or (:key v) (:key (:fixture v)))]))\n                                 addr-map)) (sorted-map) fixtures))\n\n(defn address-map\n  \"Returns a sorted map whose keys are the IDs of the universes\n  managed by [[*show*]], and whose values are address maps for the\n  corresponding universe. The address maps have keys for every channel\n  in use by the show in that universe, and the value is the key of the\n  fixture using that address.\"\n  []\n  {:pre [(some? *show*)]}\n  (into (sorted-map) (for [u (:universes *show*)]\n             [u (address-map-internal @(:fixtures *show*) u)])))\n\n(defn remove-fixture!\n  \"Remove a fixture from thosed patched into [[*show*]].\"\n  [key]\n  {:pre [(some? *show*) (some? key)]}\n  (swap! (:fixtures *show*) #(dissoc % (keyword key)))\n  nil)\n\n(defn- next-id\n  \"Assign an ID value which is unique to the current show, for\n  efficient identification of fixtures and heads while combining\n  effects functions.\"\n  []\n  {:pre [(some? *show*)]}\n  (swap! (:next-id *show*) inc))\n\n(defn- patch-fixture-internal\n  \"Helper function which patches a fixture to a given address and universe, first removing\n  any fixture which was previously assigned that key, and making sure there are no DMX\n  channel collisions.\"\n  [show fixtures ^clojure.lang.Keyword key fixture]\n  (let [base (dissoc fixtures key)\n        addrs-in-use (address-map-internal base (:universe (or (first (:channels fixture))\n                                                               (first (:channels (first (:heads fixture)))))))\n        addrs-wanted (chan/all-addresses [fixture])\n        max-needed (apply max addrs-wanted)\n        conflicts (select-keys addrs-in-use addrs-wanted)]\n    (when (> max-needed 512)\n      (throw (IllegalArgumentException. (str \"Cannot complete patch: Would use addresses up to \" max-needed\n                                             \" which exceeds the DMX upper bound of 512.\"))))\n    (when (seq conflicts)\n      (throw (IllegalStateException.\n              (str \"Cannot complete patch: \"\n                   (clojure.string/join \", \" (vec (for [[k v] conflicts]\n                                                    (str \"Channel \" k \" in use by fixture \" v))))))))\n    (assoc fixtures\n           key (assoc (fixtures/index-color-wheel-hues\n                       (fixtures/index-functions fixture)) :key key :id (next-id)))))\n\n(defn- calculate-dimensions\n  \"Determine the center and bounding cube of the show, as defined by\n  the minimum and maximum coordinates in all three dimensions of all\n  patched fixtures and heads. Also enumerate the fixtures which might\n  and heads which might participate in a visualization, in a map whose\n  keys are their sorted IDs.\"\n  [show]\n  (merge (transform/calculate-bounds (vals @(:fixtures show)))\n         {:visualizer-visible (into (sorted-map)\n                                    (map (fn [head] [(:id head) head])\n                                         (fixtures/visualizer-relevant (vals @(:fixtures show)))))\n          :timestamp (at-at/now)}))\n\n(defn patch-fixture!\n  \"Patch a fixture to a universe in [[*show*]] at a starting DMX\n  channel address, at a particular point in space, with a particular\n  orientation.\n\n  `key` is a keyword identifying the fixture. If you need to remove\n  the fixture later, or re-patch it with different parameters, you can\n  do that by passing the same keyword to [[remove-fixture!]] or\n  `patch-fixture!`. If you have a set of fixtures that you want to be\n  able to easily group, give them keywords that start with the same\n  name, followed by a hyphen and uniqe numbers. That way, if you pass\n  the name portion (everthing before the final hyphen and number)\n  to [[fixtures-named]], you will get back a list of all those\n  fixtures.\n\n  `fixture` is a [Fixture Definition\n  map]({{guide-url}}fixture_definitions.html)\n  which specifies all the capabilities of the fixture and how\n  Afterglow can control it.\n\n  `universe` identifies which DMX universe the fixture is attached to,\n  and must be one of the universe numbers that was passed in the\n  `universes` argument to [[show]] when creating the show.\n  `start-address` identifies the DMX address of the first channel the\n  fixture is listening to in that universe (it will be displayed on\n  the fixture's configuration panel or DIP switches), and is an\n  integer ranging from `1` to `512`, the legal DMX addresses in a\n  universe. The attempt to patch will fail if there are more channels\n  in the fixture definition than fit within the 512-channel address\n  space starting at that address, or if any of the addresses used by\n  the fixture have already been assigned to other patched fixtures.\n\n  Coordinates and rotations are optional, expressed along with the\n  keyword arguments `:x`, `:y`, `:z`, `:x-rotation`, `:y-rotation`,\n  and `:z-rotation`, which all default to zero if not specified. All\n  coordinates and rotations are interpreted with respect to the [show\n  frame of\n  reference]({{guide-url}}show_space.html),\n  and are in meters and radians. You can\n  use [[transform/inches]], [[transform/feet]]\n  and [[transform/degrees]] to convert those units for you if\n  desired.\n\n  When you specify a fixture rotation using the `:x-rotation`,\n  `:y-rotation`, and `:z-rotation` arguments, this represents a set of\n  Euler angles within the fixed frame of reference of show space, as\n  implemented by [[transform-fixture-euler]], which uses the\n  `setEuler` method of the\n  Java3D [Transform3D](https://docs.oracle.com/cd/E17802_01/j2se/javase/technologies/desktop/java3d/forDevelopers/J3D_1_3_API/j3dapi/javax/media/j3d/Transform3D.html)\n  object. It can sometimes be very challenging, when looking at a\n  fixture, to figure out how to calculate the Euler angles\n  representing how it was hung. In those situations, you can use an\n  alternate method to specify its rotations:\n\n  If you pass in the optional keyword argument `:relative-rotations`,\n  you can follow it with a vector of paired rotation keywords and\n  angles of any length, and Afterglow will interpret them\n  using [[transform-fixture-relative]]. Starting with the fixture at\n  its default orientation, Afterglow will perform all the rotations\n  you list, in order, from the perspective of the transfomed fixture\n  at each step. This can be a lot easier to think about. For example,\n  if the fixture was first rotated 90 degrees counterclockwise on its\n  _y_ axis, then 45 degrees clockwise on its (new) _z_ axis, you would\n  specify:\n\n  `:relative-rotations [[:y-rotation (tf/degrees 90)] [:z-rotation (tf/degrees -45)]]`\n\n  Finally, if you happen to have a `Transform3D` object which\n  specifies the rotation applied to the fixture (perhaps from some\n  other program), you can simply pass that using the optional keyword\n  argument `:rotation-matrix`.\"\n  [key fixture universe start-address & {:keys [x y z x-rotation y-rotation z-rotation\n                                                relative-rotations rotation-matrix]\n                                         :or {x 0.0 y 0.0 z 0.0 x-rotation 0.0 y-rotation 0.0 z-rotation 0.0}}]\n  {:pre [(some? *show*) (some? fixture) (some? universe) (integer? start-address) (<= 1 start-address 512)]}\n  (when-not (contains? (:universes *show*) universe)\n    (throw (IllegalArgumentException. (str \"Show does not contain universe \" universe))))\n  (let [positioned (cond (= (type rotation-matrix) javax.media.j3d.Transform3D)\n                         (transform/transform-fixture-rotation-matrix fixture x y z rotation-matrix)\n\n                         (seq relative-rotations)\n                         (transform/transform-fixture-relative fixture x y z relative-rotations)\n\n                         :default\n                         (transform/transform-fixture-euler fixture x y z x-rotation y-rotation z-rotation))]\n    (swap! (:fixtures *show*) #(patch-fixture-internal *show* % (keyword key)\n                                                       (chan/patch-fixture positioned universe start-address next-id))))\n  (reset! (:dimensions *show*) (calculate-dimensions *show*))\n  key) ; Don't return the dimensions, it is a deep recursive structure which causes print spasms.\n\n(defn patch-fixture-group!\n  \"*Deprecated until it supports positioning each fixture.*\n\n  Patch a fixture group to a universe in [[*show*]] at a starting DMX channel address.\n  Names will be assigned by adding a hyphen and numeric suffix, starting with 1,\n  to the key supplied. If an offset is supplied, it will be added to the starting\n  address for each subsequent fixture; if not, the largest offset used by the\n  fixture will be used to calculate a suitable offset.\"\n  {:deprecated \"0.1.2\"}\n  ([key fixture universe start-address count]\n   (patch-fixture-group! key fixture universe start-address count (apply max (map :offset (:channels fixture)))))\n  ([key fixture universe start-address count offset]\n   {:pre [(some? *show*) (some? fixture) (some? universe) (integer? start-address) (<= 1 start-address 512)\n          (integer? count) (pos? count)]}\n   (for [i (range count)]\n     (patch-fixture! (keyword (str (name key) \"-\" (inc i))) fixture universe (+ start-address (* i offset))))))\n\n\n(defn all-fixtures\n  \"Returns all fixtures patched into [[*show*]].\"\n  []\n   {:pre [(some? *show*)]}\n  (vals @(:fixtures *show*)))\n\n(defn fixtures-named\n  \"Returns all fixtures patched into [[*show*]] whose key matches the\n  specified name, with an optional number following it, as would be\n  assigned to a fixture group by [[patch-fixture-group!]]\"\n  [n]\n  {:pre [(some? *show*) (some? n)]}\n  (let [pattern (re-pattern (str (name n) \"(-\\\\d+)?\"))]\n    (reduce (fn [result [k v]] (if (re-matches pattern (name k))\n                                 (conj result v)\n                                 result)) [] @(:fixtures *show*))))\n\n;; TODO: Provide general regex search of fixtures? Provide named fixture groups?\n\n(defn active-effect-keys\n  \"Returns a set of the keywords assigned to all currently-active\n  effects.\"\n  [show]\n  {:pre [(= (type show) :show)]}\n  (set (map :key (:meta @(:active-effects show)))))\n\n(defn profile-show\n  \"Gather statistics about the performance of generating and sending a\n  frame of DMX data to the universes [[*show*]]. The show must be\n  stopped to run this function since it manipulates the thread pool\n  atom to run the kind of test requested.\n\n  Specify the number of iterations of the rendering loop that should\n  be profiled with the optional keyword argument `:iterations` (which\n  defaults to 100). Assumes you want to profile without the use of a\n  thread pool to look for worst-case performance unless you pass\n  `false` with the optional keyword argument `:serial?`.\"\n  [& {:keys [iterations serial?] :or {iterations 100 serial? true}}]\n  {:pre [(some? *show*) (integer? iterations) (pos? iterations) (nil? @(:pool *show*))]}\n  (reset! (:pool *show*) (if serial? :serial :builtin))\n  (let [buffers (create-buffers *show*)]\n    (tufte/profile {}\n                   (dotimes [_i iterations]\n                     (let [snapshot (rhythm/metro-snapshot (:metronome *show*))]\n                       (send-frame *show* buffers snapshot)))))\n  (reset! (:pool *show*) nil))\n\n(defn register-grid-controller\n  \"Add a cue grid controller to the list available for linking in the\n  web interface. The argument must implement the [[IGridController]]\n  protocol.\"\n  [controller]\n  {:pre [(some? *show*) (satisfies? controllers/IGridController controller)]}\n  (swap! (:grid-controllers *show*) conj controller)\n  (when-let [listener (:grid-controller-listener *show*)]\n    (listener :register controller)))\n\n(defn unregister-grid-controller\n  \"Remove a cue grid controller from the list available for linking in the\n  web interface.\"\n  [controller]\n  {:pre [(some? *show*) (satisfies? controllers/IGridController controller)]}\n  (swap! (:grid-controllers *show*) disj controller)\n  (when-let [listener (:grid-controller-listener *show*)]\n    (listener :unregister controller)))\n"
  },
  {
    "path": "src/afterglow/show_context.clj",
    "content": "(ns afterglow.show-context\n  \"Establishes a notion of the _current show_ using the dynamic var\n  `*show*`, to save having to pass it as a parameter to dozens of\n  functions in the Afterglow API. This needs to be bound to a\n  value for many Afterglow functions to work.\n\n  The current show can be set locally using [[with-show]], which is\n  what you should do when you have multiple light shows active.\n  However, in the extremely common case of defining and running only a\n  single lighr show, you can also establish a default show,\n  using [[set-default-show!]], and omit even the `with-show` wrappers.\"\n  {:author \"James Elliott\"})\n\n(defonce\n  ^{:dynamic true\n    :doc \"The light show on which Afterglow functions should operate,\n  defined as a dynamic variable so it does not need to be passed as an\n  argument to dozens of functions. The current show can be established\n  locally using [[with-show]], or, if you are only creating and using a\n  single light show, which is a very common situation, you can\n  globally establish a default value by\n  calling [[set-default-show!]].\"}\n  *show* nil)\n\n(defmacro with-show\n  \"Execute the body in the context of the specified light show, so\n  Afterglow knows what show should be affected by its statements.\"\n  [show & body]\n  `(binding [*show* ~show]\n     ~@body))\n\n(defn set-default-show!\n  \"Establish the specified show as the default, so that functions that\n  have not been wrapped inside [[with-show]] contexts will act on it.\n  This makes sense when you are only working with one light show and\n  do not want to have to use `with-show` all the time.\"\n  [show]\n  {:pre [(= (type show) :show)]}\n  (alter-var-root #'*show* (constantly show)))\n"
  },
  {
    "path": "src/afterglow/shows/chris.clj",
    "content": "(ns afterglow.shows.chris\n  \"Cues for shows Chris wants to run for Rhett. Useful as an example of\n  how a small show run by someone unfamiliar with Afterglow was\n  organized after a few years of not working with it.\"\n  (:require [afterglow.beyond :as beyond]\n            [afterglow.channels :as chan]\n            [afterglow.controllers :as ct]\n            [afterglow.controllers.ableton-push :as push]\n            [afterglow.controllers.ableton-push-2 :as push-2]\n            [afterglow.controllers.tempo]\n            [afterglow.core :as core]\n            [afterglow.effects :as fx]\n            [afterglow.effects.channel :as chan-fx]\n            [afterglow.effects.color :as color-fx]\n            [afterglow.effects.cues :as cues]\n            [afterglow.effects.dimmer :refer [dimmer-effect master-set-level]]\n            [afterglow.effects.fun :as fun]\n            [afterglow.effects.movement :as move]\n            [afterglow.effects.oscillators :as oscillators]\n            [afterglow.effects.params :as params]\n            [afterglow.effects.show-variable :as var-fx]\n            [afterglow.examples :as ex]\n            [afterglow.fixtures.american-dj :as adj]\n            [afterglow.fixtures.blizzard :as blizzard]\n            [afterglow.fixtures.chauvet :as chauvet]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [*show* with-show set-default-show!]]\n            [afterglow.transform :as tf]\n            [afterglow.web.routes.show-control]\n            [clojure.math.numeric-tower :as math]\n            [clojure.set :as set]\n            [com.evocomputing.colors :as colors :refer [color-name create-color hue adjust-hue]]\n            [taoensso.timbre :as timbre]))\n\n(defonce ^{:doc \"Holds the show if it has been created,\n  so it can be unregistered if it is being re-created.\"}\n  chris-show\n  (atom nil))\n\n(defn make-movement-cues\n  \"Create a page of with some large scale and layered movement\n  effects. And miscellany which I'm not totally sure what to do with\n  yet.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)]\n\n    (show/set-cue! (+ x-base 2) (inc y-base)\n                   (cues/cue :movement (fn [var-map]\n                                         (cues/apply-merging-var-map var-map fun/aim-fan\n                                                                     (concat (show/fixtures-named \"blade\")\n                                                                             (show/fixtures-named \"torrent\"))))\n                             :variables [{:key \"x-scale\" :min -5 :max 5 :start 1 :name \"X Scale\"}\n                                         {:key \"y-scale\" :min -10 :max 10 :start 5 :name \"Y Scale\"}\n                                         {:key \"z\" :min 0 :max 20 :start 4}\n                                         {:key \"y\" :min -10 :max 10 :start ex/rig-height}\n                                         {:key \"x\" :min -10 :max 10 :start 0.0}]\n                           :color :blue :end-keys [:move-blades :move-torrents]))\n\n    (show/set-cue! (+ x-base 2) (+ y-base 2)\n                   (cues/cue :movement (fn [var-map]\n                                         (cues/apply-merging-var-map var-map fun/twirl\n                                                                     (concat (show/fixtures-named \"blade\")\n                                                                             (show/fixtures-named \"torrent\"))))\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 8 :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"radius\" :min 0 :max 10 :start 0.25 :name \"Radius\"}\n                                         {:key \"z\" :min -10 :max 10 :start -1.0}\n                                         {:key \"y\" :min -10 :max 10 :start ex/rig-height}\n                                         {:key \"x\" :min -10 :max 10 :start 0.0}]\n                             :color :green :end-keys [:move-blades :move-torrents]))\n\n    (show/set-cue! (inc x-base) (+ y-base 3)\n                   (cues/cue :move-torrents\n                             (fn [var-map] (cues/apply-merging-var-map var-map ex/torrent-8))\n                             :variables [{:key \"bars\" :name \"Bars\" :min 1 :max 8 :type :integer :start 2}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 8 :type :integer :start 1}\n                                         {:key \"stagger\" :name \"Stagger\" :min 0 :max 4 :start 0}\n                                         {:key      \"spread\" :name       \"Spread\" :min   -45 :max 45\n                                          :centered true     :resolution 0.25     :start 0}\n                                         {:key      \"pan-min\" :name       \"Pan min\" :min   -180 :max 180\n                                          :centered true      :resolution 0.5       :start -75}\n                                         {:key      \"pan-max\" :name       \"Pan max\" :min   -180 :max 180\n                                          :centered true      :resolution 0.5       :start 90}\n                                         {:key      \"tilt-min\" :name       \"Tilt min\" :min   -180 :max 180\n                                          :centered true       :resolution 0.5        :start -10}\n                                         {:key      \"tilt-max\" :name       \"Tilt max\" :min   -180 :max 180\n                                          :centered true       :resolution 0.5        :start 75}]\n                             :color :yellow :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 3) (+ y-base 3)\n                   (cues/cue :move-blades\n                             (fn [var-map] (cues/apply-merging-var-map var-map ex/can-can))\n                             :variables [{:key \"bars\" :name \"Bars\" :min 1 :max 8 :type :integer :start 1}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 8 :type :integer :start 1}\n                                         {:key \"stagger\" :name \"Stagger\" :min 0 :max 4 :start 0.5}\n                                         {:key      \"spread\" :name       \"Spread\" :min   -45 :max 45\n                                          :centered true     :resolution 0.25     :start 0}\n                                         {:key      \"pan-min\" :name       \"Pan min\" :min   -180 :max 180\n                                          :centered true      :resolution 0.5       :start 0}\n                                         {:key      \"pan-max\" :name       \"Pan max\" :min   -180 :max 180\n                                          :centered true      :resolution 0.5       :start 0}\n                                         {:key      \"tilt-min\" :name       \"Tilt min\" :min   -180 :max 180\n                                          :centered true       :resolution 0.5        :start -60}\n                                         {:key      \"tilt-max\" :name       \"Tilt max\" :min   -180 :max 180\n                                          :centered true       :resolution 0.5        :start 100}]\n                             :color :yellow :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 3) (+ y-base 4)\n                   (cues/cue :blade-circles\n                             (fn [var-map] (cues/apply-merging-var-map var-map ex/circle-chain\n                                                                       (show/fixtures-named :blade) true))\n                             :variables [{:key \"bars\" :name \"Bars\" :min 1 :max 8 :type :integer :start 2}\n                                         {:key        \"radius\" :name  \"Radius\" :min 0.1 :max 2\n                                          :resolution 0.1      :start 1.0}\n                                         {:key        \"stagger\" :name \"Stagger\" :min 0 :max 2 :start 0\n                                          :resolution 0.1}]\n                             :short-name \"Blade Circles\" :color :green :priority 4))\n\n    (show/set-cue! (inc x-base) (+ y-base 4)\n                   (cues/cue :torrent-circles\n                             (fn [var-map] (cues/apply-merging-var-map var-map ex/circle-chain\n                                                                       (show/fixtures-named :torrent) false))\n                             :variables [{:key \"bars\" :name \"Bars\" :min 1 :max 8 :type :integer :start 2}\n                                         {:key        \"radius\" :name  \"Radius\" :min 0.1 :max 2\n                                          :resolution 0.1      :start 1.0}\n                                         {:key        \"stagger\" :name \"Stagger\" :min 0 :max 2 :start 0\n                                          :resolution 0.1}]\n                             :short-name \"Torrent Circles\" :color :green :priority 4))\n\n    ;; A chase which overlays on other movement cues, gradually taking over the lights\n    (show/set-cue! (+ x-base 2) (+ y-base 5)\n                   (cues/cue :crossover (fn [var-map] (cues/apply-merging-var-map var-map ex/crossover-chase))\n                             :variables [{:key \"beats\" :min 1 :max 8 :start 2 :type :integer :name \"Beats\"}\n                                         {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}\n                                         {:key  \"cross-color\" :type :color :start (colors/create-color :red)\n                                          :name \"X Color\"}\n                                         {:key  \"end-color\" :type :color :start (colors/create-color :yellow)\n                                          :name \"End Color\"}]\n                             :color :cyan :priority 5))\n\n    ;; Some macros based on the pan/tilt oscillator cues\n    (show/set-cue! (+ x-base 7) (inc y-base)\n                   (cues/cue :move-torrents\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Torrent Nod\" *show*\n                                      [[17 7 {:pan-min  90.0  :pan-max  179.0 :pan-bars  2  :pan-phase  0.0\n                                              :tilt-min 148.0 :tilt-max 255.0 :tilt-bars 1, :tilt-phase 0.0}]\n                                       [16 7 {:pan-min  77.0  :pan-max  164.0  :pan-bars  2  :pan-phase  0.0\n                                              :tilt-min 148.0 :tilt-max 255.0, :tilt-bars 1, :tilt-phase 0.0}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/cue :move-torrents\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Torrent Cross Nod\" *show*\n                                      [[16 7 {:pan-min  77.0,  :pan-max  164.0, :pan-bars  2, :pan-phase  0.5,\n                                              :tilt-min 148.0, :tilt-max 255.0, :tilt-bars 1, :tilt-phase 0.25}]\n                                       [17 7 {:pan-min  90.0,  :pan-max  179.0, :pan-bars  2, :pan-phase  0.0,\n                                              :tilt-min 148.0, :tilt-max 255.0, :tilt-bars 1, :tilt-phase 0.0}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 6) (inc y-base)\n                   (cues/cue :move-blades\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Sync Can Can\" *show*\n                                      [[21 7 {:pan-min  42.0, :pan-max  42.0,  :pan-bars  1, :pan-phase  0.0,\n                                              :tilt-min 0.0,  :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.0}]\n                                       [20 7 {:pan-min  42.0, :pan-max  42.0,  :pan-bars  1, :pan-phase  0.0,\n                                              :tilt-min 0.0,  :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.0}]\n                                       [19 7 {:pan-min  42.0, :pan-max  42.0,  :pan-bars  1, :pan-phase  0.0,\n                                              :tilt-min 0.0,  :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.0}]\n                                       [18 7 {:pan-min  42.0, :pan-max  42.0,  :pan-bars  1, :pan-phase  0.0,\n                                              :tilt-min 0.0,  :tilt-max 216.0, :tilt-bars 1, :tilt-phase 0.0}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 6) (+ y-base 2)\n                   (cues/cue :move-blades\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Spread Can Can\" *show*\n                                      [[18 7 {:pan-min  42.0, :pan-max  42.0,  :pan-bars  1, :pan-phase  0.0,\n                                              :tilt-min 0.0,  :tilt-max 216.0, :tilt-bars 1, :tilt-phase 0.0}]\n                                       [19 7 {:pan-min  42.0, :pan-max  42.0,  :pan-bars  1, :pan-phase  0.0,\n                                              :tilt-min 0.0,  :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.2}]\n                                       [20 7 {:pan-min  42.0, :pan-max  42.0,  :pan-bars  1, :pan-phase  0.0,\n                                              :tilt-min 0.0,  :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.4}]\n                                       [21 7 {:pan-min  42.0, :pan-max  42.0,  :pan-bars  1, :pan-phase  0.0,\n                                              :tilt-min 0.0,  :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.6}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 6) (+ y-base 3)\n                   (cues/cue :move-blades\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Swing Can Can\" *show*\n                                      [[21 7 {:pan-min  24.0, :pan-max  64.0,  :pan-bars  4, :pan-phase  0.0,\n                                              :tilt-min 0.0,  :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.6}]\n                                       [20 7 {:pan-min  23.0, :pan-max  64.0,  :pan-bars  4, :pan-phase  0.0,\n                                              :tilt-min 0.0,  :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.4}]\n                                       [19 7 {:pan-min  23.0, :pan-max  64.0,  :pan-bars  4, :pan-phase  0.0,\n                                              :tilt-min 0.0,  :tilt-max 197.0, :tilt-bars 1, :tilt-phase 0.2}]\n                                       [18 7 {:pan-min  23.0, :pan-max  64.0,  :pan-bars  4, :pan-phase  0.0,\n                                              :tilt-min 0.0,  :tilt-max 216.0, :tilt-bars 1, :tilt-phase 0.0}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 6) (+ y-base 6)\n                   (cues/cue :move-blades\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Slow Ceiling LR\" *show*\n                                      [[18 7 {:pan-min  12.0,  :pan-max  66.0,  :pan-bars  4, :pan-phase  0.0,\n                                              :tilt-min 170.0, :tilt-max 170.0, :tilt-bars 1, :tilt-phase 0.0}]\n                                       [19 7 {:pan-min  12.0,  :pan-max  66.0,  :pan-bars  4, :pan-phase  0.0,\n                                              :tilt-min 170.0, :tilt-max 170.0, :tilt-bars 1, :tilt-phase 0.2}]\n                                       [20 7 {:pan-min  12.0,  :pan-max  66.0,  :pan-bars  4, :pan-phase  0.0,\n                                              :tilt-min 170.0, :tilt-max 170.0, :tilt-bars 1, :tilt-phase 0.4}]\n                                       [21 7 {:pan-min  12.0,  :pan-max  66.0,  :pan-bars  4, :pan-phase  0.0,\n                                              :tilt-min 170.0, :tilt-max 170.0, :tilt-bars 1, :tilt-phase 0.6}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 6) (+ y-base 5)\n                   (cues/cue :move-blades\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Slow Scan LR\" *show*\n                                      [[21 7 {:pan-min  12.0,  :pan-max  66.0,  :pan-bars  4, :pan-phase  0.4,\n                                              :tilt-min 130.0, :tilt-max 130.0, :tilt-bars 1, :tilt-phase 0.6}]\n                                       [20 7 {:pan-min  12.0,  :pan-max  66.0,  :pan-bars  4, :pan-phase  0.8,\n                                              :tilt-min 130.0, :tilt-max 130.0, :tilt-bars 1, :tilt-phase 0.4}]\n                                       [19 7 {:pan-min  12.0,  :pan-max  66.0,  :pan-bars  4, :pan-phase  0.2,\n                                              :tilt-min 130.0, :tilt-max 130.0, :tilt-bars 1, :tilt-phase 0.2}]\n                                       [18 7 {:pan-min  12.0,  :pan-max  66.0,  :pan-bars  4, :pan-phase  0.6,\n                                              :tilt-min 162.0, :tilt-max 162.0, :tilt-bars 1, :tilt-phase 0.0}]]))\n                             :end-keys [:movement]))))\n\n(defn misc-movement-cues\n  \"some miscellany which I'm not totally sure what to do with.\n  yet.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)]\n\n    (show/set-cue! x-base (+ y-base 6)\n                   (cues/cue :confetti\n                             (fn [var-map]\n                               (let [beats (params/bind-keyword-param (:beats var-map) Number 2)\n                                     cycles (params/bind-keyword-param (:cycles var-map ) Number 1)\n                                     step-ratio (params/build-param-formula Number #(/ %1 %2) beats cycles)\n                                     step (params/build-step-param :interval-ratio step-ratio)]\n                                 (cues/apply-merging-var-map var-map\n                                                             fun/confetti (show/all-fixtures)\n                                                             :step step)))\n                             :variables [{:key \"beats\" :min 1 :max 8 :start 2 :type :integer :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 8 :start 1 :type :integer :name \"Cycles\"}\n                                         {:key \"min-added\" :min 0 :max 20 :start 1 :type :integer :name \"Min Add\"}\n                                         {:key \"max-added\" :min 1 :max 20 :start 4 :type :integer :name \"Max Add\"}\n                                         {:key \"min-duration\" :min 1 :max 16 :start 1 :type :integer :name \"Min Last\"}\n                                         {:key \"max-duration\" :min 1 :max 16 :start 4 :type :integer :name \"Max Last\"}\n                                         {:key \"min-saturation\" :min 0 :max 100 :start 100 :name \"Min Sat\"}]\n                             :color :orange :priority 5))\n    (show/set-cue! (inc x-base) (+ y-base 6)\n                   (cues/cue :confetti\n                             (fn [var-map]\n                               (let [beats (params/bind-keyword-param (:beats var-map) Number 2)\n                                     cycles (params/bind-keyword-param (:cycles var-map ) Number 1)\n                                     step-ratio (params/build-param-formula Number #(/ %1 %2) beats cycles)\n                                     step (params/build-step-param :interval-ratio step-ratio)]\n                                 (cues/apply-merging-var-map var-map\n                                                             fun/confetti (show/all-fixtures)\n                                                             :step step :aim? true)))\n                             :variables [{:key \"beats\" :min 1 :max 8 :start 2 :type :integer :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 8 :start 1 :type :integer :name \"Cycles\"}\n                                         {:key \"min-added\" :min 0 :max 20 :start 1 :type :integer :name \"Min Add\"}\n                                         {:key \"max-added\" :min 1 :max 20 :start 4 :type :integer :name \"Max Add\"}\n                                         {:key \"min-duration\" :min 1 :max 16 :start 1 :type :integer :name \"Min Last\"}\n                                         {:key \"max-duration\" :min 1 :max 16 :start 4 :type :integer :name \"Max Last\"}\n                                         {:key \"min-saturation\" :min 0 :max 100 :start 100 :name \"Min Sat\"}]\n                             :color :orange :priority 5 :short-name \"Confetti Dance\"))))\n\n(defn make-main-color-cues\n  \"Creates a page of cues that assign colors to the lights. If Beyond\n  laser show integration is desired, `add-beyond?` will be `true`.\"\n  [page-x page-y add-beyond?]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)\n        rig-left (:x (first (show/fixtures-named :torrent-2)))\n        rig-right (:x (first (show/fixtures-named :torrent-1)))\n        rig-width (- rig-right rig-left)\n        hue-bar (oscillators/build-oscillated-param  ; Spread a rainbow across a bar of music\n                 (oscillators/sawtooth :interval :bar) :max 360)\n        desat-beat (oscillators/build-oscillated-param  ; Desaturate a color as a beat progresses\n                    (oscillators/sawtooth :down? true) :max 100)\n        hue-gradient (params/build-spatial-param  ; Spread a rainbow across the light grid\n                      (show/all-fixtures)\n                      (fn [head] (- (:x head) (:min-x @(:dimensions *show*)))) :max 360)\n        rig-hue-gradient (params/build-spatial-param  ; Spread a rainbow across just the main rig, repeating\n                          (show/all-fixtures)         ; beyond that, irrespective of other lights' positions.\n                          (fn [head] (colors/clamp-hue (* 360 (/ (- (:x head) rig-left) rig-width)))))\n        hue-z-gradient (params/build-spatial-param  ; Spread a rainbow across the light grid front to back\n                        (show/all-fixtures)\n                        (fn [head] (- (:z head) (:min-z @(:dimensions *show*)))) :max 360)]\n\n    ;; Bottom row assigns colors, first to all fixtures, and then (at a higher priority, so they can\n    ;; run a the same time as the first, and locally override it) individual fixture groups.\n    (ex/make-color-cue \"white\" x-base y-base :include-color-wheels? true\n                    :fixtures (show/all-fixtures) :effect-key :all-color :effect-name \"Color all\")\n    (doall (map-indexed (fn [i group]\n                          (ex/make-color-cue \"white\" (+ x-base (inc i)) y-base :include-color-wheels? true\n                                             :fixtures (show/fixtures-named group)\n                                             :effect-key (keyword (str (name group) \"-color\"))\n                                             :effect-name (str \"Color \" (name group))\n                                             :priority 1))\n                        ex/light-groups))\n\n    ;; Some special/fun cues\n    (show/set-variable! :rainbow-saturation 100)\n    (show/set-cue! x-base (inc y-base)\n                   (let [color-param (params/build-color-param :s :rainbow-saturation :l 50 :h hue-bar)]\n                     (cues/cue :all-color (fn [_] (ex/global-color-effect color-param))\n                               :color-fn (cues/color-fn-from-param color-param)\n                               :short-name \"Rainbow Bar Fade\"\n                               :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                            :type :integer}])))\n    (show/set-cue! (inc x-base) (inc y-base)\n                   (cues/cue :all-color (fn [_] (ex/global-color-effect\n                                                 (params/build-color-param :s :rainbow-saturation :l 50\n                                                                           :h rig-hue-gradient)\n                                                 :include-color-wheels? true))\n                             :short-name \"Rainbow Rig\"\n                             :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                          :type :integer}]))\n    (show/set-cue! (+ x-base 2) (inc y-base)\n                   (let [color-param (params/build-color-param :s :rainbow-saturation :l 50 :h hue-gradient\n                                                               :adjust-hue hue-bar)]\n                     (cues/cue :all-color (fn [_] (ex/global-color-effect color-param))\n                               :color-fn (cues/color-fn-from-param color-param)\n                               :short-name \"Rainbow Grid+Bar\"\n                               :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                            :type :integer}])))\n    (show/set-cue! (+ x-base 3) (inc y-base) ; Desaturate the rainbow as each beat progresses\n                   (let [color-param (params/build-color-param :s desat-beat :l 50 :h hue-gradient\n                                                               :adjust-hue hue-bar)]\n                     (cues/cue :all-color (fn [_] (ex/global-color-effect color-param))\n                               :color-fn (cues/color-fn-from-param color-param)\n                               :short-name \"Rainbow Pulse\")))\n\n    (show/set-cue! (+ x-base 4) (inc y-base)\n                   (cues/cue :transform-colors (fn [_] (color-fx/transform-colors (show/all-fixtures)))\n                             :priority 1000))\n\n    (show/set-cue! (+ x-base 5) (inc y-base)\n                   (cues/cue :all-color (fn [_] (ex/global-color-effect\n                                                 (params/build-color-param :s 100 :l 50 :h hue-z-gradient)\n                                                 :include-color-wheels? true))\n                             :short-name \"Z Rainbow Grid\"))\n    (when add-beyond?\n      (show/set-cue! (+ x-base 6) (inc y-base)\n                     (let [color-param (params/build-color-param :s :rainbow-saturation :l 50 :h hue-bar)]\n                       (cues/cue :all-color (fn [_] (fx/scene \"Rainbow with laser\" (ex/global-color-effect color-param)\n                                                              (beyond/laser-color-effect ex/laser-show color-param)))\n                                 :color-fn (cues/color-fn-from-param color-param)\n                                 :short-name \"Rainbow with Laser\"\n                                 :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                              :type :integer}]))))\n    (show/set-cue! (+ x-base 7) (inc y-base)\n                   (let [color-param (params/build-color-param :s 100 :l 50 :h hue-gradient\n                                                               :adjust-hue hue-bar)]\n                     (cues/cue :all-color (fn [_] (ex/global-color-effect color-param\n                                                                          :fixtures (show/fixtures-named \"blade\")))\n                               :color-fn (cues/color-fn-from-param color-param)\n                               :short-name \"Rainbow Blades\")))\n\n    ;; The fun sparkle cue.\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/cue :sparkle (fn [var-map]\n                                        (cues/apply-merging-var-map var-map fun/sparkle (show/all-fixtures)))\n                             :held true\n                             :priority 100\n                             :variables [{:key \"chance\" :min 0.0 :max 0.4 :start 0.05 :velocity true}\n                                         {:key \"fade-time\" :name \"Fade\" :min 1 :max 2000 :start 50 :type :integer}]))))\n\n(defn make-main-dimmer-cues\n  \"Creates a page of cues that assign dimmers to the lights.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)]\n\n    ;; Dimmer cues to turn on and set brightness of groups of lights\n    (ex/make-dimmer-cue nil x-base (+ y-base 1) :yellow)\n    (doall (map-indexed (fn [i group] (ex/make-dimmer-cue group (+ x-base (inc i)) (+ y-base 1) :yellow))\n                        ex/light-groups))\n\n    ;; Dimmer oscillator cues: Sawtooth\n    (ex/make-sawtooth-dimmer-cue nil x-base (+ y-base 2) :yellow)\n    (doall (map-indexed (fn [i group]\n                          (ex/make-sawtooth-dimmer-cue group (+ x-base (inc i)) (+ y-base 2) :orange))\n                        ex/light-groups))\n\n    ;; Dimmer oscillator cues: Triangle\n    (ex/make-triangle-dimmer-cue nil x-base (+ y-base 3) :orange)\n    (doall (map-indexed (fn [i group]\n                          (ex/make-triangle-dimmer-cue group (+ x-base (inc i)) (+ y-base 3) :red)) ex/light-groups))\n\n    ;; Dimmer oscillator cues: Sine\n    (ex/make-sine-dimmer-cue nil x-base (+ y-base 4) :cyan)\n    (doall (map-indexed (fn [i group]\n                          (ex/make-sine-dimmer-cue group (+ x-base (inc i)) (+ y-base 4) :blue)) ex/light-groups))\n\n    ;; Dimmer oscillator cues: Square\n    (ex/make-square-dimmer-cue nil x-base (+ y-base 5) :cyan)\n    (doall (map-indexed (fn [i group]\n                          (ex/make-square-dimmer-cue group (+ x-base (inc i)) (+ y-base 5) :green)) ex/light-groups))\n\n    ;; Strobe cues, first raw strobes.\n    (show/set-cue! x-base (+ y-base 6)\n                   (cues/function-cue :strobe-all :strobe (show/all-fixtures) :held true :velocity true\n                                      :effect-name \"Raw All\"))\n    (show/set-cue! (inc x-base) (+ y-base 6)\n                   (cues/function-cue :strobe-torrents :strobe (show/fixtures-named \"torrent\") :held true\n                                      :velocity true :effect-name \"Raw Torrents\"))\n    (show/set-cue! (+ x-base 2) (+ y-base 6)\n                   (cues/function-cue :strobe-blades :strobe (show/fixtures-named \"blade\") :held true\n                                      :velocity true :effect-name \"Raw Blades\"))\n    (show/set-cue! (+ x-base 3) (+ y-base 6)\n                   (cues/function-cue :strobe-weather-systems :strobe (show/fixtures-named \"ws\") :held true\n                                      :velocity true :effect-name \"Raw Weather Systems\"))\n    (show/set-cue! (+ x-base 4) (+ y-base 6)\n                   (cues/function-cue :strobe-hexes :strobe (show/fixtures-named \"hex\") :held true\n                                      :velocity true :effect-name \"Raw Hex\"))\n    (show/set-cue! (+ x-base 5) (+ y-base 6)\n                   (cues/function-cue :strobe-pucks :strobe (show/fixtures-named \"puck\") :held true\n                                      :velocity true :effect-name \"Raw Pucks\"))\n    (show/set-cue! (+ x-base 6) (+ y-base 6)\n                   (cues/function-cue :strobe-snowball :strobe (show/fixtures-named \"snowball\") :held true\n                                      :velocity true :effect-name \"Raw Snowball\"))\n\n    ;; Then colorized, pressure-sensitive strobes.\n    (ex/make-strobe-cue-2 \"All\" (show/all-fixtures) x-base (+ y-base 7))\n    (ex/make-strobe-cue-2 \"Torrents\" (show/fixtures-named \"torrent\") (inc x-base) (+ y-base 7))\n    (ex/make-strobe-cue-2 \"Blades\" (show/fixtures-named \"blade\") (+ x-base 2) (+ y-base 7))\n    (ex/make-strobe-cue-2 \"Weather Systems\" (show/fixtures-named \"ws\") (+ x-base 3) (+ y-base 7))\n    (ex/make-strobe-cue-2 \"Hexes\" (show/fixtures-named \"hex\") (+ x-base 4) (+ y-base 7))\n    (ex/make-strobe-cue-2 \"Pucks\" (show/fixtures-named \"puck\") (+ x-base 5) (+ y-base 7))\n    (ex/make-strobe-cue-2 \"Snowball\" (show/fixtures-named \"snowball\") (+ x-base 6) (+ y-base 7))\n\n    (let [color-var {:key :strobe-color :type :color :name \"Strobe Color\"}]\n      (show/set-cue! (+ x-base 7) (+ y-base 7) (cues/cue :strobe-color (fn [_] (fx/blank \"Strobe Color\"))\n                                                         :color :purple\n                                                         :color-fn (cues/color-fn-from-cue-var color-var)\n                                                         :variables [color-var])))\n\n))\n\n(defn more-color-cues\n  \"Some miscellany which I'm not totally sure what to do with.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)]\n\n    ;; Some dimmer sweeps\n    (let [dimmer-sweep-fixtures (concat (show/fixtures-named :torrent) (show/fixtures-named :blade)\n                                        (show/fixtures-named :hex))]\n      (show/set-cue! x-base y-base\n                     (cues/cue :dimmers\n                               (fn [var-map] (cues/apply-merging-var-map\n                                              var-map ex/dimmer-sweep  dimmer-sweep-fixtures\n                                              (oscillators/sawtooth :down? (:down var-map)\n                                                                    :interval-ratio (ex/build-ratio-param var-map))))\n                               :color :red :short-name \"Sawtooth Sweep\"\n                               :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                           {:key \"down\" :type :boolean :start true :name \"Down?\"}\n                                           {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                           {:key \"width\" :min 0 :max 1 :start 0.1 :name \"Width\"}\n                                           {:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}\n                                           {:key \"fade\" :type :boolean :start false :name \"Fade?\"}]))\n\n      (show/set-cue! x-base (inc y-base)\n                     (cues/cue :dimmers\n                               (fn [var-map] (cues/apply-merging-var-map\n                                              var-map ex/dimmer-sweep dimmer-sweep-fixtures\n                                              (oscillators/triangle :interval-ratio (ex/build-ratio-param var-map))))\n                               :color :red :short-name \"Triangle Sweep\"\n                               :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                           {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                           {:key \"width\" :min 0 :max 1 :start 0.25 :name \"Width\"}\n                                           {:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}\n                                           {:key \"fade\" :type :boolean :start false :name \"Fade?\"}])))\n\n    (show/set-cue! (inc x-base) y-base\n                   (cues/cue :blade-dimmers\n                             (fn [var-map] (cues/apply-merging-var-map\n                                            var-map ex/dimmer-sweep  (show/fixtures-named :blade)\n                                            (oscillators/sawtooth :down? (:down var-map)\n                                                                  :interval-ratio (ex/build-ratio-param var-map))))\n                             :color :red :short-name \"Blade Saw Sweep\"\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                         {:key \"down\" :type :boolean :start true :name \"Down?\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"width\" :min 0 :max 1 :start 0.1 :name \"Width\"}\n                                         {:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}\n                                         {:key \"fade\" :type :boolean :start false :name \"Fade?\"}]))\n\n    (show/set-cue! (inc x-base) (inc y-base)\n                   (cues/cue :blade-dimmers\n                             (fn [var-map] (cues/apply-merging-var-map\n                                            var-map ex/dimmer-sweep (show/fixtures-named :blade)\n                                            (oscillators/triangle :interval-ratio (ex/build-ratio-param var-map))))\n                               :color :red :short-name \"Blade Triangle Sweep\"\n                               :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                           {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                           {:key \"width\" :min 0 :max 1 :start 0.25 :name \"Width\"}\n                                           {:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}\n                                           {:key \"fade\" :type :boolean :start false :name \"Fade?\"}]))\n\n    (show/set-cue! (inc x-base) (+ 2 y-base)\n                   (cues/cue :blade-dimmers\n                             (fn [var-map]\n                               (let [step (params/build-step-param :interval-ratio (ex/build-ratio-param var-map)\n                                                                   :fade-fraction (:fade-fraction var-map))]\n                                 (fx/chase \"Blade Cross\"\n                                           (map #(dimmer-effect (:level var-map) (show/fixtures-named %))\n                                                [:blade-1 :blade-3 :blade-2 :blade-4])\n                                           step :beyond :loop)))\n                               :color :red :short-name \"Blade Cross\"\n                               :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 1 :name \"Beats\"}\n                                           {:key \"cycles\" :min 1 :max 10 :type :integer :start 4 :name \"Cycles\"}\n                                           {:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}\n                                           {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}]))\n\n    ;; A fun pressure-sensitive dimmer spread effect\n    (show/set-cue! x-base (+ y-base 2)\n                   (cues/cue :bloom (fn [var-map]\n                                      (cues/apply-merging-var-map\n                                       var-map fun/bloom (show/all-fixtures)\n                                       :measure (tf/build-distance-measure 0 ex/rig-height 0 :ignore-z true)))\n                             :variables [{:key \"color\" :type :color :start (colors/create-color :white)\n                                          :name \"Color\"}\n                                         {:key \"fraction\" :min 0 :max 1 :start 0 :velocity true}]\n                             :held true :priority 1000 :color :purple))\n\n    ;; Some color cycle chases  TODO: These probably belong in the color section.\n    (show/set-cue! x-base (+ y-base 7)\n                   (cues/cue :all-color (fn [_] (fun/iris-out-color-cycle-chase (show/all-fixtures)))))\n    (show/set-cue! (inc x-base) (+ y-base 7)\n                   (cues/cue :all-color\n                             (fn [_] (fun/wipe-right-color-cycle-chase\n                                      (show/all-fixtures)\n                                      :transition-phase-function rhythm/snapshot-bar-phase))))\n    (show/set-cue! (+ x-base 2) (+ y-base 7)\n                   (cues/cue :all-color (fn [_] (fun/wipe-right-color-cycle-chase\n                                                 (show/all-fixtures)\n                                                 :color-index-function rhythm/snapshot-beat-within-phrase\n                                                 :transition-phase-function rhythm/snapshot-beat-phase\n                                                 :effect-name \"Wipe Right Beat\"))))\n\n    (show/set-cue! (+ x-base 5) y-base\n                   (cues/cue :pinstripes\n                             (fn [var-map]\n                               (let [step-ratio (ex/build-ratio-param var-map)\n                                     step (params/build-step-param :interval-ratio step-ratio\n                                                                   :fade-fraction (:fade-fraction var-map))\n                                     colors [(:color-1 var-map) (:color-2 var-map)]]\n                                 (fun/pinstripes (set/difference\n                                                  (set (show/all-fixtures))\n                                                  (set (show/fixtures-named :snowball)))\n                                                 :step step :colors colors)))\n                             :variables [{:key \"beats\" :name \"Beats\" :min 1 :max 32 :type :integer :start 1}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 16 :type :integer :start 1}\n                                         {:key \"color-1\" :type :color :start (colors/create-color :red)\n                                          :name \"Color 1\"}\n                                         {:key \"color-2\" :type :color :start (colors/create-color :white)\n                                          :name \"Color 2\"}\n                                         {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}]\n                             :color :yellow))\n\n    (show/set-cue! (+ x-base 5) (inc y-base)\n                   (cues/cue :pinstripes\n                             (fn [var-map]\n                               (let [step-ratio (ex/build-ratio-param var-map)\n                                     step (params/build-step-param :interval-ratio step-ratio\n                                                                   :fade-fraction (:fade-fraction var-map))\n                                     colors [(:color-1 var-map) (:color-2 var-map) (:color-3 var-map)]]\n                                 (fun/pinstripes (set/difference\n                                                  (set (show/all-fixtures))\n                                                  (set (show/fixtures-named :snowball)))\n                                                 :step step :colors colors)))\n                             :variables [{:key \"beats\" :name \"Beats\" :min 1 :max 32 :type :integer :start 1}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 16 :type :integer :start 1}\n                                         {:key \"color-1\" :type :color :start (colors/create-color :red)\n                                          :name \"Color 1\"}\n                                         {:key \"color-2\" :type :color :start (colors/create-color :white)\n                                          :name \"Color 2\"}\n                                         {:key \"color-3\" :type :color :start (colors/create-color :blue)\n                                          :name \"Color 3\"}\n                                         {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}]\n                             :color :orange :short-name \"Pin 3\"))\n\n    (show/set-cue! (+ x-base 5) (+ 2 y-base)\n                   (cues/cue :pinstripes\n                             (fn [var-map]\n                               (let [step-ratio (ex/build-ratio-param var-map)\n                                     step (params/build-step-param :interval-ratio step-ratio\n                                                                   :fade-fraction (:fade-fraction var-map))\n                                     colors [(:color-1 var-map) (:color-2 var-map)\n                                             (:color-3 var-map) (:color-4 var-map)]]\n                                 (fun/pinstripes (set/difference\n                                                  (set (show/all-fixtures))\n                                                  (set (show/fixtures-named :snowball)))\n                                                 :step step :colors colors)))\n                             :variables [{:key \"beats\" :name \"Beats\" :min 1 :max 32 :type :integer :start 1}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 16 :type :integer :start 1}\n                                         {:key \"color-1\" :type :color :start (colors/create-color :yellow)\n                                          :name \"Color 1\"}\n                                         {:key \"color-2\" :type :color :start (colors/create-color :purple)\n                                          :name \"Color 2\"}\n                                         {:key \"color-3\" :type :color :start (colors/create-color :white)\n                                          :name \"Color 3\"}\n                                         {:key \"color-4\" :type :color :start (colors/create-color :cyan)\n                                          :name \"Color 4\"}\n                                         {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}]\n                             :color :orange :short-name \"Pin 4\"))))\n\n(defn restore-macros\n  \"Adds the macros Chris created while figuring out how to use the show.\"\n  []\n  (show/set-cue! 6 4\n  (cues/cue :macro-19\n    (fn [_] (cues/compound-cues-effect \"figure 8 Blades\" *show*\n            [[21 7 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.0, :tilt-min 76.0, :tilt-max 170.0, :tilt-bars 6, :tilt-phase 0.6}] [20 7 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.0, :tilt-min 48.0, :tilt-max 170.0, :tilt-bars 6, :tilt-phase 0.4}] [19 7 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.0, :tilt-min 49.0, :tilt-max 170.0, :tilt-bars 6, :tilt-phase 0.2}] [18 7 {:pan-min 12.0, :pan-max 66.0, :pan-bars 4, :pan-phase 0.0, :tilt-min 76.0, :tilt-max 170.0, :tilt-bars 6, :tilt-phase 0.0}] [18 4 {:direction-group-b-pan 0.0, :direction-group-b-tilt 0.0}]])))))\n\n(defn make-cues\n  \"Set up the pages of cues.\"\n  []\n  ;; Enable cues whose purpose is to set show variable values while they run.\n  (let [var-binder (atom (var-fx/create-for-show *show*))]\n    (make-movement-cues 0 0)\n    (misc-movement-cues 1 0)\n    (ex/make-main-direction-cues 2 0 var-binder)\n    (ex/make-main-aim-cues 3 0 var-binder false)\n    (ex/make-torrent-cues 0 1)\n    (make-main-dimmer-cues 0 2)\n    (ex/make-ambient-cues 1 2)\n    (make-main-color-cues 0 3 false)\n    (more-color-cues 1 3)\n    (restore-macros)))\n\n(def quantize-id\n  \"Keeps track of the ID of the strobe effect launched by pressing the\n  quantize button, so we can safely end it when releasing the button.\"\n  (atom nil))\n\n(defn quantize-pushed\n  \"We register this to be called when the quantize button is pressed on a\n  push, to trigger our strobe-all effect.\"\n  []\n  (show/set-variable! :strobe-color (colors/create-color :white))\n  (reset! quantize-id (show/add-effect-from-cue-grid! 0 23)))\n\n(defn quantize-released\n  \"We register this to be called when the quantize button is released on a\n  push, to end the strobe-all effect if it's still running from when\n  the quantize button was pressed.\"\n  []\n  (show/end-effect! :strobe-all :when-id @quantize-id))\n\n(defn master-pushed\n  \"We register this function to be called when the master button is\n  pressed on a push, to jump to our dimmer cues page.\"\n  [grid-controller]\n  (ct/current-left grid-controller 0)\n  (ct/current-bottom grid-controller 16))\n\n(defn delete-pushed\n  \"We register this function to be called when the delete button is\n  pressed on a push, to kill all cues and then restart the torrent\n  shutter open cue.\"\n  []\n  (show/clear-effects!)\n  (show/add-effect-from-cue-grid! 0 15))\n\n(defn grid-controller-listener\n  \"Called whenever grid controllers are added to or removed from the\n  show. Sets up our custom buttons on any Ableton Push controllers\n  that get attached.\"\n  [event grid-controller]\n  (when (= :register event)\n    (let [controller (ct/controller grid-controller)]\n      (when (#{:afterglow.controllers.ableton-push/controller\n               :afterglow.controllers.ableton-push-2/controller} (:type (meta controller)))\n        (push/add-custom-control-button controller :quantize quantize-pushed quantize-released)\n        (push/add-custom-control-button controller :master (partial master-pushed grid-controller)\n                                        (constantly nil))\n        (push/add-custom-control-button controller :delete delete-pushed (constantly nil))))))\n\n(defn use-chris-show\n  \"Set up the show for Chris. By default it will create the\n  show to use universe 1, but if you want to use a different\n  universe (for example, a dummy universe on ID 0, because your DMX\n  interface isn't handy right now), you can override that by supplying\n  a different ID after :universe.\"\n  [& {:keys [universe] :or {universe 1}}]\n  ;; Since this class is an entry point for interactive REPL usage,\n  ;; make sure a sane logging environment is established.\n  (core/init-logging)\n\n  ;; Create, or re-create the show, on the chosen OLA universe, for demonstration\n  ;; purposes. Make it the default show so we don't need to wrap everything below\n  ;; in a (with-show sallie-show ...) binding\n  (set-default-show! (swap! chris-show (fn [s]\n                                         (when s\n                                           (show/unregister-show s)\n                                           (with-show s (show/stop!)))\n                                         (show/show :universes [universe]\n                                                    :description \"Chris Show\"\n                                                    :grid-controller-listener grid-controller-listener))))\n\n  (ex/patch-lighting-rig :universe universe :y ex/rig-height\n                         :blade-3-angle (tf/degrees 71.2) :blade-4-angle (tf/degrees 78.7))\n  (show/patch-fixture! :ws-1 (blizzard/weather-system) universe 161 :x 2.2 :y 1.33 :z -1.1 :y-rotation 0.0)\n  (show/patch-fixture! :ws-2 (blizzard/weather-system) universe 187 :x -2.2 :y 1.33 :z -1.1 :y-rotation 0.0)\n  (show/patch-fixture! :puck-1 (blizzard/puck-fab5) universe 97 :x (tf/inches -76) :y (tf/inches 8) :z (tf/inches 52))\n  (show/patch-fixture! :puck-2 (blizzard/puck-fab5) universe 113 :x (tf/inches -76) :y (tf/inches 8) :z (tf/inches 40))\n\n  (make-cues)\n\n  ;; Automatically bind the show to any compatible grid controllers that are connected now\n  ;; or in the future.\n  (ct/auto-bind *show*)\n\n  ;; Start the torrent shutter open cue, which we always want to have running.\n  (show/add-effect-from-cue-grid! 0 15)\n\n  ;; Open the web browser interface\n  (core/start-web-server 16000 true)\n\n  ;; Save any macros Chris records so we can add them to the show if we want to.\n  (reset! afterglow.web.routes.show-control/macro-record-file \"/Users/Zim/macros.clj\")\n\n  '*show*)\n"
  },
  {
    "path": "src/afterglow/shows/sallie.clj",
    "content": "(ns afterglow.shows.sallie\n  \"Cues for Sallie's birthday/housewarming party. Useful as an example\n  of how an actual small show was put together early in Afterglow's\n  development, and also as a source of effects that may want to make\n  their way into a more central place.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.beyond :as beyond]\n            [afterglow.controllers.ableton-push :as push]\n            [afterglow.controllers :as ct]\n            [afterglow.core :as core]\n            [afterglow.effects :as fx]\n            [afterglow.effects.color :as color-fx]\n            [afterglow.effects.cues :as cues]\n            [afterglow.effects.dimmer :refer [dimmer-effect master-set-level]]\n            [afterglow.effects.fun :as fun]\n            [afterglow.effects.movement :as move]\n            [afterglow.effects.oscillators :as oscillators]\n            [afterglow.effects.params :as params]\n            [afterglow.effects.show-variable :as var-fx]\n            [afterglow.fixtures.american-dj :as adj]\n            [afterglow.fixtures.blizzard :as blizzard]\n            [afterglow.fixtures.chauvet :as chauvet]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [*show* with-show set-default-show!]]\n            [afterglow.transform :as tf]\n            [com.evocomputing.colors :refer [color-name create-color hue adjust-hue]]\n            [overtone.osc :as osc]\n            [taoensso.timbre :as timbre]))\n\n(defonce ^{:doc \"Holds the show if it has been created,\n  so it can be unregistered if it is being re-created.\"}\n  sallie-show\n  (atom nil))\n\n(defonce ^{:doc \"Allows commands to be sent to the instance of\n  Pangolin Beyond running alongside this light show, in order to\n  affect laser cues.\"}\n  laser-show\n  (afterglow.beyond/beyond-server \"192.168.212.128\" 16062))\n\n(defonce ^{:doc \"Allows effects to set variables in the running show.\"}\n  var-binder\n  (atom nil))\n\n(defn use-sallie-show\n  \"Set up the show for Sallie's party. By default it will create the\n  show to use universe 1, but if you want to use a different\n  universe (for example, a dummy universe on ID 0, because your DMX\n  interface isn't handy right now), you can override that by supplying\n  a different ID after :universe.\"\n  [& {:keys [universe] :or {universe 1}}]\n  ;; Since this class is an entry point for interactive REPL usage,\n  ;; make sure a sane logging environment is established.\n  (core/init-logging)\n\n  ;; Create, or re-create the show, on the chosen OLA universe, for demonstration\n  ;; purposes. Make it the default show so we don't need to wrap everything below\n  ;; in a (with-show sallie-show ...) binding\n  (set-default-show! (swap! sallie-show (fn [s]\n                                          (when s\n                                            (show/unregister-show s)\n                                            (with-show s (show/stop!)))\n                                          (show/show :universes [universe] :description \"Sallie Show\"))))\n\n  (show/patch-fixture! :hex-1 (chauvet/slimpar-hex3-irc) universe 129 :x (tf/inches 14) :y (tf/inches 44)\n                       :z (tf/inches -4.75)\n                       :x-rotation (tf/degrees 90))\n  (show/patch-fixture! :hex-2 (chauvet/slimpar-hex3-irc) universe 145 :x (tf/inches -14) :y (tf/inches 44)\n                       :z (tf/inches -4.75)\n                       :x-rotation (tf/degrees 90))\n  (show/patch-fixture! :ws-1 (blizzard/weather-system) universe 161\n                       :x (tf/inches 55) :y (tf/inches 71) :z (tf/inches 261) :y-rotation (tf/degrees 225))\n  (show/patch-fixture! :snowball (blizzard/snowball) universe 33 :x (tf/inches -76) :y (tf/inches 32)\n                       :z (tf/inches 164.5))\n  (beyond/bind-to-show laser-show *show*)\n  (reset! var-binder (var-fx/create-for-show *show*))\n  '*show*)\n\n\n(defn global-color-effect\n  \"Make a color effect which affects all lights in the Sallie show.\n  If the show variable `:also-color-laser` has a value other than `0`,\n  the color will be sent to Beyond to affect laser cues as well. Can\n  include only a specific set of lights by passing them with\n  `:lights`\"\n  [color & {:keys [include-color-wheels? lights] :or {lights (show/all-fixtures)}}]\n  (try\n    (let [[c desc] (cond (= (type color) :com.evocomputing.colors/color)\n                       [color (color-name color)]\n                       (and (params/param? color)\n                            (= (params/result-type color) :com.evocomputing.colors/color))\n                       [color \"variable\"]\n                       :else\n                       [(create-color color) color])]\n      (fx/scene (str \"Color: \" desc)\n                (color-fx/color-effect (str \"Color: \" desc) c lights :include-color-wheels? include-color-wheels?)\n                (fx/conditional-effect \"Color Laser?\" (params/build-variable-param :also-color-laser)\n                                       (beyond/laser-color-effect laser-show c))))\n    (catch Exception e\n      (throw (Exception. (str \"Can't figure out how to create color from \" color) e)))))\n\n(defn global-dimmer-effect\n  \"Return an effect that sets all the dimmers in the sallie rig.\n  Originally this had to be to a static value, but now that dynamic\n  parameters exist, it can vary in response to a MIDI mapped show\n  variable, an oscillator, or the location of the fixture. You can\n  override the default name by passing in a value with :effect-name\"\n  [level & {:keys [effect-name]}]\n  (dimmer-effect level (show/all-fixtures) :effect-name effect-name))\n\n(defn global-color-cue\n  \"Create a cue-grid entry which establishes a global color effect.\"\n  [color x y & {:keys [include-color-wheels? held]}]\n  (let [cue (cues/cue :color (fn [_] (global-color-effect color :include-color-wheels? include-color-wheels?))\n                      :held held\n                      :color (create-color color))]\n    (ct/set-cue! (:cue-grid *show*) x y cue)))\n\n(defn make-strobe-cue\n  \"Create a cue which strobes a set of fixtures as long as the cue pad\n  is held down, letting the operator adjust the lightness of the\n  strobe color by varying the pressure they are applying to the pad on\n  controllers which support pressure sensitivity.\"\n  [name fixtures x y]\n  (ct/set-cue! (:cue-grid *show*) x y\n               (cues/cue (keyword (str \"strobe-\" (clojure.string/replace (clojure.string/lower-case name) \" \" \"-\")))\n                         (fn [var-map] (fun/strobe (str \"Strobe \" name) fixtures\n                                                   (:level var-map 50) (:lightness var-map 100)))\n                         :color :purple\n                         :held true\n                         :priority 100\n                         :variables [{:key \"level\" :min 0 :max 100 :start 100 :name \"Level\"}\n                                     {:key \"lightness\" :min 0 :max 100 :name \"Lightness\" :velocity true}])))\n\n(defn x-phase\n  \"Return a value that ranges from zero for the leftmost fixture in a\n  show to 1 for the rightmost, for staggering the phase of an\n  oscillator in making a can-can chase.\"\n  [head show]\n  (let [dimensions @(:dimensions *show*)]\n    (/ (- (:x head) (:min-x dimensions)) (- (:max-x dimensions) (:min-x dimensions)))))\n\n(defn try-laser-cues\n  \"Create some cues that integrate Pangolin Beyond. Assumes sallie\n  show has been created, and takes the beyond server to work with as\n  an argument.\"\n  [server]\n  (ct/set-cue! (:cue-grid *show*) 2 7\n               (cues/cue :beyond-cue-1-1 (fn [_] (beyond/cue-effect server 1 1))\n                         :short-name \"Beyond 1 1\"))\n  (ct/set-cue! (:cue-grid *show*) 3 7\n               (cues/cue :beyond-cue-1-2 (fn [_] (beyond/cue-effect server 1 2))\n                         :short-name \"Beyond 1 2\")))\n\n\n(defn make-cues\n  \"Create the cues for the Sallie show.\"\n  []\n  {:pre [(some? *show*)]}\n  (let [hue-bar (oscillators/build-oscillated-param  ; Spread a rainbow across a bar of music\n                 (oscillators/sawtooth :interval :bar) :max 360)\n        desat-beat (oscillators/build-oscillated-param  ; Desaturate a color as a beat progresses\n                    (oscillators/sawtooth :down? true) :max 100)\n        hue-gradient (params/build-spatial-param  ; Spread a rainbow across the light grid\n                      (show/all-fixtures)\n                      (fn [head] (- (:x head) (:min-x @(:dimensions *show*)))) :max 360)]\n    (global-color-cue \"red\" 0 0 :include-color-wheels? true)\n    (global-color-cue \"orange\" 1 0 :include-color-wheels? true)\n    (global-color-cue \"yellow\" 2 0 :include-color-wheels? true)\n    (global-color-cue \"green\" 3 0 :include-color-wheels? true)\n    (global-color-cue \"blue\" 4 0 :include-color-wheels? true)\n    (global-color-cue \"purple\" 5 0 :include-color-wheels? true)\n    (global-color-cue \"violet\" 6 0 :include-color-wheels? true)\n    (global-color-cue \"white\" 7 0 :include-color-wheels? true)\n    (global-color-cue \"pink\" 0 1 :include-color-wheels? true)\n    (global-color-cue \"salmon\" 1 1 :include-color-wheels? true)\n    (global-color-cue \"teal\" 2 1 :include-color-wheels? true)\n    (global-color-cue \"cyan\" 3 1 :include-color-wheels? true)\n\n    (ct/set-cue! (:cue-grid *show*) 4 1\n                 (cues/cue :color (fn [_] (global-color-effect\n                                           (params/build-color-param :s :rainbow-saturation :l 50 :h hue-bar)))\n                           :short-name \"Rainbow Bar Fade\"\n                           :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                        :type :integer}]))\n    (ct/set-cue! (:cue-grid *show*) 5 1\n                 (cues/cue :color (fn [_] (global-color-effect\n                                           (params/build-color-param :s :rainbow-saturation :l 50 :h hue-gradient)\n                                           :include-color-wheels? true))\n                           :short-name \"Rainbow Grid\"\n                           :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                        :type :integer}]))\n    (ct/set-cue! (:cue-grid *show*) 6 1\n                 (cues/cue :color (fn [_] (global-color-effect\n                                           (params/build-color-param :s :rainbow-saturation :l 50 :h hue-gradient\n                                                                     :adjust-hue hue-bar)))\n                           :short-name \"Rainbow Grid+Bar\"\n                           :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                        :type :integer}]))\n\n    (ct/set-cue! (:cue-grid *show*) 7 1  ; Desaturate the rainbow as each beat progresses\n                 (cues/cue :color (fn [_] (global-color-effect\n                                           (params/build-color-param :s desat-beat :l 50 :h hue-gradient\n                                                                     :adjust-hue hue-bar)))\n                           :short-name \"Rainbow Pulse\"))\n\n    ;; A cue which causes any colors to be desaturated over the course of each beat.\n    (ct/set-cue! (:cue-grid *show*) 2 7\n                 (cues/cue :transform-colors (fn [_] (color-fx/transform-colors (show/all-fixtures)\n                                                                                :beyond-server laser-show))\n                           :priority 1000))\n\n    (ct/set-cue! (:cue-grid *show*) 3 7\n                 (cues/cue :color (fn [var-map]\n                                    (let [hue (fun/random-beat-number-param :max 360 :min-change 60)]\n                                      (global-color-effect\n                                       (params/build-color-param :h hue :l 50 :s (:saturation var-map 100)))))\n                           :short-name \"Random Beat Color\"))\n\n    (ct/set-cue! (:cue-grid *show*) 0 7\n                 (cues/cue :sparkle (fn [var-map] (fun/sparkle (show/all-fixtures)\n                                                               :chance (:chance var-map 0.05)\n                                                               :fade-time (:fade-time var-map 50)))\n                           :held true\n                           :priority 100\n                           :variables [{:key \"chance\" :min 0.0 :max 0.4 :start 0.05 :velocity true}\n                                       {:key \"fade-time\" :name \"Fade\" :min 1 :max 2000 :start 50 :type :integer}]))\n\n    (ct/set-cue! (:cue-grid *show*) 5 6\n                 (cues/function-cue :strobe-all :strobe (show/all-fixtures) :effect-name \"Raw Strobe\"))\n\n    (ct/set-cue! (:cue-grid *show*) 5 7\n                 (cues/cue :color-laser (fn [_] (var-fx/variable-effect @var-binder :also-color-laser 1))\n                           :color :red :short-name \"Also color laser\"))\n\n    (ct/set-cue! (:cue-grid *show*) 6 7\n                 (cues/function-cue :snowball-sound :sound-active (show/fixtures-named \"snowball\")\n                                    :color :cyan))\n\n    (ct/set-cue! (:cue-grid *show*) 7 7\n                 (cues/function-cue :hex-uv :uv (show/all-fixtures)\n                                    :level 100 :color :blue :short-name \"All UV\"))\n\n    ;; Dimmer cues to turn on and set brightness of groups of lights\n    (ct/set-cue! (:cue-grid *show*) 0 2\n                 (cues/cue :dimmers (fn [var-map] (global-dimmer-effect\n                                                   (params/bind-keyword-param (:level var-map 255) Number 255)\n                                                   :effect-name \"All Dimmers\"))\n                           :variables [{:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}]\n                           :color :yellow :end-keys [:torrent-dimmers :blade-dimmers :ws-dimmers\n                                                     :puck-dimmers :hex-dimmers :snowball-dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 1 2\n                 (cues/cue :ws-dimmers (fn [var-map] (dimmer-effect\n                                                      (params/bind-keyword-param (:level var-map 255) Number 255)\n                                                      (show/fixtures-named \"ws\")\n                                                      :effect-name \"Weather System Dimmers\"))\n                           :variables [{:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}]\n                           :color :orange :end-keys [:dimmers]))\n\n    (ct/set-cue! (:cue-grid *show*) 2 2\n                 (cues/cue :hex-dimmers (fn [var-map] (dimmer-effect\n                                                       (params/bind-keyword-param (:level var-map 255) Number 255)\n                                                       (show/fixtures-named \"hex\")\n                                                       :effect-name \"Hex Dimmers\"))\n                           :variables [{:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}]\n                           :color :orange :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 3 2\n                 (cues/cue :snowball-dimmers (fn [var-map] (dimmer-effect\n                                                            (params/bind-keyword-param (:level var-map 255) Number 255)\n                                                            (show/fixtures-named \"snowball\")\n                                                            :effect-name \"Snowball Dimmers\"))\n                           :variables [{:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}]\n                           :color :orange :end-keys [:dimmers]))\n\n    ;; Dimmer oscillator cues: Sawtooth down each beat\n    (ct/set-cue! (:cue-grid *show*) 0 3\n                 (cues/cue :dimmers (fn [_] (global-dimmer-effect\n                                             (oscillators/build-oscillated-param\n                                              (oscillators/sawtooth :down? true))\n                                             :effect-name \"All Saw Down Beat\"))\n                           :color :yellow :end-keys [:ws-dimmers :hex-dimmers :snowball-dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 1 3\n                 (cues/cue :ws-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sawtooth :down? true))\n                                    (show/fixtures-named \"ws\") :effect-name \"WS Saw Down Beat\"))\n                           :color :orange :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 2 3\n                 (cues/cue :hex-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sawtooth :down? true))\n                                    (show/fixtures-named \"hex\") :effect-name \"Hex Saw Down Beat\"))\n                           :color :orange :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 3 3\n                 (cues/cue :snowball-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sawtooth :down? true))\n                                    (show/fixtures-named \"snowball\") :effect-name \"Snowball Saw Down Beat\"))\n                           :color :orange :end-keys [:dimmers]))\n\n    ;; Dimmer oscillator cues: Sawtooth up each beat\n    (ct/set-cue! (:cue-grid *show*) 4 3\n                 (cues/cue :dimmers (fn [_] (global-dimmer-effect\n                                             (oscillators/build-oscillated-param (oscillators/sawtooth))\n                                             :effect-name \"All Saw Up Beat\"))\n                           :color :yellow :end-keys [:ws-dimmers :hex-dimmers :snowball-dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 5 3\n                 (cues/cue :ws-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sawtooth))\n                                    (show/fixtures-named \"ws\") :effect-name \"WS Saw Up Beat\"))\n                           :color :orange :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 6 3\n                 (cues/cue :hex-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sawtooth))\n                                    (show/fixtures-named \"hex\") :effect-name \"Hex Saw Up Beat\"))\n                           :color :orange :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 7 3\n                 (cues/cue :snowball-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sawtooth))\n                                    (show/fixtures-named \"snowball\") :effect-name \"Snowball Saw Up Beat\"))\n                           :color :orange :end-keys [:dimmers]))\n\n    ;; Dimmer oscillator cues: Sawtooth down over 2 beat\n    (ct/set-cue! (:cue-grid *show*) 0 4\n                 (cues/cue :dimmers (fn [_] (global-dimmer-effect\n                                             (oscillators/build-oscillated-param\n                                              (oscillators/sawtooth :interval-ratio 2 :down? true))\n                                             :effect-name \"All Saw Down 2 Beat\"))\n                           :color :yellow :end-keys [:ws-dimmers :hex-dimmers :snowball-dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 1 4\n                 (cues/cue :ws-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sawtooth :interval-ratio 2\n                                                                                              :down? true))\n                                    (show/fixtures-named \"ws\") :effect-name \"WS Saw Down 2 Beat\"))\n                           :color :orange :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 2 4\n                 (cues/cue :hex-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sawtooth :interval-ratio 2\n                                                                                              :down? true))\n                                    (show/fixtures-named \"hex\") :effect-name \"Hex Saw Down 2 Beat\"))\n                           :color :orange :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 3 4\n                 (cues/cue :snowball-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sawtooth :interval-ratio 2\n                                                                                              :down? true))\n                                    (show/fixtures-named \"snowball\") :effect-name \"Snowball Saw Down 2 Beat\"))\n                           :color :orange :end-keys [:dimmers]))\n\n    ;; Dimmer oscillator cues: Sawtooth up over 2 beat\n    (ct/set-cue! (:cue-grid *show*) 4 4\n                 (cues/cue :dimmers (fn [_] (global-dimmer-effect\n                                             (oscillators/build-oscillated-param\n                                              (oscillators/sawtooth :interval-ratio 2))\n                                             :effect-name \"All Saw Up 2 Beat\"))\n                           :color :yellow :end-keys [:ws-dimmers :hex-dimmers :snowball-dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 5 4\n                 (cues/cue :ws-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sawtooth :interval-ratio 2))\n                                    (show/fixtures-named \"ws\") :effect-name \"WS Saw Up 2 Beat\"))\n                           :color :orange :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 6 4\n                 (cues/cue :hex-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sawtooth :interval-ratio 2))\n                                    (show/fixtures-named \"hex\") :effect-name \"Hex Saw Up 2 Beat\"))\n                           :color :orange :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 7 4\n                 (cues/cue :snowball-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sawtooth :interval-ratio 2))\n                                    (show/fixtures-named \"snowball\") :effect-name \"Snowball Saw Up 2 Beat\"))\n                           :color :orange :end-keys [:dimmers]))\n\n    ;; Dimmer oscillator cues: Sine over a bar\n    (ct/set-cue! (:cue-grid *show*) 0 5\n                 (cues/cue :dimmers (fn [_] (global-dimmer-effect\n                                             (oscillators/build-oscillated-param (oscillators/sine :interval :bar)\n                                                                                 :min 1)\n                                             :effect-name \"All Sine Bar\"))\n                           :color :cyan :end-keys [:ws-dimmers :hex-dimmers :snowball-dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 1 5\n                 (cues/cue :ws-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sine :interval :bar) :min 1)\n                                    (show/fixtures-named \"ws\") :effect-name \"WS Sine Bar\"))\n                           :color :blue :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 2 5\n                 (cues/cue :hex-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sine :interval :bar) :min 1)\n                                    (show/fixtures-named \"hex\") :effect-name \"Hex Sine Bar\"))\n                           :color :blue :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 3 5\n                 (cues/cue :snowball-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/sine :interval :bar) :min 1)\n                                    (show/fixtures-named \"snowball\") :effect-name \"Snowball Sine Bar\"))\n                           :color :blue :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 4 5\n                 (cues/cue :dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/triangle :interval :bar) :min 1)\n                                    (show/all-fixtures) :effect-name \"All Triangle Bar\"))\n                           :color :purple :end-keys [:ws-dimmers :hex-dimmers :snowball-dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 5 5\n                 (cues/cue :ws-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/triangle :interval :bar) :min 1)\n                                    (show/fixtures-named \"ws\") :effect-name \"WS Triangle Bar\"))\n                           :color :violet :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 6 5\n                 (cues/cue :hex-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/triangle :interval :bar) :min 1)\n                                    (show/fixtures-named \"hex\") :effect-name \"Hex Triangle Bar\"))\n                           :color :violet :end-keys [:dimmers]))\n    (ct/set-cue! (:cue-grid *show*) 7 5\n                 (cues/cue :snowball-dimmers\n                           (fn [_] (dimmer-effect\n                                    (oscillators/build-oscillated-param (oscillators/triangle :interval :bar) :min 1)\n                                    (show/fixtures-named \"snowball\") :effect-name \"Snowball Triangle Bar\"))\n                           :color :violet :end-keys [:dimmers]))\n\n    ;; Strobe cues\n    (make-strobe-cue \"All\" (show/all-fixtures) 0 6)\n    (make-strobe-cue \"Weather Systems\" (show/fixtures-named \"ws\") 1 6)\n    (make-strobe-cue \"Hexes\" (show/fixtures-named \"hex\") 2 6)\n    (make-strobe-cue \"Snowball\" (show/fixtures-named \"snowball\") 3 6)\n\n    (ct/set-cue! (:cue-grid *show*) 7 6\n                 (cues/cue :adjust-strobe (fn [_] (fun/adjust-strobe))\n                           :color :purple\n                           :variables [{:key :strobe-hue :min 0 :max 360 :name \"Hue\" :centered true}\n                                       {:key :strobe-saturation :min 0 :max 100 :name \"Saturatn\"}]))\n\n    ;; A couple snowball cues\n    (ct/set-cue! (:cue-grid *show*) 0 10 (cues/function-cue :sb-pos :beams-fixed (show/fixtures-named \"snowball\")\n                                                            :effect-name \"Snowball Fixed\"))\n    (ct/set-cue! (:cue-grid *show*) 1 10 (cues/function-cue :sb-pos :beams-moving (show/fixtures-named \"snowball\")\n                                                            :effect-name \"Snowball Moving\"))\n\n    ;; Some example chases\n    (ct/set-cue! (:cue-grid *show*) 8 1\n                 (cues/cue :color (fn [_] (fun/iris-out-color-cycle-chase (show/all-fixtures)))))\n    (ct/set-cue! (:cue-grid *show*) 9 1\n                 (cues/cue :color (fn [_] (fun/wipe-right-color-cycle-chase\n                                           (show/all-fixtures) :transition-phase-function rhythm/snapshot-bar-phase))))\n    (ct/set-cue! (:cue-grid *show*) 10 1\n                 (cues/cue :color (fn [_] (fun/wipe-right-color-cycle-chase\n                                           (show/all-fixtures)\n                                           :color-index-function rhythm/snapshot-beat-within-phrase\n                                           :transition-phase-function rhythm/snapshot-beat-phase\n                                           :effect-name \"Wipe Right Beat\"))))))\n"
  },
  {
    "path": "src/afterglow/shows/wedding.clj",
    "content": "(ns afterglow.shows.wedding\n  \"Cues for Joey and Courtney's wedding reception. Useful as an example\n  of how an actual small show was put together using a subset of the\n  Deep Symmetry lighting rig, and perhaps as a source of effects that\n  may want to make their way to a more central place\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as chan]\n            [afterglow.controllers :as ct]\n            [afterglow.controllers.tempo]\n            [afterglow.core :as core]\n            [afterglow.effects :as fx]\n            [afterglow.effects.channel :as chan-fx]\n            [afterglow.effects.color :as color-fx]\n            [afterglow.effects.cues :as cues]\n            [afterglow.effects.dimmer :refer [dimmer-effect master-set-level]]\n            [afterglow.effects.fun :as fun]\n            [afterglow.effects.movement :as move]\n            [afterglow.effects.oscillators :as oscillators]\n            [afterglow.effects.params :as params]\n            [afterglow.effects.show-variable :as var-fx]\n            [afterglow.fixtures.american-dj :as adj]\n            [afterglow.fixtures.blizzard :as blizzard]\n            [afterglow.fixtures.chauvet :as chauvet]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [*show* with-show set-default-show!]]\n            [afterglow.transform :as tf]\n            [amalloy.ring-buffer :refer [ring-buffer]]\n            [clojure.math.numeric-tower :as math]\n            [com.evocomputing.colors :as colors :refer [color-name create-color hue adjust-hue]]\n            [taoensso.timbre :as timbre])\n  (:import [afterglow.effects Effect]\n           [javax.media.j3d Transform3D]\n           [javax.vecmath Point3d Vector3d]))\n\n(defonce ^{:doc \"Allows effects to set variables in the running show.\"}\n  var-binder\n  (atom nil))\n\n(defonce ^{:doc \"Holds the show if it has been created,\n  so it can be unregistered if it is being re-created.\"}\n  wedding-show\n  (atom nil))\n\n(def rig-height\n  \"The height of the center of the T-bar of the tripod holding the\n  moving heads as set up in the current venue.\"\n  (tf/inches 88))\n\n(def stage-wall\n  \"The location of the wall behind the rig on the show Z axis.\"\n  -0.66)\n\n(def house-rear-wall\n  \"The location of the wall behind the audience on the show Z axis.\"\n  6.29)\n\n(def left-wall\n  \"The location of the house left wall on the show X axis.\"\n  -1.47)\n\n(def right-wall\n  \"The location of the house right wall on the show X axis.\"\n  1.52)\n\n(def ceiling\n  \"The location of the ceiling on the show Y axis.\"\n  2.71)\n\n(defn patch-other-lights\n  \"Patches the Weather Systems and Hex IRCs, which are going to be\n  separately positioned so this will need to be hand-edited to reflect\n  their actual locations before using the show.\"\n  [& {:keys [universe]\n      :or   {universe 1}}]\n\n  ;; Hex IRC mini RGBAW+UV pars\n  (show/patch-fixture! :hex-1 (chauvet/slimpar-hex3-irc) universe 129\n                       :x (tf/feet 6) :y (tf/inches 5) :z (tf/feet 4))\n  (show/patch-fixture! :hex-2 (chauvet/slimpar-hex3-irc) universe 145\n                       :x (tf/feet -6) :y (tf/inches 5) :z (tf/feet 4))\n\n  ;; Weather Systems\n  (show/patch-fixture! :ws-1 (blizzard/weather-system) universe 161\n                       :x (tf/inches 43) :y (tf/inches 73) :z 0.0 :y-rotation (tf/degrees -30.0))\n  (show/patch-fixture! :ws-2 (blizzard/weather-system) universe 187\n                       :x (tf/inches -40.0) :y (tf/inches 75) :z 0.0 :y-rotation (tf/degrees 30.0)))\n\n(defn patch-torrents-and-snowball\n  \"Patches the moving heads which are on the larger tripod stand, which\n  defines the origin of the show, the spot on the floor underneath the\n  center of the T-bar. The _z_ axis increases towards the audience\n  from that point.\n\n  Because the height of the tripod can be adjusted, you can pass in a\n  value with `:y` to set the height of the center of the T-bar. If\n  omitted a default height of 88 inches is used, which is the height\n  to which it was raised during our rehearsals.\n\n  Fixture numbers are assigned stage left to stage right (looking at\n  the lights from behind).\"\n  [& {:keys [universe y]\n      :or   {universe 1 y (tf/inches 88)}}]\n\n  ;; Torrent F3 moving head effect spots\n  (show/patch-fixture! :torrent-1 (blizzard/torrent-f3) universe 1\n                       :x (tf/inches 15) :y (+ y (tf/inches -14))\n                       :x-rotation (tf/degrees 180)\n                       :y-rotation (tf/degrees -90))\n  (show/patch-fixture! :torrent-2 (blizzard/torrent-f3) universe 17\n                       :x (tf/inches -15) :y (+ y (tf/inches -14))\n                       :x-rotation (tf/degrees 180)\n                       :y-rotation (tf/degrees -90))\n\n  ;; Snowball RGBA moonflower effect\n  (show/patch-fixture! :snowball (blizzard/snowball) universe 33\n                       :x (tf/inches 4.5) :y (+ y (tf/inches 2))))\n\n(declare make-cues)\n\n(defn use-wedding-show\n  \"Set up the show for the wedding reception. By default it will create\n  the show to use universe 1, but if you want to use a different\n  universe (for example, a dummy universe on ID 0, because your DMX\n  interface isn't handy right now), you can override that by supplying\n  a different ID after `:universe`.\"\n  [& {:keys [universe] :or {universe 1}}]\n\n  ;; Since this class is an entry point for interactive REPL usage,\n  ;; make sure a sane logging environment is established.\n  (core/init-logging)\n\n  ;; Create, or re-create the show, on the chosen OLA universe. Make\n  ;; it the default show so we don't need to wrap everything below in\n  ;; a (with-show wedding-show ...) binding\n  (set-default-show! (swap! wedding-show (fn [s]\n                                          (when s\n                                            (show/unregister-show s)\n                                            (with-show s\n                                              (show/stop!)\n                                              (show/blackout-show)))\n                                          (show/show :universes [1]\n                                                     :description \"Joey + Courtney Show\"))))\n\n  (patch-torrents-and-snowball :universe universe :y rig-height)\n  (patch-other-lights :universe universe)\n\n  ;; Enable cues whose purpose is to set show variable values while they run.\n  (reset! var-binder (var-fx/create-for-show *show*))\n\n  ;; Create a bunch of cues\n  (make-cues)\n\n  ;; Automatically bind the show to any compatible grid controllers that are connected now\n  ;; or in the future.\n  (ct/auto-bind *show*)\n\n  ;; Return the symbol through which the show can be accessed, rather than the value itself,\n  ;; which is huge and causes issues for some REPL environments.\n  '*show*)\n\n(defn global-color-effect\n  \"Make a color effect which affects all lights in the show.\n  This became vastly more useful once I implemented dynamic color\n  parameters. Can include only a specific set of lights by passing\n  them with :fixtures\"\n  [color & {:keys [include-color-wheels? fixtures effect-name] :or {fixtures (show/all-fixtures)}}]\n  (try\n    (let [[c desc] (cond (= (type color) :com.evocomputing.colors/color)\n                       [color (color-name color)]\n                       (and (params/param? color)\n                            (= (params/result-type color) :com.evocomputing.colors/color))\n                       [color \"variable\"]\n                       :else\n                       [(create-color color) color])]\n      (color-fx/color-effect (or effect-name (str \"Global \" desc)) c fixtures\n                             :include-color-wheels? include-color-wheels?))\n    (catch Exception e\n      (throw (Exception. (str \"Can't figure out how to create color from \" color) e)))))\n\n(defn global-dimmer-effect\n  \"Return an effect that sets all the dimmers in the show.\n  Originally this had to be to a static value, but now that dynamic\n  parameters exist, it can vary in response to a MIDI mapped show\n  variable, an oscillator, or the location of the fixture. You can\n  override the default name by passing in a value with :effect-name\"\n  [level & {:keys [effect-name add-virtual-dimmers?]}]\n  (let [htp? (not add-virtual-dimmers?)]\n    (dimmer-effect level (show/all-fixtures) :effect-name effect-name :htp? htp?\n                   :add-virtual-dimmers? add-virtual-dimmers?)))\n\n(defn make-color-cue\n  \"Create a cue-grid entry which establishes a global color effect,\n  given a named color. Also set up a cue color parameter so the color\n  can be tweaked in the Web UI or on the Ableton Push, and changes\n  can be saved to persist between invocations.\"\n  [color-name x y & {:keys [include-color-wheels? held fixtures effect-key effect-name priority]\n                     :or   {fixtures    (show/all-fixtures)\n                            effect-key  :color\n                            effect-name (str \"Color \" color-name)\n                            priority    0}}]\n  (let [color     (create-color color-name)\n        color-var {:key \"color\" :type :color :start color :name \"Color\"}\n        cue       (cues/cue effect-key\n                            (fn [var-map]\n                              (global-color-effect (params/bind-keyword-param (:color var-map)\n                                                                              :com.evocomputing.colors/color\n                                                                              color)\n                                                   :effect-name effect-name\n                                                   :fixtures fixtures\n                                                   :include-color-wheels? include-color-wheels?))\n                            :priority priority\n                            :held held\n                            :color color\n                            :color-fn (cues/color-fn-from-cue-var color-var x y)\n                            :variables [color-var])]\n    (show/set-cue! x y cue)))\n\n(defn- name-torrent-gobo-cue\n  \"Come up with a summary name for one of the gobo cues we are\n  creating that is concise but meaningful on a controller interface.\"\n  [prefix function]\n  (let [simplified (clojure.string/replace (name function) #\"^gobo-fixed-\" \"\")\n        simplified (clojure.string/replace simplified #\"^gobo-moving-\" \"m/\")\n        spaced (clojure.string/replace simplified \"-\" \" \")]\n    (str (clojure.string/upper-case (name prefix)) \" \" spaced)))\n\n(defn- make-torrent-gobo-cues\n  \"Create cues for the fixed and moving gobo options, stationary and\n  shaking. Takes up half a page, with the top left at the coordinates\n  specified.\"\n  [prefix fixtures top left]\n  ;; Make cues for the stationary and shaking versions of all fixed gobos\n  (doseq [_ (map-indexed (fn [i v]\n                           (let [blue (create-color :blue)\n                                 x (if (< i 8) left (+ left 2))\n                                 y (if (< i 8) (- top i) (- top i -1))\n                                 cue-key (keyword (str (name prefix) \"-gobo-fixed\"))]\n                             (show/set-cue! x y (cues/function-cue cue-key (keyword v) fixtures :color blue\n                                                                   :short-name (name-torrent-gobo-cue prefix v)))\n                             (let [function (keyword (str (name v) \"-shake\"))]\n                               (show/set-cue! (inc x) y (cues/function-cue\n                                                         cue-key function fixtures :color blue\n                                                         :short-name (name-torrent-gobo-cue prefix function))))))\n                         [\"gobo-fixed-mortar\" \"gobo-fixed-4-rings\" \"gobo-fixed-atom\" \"gobo-fixed-jacks\"\n                          \"gobo-fixed-saw\" \"gobo-fixed-sunflower\" \"gobo-fixed-45-adapter\"\n                          \"gobo-fixed-star\" \"gobo-fixed-rose-fingerprint\"])])\n  ;; Make cues for the stationary and shaking versions of all rotating gobos\n  (doseq [_ (map-indexed (fn [i v]\n                           (let [green (create-color :green)\n                                 cue-key (keyword (str (name prefix) \"-gobo-moving\"))]\n                             (show/set-cue! (+ left 2) (- top i)\n                                            (cues/function-cue cue-key (keyword v) fixtures :color green\n                                                               :short-name (name-torrent-gobo-cue prefix v)))\n                             (let [function (keyword (str (name v) \"-shake\"))]\n                               (show/set-cue! (+ left 3) (- top i)\n                                              (cues/function-cue\n                                               cue-key function fixtures :color green\n                                               :short-name (name-torrent-gobo-cue prefix function))))))\n                         [\"gobo-moving-rings\" \"gobo-moving-color-swirl\" \"gobo-moving-stars\"\n                          \"gobo-moving-optical-tube\" \"gobo-moving-magenta-bundt\"\n                          \"gobo-moving-blue-mega-hazard\" \"gobo-moving-turbine\"])]))\n\n(def white\n  \"The color to flash strobe cues to identify them as such.\"\n  (create-color :white))\n\n(defn make-strobe-cue-2\n  \"Create a cue which strobes a set of fixtures as long as the cue pad\n  is held down, letting the operator adjust the lightness of the\n  strobe color by varying the pressure they are applying to the pad on\n  controllers which support pressure sensitivity, and having the base\n  strobe color depend on a shared show color variable. On controllers\n  which support it, the color of the cue pad will be also driven by\n  this shared color variable, with a white flicker to emphasize them\n  as strobing cues.\"\n  [name fixtures x y]\n  (when-not (= (type (show/get-variable :strobe-color)) :com.evocomputing.colors/color)\n    ;; If the default strobe color has not yet been established, set it to purple.\n    (show/set-variable! :strobe-color (create-color :purple)))\n  (let [color-var {:key :strobe-color :type :color :name \"Strobe Color\"}]\n    (show/set-cue! x y\n                   (cues/cue (keyword (str \"strobe-\" (clojure.string/replace (clojure.string/lower-case name) \" \" \"-\")))\n                             (fn [var-map] (fun/strobe-2 (str \"Strobe \" name) fixtures\n                                                         (:level var-map 50) (:lightness var-map 100)))\n                             :color :purple\n                             :color-fn (fn [cue active show snapshot]\n                                         (if (> (rhythm/snapshot-beat-phase snapshot 0.5) 0.7)\n                                           white\n                                           (or (show/get-variable :strobe-color)\n                                               (:color cue))))\n                             :held true\n                             :priority 100\n                             :variables [{:key \"level\" :min 0 :max 100 :start 100 :name \"Level\"}\n                                         {:key \"lightness\" :min 0 :max 100 :name \"Lightness\" :velocity true}\n                                         color-var]))))\n\n(def light-groups\n  \"The named groupings of lights to build rows of effects in the cue grid.\"\n  [:torrent :ws :hex :snowball])\n\n(defn group-end-keys\n  \"Helper function to produce a vector of effect keywords to end all\n  effects running on light groups with a given suffix.\"\n  [effect-suffix]\n  (mapv #(keyword (str (name %) \"-\" effect-suffix)) light-groups))\n\n(defn build-group-cue-elements\n  \"Helper function which builds the common variables needed to create\n  a cue which runs on either all lights or a named group of lights.\"\n  [group effect-suffix name-suffix]\n  (let [effect-key (or (when group (keyword (str (name group) \"-\" effect-suffix)))\n                       (keyword effect-suffix))\n        fixtures (or (when group (show/fixtures-named group))\n                     (show/all-fixtures))\n        end-keys (or (when group [(keyword effect-suffix)])\n                     (group-end-keys effect-suffix))\n        effect-name (str (case group\n                           nil \"All\"\n                           :ws \"WS\"\n                           (clojure.string/capitalize (name group)))\n                         \" \" (clojure.string/capitalize name-suffix))]\n    [effect-key fixtures end-keys effect-name]))\n\n(defn make-dimmer-cue\n  \"Creates a cue which lets the operator adjust the dimmer level of a\n  group of fixtures. Group will be one of the values\n  in [[light-groups]], or `nil` if the cue should affect all lights.\"\n  [group x y color]\n  (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group \"dimmers\" \"dimmers\")]\n    (show/set-cue! x y\n                   (cues/cue effect-key\n                             (fn [var-map] (dimmer-effect\n                                            (params/bind-keyword-param (:level var-map 255) Number 255)\n                                            fixtures :effect-name effect-name))\n                             :variables [{:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}]\n                             :color color :end-keys end-keys))))\n\n(defn build-ratio-param\n  \"Creates a dynamic parameter for setting the beat ratio of one of\n  the dimmer oscillator cues in [[make-cues]] by forming the ratio of\n  the cue variables introduced by the cue. This allows the show\n  operator to decide over how many beats the oscillator runs, and how\n  many times it cycles in that interval.\n\n  Expects the cue's variable map to contain entries `:beats` and\n  `:cycles` which will form the numerator and denominator of the\n  ratio. If any entry is missing, a default value of `1` is used\n  for it.\"\n  [var-map]\n  (let [beats-param (params/bind-keyword-param (:beats var-map) Number 1)\n        cycles-param (params/bind-keyword-param (:cycles var-map) Number 1)]\n    (params/build-param-formula Number #(/ %1 %2) beats-param cycles-param)))\n\n(defn- make-sawtooth-dimmer-param\n  \"Creates the sawtooth oscillated parameter used by\n  `make-sawtooth-dimmer-cue` for both the actual effect and its\n  visualizer.\"\n  [var-map]\n  (oscillators/build-oscillated-param (oscillators/sawtooth :down? (:down var-map)\n                                                            :interval-ratio (build-ratio-param var-map)\n                                                            :phase (:phase var-map))\n                                      :min (:min var-map) :max (:max var-map)))\n\n(defn make-sawtooth-dimmer-cue\n  \"Create a cue which applies a sawtooth oscillator to the dimmers of\n  the specified group of fixtures, with cue variables to adjust the\n  oscillator parameters.\"\n  [group x y color]\n  (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group \"dimmers\" \"saw\")]\n    (show/set-cue! x y\n                   (cues/cue effect-key\n                             (fn [var-map] (dimmer-effect (make-sawtooth-dimmer-param var-map) fixtures\n                                            :effect-name effect-name))\n                             :color color\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                         {:key \"down\" :type :boolean :start true :name \"Down?\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"phase\" :min 0 :max 1 :start 0 :name \"Phase\"}\n                                         {:key \"min\" :min 0 :max 255 :start 0 :name \"Min\"}\n                                         {:key \"max\" :min 0 :max 255 :start 255 :name \"Max\"}]\n                             :visualizer (fn [var-map show]\n                                           (let [p (make-sawtooth-dimmer-param var-map)]\n                                             (fn [snapshot]\n                                               (/ (params/evaluate p show snapshot nil) 255.0))))\n                             :end-keys end-keys))))\n\n(defn- make-triangle-dimmer-param\n  \"Creates the triangle oscillated parameter used by\n  `make-triangle-dimmer-cue` for both the actual effect and its\n  visualizer.\"\n  [var-map]\n  (oscillators/build-oscillated-param (oscillators/triangle :interval-ratio (build-ratio-param var-map)\n                                                            :phase (:phase var-map))\n                                      :min (:min var-map) :max (:max var-map)))\n\n(defn make-triangle-dimmer-cue\n  \"Create a cue which applies a triangle oscillator to the dimmers of\n  the specified set of fixtures, with cue variables to adjust the\n  oscillator parameters.\"\n  [group x y color]\n  (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group \"dimmers\" \"triangle\")]\n    (show/set-cue! x y\n                   (cues/cue effect-key\n                             (fn [var-map] (dimmer-effect (make-triangle-dimmer-param var-map) fixtures\n                                                          :effect-name effect-name))\n                             :color color\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"phase\" :min 0 :max 1 :start 0 :name \"Phase\"}\n                                         {:key \"min\" :min 0 :max 255 :start 0 :name \"Min\"}\n                                         {:key \"max\" :min 0 :max 255 :start 255 :name \"Max\"}]\n                             :visualizer (fn [var-map show]\n                                           (let [p (make-triangle-dimmer-param var-map)]\n                                             (fn [snapshot]\n                                               (/ (params/evaluate p show snapshot nil) 255.0))))\n                             :end-keys end-keys))))\n\n(defn- make-sine-dimmer-param\n  \"Creates the sine oscillated parameter used by\n  `make-sine-dimmer-cue` for both the actual effect and its\n  visualizer.\"\n  [var-map]\n  (oscillators/build-oscillated-param (oscillators/sine :interval-ratio (build-ratio-param var-map)\n                                                        :phase (:phase var-map))\n                                      :min (:min var-map) :max (:max var-map)))\n\n(defn make-sine-dimmer-cue\n  \"Create a cue which applies a sine oscillator to the dimmers of the\n  specified set of fixtures, with cue variables to adjust the\n  oscillator parameters.\"\n  [group x y color]\n  (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group \"dimmers\" \"sine\")]\n    (show/set-cue! x y\n                   (cues/cue effect-key\n                             (fn [var-map] (dimmer-effect (make-sine-dimmer-param var-map) fixtures\n                                                          :effect-name effect-name))\n                             :color color\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"phase\" :min 0 :max 1 :start 0 :name \"Phase\"}\n                                         {:key \"min\" :min 0 :max 255 :start 1 :name \"Min\"}\n                                         {:key \"max\" :min 0 :max 255 :start 255 :name \"Max\"}]\n                             :visualizer (fn [var-map show]\n                                           (let [p (make-sine-dimmer-param var-map)]\n                                             (fn [snapshot]\n                                               (/ (params/evaluate p show snapshot nil) 255.0))))\n                             :end-keys end-keys))))\n\n(defn- make-square-dimmer-param\n  \"Creates the square oscillated parameter used by\n  `make-square-dimmer-cue` for both the actual effect and its\n  visualizer.\"\n  [var-map]\n  (oscillators/build-oscillated-param (oscillators/square :interval-ratio (build-ratio-param var-map)\n                                                          :width (:width var-map)\n                                                          :phase (:phase var-map))\n                                      :min (:min var-map) :max (:max var-map)))\n\n(defn make-square-dimmer-cue\n  \"Create a cue which applies a square oscillator to the dimmers of\n  the specified set of fixtures, with cue variables to adjust the\n  oscillator parameters.\"\n  [group x y color]\n  (let [[effect-key fixtures end-keys effect-name] (build-group-cue-elements group \"dimmers\" \"square\")]\n    (show/set-cue! x y\n                   (cues/cue effect-key\n                             (fn [var-map] (dimmer-effect (make-square-dimmer-param var-map) fixtures\n                                                          :effect-name effect-name))\n                             :color color\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                         {:key \"width\" :min 0 :max 1 :start 0.5 :name \"Width\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"phase\" :min 0 :max 1 :start 0 :name \"Phase\"}\n                                         {:key \"min\" :min 0 :max 255 :start 0 :name \"Min\"}\n                                         {:key \"max\" :min 0 :max 255 :start 255 :name \"Max\"}]\n                             :visualizer (fn [var-map show]\n                                           (let [p (make-square-dimmer-param var-map)]\n                                             (fn [snapshot]\n                                               (/ (params/evaluate p show snapshot nil) 255.0))))\n                             :end-keys end-keys))))\n\n(defn x-phase\n  \"Return a value that ranges from zero for the leftmost fixture in a\n  show to 1 for the rightmost, for staggering the phase of an\n  oscillator in making a can-can chase.\"\n  [head show]\n  (let [dimensions @(:dimensions *show*)]\n    (/ (- (:x head) (:min-x dimensions)) (- (:max-x dimensions) (:min-x dimensions)))))\n\n(defonce ^{:doc \"A step parameter for controlling example chase cues.\n  Change it to experiment with other kinds of timing and fades.\"}\n  step-param\n  (atom nil))\n\n(defn- build-focus-oscillator\n  \"Returns a cue which oscillates a fixture's focus between a minimum\n  and minimum value using a sine oscillator with cue variables to\n  adjust the range and the oscillator's parameters.\"\n  [effect-key effect-name fixtures]\n  (cues/cue effect-key\n            (fn [var-map] (afterglow.effects.channel/function-effect\n                           effect-name :focus\n                           (oscillators/build-oscillated-param\n                            (oscillators/sine :interval-ratio (build-ratio-param var-map) :phase (:phase var-map))\n                            :min (:min var-map) :max (:max var-map))\n                           fixtures))\n            :color (create-color :yellow)\n            :variables [{:key \"min\" :min 0 :max 100 :start 0 :name \"Min\"}\n                        {:key \"max\" :min 0 :max 100 :start 100 :name \"Max\"}\n                        {:key \"beats\" :min 1 :max 32 :type :integer :start 4 :name \"Beats\"}\n                        {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                        {:key \"phase\" :min 0 :max 1 :start 0 :name \"Phase\"}]))\n\n(defn make-main-color-dimmer-cues\n  \"Creates a page of cues that assign dimmers and colors to the\n  lights. This is probably going to be assigned as the first page, but\n  can be moved by passing non-zero values for `page-x` and `page-y`.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)\n        rig-left (:x (first (show/fixtures-named :hex-2)))\n        rig-right (:x (first (show/fixtures-named :hex-1)))\n        rig-width (- rig-right rig-left)\n        hue-bar (oscillators/build-oscillated-param  ; Spread a rainbow across a bar of music\n                 (oscillators/sawtooth :interval :bar) :max 360)\n        desat-beat (oscillators/build-oscillated-param  ; Desaturate a color as a beat progresses\n                    (oscillators/sawtooth :down? true) :max 100)\n        hue-gradient (params/build-spatial-param  ; Spread a rainbow across the light grid\n                      (show/all-fixtures)\n                      (fn [head] (- (:x head) (:min-x @(:dimensions *show*)))) :max 360)\n        rig-hue-gradient (params/build-spatial-param  ; Spread a rainbow across just the main rig, repeating\n                          (show/all-fixtures)         ; beyond that, irrespective of other lights' positions.\n                          (fn [head] (colors/clamp-hue (* 360 (/ (- (:x head) rig-left) rig-width)))))\n        hue-z-gradient (params/build-spatial-param  ; Spread a rainbow across the light grid front to back\n                        (show/all-fixtures)\n                        (fn [head] (- (:z head) (:min-z @(:dimensions *show*)))) :max 360)]\n\n    ;; Bottom row assigns colors, first to all fixtures, and then (at a higher priority, so they can\n    ;; run a the same time as the first, and locally override it) individual fixture groups.\n    (make-color-cue \"white\" x-base y-base :include-color-wheels? true\n                    :fixtures (show/all-fixtures) :effect-key :all-color :effect-name \"Color all\")\n    (doall (map-indexed (fn [i group]\n                          (make-color-cue \"white\" (+ x-base (inc i)) y-base :include-color-wheels? true\n                                          :fixtures (show/fixtures-named group)\n                                          :effect-key (keyword (str (name group) \"-color\"))\n                                          :effect-name (str \"Color \" (name group))\n                                          :priority 1))\n                        light-groups))\n\n    ;; Some special/fun cues\n    (show/set-variable! :rainbow-saturation 100)\n    (show/set-cue! x-base (inc y-base)\n                   (let [color-param (params/build-color-param :s :rainbow-saturation :l 50 :h hue-bar)]\n                     (cues/cue :all-color (fn [_] (global-color-effect color-param))\n                               :color-fn (cues/color-fn-from-param color-param)\n                               :short-name \"Rainbow Bar Fade\"\n                               :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                            :type :integer}])))\n    (show/set-cue! (inc x-base) (inc y-base)\n                   (cues/cue :all-color (fn [_] (global-color-effect\n                                                 (params/build-color-param :s :rainbow-saturation :l 50\n                                                                           :h rig-hue-gradient)\n                                                 :include-color-wheels? true))\n                             :short-name \"Rainbow Rig\"\n                             :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                          :type :integer}]))\n    (show/set-cue! (+ x-base 2) (inc y-base)\n                   (let [color-param (params/build-color-param :s :rainbow-saturation :l 50 :h hue-gradient\n                                                               :adjust-hue hue-bar)]\n                     (cues/cue :all-color (fn [_] (global-color-effect color-param))\n                               :color-fn (cues/color-fn-from-param color-param)\n                               :short-name \"Rainbow Grid+Bar\"\n                               :variables [{:key :rainbow-saturation :name \"Saturatn\" :min 0 :max 100 :start 100\n                                            :type :integer}])))\n    (show/set-cue! (+ x-base 3) (inc y-base) ; Desaturate the rainbow as each beat progresses\n                   (let [color-param (params/build-color-param :s desat-beat :l 50 :h hue-gradient\n                                                               :adjust-hue hue-bar)]\n                     (cues/cue :all-color (fn [_] (global-color-effect color-param))\n                               :color-fn (cues/color-fn-from-param color-param)\n                               :short-name \"Rainbow Pulse\")))\n\n    (show/set-cue! (+ x-base 4) (inc y-base)\n                   (cues/cue :all-color (fn [_] (global-color-effect\n                                                 (params/build-color-param :s 100 :l 50 :h hue-z-gradient)\n                                                 :include-color-wheels? true))\n                             :short-name \"Z Rainbow Grid\"))\n\n    (show/set-cue! (+ x-base 7) (inc y-base)\n                   (cues/cue :transform-colors (fn [_] (color-fx/transform-colors (show/all-fixtures)))\n                             :priority 1000 :short-name \"Beat Bleach\"))\n\n    ;; The fun sparkle cue\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/cue :sparkle (fn [var-map]\n                                        (cues/apply-merging-var-map var-map fun/sparkle (show/all-fixtures)))\n                             :held true\n                             :priority 100\n                             :variables [{:key \"chance\" :min 0.0 :max 0.4 :start 0.05 :velocity true}\n                                         {:key \"fade-time\" :name \"Fade\" :min 1 :max 2000 :start 50 :type :integer}]))\n\n    ;; Dimmer cues to turn on and set brightness of groups of lights\n    (make-dimmer-cue nil x-base (+ y-base 2) :yellow)\n    (doall (map-indexed (fn [i group] (make-dimmer-cue group (+ x-base (inc i)) (+ y-base 2) :yellow)) light-groups))\n\n    ;; Dimmer oscillator cues: Sawtooth\n    (make-sawtooth-dimmer-cue nil x-base (+ y-base 3) :yellow)\n    (doall (map-indexed (fn [i group]\n                          (make-sawtooth-dimmer-cue group (+ x-base (inc i)) (+ y-base 3) :orange)) light-groups))\n\n    ;; Dimmer oscillator cues: Triangle\n    (make-triangle-dimmer-cue nil x-base (+ y-base 4) :orange)\n    (doall (map-indexed (fn [i group]\n                          (make-triangle-dimmer-cue group (+ x-base (inc i)) (+ y-base 4) :red)) light-groups))\n\n    ;; Dimmer oscillator cues: Sine\n    (make-sine-dimmer-cue nil x-base (+ y-base 5) :cyan)\n    (doall (map-indexed (fn [i group]\n                          (make-sine-dimmer-cue group (+ x-base (inc i)) (+ y-base 5) :blue)) light-groups))\n\n    ;; Dimmer oscillator cues: Square\n    (make-square-dimmer-cue nil x-base (+ y-base 6) :cyan)\n    (doall (map-indexed (fn [i group]\n                          (make-square-dimmer-cue group (+ x-base (inc i)) (+ y-base 6) :green)) light-groups))\n\n    ;; Strobe cues\n    (make-strobe-cue-2 \"All\" (show/all-fixtures) x-base (+ y-base 7))\n    (make-strobe-cue-2 \"Torrents\" (show/fixtures-named \"torrent\") (inc x-base) (+ y-base 7))\n    (make-strobe-cue-2 \"Weather Systems\" (show/fixtures-named \"ws\") (+ x-base 2) (+ y-base 7))\n    (make-strobe-cue-2 \"Hexes\" (show/fixtures-named \"hex\") (+ x-base 3) (+ y-base 7))\n    (make-strobe-cue-2 \"Snowball\" (show/fixtures-named \"snowball\") (+ x-base 4) (+ y-base 7))\n\n    (let [color-var {:key :strobe-color :type :color :name \"Strobe Color\"}]\n      (show/set-cue! (+ x-base 5) (+ y-base 7) (cues/cue :strobe-color (fn [_] (fx/blank \"Strobe Color\"))\n                                                         :color :purple\n                                                         :color-fn (cues/color-fn-from-cue-var color-var)\n                                                         :variables [color-var])))))\n\n(defn make-torrent-cues\n  \"Create a page of cues for configuring aspects of the Torrent F3s\n  and another to its right for their gobo selection.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)]\n    (show/set-cue! x-base (+ y-base 7)\n                   (cues/function-cue :torrent-shutter :shutter-open (show/fixtures-named \"torrent\")))\n    (show/set-cue! (inc x-base) (+ y-base 7)\n                   (cues/function-cue :torrent-reset :motor-reset (show/fixtures-named \"torrent\")\n                                      :color (create-color :red) :held true))\n\n    (show/set-cue! (+ x-base 6) (+ y-base 7)\n                   (cues/function-cue :t1-focus :focus (show/fixtures-named \"torrent-1\") :effect-name \"Torrent 1 Focus\"\n                                      :color (create-color :yellow)))\n    (show/set-cue! (+ x-base 7) (+ y-base 7)\n                   (cues/function-cue :t2-focus :focus (show/fixtures-named \"torrent-2\") :effect-name \"Torrent 2 Focus\"\n                                      :color (create-color :yellow)))\n    (show/set-cue! (+ x-base 4) (+ y-base 7)\n                   (build-focus-oscillator :t1-focus \"Torrent 1 Focus Sine\" (show/fixtures-named \"torrent-1\")))\n    (show/set-cue! (+ x-base 5) (+ y-base 7)\n                   (build-focus-oscillator :t2-focus \"Torrent 2 Focus Sine\" (show/fixtures-named \"torrent-2\")))\n    (show/set-cue! (+ x-base 6) (+ y-base 6)\n                   (cues/function-cue :t1-prism :prism-clockwise (show/fixtures-named \"torrent-1\") :level 100\n                                      :effect-name \"T1 Prism Spin CW\" :color (create-color :orange)))\n    (show/set-cue! (+ x-base 7) (+ y-base 6)\n                   (cues/function-cue :t2-prism :prism-clockwise (show/fixtures-named \"torrent-2\") :level 100\n                                      :effect-name \"T2 Prism Spin CW\" :color (create-color :orange)))\n    (show/set-cue! (+ x-base 6) (+ y-base 5)\n                   (cues/function-cue :t1-prism :prism-in (show/fixtures-named \"torrent-1\")\n                                      :effect-name \"T1 Prism In\" :color (create-color :orange)))\n    (show/set-cue! (+ x-base 7) (+ y-base 5)\n                   (cues/function-cue :t2-prism :prism-in (show/fixtures-named \"torrent-2\")\n                                      :effect-name \"T2 Prism In\" :color (create-color :orange)))\n    (show/set-cue! (+ x-base 6) (+ y-base 4)\n                   (cues/function-cue :t1-prism :prism-counterclockwise (show/fixtures-named \"torrent-1\")\n                                      :effect-name \"T1 Prism Spin CCW\" :color (create-color :orange)))\n    (show/set-cue! (+ x-base 7) (+ y-base 4)\n                   (cues/function-cue :t2-prism :prism-counterclockwise (show/fixtures-named \"torrent-2\")\n                                      :effect-name \"T2 Prism Spin CCW\" :color (create-color :orange)))\n    (show/set-cue! (+ x-base 6) (+ y-base 3)\n                   (cues/function-cue :t1-gobo-fixed :gobo-fixed-clockwise (show/fixtures-named \"torrent-1\")\n                                      :effect-name \"T1 Fixed Gobos Swap CW\" :color (create-color :blue)))\n    (show/set-cue! (+ x-base 7) (+ y-base 3)\n                   (cues/function-cue :t2-gobo-fixed :gobo-fixed-clockwise (show/fixtures-named \"torrent-2\")\n                                      :effect-name \"T2 Fixed Gobos Swap CW\" :color (create-color :blue)))\n    (show/set-cue! (+ x-base 6) (+ y-base 2)\n                   (cues/function-cue :t1-gobo-moving :gobo-moving-clockwise (show/fixtures-named \"torrent-1\")\n                                      :effect-name \"T1 Moving Gobos Swap CW\" :color (create-color :green)))\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/function-cue :t2-gobo-moving :gobo-moving-clockwise (show/fixtures-named \"torrent-2\")\n                                      :effect-name \"T2 Moving Gobos Swap CW\" :color (create-color :green)))\n    (show/set-cue! (+ x-base 6) (inc y-base)\n                   (cues/function-cue :t1-gobo-rotation :gobo-rotation-clockwise (show/fixtures-named \"torrent-1\")\n                                      :effect-name \"T1 Spin Gobo CW\" :color (create-color :cyan) :level 100))\n    (show/set-cue! (+ x-base 7) (inc y-base)\n                   (cues/function-cue :t2-gobo-rotation :gobo-rotation-clockwise (show/fixtures-named \"torrent-2\")\n                                      :effect-name \"T2 Spin Gobo CW\" :color (create-color :cyan) :level 100))\n    (show/set-cue! (+ x-base 6) y-base\n                   (cues/function-cue :t1-gobo-rotation :gobo-rotation-counterclockwise\n                                      (show/fixtures-named \"torrent-1\")\n                                      :effect-name \"T1 Spin Gobo CCW\" :color (create-color :cyan)))\n    (show/set-cue! (+ x-base 7) y-base\n                   (cues/function-cue :t2-gobo-rotation :gobo-rotation-counterclockwise\n                                      (show/fixtures-named \"torrent-2\")\n                                      :effect-name \"T2 Spin Gobo CCW\" :color (create-color :cyan)))\n\n    ;; Simple color wheel settings for each Torrent\n    (dotimes [x 2]\n      (doall (map-indexed (fn [y color]\n                            (make-color-cue color (+ x-base x) (+ y-base y) :include-color-wheels? true\n                                            :fixtures (show/fixtures-named (str \"torrent-\" (inc x)))\n                                            :effect-key (keyword (str \"torrent-\" (inc x) \"-color\"))\n                                            :effect-name (str \"Torrent \" (inc x) \" \" color)\n                                            :priority 2))\n                          [\"red\" \"blue\" \"green\" \"yellow\" \"magenta\" \"cyan\" \"orange\"])))\n\n\n    ;; Some compound cues\n    (show/set-cue! (+ x-base 2) y-base\n                   (cues/cue :star-swirl (fn [_] (cues/compound-cues-effect\n                                                  \"Star Swirl\" *show* [[(+ x-base 8) (+ y-base 4)]\n                                                                       [(+ x-base 10) (inc y-base)]\n                                                                       [(+ x-base 6) (+ y-base 7) {:level 60}]\n                                                                       [(+ x-base 6) y-base {:level 25}]]))))\n\n    (make-torrent-gobo-cues :t1 (show/fixtures-named \"torrent-1\") (+ y-base 7) (+ x-base 8))\n    (make-torrent-gobo-cues :t2 (show/fixtures-named \"torrent-2\") (+ y-base 7) (+ x-base 12))))\n\n(defn circle-chain\n  \"Create a chase that generates a series of circles on either the\n  floor or the ceiling, causing a single head to trace out each, and\n  passing them along from head to head.\n\n  The number of bars taken to trace out each circle defaults to 2 and\n  can be adjusted by passing a different value with the optional\n  keyword argument `:bars`. The radius of each circle defaults to one\n  meter, and can be adjusted with `:radius`. If you want each head to\n  be tracing a different position in its circle, you can pass a value\n  between zero and one with `:stagger`.\"\n  [fixtures ceiling? & {:keys [bars radius stagger] :or {bars 2 radius 1.0 stagger 0.0}}]\n  (let [bars (params/bind-keyword-param bars Number 2)\n        radius (params/bind-keyword-param radius Number 1.0)\n        stagger (params/bind-keyword-param stagger Number 0.0)\n        snapshot (rhythm/metro-snapshot (:metronome *show*))\n        bars (params/resolve-unless-frame-dynamic bars *show* snapshot)\n        radius (params/resolve-unless-frame-dynamic radius *show* snapshot)\n        stagger (params/resolve-unless-frame-dynamic stagger *show* snapshot)\n        step (params/build-step-param :interval :bar :interval-ratio bars)\n        phase-osc (oscillators/sawtooth :interval :bar :interval-ratio bars)\n        width (- right-wall left-wall)\n        front (if ceiling? 0.5 stage-wall)  ; The blades can't reach behind the rig\n        depth (- house-rear-wall front)\n        y (if ceiling? ceiling 0.0)\n        heads (sort-by :x (move/find-moving-heads fixtures))\n        points (ref (ring-buffer (count heads)))\n        running (ref true)\n        current-step (ref nil)]\n    ;; It would also be possible to build this using a scene with fomula parameters to create\n    ;; the aiming points, but it is slightly more concise and direct to drop to implementing\n    ;; the lower-level effect interface. If this is too deep for your current stage of Afterglow\n    ;; learning, ignore it until you are ready to dig deeper into the rendering pipeline.\n    (Effect. \"Circle Chain\"\n             (fn [show snapshot]\n               ;; Continue running until all circles are finished\n               (dosync\n                (or @running (seq @points))))\n             (fn [show snapshot]\n               (dosync\n                (let [now (math/round (params/resolve-param step show snapshot))\n                      phase (oscillators/evaluate phase-osc show snapshot nil)\n                      stagger (params/resolve-param stagger show show snapshot)\n                      head-phases (map #(* stagger %) (range))]\n                  (when (not= now @current-step)\n                    (ref-set current-step now)\n                    (if @running  ;; Either add a new circle, or just drop the oldest\n                      (alter points conj (Point3d. (+ left-wall (rand width)) y (+ front (rand depth))))\n                      (alter points pop)))\n                  (map (fn [head point head-phase]\n                         (let [radius (params/resolve-param radius show snapshot head)\n                               theta (* 2.0 Math/PI (+ phase head-phase))\n                               head-point (Point3d. (+ (.x point) (* radius (Math/cos theta)))\n                                                    (.y point)\n                                                    (+ (.z point) (* radius (Math/sin theta))))]\n                           (fx/build-head-parameter-assigner :aim head head-point show snapshot)))\n                       heads @points head-phases))))\n             (fn [show snapshot]\n                 ;; Stop making new circles, and shut down once all exiting ones have ended.\n                 (dosync (ref-set running false))))))\n\n(defn make-ambient-cues\n  \"Create a page of cues for controlling lasers, and ambient effects\n  like the H2O LED and black light.\n\n  Also holds cues for turning on sound active mode when the show\n  operator wants to let things take care of themselves for a while,\n  and doesn't mind losing the ability to control show brightness via\n  dimmer masters.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)]\n\n    ;; Various ultraviolet options. Start by defining the pair of effects needed to turn the hex fixtures on\n    ;; in full UV mode.\n    (let [hex-uv-fx [(chan-fx/function-effect \"Hex UV\" :uv 100 (show/fixtures-named \"hex\"))\n                     (dimmer-effect 255 (show/fixtures-named \"hex\")\n                                    :effect-name \"Hex Dimmers for UV\")]]\n      (show/set-cue! (+ x-base 2) y-base\n                     (cues/cue :hex-uv (fn [_] (apply fx/scene \"Hex UV\" hex-uv-fx))\n                               :color :purple :end-keys [:uv])))\n\n    ;; Sound active mode for groups of lights\n    (show/set-cue! (+ x-base 4) (+ y-base 7)\n                   (cues/cue :hex-sound\n                             (fn [var-map]\n                               (fx/scene \"Hex Sound\"\n                                         (chan-fx/function-effect\n                                          \"sound on\" :sound-active (:level var-map) (show/fixtures-named \"hex\"))\n                                         (dimmer-effect (:dimmer var-map) (show/fixtures-named \"hex\"))))\n                             :color :orange\n                             :variables [{:key \"level\" :min 1 :max 100 :type :integer :start 50 :name \"Level\"}\n                                         {:key \"dimmer\" :min 0 :max 255 :type :integer :start 255 :name \"Dimmer\"}]))\n\n    (show/set-cue! (+ x-base 6) (+ y-base 7)\n                   (cues/function-cue :snowball-sound :sound-active (show/fixtures-named \"snowball\")\n                                      :color :orange :effect-name \"Snowball Sound\" :end-keys [:snowball-pos]))\n\n    ;; A couple other snowball cues\n    (show/set-cue! (+ x-base 6) (+ y-base 6)\n                   (cues/function-cue :snowball-pos :beams-moving (show/fixtures-named \"snowball\")\n                                      :effect-name \"Snowball Moving\" :color :yellow :end-keys [:snowball-sound]))\n    (show/set-cue! (+ x-base 6) (+ y-base 5)\n                   (cues/function-cue :snowball-pos :beams-fixed (show/fixtures-named \"snowball\")\n                                      :effect-name \"Snowball Fixed\" :end-keys [:snowball-sound]))))\n\n(defn torrent-8\n  \"A effect that moves the torrents in a figure 8.\"\n  [& {:keys [bars cycles stagger spread pan-min pan-max tilt-min tilt-max]\n      :or {bars 1 cycles 1 stagger 0 spread 0 pan-min -45 pan-max 45 tilt-min 0 tilt-max 45}}]\n  (let [bars (params/bind-keyword-param bars Number 1)\n        cycles (params/bind-keyword-param cycles Number 1)\n        stagger (params/bind-keyword-param stagger Number 0)\n        spread (params/bind-keyword-param spread Number 0)\n        pan-min (params/bind-keyword-param pan-min Number -45)\n        pan-max (params/bind-keyword-param pan-max Number 45)\n        tilt-min (params/bind-keyword-param tilt-min Number 0)\n        tilt-max (params/bind-keyword-param tilt-max Number 45)\n        pan-ratio (params/build-param-formula Number #(/ (* 2 %1) %2) bars cycles)\n        tilt-ratio (params/build-param-formula Number #(/ %1 %2) bars cycles)\n        fx (for [head [{:key :torrent-1 :phase 0.0 :pan-offset 1}\n                       {:key :torrent-2 :phase 0.5 :pan-offset -1}]]\n             (let [head-phase (params/build-param-formula Number #(+ 0.25 (* % (:phase head 0))) stagger)\n                   tilt-osc (oscillators/sine :interval :bar :interval-ratio tilt-ratio :phase head-phase)\n                   tilt-param (oscillators/build-oscillated-param tilt-osc :min tilt-min :max tilt-max)\n                   pan-osc (oscillators/sine :interval :bar :interval-ratio pan-ratio :phase head-phase)\n                   head-pan-min (params/build-param-formula Number #(+ (if (zero? (:phase head)) %1 (- %2))\n                                                                       (* (:pan-offset head 0) %3))\n                                                            pan-min pan-max spread)\n                   head-pan-max (params/build-param-formula Number #(+ (if (zero? (:phase head)) %1 (- %2))\n                                                                       (* (:pan-offset head 0) %3))\n                                                            pan-max pan-min spread)\n                   pan-param (oscillators/build-oscillated-param pan-osc\n                                                                 :min head-pan-min\n                                                                 :max head-pan-max)\n                   direction (params/build-pan-tilt-param :pan pan-param :tilt tilt-param)]\n               (move/pan-tilt-effect \"t8 element\" direction (show/fixtures-named (:key head)))))]\n    (apply fx/scene \"Torrent 8\" fx)))\n\n(defn dimmer-sweep\n  \"An effect which uses an oscillator to move a bar of light across a\n  group of fixtures. The width of the bar, maximum dimmer level, and\n  whether the level should fade from the center of the bar to the\n  edge, can be controlled with optional keyword arguments.\"\n  [fixtures osc & {:keys [width level fade] :or {width 0.1 level 255 fade false}}]\n  (let [width (params/bind-keyword-param width Number 0.1)\n        level (params/bind-keyword-param level Number 255)\n        fade (params/bind-keyword-param fade Boolean false)\n        min-x (apply min (map :x fixtures))\n        max-x (apply max (map :x fixtures))\n        position (oscillators/build-oscillated-param osc :min min-x :max max-x)]\n    (apply fx/scene \"Dimmer Sweep\"\n           (for [fixture fixtures]\n             (let [fixture-level (params/build-param-formula\n                                  Number\n                                  (fn [position width level fade]\n                                    (let [range (/ width 2)\n                                          distance (math/abs (- position (:x fixture)))]\n                                      (if (> distance range)\n                                        0\n                                        (if fade\n                                          (* level (/ (- range distance) range))\n                                          level))))\n                                  position width level fade)]\n               (dimmer-effect fixture-level [fixture]))))))\n\n(defn make-movement-cues\n  \"Create a page of with some large scale and layered movement\n  effects. And miscellany which I'm not totally sure what to do with\n  yet.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)]\n\n    ;; Some dimmer sweeps\n    (let [dimmer-sweep-fixtures (concat (show/fixtures-named :torrent) (show/fixtures-named :hex))]\n      (show/set-cue! x-base y-base\n                     (cues/cue :dimmers\n                               (fn [var-map] (cues/apply-merging-var-map\n                                              var-map dimmer-sweep  dimmer-sweep-fixtures\n                                              (oscillators/sawtooth :down? (:down var-map)\n                                                                    :interval-ratio (build-ratio-param var-map))))\n                               :color :red :short-name \"Sawtooth Sweep\"\n                               :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                           {:key \"down\" :type :boolean :start true :name \"Down?\"}\n                                           {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                           {:key \"width\" :min 0 :max 1 :start 0.1 :name \"Width\"}\n                                           {:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}\n                                           {:key \"fade\" :type :boolean :start false :name \"Fade?\"}]))\n\n      (show/set-cue! x-base (inc y-base)\n                     (cues/cue :dimmers\n                               (fn [var-map] (cues/apply-merging-var-map\n                                              var-map dimmer-sweep dimmer-sweep-fixtures\n                                              (oscillators/triangle :interval-ratio (build-ratio-param var-map))))\n                               :color :red :short-name \"Triangle Sweep\"\n                               :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 2 :name \"Beats\"}\n                                           {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                           {:key \"width\" :min 0 :max 1 :start 0.25 :name \"Width\"}\n                                           {:key \"level\" :min 0 :max 255 :start 255 :name \"Level\"}\n                                           {:key \"fade\" :type :boolean :start false :name \"Fade?\"}])))\n\n\n    ;; A fun pressure-sensitive dimmer spread effect\n    (show/set-cue! x-base (+ y-base 2)\n                   (cues/cue :bloom (fn [var-map]\n                                      (cues/apply-merging-var-map\n                                       var-map fun/bloom (show/all-fixtures)\n                                       :measure (tf/build-distance-measure 0 rig-height 0 :ignore-z true)))\n                             :variables [{:key \"color\" :type :color :start (colors/create-color :white)\n                                          :name \"Color\"}\n                                         {:key \"fraction\" :min 0 :max 1 :start 0 :velocity true}]\n                             :held true :priority 1000 :color :purple))\n\n    (show/set-cue! (+ x-base 2) (inc y-base)\n                   (cues/cue :movement (fn [var-map]\n                                         (cues/apply-merging-var-map var-map fun/aim-fan\n                                                                     (show/fixtures-named \"torrent\")))\n                             :variables [{:key \"x-scale\" :min -5 :max 5 :start 1 :name \"X Scale\"}\n                                         {:key \"y-scale\" :min -10 :max 10 :start 5 :name \"Y Scale\"}\n                                         {:key \"z\" :min 0 :max 20 :start 4}\n                                       {:key \"y\" :min -10 :max 10 :start rig-height}\n                                       {:key \"x\" :min -10 :max 10 :start 0.0}]\n                           :color :blue :end-keys [:move-torrents]))\n\n    (show/set-cue! (+ x-base 2) (+ y-base 2)\n                   (cues/cue :movement (fn [var-map]\n                                         (cues/apply-merging-var-map var-map fun/twirl\n                                                                     (show/fixtures-named \"torrent\")))\n                             :variables [{:key \"beats\" :min 1 :max 32 :type :integer :start 8 :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 10 :type :integer :start 1 :name \"Cycles\"}\n                                         {:key \"radius\" :min 0 :max 10 :start 0.25 :name \"Radius\"}\n                                         {:key \"z\" :min -10 :max 10 :start -1.0}\n                                         {:key \"y\" :min -10 :max 10 :start rig-height}\n                                         {:key \"x\" :min -10 :max 10 :start 0.0}]\n                             :color :green :end-keys [:move-torrents]))\n\n    (show/set-cue! (inc x-base) (+ y-base 3)\n                   (cues/cue :move-torrents\n                             (fn [var-map] (cues/apply-merging-var-map var-map torrent-8))\n                             :variables [{:key \"bars\" :name \"Bars\" :min 1 :max 8 :type :integer :start 2}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 8 :type :integer :start 1}\n                                         {:key \"stagger\" :name \"Stagger\" :min 0 :max 4 :start 0}\n                                         {:key \"spread\" :name \"Spread\" :min -45 :max 45\n                                          :centered true :resolution 0.25 :start 0}\n                                         {:key \"pan-min\" :name \"Pan min\" :min -180 :max 180\n                                          :centered true :resolution 0.5 :start -75}\n                                         {:key \"pan-max\" :name \"Pan max\" :min -180 :max 180\n                                          :centered true :resolution 0.5 :start 90}\n                                         {:key \"tilt-min\" :name \"Tilt min\" :min -180 :max 180\n                                          :centered true :resolution 0.5 :start -10}\n                                         {:key \"tilt-max\" :name \"Tilt max\" :min -180 :max 180\n                                          :centered true :resolution 0.5 :start 75}]\n                             :color :yellow :end-keys [:movement]))\n\n    (show/set-cue! (inc x-base) (+ y-base 4)\n                   (cues/cue :torrent-circles\n                             (fn [var-map] (cues/apply-merging-var-map var-map circle-chain\n                                                                       (show/fixtures-named :torrent) false))\n                             :variables [{:key \"bars\" :name \"Bars\" :min 1 :max 8 :type :integer :start 2}\n                                         {:key \"radius\" :name \"Radius\" :min 0.1 :max 2\n                                          :resolution 0.1 :start 1.0}\n                                         {:key \"stagger\" :name \"Stagger\" :min 0 :max 2 :start 0\n                                          :resolution 0.1}]\n                             :short-name \"Torrent Circles\" :color :green :priority 4))\n\n    ;; Some color cycle chases\n    (show/set-cue! x-base (+ y-base 7)\n                   (cues/cue :all-color (fn [_] (fun/iris-out-color-cycle-chase (show/all-fixtures)))))\n    (show/set-cue! (inc x-base) (+ y-base 7)\n                   (cues/cue :all-color\n                             (fn [_] (fun/wipe-right-color-cycle-chase\n                                      (show/all-fixtures)\n                                      :transition-phase-function rhythm/snapshot-bar-phase))))\n    (show/set-cue! (+ x-base 2) (+ y-base 7)\n                   (cues/cue :all-color (fn [_] (fun/wipe-right-color-cycle-chase\n                                                 (show/all-fixtures)\n                                                 :color-index-function rhythm/snapshot-beat-within-phrase\n                                                 :transition-phase-function rhythm/snapshot-beat-phase\n                                                 :effect-name \"Wipe Right Beat\"))))\n\n    (show/set-cue! x-base (+ y-base 6)\n                   (cues/cue :confetti\n                             (fn [var-map]\n                               (let [beats (params/bind-keyword-param (:beats var-map) Number 2)\n                                     cycles (params/bind-keyword-param (:cycles var-map ) Number 1)\n                                     step-ratio (params/build-param-formula Number #(/ %1 %2) beats cycles)\n                                     step (params/build-step-param :interval-ratio step-ratio)]\n                                 (cues/apply-merging-var-map var-map\n                                                             fun/confetti (show/all-fixtures)\n                                                             :step step)))\n                             :variables [{:key \"beats\" :min 1 :max 8 :start 2 :type :integer :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 8 :start 1 :type :integer :name \"Cycles\"}\n                                         {:key \"min-added\" :min 0 :max 20 :start 1 :type :integer :name \"Min Add\"}\n                                         {:key \"max-added\" :min 1 :max 20 :start 4 :type :integer :name \"Max Add\"}\n                                         {:key \"min-duration\" :min 1 :max 16 :start 1 :type :integer :name \"Min Last\"}\n                                         {:key \"max-duration\" :min 1 :max 16 :start 4 :type :integer :name \"Max Last\"}\n                                         {:key \"min-saturation\" :min 0 :max 100 :start 100 :name \"Min Sat\"}]\n                             :color :orange :priority 5))\n\n    (show/set-cue! (inc x-base) (+ y-base 6)\n                   (cues/cue :confetti\n                             (fn [var-map]\n                               (let [beats (params/bind-keyword-param (:beats var-map) Number 2)\n                                     cycles (params/bind-keyword-param (:cycles var-map ) Number 1)\n                                     step-ratio (params/build-param-formula Number #(/ %1 %2) beats cycles)\n                                     step (params/build-step-param :interval-ratio step-ratio)]\n                                 (cues/apply-merging-var-map var-map\n                                                             fun/confetti (show/all-fixtures)\n                                                             :step step :aim? true)))\n                             :variables [{:key \"beats\" :min 1 :max 8 :start 2 :type :integer :name \"Beats\"}\n                                         {:key \"cycles\" :min 1 :max 8 :start 1 :type :integer :name \"Cycles\"}\n                                         {:key \"min-added\" :min 0 :max 20 :start 1 :type :integer :name \"Min Add\"}\n                                         {:key \"max-added\" :min 1 :max 20 :start 4 :type :integer :name \"Max Add\"}\n                                         {:key \"min-duration\" :min 1 :max 16 :start 1 :type :integer :name \"Min Last\"}\n                                         {:key \"max-duration\" :min 1 :max 16 :start 4 :type :integer :name \"Max Last\"}\n                                         {:key \"min-saturation\" :min 0 :max 100 :start 100 :name \"Min Sat\"}]\n                             :color :orange :priority 5 :short-name \"Confetti Dance\"))\n\n    (show/set-cue! (+ x-base 5) y-base\n                   (cues/cue :pinstripes\n                             (fn [var-map]\n                               (let [step-ratio (build-ratio-param var-map)\n                                     step (params/build-step-param :interval-ratio step-ratio\n                                                                   :fade-fraction (:fade-fraction var-map))\n                                     colors [(:color-1 var-map) (:color-2 var-map)]]\n                                 (fun/pinstripes (clojure.set/difference\n                                                  (set (show/all-fixtures))\n                                                  (set (show/fixtures-named :snowball)))\n                                                 :step step :colors colors)))\n                             :variables [{:key \"beats\" :name \"Beats\" :min 1 :max 32 :type :integer :start 1}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 16 :type :integer :start 1}\n                                         {:key \"color-1\" :type :color :start (colors/create-color :red)\n                                          :name \"Color 1\"}\n                                         {:key \"color-2\" :type :color :start (colors/create-color :white)\n                                          :name \"Color 2\"}\n                                         {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}]\n                             :color :yellow))\n\n    (show/set-cue! (+ x-base 5) (inc y-base)\n                   (cues/cue :pinstripes\n                             (fn [var-map]\n                               (let [step-ratio (build-ratio-param var-map)\n                                     step (params/build-step-param :interval-ratio step-ratio\n                                                                   :fade-fraction (:fade-fraction var-map))\n                                     colors [(:color-1 var-map) (:color-2 var-map) (:color-3 var-map)]]\n                                 (fun/pinstripes (clojure.set/difference\n                                                  (set (show/all-fixtures))\n                                                  (set (show/fixtures-named :snowball)))\n                                                 :step step :colors colors)))\n                             :variables [{:key \"beats\" :name \"Beats\" :min 1 :max 32 :type :integer :start 1}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 16 :type :integer :start 1}\n                                         {:key \"color-1\" :type :color :start (colors/create-color :red)\n                                          :name \"Color 1\"}\n                                         {:key \"color-2\" :type :color :start (colors/create-color :white)\n                                          :name \"Color 2\"}\n                                         {:key \"color-3\" :type :color :start (colors/create-color :blue)\n                                          :name \"Color 3\"}\n                                         {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}]\n                             :color :orange :short-name \"Pin 3\"))\n\n    (show/set-cue! (+ x-base 5) (+ 2 y-base)\n                   (cues/cue :pinstripes\n                             (fn [var-map]\n                               (let [step-ratio (build-ratio-param var-map)\n                                     step (params/build-step-param :interval-ratio step-ratio\n                                                                   :fade-fraction (:fade-fraction var-map))\n                                     colors [(:color-1 var-map) (:color-2 var-map)\n                                             (:color-3 var-map) (:color-4 var-map)]]\n                                 (fun/pinstripes (clojure.set/difference\n                                                  (set (show/all-fixtures))\n                                                  (set (show/fixtures-named :snowball)))\n                                                 :step step :colors colors)))\n                             :variables [{:key \"beats\" :name \"Beats\" :min 1 :max 32 :type :integer :start 1}\n                                         {:key \"cycles\" :name \"Cycles\" :min 1 :max 16 :type :integer :start 1}\n                                         {:key \"color-1\" :type :color :start (colors/create-color :yellow)\n                                          :name \"Color 1\"}\n                                         {:key \"color-2\" :type :color :start (colors/create-color :purple)\n                                          :name \"Color 2\"}\n                                         {:key \"color-3\" :type :color :start (colors/create-color :white)\n                                          :name \"Color 3\"}\n                                         {:key \"color-4\" :type :color :start (colors/create-color :cyan)\n                                          :name \"Color 4\"}\n                                         {:key \"fade-fraction\" :min 0 :max 1 :start 0 :name \"Fade\"}]\n                             :color :orange :short-name \"Pin 4\"))\n\n    ;; Some macro-based chases\n    (show/set-cue! (+ x-base 7) (inc y-base)\n                   (cues/cue :move-torrents\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Torrent Nod\" *show*\n                                      [[17 15 {:pan-min 90.0 :pan-max 179.0 :pan-bars 2 :pan-phase 0.0\n                                               :tilt-min 148.0 :tilt-max 255.0 :tilt-bars 1, :tilt-phase 0.0}]\n                                       [16 15 {:pan-min 77.0 :pan-max 164.0 :pan-bars 2 :pan-phase 0.0\n                                               :tilt-min 148.0 :tilt-max 255.0, :tilt-bars 1, :tilt-phase 0.0}]]))\n                             :end-keys [:movement]))\n\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/cue :move-torrents\n                             (fn [_] (cues/compound-cues-effect\n                                      \"Torrent Cross Nod\" *show*\n                                      [[16 15 {:pan-min 77.0, :pan-max 164.0, :pan-bars 2, :pan-phase 0.5,\n                                               :tilt-min 148.0, :tilt-max 255.0, :tilt-bars 1, :tilt-phase 0.25}]\n                                       [17 15 {:pan-min 90.0, :pan-max 179.0, :pan-bars 2, :pan-phase 0.0,\n                                               :tilt-min 148.0, :tilt-max 255.0, :tilt-bars 1, :tilt-phase 0.0}]]))\n                             :end-keys [:movement]))))\n\n(defn- aim-cue-var-key\n  \"Determine the cue variable key value to use for a variable being\n  created for an aim cue page cue. `base-name` is the name that will\n  be used for the variable if it is not part of a group of cues\n  sharing variables; if `shared-prefix` is not blank then the variable\n  key will refer to a show variable with that prefix identifying which\n  group it belongs to.\"\n  [base-name shared-prefix]\n  (if (clojure.string/blank? shared-prefix)\n    (name base-name)\n    (keyword (str \"aim-group-\" shared-prefix \"-\" (name base-name)))))\n\n(defn- build-aim-cue\n  \"Build an aim cue for the mutiplexable fixture aiming page.\"\n  [fixture-key shared-prefix transform? color]\n  (let [isolated? (clojure.string/blank? shared-prefix)]\n    (cues/cue (keyword (str \"aim-\" (name fixture-key)))\n              (fn [var-map]\n                (let [base-aim (if isolated?\n                                 (cues/apply-merging-var-map var-map params/build-aim-param)\n                                 (params/build-aim-param :x (aim-cue-var-key \"x\" shared-prefix)\n                                                         :y (aim-cue-var-key \"y\" shared-prefix)\n                                                         :z (aim-cue-var-key \"z\" shared-prefix)))\n                      aim-param (if transform?\n                                  (params/build-aim-transformer base-aim\n                                                                (keyword (str \"aim-group-\" shared-prefix \"-transform\")))\n                                  base-aim)]\n                  (move/aim-effect (str \"Aim \" (name fixture-key)\n                                        (when-not isolated?\n                                          (str \" (Group \" (clojure.string/upper-case shared-prefix)\n                                               (when transform? \" flip\") \")\")))\n                                   aim-param (show/fixtures-named fixture-key))))\n              :variables [(merge {:key (aim-cue-var-key \"x\" shared-prefix) :name \"X\" :min -20.0 :max 20.0\n                                  :centered true :resolution 0.05}\n                                 (when isolated? {:start 0.0}))\n                          (merge {:key (aim-cue-var-key \"y\" shared-prefix) :name \"Y\" :min -20.0 :max 20.0\n                                  :centered true :resolution 0.05}\n                                 (when isolated? {:start 0.0}))\n                          (merge {:key (aim-cue-var-key \"z\" shared-prefix) :name \"Z\" :min -20.0 :max 20.0\n                                  :centered true :resolution 0.05}\n                                 (when isolated? {:start 2.0}))]\n              :color color :priority 1)))\n\n(defn- make-main-aim-cues\n  \"Create a page of cues for aiming lights in particular points,\n  individually and in groups.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)\n        fixtures [:torrent-1 :torrent-2]\n        transform (Transform3D.)\n        width (- right-wall left-wall)\n        depth (- house-rear-wall stage-wall)]\n\n    ;; Set up default shared aiming coordinates\n    (show/set-variable! :aim-group-a-x 0.0)\n    (show/set-variable! :aim-group-a-y 0.0)\n    (show/set-variable! :aim-group-a-z 2.0)\n    (show/set-variable! :aim-group-b-x 0.0)\n    (show/set-variable! :aim-group-b-y 0.0)\n    (show/set-variable! :aim-group-b-z 2.0)\n\n    ;; Set up default transformation of a reflection over the Y axis\n    (.setScale transform (Vector3d. -1.0 1.0 1.0))\n    (show/set-variable! :aim-group-a-transform transform)\n    (show/set-variable! :aim-group-b-transform transform)\n\n    (loop [fixtures fixtures\n           index 0]\n      (when (seq fixtures)\n        (let [fixture (first fixtures)]\n          ;; Disconnected individual aim cues\n          (show/set-cue! (+ x-base index) y-base (build-aim-cue fixture nil false :white))\n\n          ;; Group A untransformed aim cues\n          (show/set-cue! (+ x-base index) (inc y-base) (build-aim-cue fixture \"a\" false :red))\n\n          ;; Group A transformed aim cues\n          (show/set-cue! (+ x-base index) (+ y-base 2) (build-aim-cue fixture \"a\" true :orange))\n\n          ;; Group B untransformed aim cues\n          (show/set-cue! (+ x-base index) (+ y-base 3) (build-aim-cue fixture \"b\" false :blue))\n\n          ;; Group B transformed aim cues\n          (show/set-cue! (+ x-base index) (+ y-base 4) (build-aim-cue fixture \"b\" true :cyan)))\n        (recur (rest fixtures) (inc index))))\n\n    ;; Transformation modifiers for group A\n    (show/set-cue! (+ x-base 7) (inc y-base)\n                   (cues/cue :aim-group-a-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. 1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :aim-group-a-transform transform)))\n                             :color :cyan :short-name \"Group A flip Y\"))\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/cue :aim-group-a-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. -1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :aim-group-a-transform transform)))\n                             :color :cyan :short-name \"Group A flip XY\"))\n\n    ;; Transformation modifiers for group B\n    (show/set-cue! (+ x-base 7) (+ y-base 3)\n                   (cues/cue :aim-group-b-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. 1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :aim-group-b-transform transform)))\n                             :color :orange :short-name \"Group B flip Y\"))\n    (show/set-cue! (+ x-base 7) (+ y-base 4)\n                   (cues/cue :aim-group-b-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. -1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :aim-group-b-transform transform)))\n                             :color :orange :short-name \"Group B flip XY\"))))\n\n(defn- direction-cue-var-key\n  \"Determine the cue variable key value to use for a variable being\n  created for an direction cue page cue. `base-name` is the name that\n  will be used for the variable if it is not part of a group of cues\n  sharing variables; if `shared-prefix` is not blank then the variable\n  key will refer to a show variable with that prefix identifying which\n  group it belongs to.\"\n  [base-name shared-prefix]\n  (if (clojure.string/blank? shared-prefix)\n    (name base-name)\n    (keyword (str \"direction-group-\" shared-prefix \"-\" (name base-name)))))\n\n(defn- build-direction-cue\n  \"Build a direction cue for the mutiplexable fixture direction page.\"\n  [fixture-key shared-prefix transform? color]\n  (let [isolated? (clojure.string/blank? shared-prefix)]\n    (cues/cue (keyword (str \"dir-\" (name fixture-key)))\n              (fn [var-map]\n                (let [base-direction (if isolated?\n                                       (cues/apply-merging-var-map var-map params/build-direction-param-from-pan-tilt)\n                                       (params/build-direction-param-from-pan-tilt\n                                        :pan (direction-cue-var-key \"pan\" shared-prefix)\n                                        :tilt (direction-cue-var-key \"tilt\" shared-prefix)))\n                      direction-param (if transform?\n                                        (params/build-direction-transformer\n                                         base-direction (keyword (str \"direction-group-\" shared-prefix \"-transform\")))\n                                        base-direction)]\n                  (move/direction-effect (str \"P/T \" (name fixture-key)\n                                              (when-not isolated?\n                                                (str \" (Group \" (clojure.string/upper-case shared-prefix)\n                                                     (when transform? \" flip\") \")\")))\n                                         direction-param (show/fixtures-named fixture-key))))\n              :variables [(merge {:key (direction-cue-var-key \"pan\" shared-prefix) :name \"Pan\" :min -180.0 :max 180.0\n                                  :centered true :resolution 0.5}\n                                 (when isolated? {:start 0.0}))\n                          (merge {:key (direction-cue-var-key \"tilt\" shared-prefix) :name \"Tilt\" :min -180.0 :max 180.0\n                                  :centered true :resolution 0.5}\n                                 (when isolated? {:start 0.0}))]\n              :color color :priority 1)))\n\n(defn- build-pan-tilt-osc-cue\n  \"Build a raw pan/tilt oscillator cue.\"\n  [fixture-key]\n  (cues/cue (keyword (str \"p-t-\" (name fixture-key)))\n            (fn [var-map]\n              (let [pan-osc (oscillators/sine :interval :bar :interval-ratio (:pan-bars var-map)\n                                              :phase (:pan-phase var-map))\n                    pan-param (oscillators/build-oscillated-param pan-osc :min (:pan-min var-map)\n                                                                  :max (:pan-max var-map))\n                    tilt-osc (oscillators/sine :interval :bar :interval-ratio (:tilt-bars var-map)\n                                               :phase (:tilt-phase var-map))\n                      tilt-param (oscillators/build-oscillated-param tilt-osc :min (:tilt-min var-map)\n                                                                     :max (:tilt-max var-map))]\n                (fx/scene (str \"P/T \" (name fixture-key))\n                          (chan-fx/channel-effect\n                           \"pan\" pan-param\n                           (chan/extract-channels (chan/expand-heads\n                                                   (show/fixtures-named fixture-key))\n                                                  #(= (:type %) :pan)))\n                          (chan-fx/channel-effect\n                           \"tilt\" tilt-param\n                           (chan/extract-channels (chan/expand-heads (show/fixtures-named fixture-key))\n                                                  #(= (:type %) :tilt))))))\n            :variables [{:key \"pan-min\" :name \"Pan min\" :min 0 :max 255\n                         :centered true :resolution 0.5 :start 0}\n                        {:key \"pan-max\" :name \"Pan max\" :min 0 :max 255\n                         :centered true :resolution 0.5 :start 255}\n                        {:key \"pan-bars\" :name \"Pan bars\" :min 1 :max 16\n                         :type :integer :start 1}\n                        {:key \"pan-phase\" :name \"Pan phase\" :min 0.0 :max 1.0 :start 0.0}\n                        {:key \"tilt-min\" :name \"Tilt min\" :min 0 :max 255\n                         :centered true :resolution 0.5 :start 0}\n                        {:key \"tilt-max\" :name \"Tilt max\" :min 0 :max 255\n                         :centered true :resolution 0.5 :start 255}\n                        {:key \"tilt-bars\" :name \"Tilt bars\" :min 1 :max 16\n                         :type :integer :start 1}\n                        {:key \"tilt-phase\" :name \"Tilt phase\" :min 0.0 :max 1.0 :start 0.0}]\n            :color :green :priority 1))\n\n(defn- make-main-direction-cues\n  \"Create a page of cues for aiming lights in particular directions,\n  individually and in groups.\"\n  [page-x page-y]\n  (let [x-base (* page-x 8)\n        y-base (* page-y 8)\n        fixtures [:torrent-1 :torrent-2]\n        transform (Transform3D.)]\n\n    ;; Set up default shared direction coordinates\n    (show/set-variable! :direction-group-a-pan 0.0)\n    (show/set-variable! :direction-group-a-tilt 0.0)\n    (show/set-variable! :direction-group-b-pan 0.0)\n    (show/set-variable! :direction-group-b-tilt 0.0)\n\n    ;; Set up default transformation of a reflection over the Y axis\n    (.setScale transform (Vector3d. -1.0 1.0 1.0))\n    (show/set-variable! :direction-group-a-transform transform)\n    (show/set-variable! :direction-group-b-transform transform)\n\n    (loop [fixtures fixtures\n           index 0]\n      (when (seq fixtures)\n        (let [fixture (first fixtures)]\n          ;; Disconnected individual direction cues\n          (show/set-cue! (+ x-base index) y-base (build-direction-cue fixture nil false :white))\n\n          ;; Group A untransformed direction cues\n          (show/set-cue! (+ x-base index) (inc y-base) (build-direction-cue fixture \"a\" false :blue))\n          ;; Group A transformed direction cues\n          (show/set-cue! (+ x-base index) (+ y-base 2) (build-direction-cue fixture \"a\" true :cyan))\n\n          ;; Group B untransformed direction cues\n          (show/set-cue! (+ x-base index) (+ y-base 3) (build-direction-cue fixture \"b\" false :red))\n          ;; Group B transformed direction cues\n          (show/set-cue! (+ x-base index) (+ y-base 4) (build-direction-cue fixture \"b\" true :orange))\n\n          ;; Raw pan/tilt oscillated cues\n          (show/set-cue! (+ x-base index) (+ y-base 7) (build-pan-tilt-osc-cue fixture)))\n        (recur (rest fixtures) (inc index))))\n\n    ;; Transformation modifiers for group A\n    (show/set-cue! (+ x-base 7) (inc y-base)\n                   (cues/cue :direction-group-a-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. 1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :direction-group-a-transform transform)))\n                             :color :cyan :short-name \"Group B flip Y\"))\n    (show/set-cue! (+ x-base 7) (+ y-base 2)\n                   (cues/cue :direction-group-a-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. -1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :direction-group-a-transform transform)))\n                             :color :cyan :short-name \"Group B flip XY\"))\n\n    ;; Transformation modifiers for group B\n    (show/set-cue! (+ x-base 7) (+ y-base 3)\n                   (cues/cue :direction-group-b-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. 1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :direction-group-b-transform transform)))\n                             :color :orange :short-name \"Group B flip Y\"))\n    (show/set-cue! (+ x-base 7) (+ y-base 4)\n                   (cues/cue :direction-group-b-transform\n                             (fn [_]\n                               (let [transform (Transform3D.)]\n                                 (.setScale transform (Vector3d. -1.0 -1.0 1.0))\n                                 (var-fx/variable-effect @var-binder :direction-group-b-transform transform)))\n                             :color :orange :short-name \"Group B flip XY\"))))\n\n(defn make-cues\n  \"Create the cues for the show, using the above helper functions.\"\n  []\n  ;; Fill in some cue pages\n  (make-main-color-dimmer-cues 0 0)  ; Creates a sigle 8x8 page at the origin\n  (make-torrent-cues 0 2)  ; Creates 2 8x8 pages: two pages up from the origin, and the next page to the right\n  (make-ambient-cues 1 0)  ; Creates a single 8x8 page to the right of the origin\n  (make-movement-cues 0 1)  ; Creates an 8x8 page above the origin\n  (make-main-aim-cues 1 1)  ; Creates an 8x8 page above the ambient cues\n  (make-main-direction-cues 2 1)  ; Creates an 8x8 page to the right of that\n\n)\n"
  },
  {
    "path": "src/afterglow/transform.clj",
    "content": "(ns afterglow.transform\n  \"Functions for modeling light position and rotation. If you want to\n  make use of Afterglow's spatial reasoning capabilities, you need to\n  tell it, when patching a fixture, the location and orientation of\n  that fixture.\n\n  The coordinate system in afterglow is from the perspective of the\n  audience: Standing facing your show, the X axis passes through it\n  increasing from left to right, the Y axis passes through it\n  increasing away from the floor, and the Z axis passes through it\n  increasing towards the audience. (There is a diagram on the [Show\n  Space]({{guide-url}}show_space.html)\n  documentation page.)\n\n  Pick an origin when setting up your show; in our case it is easiest\n  to use the spot on the floor directly under the center of gravity of\n  the main truss in our lighting rig. Something else may be better for\n  you.\n\n  When hanging your lights, measure how far the center of the light is\n  from the origin of the show, in the X, Y, and Z directions. You\n  don't need to get this precise to the millimeter level, but having\n  it roughly right will make your spatial cues look great.\n\n  Distances in Afterglow are expressed in meters, though there are\n  functions in this namespace for translating other units, if you do\n  not have metric measuring tools handy.\n\n  Fixture definitions for Afterglow should include information about\n  the positions of the light-emitting heads as offsets from the origin\n  of the fixture, and a description of how to identify the origin of\n  the fixture, so that when you patch the fixture and tell Afterglow\n  the position of that origin with respect to the origin of the light\n  show itself, it can calculate the location of each head.\n\n  For this to work you also need to tell Afterglow the orientation in\n  which you have hung the fixture, expressed as a rotation away from\n  the standard orientation described in the fixture definition. Yes,\n  this can be painful to figure out, especially the first few times,\n  and we have ideas about an iPhone app to help automate this, using\n  the phone's camera and ability to track its own orientation. But\n  until then, figure out how much you have rotated the fixture, in\n  radians, around the X, then Y, then Z axes, in that order, and feed\n  that in as well when patching it.\n\n  Again there are functions in this namespace to convert degrees to\n  radians if they are easier for you to work with. In many cases,\n  hopefully, the rotations will be simple. For example, if a light is\n  hanging backwards with respect to its reference orientation, that is\n  a rotation of zero around the X axis, Pi radians about the Y axis,\n  and zero about the Z axis.\n\n  If a fixture does not have multiple heads, and is not a moving head\n  fixture, you can generally ignore the rotation completely when\n  patching it. Getting the orientation right is most important for\n  moving heads, because Afterglow relies on having that information in\n  order to figure out how to aim the light where you want it aimed.\"\n  {:author \"James Elliott\"}\n  (:require [afterglow.channels :as chan]\n            [clojure.math.numeric-tower :as math]\n            [taoensso.timbre :as timbre :refer [debug]])\n  (:import [javax.media.j3d Transform3D]\n           [javax.vecmath Point3d Vector3d]))\n\n(defn inches\n  \"Converts a number of inches to the corresponding number of meters.\"\n  [in]\n  (* in 0.0254))\n\n(defn feet\n  \"Converts a number of feet to the corresponding number of meters.\"\n  [f]\n  (inches (* f 12)))\n\n(defn degrees\n  \"Converts a number of degrees into the corresponding number of\n  radians.\"\n  [deg]\n  (* (/ deg 180) Math/PI))\n\n(defn interpret-rotation\n  \"Given a fixture definition or head, checks whether it has been\n  assigned extrinsic (Euler) angle rotations, or a list of intrinsic\n  rotations. Either way, construct and return the appropriate rotation\n  matrix to represent its orientation.\"\n  [head]\n  (let [rotation (Transform3D.)]\n    (if-let [rotations (seq (:relative-rotations head))]\n      (if (every? zero? (select-keys head [:x-rotation :y-rotation :z-rotation]))\n        (doseq [[axis angle] rotations]\n          (let [rotation-step (Transform3D.)]\n            (case axis\n              :x-rotation (.rotX rotation-step angle)\n              :y-rotation (.rotY rotation-step angle)\n              :z-rotation (.rotZ rotation-step angle)\n              (throw (IllegalArgumentException. (str \"Unknown intrinsic rotation: \" axis\n                                                     \" (must be :x-rotation, :y-rotation, or :z-rotation) \"\n                                                     \" for head: \" head))))\n            (.mul rotation rotation-step)))\n        (throw (IllegalArgumentException.\n                (str \"Head cannot have both extrinsic and intrinsic rotations: \") head)))\n      (let [euler-angles (Vector3d. (:x-rotation head 0.0) (:y-rotation head 0.0) (:z-rotation head 0.0))]\n        (.setEuler rotation euler-angles)))\n    rotation))\n\n;; TODO: Today we are considering the heads to be in a fixed location relative to\n;;       the fixture. Someday this needs to be generalized to cope with fixtures\n;;       with multiple heads where the base fixture can pan and tilt, moving the\n;;       heads themselves, which can then individually pan and tilt.\n(defn- transform-head\n  \"Determine the position and orientation of a fixture's head.\"\n  [fixture head]\n  (let [rotation (Transform3D. (:rotation fixture)) ; Not immutable, so copy!\n        point (Point3d. (:x head 0.0) (:y head 0.0) (:z head 0.0))]\n\n    ;; Transform the location of the head based on the fixture rotation\n    (.transform rotation point)\n\n    ;; Calculate the compound rotation applied to the head\n    (.mul rotation (interpret-rotation head))\n    ;; fixture-rotation now holds the result of both rotations: First the rotation\n    ;; from hanging the fixture, then the rotation of the individual head with\n    ;; respect to the fixture itself, if any.\n\n    (assoc head\n           :rotation rotation\n           :x (+ (:x fixture) (.-x point))\n           :y (+ (:y fixture) (.-y point))\n           :z (+ (:z fixture) (.-z point)))))\n\n(defn- transform-heads\n  \"Determine the positions and orientations of the individual heads of\n  a fixture once its own position and orientation have been\n  established.\"\n  [fixture]\n  (let [transformer (partial transform-head fixture)]\n    (update-in fixture [:heads] #(map transformer %))))\n\n(defn transform-fixture-euler\n  \"Determine the positions and orientations of the fixture and its\n  heads when it is patched into a show. `x`, `y`, and `z` are the\n  position of the fixture's origin point with respect to the show's\n  origin.\n\n  The fixture rotation is expressed as Euler angles in `x-rotation`,\n  `y-rotation`, and `z-rotation`. These are interpreted as the\n  counter-clockwise extrinsic rotations around the show space axes, in\n  that order, needed to get the fixture from its reference orientation\n  to the orientation in which it was actually hung. Extrinsic means\n  that the axes are always the fixed axes of show space, they do not\n  change as you rotate the fixture.\"\n  [fixture x y z x-rotation y-rotation z-rotation]\n  (let [fixture (assoc fixture :x x :y y :z z\n                       :x-rotation x-rotation :y-rotation y-rotation :z-rotation z-rotation)]\n    (transform-heads (assoc fixture :rotation (interpret-rotation fixture)))))\n\n(defn transform-fixture-relative\n  \"Determine the positions and orientations of the fixture and its\n  heads when it is patched into a show. `x`, `y`, and `z` are the\n  position of the fixture's origin point with respect to the show's\n  origin.\n\n  The fixture rotation is expressed as a list of `relative-rotations`\n  in any order. Each list element is a tuple of the rotation\n  type (`:x-rotation`, `:y-rotation`, or `:z-rotation`) and the\n  counter-clockwise angle in radians around that axis which the\n  fixture should be rotated. The fixtue starts at its reference\n  orientation, and these intrinsic rotations are applied, in order,\n  always from the frame of reference of the fixture, including any\n  accumulated previous rotations.\"\n  [fixture x y z relative-rotations]\n  (let [fixture (assoc fixture :x x :y y :z z\n                       :relative-rotations relative-rotations)]\n    (transform-heads (assoc fixture :rotation (interpret-rotation fixture)))))\n\n(defn transform-fixture-rotation-matrix\n  \"Determine the positions and orientations of the fixture and its\n  heads when it is patched into a show. `x`, `y`, and `z` are the\n  position of the fixture's origin point with respect to the show's\n  origin.\n\n  The fixture rotation is expressed as a `javax.media.j3d.Transform3D`\n  matrix containing only rotational components which represents the\n  transformation needed to get the fixture from its reference\n  orientation to the orientation at which it was actually hung.\n\n  This function is useful when you are precomupting a set of rotations\n  based on groups of fixtures that are being patched as an assembly.\"\n  [fixture x y z rotation]\n  (transform-heads (assoc fixture :x x :y y :z z :rotation rotation)))\n\n(defn show-head-positions\n  \"To help sanity-check fixtures' position and orientation after\n  patching them, displays the positions of all heads of the list of\n  fixtures supplied. In the resulting list, top-level fixtures will be\n  identifiable by the presence of their :key entry in the map that\n  includes their position, and will be followed by their heads, if\n  any, until the next top-level fixture entry.\"\n  [fixtures]\n  (map #(select-keys % [:key :x :y :z]) (chan/expand-heads fixtures)))\n\n\n(def two-pi\n  \"The angle which represents a full rotation around a circle.\"\n  (* 2 Math/PI))\n\n(defn invert-direction\n  \"Transform a direction vector in show coordinate space to the way it\n  appears to a head or fixture that has been rotated when hanging.\"\n  [fixture direction]\n  (let [rotation (Transform3D. (:rotation fixture))\n        direction (Vector3d. direction)]  ;; Copy since it is mutable\n    (.invert rotation)\n    #_(.normalize direction)\n    (.transform rotation direction)\n    (debug \"Inverted direction:\" direction)\n    direction))\n\n(defn angle-to-dmx-value\n  \"Given an angle in radians, where positive means counterclockwise\n  around the axis, determine the DMX value needed to achieve that\n  amount of rotation of a fixture away from its center position, given\n  the DMX value of that center position, and the amount the DMX value\n  must change to cause a counterclockwise rotation halfway around a\n  circle. The return value may not be a legal DMX value if the fixture\n  cannot rotate that far; this will be weeded out in other parts of\n  the algorithm.\"\n  [angle center-value half-circle-value]\n  (+ center-value (* (/ angle Math/PI) half-circle-value)))\n\n(defn distance-from-legal-dmx-value\n  \"Measure how far a value is from being within the legal DMX range,\n  to help choose the least-worst solution if a fixture cannot actually\n  reach the desired position.\"\n  [value]\n  (if (neg? value)\n    (- value)\n    (- value 255)))\n\n(defn find-closest-legal-dmx-value-for-angle\n  \"Given a desired rotation from the center position (expressed in\n  radians, with positive values representing counterclockwise\n  rotations around the axis), the DMX value at which the fixture is in\n  its center position, and the amount the DMX value must change in\n  order to cause a counterclockwise rotation halfway around a circle,\n  find the DMX value which achieves that rotation, or if that is not\n  possible, the legal value which yields the closest possible\n  approximation, considering forward and backward rotations beyond a\n  full circle if necessary. Return a tuple of the resulting value and\n  a boolean indicating whether it achieves the desired angle.\n\n  If there is more than one legal solution, return the one that is\n  closest to the specified target value. If no target value is\n  specified (using the keyword parameter :target-value), then use the\n  fixture's center position as the default target value to stay close\n  to.\"\n  [angle center-value half-circle-value & {:keys [target-value] :or {target-value center-value}}]\n  (let [candidates (map #(angle-to-dmx-value % center-value half-circle-value)\n                        [angle (+ angle two-pi) (- angle two-pi)])\n        legal (filter #(<= 0 % 255.99) candidates)]\n    (debug \"candidates:\" candidates)\n    (debug \"legal:\" legal)\n    (debug \"target-value:\" target-value)\n    (if (empty? legal)\n      ;; No legal values, return the closest legal value to the candidate whose value\n      ;; is closest to the valid DMX range.\n      (let [closest (reduce (fn [a b]\n                              (if (< (distance-from-legal-dmx-value a) (distance-from-legal-dmx-value b))\n                                a\n                                b)) candidates)]\n        [(if (neg? closest) 0 255.99) false])\n      ;; We have legal values, return the one cloest to the target value\n      [(reduce (fn [a b]\n                  (if (< (math/abs (- a target-value)) (math/abs (- b target-value)))\n                    a\n                    b)) legal) true])))\n\n(defn- solve-for-tilt-given-pan\n  \"Once we have chosen a candidate pan angle to try to aim the\n  fixture, see what kind of a solution we can get for tilt and DMX\n  values. Returns the best legal DMX values, and whether they actually\n  achieve the desired position.\n\n  If there is more than one legal solution, return the one that is\n  closest to the specified target value.\"\n  [fixture direction rot-y target-pan target-tilt]\n  (let [direction (Vector3d. direction)  ; Make a copy since we are going to mutate it\n        rotation (Transform3D.)]\n    (.rotY rotation (- rot-y))  ; Determine what the aiming vector looks like after we have panned\n    (.transform rotation direction)\n    ;; Now figure out the tilt angle\n    (let [rot-x (- (Math/atan2 (.y direction) (.z direction)))\n          pan-solution (find-closest-legal-dmx-value-for-angle rot-y (:pan-center fixture) (:pan-half-circle fixture)\n                                                               :target-value target-pan)\n          tilt-solution (find-closest-legal-dmx-value-for-angle rot-x (:tilt-center fixture) (:tilt-half-circle fixture)\n                                                                :target-value target-tilt)]\n      (debug \"For pan of\" (/ rot-y Math/PI) \"Pi, we get tilt:\" (/ rot-x Math/PI) \"Pi,\" [pan-solution tilt-solution])\n      [pan-solution tilt-solution])))\n\n(defn- success-score\n  \"Given a pan and tilt solution, assign it a score based on how many\n  components were actually achieved. Currently both pan and tilt\n  solutions re weighted equally; if experience dictates that one\n  matters more than the other, this can be adjusted.\"\n  [[[_ pan-correct] [_ tilt-correct]]]\n  (+ (if pan-correct 1 0) (if tilt-correct 1 0)))\n\n(defn- target-distance\n  \"Given a pan and tilt solution, measure how close it is to the\n  target pan and tilt. Consider pan changes to be twice as disruptive\n  as tilt changes, since they are more obvious.\"\n  [[[pan _] [tilt _]] target-pan target-tilt]\n  (math/sqrt (+ (math/expt (* 2 (math/abs (- pan target-pan))) 2)\n                (math/expt (math/abs (- tilt target-tilt)) 2))))\n\n(defn- pick-best-solution\n  \"Given a pair of potential solutions for pan and tilt, choose the\n  best. First, if they differ in how many of the components were\n  successfully achieved, that determines the best fit. If they are\n  both equally successful, then choose the one which is closest to the\n  target values.\"\n  [target-pan target-tilt solution-a solution-b]\n  (let [success-a (success-score solution-a)\n        success-b (success-score solution-b)]\n    (if (> success-a success-b)\n      solution-a\n      (if (> success-b success-a)\n        solution-b\n        (if (< (target-distance solution-a target-pan target-tilt) (target-distance solution-b target-pan target-tilt))\n          solution-a\n          solution-b)))))\n\n(defn direction-to-dmx\n  \"Given a fixture or head and vector representing a direction in the\n  frame of reference of the light show, calculate the best pan and\n  tilt values to send to that fixture or head in order to aim it in\n  that direction.\n\n  If there is more than one legal solution, return the one that is\n  closest to the former values supplied. If no former values were\n  specified, then use the fixture's center position as the\n  default target value to stay close to.\"\n  [fixture direction former-values]\n  {:pre [(some? fixture) (instance? Vector3d direction)]}\n  (let [direction (invert-direction fixture direction)  ;; Transform to perspective of hung fixture\n        rot-y (Math/atan2 (.x direction) (.z direction))  ;; Calculate pan\n        [target-pan target-tilt] (or former-values [(:pan-center fixture) (:tilt-center fixture)])\n        ;; Try both our calculated pan, and flips halfway around the circle in both directions,\n        ;; hunting for the best solution.\n        candidates (map #(solve-for-tilt-given-pan fixture direction % target-pan target-tilt)\n                        [rot-y (+ rot-y Math/PI) (- rot-y Math/PI)])\n        best (reduce (partial pick-best-solution target-pan target-tilt) candidates)]\n    (debug \"All solutions found: \" candidates)\n    (debug \"Best solution found: \" best)\n    (let [[[pan _] [tilt _]] best]\n      [pan tilt])))\n\n(defn aim-to-dmx\n  \"Given a fixture or head and a point in the frame of reference of\n  the light show, calculate the best pan and tilt values to send to\n  that fixture or head in order to aim it at that point.\n\n  If there is more than one legal solution, return the one that is\n  closest to the former values supplied. If no former values were\n  specified, then use the fixture's center position as the\n  default target value to stay close to.\"\n  [fixture target-point former-values]\n  {:pre [(some? fixture) (instance? Point3d target-point)]}\n  ;; Find direction from fixture to point\n  (let [direction (Vector3d. (- (.x target-point) (:x fixture))\n                             (- (.y target-point) (:y fixture))\n                             (- (.z target-point) (:z fixture)))]\n    (debug \"Calculating aim as direction\" direction)\n    (direction-to-dmx fixture direction former-values)))\n\n(defn calculate-bounds\n  \"Given a list of fixtures, determine the corners of the smallest\n  box which contains them all, and the center of that box.\"\n  [fixtures]\n  (let [all-heads (chan/expand-heads fixtures)\n        min-x (apply min (map :x all-heads))\n        min-y (apply min (map :y all-heads))\n        min-z (apply min (map :z all-heads))\n        max-x (apply max (map :x all-heads))\n        max-y (apply max (map :y all-heads))\n        max-z (apply max (map :z all-heads))\n        center-x (/ (+ min-x max-x) 2)\n        center-y (/ (+ min-y max-y) 2)\n        center-z (/ (+ min-z max-z) 2)]\n    {:min-x min-x :min-y min-y :min-z min-z\n     :max-x max-x :max-y max-y :max-z max-z\n     :center-x center-x :center-y center-y :center-z center-z}))\n\n(defn build-distance-measure\n  \"Returns a function which calculates the distance from a fixture or\n  head to a specified point, optionally ignoring one or more axes.\n  Useful in building transitions which depend on the locations of\n  lights, perhaps only within certain planes or along a single axis.\n\n  The function returned takes a fixture definition, and returns its\n  distance from the configured reference point, after discarding any\n  axes which have been marked as ignored by passing true values along\n  with :ignore-x, :ignore-y, or :ignore-z.\"\n  [x y z & {:keys [ignore-x ignore-y ignore-z]}]\n  (let [reference (Point3d. (if ignore-x 0 x) (if ignore-y 0 y) (if ignore-z 0 z))]\n    (with-meta\n      (fn [head]\n        (let [location (Point3d. (if ignore-x 0 (:x head)) (if ignore-y 0 (:y head)) (if ignore-z 0 (:z head)))]\n          (.distance reference location)))\n      {:type ::distance-measure})))\n\n(defn max-distance\n  \"Calculates the maximum distance that will ever be returned by a\n  distance measure for a set of fixtures.\"\n  [measure fixtures]\n  (let [all-heads (chan/expand-heads fixtures)]\n    (apply max (map measure all-heads))))\n"
  },
  {
    "path": "src/afterglow/util.clj",
    "content": "(ns afterglow.util\n  \"Utility functions that are likely to be widely useful\"\n  {:author \"James Elliott\"}\n  (:require [clojure.math.numeric-tower :as math]\n            [com.evocomputing.colors :as colors]))\n\n(defn ubyte\n  \"Convert small integer to its signed byte equivalent. Necessary for convenient handling of DMX values\n  in the range 0-255, since Java does not have unsigned numbers.\"\n  [val]\n   (if (>= val 128)\n     (byte (- val 256))\n     (byte val)))\n\n(defn unsign\n  \"Convert a signed byte to its unsigned int equivalent, in the range 0-255.\"\n  [val]\n  (bit-and val 0xff))\n\n(defn valid-dmx-value?\n  \"Checks that the supplied value is within the legal range for a DMX\n  channel assignment.\"\n  [v]\n  (<= 0 v 255))\n\n(defn find-closest-key\n  \"Finds the key closest to the one specified in a sorted map.\"\n  [sm k]\n  (if-let [a (first (rsubseq sm <= k))]\n    (let [a (key a)]\n      (if (= a k)\n        a\n        (if-let [b (first (subseq sm >= k))]\n          (let [b (key b)]\n            (if (< (math/abs (- k b)) (math/abs (- k a)))\n              b\n              a))\n          a)))\n    (when-let [found (first (subseq sm >= k))]\n      (key found))))\n\n(def float-epsilon\n  \"The tolerance value for comparing two floating point numbers. If\n  the difference between the values is smaller than this, after\n  scaling appropriately for very small or very large numbers, they\n  will be considered equal.\"\n  0.00001)\n\n(defn- scale\n  \"Calculate a suitable scale factor for floating point comparison\n  tolerance.\"\n  [x y]\n  (if (or (zero? x) (zero? y))\n    1\n    (math/abs x)))\n\n(defn float=\n  \"Compare two floating point numbers for equality, with a tolerance\n  specified by `epsilon`, which defaults to `float-epsilon` if not\n  provided.\"\n  ([x y] (float= x y float-epsilon))\n  ([x y epsilon] (<= (math/abs (- x y))\n                     (* (scale x y) epsilon))))\n\n(defn float<\n  \"Checks whether `x` is less than `y` with an equality tolerance\n  specified by `epsilon`, which defaults to `float-epsilon` if not\n  provided.\"\n  ([x y] (float< x y float-epsilon))\n  ([x y epsilon] (< x\n                    (- y (* (scale x y) epsilon)))))\n\n(defn float>\n  \"Checks whether `x` is greater than `y` with an equality tolerance\n  specified by `epsilon`, which defaults to `float-epsilon` if not\n  provided.\"\n  ([x y] (float< y x))\n  ([x y epsilon] (float< y x epsilon)))\n\n(defn float<=\n  \"Checks whether `x` is less than or equal to `y` with an equality\n  tolerance specified by `epsilon`, which defaults to `float-epsilon`\n  if not provided.\"\n  ([x y] (not (float> x y)))\n  ([x y epsilon] (not (float> x y epsilon))))\n\n(defn float>=\n  \"Checks whether `x` is greater than or equal to `y` with an equality\n  tolerance specified by `epsilon`, which defaults to `float-epsilon`\n  if not provided.\"\n  ([x y] (not (float< x y)))\n  ([x y epsilon] (not (float< x y epsilon))))\n\n(defn contrasting-text-color\n  \"If the default text color of white will be hard to read against a\n  cell assigned the specified color, returns black. Otherwise returns\n  white. Both are in the form of hex strings suitable for use in a CSS\n  style.\"\n  [color]\n  (if (and color\n           ;; Calculate the perceived brightness of the color.\n           (let [[r g b] (map #(/ % 255) [(colors/red color) (colors/green color) (colors/blue color)])]\n             (> (Math/sqrt (+ (* 0.299 r r) (* 0.587 g g) (* 0.114 b b))) 0.6)))\n    \"#000\"\n    \"#fff\"))\n\n(defn normalize-cue-variable-value\n  \"Given a raw value that has been looked up for a cue variable,\n  convert it to the appropriate type based on the variable\n  specification.\"\n  [var-spec raw]\n  (when (some? raw)\n    (case (:type var-spec)\n      :boolean (boolean raw)\n      :integer (Math/round (double raw))\n      :color raw\n      (double raw))))\n"
  },
  {
    "path": "src/afterglow/version.clj",
    "content": "(ns afterglow.version\n  \"Allows the runtime environment to determine the project name and\n  version which built it.\"\n  (:require [afterglow.show-context :as context]\n            [environ.core :refer [env]]))\n\n(defn tag\n  \"Returns the version tag from the project.clj file, either from the\n  environment variable set up by Leiningen, if running in development\n  mode, or from the JAR manifest if running from a production build.\"\n  []\n  (or (env :afterglow-version)\n      (when-let [pkg (.getPackage (class context/set-default-show!))]\n        (.getSpecificationVersion pkg))\n      \"DEV\")) ; Must be running in dev mode embedded in another project\n\n(defn title\n  \"Returns the project name from the project.clj file, either from the\n  environment variable set up by Leiningen, if running in development\n  mode, or from the JAR manifest if running from a production build.\"\n  []\n  (or (env :afterglow-title)\n      (when-let [pkg (.getPackage (class context/set-default-show!))]\n        (.getSpecificationTitle pkg))\n      \"afterglow\"))\n"
  },
  {
    "path": "src/afterglow/web/handler.clj",
    "content": "(ns afterglow.web.handler\n  (:require [afterglow.web.middleware :as middleware]\n            [afterglow.web.routes.home :refer [home-routes]]\n            [compojure.core :refer [defroutes routes wrap-routes]]\n            [compojure.route :as route]))\n\n(defroutes base-routes\n           (route/resources \"/\")\n           (route/not-found \"Not Found\"))\n\n(def app\n  (-> (routes\n        (wrap-routes home-routes middleware/wrap-csrf)\n        base-routes)\n      middleware/wrap-base))\n"
  },
  {
    "path": "src/afterglow/web/layout.clj",
    "content": "(ns afterglow.web.layout\n  (:require [clojure.java.io]\n            [environ.core :refer [env]]\n            [markdown.core :refer [md-to-html-string]]\n            [ring.middleware.anti-forgery :refer [*anti-forgery-token*]]\n            [ring.util.anti-forgery :refer [anti-forgery-field]]\n            [ring.util.response :refer [content-type response]]\n            [selmer.filters :as filters]\n            [selmer.parser :as parser]))\n\n(declare ^:dynamic *identity*)\n(declare ^:dynamic *servlet-context*)\n(parser/set-resource-path!  (clojure.java.io/resource \"templates\"))\n(parser/add-tag! :csrf-field (fn [_ _] (anti-forgery-field)))\n(filters/add-filter! :markdown (fn [content] [:safe (md-to-html-string content)]))\n\n(defn render-with-type [template mime-type & [params]]\n  (-> template\n      (parser/render-file\n        (assoc params\n          :page template\n          :dev (Boolean/valueOf (env :dev))\n          :csrf-token *anti-forgery-token*\n          :servlet-context *servlet-context*\n          :identity *identity*))\n      response\n      (content-type mime-type)))\n\n(defn render [template & [params]]\n  (render-with-type template \"text/html; charset=utf-8\" params))\n"
  },
  {
    "path": "src/afterglow/web/middleware.clj",
    "content": "(ns afterglow.web.middleware\n  (:require [afterglow.web.layout :refer [*servlet-context* *identity*]]\n            [afterglow.web.session :as session]\n            [buddy.auth.accessrules :refer [restrict]]\n            [buddy.auth.backends.session :refer [session-backend]]\n            [buddy.auth.middleware :refer [wrap-authentication]]\n            [buddy.auth :refer [authenticated?]]\n            [clojure.java.io :as io]\n            [environ.core :refer [env]]\n            [prone.middleware :refer [wrap-exceptions]]\n            [ring.middleware.anti-forgery :refer [wrap-anti-forgery]]\n            [ring.middleware.defaults :refer [site-defaults wrap-defaults]]\n            [ring.middleware.format :refer [wrap-restful-format]]\n            [ring.middleware.session.memory :refer [memory-store]]\n            [ring.middleware.session-timeout :refer [wrap-idle-session-timeout]]\n            [ring.util.response :refer [redirect]]\n            [selmer.middleware :refer [wrap-error-page]]\n            [taoensso.timbre :as timbre]))\n\n(defn wrap-servlet-context [handler]\n  (fn [request]\n    (binding [*servlet-context*\n              (if-let [context (:servlet-context request)]\n                ;; If we're not inside a serlvet environment\n                ;; (for example when using mock requests), then\n                ;; .getContextPath might not exist\n                (try (.getContextPath context)\n                     (catch IllegalArgumentException _ context)))]\n      (handler request))))\n\n(defn wrap-internal-error [handler]\n  (fn [req]\n    (try\n      (handler req)\n      (catch Throwable t\n        (timbre/error t)\n        {:status 500\n         :headers {\"Content-Type\" \"text/html\"}\n         :body (-> \"templates/error.html\" io/resource slurp)}))))\n\n(defn wrap-dev [handler]\n  (if (Boolean/valueOf (env :dev))\n    (-> handler\n        wrap-error-page\n        wrap-exceptions)\n    handler))\n\n(defn wrap-csrf [handler]\n  (wrap-anti-forgery handler))\n\n(defn wrap-formats [handler]\n  (wrap-restful-format handler :formats [:json-kw :transit-json :transit-msgpack]))\n\n(defn on-error [request response]\n  {:status  403\n   :headers {\"Content-Type\" \"text/plain\"}\n   :body    (str \"Access to \" (:uri request) \" is not authorized\")})\n\n(defn wrap-restricted [handler]\n  (restrict handler {:handler authenticated?\n                     :on-error on-error}))\n\n(defn wrap-identity [handler]\n  (fn [request]\n    (binding [*identity* (or (get-in request [:session :identity]) nil)]\n      (handler request))))\n\n(defn wrap-auth [handler]\n  (-> handler\n      wrap-identity\n      (wrap-authentication (session-backend))))\n\n(defn wrap-base [handler]\n  (-> handler\n      wrap-dev\n      wrap-auth\n      (wrap-idle-session-timeout\n        {:timeout (* 60 30)\n         :timeout-response (redirect \"/\")})\n      wrap-formats\n      (wrap-defaults\n        (-> site-defaults\n            (assoc-in [:security :anti-forgery] false)\n            (assoc-in  [:session :store] (memory-store session/mem))))\n      wrap-servlet-context\n      wrap-internal-error))\n"
  },
  {
    "path": "src/afterglow/web/routes/home.clj",
    "content": "(ns afterglow.web.routes.home\n  (:require [afterglow.show :as show]\n            [afterglow.version :as version]\n            [afterglow.web.layout :as layout]\n            [afterglow.web.routes.show-control :as show-control]\n            [afterglow.web.routes.visualizer :as visualizer]\n            [afterglow.web.routes.web-repl :as web-repl]\n            [clojure.java.io :as io]\n            [compojure.core :as compojure]\n            [compojure.route :as route]\n            [ring.middleware.anti-forgery :refer [*anti-forgery-token*]]\n            [ring.util.response :as response]))\n\n(defn home-page []\n  (let [shows (map (fn [[show description]]\n                     {:show show :description description})\n                   (vals @show/shows))]\n    (layout/render\n     \"home.html\" {:shows shows\n                  :docs (-> \"docs/docs.md\" io/resource slurp)\n                  :version (str (version/title) \" \" (version/tag))\n                  :csrf-token *anti-forgery-token*})))\n\n(defn about-page []\n  (layout/render \"about.html\" {:csrf-token *anti-forgery-token*}))\n\n(defn visualizer-page []\n  (layout/render \"visualizer.html\" {:csrf-token *anti-forgery-token*}))\n\n(compojure/defroutes home-routes\n  (compojure/GET \"/\" [] (home-page))\n  (compojure/GET \"/show/:id\" [id] (show-control/show-page id))\n  (compojure/GET \"/ui-updates/:id\" [id] (show-control/get-ui-updates id))\n  (compojure/POST \"/ui-event/:id/:kind\" [id kind :as req] (show-control/post-ui-event id kind req))\n  (compojure/GET \"/console\" [] (web-repl/page))\n  (compojure/POST \"/console\" [:as req] (web-repl/handle-command req))\n  (compojure/GET \"/guide\" [] (response/redirect \"/guide/index.html\"))\n  (route/resources \"/guide/\" {:root \"developer_guide\"})\n  (compojure/GET \"/api-doc\" [] (response/redirect \"/api-doc/index.html\"))\n  (route/resources \"/api-doc/\" {:root \"api_doc\"})\n  (compojure/GET \"/about\" [] (about-page))\n  (compojure/GET \"/visualizer/:id\" [id] (visualizer/page id))\n  (compojure/GET \"/visualizer-update/:id\" [id] (visualizer/update-preview id))\n  (compojure/GET \"/shaders/:id/fragment.glsl\" [id] (visualizer/shader id))\n  (route/not-found \"<p>Page not found.</p>\"))\n"
  },
  {
    "path": "src/afterglow/web/routes/show_control.clj",
    "content": "(ns afterglow.web.routes.show-control\n  (:require [afterglow.controllers :as controllers]\n            [afterglow.controllers.tempo :as tempo]\n            [afterglow.carabiner :as carabiner]\n            [afterglow.dj-link :as dj-link]\n            [afterglow.effects.cues :as cues]\n            [afterglow.effects.dimmer :as dimmer]\n            [afterglow.midi :as amidi]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [with-show]]\n            [afterglow.util :as util]\n            [afterglow.web.layout :as layout]\n            (clj-time core format coerce)\n            [clojure.string :as string]\n            [com.evocomputing.colors :as colors]\n            [overtone.at-at :refer [now]]\n            [ring.middleware.anti-forgery :refer [*anti-forgery-token*]]\n            [ring.util.response :refer [response]]\n            [selmer.parser :as parser]\n            [taoensso.timbre :as timbre :refer [warn error]]))\n\n(defn- current-cue-color\n  \"Given a show, the set of keys identifying effects that are\n  currently running in that show, a cue, and the currently-running\n  effect launched by that cue (if any), determines the color with\n  which that cue cell should be drawn in the web interface.\"\n  [show active-keys cue cue-effect held? snapshot]\n  (let [ending (and cue-effect (:ending cue-effect))\n        color (cues/current-cue-color cue cue-effect show snapshot)\n        l-boost (if (zero? (colors/saturation color)) 10.0 0.0)]\n    (colors/create-color\n     :h (colors/hue color)\n     ;; Figure the lightness. Held cues are the lightest, followed by active, non-ending\n     ;; cues. When ending, cues blink between middle and low. If they are not active,\n     ;; they are at middle lightness unless there is another active effect with the same\n     ;; keyword, in which case they are dim.\n     :s (colors/saturation color)\n     :l (+ (if cue-effect\n             (if ending\n               (if (> (rhythm/snapshot-beat-phase snapshot) 0.4) 25.0 50.0)\n               (if held? 90.0 80.0))\n             (if (or (active-keys (:key cue))\n                     (seq (clojure.set/intersection active-keys (set (:end-keys cue))))) 25.0 50.0))\n           l-boost))))\n\n(defn cue-view\n  \"Returns a nested structure of rows of cue information starting at the\n  specified origin, with the specified width and height. Ideal for\n  looping over and rendering in textual form, such as in a HTML table.\n  Each cell contains a tuple of `cue` and `effect`, the cue assigned\n  to that grid location, and the currently-running effect, if any,\n  launched from that cue. Cells which do not have associated cues\n  still be assigned a unique cue ID (identifying page-relative\n  coordinates, with zero at the lower left) so they can be updated if\n  a cue is created for that slot while the page is still up.\"\n  [show left bottom width height holding snapshot]\n  (let [active-keys (show/active-effect-keys show)]\n    (for [y (range (dec (+ bottom height)) (dec bottom) -1)]\n      (for [x (range left (+ left width))]\n        (assoc\n         (if-let [[cue active] (show/find-cue-grid-active-effect show x y)]\n           (let [held? (and holding (= holding [x y (:id active)]))\n                 color (current-cue-color show active-keys cue active held? snapshot)]\n             (assoc cue :current-color color\n                    :style-color (str \"style=\\\"background-color: \" (colors/rgb-hexstr color)\n                                      \"; color: \" (util/contrasting-text-color color) \"\\\"\")))\n           ;; No actual cue found, start with an empty map\n           {})\n         ;; Add the ID whether or not there is a cue\n         :id (str \"cue-\" (- x left) \"-\" (- y bottom)))))))\n\n(defonce ^{:doc \"Tracks the active show interface pages, and any\n  pending interface updates for each.\"}\n  clients\n  (atom {:counter 0}))\n\n(defn- record-page-grid\n  \"Stores the view of the cue grid last rendered by a particular web\n  interface so that differences can be sent the next time the page\n  asks for an update.\"\n  [page-id grid left bottom width height]\n  (swap! clients update-in [page-id] assoc :view [left bottom width height] :grid grid :when (now)))\n\n(defn update-known-controllers\n  \"Makes sure the cached page information contains list of the\n  currently-registered physical grid controllers associated with a\n  page's show, assigning each a unique id number, so they can be\n  selected in the user interface for scrolling or linking to. If this\n  list changed, return the new list so it can be sent as an update to\n  the page.\"\n  [page-id]\n  (let [page-info (get @clients page-id)\n        show (:show page-info)\n        old-info (:controller-info page-info)\n        updated-known (loop [result (update-in old-info [:known]\n                                               select-keys @(:grid-controllers show))\n                             new-controllers (clojure.set/difference @(:grid-controllers show)\n                                                                     (set (keys (:known result))))\n                             counter (inc (:counter result 0))]\n                        (if-not (seq new-controllers)\n                          result\n                          (recur (-> result\n                                     (assoc-in [:known (first new-controllers)] counter)\n                                     (assoc-in [:counter] counter))\n                                 (rest new-controllers)\n                                 (inc counter))))\n        controller-info (if (and (:selected updated-known)\n                                 (not (get (:known updated-known) (:selected updated-known))))\n                          (dissoc updated-known :selected)\n                          updated-known)]\n    (when (not= old-info controller-info)\n      (swap! clients assoc-in [page-id :controller-info] controller-info)\n      controller-info)))\n\n(defn- build-link-select\n  \"Creates the list needed by the template which renders the HTML\n  select object allowing the user to link to one of the currently\n  available controllers, with the current selection, if any, properly\n  identified.\"\n  [controller-info]\n  (let [known (:known controller-info)\n        selected (:selected controller-info)]\n    (loop [sorted (into (sorted-map-by (fn [key1 key2] (compare [(get known key2) key2]\n                                                                [(get known key1) key1])))\n                        known)\n           result [{:label \"\" :value \"\" :selected (nil? selected)}]]\n      (if-not (seq sorted)\n        result\n        (let [[controller id] (first sorted)]\n          (recur (rest sorted)\n                 (conj result {:label (controllers/display-name controller)\n                               :value id\n                               :selected (= controller selected)})))))))\n\n(defn- link-menu-changes\n  \"Returns the changes which need to be sent to a page to update its\n  link menu since it was last displayed, and updates the record in\n  process.\"\n  [page-id]\n  (when-let [new-info (update-known-controllers page-id)]\n    {:link-menu-changes (parser/render-file \"link_menu.html\" {:link-menu (build-link-select new-info)})}))\n\n(defn update-known-midi-sync-sources\n  \"Scans for sources of MIDI clock pulses, and updates the cached page\n  information to contain current list, assigning each a unique id\n  number, so they can be selected in the sync interface.\"\n  [page-id]\n  (let [page-info (get @clients page-id)\n        old-info (:midi-sync page-info)]\n    (try\n      (let [found (amidi/current-clock-sources)\n            source-info (loop [result (update-in old-info [:known] select-keys found)\n                               new-sources (clojure.set/difference found\n                                                                   (set (keys (:known result))))\n                               counter (inc (:counter result 0))]\n                          (if-not (seq new-sources)\n                            result\n                            (recur (-> result\n                                       (assoc-in [:known (first new-sources)] counter)\n                                       (assoc-in [:counter] counter))\n                                   (rest new-sources)\n                                   (inc counter))))]\n        (when (not= old-info source-info)\n          (swap! clients assoc-in [page-id :midi-sync] source-info)))\n      (catch Throwable t\n        (error t \"Problem updating list of MIDI clock sources\")))\n    controllers/pool))\n\n(defn update-known-dj-link-sync-sources\n  \"Updates the cached information to contain current list of Pro DJ\n  Link sync sources seen on the network, assigning each a unique id\n  number, so they can be selected in the sync interface.\"\n  [page-id]\n  (let [page-info (get @clients page-id)\n        old-info (:dj-link-sync page-info)\n        found (dj-link/current-dj-link-sources)\n        source-info (loop [result (update-in old-info [:known] select-keys found)\n                           new-sources (clojure.set/difference found\n                                                               (set (keys (:known result))))\n                           counter (inc (:counter result 0))]\n                      (if-not (seq new-sources)\n                        result\n                        (recur (-> result\n                                   (assoc-in [:known (first new-sources)] counter)\n                                   (assoc-in [:counter] counter))\n                               (rest new-sources)\n                               (inc counter))))]\n    (when (not= old-info source-info)\n      (swap! clients assoc-in [page-id :dj-link-sync] source-info))))\n\n(defn show-page\n  \"Renders the web interface for interacting with the specified show.\"\n  [show-id]\n  (try\n    (amidi/open-inputs-if-needed!) ; Make sure we are watching for clock messages, for the sync UI\n    (catch Throwable t\n      (error t \"Problem opening MIDI inputs\")))\n  (let [[show description] (get @show/shows (Integer/valueOf show-id))\n        snapshot (rhythm/metro-snapshot (:metronome show))\n        grid (cue-view show 0 0 8 8 nil snapshot)\n        page-id (:counter (swap! clients update-in [:counter] inc))\n        shift-mode (atom false)]\n    (swap! clients update-in [page-id] assoc :show show :id page-id\n           :shift-mode shift-mode\n           :tempo-tap-handler (tempo/create-show-tempo-tap-handler show :shift-fn (fn [] @shift-mode)))\n    (record-page-grid page-id grid 0 0 8 8)\n    (layout/render \"show.html\" {:show show :title description :grid grid :page-id page-id\n                                :min-bpm controllers/minimum-bpm :max-bpm controllers/maximum-bpm\n                                :link-menu (build-link-select (update-known-controllers page-id))\n                                :csrf-token *anti-forgery-token*})))\n\n(defn- cue-var-values\n  \"Returns information about the current cue variable values for all\n  currently running effects.\"\n  [show current]\n  (flatten\n   (for [effect current]\n     (for [v (:variables (:cue effect))]\n       (let [value (cues/get-cue-variable (:cue effect) v :show show :when-id (:id effect))]\n         {:effect (:key effect)\n          :id (:id effect)\n          :var (merge {:name (name (:key v))}\n                      (select-keys v [:key :name :min :max :type]))\n          :value (case (:type v)\n                   :color (when value (colors/rgb-hexstr value))\n                   value)})))))\n\n(defn- cue-var-changes\n  \"Returns information about any cue variables for current effects\n  that are different from the last values reported, and updates the\n  list of reported values.\"\n  [page-id current-effects]\n  (let [last-info (get @clients page-id)\n        show (:show last-info)\n        current-vars (cue-var-values show current-effects)\n        prev-vars (or (:cue-vars last-info) #{})\n        changes (filter identity (for [candidate current-vars]\n                                   (when-not (prev-vars candidate)\n                                     {:cue-var-change candidate})))]\n    (swap! clients update-in [page-id] assoc :cue-vars (set current-vars))\n    changes))\n\n(def effect-time-formatter\n  \"The format to use when showing the time an effect was started. See\n  the [clj-time documentation](https://github.com/clj-time/clj-time)\n  if you want details of how to set up a different format string.\"\n  (clj-time.format/formatter-local \"HH:mm:ss\"))\n\n(defn hundredths\n  \"Given a value from 0 to 1, return it as a rounded number of\n  hundredths, except return 99 when it would round to 100, since it\n  has to tie in with a whole value that we cannot easily increment.\n  Used to provide information about the fractional beat and second at\n  which an effect was started in the web interface.\"\n  [n]\n  (min 99 (Math/round (* 100.0 n))))\n\n(defn- effect-summary\n  \"Gather summary information about the effects currently running for\n  display on the page, given the currently active effects reported by\n  the show.\"\n  [active]\n  (let [ending (:ending active)\n        combine (fn [effect effect-meta]\n                  (let [started (:started effect-meta)\n                        start-ms (:instant started)\n                        start-time (clj-time.core/to-time-zone (clj-time.coerce/from-long start-ms)\n                                                                 (clj-time.core/default-time-zone))\n                        start-time-frac (hundredths (/ (clj-time.core/milli start-time) 1000))\n                        start-beat (rhythm/snapshot-marker started)\n                        start-beat-frac (hundredths (rhythm/snapshot-beat-phase started))]\n                    (merge (assoc effect-meta :effect effect)\n                           {:start-time (clj-time.format/unparse effect-time-formatter start-time)\n                            :start-time-frac start-time-frac\n                            :start-beat start-beat :start-beat-frac start-beat-frac}\n                           (when (ending (:key effect-meta))\n                             {:ending true}))))]\n    (map combine (:effects active) (:meta active))))\n\n(defn- new-effect-info\n  \"If the effect was not present when the page was last rendered,\n  return information about it to render now. If there are any existing\n  effects on the page which come after it (meaning they have higher\n  priority), note that this new effect should be rendered on the page\n  after the first existing one found.\"\n  [last-ids effect other-effects]\n  (when-not (last-ids (:id effect))\n    [{:started (merge (select-keys effect [:key :id :priority :start-time :start-time-frac\n                                           :start-beat :start-beat-frac :x :y])\n                      {:name (:name (:effect effect))}\n                      (when (and (:x effect) (:y effect) (:cue effect))\n                        {:macro true})  ; Indicate that it can be used in macros\n                      (when-let [after (some last-ids (map :id other-effects))]\n                        {:after after}))}]))\n\n(defn- new-effects\n  \"Returns descriptions about effects that are new to the page and,\n  where relevant, the existing effects they should be added after.\n  Effects are traversed in increasing priority order, and added to the\n  top of the page, so highest priority and newest are on top.\"\n  [last-ids current]\n  (loop [left current\n         result []]\n    (if (empty? left)\n      result\n      (let [remainder (rest left)]\n        (recur remainder\n               (concat result (new-effect-info last-ids (first left) remainder)))))))\n\n(defn effect-save-button-states\n  \"Returns a set describing all effects which should have a save or\n  clear button visible based on the state of their cue variables. Set\n  elements are a tuple of the effect ID and either `:save` or\n  `:clear`, depending on which button should be visible.\"\n  [show current]\n  (set (for [effect current]\n         (when (and (:x effect) (:y effect) (:cue effect))\n           (let [cur-vals (cues/snapshot-cue-variables\n                           (:cue effect)\n                           (:id effect)\n                           :show\n                           show)]\n             (when (seq cur-vals)\n               (let [saved-vals (controllers/cue-vars-saved-at\n                                 (:cue-grid show)\n                                 (:x effect)\n                                 (:y effect))]\n                 (if (seq saved-vals)\n                   [(:id effect) (if (= cur-vals saved-vals) :clear :save)]\n                   (when (not= cur-vals (:starting-vars effect))\n                     [(:id effect) :save])))))))))\n\n(defn effect-save-button-changes\n  \"Returns the changes which need to be sent to a page to update its\n  effect save/clear button states since it was last rendered, and\n  updates the record.\"\n  [page-id current]\n  (let [last-info (get @clients page-id)\n        show (:show last-info)\n        last-states (:save-button-states last-info)\n        states (effect-save-button-states show current)]\n    (swap! clients update-in [page-id] assoc :save-button-states states)\n    (concat (map (fn [[id kind]]\n                        (if (= kind :save)\n                          {:remove-save-button id}\n                          {:remove-clear-button id}))\n                 (clojure.set/difference last-states states))\n            (map (fn [[id kind]]\n                        (if (= kind :save)\n                          {:add-save-button id}\n                          {:add-clear-button id}))\n                 (clojure.set/difference states last-states)))))\n\n(defn- effect-changes\n  \"Returns the changes which need to be sent to a page to update its\n  effect display since it was last rendered, and updates the record.\"\n  [page-id]\n  (let [last-info (get @clients page-id)\n        show (:show last-info)\n        active @(:active-effects show)\n        current (effect-summary active)\n        current-ids (set (map :id current))\n        last-ids (set (map :id (:effects last-info)))\n        ending (set (filter identity (map #(when (:ending %) (:id %)) current)))\n        endings (map (fn [id] {:ending id}) (clojure.set/difference ending (:effects-ending last-info)))\n        deletions (map (fn [id] {:ended id}) (clojure.set/difference last-ids current-ids))\n        changes (concat deletions (new-effects last-ids current) endings (cue-var-changes page-id current)\n                        (effect-save-button-changes page-id current))]\n    (swap! clients update-in [page-id] assoc :effects current :effects-ending ending)\n    (when (seq changes) {:effect-changes changes})))\n\n(defn- grand-master-changes\n  \"If the dimmer grand master has changed since the last update, report that.\"\n  [page-id]\n  (let [last-info (get @clients page-id)\n        show (:show last-info)\n        master (dimmer/master-get-level (:grand-master show))]\n    (when (not= master (:grand-master last-info))\n      (swap! clients update-in [page-id] assoc :grand-master master)\n      {:grand-master master})))\n\n(defn- grid-changes\n  \"Returns the changes which need to be sent to a page to update its\n  cue grid display since it was last rendered, and updates the\n  record.\"\n  [page-id left bottom width height snapshot]\n  (let [last-info (get @clients page-id)\n        grid (cue-view (:show last-info) left bottom width height (:holding last-info) snapshot)\n        changes (filter identity (flatten (for [[last-row row] (map list (:grid last-info) grid)]\n                                            (for [[last-cell cell] (map list last-row row)]\n                                              (when (not= last-cell cell)\n                                                {:id (:id cell)\n                                                 :name (:name cell)\n                                                 :color (if (:current-color cell)\n                                                          (colors/rgb-hexstr (:current-color cell))\n                                                          \"\")\n                                                 :textColor (util/contrasting-text-color (:current-color cell))})))))]\n    (record-page-grid page-id grid left bottom width height)\n    (when (seq changes) {:grid-changes changes})))\n\n(defn- button-states\n  \"Determine which of the scroll buttons should be enabled for the cue\n  grid.\"\n  [show left bottom width height]\n  (let [bounds @(:dimensions (:cue-grid show))]\n    {:cues-up (>= (second bounds) (+ bottom height))\n     :cues-right (>= (first bounds) (+ left width))\n     :cues-down (pos? bottom)\n     :cues-left (pos? left)}))\n\n(defn- button-changes\n  \"Return the list of changes that should be applied to the cue scroll\n  buttons since the last time they were updated.\"\n  [page-id left bottom width height]\n  (let [last-info (get @clients page-id)\n        last-states (:button-states last-info)\n        next-states (button-states (:show last-info) left bottom width height)\n        changes (filter identity (for [[k _] next-states]\n                                   (when (not= (k last-states) (k next-states))\n                                     {:id (name k)\n                                      :disabled (not (k next-states))})))]\n    (swap! clients update-in [page-id] assoc :button-states next-states)\n    (when (seq changes) {:button-changes changes})))\n\n(defn metronome-states\n  \"Gather details about the current state of the main show metronome.\"\n  [show last-states snap]\n  (with-show show\n    (let [position {:phrase (:phrase snap)\n                    :bar (rhythm/snapshot-bar-within-phrase snap)\n                    :beat (rhythm/snapshot-beat-within-bar snap)}]\n      (merge {:bpm (format \"%.1f\" (double (:bpm snap)))\n              :blink (or (not= position (select-keys last-states [:phrase :bar :beat]))\n                         (< (rhythm/snapshot-beat-phase snap) 0.2))\n              :sync (dissoc (show/sync-status) :status :source)}\n             position))))\n\n(defn metronome-changes\n  \"Return the list of changes that should be applied to the show\n  metronome section since the last time it was updated.\"\n  [page-id snapshot]\n  (let [last-info (get @clients page-id)\n        last-states (:metronome last-info)\n        next-states (metronome-states (:show last-info) last-states snapshot)\n        changes (filter identity (for [[k v] next-states]\n                                   (when (not= (k last-states) (k next-states))\n                                     {:id (name k) :val v})))]\n    (swap! clients update-in [page-id] assoc :metronome next-states)\n    (when (seq changes) {:metronome-changes changes})))\n\n(defn- name-for-sync-sorting\n  \"Sort entries in the sync selection menu first by name, then if that\n  is not unique, by player number if there is one.\"\n  [v]\n  (str (:name v) (:player v)))\n\n(defn- build-sync-list\n  \"Builds a list of sync sources of a particular type for constructing\n  the user interface.\"\n  [known kind name-fn selected]\n  (loop [sorted (into (sorted-map-by (fn [key1 key2] (compare [(name-for-sync-sorting key1) key1]\n                                                              [(name-for-sync-sorting key2) key2])))\n                      known)\n           result []]\n    (if-not (seq sorted)\n      result\n      (let [[source id] (first sorted)]\n        (recur (rest sorted)\n               (conj result {:label (name-fn source)\n                             :value (str (name kind) \"-\" id)\n                             :selected (= source selected)}))))))\n\n(defn build-sync-select\n  \"Creates the list needed by the template which renders the HTML\n  interface allowing the user to link to one of the currently\n  available sources of metronome synchronization, with the current\n  selection, if any, properly identified.\"\n  [page-id]\n  (let [page-info          (get @clients page-id)\n        known-midi         (:known (:midi-sync page-info))\n        known-dj           (:known (:dj-link-sync page-info))\n        traktor-beat-phase (amidi/current-traktor-beat-phase-sources)]\n    (with-show (:show page-info)\n      (concat [{:label    \"Manual (no automatic sync).\"\n                :value    \"manual\"\n                :selected (= :manual (:type (show/sync-status)))}]\n              (when (carabiner/active?)\n                [{:label \"Ableton Link\"\n                  :value \"ableton\"\n                  :selected (= :ableton (:type (show/sync-status)))}])\n              (build-sync-list known-midi :midi #(str (:name %)\n                                                      (if (traktor-beat-phase %)\n                                                        \" (Traktor, sync BPM and beat phase).\"\n                                                        \" (MIDI, sync BPM only).\"))\n                               (:source (show/sync-status)))\n              (build-sync-list known-dj :dj-link #(str (:name %)\n                                                       (when (.startsWith (:name %) \"CDJ\")\n                                                         (str \", Player \" (:player %)))\n                                                       \" (DJ Link Pro, sync precise BPM and beat grid).\")\n                               (:source (show/sync-status)))))))\n\n(defn sync-menu-changes\n  \"Return any changes that should be applied to the menu of available\n  metronome sync options since the last time it was updated.\"\n  [page-id]\n  (let [last-info (get @clients page-id)\n        next-menu (parser/render-file \"sync_menu.html\" {:sync-menu (build-sync-select page-id)})]\n    (when (> (- (now) (:last-sync-refresh last-info 0)) 2000)\n      (swap! clients assoc-in [page-id :last-sync-refresh] (now))\n      (update-known-dj-link-sync-sources page-id)\n      (update-known-midi-sync-sources page-id))\n    (when (not= next-menu (:sync-menu last-info))\n      (swap! clients assoc-in [page-id :sync-menu] next-menu)\n      {:sync-menu-changes next-menu})))\n\n(defn load-update\n  \"If the show is running and we haven't sent a load update in the\n  last half second, send one.\"\n  [page-id]\n  (let [last-info (get @clients page-id)]\n    (with-show (:show last-info)\n      (when (and (show/running?) (> (- (now) (:last-load-update last-info 0)) 500))\n        (swap! clients assoc-in [page-id :last-load-update] (now))\n        {:load-level (show/current-load)}))))\n\n(defn status-update\n  \"If the running or error status of the show has changed, send an\n  update about it.\"\n  [page-id]\n  (let [last-info (get @clients page-id)]\n    (with-show (:show last-info)\n      (let [ola-failure (show/ola-failure-description)\n            status (merge {:running (show/running?)}\n                          (when ola-failure {:error ola-failure}))]\n        (when (not= status (:last-status last-info))\n          (swap! clients assoc-in [page-id :last-status] status)\n          {:show-status status})))))\n\n(defn- find-page-in-cache\n  \"Looks up the cached show page status for the specified ID, cleaning\n  out any other entries which have not been used for a few minutes.\"\n  [page-id]\n  (doseq [[k v] @clients]\n    (when (and (number? k)\n               (not= k page-id)\n               (> (- (now) (:when v)) 12000))\n      (swap! clients dissoc k)))\n  (get @clients page-id))\n\n(defn get-ui-updates\n  \"Route which delivers any changes which need to be applied to a show\n  web interface to reflect differences in the current show state\n  compared to when it was last updated.\"\n  [id]\n  (try\n    (let [page-id(Integer/valueOf id)]\n      (if-let [last-info (find-page-in-cache page-id)]\n        ;; Found the page tracking information, send an update.\n        (let [[left bottom width height] (:view last-info)\n              snapshot (rhythm/metro-snapshot (get-in last-info [:show :metronome]))]\n          (response (merge {}\n                           (grid-changes page-id left bottom width height snapshot)\n                           (effect-changes page-id)\n                           (grand-master-changes page-id)\n                           (button-changes page-id left bottom width height)\n                           (sync-menu-changes page-id)\n                           (link-menu-changes page-id)\n                           (metronome-changes page-id snapshot)\n                           (load-update page-id)\n                           (status-update page-id))))\n        ;; Found no page tracking information, advise the page to reload itself.\n        (response {:reload \"Page ID not found\"})))\n    (catch Throwable t\n           (warn t \"Problem building web UI updates.\")\n           (response {:error (str \"Unable to build updates:\" (.getMessage t))}))))\n\n;; TODO: Move this macro recording facility into a separate namespace so that the\n;;       Ableton Push can use it too.\n\n(defonce ^:private ^{:doc \"Used to assign unique keywords to cues created as macros.\"}\n  macro-counter\n  (atom 0))\n\n(defonce macro-record-file ^{:doc \"When not nil, any macros defined\n  will have the code that can re-create them appended to the named\n  file.\"}\n  (atom nil))\n\n(defn- reformat-colors-for-saving\n  \"Rewrite the cue variables of a macro being saved for later use in a\n  form where the color objects will get properly recreated.\"\n  [cues-with-vars]\n  (mapv (fn [[x y vars]]\n          [x y (reduce (fn [r [k v]]\n                         (assoc r k (if (= (type v) :com.evocomputing.colors/color)\n                                      (list 'colors/create-color (str \\\" (colors/rgb-hexstr v) \\\"))\n                                      v))) {} vars)])\n        cues-with-vars))\n\n(defn- handle-create-macro\n  \"Process a request to create a macro from running effects.\"\n  [page-info x y macro-name macro-effects]\n  (with-show (:show page-info)\n    (let [cues           (map #(controllers/cue-at (:cue-grid (:show page-info)) (:x %) (:y %)) macro-effects)\n          cue-errors     (filter identity (map (fn [cue effect]\n                                                 (when (nil? cue) (str \"No cue found at [\" (:x effect) (:y effect) \"].\")))\n                                               cues macro-effects))\n          cues-with-vars (when (empty? cue-errors)\n                           (vec (map (fn [cue effect]\n                                       [(:x effect) (:y effect) (cues/snapshot-cue-variables cue (:id effect))])\n                                     cues macro-effects)))\n          errors         (concat cue-errors (when (clojure.string/blank? macro-name) [\"No macro name provided.\"]))]\n      (if (seq errors)\n        {:error (clojure.string/join \" \" errors)}\n        (let [macro-key (keyword (str \"macro-\" (swap! macro-counter inc)))\n              save-err  (atom nil)]\n          (when-let [file @macro-record-file]\n            (try\n              (spit file (with-out-str\n                           (println)\n                           (println \";; Macro recorded\" (java.util.Date.))\n                           (println \"(show/set-cue!\" x  y)\n                           (println \"  (cues/cue\" macro-key)\n                           (println (str \"    (fn [_] (cues/compound-cues-effect \\\"\" macro-name \"\\\" *show*\"))\n                           (print \"           \" (reformat-colors-for-saving cues-with-vars))\n                           (println \"))))\"))\n                    :append true)\n              (catch Throwable t\n                (reset! save-err t))))\n          (controllers/set-cue! (:cue-grid (:show page-info)) x y\n                                (cues/cue macro-key\n                                          (fn [_] (cues/compound-cues-effect macro-name (:show page-info)\n                                                                             cues-with-vars))))\n          (if (nil? @save-err)\n            {:macro-created macro-key}\n            {:error (str \"Macro saved to cue grid, but unable to write to file \" @macro-record-file \": \"\n                         @save-err)}))))))\n\n(defn- handle-cue-click-event\n  \"Process a mouse down on a cue grid cell.\"\n  [page-info kind req]\n  (let [[left bottom] (:view page-info)\n        [_ column row] (clojure.string/split kind #\"-\")\n        [x y] (map + (map #(Integer/valueOf %) [column row]) [left bottom])  ; Translate relative page coordinates\n        [cue active] (show/find-cue-grid-active-effect (:show page-info) x y)\n        shift (get-in req [:params :shift])]\n    (if cue\n      (with-show (:show page-info)\n        (if (and active (not (:held cue)))\n          (do (show/end-effect! (:key cue))\n              {:ended kind})\n          (let [id (show/add-effect-from-cue-grid! x y)]\n            (if (and (:held cue) (not shift))\n              (do\n                ;; Let the grid know a momentary cue is being held, so proper feedback can be shown\n                (swap! clients assoc-in [(:id page-info) :holding] [x y id])\n                {:holding {:x x :y y :id id}})\n              {:started id}))))\n      (let [macro-name (get-in req [:params :macroName])\n            macro-effects (get-in req [:params :macroEffects])]\n        (if (seq macro-effects)\n          (handle-create-macro page-info x y macro-name macro-effects)\n          {:error (str \"No cue found for cell: \" kind)})))))\n\n(defn- handle-cue-release-event\n  \"Process a mouse up after clicking a momentary cue grid cell.\"\n  [page-info kind]\n  (let [[_ column row id] (clojure.string/split kind #\"-\")\n        [x y] (map #(Integer/valueOf %) [column row])  ; The actual cue coordinates are sent\n        id (Integer/valueOf id)\n        [cue active] (show/find-cue-grid-active-effect (:show page-info) x y)]\n    (swap! clients update-in [(:id page-info)] dissoc :holding)\n    (if cue\n      (with-show (:show page-info)\n        (if (:held cue)\n          (do (show/end-effect! (:key cue) :when-id id)\n              {:ended id})\n          {:error (str \"Cue was not held for cell: \" kind)}))\n      {:error (str \"No cue found for cell: \" kind)})))\n\n(defn- handle-cue-delete-event\n  \"Process a request to delete a cue in a grid cell.\"\n  [page-info kind]\n  (let [[left bottom] (:view page-info)\n        [_ _ column row] (clojure.string/split kind #\"-\")\n        [x y] (map + (map #(Integer/valueOf %) [column row]) [left bottom])]\n    (controllers/clear-cue! (get-in page-info [:show :cue-grid]) x y)\n    {:deleted [x y]}))\n\n(defn- handle-end-effect-event\n  \"Process a mouse down on an event's end button.\"\n  [page-info req]\n  (let [id (Integer/valueOf (get-in req [:params :effect-id]))]\n    (with-show (:show page-info)\n      (show/end-effect! (get-in req [:params :key]) :when-id id))\n    {:ended id}))\n\n(defn- handle-set-cue-var-event\n  \"Process a change to a cue variable (e.g. dragging the slider).\"\n  [page-info req]\n  (with-show (:show page-info)\n    (let [{:keys [effect-key effect-id var-key value]} (:params req)\n          effect (show/find-effect effect-key)\n          cue (:cue effect)\n          var-spec (some #(when (= (name (:key %)) var-key) %) (:variables cue))]\n      (when (every? some? [cue var-spec value])\n        (let [value (case (:type var-spec)\n                      :color (colors/create-color value)\n                      :boolean (Boolean/valueOf value)\n                      :integer (Integer/valueOf value)\n                      (Double/valueOf value))]\n          (cues/set-cue-variable! cue var-spec value :when-id (Integer/valueOf effect-id))))\n      {:set effect-key})))\n\n(defn- handle-save-effect-event\n  \"Process a request to save the current state of an effect's cue\n  variables.\"\n  [page-info req]\n  (with-show (:show page-info)\n    (let [{:keys [effect-key effect-id]} (:params req)\n          effect (show/find-effect effect-key)\n          cue (:cue effect)]\n      (when (some? cue)\n        (controllers/save-cue-vars! (:cue-grid (:show page-info)) (:x effect) (:y effect)\n                                    (cues/snapshot-cue-variables cue (Integer/valueOf effect-id))))\n      {:saved effect-key})))\n\n(defn- handle-clear-effect-event\n  \"Process a request to clear an effect's saved cue variables.\"\n  [page-info req]\n    (with-show (:show page-info)\n    (let [{:keys [effect-key effect-id]} (:params req)\n          effect (show/find-effect effect-key)\n          cue (:cue effect)]\n      (when (and (= (Integer/valueOf effect-id) (:id effect)) (some? cue))\n        (controllers/clear-saved-cue-vars! (:cue-grid (:show page-info)) (:x effect) (:y effect)))\n      {:cleared effect-key})))\n\n(defn- move-view\n  \"Updates the origin of our view rectangle, and if it actually\n  changed, also moves any linked controller.\"\n  [page-info new-left new-bottom]\n  (let [[left bottom width height] (:view page-info)]\n    (when (or (not= left new-left) (not= bottom new-bottom))\n      (swap! clients assoc-in [(:id page-info) :view] [new-left new-bottom width height])\n      (when-let [controller (:linked-controller page-info)]\n        (when (not= left new-left) (controllers/current-left controller new-left))\n        (when (not= bottom new-bottom) (controllers/current-bottom controller new-bottom))))))\n\n(defn- handle-cue-move-event\n  \"Process a request to scroll the cue grid.\"\n  [page-info kind req]\n  (let [[left bottom width height] (:view page-info)\n        grid-width (controllers/grid-width (:cue-grid (:show page-info)))\n        grid-height (controllers/grid-height (:cue-grid (:show page-info)))\n        shift (= (get-in req [:params :shift]) \"true\")]\n    (if (case kind\n          \"cues-up\" (when (> (- grid-height bottom) (dec height))\n                      (move-view page-info left (if shift (* 8 (quot (dec grid-width) 8)) (+ bottom height))))\n          \"cues-down\" (when (pos? bottom)\n                        (move-view page-info left (if shift 0 (- bottom (min bottom height)))))\n          \"cues-right\" (when (> (- grid-width left) (dec width))\n                         (move-view page-info (if shift (* 8 (quot (dec grid-width) 8)) (+ left width)) bottom))\n          \"cues-left\" (when (pos? left)\n                        (move-view page-info (if shift 0 (- left (min left width))) bottom))\n          nil)  ; We did not recognize the direction\n      {:moved kind}\n      {:error (str \"Unable to move cue grid in direction: \" kind)})))\n\n(defn- linked-controller-update\n  \"Called when a linked physical controller has scrolled, or is being\n  deactivated.\"\n  [old-page-info controller action]\n  (case action\n    :moved\n    (if-let [page-info (get @clients (:id old-page-info))]\n      ;; Page is still active, so update its view origin.\n      (move-view page-info (controllers/current-left controller) (controllers/current-bottom controller))\n      ;; Page is no longer active, remove our listener so we can be garbage collected.\n      (controllers/remove-move-listener controller (:move-handler old-page-info)))\n\n    :deactivated\n    (when-let [page-info (get @clients (:id old-page-info))]\n      (swap! clients update-in [(:id page-info)] dissoc :move-handler :linked-controller))))\n\n(defn unlink-controller\n  \"Remove any physical grid controller currently linked to scroll in\n  tandem.\"\n  [page-id]\n  (when-let [page-info (get @clients page-id)]\n    (when-let [controller (:linked-controller page-info)]\n      (controllers/remove-move-listener controller (:move-handler page-info)))\n    (swap! clients update-in [page-id] dissoc :move-handler :linked-controller)\n    (swap! clients update-in [page-id :controller-info] dissoc :selected)))\n\n;; TODO: Reload the window with the right number of rows and columns if the\n;; physical controller has a different number?\n(defn link-controller\n  \"Tie the cue grid display to that of a physical grid controller, so\n  that they scroll in tandem.\"\n  [page-id controller]\n  (when-let [page-info (get @clients page-id)]\n    (unlink-controller page-id)  ;; In case there was a previous link\n    (let [move-handler (partial linked-controller-update page-info)]\n      (swap! clients update-in [page-id] assoc :move-handler move-handler :linked-controller controller)\n      (swap! clients assoc-in [page-id :controller-info :selected] controller)\n      (controllers/add-move-listener controller move-handler)\n      (move-view (dissoc page-info :linked-controller)\n                 (controllers/current-left controller) (controllers/current-bottom controller)))))\n\n(defn- handle-link-controller-event\n  \"Process a request to specify a controller to link to.\"\n  [page-info id]\n  (if (clojure.string/blank? id)\n    (do (unlink-controller (:id page-info))\n        {:linked \"\"})\n    (let [id (Long/valueOf id)]\n      (loop [choices (:known (:controller-info page-info))]\n        (if-not (seq choices)\n          {:error (str \"Unrecognized controller id: \" id)}\n          (let [[k v] (first choices)]\n            (if (= v id)\n              (do (link-controller (:id page-info) k)\n                  {:linked id})\n              (recur (rest choices)))))))))\n\n(defn- handle-sync-choice-event\n  \"Process a request to specify a metronome sync source.\"\n  [page-info value]\n  (with-show (:show page-info)\n    (cond (or (clojure.string/blank? value) (= \"manual\" value))\n          (do (show/sync-to-external-clock nil)\n              {:sync \"manual\"})\n\n          (.startsWith value \"midi-\")\n          (let [id (Long/valueOf (second (clojure.string/split value #\"-\")))]\n            (loop [choices (:known (:midi-sync page-info))]\n              (if-not (seq choices)\n                {:error (str \"Unrecognized MIDI sync source id: \" id)}\n                (let [[k v] (first choices)]\n                  (if (= v id)\n                    (do (show/sync-to-external-clock (amidi/sync-to-midi-clock k))\n                        {:linked value})\n                    (recur (rest choices)))))))\n\n          (.startsWith value \"dj-link-\")\n          (let [id (Long/valueOf (get (clojure.string/split value #\"-\") 2))]\n            (loop [choices (:known (:dj-link-sync page-info))]\n              (if-not (seq choices)\n                {:error (str \"Unrecognized DJ Link sync source id: \" id)}\n                (let [[k v] (first choices)]\n                  (if (= v id)\n                    (do (show/sync-to-external-clock (dj-link/sync-to-dj-link k))\n                        {:linked value})\n                    (recur (rest choices)))))))\n          :else\n          {:error (str \"Unrecognized sync option\" value)})))\n\n(defn metronome-delta-for-event\n  \"If the UI event name submitted by a show page corresponds to a\n  metronome shift, return the appropriate number of milliseconds.\"\n  [page-info kind]\n  (let [metro (:metronome (:show page-info))]\n    (when-let [delta (get {\"beat-up\" (- (rhythm/metro-tick metro))\n                           \"beat-down\" (rhythm/metro-tick metro)\n                           \"bar-up\" (- (rhythm/metro-tock metro))\n                           \"bar-down\" (rhythm/metro-tock metro)}\n                          kind)]\n      [delta metro])))\n\n(defn metronome-bpm-delta-for-event\n  \"If the UI event name submitted by a show page corresponds to a\n  metronome bpm shift, and the metronome is not synced, return the\n  appropriate bpm adjustment.\"\n  [page-info kind]\n  (with-show (:show page-info)\n    (when (= (:type (show/sync-status)) :manual)\n      (let [metro (:metronome (:show page-info))]\n        (when-let [delta (get {\"bpm-up\" (/ 1 10)\n                               \"bpm-down\" (- (/ 1 10))}\n                              kind)]\n          [delta metro])))))\n\n(defn- interpret-tempo-tap\n  \"React appropriately to a tempo tap, based on the sync mode of the\n  show metronome.\"\n  [page-info req]\n  (reset! (:shift-mode page-info) (= (get-in req [:params :shift]) \"true\"))\n  ((:tempo-tap-handler page-info)))\n\n(defn post-ui-event\n  \"Route which reports a user interaction with the show web\n  interface.\"\n  [id kind req]\n  (try (when-let [page-id (Integer/valueOf id)]\n         (if-let [page-info (get @clients page-id)]\n           ;; Found the page tracking information, process the event.\n           (response\n            (cond (.startsWith kind \"cue-\")\n                  (handle-cue-click-event page-info kind req)\n\n                  (.startsWith kind \"release-\")\n                  (handle-cue-release-event page-info kind)\n\n                  (.startsWith kind \"delete-cue-\")\n                  (handle-cue-delete-event page-info kind)\n\n                  (.startsWith kind \"cues-\")\n                  (handle-cue-move-event page-info kind req)\n\n                  (= kind \"end-effect\")\n                  (handle-end-effect-event page-info req)\n\n                  (= kind \"set-cue-var\")\n                  (handle-set-cue-var-event page-info req)\n\n                  (= kind \"link-select\")\n                  (handle-link-controller-event page-info (get-in req [:params :value]))\n\n                  (= kind \"choose-sync\")\n                  (handle-sync-choice-event page-info (get-in req [:params :value]))\n\n                  (when-let [[delta metro] (metronome-delta-for-event page-info kind)]\n                    (rhythm/metro-adjust metro delta))\n                  {:adjusted kind}\n\n                  (when-let [[delta metro] (metronome-bpm-delta-for-event page-info kind)]\n                    (rhythm/metro-bpm metro (+ (rhythm/metro-bpm metro) delta)))\n                  {:adjusted kind}\n\n                  (= kind \"bpm-slider\")\n                  (rhythm/metro-bpm (:metronome (:show page-info))\n                                    (Double/valueOf (get-in req [:params :value])))\n\n                  (= kind \"grand-master-slider\")\n                  (dimmer/master-set-level (:grand-master (:show page-info))\n                                           (Double/valueOf (get-in req [:params :value])))\n\n                  (= kind \"phrase-reset\")\n                  (do (rhythm/metro-phrase-start (:metronome (:show page-info)) 1)\n                      {:adjusted kind})\n\n                  (= kind \"tap-tempo\")\n                  (interpret-tempo-tap page-info req)\n\n                  (= kind \"startButton\")\n                  (with-show (:show page-info)\n                    (show/start!)\n                    {:running true})\n\n                  (= kind \"stopButton\")\n                  (with-show (:show page-info)\n                    (show/stop!)\n                    (Thread/sleep (:refresh-interval (:show page-info)))\n                    (show/blackout-show)\n                    {:running false})\n\n                  (= kind \"save-effect\")\n                  (handle-save-effect-event page-info req)\n\n                  (= kind \"clear-effect\")\n                  (handle-clear-effect-event page-info req)\n\n                  ;; We do no recognize this kind of request\n                  :else\n                  (do\n                    (warn \"Unrecognized UI event posted:\" kind)\n                    {:error (str \"Unrecognized UI event kind: \" kind)})))\n           ;; Found no page tracking information, advise the page to reload itself.\n           (response {:reload \"Page ID not found\"})))\n       (catch Throwable t\n           (warn t \"Problem processing web UI event.\")\n           (response {:error (str \"Unable to process event:\" (.getMessage t))}))))\n"
  },
  {
    "path": "src/afterglow/web/routes/visualizer.clj",
    "content": "(ns afterglow.web.routes.visualizer\n  (:require [afterglow.effects.movement :as movement]\n            [afterglow.fixtures :as fixtures]\n            [afterglow.show :as show]\n            [afterglow.web.layout :as layout]\n            [com.evocomputing.colors :as colors])\n  (:import [javax.media.j3d Transform3D]\n           [javax.vecmath Matrix3d Vector3d]))\n\n(def max-lights\n  \"The maximum number of lights that the visualizer will attempt to\n  render. Adjust this based on the performance of your graphics hardware.\"\n  4)\n\n(defn show-span\n  \"Determine the degree to which a show spreads over an axis. For the\n  X and Z axes, this is simply the difference in bounding box\n  coordinates. For Y, we want to preserve height from the floor, so we\n  use zero as a lower bound on the minimum coordinate.\"\n  [show axis]\n  (let [dim @(:dimensions show)\n        min-val ((keyword (str \"min-\" axis)) dim)\n        lower-bound (if (= axis \"y\")\n                      (min 0 min-val)\n                      min-val)]\n    (- ((keyword (str \"max-\" axis)) dim) lower-bound)))\n\n(defn shader-scale\n  \"Determine how much we need to scale the show so it fits in the\n  shader's bounding cube which has a width of 1.0, a height of 0.5,\n  and a depth of 0.5. We are not going to shift lights down to the\n  floor, though.\"\n  [show]\n  (double (apply min (map / [1 0.5 0.5]\n                          (for [axis [\"x\" \"y\" \"z\"]]\n                            (max 0.0001 (show-span show axis)))))))\n\n(defn axis-shift\n  \"Determine how much we need to translate show space points along an\n  axis after they have been scaled to move them into the shader's\n  bounding cube. If there is extra room for this axis, center it\n  within the bounding cube.\"\n  [show axis origin available-span scale]\n  (let [scaled-span (* scale (show-span show axis))\n        padding (/ (- available-span scaled-span) 2)\n        scaled-smallest-value (* scale (if (= axis \"y\")\n                                         0\n                                         ((keyword (str \"min-\" axis)) @(:dimensions show))))\n        full-shift (double (- origin scaled-smallest-value))]\n    (println axis \"ssv:\" scaled-smallest-value \"origin:\" origin \"padding:\" padding)\n    [(keyword (str axis \"-offset\"))\n     (+ full-shift padding)]))\n\n(defn shader-offsets\n  \"Determine the values to add to the coordinates of scaled light positions\n  to move them inside the shader's bounding cube, whose origin is\n  (-0.5, -0.25, 0).\"\n  [show scale]\n  (into {} (for [[axis origin available-span] [[\"x\" -0.5 1.0] [\"y\" -0.25 0.5] [\"z\" 0 0.5]]]\n             (axis-shift show axis origin available-span scale))))\n\n(defn adjusted-positions\n  \"Move the spotlights so they all fit within the shader's bounding\n  cube, which extends from (-0.5, 0.25, 0.5) to (0.5, -0.25, 0).\"\n  [lights show scale]\n  (let [offsets (shader-offsets show scale)]\n    (partition 3 (for [[_ head] lights\n                       [axis flip] [[\"x\" -1] [\"y\" -1] [\"z\" 1]]]\n                   (* flip (+ (* ((keyword axis) head) scale)\n                              ((keyword (str axis \"-offset\")) offsets)))))))\n\n(defn adjusted-rotations\n  \"Get the current orientations of the active spotlights for the visualizer.\n  Return as a series of columns of the rotation matrices, since it\n  looks like WebGL or THREE.js is a lot happier passing vectors than\n  matrices as uniforms.\"\n  [show]\n  (apply concat (for [[_ head] (:visualizer-visible @(:dimensions show))]\n                  (let [rot (Matrix3d.)\n                        adjust (Matrix3d.)]\n                    ;; Transform from show orientation to shader orientation\n                    (.rotX adjust (/ Math/PI 2))\n                    (.get (:rotation head) rot)\n                    (.mulNormalize rot adjust)\n                    [[(.-m00 rot) (.-m10 rot) (.-m20 rot)]\n                     [(.-m01 rot) (.-m11 rot) (.-m21 rot)]\n                     [(.-m02 rot) (.-m12 rot) (.-m22 rot)]]))))\n\n(defn visualizer-pan-tilt\n  \"Given a head and DMX pan and tilt values, calculate the pan\n  and tilt angles to send the visualizer\"\n  [head pan tilt]\n  (let [rotation (movement/current-rotation head pan tilt)\n        visualizer-perspective (Transform3D.)\n        direction (Vector3d. 0 0 1)]\n    ;; Add a rotation so we are seeing the rotation from the\n    ;; default perspectve of the visualizer.\n    (.rotX visualizer-perspective (/ Math/PI 2))\n    (.mul rotation visualizer-perspective)\n\n    (.transform rotation direction)\n    (let [rot-y (Math/atan2 (.x direction) (.z direction)) ;; Get pan\n          new-direction (Vector3d. direction)] ;; Determine aiming vector after pan\n      (.rotY visualizer-perspective (- rot-y))\n      (.transform visualizer-perspective new-direction)\n      [rot-y (- (Math/atan2 (.y direction) (.z direction)))])))\n\n;; TODO: Need to take into account dimmers, and someday be based on raw DMX\n;;       values rather than the current higher-level abstractions.\n(defn active?\n  \"Check whether the given fixture (represented as a tuple of `id` and\n  `spec`, as found in a show's :visualizer-visible map) should be\n  included in the current visualizer frame, because it is emitting\n  light.\"\n  [show [id fixture-or-head]]\n  (when-let [color ((keyword (str \"color-\" id)) (:previous @(:movement show)))]\n    (pos? (colors/lightness color))))\n\n(defn active-fixtures\n  \"Return the fixtures which should currently be rendered, because they\n  are emitting light.\"\n  [show]\n  (filter (partial active? show) (:visualizer-visible @(:dimensions show))))\n\n(defn current-pan-tilts\n  \"Get the current pan and tilt values of the active spotlights for the visualizer.\n  Return as a series of two-element vectors of pan and tilt angles in\n  the perspective of the visualizer, to save space compared to sending actual\n  rotation matrices.\"\n  [lights show]\n  (for [[id head] lights]\n    (let [[pan tilt] ((keyword (str \"pan-tilt-\" id)) (:previous @(:movement show)) [0 0])]\n      (visualizer-pan-tilt head pan tilt))))\n\n(defn byte-to-double\n  \"Convert a one-byte color component, as used in Afterglow, to a\n  floating point color component as used in OpenGL, where 255 becomes\n  1.0.\"\n  [val]\n  (double (/ val 255)))\n\n(defn current-colors\n  \"Get the current color values of the active spotlights for the visualizer.\n  Return as a series of four-element vectors of red, green, blue, and alpha.\"\n  [lights show]\n  (for [[id head] lights]\n    (let [color ((keyword (str \"color-\" id)) (:previous @(:movement show)))]\n      [(byte-to-double (colors/red color)) (byte-to-double (colors/green color))\n       (byte-to-double (colors/blue color)) (byte-to-double (colors/alpha color))])))\n\n(defn page\n  \"Render the real-time show preview.\"\n  [show-id]\n  (let [[show description] (get @show/shows (Integer/valueOf show-id))\n        scale (shader-scale show)\n        lights (take max-lights (active-fixtures show))]\n    (layout/render\n     \"visualizer.html\" {:show show\n                        :timestamp (:timestamp @(:dimensions show))\n                        :count (count lights)\n                        :positions (adjusted-positions lights show scale)\n                        :colors (current-colors lights show)\n                        :rotations (current-pan-tilts lights show)})))\n\n(defn shader\n  \"Render a GLSL shader capable of volumetric rendering of enough\n  lights to accommodate the current show.\"\n  [show-id]\n  (let [[show description] (get @show/shows (Integer/valueOf show-id))\n        scale (shader-scale show)]\n    (layout/render-with-type\n     \"fragment.glsl\" \"x-shader/x-fragment\"\n     {:show show\n      :scale scale\n      :max-lights (min max-lights (count (:visualizer-visible @(:dimensions show))))})))\n\n(defn update-preview\n  \"Render updated lighting information for the preview.\"\n  [show-id]\n  (let [[show description] (get @show/shows (Integer/valueOf show-id))\n        scale (shader-scale show)\n        lights (take max-lights (active-fixtures show))]\n    (layout/render\n     \"current-scene.json\" {:timestamp (:timestamp @(:dimensions show))\n                           :count (count lights)\n                           :positions (adjusted-positions lights show scale)\n                           :colors (current-colors lights show)\n                           :rotations (current-pan-tilts lights show)})))\n"
  },
  {
    "path": "src/afterglow/web/routes/web_repl.clj",
    "content": "(ns afterglow.web.routes.web-repl\n  \"Provides a web interface for interacting with the Clojure environment.\"\n  (:require [afterglow.web.layout :as layout]\n            [clojure.main :as main]\n            [clojure.stacktrace :refer [root-cause]]\n            [ring.middleware.anti-forgery :refer [*anti-forgery-token*]]\n            [ring.util.response :refer [response]]\n            [taoensso.timbre :as timbre]))\n\n(defonce ^{:private true\n           :doc \"Stores thread-local bindings for each web REPL session.\"}\n  repl-sessions (ref {}))\n\n(defn- current-bindings\n  \"Wrap a new layer of bindings around the dynamically bound variables\n  we want to isolate for each web REPL sessions, initializing a few we\n  want to start with clean values.\"\n  []\n  (binding [*ns* *ns*\n            *warn-on-reflection* *warn-on-reflection*\n            *math-context* *math-context*\n            *print-meta* *print-meta*\n            *print-length* *print-length*\n            *print-level* *print-level*\n            *compile-path* (System/getProperty \"clojure.compile.path\" \"classes\")\n            *command-line-args* *command-line-args*\n            *assert* *assert*\n            *1 nil\n            *2 nil\n            *3 nil\n            *e nil]\n    (get-thread-bindings)))\n\n(defn- bindings-for\n  \"Look up the dynamic bindings specific to this web REPL session,\n  creating fresh ones if this is the first time it is being used.\n  Start out in the afterglow.examples namespace.\"\n [session-key]\n  (when-not (@repl-sessions session-key)\n    (require '[afterglow.examples])\n    (binding [*ns* *ns*]\n      (in-ns 'afterglow.examples)\n      (dosync\n       (commute repl-sessions assoc session-key (current-bindings)))))\n  (@repl-sessions session-key))\n\n(defn- store-bindings-for\n  \"Store the dynamic bindings specific to this web REPL session.\"\n [session-key]\n  (dosync\n    (commute repl-sessions assoc session-key (current-bindings))))\n\n(defmacro with-session\n  \"Wrap the body in a session-specific set of dynamic variable\n  bindings.\"\n  [session-key & body]\n  `(with-bindings (bindings-for ~session-key)\n    (let [r# ~@body]\n      (store-bindings-for ~session-key)\n      r#)))\n\n(defn discard-bindings\n  \"Clean up the thread-local bindings stored for a non-web hosted repl\n  session, such as those used by\n  [afterglow-max](https://github.com/Deep-Symmetry/afterglow-max#afterglow-max),\n  which are not automatically timed out. `session-key` is the unique,\n  non-String key used to identify the REPL session to [[do-eval]].\"\n  [session-key]\n  (dosync\n   (commute repl-sessions dissoc session-key)))\n\n(defn do-eval\n  \"Evaluate an expression sent to the web REPL and return the result\n  or an error description. Also supports evaluation of expressions in\n  non-web hosting contexts like\n  [afterglow-max](https://github.com/Deep-Symmetry/afterglow-max#afterglow-max)\n  by passing in a unique non-String value for `session-key`. In such\n  cases the thread local bindings will not be automatically cleaned\n  up, and it is the responsibility of the hosting implementation to\n  call [[discard-bindings]] when they are no longer needed.\"\n  [txt session-key]\n  (with-session session-key\n    (let [form (binding [*read-eval* false] (read-string txt))]\n      (with-open [writer (java.io.StringWriter.)]\n        (binding [*out* writer]\n          (try\n            (let [r (pr-str (eval form))]\n              {:result (str (.toString writer) (str r))})\n            (catch Throwable t\n              {:error (str (root-cause t))})))))))\n\n(defn handle-command\n  \"Route which processes a command typed into the web console.\"\n  [req]\n  (let [session-key (get-in req [:cookies \"ring-session\" :value])\n        command (get-in req [:params :command])]\n    (response (do-eval command session-key))))\n\n(defn page\n  \"Route which renders the web console interface.\"\n  []\n  (layout/render \"console.html\" {:csrf-token *anti-forgery-token*}))\n\n(defn- still-needed?\n  \"Returns true if the bindings have a key that either refers to a\n  non-expired web session, or is not a String, which means that it\n  does not come from a web session at all, but rather a hosting\n  environment like\n  [afterglow-max](https://github.com/Deep-Symmetry/afterglow-max#afterglow-max),\n  which does not expire.\"\n  [web-sessions [id _]]\n  (or (not (string? id))\n      (some? (web-sessions id))))\n\n(defn clean-expired-bindings\n  \"Clean out the dynamic variable bindings stored for web sessions\n  which have expired. Ignores bindings whose keys are not strings,\n  because they do not come from web sessions, but from hosting\n  environments like\n  [afterglow-max](https://github.com/Deep-Symmetry/afterglow-max#afterglow-max)\n  which do not expire.\"\n  [web-sessions]\n  (dosync\n   (commute repl-sessions #(->> % (filter (partial still-needed? web-sessions)) (into {})))))\n"
  },
  {
    "path": "src/afterglow/web/session.clj",
    "content": "(ns afterglow.web.session\n  \"Manages the session store for Afterglow's web interface\"\n  (:require [afterglow.web.routes.web-repl :as web-repl]))\n\n(defonce ^{:doc \"The session store\"}\n  mem (atom {}))\n\n(def half-hour\n  \"How often expired sessions should be purged.\"\n  1800000)\n\n(defn- current-time\n  \"Gets the current time, in seconds, which is how Ring expresses\n  session timeouts.\"\n  []\n  (quot (System/currentTimeMillis) 1000))\n\n(defn- not-yet-expired?\n  \"Returns true if the session's expiration time still lies in the\n  future.\"\n  [[id session]]\n  (pos? (- (:ring.middleware.session-timeout/idle-timeout session) (current-time))))\n\n(defn clear-expired-sessions\n  \"Removes any session entries for sessions whose expiration time has\n  arrived.\"\n  []\n  (swap! mem #(->> % (filter not-yet-expired?) (into {}))))\n\n(defn start-cleanup-job!\n  \"Creates a background thread which cleans out expired sessions every\n  half hour.\"\n  []\n  (future\n    (loop []\n      (clear-expired-sessions)\n      (web-repl/clean-expired-bindings @mem)\n      (Thread/sleep half-hour)\n      (recur))))\n"
  },
  {
    "path": "test/afterglow/core_test.clj",
    "content": "(ns afterglow.core-test\n  (:require [clojure.test :refer :all]\n            [afterglow.core :refer :all]))\n\n(deftest a-test\n  (testing \"FIXME, I fail to test anything useful.\"\n    (is (= 1 1))))\n"
  },
  {
    "path": "test/afterglow/effects/color_test.clj",
    "content": "(ns afterglow.effects.color-test\n  (:require [clojure.test :refer :all]\n            [afterglow.effects.color :refer :all]\n            [afterglow.channels :as channels]\n            [com.evocomputing.colors :as colors]\n            [afterglow.fixtures.chauvet :as chauvet]\n            [taoensso.timbre :as timbre :refer [error warn info debug spy]]))\n\n(deftest test-extract-rgb\n  (testing \"Finding RGB color channels\")\n  (is (= [:12-channel] (map :mode (channels/find-rgb-heads [(chauvet/slimpar-hex3-irc)])))))\n"
  },
  {
    "path": "test/afterglow/effects_test.clj",
    "content": "(ns afterglow.effects-test\n  (:require [clojure.test :refer :all]\n            [afterglow.effects :refer :all]\n            [afterglow.effects.params :as params]\n            [afterglow.fixtures.blizzard :as blizzard]\n            [afterglow.show :as show]\n            [afterglow.show-context :refer [with-show]]\n            [afterglow.rhythm :as rhythm]\n            [afterglow.transform :as tf]\n            [afterglow.util :as util]\n            [com.evocomputing.colors :as colors])\n  (:import [javax.vecmath Point3d Vector3d]\n           [afterglow.rhythm MetronomeSnapshot]))\n\n(defonce test-show (atom nil))\n(defonce test-snapshot (atom nil))\n\n(defn effects-fixture\n  \"Set up a show and snapshot for the duration of the tests.\"\n  [f]\n  (reset! test-show (show/show))\n  (reset! test-snapshot (rhythm/metro-snapshot (:metronome @test-show)))\n  (with-show @test-show\n    (show/patch-fixture! :torrent-1 (blizzard/torrent-f3) 1 1\n                         :x (tf/inches 44) :y (tf/inches 51.75) :z (tf/inches -4.75)\n                         :y-rotation (tf/degrees 0))\n    (f))\n  (reset! test-snapshot nil)\n  (reset! test-show nil))\n\n(use-fixtures :once effects-fixture)\n\n(deftest test-validations\n  (testing \"Assigners must have compatible types and target IDs\"\n    (let [base (->Assignment :fnord :xyz {:some \"target values\"} 10)]\n      (is (= base (fade-assignment base base 0 @test-show @test-snapshot)))\n      (is (thrown? AssertionError (fade-assignment base (merge base {:kind :boom}) 0 @test-show @test-snapshot)))\n      (is (thrown? AssertionError (fade-assignment base (merge base {:target-id :pdq}) 0 @test-show @test-snapshot))))))\n\n(deftest test-fade-unknown-type\n  (testing \"Fading an unrecognized assigner flips the value at midpoint\"\n    (let [from (->Assignment :fnord :xyz {:some \"target values\"} 10)\n          to (->Assignment :fnord :xyz {:some \"target values\"} 42)]\n      (is (= from (fade-assignment from to 0 @test-show @test-snapshot)))\n      (is (= to (fade-assignment from to 1 @test-show @test-snapshot)))\n      (is (= from (fade-assignment from to -1 @test-show @test-snapshot)))\n      (is (= to (fade-assignment from to 10 @test-show @test-snapshot)))\n      (is (= from (fade-assignment from to 0.4 @test-show @test-snapshot)))\n      (is (= to (fade-assignment from to 0.6 @test-show @test-snapshot)))\n      (is (= to (fade-assignment from to 0.5 @test-show @test-snapshot)))\n      (is (= from (fade-assignment from nil 0.3 @test-show @test-snapshot)))\n      (is (= to (fade-assignment nil to 0.7 @test-show @test-snapshot)))\n      (is (nil? (:value (fade-assignment from nil 0.9 @test-show @test-snapshot))))\n      (is (= :fnord (:kind (fade-assignment from nil 0.9 @test-show @test-snapshot))))\n      (is (nil? (:value (fade-assignment nil to 0.02 @test-show @test-snapshot))))\n      (is (= :fnord (:kind (fade-assignment nil to 0.02 @test-show @test-snapshot))))\n      (is (nil? (fade-assignment nil nil 0.2 @test-show @test-snapshot))))))\n\n(deftest test-fade-channel\n  (testing \"Fading a channel assigner scales the value\"\n    (let [from (->Assignment :channel :u1a3 {:some \"target values\"} 10)\n          to (->Assignment :channel :u1a3 {:some \"target values\"} 20)\n          too-big (->Assignment :channel :u1a3 {:some \"target values\"} 420)\n          too-small (->Assignment :channel :u1a3 {:some \"target values\"} -20)]\n      (is (= from (fade-assignment from to 0 @test-show @test-snapshot)))\n      (is (= to (fade-assignment from to 1 @test-show @test-snapshot)))\n      (is (= from (fade-assignment from to -1 @test-show @test-snapshot)))\n      (is (= to (fade-assignment from to 10 @test-show @test-snapshot)))\n      (is (util/float= 14.0 (:value (fade-assignment from to 0.4 @test-show @test-snapshot))))\n      (is (util/float= 16.0 (:value (fade-assignment from to 0.6 @test-show @test-snapshot))))\n      (is (util/float= 15.0 (:value (fade-assignment from to 0.5 @test-show @test-snapshot))))\n      (is (util/float= 132.5 (:value (fade-assignment from too-big 0.5 @test-show @test-snapshot))))\n      (is (util/float= 5.0 (:value (fade-assignment from too-small 0.5 @test-show @test-snapshot))))\n      (is (util/float= 7.0 (:value (fade-assignment from nil 0.3 @test-show @test-snapshot))))\n      (is (util/float= 14.0 (:value (fade-assignment nil to 0.7 @test-show @test-snapshot))))\n      (is (util/float= 1.0 (:value (fade-assignment from nil 0.9 @test-show @test-snapshot))))\n      (is (= :channel (:kind (fade-assignment from nil 0.9 @test-show @test-snapshot))))\n      (is (util/float= 0.4 (:value (fade-assignment nil to 0.02 @test-show @test-snapshot))))\n      (is (= :channel (:kind (fade-assignment nil to 0.02 @test-show @test-snapshot)))))))\n\n(deftest test-fade-function\n  (testing \"Fading a function assigner scales the value only if active on both sides\"\n    (let [from (->Assignment :function :3-strobe {:some \"target values\"} 10)\n          to (->Assignment :function :3-strobe {:some \"target values\"} 20)\n          too-big (->Assignment :function :3-strobe {:some \"target values\"} 120)\n          too-small (->Assignment :function :3-strobe {:some \"target values\"} -20)]\n      (is (= from (fade-assignment from to 0 @test-show @test-snapshot)))\n      (is (= to (fade-assignment from to 1 @test-show @test-snapshot)))\n      (is (= from (fade-assignment from to -1 @test-show @test-snapshot)))\n      (is (= to (fade-assignment from to 10 @test-show @test-snapshot)))\n      (is (util/float= 14.0 (:value (fade-assignment from to 0.4 @test-show @test-snapshot))))\n      (is (util/float= 16.0 (:value (fade-assignment from to 0.6 @test-show @test-snapshot))))\n      (is (util/float= 15.0 (:value (fade-assignment from to 0.5 @test-show @test-snapshot))))\n      (is (util/float= 55.0 (:value (fade-assignment from too-big 0.5 @test-show @test-snapshot))))\n      (is (util/float= 5.0 (:value (fade-assignment from too-small 0.5 @test-show @test-snapshot))))\n      (is (util/float= 10.0 (:value (fade-assignment from nil 0.3 @test-show @test-snapshot))))\n      (is (util/float= 20.0 (:value (fade-assignment nil to 0.7 @test-show @test-snapshot))))\n      (is (nil? (:value (fade-assignment from nil 0.9 @test-show @test-snapshot))))\n      (is (= :function (:kind (fade-assignment from nil 0.9 @test-show @test-snapshot))))\n      (is (nil? (:value (fade-assignment nil to 0.02 @test-show @test-snapshot))))\n      (is (= :function (:kind (fade-assignment nil to 0.02 @test-show @test-snapshot)))))))\n\n(deftest test-fade-color\n  (testing \"Fading a color assigner blends the colors\"\n    (let [red (->Assignment :color :i42 {:some \"target values\"} (colors/create-color :red))\n          green (->Assignment :color :i42 {:some \"target values\"} (colors/create-color :green))\n          white (->Assignment :color :i42 {:some \"target values\"} (colors/create-color :white))]\n      (is (= red (fade-assignment red green 0 @test-show @test-snapshot)))\n      (is (= green (fade-assignment red green 1 @test-show @test-snapshot)))\n      (is (= red (fade-assignment red green -1 @test-show @test-snapshot)))\n      (is (= green (fade-assignment red green 10 @test-show @test-snapshot)))\n      (is (util/float= 60.0 (colors/hue (:value (fade-assignment red green 0.5 @test-show @test-snapshot)))))\n      (is (util/float= 50 (colors/lightness (:value (fade-assignment red green 0.5 @test-show @test-snapshot)))))\n      (is (util/float= 100 (colors/saturation (:value (fade-assignment red green 0.5 @test-show @test-snapshot)))))\n      (is (util/float= 30.0 (colors/hue (:value (fade-assignment red green 0.25 @test-show @test-snapshot)))))\n      (is (util/float= 90 (colors/hue (:value (fade-assignment red green 0.75 @test-show @test-snapshot)))))\n      (is (util/float= 0.0 (colors/hue (:value (fade-assignment red white 0.5 @test-show @test-snapshot)))))\n      (is (util/float= 75.0 (colors/lightness (:value (fade-assignment red white 0.5 @test-show @test-snapshot)))))\n      (is (util/float= 0.0 (colors/hue (:value (fade-assignment red nil 0.9 @test-show @test-snapshot)))))\n      (is (util/float= 5.0 (colors/lightness (:value (fade-assignment red nil 0.9 @test-show @test-snapshot)))))\n      (is (util/float= 120 (colors/hue (:value (fade-assignment nil green 0.02 @test-show @test-snapshot)))))\n      (is (util/float= 1.0 (colors/lightness (:value (fade-assignment nil green 0.02 @test-show @test-snapshot))))))))\n\n(deftest test-fade-direction\n  (testing \"Fading a direction assigner moves between the directions\"\n    (let [fixture (first (show/fixtures-named :torrent-1))\n          from (->Assignment :direction :i13 fixture (Vector3d. -1.0 1.0 0.0))\n          to (->Assignment :direction :i13 fixture (Vector3d. 1.0 1.0 0.0))]\n      (is (= from (fade-assignment from to 0 @test-show @test-snapshot)))\n      (is (= to (fade-assignment from to 1 @test-show @test-snapshot)))\n      (is (= from (fade-assignment from to -1 @test-show @test-snapshot)))\n      (is (= to (fade-assignment from to 10 @test-show @test-snapshot)))\n      (is (= (Vector3d. -0.196116135138184, 0.9805806756909201, 0.0)\n             (:value (fade-assignment from to 0.4 @test-show @test-snapshot))))\n      (is (= (Vector3d. 0.196116135138184, 0.9805806756909201, 0.0)\n             (:value (fade-assignment from to 0.6 @test-show @test-snapshot))))\n      (is (= (Vector3d. 0.0, 1.0, 0.0)\n             (:value (fade-assignment from to 0.5 @test-show @test-snapshot))))\n      (is (= (Vector3d. -0.679071744760261, 0.6739354942419622, -0.2909854207157071)\n             (:value (fade-assignment from nil 0.3 @test-show @test-snapshot))))\n      (is (= (Vector3d. 0.679071744760261, 0.6739354942419622, -0.29098542071570715)\n             (:value (fade-assignment nil to 0.7 @test-show @test-snapshot))))\n      (is (= (Vector3d. -0.10997491972977708, 0.09250690755105184, -0.9896201236261165)\n             (:value (fade-assignment from nil 0.9 @test-show @test-snapshot))))\n      (is (= :direction (:kind (fade-assignment from nil 0.9 @test-show @test-snapshot))))\n      (is (= (Vector3d. 0.020407013973550377, 0.002759527209833684, -0.9997879469118747)\n             (:value (fade-assignment nil to 0.02 @test-show @test-snapshot))))\n      (is (= :direction (:kind (fade-assignment nil to 0.02 @test-show @test-snapshot)))))))\n\n(deftest test-fade-aim\n  (testing \"Fading an aim assigner moves between the aim points\"\n    (let [fixture (first (show/fixtures-named :torrent-1))\n          from (->Assignment :aim :i13 fixture (Vector3d. -1.0 4.0 1.0))\n          to (->Assignment :aim :i13 fixture (Vector3d. 1.0 2.0 2.0))]\n      (is (= from (fade-assignment from to 0 @test-show @test-snapshot)))\n      (is (= to (fade-assignment from to 1 @test-show @test-snapshot)))\n      (is (= from (fade-assignment from to -1 @test-show @test-snapshot)))\n      (is (= to (fade-assignment from to 10 @test-show @test-snapshot)))\n      (is (= (Point3d. -0.19999999999999996, 3.2, 1.4)\n             (:value (fade-assignment from to 0.4 @test-show @test-snapshot))))\n      (is (= (Point3d. 0.19999999999999996, 2.8, 1.6)\n             (:value (fade-assignment from to 0.6 @test-show @test-snapshot))))\n      (is (= (Point3d. 0.0, 3.0, 1.5)\n             (:value (fade-assignment from to 0.5 @test-show @test-snapshot))))\n      (is (= (Point3d. -0.36471999999999993, 3.1890404558070613, 0.36385172396890036)\n             (:value (fade-assignment from nil 0.3 @test-show @test-snapshot))))\n      (is (= (Point3d. 1.03528, 1.7890404558070614, 1.0638517239689003)\n             (:value (fade-assignment nil to 0.7 @test-show @test-snapshot))))\n      (is (= (Point3d. 0.9058400000000001, 1.5671213674211841, -0.9084448280932987)\n             (:value (fade-assignment from nil 0.9 @test-show @test-snapshot))))\n      (is (= :aim (:kind (fade-assignment from nil 0.9 @test-show @test-snapshot))))\n      (is (= (Point3d. 1.1152480000000002, 1.310865488969734, -1.0580843683682586)\n             (:value (fade-assignment nil to 0.02 @test-show @test-snapshot))))\n      (is (= :aim (:kind (fade-assignment nil to 0.02 @test-show @test-snapshot)))))))\n\n(defn build-test-snapshot\n  \"Creates a metronome snapshot representing the specified number of\n  milliseconds after the supplied metrome was started.\"\n  [metro offset]\n  (let [snap (rhythm/metro-snapshot metro)\n        start (:start snap)\n        instant (+ start offset)\n        beat (rhythm/marker-number instant start (rhythm/metro-tick metro))\n        bar (rhythm/marker-number instant start (rhythm/metro-tock metro))\n        phrase (rhythm/marker-number instant start (rhythm/metro-ding metro))\n        beat-phase (rhythm/marker-phase instant start (rhythm/metro-tick metro))\n        bar-phase (rhythm/marker-phase instant start (rhythm/metro-tock metro))\n        phrase-phase (rhythm/marker-phase instant start (rhythm/metro-ding metro))]\n    (MetronomeSnapshot. start (:bpm snap) (:bpb snap) (:bpp snap)\n                        instant beat bar phrase beat-phase bar-phase phrase-phase)))\n\n(defn build-beat-snapshot\n  \"Create a snapshot that represents the specified number of beats after\n  the creation of the supplied metronome.\"\n  [metro beats]\n  (build-test-snapshot metro (* beats (rhythm/metro-tick metro))))\n\n(defn build-bar-snapshot\n  \"Create a snapshot that represents the specified number of bars after\n  the creation of the supplied metronome.\"\n  [metro bars]\n  (build-test-snapshot metro (* bars (rhythm/metro-tock metro))))\n\n(defn build-phrase-snapshot\n  \"Create a snapshot that represents the specified number of phrases\n  after the creation of the supplied metronome.\"\n  [metro phrases]\n  (build-test-snapshot metro (* phrases (rhythm/metro-ding metro))))\n\n(deftest test-beat-step-param\n  (testing \"Step parameters based on beats behave as expected.\"\n    (let [metro (:metronome @test-show)\n          basic-51 (params/build-step-param :starting (build-beat-snapshot metro 51))\n          smooth-99 (params/build-step-param :fade-fraction 1 :starting (build-beat-snapshot metro 99))\n          half-12 (params/build-step-param :fade-fraction 0.5 :starting (build-beat-snapshot metro 12))\n          fifth-12 (params/build-step-param :fade-fraction 0.2 :starting (build-beat-snapshot metro 12))]\n\n      ;; Basic step function starting with beat 51.\n      (is (= 1 (params/evaluate basic-51 @test-show (build-beat-snapshot metro 51) nil)))\n      (is (= 2 (params/evaluate basic-51 @test-show (build-beat-snapshot metro 52) nil)))\n      (is (= 0 (params/evaluate basic-51 @test-show (build-beat-snapshot metro 50) nil)))\n      (is (= -1 (params/evaluate basic-51 @test-show (build-beat-snapshot metro 49) nil)))\n      (is (= 1 (params/evaluate basic-51 @test-show (build-beat-snapshot metro 51.4) nil)))\n      (is (= 1 (params/evaluate basic-51 @test-show (build-beat-snapshot metro 51.9) nil)))\n      (is (= 100 (params/evaluate basic-51 @test-show (build-beat-snapshot metro 150) nil)))\n\n      ;; Continuous fade starting with beat 98\n      (is (util/float= 0.5 (params/evaluate smooth-99 @test-show (build-beat-snapshot metro 99) nil)))\n      (is (util/float= 1 (params/evaluate smooth-99 @test-show (build-beat-snapshot metro 99.5) nil)))\n      (is (util/float= 1.5 (params/evaluate smooth-99 @test-show (build-beat-snapshot metro 100) nil)))\n      (is (util/float= 2 (params/evaluate smooth-99 @test-show (build-beat-snapshot metro 100.5) nil)))\n      (is (util/float= -0.5 (params/evaluate smooth-99 @test-show (build-beat-snapshot metro 98) nil)))\n      (is (util/float= -1 (params/evaluate smooth-99 @test-show (build-beat-snapshot metro 97.5) nil)))\n      (is (util/float= -1.5 (params/evaluate smooth-99 @test-show (build-beat-snapshot metro 97) nil)))\n      (is (util/float= 0.9 (params/evaluate smooth-99 @test-show (build-beat-snapshot metro 99.4) nil)))\n      (is (util/float= 1.4 (params/evaluate smooth-99 @test-show (build-beat-snapshot metro 99.9) nil)))\n      (is (util/float= 100 (params/evaluate smooth-99 @test-show (build-beat-snapshot metro 198.5) nil)))\n\n      ;; Fade for half of each beat starting with beat 12\n      (is (util/float= 0.5 (params/evaluate half-12 @test-show (build-beat-snapshot metro 12) nil)))\n      (is (util/float= 1 (params/evaluate half-12 @test-show (build-beat-snapshot metro 12.5) nil)))\n      (is (util/float= 1.5 (params/evaluate half-12 @test-show (build-beat-snapshot metro 13) nil)))\n      (is (util/float= 2 (params/evaluate half-12 @test-show (build-beat-snapshot metro 13.5) nil)))\n      (is (util/float= -0.5 (params/evaluate half-12 @test-show (build-beat-snapshot metro 11) nil)))\n      (is (util/float= -1 (params/evaluate half-12 @test-show (build-beat-snapshot metro 10.5) nil)))\n      (is (util/float= -1.5 (params/evaluate half-12 @test-show (build-beat-snapshot metro 10) nil)))\n      (is (util/float= 1 (params/evaluate half-12 @test-show (build-beat-snapshot metro 12.4) nil)))\n      (is (util/float= 1.3 (params/evaluate half-12 @test-show (build-beat-snapshot metro 12.9) nil)))\n      (is (util/float= 1.98 (params/evaluate half-12 @test-show (build-beat-snapshot metro 13.24) nil)))\n      (is (util/float= 2 (params/evaluate half-12 @test-show (build-beat-snapshot metro 13.25) nil)))\n      (is (util/float= 101 (params/evaluate half-12 @test-show (build-beat-snapshot metro 112.4) nil)))\n      (is (util/float= 102 (params/evaluate half-12 @test-show (build-beat-snapshot metro 113.75) nil)))\n\n      ;; Fade for 1/5 of each beat starting with beat 12\n      (is (util/float= 0.5 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 12) nil)))\n      (is (util/float= 1 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 12.5) nil)))\n      (is (util/float= 1.5 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 13) nil)))\n      (is (util/float= 2 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 13.5) nil)))\n      (is (util/float= -0.5 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 11) nil)))\n      (is (util/float= -1 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 10.5) nil)))\n      (is (util/float= -1.5 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 10) nil)))\n      (is (util/float= 1 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 12.4) nil)))\n      (is (util/float= 1.25 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 12.95) nil)))\n      (is (util/float= 1.95 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 13.09) nil)))\n      (is (util/float= 2 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 13.1) nil)))\n      (is (util/float= 101 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 112.2) nil)))\n      (is (util/float= 102 (params/evaluate fifth-12 @test-show (build-beat-snapshot metro 113.9) nil))))))\n\n(deftest test-bar-step-param\n  (testing \"Step parameters based on bars behave as expected.\"\n    (let [metro (:metronome @test-show)\n          basic-51 (params/build-step-param :interval :bar :starting (build-bar-snapshot metro 51))\n          smooth-99 (params/build-step-param :interval :bar :fade-fraction 1 :starting (build-bar-snapshot metro 99))\n          half-12 (params/build-step-param :interval :bar :fade-fraction 0.5 :starting (build-bar-snapshot metro 12))\n          fifth-12 (params/build-step-param :interval :bar :fade-fraction 0.2 :starting (build-bar-snapshot metro 12))]\n\n      ;; Basic step function starting with bar 51.\n      (is (= 1 (params/evaluate basic-51 @test-show (build-bar-snapshot metro 51) nil)))\n      (is (= 2 (params/evaluate basic-51 @test-show (build-bar-snapshot metro 52) nil)))\n      (is (= 0 (params/evaluate basic-51 @test-show (build-bar-snapshot metro 50) nil)))\n      (is (= -1 (params/evaluate basic-51 @test-show (build-bar-snapshot metro 49) nil)))\n      (is (= 1 (params/evaluate basic-51 @test-show (build-bar-snapshot metro 51.4) nil)))\n      (is (= 1 (params/evaluate basic-51 @test-show (build-bar-snapshot metro 51.9) nil)))\n      (is (= 100 (params/evaluate basic-51 @test-show (build-bar-snapshot metro 150) nil)))\n\n      ;; Continuous fade starting with bar 98\n      (is (util/float= 0.5 (params/evaluate smooth-99 @test-show (build-bar-snapshot metro 99) nil)))\n      (is (util/float= 1 (params/evaluate smooth-99 @test-show (build-bar-snapshot metro 99.5) nil)))\n      (is (util/float= 1.5 (params/evaluate smooth-99 @test-show (build-bar-snapshot metro 100) nil)))\n      (is (util/float= 2 (params/evaluate smooth-99 @test-show (build-bar-snapshot metro 100.5) nil)))\n      (is (util/float= -0.5 (params/evaluate smooth-99 @test-show (build-bar-snapshot metro 98) nil)))\n      (is (util/float= -1 (params/evaluate smooth-99 @test-show (build-bar-snapshot metro 97.5) nil)))\n      (is (util/float= -1.5 (params/evaluate smooth-99 @test-show (build-bar-snapshot metro 97) nil)))\n      (is (util/float= 0.9 (params/evaluate smooth-99 @test-show (build-bar-snapshot metro 99.4) nil)))\n      (is (util/float= 1.4 (params/evaluate smooth-99 @test-show (build-bar-snapshot metro 99.9) nil)))\n      (is (util/float= 100 (params/evaluate smooth-99 @test-show (build-bar-snapshot metro 198.5) nil)))\n\n      ;; Fade for half of each bar starting with bar 12\n      (is (util/float= 0.5 (params/evaluate half-12 @test-show (build-bar-snapshot metro 12) nil)))\n      (is (util/float= 1 (params/evaluate half-12 @test-show (build-bar-snapshot metro 12.5) nil)))\n      (is (util/float= 1.5 (params/evaluate half-12 @test-show (build-bar-snapshot metro 13) nil)))\n      (is (util/float= 2 (params/evaluate half-12 @test-show (build-bar-snapshot metro 13.5) nil)))\n      (is (util/float= -0.5 (params/evaluate half-12 @test-show (build-bar-snapshot metro 11) nil)))\n      (is (util/float= -1 (params/evaluate half-12 @test-show (build-bar-snapshot metro 10.5) nil)))\n      (is (util/float= -1.5 (params/evaluate half-12 @test-show (build-bar-snapshot metro 10) nil)))\n      (is (util/float= 1 (params/evaluate half-12 @test-show (build-bar-snapshot metro 12.4) nil)))\n      (is (util/float= 1.3 (params/evaluate half-12 @test-show (build-bar-snapshot metro 12.9) nil)))\n      (is (util/float= 1.98 (params/evaluate half-12 @test-show (build-bar-snapshot metro 13.24) nil)))\n      (is (util/float= 2 (params/evaluate half-12 @test-show (build-bar-snapshot metro 13.25) nil)))\n      (is (util/float= 101 (params/evaluate half-12 @test-show (build-bar-snapshot metro 112.4) nil)))\n      (is (util/float= 102 (params/evaluate half-12 @test-show (build-bar-snapshot metro 113.75) nil)))\n\n      ;; Fade for 1/5 of each bar starting with bar 12\n      (is (util/float= 0.5 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 12) nil)))\n      (is (util/float= 1 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 12.5) nil)))\n      (is (util/float= 1.5 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 13) nil)))\n      (is (util/float= 2 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 13.5) nil)))\n      (is (util/float= -0.5 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 11) nil)))\n      (is (util/float= -1 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 10.5) nil)))\n      (is (util/float= -1.5 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 10) nil)))\n      (is (util/float= 1 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 12.4) nil)))\n      (is (util/float= 1.25 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 12.95) nil)))\n      (is (util/float= 1.95 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 13.09) nil)))\n      (is (util/float= 2 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 13.1) nil)))\n      (is (util/float= 101 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 112.2) nil)))\n      (is (util/float= 102 (params/evaluate fifth-12 @test-show (build-bar-snapshot metro 113.9) nil))))))\n\n(deftest test-phrase-step-param\n  (testing \"Step parameters based on phrases behave as expected.\"\n    (let [metro (:metronome @test-show)\n          basic-51 (params/build-step-param :interval :phrase :starting (build-phrase-snapshot metro 51))\n          smooth-99 (params/build-step-param :interval :phrase :fade-fraction 1\n                                             :starting (build-phrase-snapshot metro 99))\n          half-12 (params/build-step-param :interval :phrase :fade-fraction 0.5\n                                           :starting (build-phrase-snapshot metro 12))\n          fifth-12 (params/build-step-param :interval :phrase :fade-fraction 0.2\n                                            :starting (build-phrase-snapshot metro 12))]\n\n      ;; Basic step function starting with phrase 51.\n      (is (= 1 (params/evaluate basic-51 @test-show (build-phrase-snapshot metro 51) nil)))\n      (is (= 2 (params/evaluate basic-51 @test-show (build-phrase-snapshot metro 52) nil)))\n      (is (= 0 (params/evaluate basic-51 @test-show (build-phrase-snapshot metro 50) nil)))\n      (is (= -1 (params/evaluate basic-51 @test-show (build-phrase-snapshot metro 49) nil)))\n      (is (= 1 (params/evaluate basic-51 @test-show (build-phrase-snapshot metro 51.4) nil)))\n      (is (= 1 (params/evaluate basic-51 @test-show (build-phrase-snapshot metro 51.9) nil)))\n      (is (= 100 (params/evaluate basic-51 @test-show (build-phrase-snapshot metro 150) nil)))\n\n      ;; Continuous fade starting with phrase 98\n      (is (util/float= 0.5 (params/evaluate smooth-99 @test-show (build-phrase-snapshot metro 99) nil)))\n      (is (util/float= 1 (params/evaluate smooth-99 @test-show (build-phrase-snapshot metro 99.5) nil)))\n      (is (util/float= 1.5 (params/evaluate smooth-99 @test-show (build-phrase-snapshot metro 100) nil)))\n      (is (util/float= 2 (params/evaluate smooth-99 @test-show (build-phrase-snapshot metro 100.5) nil)))\n      (is (util/float= -0.5 (params/evaluate smooth-99 @test-show (build-phrase-snapshot metro 98) nil)))\n      (is (util/float= -1 (params/evaluate smooth-99 @test-show (build-phrase-snapshot metro 97.5) nil)))\n      (is (util/float= -1.5 (params/evaluate smooth-99 @test-show (build-phrase-snapshot metro 97) nil)))\n      (is (util/float= 0.9 (params/evaluate smooth-99 @test-show (build-phrase-snapshot metro 99.4) nil)))\n      (is (util/float= 1.4 (params/evaluate smooth-99 @test-show (build-phrase-snapshot metro 99.9) nil)))\n      (is (util/float= 100 (params/evaluate smooth-99 @test-show (build-phrase-snapshot metro 198.5) nil)))\n\n      ;; Fade for half of each phrase starting with phrase 12\n      (is (util/float= 0.5 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 12) nil)))\n      (is (util/float= 1 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 12.5) nil)))\n      (is (util/float= 1.5 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 13) nil)))\n      (is (util/float= 2 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 13.5) nil)))\n      (is (util/float= -0.5 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 11) nil)))\n      (is (util/float= -1 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 10.5) nil)))\n      (is (util/float= -1.5 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 10) nil)))\n      (is (util/float= 1 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 12.4) nil)))\n      (is (util/float= 1.3 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 12.9) nil)))\n      (is (util/float= 1.98 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 13.24) nil)))\n      (is (util/float= 2 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 13.25) nil)))\n      (is (util/float= 101 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 112.4) nil)))\n      (is (util/float= 102 (params/evaluate half-12 @test-show (build-phrase-snapshot metro 113.75) nil)))\n\n      ;; Fade for 1/5 of each phrase starting with phrase 12\n      (is (util/float= 0.5 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 12) nil)))\n      (is (util/float= 1 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 12.5) nil)))\n      (is (util/float= 1.5 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 13) nil)))\n      (is (util/float= 2 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 13.5) nil)))\n      (is (util/float= -0.5 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 11) nil)))\n      (is (util/float= -1 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 10.5) nil)))\n      (is (util/float= -1.5 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 10) nil)))\n      (is (util/float= 1 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 12.4) nil)))\n      (is (util/float= 1.25 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 12.95) nil)))\n      (is (util/float= 1.95 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 13.09) nil)))\n      (is (util/float= 2 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 13.1) nil)))\n      (is (util/float= 101 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 112.2) nil)))\n      (is (util/float= 102 (params/evaluate fifth-12 @test-show (build-phrase-snapshot metro 113.9) nil))))))\n"
  }
]