Swagger2-0.73/000755 000765 000024 00000000000 12660346320 014275 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/.perltidyrc000644 000765 000024 00000000720 12645123651 016461 0ustar00jhthorsenstaff000000 000000 -pbp # Start with Perl Best Practices -w # Show all warnings -iob # Ignore old breakpoints -l=120 # 120 characters per line -mbl=2 # No more than 2 blank lines -i=2 # Indentation is 2 columns -ci=2 # Continuation indentation is 2 columns -vt=0 # Less vertical tightness -pt=2 # High parenthesis tightness -bt=2 # High brace tightness -sbt=2 # High square bracket tightness -isbc # Don't indent comments without leading space Swagger2-0.73/.ship.conf000644 000765 000024 00000000470 12645123651 016171 0ustar00jhthorsenstaff000000 000000 # Generated by git-ship. See 'git-ship --man' for help or https://github.com/jhthorsen/app-git-ship class = App::git::ship::perl project_name = homepage = https://github.com/jhthorsen/swagger2 bugtracker = https://github.com/jhthorsen/swagger2/issues license = artistic_2 build_test_options = # Example: -l -j8 Swagger2-0.73/.travis.yml000644 000765 000024 00000000507 12645123651 016413 0ustar00jhthorsenstaff000000 000000 language: perl perl: - "5.20" - "5.16" - "5.10" env: - "HARNESS_OPTIONS=j6" install: - "cpanm -n Test::Pod Test::Pod::Coverage Data::Validate::Domain Data::Validate::IP YAML" - "cpanm -n https://github.com/jhthorsen/json-validator/archive/master.tar.gz" - "cpanm -n --installdeps ." notifications: email: false Swagger2-0.73/Changes000644 000765 000024 00000025077 12660346317 015611 0ustar00jhthorsenstaff000000 000000 Revision history for perl distribution Swagger2 0.73 2016-02-15T14:04:15+0100 - Fix "0" as placeholder value #74 Contributor: Le Garff Yoann 0.72 2016-02-12T11:30:05+0100 - Fix rendering Swagger spec cannot contain "id" and "x-mojo-xxx" - Fix rendering Swagger spec with requested host in response. - Made the code less confusing by removing the /o regex modifier #71 Contributor: Daniel Böhmer 0.71 2016-02-08T21:29:57+0100 - Bundle EXPERIMENTAL swagger2-client.js - Fix spelling error #70 Contributor: Lucas Kanashiro 0.70 2016-01-29T10:50:57+0100 - Documentation fixes Contributor: Bernhard Graf - Remove outdated warning #69 Contributor: Denny de la Haye 0.69 2016-01-14T22:01:15+0100 - Allow blocking Swagger2::Client requests to return on failure #67 0.68 2016-01-13T16:36:28+0100 - Can serve specification from basePath - Fix skipping tests on MSWin32 #66 Contributor: Paul Durden 0.67 2016-01-12T14:36:24+0100 - Add "basePath" to "Add route ..." debug message #64 - Can pass Swagger2->new to Swagger2::Client #63 - Fix new(url => Mojo::URL->new(...)); - Fix expand() will not clear url() 0.66 2015-12-29T11:52:06+0100 - Will not add non-existing input keys to $args #52 Contributor: Scott Wiersdorf - Use $c->match instead of $c->stash to get placeholder data - Add "From" to list of ignored words in SKIP_OP_RE #54 - Allow more complex method name detection from operationId #55 - Skipping editor test on Win32 #56 - Boolean in headers will be the strings "true" and "false" #58 0.65 2015-12-03T12:51:51+0100 - Swagger2::Client will generate both camel- and snake case methods - Swagger2::Client pass $err as a string to callback - Swagger2::Editor can save specification back to disk on POST 0.64 2015-11-28T08:18:45+0100 - YAML::Tiny is no longer supported by JSON::Validator - Bump JSON::Validator dependency to 0.63 0.63 2015-11-19T09:22:44+0100 - Add validation of output headers, fixes #41 - Add support for "readOnly" in object properties #49 0.62 2015-11-04T12:42:32+0000 - Trying to authorise release 0.61 2015-11-03T20:22:55+0000 - Fix handling of empty collectionFormat value - Fix handling of arrays in request body - Add validation for 204 No Content response 0.60 2015-10-14T23:25:14+0200 - Fix pass on $app to WebSocket controller - Fix support for "collectionFormat" for both "parameters" and "items" - Add support for "collectionFormat" "multi" 0.59 2015-10-11T13:22:31+0200 - Fix validating required body - Add resource to download full API spec - Add before_render hook to make sure we reply with JSON - Add EXPERIMENTAL dispatch_to_swagger() 0.58 2015-10-06T11:36:29+0200 - Add support for using operationId instead of x-mojo-controller #36 #37 - Add "swagger_route_added" event #27 - Remove "valid" from standard error structure since it was redundant - Documented how to include http://git.io/vcKD4 0.57 2015-09-30T11:48:22+0200 - Require JSON::Validator 0.56 for YAML validation - Add support for passing "coerce" to M::P::Swagger2::register() 0.56 2015-09-29T20:23:07+0200 - Add Mojolicious::Plugin::Swagger2 will validate spec on load 0.55 2015-09-27T16:53:08+0200 - Split Mojolicious::Plugin::Swagger2 into guides - Remove EXPERIMENTAL from "x-mojo-around-action" 0.54 2015-09-27T13:37:06+0200 - Compatible with JSON::Validator 0.54 - Compatible with Mojolicious 6.22 - Rename index.html.ep to list.html.ep in blog example #28 Contributor: Stephan Jauernick - Paths are sorted from the most specific to least specific #35 Contributor: Olli-Antti Kivilahti 0.53 2015-09-13T15:55:54+0200 - Add EXPERIMENTAL naming of swagger routes #27 - Add "swagger_operation_spec" to route defaults #30 - Allow x-mojo-around-action to be inherited #30 - Allow x-mojo-controller to be inherited - Swagger2::SchemaValidator is back because JSON::Validator cannot be Swagger specific 0.52 2015-09-13T10:53:14+0200 - Fix validate(): Need to expand, as well as depend on fixes in JSON::Validator - Will also log the operationId not implemented - Deprecated tree() in favor of api_spec() - Deprecated specification() 0.51 2015-09-03T12:22:20+0200 - Fix dumper() in Command::swagger2 - Add /editor to example blog application - Add slides for YAPC::EU 2015 t/blog/2015-yapc-eu-slides.pdf 0.50 2015-08-24T16:28:42+0200 - Should not use Swagger2::SchemaValidator #25 0.49 2015-08-23T15:16:09+0200 - Remove naming or routes to fix unique problem #23 0.48 2015-08-23T15:09:58+0200 - Core validation functionality is moved to JSON::Validator #25 0.47 2015-08-11T18:16:54+0200 - Add "swagger" as default stash() value 0.46 2015-08-11T16:35:04+0200 - Add support for giving an Swagger2 object to the plugin - Add support for "collectionFormat" (PARTIAL) #17 - Deprecated passing "controller" as argument to plugin - Remove warning about helpers defined twice #21 0.45 2015-08-11T14:32:05+0200 - Add support for x-mojo-around-action (EXPERIMENTAL) 0.44 2015-08-10T23:13:15+0200 - Updated schema.json https://twitter.com/SwaggerApi/status/627128354827862016 0.43 2015-07-14T17:36:07+0200 - Fix loading swagger spec from editor on Windows 0.42 2015-07-11T22:02:27+0200 - Fix parsing formData - Add support for no content in response 0.41 2015-07-11T12:25:55+0200 - Fix loading swagger spec from editor on Windows (failed) - Bump Mojolicous requirement to 6.00 0.40 2015-07-08T10:47:39+0200 - Fix "&Digest::MD5::md5_hex function called with reference argument" 0.39 2015-07-08T10:33:02+0200 - Allow negative integers in query string 0.38 2015-07-07T09:48:13+0200 - Will use "basePath" in root API route - Swagger2::Editor can load specifications over HTTP 0.37 2015-07-06T23:27:17+0200 - Bundle http://json-schema.org/draft-04/schema - Bundle http://swagger.io/v2/schema.json 0.36 2015-07-06T21:07:30+0200 - Remove EXPERIMENTAL from main Swagger2 module - Fix POST JSON data with Swagger2::Client - Updated swagger2 schema.json: Allow empty arrays for parameters - Add example blog app 0.35 2015-06-24T08:17:43+0200 - Add "mojo swagger2 client" command - Add EXPERIMENTAL "coerce" attribute to Swagger2::SchemaValidator 0.34 2015-06-22T10:13:44+0200 - Change order of YAML modules 0.33 2015-06-19T22:04:15+0200 - Add Swagger2::Client #8 - Fixed Mojolicious::Plugin::Swagger2 can use default values from schema #18 - Started deprecating "controller" as plugin config 0.32 2015-06-17T15:34:32+0200 - Allowing {n,no,false,off} as boolean false, #15 0.31 2015-05-13T12:42:39+0200 - Change required Mojolicious verision to 5.54 #14 0.30 2015-04-21T20:33:43+0200 - Fix failing test with YAML 1.15 #12 0.29 2015-04-09T09:52:40Z - Fix _schema_to_string_dispatch() can only be called with reference - Add support for raw text/binary data #6 - Add POD rendering of anyOf, allOf and oneOf #7 Contributor: Julian Maurice 0.28 2015-03-01T18:02:20Z - Allow setting specification_file when constructing Swagger2::Editor - Mojolicious::Routes::Route::bridge is DEPRECATED 0.27 2015-01-22T19:52:37Z - Fix validating "required" on a property - Fix validating output - Fix "path" in errors response when posting JSON or form data 0.26 2015-01-21T14:05:44Z - Fix validating body and form data - Add support for custom placeholder types 0.25 2015-01-20T12:26:23Z - Fix rendering "not implemented" - Fix parsing true/false in URL - Fix validating against empty rule set - Fix validating against "body" - Fix rendering "body" parameters in POD #5 - Documented custom route for Swagger2 Mojolicious plugin 0.24 2015-01-19T14:05:08Z - Add support for x-mojo-controller in swagger spec - HTTP method is not used in method name looked any more 0.23 2015-01-12T09:42:19Z - Fix scrolling to the right position after rendering POD - Fix loading ace.js from relative url - Will include description in POD, instead of just "required" - Remove editor shortcut CTRL+L - Add editor shortcut CTRL+F (find) - Can load API from same domain, using "#/path/to/api.json" fragment 0.22 2015-01-09T19:37:46Z - Allow "number" type when generating POD - Editor will also render "Table of contents" 0.21 2015-01-05T12:26:46Z - Fix order of headings in generated POD - Fix response codes are rendered with "=head4" - Made text in editor easier to read 0.20 2015-01-03T17:11:06Z - Fix loading $SWAGGER_API_FILE on Windows in Swagger2::Editor #4 Contributor: Andreas Koenig 0.19 2015-01-03T15:16:15Z - Move editor code from Mojolicious::Command::swagger2 to Swagger2::Editor 0.18 2015-01-03T14:16:31Z - Fix bodytest.t: YAML is not a required dependency 0.17 2015-01-03T10:30:29Z - Fix failing Windows test where the Mojo::URL path part is invalid 0.16 2015-01-02T12:44:33Z - Tried to fix failing Windows test where c:\path\to\spec is converted into a URL with scheme "c", #4 0.15 2014-12-19T13:26:24Z - Fix parse() will set tree() attribute - Allow editor to start without file 0.14 2014-12-18T16:06:02Z - Add both "summary" and "description" to POD - Add print styling for editor - Can resize editor area - Fix detecting yaml/json mode in editor 0.13 2014-12-18T14:06:26Z - Fix "not" logic in SchemaValidator 0.12 2014-12-16T11:30:34Z - Add missing Swagger2::POD::_schema_boolean_to_string() method - Add Swagger2::parse() method - Add "mojo swagger2 edit" command - Fix printing "Resource URL" when generating POD - Fix parameter references - Fix expanding bare $ref and $ref inside refs 0.11 2014-12-15T09:29:27Z - Add "mojo swagger2 pod" command - Add "mojo swagger2 perldoc" command - Add "mojo swagger2 validate" command - Change POD output to follow standard formatting 0.10 2014-12-15T07:27:51Z - Disable "int64" format test if Perl does not support 64 bit 0.09 2014-12-13T12:46:39Z - Fix adding parameter to route #1 - Fix "Resource URL" in generated POD - Add "Type" to "Parameters" POD table 0.08 2014-12-11T11:08:05Z - Change "floats" and "double" formats are not tested - Add support for "byte" format 0.07 2014-12-10T14:58:15Z - Fix test for negative integers - Add more formats: date, double, float, int32 and int64 0.06 2014-12-10T12:19:40Z - Fix t/jv-formats.t: Label not found for "last SKIP" 0.05 2014-12-09T22:01:31Z - Fix "Not an ARRAY reference at lib/Swagger2.pm line 356." 0.04 2014-12-09T21:02:43Z - Add "formats" to Swagger2::SchemaValidator 0.03 2014-12-09T15:36:04Z - Add Swagger2::validate() - Add Swagger 2.0 schema - Fix circular $ref when expanding a document - Rewrote Swagger2::SchemaValidator to support draft 4 0.02 2014-12-05T10:01:34Z - Add Swagger2::SchemaValidator - Add Swagger2::expand() - Add Mojolicious::Plugin::Swagger2 0.01 2014-12-04T14:01:27Z - Add load() - Add pod() and Swagger2::POD - Add to_string($format) - Started project Swagger2-0.73/cpanfile000644 000765 000024 00000000603 12652632443 016005 0ustar00jhthorsenstaff000000 000000 # You can install this projct with curl -L http://cpanmin.us | perl - https://github.com/jhthorsen/swagger2/archive/master.tar.gz requires "JSON::Validator" => "0.63"; requires "Mojolicious" => "6.00"; recommends "Data::Validate::Domain" => "0.10"; recommends "Data::Validate::IP" => "0.24"; test_requires "Test::More" => "0.88"; test_requires "Test::Warnings" => "0.016"; Swagger2-0.73/lib/000755 000765 000024 00000000000 12660346320 015043 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/Makefile.PL000644 000765 000024 00000001456 12660346317 016263 0ustar00jhthorsenstaff000000 000000 # Generated by git-ship. See 'git-ship --man' for help or https://github.com/jhthorsen/app-git-ship use ExtUtils::MakeMaker; WriteMakefile( NAME => 'Swagger2', AUTHOR => 'Jan Henning Thorsen ', LICENSE => 'artistic_2', ABSTRACT_FROM => 'lib/Swagger2.pm', VERSION_FROM => 'lib/Swagger2.pm', EXE_FILES => [qw( )], META_MERGE => { resources => { bugtracker => 'https://github.com/jhthorsen/swagger2/issues', homepage => 'https://github.com/jhthorsen/swagger2', repository => 'https://github.com/jhthorsen/swagger2.git', }, }, BUILD_REQUIRES => { 'Test::More' => '0.88', 'Test::Warnings' => '0.016' } , PREREQ_PM => { 'JSON::Validator' => '0.63', 'Mojolicious' => '6.00' } , test => {TESTS => (-e 'META.yml' ? 't/*.t' : 't/*.t xt/*.t')}, ); Swagger2-0.73/MANIFEST000644 000765 000024 00000005077 12660346320 015437 0ustar00jhthorsenstaff000000 000000 .perltidyrc .ship.conf .travis.yml Changes cpanfile lib/Mojolicious/Command/swagger2.pm lib/Mojolicious/Plugin/Swagger2.pm lib/Swagger2.pm lib/Swagger2/Client.pm lib/Swagger2/Editor.pm lib/Swagger2/error.json lib/Swagger2/Guides/CustomPlaceholder.pod lib/Swagger2/Guides/ProtectedApi.pod lib/Swagger2/Guides/Render.pod lib/Swagger2/Guides/Tutorial.pod lib/Swagger2/Guides/WebSocket.pod lib/Swagger2/POD.pm lib/Swagger2/public/ace.js lib/Swagger2/public/cache/05a9f0030e1b92e1603618dad61dbc8d lib/Swagger2/public/cache/062bec94cfcd2cb0049773ae5d15da61 lib/Swagger2/public/cache/0a8e1de16692c32db582df9bdabdbdd7 lib/Swagger2/public/cache/36d1bd12eeed51e86c8695bd8876a9df lib/Swagger2/public/cache/49c95b866e40f788892a7fb3c816b0e8 lib/Swagger2/public/cache/630949337805585c8e52deea27d11419 lib/Swagger2/public/cache/84a4b37fb9b912219cbeb486174f4066 lib/Swagger2/public/cache/ea34d47d4e060a1c3b12d2287aff89a7 lib/Swagger2/public/cache/eaa832720f36cff0abc20c05236a9cd9 lib/Swagger2/public/mode-json.js lib/Swagger2/public/mode-yaml.js lib/Swagger2/public/theme-solarized_dark.js lib/Swagger2/public/worker-json.js lib/Swagger2/schema.json lib/Swagger2/SchemaValidator.pm lib/Swagger2/swagger2-client.js Makefile.PL MANIFEST This list of files README t/00-basic.t t/00-copy.t t/Api.pm t/around-action.t t/authenticate.t t/blog.t t/blog/2015-yapc-eu-slides.pdf t/blog/api.json t/blog/blog.conf t/blog/lib/Blog.pm t/blog/lib/Blog/Controller/Post.pm t/blog/lib/Blog/Model/Posts.pm t/blog/migrations/blog.sql t/blog/script/blog t/blog/templates/layouts/blog.html.ep t/blog/templates/post/_form.html.ep t/blog/templates/post/create.html.ep t/blog/templates/post/edit.html.ep t/blog/templates/post/list.html.ep t/blog/templates/post/show.html.ep t/bodytest.t t/boolean-in-url.t t/client-return-on-error.t t/client-with-swagger.t t/client.t t/collection-format.t t/command-client.t t/data/petstore.json t/data/petstore.yaml t/data/pod-as-string.json t/data/pod-as-string.pod t/data/validate.json t/editor.t t/emtpy-response.t t/ensure-swagger-response.t t/example-json-patch.t t/example-lowercase-request-params.t t/expand.t t/file.t t/formdata.t t/headers.t t/ip-in-url.t t/jv-formats.t t/lib/MyApp/Controller/Pet.pm t/not-implemented-501.t t/nullable.t t/operation-id.t t/order-pathobjects-lengthwise.t t/parse-json.t t/plugin-defaults.t t/plugin-yaml.t t/plugin.t t/pod-as-string.t t/read-only-property.t t/stash-defaults.t t/swagger.t t/validate.t t/websocket.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Swagger2-0.73/META.json000664 000765 000024 00000002332 12660346320 015720 0ustar00jhthorsenstaff000000 000000 { "abstract" : "Swagger RESTful API Documentation", "author" : [ "Jan Henning Thorsen " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.0401, CPAN::Meta::Converter version 2.150001", "license" : [ "artistic_2" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Swagger2", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "Test::More" : "0.88", "Test::Warnings" : "0.016" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "JSON::Validator" : "0.63", "Mojolicious" : "6.00" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/jhthorsen/swagger2/issues" }, "homepage" : "https://github.com/jhthorsen/swagger2", "repository" : { "url" : "https://github.com/jhthorsen/swagger2.git" } }, "version" : "0.73" } Swagger2-0.73/META.yml000664 000765 000024 00000001345 12660346320 015553 0ustar00jhthorsenstaff000000 000000 --- abstract: 'Swagger RESTful API Documentation' author: - 'Jan Henning Thorsen ' build_requires: Test::More: '0.88' Test::Warnings: '0.016' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.0401, CPAN::Meta::Converter version 2.150001' license: artistic_2 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Swagger2 no_index: directory: - t - inc requires: JSON::Validator: '0.63' Mojolicious: '6.00' resources: bugtracker: https://github.com/jhthorsen/swagger2/issues homepage: https://github.com/jhthorsen/swagger2 repository: https://github.com/jhthorsen/swagger2.git version: '0.73' Swagger2-0.73/README000644 000765 000024 00000010315 12660346317 015163 0ustar00jhthorsenstaff000000 000000 NAME Swagger2 - Swagger RESTful API Documentation VERSION 0.73 DESCRIPTION Swagger2 is a module for generating, parsing and transforming swagger API specification. It has support for reading swagger specification in JSON notation and as well YAML format. Please read for an introduction to Swagger and reasons for why you would to use it. Mojolicious server side code generator This distribution comes with a Mojolicious plugin, Mojolicious::Plugin::Swagger2, which can set up routes and perform input and output validation. Mojolicious client side code generator Swagger2 also comes with a Swagger2::Client generator, which converts the client spec to perl code in memory. RECOMMENDED MODULES * YAML parser A YAML parser is required if you want to read/write spec written in the YAML format. Supported modules are YAML::XS, YAML::Syck, YAML and YAML::Tiny. SYNOPSIS use Swagger2; my $swagger = Swagger2->new("/path/to/api-spec.yaml"); # Access the raw specification values print $swagger->api_spec->get("/swagger"); # Returns the specification as a POD document print $swagger->pod->to_string; ATTRIBUTES api_spec $pointer = $self->api_spec; $self = $self->api_spec(Mojo::JSON::Pointer->new({})); Holds a Mojo::JSON::Pointer object containing your API specification. base_url $mojo_url = $self->base_url; Mojo::URL object that holds the location to the API endpoint. Note: This might also just be a dummy URL to . specification DEPRECATED. If you need to change this, then you probably want JSON::Validator instead. tree DEPRECATED. Use "api_spec" instead. ua $ua = $self->ua; $self = $self->ua(Mojo::UserAgent->new); A Mojo::UserAgent used to fetch remote documentation. url $mojo_url = $self->url; Mojo::URL object that holds the location to the documentation file. This can be both a location on disk or an URL to a server. A remote resource will be fetched using Mojo::UserAgent. METHODS expand $swagger = $self->expand; This method returns a new "Swagger2" object, where all the references are resolved. javascript_client $file = $self->javascript_client; Returns a Mojo::Asset::File object which points to a file containing a custom JavaScript file which can communicate with Mojolicious::Plugin::Swagger2. See for source code. "swagger2-client.js" is currently EXPERIMENTAL! load $self = $self->load; $self = $self->load($url); Used to load the content from $url or "url". This method will try to guess the content type (JSON or YAML) by looking at the content of the $url. new $self = Swagger2->new($url); $self = Swagger2->new(%attributes); $self = Swagger2->new(\%attributes); Object constructor. parse $self = $self->parse($text); Used to parse $text instead of loading data from "url". The type of input text can be either JSON or YAML. It will default to YAML, but parse the text as JSON if it starts with "{". pod $pod_object = $self->pod; Returns a Swagger2::POD object. to_string $json = $self->to_string; $json = $self->to_string("json"); $yaml = $self->to_string("yaml"); This method can transform this object into Swagger spec. validate @errors = $self->validate; Will validate "api_spec" against Swagger RESTful API Documentation Specification , and return a list with all the errors found. See also "validate" in JSON::Validator. COPYRIGHT AND LICENSE Copyright (C) 2014-2015, Jan Henning Thorsen This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0. AUTHOR Jan Henning Thorsen - "jhthorsen@cpan.org" Swagger2-0.73/t/000755 000765 000024 00000000000 12660346320 014540 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/00-basic.t000644 000765 000024 00000002142 12656403247 016231 0ustar00jhthorsenstaff000000 000000 use Test::More; use File::Find; if (($ENV{HARNESS_PERL_SWITCHES} || '') =~ /Devel::Cover/) { plan skip_all => 'HARNESS_PERL_SWITCHES =~ /Devel::Cover/'; } if (!eval 'use Test::Pod; 1') { *Test::Pod::pod_file_ok = sub { SKIP: { skip "pod_file_ok(@_) (Test::Pod is required)", 1 } }; } if (!eval 'use Test::Pod::Coverage; 1') { *Test::Pod::Coverage::pod_coverage_ok = sub { SKIP: { skip "pod_coverage_ok(@_) (Test::Pod::Coverage is required)", 1 } }; } if (!eval 'use Test::CPAN::Changes; 1') { *Test::CPAN::Changes::changes_file_ok = sub { SKIP: { skip "changes_ok(@_) (Test::CPAN::Changes is required)", 4 } }; } find({wanted => sub { /\.pm$/ and push @files, $File::Find::name }, no_chdir => 1}, -e 'blib' ? 'blib' : 'lib',); plan tests => @files * 3 + 4; for my $file (@files) { my $module = $file; $module =~ s,\.pm$,,; $module =~ s,.*/?lib/,,; $module =~ s,/,::,g; ok eval "use $module; 1", "use $module" or diag $@; Test::Pod::pod_file_ok($file); Test::Pod::Coverage::pod_coverage_ok($module, {also_private => [qr/^[A-Z_]+$/],}); } Test::CPAN::Changes::changes_file_ok(); Swagger2-0.73/t/00-copy.t000644 000765 000024 00000002123 12656403247 016121 0ustar00jhthorsenstaff000000 000000 use strict; use Test::More; use File::Spec; use Mojo::JSON 'decode_json'; use Mojo::Loader 'data_section'; use Mojo::Util 'md5_sum'; plan skip_all => 'Author test' unless -d './.git'; my @url = qw( http://git.io/vcKD4 https://raw.githubusercontent.com/jhthorsen/swagger2/master/lib/Swagger2/error.json ); my $error_json = data_section qw( main error.json ); ok decode_json($error_json), 'error_json'; { my $file = File::Spec->catfile(qw( lib Swagger2 error.json )); open my $FH, '>', $file or die "Write $file: $!"; print $FH $error_json; } for my $url (@url) { my $file = File::Spec->catfile(qw( lib Swagger2 public cache ), md5_sum $url); open my $FH, '>', $file or die "Write $file: $!"; print $FH $error_json; } done_testing; __DATA__ @@ error.json { "type" : "object", "required": [ "errors" ], "properties": { "errors": { "type": "array", "items": { "type" : "object", "required": [ "message", "path" ], "properties": { "message": { "type": "string" }, "path": { "type": "string" } } } } } } Swagger2-0.73/t/Api.pm000644 000765 000024 00000003353 12656642162 015623 0ustar00jhthorsenstaff000000 000000 package t::Api; use Mojo::Base 'Mojolicious::Controller'; our $ERR; our $RES = {}; our $CODE = 200; sub authenticate { my ($next, $c, $config) = @_; return $next->($c) if $CODE eq '200'; return $c->render(json => $config, status => $CODE); } sub collection_format { my ($c, $args, $cb) = @_; $c->$cb($args, $CODE); } sub empty { my ($c, $args, $cb) = @_; $c->$cb('', $CODE); } sub get_headers { my ($c, $args, $cb) = @_; $c->res->headers->header('what-ever' => delete $RES->{header}); $c->res->headers->header('x-bool' => $args->{'x-bool'}) if exists $args->{'x-bool'}; $c->$cb($args, 200); } sub test_file { my ($c, $args, $cb) = @_; $c->$cb($c->stash('swagger')->pod->to_string, 200); } sub boolean_in_url { my ($c, $args, $cb) = @_; $c->$cb({p1 => $args->{p1}, q1 => $args->{q1}}); } sub ip_in_url { my ($c, $args, $cb) = @_; $c->$cb({ip => $args->{ip}}); } sub list_pets { my ($c, $args, $cb) = @_; $c->$cb($RES, $CODE); } sub status { my ($c, $args, $cb) = @_; my $resp = {}; $resp->{status} = $RES; $c->$cb($resp, $CODE); } sub show_pet_by_id { my ($c, $args, $cb) = @_; $RES->{id} = $args->{petId}; $c->$cb($RES, $CODE); } sub get_pet { my ($c, $args, $cb) = @_; die $ERR if $ERR; return $c->$cb('', 201) if $CODE eq '201'; return $c->$cb($RES, $CODE); } sub add_pet { my ($c, $args, $cb) = @_; $RES->{name} = $args->{data}{name} if ref $args->{data} eq 'HASH'; $c->$cb($RES, $CODE); } sub update_pet { my ($c, $args, $cb) = @_; $c->$cb($RES, $CODE); } sub patch_pet { my ($c, $args, $cb) = @_; $c->$cb({}, 204); } sub with_defaults { my ($c, $args, $cb) = @_; $c->$cb({ip => $args->{ip}, x => $args->{x}}); } sub import { strict->import; warnings->import; } 1; Swagger2-0.73/t/around-action.t000644 000765 000024 00000003563 12656403247 017506 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Mojolicious; use Test::Mojo; use Test::More; use File::Spec::Functions; use t::Api; for my $file (qw( around-action inherit-path inherit-global )) { my $app = Mojolicious->new; $app->plugin(Swagger2 => {url => "data://main/$file.json"}); my $t = Test::Mojo->new($app); $t::Api::CODE = 401; $t::Api::RES = [{id => 123, name => "kit-cat"}]; $t->get_ok('/api/pets')->status_is(401)->json_is('/operationId', 'listPets')->json_is('/x-mojo-controller', 't::Api') ->json_is('/x-mojo-around-action', 't::Api::authenticate')->json_is('/responses/200/description', 'anything'); $t::Api::CODE = 200; $t->get_ok('/api/pets')->status_is(200); } done_testing; __DATA__ @@ around-action.json { "swagger": "2.0", "basePath": "/api", "info": { "version": "1.0", "title": "around-action" }, "paths": { "/pets": { "get": { "x-mojo-controller": "t::Api", "x-mojo-around-action": "t::Api::authenticate", "operationId": "listPets", "responses": { "200": {"description": "anything"} } } } } } @@ inherit-path.json { "swagger": "2.0", "basePath": "/api", "info": { "version": "1.0", "title": "inherit-path" }, "paths": { "/pets": { "x-mojo-around-action": "t::Api::authenticate", "x-mojo-controller": "t::Api", "get": { "operationId": "listPets", "responses": { "200": {"description": "anything"} } } } } } @@ inherit-global.json { "swagger": "2.0", "info": { "version": "1.0", "title": "inherit-global" }, "basePath": "/api", "x-mojo-around-action": "t::Api::authenticate", "x-mojo-controller": "t::Api", "paths": { "/pets": { "get": { "operationId": "listPets", "responses": { "200": {"description": "anything"} } } } } } Swagger2-0.73/t/authenticate.t000644 000765 000024 00000002113 12656403247 017407 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use t::Api; my $spec; { use Mojolicious::Lite; my $route = app->routes->under('/protected')->to( cb => sub { my $c = shift; $spec = $c->stash('swagger'); return 1 if $c->param('secret'); $c->render(json => {error => {code => 401, message => "Not authenticated"}}, status => 401); return undef; } ); plugin Swagger2 => {url => 't/data/petstore.json', route => $route}; } my $t = Test::Mojo->new; $t->get_ok('/protected/pets')->status_is(401)->json_is('/error/message', 'Not authenticated'); $t::Api::RES = [{id => 123, name => "kit-cat"}]; $t->get_ok('/protected/pets?secret=whatever')->status_is(200)->json_is('/0/id', 123)->json_is('/0/name', 'kit-cat'); # fetch expanded specification is $t->app->url_for('swagger_petstore'), '/protected', 'spec url'; $t->get_ok('/protected')->status_is(401); $t->get_ok('/protected?secret=whatever')->status_is(200)->json_is('/basePath', '/protected') ->json_is('/paths/~1pets/get/parameters/0/in', 'query'); done_testing; Swagger2-0.73/t/blog/000755 000765 000024 00000000000 12660346320 015463 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/blog.t000644 000765 000024 00000002611 12656403247 015657 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use lib 't/blog/lib'; plan skip_all => 'BLOG_PG_URL=postgresql://postgres@/test' unless $ENV{BLOG_PG_URL}; if ($ENV{RUN}) { require Mojolicious::Commands; Mojolicious::Commands->start_app('Blog'); exit; } plan skip_all => $@ unless my $t = eval { Test::Mojo->new('Blog') }; $t->app->pg->migrations->migrate(0)->migrate unless $ENV{KEEP_DATABASE}; $t->get_ok('/')->status_is(302); $t->get_ok('/api/posts')->content_is('[]'); $t->post_ok('/api/posts', json => {title => 'test 123', body => undef})->status_is(400) ->json_is('/errors/0/message', 'Expected string - got null.')->json_is('/errors/0/path', '/entry/body'); $t->post_ok('/api/posts', json => {title => 'test 123', body => 'Cool blog post!'})->status_is(200) ->json_like('/id', qr{\d+}); my $id = $t->tx->res->json->{id}; $t->get_ok("/api/posts/$id")->status_is(200)->json_is('/title', 'test 123')->json_is('/body', 'Cool blog post!'); $t->get_ok('/api/posts')->status_is(200)->json_is('/0/title', 'test 123')->json_is('/0/body', 'Cool blog post!'); $t->put_ok("/api/posts/$id", json => {title => 'foo', body => 'Still awesome'})->status_is(200)->content_is('{}'); $t->delete_ok("/api/posts/$id")->status_is(200)->content_is('{}'); $t->get_ok("/api/posts/$id")->status_is(404)->json_is('/errors/0/message', 'Blog post not found.') ->json_is('/errors/0/path', '/id'); done_testing; Swagger2-0.73/t/bodytest.t000644 000765 000024 00000010760 12656403247 016575 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use Test::Warnings; use t::Api; use Mojolicious::Lite; plugin Swagger2 => {url => 'data://main/bodytest.json'}; my $t = Test::Mojo->new; $t::Api::RES = {}; # EXPERIMENTAL ok $t->app->routes->lookup('t_api_add_pet'), 'add route add_pet'; # invalid input $t->post_ok('/api/pets')->status_is(400)->json_is('/errors/0/message', 'Expected object - got null.') ->json_is('/errors/0/path', '/pet'); $t->post_ok('/api/pets' => json => {id => 123})->status_is(400)->json_is('/errors/0/message', 'Missing property.') ->json_is('/errors/0/path', '/pet/name'); # invalid input $t->post_ok('/api/pets' => json => {id => "123", name => "kit-cat"})->status_is(400) ->json_is('/errors/0/message', 'Expected integer - got string.')->json_is('/errors/0/path', '/pet/id'); # valid patch $t->patch_ok('/api/pets' => json => [ { name => "123" } ])->status_is(204); # valid input and output $t::Api::RES = [{id => 123, name => "kit-cat"}]; $t->post_ok('/api/pets' => json => {id => 123, name => "kit-cat"})->status_is(200)->json_is('/0/id', 123); # do it again to check if clobbered $t->post_ok('/api/pets' => json => {id => 123, name => "kit-cat"})->status_is(200)->json_is('/0/id', 123); # invalid output $t::Api::RES = [{id => "123", name => "kit-cat"}]; $t->post_ok('/api/pets' => json => {id => 123, name => "kit-cat"})->status_is(500)->json_is('/errors/0/path', '/0/id') ->json_is('/errors/0/message', 'Expected integer - got string.'); # invalid output $t::Api::RES = {some_parent_key => {id => "123", name => "kit-cat"}}; $t->get_ok('/api/pets' => json => {id => 123, name => "kit-cat"})->status_is(500) ->json_is('/errors/0/path', '/some_parent_key/id')->json_is('/errors/0/message', 'Expected integer - got string.'); # invalid output $t::Api::RES = {}; $t->post_ok('/api/pets' => json => {id => 123, name => "kit-cat"})->status_is(500)->json_is('/errors/0/path', '/') ->json_is('/errors/0/message', 'Expected array - got object.'); # no output rules defined $t::Api::CODE = 204; $t->post_ok('/api/pets' => json => {id => 123, name => "kit-cat"})->status_is(500)->json_is('/errors/0/path', '/') ->json_is('/errors/0/message', 'No validation rules defined.'); # empty document $t::Api::CODE = 201; $t->get_ok('/api/pets')->status_is(201)->content_is(''); done_testing; __DATA__ @@ bodytest.json { "swagger" : "2.0", "info" : { "version": "9.1", "title" : "Test API for body parameters" }, "consumes" : [ "application/json" ], "produces" : [ "application/json" ], "schemes" : [ "http" ], "basePath" : "/api", "paths" : { "/pets" : { "get" : { "x-mojo-controller": "t::Api", "operationId" : "getPet", "responses" : { "200" : { "description": "this is required", "schema": { "type" : "object", "properties" : { "some_parent_key": { "$ref": "#/definitions/Pet" } } } }, "201": { "description": "empty body." } } }, "post" : { "x-mojo-controller": "t::Api", "operationId" : "addPet", "parameters" : [ { "name" : "pet", "schema" : { "$ref" : "#/definitions/Pet" }, "in" : "body", "required": true, "description" : "Pet object that needs to be added to the store" } ], "responses" : { "200": { "description": "pet response", "schema": { "type": "array", "items": { "$ref": "#/definitions/Pet" } } } } }, "patch" : { "x-mojo-controller": "t::Api", "operationId" : "patchPet", "parameters" : [ { "name" : "patch", "schema" : { "$ref" : "#/definitions/Patch" }, "in" : "body", "required": true, "description" : "Patch object to update pet" } ], "responses" : { "204": { "description": "pet response" } } } } }, "definitions" : { "Pet" : { "required" : ["name"], "properties" : { "id" : { "format" : "int64", "type" : "integer" }, "name" : { "type" : "string" } } }, "Patch" : { "type" : "array", "items" : { "properties" : { "name" : { "type": "string" } } } } } } Swagger2-0.73/t/boolean-in-url.t000644 000765 000024 00000002544 12656403247 017564 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use Mojolicious::Lite; plugin Swagger2 => {url => 'data://main/boolean-in-url.json'}; my $t = Test::Mojo->new; $t->get_ok('/boolean-in-url/false?q1=true')->status_is(200); like $t->tx->res->body, qr{"p1":false}, 'p1 false'; like $t->tx->res->body, qr{"q1":true}, 'q1 true'; $t->get_ok('/boolean-in-url/true')->status_is(200); like $t->tx->res->body, qr{"p1":true}, 'p1 true'; like $t->tx->res->body, qr{"q1":null}, 'q1 null'; $t->get_ok('/boolean-in-url/1')->status_is(200); like $t->tx->res->body, qr{"p1":true}, 'p1 1'; $t->get_ok('/boolean-in-url/0')->status_is(200); like $t->tx->res->body, qr{"p1":false}, 'p1 0'; done_testing; __DATA__ @@ boolean-in-url.json { "swagger" : "2.0", "info" : { "version": "1.0", "title" : "Test _not_implemented() in plugin" }, "paths" : { "/boolean-in-url/{p1}" : { "get" : { "x-mojo-controller": "t::Api", "operationId" : "BooleanInUrl", "parameters" : [ { "name": "p1", "type": "boolean", "in": "path", "required": true }, { "name": "q1", "type": "boolean", "in": "query" } ], "responses" : { "200" : { "description": "whatever", "schema" : { "type": "object" } } } } } } } Swagger2-0.73/t/client-return-on-error.t000644 000765 000024 00000001354 12656403247 021273 0ustar00jhthorsenstaff000000 000000 use t::Api; use Swagger2::Client; use Test::More; use Mojolicious::Lite; app->log->level('error') unless $ENV{HARNESS_IS_VERBOSE}; plugin Swagger2 => {url => 't/data/petstore.json'}; my $client = Swagger2::Client->generate('t/data/petstore.json'); my $ua = app->ua; # sync $client->ua($ua); $client->base_url->host($ua->server->url->host); $client->base_url->port($ua->server->url->port); my $res = $client->return_on_error(1)->add_pet; is $res->code, 400, 'blocking 400'; is $res->json->{errors}[0]{message}, 'Expected object - got null.', 'expected'; $t::Api::RES = {}; $res = $client->show_pet_by_id({petId => 42}); is $res->code, 500, 'blocking 500'; is $res->json->{errors}[0]{message}, 'Missing property.', 'missing'; done_testing; Swagger2-0.73/t/client-with-swagger.t000644 000765 000024 00000001512 12656403247 020617 0ustar00jhthorsenstaff000000 000000 use t::Api; use Swagger2::Client; use Test::More; my $client = Swagger2::Client->generate(Swagger2->new('t/data/petstore.json')); use Mojolicious::Lite; app->log->level('error') unless $ENV{HARNESS_IS_VERBOSE}; plugin Swagger2 => {url => 't/data/petstore.json'}; isa_ok($client->base_url, 'Mojo::URL'); isa_ok($client->ua, 'Mojo::UserAgent'); isa_ok($client->_swagger, 'Swagger2'); can_ok($client, qw( list_pets listPets )); is $client->base_url, 'http://petstore.swagger.wordnik.com/api', 'base_url'; $client->ua(app->ua); # sync $client->base_url->host($client->ua->server->url->host); $client->base_url->port($client->ua->server->url->port); $t::Api::RES = {id => 123, name => "kit-cat"}; my $res = $client->showPetById({petId => 42}); is_deeply($res->json, {id => 42, name => "kit-cat"}, 'list_pets async ok'); done_testing; Swagger2-0.73/t/client.t000644 000765 000024 00000005356 12660346210 016212 0ustar00jhthorsenstaff000000 000000 use t::Api; use Swagger2::Client; use Test::More; use Mojolicious::Lite; app->log->level('error') unless $ENV{HARNESS_IS_VERBOSE}; plugin Swagger2 => {url => 't/data/petstore.json'}; my $client = Swagger2::Client->generate('t/data/petstore.json'); my $ua = app->ua; my $err; isa_ok($client->base_url, 'Mojo::URL'); isa_ok($client->ua, 'Mojo::UserAgent'); isa_ok($client->_swagger, 'Swagger2'); can_ok($client, qw( list_pets listPets )); is $client->base_url, 'http://petstore.swagger.wordnik.com/api', 'base_url'; $client->ua($ua); # sync $client->base_url->host($ua->server->url->host); $client->base_url->port($ua->server->url->port); $t::Api::RES = [{id => 123, name => "kit-cat"}]; my $res = $client->list_pets; is_deeply($res->json, [{id => 123, name => "kit-cat"}], 'list_pets ok'); eval { $client->list_pets({limit => 'foo'}) }; like $@, qr{^Invalid input: /limit: Expected integer - got string}, 'list_pets invalid input'; $t::Api::RES = [{id => 'foo', name => "kit-cat"}]; eval { $client->list_pets }; like $@, qr{^Internal Server Error:.*"path":"\W+0\W+id"}, 'list_pets invalid response'; # sync post $t::Api::RES = {id => 123, name => 'kit-cat'}; eval { $client->add_pet }; like $@, qr{^Invalid input: /data: Expected object - got null}, 'add_pet invalid input'; $res = $client->add_pet({data => {name => 'm4'}}); is $res->json->{name}, 'm4', 'add_pet'; # async $t::Api::RES = [{id => 123, name => "kit-cat"}]; $client->base_url->host($ua->server->nb_url->host); $client->base_url->port($ua->server->nb_url->port); $t::Api::RES = [{id => 123, name => "kit-cat"}]; $client->list_pets(sub { (my $client, $err, $res) = @_; Mojo::IOLoop->stop }); Mojo::IOLoop->start; is_deeply($res->json, [{id => 123, name => "kit-cat"}], 'list_pets async ok'); $client->list_pets({limit => 'foo'}, sub { (my $client, $err, $res) = @_ }); is_deeply($err, ['/limit: Expected integer - got string.'], 'list_pets async invalid input'); is $res, undef, 'list_pets async invalid input'; $t::Api::RES = [{id => 'foo', name => "kit-cat"}]; $client->list_pets(sub { (my $client, $err, $res) = @_; Mojo::IOLoop->stop }); Mojo::IOLoop->start; isa_ok($res, 'Mojo::Message::Response'); is $res->json->{errors}[0]{message}, 'Expected integer - got string.', 'errors'; is_deeply($err, 'Internal Server Error', 'list_pets async invalid output'); # with path $t::Api::RES = {id => 123, name => "kit-cat"}; $client->show_pet_by_id(sub { (my $client, $err, $res) = @_; Mojo::IOLoop->stop }); is_deeply($err, ['/petId: Expected integer - got null.'], 'show_pet_by_id async invalid input'); $client->show_pet_by_id({petId => 0}, sub { (my $client, $err, $res) = @_; Mojo::IOLoop->stop }); Mojo::IOLoop->start; is_deeply($res->json, {id => 0, name => "kit-cat"}, 'list_pets async ok'); done_testing; Swagger2-0.73/t/collection-format.t000644 000765 000024 00000005276 12656403247 020367 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use Mojolicious::Lite; use t::Api; plugin Swagger2 => {ensure_swagger_response => {}, url => 'data://main/collection-format.json'}; my $t = Test::Mojo->new; $t->get_ok('/collection/format/integer?foo=1|2|3')->status_is(200)->content_is('{"foo":[1,2,3]}'); $t->get_ok('/collection/format/number?foo=1.42 2 3.14')->status_is(200)->content_is('{"foo":[1.42,2,3.14]}'); $t->get_ok('/collection/format/string?foo=1,x,3')->status_is(200)->content_is('{"foo":["1","x","3"]}'); $t->get_ok('/collection/format/string?foo=x')->status_is(200)->content_is('{"foo":["x"]}'); $t->get_ok('/collection/format/array?foo=1|2,3|4')->status_is(200)->content_is('{"foo":[["1","2"],["3","4"]]}'); $t->get_ok('/collection/format/string?foo=')->status_is(200)->content_is('{"foo":[]}'); $t->get_ok('/collection/format/string?foo')->status_is(200)->content_is('{"foo":[]}'); $t->get_ok('/collection/format/string')->status_is(200)->content_is('{}'); done_testing; __DATA__ @@ collection-format.json { "info" : {"title" : "Example", "version" : "0.0.0"}, "swagger" : "2.0", "paths" : { "/collection/format/integer" : { "get" : { "x-mojo-controller": "t::Api", "operationId": "collectionFormat", "parameters" : [ { "collectionFormat" : "pipes", "items" : {"type" : "integer"}, "name" : "foo", "in" : "query", "type" : "array" } ], "responses" : {"200" : {"description" : "OK"}} } }, "/collection/format/number" : { "get" : { "x-mojo-controller": "t::Api", "operationId": "collectionFormat", "parameters" : [ { "collectionFormat" : "ssv", "items" : {"type" : "number"}, "name" : "foo", "in" : "query", "type" : "array" } ], "responses" : {"200" : {"description" : "OK"}} } }, "/collection/format/string" : { "get" : { "x-mojo-controller": "t::Api", "operationId": "collectionFormat", "parameters" : [ { "collectionFormat" : "csv", "items" : {"type" : "string"}, "name" : "foo", "in" : "query", "type" : "array" } ], "responses" : {"200" : {"description" : "OK"}} } }, "/collection/format/array" : { "get" : { "x-mojo-controller": "t::Api", "operationId": "collectionFormat", "parameters": [{ "collectionFormat" : "csv", "name" : "foo", "in" : "query", "type": "array", "items" : { "type" : "array", "collectionFormat" : "pipes", "items" : { "type" : "string" } } }], "responses" : {"200" : {"description" : "OK"}} } } } } Swagger2-0.73/t/command-client.t000644 000765 000024 00000001437 12656403247 017633 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec; use Mojolicious::Command::swagger2; plan skip_all => $^O if $^O eq 'MSWin32'; my $cmd = Mojolicious::Command::swagger2->new; close $Mojolicious::Command::swagger2::OUT; open $Mojolicious::Command::swagger2::OUT, '>', \my $stdout; $stdout = ''; $cmd->run('client'); like $stdout, qr{\# Get documentation for a method.*swagger2 client}s, 'client usage'; $stdout = ''; $cmd->run('client', File::Spec->catfile(qw(t blog api.json))); like $stdout, qr{removePost\s+showPost\s+storePost\s+updatePost}s, 'list methods'; $ENV{SWAGGER_API_FILE} = File::Spec->catfile(qw(t blog api.json)); $stdout = ''; $cmd->run(qw(client removePost help)); like $stdout, qr,DELETE http://localhost/api/posts/\{id\},, 'method help'; done_testing; Swagger2-0.73/t/data/000755 000765 000024 00000000000 12660346320 015451 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/editor.t000644 000765 000024 00000001700 12656403247 016220 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; plan skip_all => 'Skipping editor test on Win32' if $^O eq 'MSWin32'; $ENV{MOJO_APP_LOADER} = 1; $ENV{SWAGGER_API_FILE} = 't/data/petstore.json'; plan skip_all => 'Cannot read/write petstore.json' unless -w $ENV{SWAGGER_API_FILE}; my $t = Test::Mojo->new('Swagger2::Editor'); $t->get_ok('/')->status_is(200)->text_is('title', 'Swagger2 - Editor')->element_exists('#editor') ->element_exists('#preview')->element_exists('#preview .pod-container')->element_exists('h2#showPetById') ->element_exists('script[src="ace.js"]')->text_is('h2#showPetById a', 'showPetById') ->content_like(qr{xhr\.open\("POST", "/", true\);}); my $spec = Mojo::Util::slurp($ENV{SWAGGER_API_FILE}); $spec =~ s!"1\.0\.0"!"42"!; $t->post_ok('/', $spec)->status_is(200)->content_like(qr{

42

}); # "git checkout t/data/petstore.json" $spec =~ s!"42"!"1.0.0"!; $t->post_ok('/', $spec)->status_is(200); done_testing; Swagger2-0.73/t/emtpy-response.t000644 000765 000024 00000001544 12656403247 017732 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use t::Api; use Mojolicious::Lite; plugin Swagger2 => {url => 'data://main/empty.json'}; my $t = Test::Mojo->new(); $t->get_ok('/api/empty/response')->status_is(500)->json_is('/errors/0/message', 'No validation rules defined.'); $t::Api::CODE = 204; $t->get_ok('/api/empty/response')->status_is(204)->content_is(''); done_testing; __DATA__ @@ empty.json { "swagger" : "2.0", "info" : { "version": "9.1", "title" : "Test API for body parameters" }, "schemes" : [ "http" ], "basePath" : "/api", "paths" : { "/empty/response" : { "get" : { "x-mojo-controller": "t::Api", "operationId" : "empty", "responses" : { "204" : { "description": "this is required", "schema": { "type" : "string" } } } } } } } Swagger2-0.73/t/ensure-swagger-response.t000644 000765 000024 00000002227 12656403247 021531 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use Test::Warnings; use File::Spec::Functions; use t::Api; use Mojolicious::Lite; plugin Swagger2 => {ensure_swagger_response => {}, url => 'data://main/bodytest.json'}; my $t = Test::Mojo->new; $t::Api::ERR = 'ooops!'; $t->get_ok('/api/pets')->status_is(500)->json_is('/errors/0/path', '/') ->json_is('/errors/0/message', 'Internal server error.'); $t->get_ok('/api/no_such_resource')->status_is(404)->json_is('/errors/0/path', '/') ->json_is('/errors/0/message', 'Not found.'); $t->get_ok('/no_such_resource')->status_is(404)->content_unlike(qr/^{/); done_testing; __DATA__ @@ bodytest.json { "swagger" : "2.0", "info" : { "version": "9.1", "title" : "Test API for body parameters" }, "basePath" : "/api", "paths" : { "/pets" : { "get" : { "x-mojo-controller": "t::Api", "operationId" : "getPet", "responses" : { "200" : { "description": "this is required", "schema": { "type" : "object" } }, "201": { "description": "empty body." } } } } } } Swagger2-0.73/t/example-json-patch.t000644 000765 000024 00000005627 12656606515 020450 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; plan skip_all => 'TEST_ONLINE=1' unless $ENV{TEST_ONLINE}; # # https://github.com/OAI/OpenAPI-Specification/issues/57 # The swagger spec does not support oneOf, anyOf, ... # so you cannot include JSON Schema specs such as # http://json.schemastore.org/json-patch.json directly. # # This test is an example to implement parts of the spec # in a different way. # # TODO: Make sure "path" is also part of the spec, using "discriminator": # https://github.com/jhthorsen/swagger2/issues/72 # # http://json.schemastore.org/json-patch.json#/definitions/operation/oneOf/0 # => "patch" # Add, replace or test. # # http://json.schemastore.org/json-patch.json#/definitions/operation/oneOf/1 # => "delete" # DELETE can take a HTTP body, so it can either delete # the whole object, or parts of the object. # http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-19#section-6.7 # # http://json.schemastore.org/json-patch.json#/definitions/operation/oneOf/2 # => Not implemented # use Mojolicious::Lite; eval { plugin Swagger2 => {url => 'data://main/def.json'} }; is $@, '', 'valid swagger spec'; if ($ENV{TEST_ONLINE} == 2) { local $Data::Dumper::Deepcopy = 1; local $Data::Dumper::Indent = 1; local $Data::Dumper::Pair = ': '; local $Data::Dumper::Quotekeys = 1; local $Data::Dumper::Sortkeys = 1; local $Data::Dumper::Terse = 1; local $Data::Dumper::Useqq = 1; diag Data::Dumper::Dumper(JSON::Validator->new->schema("data://main/def.json")->schema->data); } done_testing; __DATA__ @@ def.json { "swagger": "2.0", "info": { "version": "9.1", "title": "Test API for json-patch" }, "paths": { "/some/object": { "delete": { "operationId": "deleteMe", "parameters": [ { "name": "data", "in": "body", "description": "Remove the whole or parts of the object", "schema": { "type": "array", "items": { "$ref": "http://json.schemastore.org/json-patch.json#/definitions/operation/oneOf/1" } } } ], "responses": { "200": { "description": "this is required", "schema": { "type": "object" } } } }, "patch": { "operationId": "patchMe", "parameters": [ { "name": "data", "in": "body", "description": "Add, replace or test", "required": true, "schema": { "type": "array", "items": { "$ref": "http://json.schemastore.org/json-patch.json#/definitions/operation/oneOf/0" } } } ], "responses": { "200": { "description": "this is required", "schema": { "type": "object" } } } } } } } Swagger2-0.73/t/example-lowercase-request-params.t000644 000765 000024 00000001225 12656403247 023320 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use t::Api; use Mojolicious::Lite; plugin Swagger2 => {url => 't/data/petstore.json'}; # This is just an example of a hook to "normalize" all # the input parameters. hook before_routes => sub { my $c = shift; for my $m (qw(body_params query_params)) { my $p = $c->req->$m; $p->param(lc $_ => $p->param($_)) for @{$p->names}; # normalize } }; my $t = Test::Mojo->new; # both "LiMIt" and "limit" are now acceptable $t->get_ok('/api/pets?LiMIt=foo')->status_is(400)->json_is('/errors/0/path', '/limit') ->json_is('/errors/0/message', 'Expected integer - got string.'); done_testing; Swagger2-0.73/t/expand.t000644 000765 000024 00000002017 12656403247 016213 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use Swagger2; my $original = Swagger2->new; my $expanded; $original->load('t/data/petstore.json'); $expanded = $original->expand; is_deeply( $original->api_spec->get('/paths/~1pets/get/responses/200/schema/items'), {'$ref' => '#/definitions/Pet'}, 'original /paths/~1pets/get/responses/200/schema/items' ); is_deeply( $expanded->api_spec->get('/paths/~1pets/get/responses/200/schema/items'), { required => ["id", "name"], properties => {id => {type => "integer", format => "int64"}, name => {type => "string"}, tag => {type => "string"}} }, 'expanded /paths/~1pets/get/responses/200/schema/items' ); ok find_key($original->api_spec->data, '$ref'), '$ref in original'; ok !find_key($expanded->api_spec->data, '$ref'), 'no $ref in expanded'; done_testing; sub find_key { my ($data, $needle) = @_; for my $k (keys %$data) { return 1 if $k eq $needle; return 1 if ref $data->{$k} eq 'HASH' and find_key($data->{$k}, $needle); } return 0; } Swagger2-0.73/t/file.t000644 000765 000024 00000000562 12656403247 015656 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use Mojolicious::Lite; plugin Swagger2 => {url => 't/data/pod-as-string.json'}; my $t = Test::Mojo->new; $t->get_ok('/api/file-example')->status_is(404); $t->post_ok('/api/file-example')->status_is(200)->content_like(qr{This response contains raw binary or text data}); done_testing; Swagger2-0.73/t/formdata.t000644 000765 000024 00000003357 12656403247 016541 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use Test::Warnings; use File::Spec::Functions; use t::Api; use Mojolicious::Lite; plugin Swagger2 => {url => 'data://main/formdata.json'}; my $t = Test::Mojo->new; $t::Api::RES = []; # invalid input $t->post_ok('/api/pets' => form => {id => 123})->status_is(400) ->json_is('/errors/0/message', 'Expected string - got null.')->json_is('/errors/0/path', '/name'); # invalid input $t->post_ok('/api/pets' => form => {id => "invalid", name => "kit-cat"})->status_is(400) ->json_is('/errors/0/message', 'Expected integer - got string.')->json_is('/errors/0/path', '/id'); # valid input and output $t::Api::RES = [{id => 123, name => "kit-cat"}]; $t->post_ok('/api/pets' => form => {id => 123, name => "kit-cat"})->status_is(200)->json_is('/0/id', 123); # do it again to check if clobbered $t->post_ok('/api/pets' => form => {id => 123, name => "kit-cat"})->status_is(200)->json_is('/0/id', 123); done_testing; __DATA__ @@ formdata.json { "swagger" : "2.0", "info" : { "version": "0.8", "title" : "Test API for body parameters" }, "consumes" : [ "application/json" ], "produces" : [ "application/json" ], "schemes" : [ "http" ], "basePath" : "/api", "paths" : { "/pets" : { "post" : { "x-mojo-controller": "t::Api", "operationId" : "addPet", "parameters" : [ { "name" : "name", "type" : "string", "in" : "formData", "required": true }, { "name" : "id", "type" : "integer", "in" : "formData", "required": true } ], "responses" : { "200": { "description": "pet response", "schema": { "type": "array", "items": {} } } } } } } } Swagger2-0.73/t/headers.t000644 000765 000024 00000004147 12656576616 016370 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use t::Api; use Mojolicious::Lite; plugin Swagger2 => {url => 'data://main/headers.json'}; my $t = Test::Mojo->new; $t->get_ok('/api/headers' => {'x-number' => 'x', 'x-string' => '123'})->status_is(400); $t::Api::RES->{header} = 123; $t->get_ok('/api/headers' => {'x-number' => 42.3, 'x-string' => '123'})->status_is(500) ->json_is('/errors/0/message', 'Expected string - got number.'); $t::Api::RES->{header} = '123'; $t->get_ok('/api/headers' => {'x-number' => 42.3, 'x-string' => '123'})->status_is(200)->json_is('/x-number', 42.3) ->header_is('what-ever', '123'); for my $bool (qw( true false 1 0 )) { my $s = $bool =~ /true|1/ ? 'true' : 'false'; $t::Api::RES->{header} = '123'; $t->get_ok('/api/headers' => {'x-bool' => $bool})->status_is(200)->content_like(qr{"x-bool":$s}) ->header_is('x-bool', $s); } done_testing; __DATA__ @@ headers.json { "swagger" : "2.0", "info" : { "version": "9.1", "title" : "Test API for body parameters" }, "consumes" : [ "application/json" ], "produces" : [ "application/json" ], "schemes" : [ "http" ], "basePath" : "/api", "paths" : { "/headers" : { "get" : { "x-mojo-controller": "t::Api", "operationId" : "getHeaders", "parameters" : [ { "in": "header", "name": "x-bool", "type": "boolean", "description": "desc..." }, { "in": "header", "name": "x-number", "type": "number", "description": "desc..." }, { "in": "header", "name": "x-string", "type": "string", "description": "desc..." } ], "responses" : { "200" : { "description": "this is required", "headers": { "$ref": "#/definitions/common_headers/properties" }, "schema": { "type" : "object" } } } } } }, "definitions": { "common_headers": { "properties": { "x-bool": { "type": "boolean" }, "what-ever": { "type": "array", "items": { "type": "string" }, "minItems": 1 } } } } } Swagger2-0.73/t/ip-in-url.t000644 000765 000024 00000001563 12656403247 016555 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use Mojolicious::Lite; plugin Swagger2 => {url => 'data://main/ip-in-url.json'}; my $t = Test::Mojo->new; $t->get_ok('/ip/1.2.3.4/stuff')->status_is(200)->json_is('/ip', '1.2.3.4'); done_testing; __DATA__ @@ ip-in-url.json { "swagger" : "2.0", "info" : { "version" : "0.76", "title" : "Test _not_implemented() in plugin" }, "paths" : { "/ip/{ip}/stuff" : { "get" : { "x-mojo-controller": "t::Api", "operationId" : "IpInUrl", "parameters" : [ { "name": "ip", "type": "string", "in": "path", "required" : true, "x-mojo-placeholder": "#" } ], "responses" : { "200" : { "description" : "", "schema" : { "type": "object" } } } } } } } Swagger2-0.73/t/jv-formats.t000644 000765 000024 00000007714 12656403247 017035 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::More; use Swagger2::SchemaValidator; my $validator = Swagger2::SchemaValidator->new; my $schema = {type => 'object', properties => {v => {type => 'string'}}}; my @errors; { $schema->{properties}{v}{format} = 'byte'; @errors = $validator->validate({v => 'amh0aG9yc2Vu'}, $schema); is "@errors", "", "byte valid"; @errors = $validator->validate({v => "\0"}, $schema); is "@errors", "/v: Does not match byte format.", "byte invalid"; } { $schema->{properties}{v}{format} = 'date'; @errors = $validator->validate({v => '2014-12-09'}, $schema); is "@errors", "", "date valid"; @errors = $validator->validate({v => '2014-12-09T20:49:37Z'}, $schema); is "@errors", "/v: Does not match date format.", "date invalid"; } { $schema->{properties}{v}{format} = 'date-time'; @errors = $validator->validate({v => '2014-12-09T20:49:37Z'}, $schema); is "@errors", "", "date-time valid"; @errors = $validator->validate({v => '20:46:02'}, $schema); is "@errors", "/v: Does not match date-time format.", "date-time invalid"; } { local $schema->{properties}{v}{type} = 'number'; local $schema->{properties}{v}{format} = 'double'; @errors = $validator->validate({v => 1.1000000238418599085576943252817727625370025634765626}, $schema); local $TODO = "cannot test double, since input is already rounded"; is "@errors", "", "positive double valid"; } { local $schema->{properties}{v}{format} = 'email'; @errors = $validator->validate({v => 'jhthorsen@cpan.org'}, $schema); is "@errors", "", "email valid"; @errors = $validator->validate({v => 'foo'}, $schema); is "@errors", "/v: Does not match email format.", "email invalid"; } { local $TODO = 'No idea how to test floats'; local $schema->{properties}{v}{type} = 'number'; local $schema->{properties}{v}{format} = 'float'; @errors = $validator->validate({v => -1.10000002384186}, $schema); is "@errors", "", "negative float valid"; @errors = $validator->validate({v => 1.10000002384186}, $schema); is "@errors", "", "positive float valid"; @errors = $validator->validate({v => 0.10000000000000}, $schema); is "@errors", "/v: Does not match float format.", "float invalid"; } { local $schema->{properties}{v}{format} = 'ipv4'; @errors = $validator->validate({v => '255.100.30.1'}, $schema); is "@errors", "", "ipv4 valid"; @errors = $validator->validate({v => '300.0.0.0'}, $schema); is "@errors", "/v: Does not match ipv4 format.", "ipv4 invalid"; } { local $schema->{properties}{v}{type} = 'integer'; local $schema->{properties}{v}{format} = 'int32'; @errors = $validator->validate({v => -2147483648}, $schema); is "@errors", "", "negative int32 valid"; @errors = $validator->validate({v => 2147483647}, $schema); is "@errors", "", "positive int32 valid"; @errors = $validator->validate({v => 2147483648}, $schema); is "@errors", "/v: Does not match int32 format.", "int32 invalid"; } if (Swagger2::SchemaValidator::IV_SIZE >= 8) { local $schema->{properties}{v}{type} = 'integer'; local $schema->{properties}{v}{format} = 'int64'; @errors = $validator->validate({v => -9223372036854775808}, $schema); is "@errors", "", "negative int64 valid"; @errors = $validator->validate({v => 9223372036854775807}, $schema); is "@errors", "", "positive int64 valid"; @errors = $validator->validate({v => 9223372036854775808}, $schema); is "@errors", "/v: Does not match int64 format.", "int64 invalid"; } { local $schema->{properties}{v}{format} = 'uri'; @errors = $validator->validate({v => 'http://mojolicio.us/?ø=123'}, $schema); is "@errors", "", "uri valid"; local $TODO = "Not sure how to make an invalid URI"; @errors = $validator->validate({v => 'anything'}, $schema); is "@errors", "/v: Does not match uri format.", "uri invalid"; } { local $schema->{properties}{v}{format} = 'unknown'; @errors = $validator->validate({v => 'whatever'}, $schema); is "@errors", "", "unknown is always valid"; } done_testing; Swagger2-0.73/t/lib/000755 000765 000024 00000000000 12660346320 015306 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/not-implemented-501.t000644 000765 000024 00000002417 12656403247 020344 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use Mojolicious::Lite; use t::Api; plugin Swagger2 => {url => 'data://main/not-implemented.json'}; my $t = Test::Mojo->new; $t->get_ok('/not-implemented')->status_is(501) ->json_is('/errors/0/message', 'Controller from operationId "noOp" could not be loaded.') ->json_is('/errors/0/path', '/'); no warnings 'once'; eval 'package t::NotImplemented; use Mojo::Base "Mojolicious::Controller"; $INC{"t/NotImplemented.pm"}=1;'; $t->get_ok('/not-implemented')->status_is(501)->json_is('/errors/0/message', 'Method "no_op" not implemented.'); *t::NotImplemented::no_op = sub { my ($c, $args, $cb) = @_; $c->$cb({}); }; $t->get_ok('/not-implemented')->status_is(200)->content_is('{}'); done_testing; __DATA__ @@ not-implemented.json { "swagger" : "2.0", "info" : { "version": "2.3", "title" : "Test _not_implemented() in plugin" }, "paths" : { "/not-implemented" : { "get" : { "x-mojo-controller": "t::NotImplemented", "operationId" : "noOp", "parameters" : [], "responses" : { "200" : { "description": "default", "schema" : { "type": "object" } } } } } } } Swagger2-0.73/t/nullable.t000644 000765 000024 00000002022 12656403247 016526 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use t::Api; use Mojolicious::Lite; plugin Swagger2 => {url => 'data://main/nullable.json'}; my $t = Test::Mojo->new; $t::Api::RES = {name => 123}; $t->get_ok('/pets')->status_is(500)->json_has('/errors'); $t::Api::RES = {name => 'batman'}; $t->get_ok('/pets')->status_is(200)->content_like(qr/"name":"batman"/); $t::Api::RES = {name => undef}; $t->get_ok('/pets')->status_is(200)->content_like(qr/"name":null/); done_testing; __DATA__ @@ nullable.json { "swagger" : "2.0", "info" : { "version": "9.1", "title" : "Test API for body parameters" }, "paths" : { "/pets" : { "get" : { "x-mojo-controller": "t::Api", "operationId" : "listPets", "responses" : { "200" : { "description": "this is required", "schema": { "type" : "object", "properties" : { "name" : { "type" : ["null", "string"] } } } } } } } } } Swagger2-0.73/t/operation-id.t000644 000765 000024 00000006467 12656576620 017351 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use Mojolicious::Lite; use lib 't/lib'; plugin Swagger2 => {url => 'data://main/petstore.json'}; app->routes->namespaces(['MyApp::Controller']); my $t = Test::Mojo->new; $MyApp::Controller::Pet::RES = [{id => 123, name => 'kit-cat'}]; $t->get_ok('/api/pets')->status_is(200)->json_is('/0/id', 123)->json_is('/0/name', 'kit-cat'); $MyApp::Controller::Pet::RES = {name => 'kit-cat'}; $t->post_ok('/api/pets/42')->status_is(200)->json_is('/id', 42)->json_is('/name', 'kit-cat'); for (qw( Person User Bar Pet Conversation Foo Fs FileSystem )) { eval "package MyApp::Controller::$_; use Mojo::Base 'Mojolicious::Controller';1" or die $@; } is_deeply [ca('childrenOfPerson')], [qw( MyApp::Controller::Person children )], 'childrenOfPerson'; is_deeply [ca('designByUser')], [qw( MyApp::Controller::User design )], 'designByUser'; is_deeply [ca('fooWithBar')], [qw( MyApp::Controller::Bar foo )], 'fooWithBar'; is_deeply [ca('messagesForPet')], [qw( MyApp::Controller::Pet messages )], 'messagesForPet'; is_deeply [ca('peopleInConversation')], [qw( MyApp::Controller::Conversation people )], 'peopleInConversation'; is_deeply [ca('sendToConversation')], [qw( MyApp::Controller::Conversation send )], 'sendToConversation'; is_deeply [ca('showPetsById')], [qw( MyApp::Controller::Pet show )], 'showPetsById'; is_deeply [ca('deleteFromFoo')], [qw( MyApp::Controller::Foo delete )], 'deleteFromFoo'; is_deeply [ca('create_fileInFs')], [qw( MyApp::Controller::Fs create_file )], 'create_fileInFs'; is_deeply [ca('createFileInFileSystem')], [qw( MyApp::Controller::FileSystem create_file )], 'createFileInFileSystem'; is_deeply [ca('removeFromFileSystem')], [qw( MyApp::Controller::FileSystem remove )], 'removeFromFileSystem'; done_testing; sub ca { my $c = $t->app->controller_class->new(app => $t->app); my $m = Mojolicious::Plugin::Swagger2->can('_find_action'); my $e = $m->($c, (my $r = {swagger_operation_spec => {operationId => $_[0]}})); diag $e if $e and $ENV{HARNESS_IS_VERBOSE}; return @$r{qw( controller action )}; } __DATA__ @@ petstore.json { "swagger": "2.0", "info": { "version": "1.0.0", "title": "Swagger Petstore" }, "basePath": "/api", "paths": { "/pets": { "get": { "operationId": "listPets", "responses": { "200": { "description": "pet response", "schema": { "type": "array", "items": { "$ref": "#/definitions/Pet" } } } } } }, "/pets/{petId}": { "post": { "operationId": "showPetById", "parameters": [ { "name": "petId", "in": "path", "required": true, "description": "The id of the pet to receive", "type": "integer" } ], "responses": { "200": { "description": "Expected response to a valid request", "schema": { "$ref": "#/definitions/Pet" } } } } } }, "definitions": { "Pet": { "required": [ "id", "name" ], "properties": { "id": { "type": "integer", "format": "int64" }, "name": { "type": "string" }, "tag": { "type": "string" } } } } } Swagger2-0.73/t/order-pathobjects-lengthwise.t000644 000765 000024 00000003276 12656403247 022532 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Mojolicious; use Test::Mojo; use Test::More; use File::Spec::Functions; use t::Api; #Run this test 11 times, to make sure that we can reproduce the bug which happens 50% of time. #If /pets/{petnumber} is added to Mojolicious before /pets/status, /pets/{petnumber} overlaps #/pets/status and all requests which should go to /pets/status are instead put to /pets/{petnumber}. #Making sure we introduce new routes shortest route first subtest "Lenghtwise Route introduction" => \&testRandomRouteIntroduction; sub testRandomRouteIntroduction { foreach (0 .. 10) { my $app = Mojolicious->new; $app->plugin(Swagger2 => {url => "data://main/lenghtwise.json"}); my $t = Test::Mojo->new($app); $t::Api::CODE = 200; $t::Api::RES = {stat_tus => 'ok'}; $t->get_ok('/api/pets/status')->status_is(200)->json_is('/status/stat_tus', 'ok'); $t->get_ok('/api/pets/5')->status_is(200)->json_is('/stat_tus', 'ok'); } } done_testing; __DATA__ @@ lenghtwise.json { "swagger": "2.0", "info": { "version": "0.9", "title": "sort by length" }, "basePath": "/api", "paths": { "/pets/status": { "get": { "x-mojo-controller": "t::Api", "operationId": "status", "responses": { "200": {"description": "anything"} } } }, "/pets/{petnumber}": { "get": { "x-mojo-controller": "t::Api", "operationId": "getPet", "parameters": [ { "name": "petnumber", "in": "path", "required": true, "type": "integer" } ], "responses": { "200": {"description": "anything"} } } } } } Swagger2-0.73/t/parse-json.t000644 000765 000024 00000001303 12656403247 017012 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions 'catfile'; use Swagger2; my $json_file = catfile qw( t data petstore.json ); my $swagger = Swagger2->new; plan skip_all => "Cannot read $json_file" unless -r $json_file; is $swagger->parse(Mojo::Util::slurp($json_file)), $swagger, 'load()'; is $swagger->api_spec->get('/swagger'), '2.0', 'tree.swagger'; is $swagger->url, 'http://127.0.0.1/#', 'url'; is $swagger->base_url, 'http://petstore.swagger.wordnik.com/api', 'base_url'; like $swagger->to_string, qr{"summary":"finds pets in the system"}, 'to_string'; like $swagger->to_string('json'), qr{"summary":"finds pets in the system"}, 'to_string json'; done_testing; Swagger2-0.73/t/plugin-defaults.t000644 000765 000024 00000002614 12656403247 020042 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use Mojolicious::Lite; plugin Swagger2 => {url => 'data://main/with-defaults.json'}; my $t = Test::Mojo->new; $t->get_ok('/ip?x=123')->status_is(200)->json_is('/ip', '1.2.3.4')->json_is('/x', '123'); $t->get_ok('/ip/2.3.4.5')->status_is(200)->json_is('/ip', '2.3.4.5')->json_is('/x', 'xyz'); $t->get_ok('/ip/2.3.4.5?x')->status_is(200)->json_is('/ip', '2.3.4.5')->json_is('/x', ''); $t->get_ok('/ip/2345')->status_is(400)->json_is('/ip', undef); done_testing; __DATA__ @@ with-defaults.json { "swagger" : "2.0", "info" : { "version": "0.1", "title" : "Test _not_implemented() in plugin" }, "paths" : { "/ip/{ip}" : { "get" : { "x-mojo-controller": "t::Api", "operationId" : "WithDefaults", "parameters" : [ { "name": "ip", "in": "path", "type": "string", "format": "ipv4", "default": "1.2.3.4", "required": true, "x-mojo-placeholder": "#" }, { "name": "x", "in": "query", "type": "string", "default": "xyz" } ], "responses" : { "200" : { "description": "yay!", "schema" : { "type": "object" } } } } } } } Swagger2-0.73/t/plugin-yaml.t000644 000765 000024 00000001714 12656403247 017175 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use Mojolicious; use t::Api; my $n = 0; # # This test checks that "require: false" is indeed false # https://github.com/jhthorsen/swagger2/issues/39 # for my $module (qw( YAML::XS YAML::Syck )) { unless (eval "require $module;1") { diag "Skipping test when $module is not installed"; next; } no warnings 'once'; local *Swagger2::LoadYAML = eval "\\\&$module\::Load"; $n++; diag join ' ', $module, $module->VERSION || 0; my $app = Mojolicious->new; unless (eval { $app->plugin(Swagger2 => {url => 't/data/petstore.yaml'}); 1 }) { diag $@; ok 0, "Could not load Swagger2 plugin using $module"; next; } my $t = Test::Mojo->new($app); $t::Api::RES = [{id => 123, name => "kit-cat"}]; $t->get_ok('/v1/pets')->status_is(200)->json_is('/0/id', 123)->json_is('/0/name', 'kit-cat'); } ok 1, 'no yaml modules available' unless $n; done_testing; Swagger2-0.73/t/plugin.t000644 000765 000024 00000004143 12656623114 016231 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use Mojolicious::Lite; use t::Api; plugin Swagger2 => {url => 't/data/petstore.json'}; hook around_action => sub { my ($next, $c) = @_; $c->stash(petId => 'will_not_change_id_from_path'); $next->(); }; my $t = Test::Mojo->new; $t::Api::RES = [{foo => 123, name => "kit-cat"}]; $t->get_ok('/api/pets')->status_is(500)->json_is('/errors/0/path', '/0/id') ->json_is('/errors/0/message', 'Missing property.')->json_is('/errors/1', undef); $t::Api::RES = [{id => "123", name => "kit-cat"}]; $t->get_ok('/api/pets')->status_is(500)->json_is('/errors/0/path', '/0/id') ->json_is('/errors/0/message', 'Expected integer - got string.')->json_is('/errors/1', undef); $t::Api::RES = [{id => 123, name => "kit-cat"}]; $t->get_ok('/api/pets')->status_is(200)->json_is('/0/id', 123)->json_is('/0/name', 'kit-cat'); $t::Api::RES = [{id => 123, name => "kit-cat"}]; $t->get_ok('/api/pets?limit=foo')->status_is(400)->json_is('/errors/0/path', '/limit') ->json_is('/errors/0/message', 'Expected integer - got string.')->json_is('/errors/1', undef); # Allow negative integers in query string $t->get_ok('/api/pets?limit=-100')->status_is(200); $t::Api::RES = {name => "kit-cat"}; $t->post_ok('/api/pets/42')->status_is(200)->json_is('/id', 42)->json_is('/name', 'kit-cat'); $t->post_ok('/api/pets/foo')->status_is(400)->json_is('/errors/0/path', '/petId') ->json_is('/errors/0/message', 'Expected integer - got string.')->json_is('/errors/1', undef); $t->get_ok('/api')->status_is(200)->json_is('/info/title', 'Swagger Petstore'); my $api_spec = $t->tx->res->json; like $api_spec->{host}, qr{:\d+$}, 'petstore.swagger.wordnik.com is replaced'; ok !exists $api_spec->{'id'}, 'no id in expanded spec'; ok !exists $api_spec->{'paths'}{'/pets'}{'x-mojo-controller'}, 'no x-mojo-controller in expanded spec'; ok !exists $api_spec->{'paths'}{'/pets'}{'x-mojo-around-action'}, 'no x-mojo-around-action in expanded spec'; { local $TODO = 'Should rendered spec contain x-mojo-?'; $t->json_is('/paths/~1pets/get/x-mojo-controller', 't::Api'); } done_testing; Swagger2-0.73/t/pod-as-string.t000644 000765 000024 00000002605 12656403247 017426 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Mojo::Util 'slurp'; use Test::More; use Swagger2; use File::Spec::Functions 'catfile'; my $pod_file = catfile qw( t data pod-as-string.pod ); plan skip_all => "Cannot read $pod_file" unless -r $pod_file; my @expected = split /\n/, slurp $pod_file; my $swagger = Swagger2->new->load('t/data/pod-as-string.json'); my $pod = $swagger->pod; my $fail = 0; my $node; isa_ok($pod, 'Swagger2::POD'); my $i = 0; for my $line (split /\n/, $pod->to_string) { my $expected = shift @expected; my $desc = $line; $desc =~ s/[^\w\s]//g; $i++; next unless $desc =~ /\w/; is $line, $expected, "$i: $desc" or $fail = 1; } if ($fail and $ENV{PRINT_DOC}) { print $pod->to_string; } local $TODO = 'do not think this is supported'; $swagger = Swagger2->new->load('t/data/pod-as-string.json'); $node = $swagger->api_spec->data->{paths}{'/any-of'}{get}{responses}{200}{schema}{properties}{identifier}; $node->{allOf} = delete $node->{anyOf}; like $swagger->pod->to_string, qr{// All of the below:}, 'allOf'; local $TODO = 'do not think this is supported'; $swagger = Swagger2->new->load('t/data/pod-as-string.json'); $node = $swagger->api_spec->data->{paths}{'/any-of'}{get}{responses}{200}{schema}{properties}{identifier}; $node->{oneOf} = delete $node->{anyOf}; like $swagger->pod->to_string, qr{// One of the below:}, 'oneOf'; done_testing; Swagger2-0.73/t/read-only-property.t000644 000765 000024 00000003514 12656403247 020513 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use Mojolicious::Lite; plugin Swagger2 => {url => 'data://main/ro.json'}; my $t = Test::Mojo->new; $t->post_ok('/pets', json => {})->status_is(400) ->json_is('/errors', [{message => 'Missing property.', path => '/body/name'}]); $t->post_ok('/pets', json => {name => 'batman'})->status_is(200); $t->post_ok('/pets', json => {name => 'batman', id => 123}) ->json_is('/errors/0', {message => 'Read-only.', path => '/body/id'}); $t->get_ok('/pet/123')->status_is(500)->json_is('/errors', [{message => 'Missing property.', path => '/name'}]) ->content_unlike(qr{\W+id}); done_testing; __DATA__ @@ ro.json { "swagger" : "2.0", "info" : { "version" : "0.76", "title" : "Test readOnly in properties" }, "paths" : { "/pets" : { "post" : { "x-mojo-controller": "t::Api", "operationId" : "addPet", "parameters" : [ { "in": "body", "name": "body", "schema": { "$ref": "#/definitions/User" }, "required": true } ], "responses" : { "200" : { "schema" : { "type": "object" }, "description" : "" } } } }, "/pet/{petId}" : { "get": { "x-mojo-controller": "t::Api", "operationId" : "showPetById", "parameters" : [ { "name": "petId", "in": "path", "type": "integer", "required": true } ], "responses" : { "200" : { "schema" : { "$ref": "#/definitions/User" }, "description" : "" } } } } }, "definitions": { "User": { "required": [ "id", "name" ], "properties": { "id": { "type": "number", "readOnly": true }, "name": { "type": "string" } } } } } Swagger2-0.73/t/stash-defaults.t000644 000765 000024 00000001737 12656403247 017673 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use t::Api; my $stash; use Mojolicious::Lite; plugin 'Swagger2' => {url => "data://main/stash.json"}; hook after_dispatch => sub { $stash = shift->stash }; $t::Api::CODE = 200; Test::Mojo->new->get_ok('/api/pets')->status_is(200); ok +UNIVERSAL::isa($stash->{swagger}, 'Swagger2'), 'swagger is set in stash'; is $stash->{swagger}->api_spec->get('/basePath'), '/api', 'basePath'; ok +UNIVERSAL::isa($stash->{swagger_operation_spec}, 'HASH'), 'swagger_operation_spec is set in stash'; is $stash->{swagger_operation_spec}{operationId}, 'listPets', 'operationId'; done_testing; __DATA__ @@ stash.json { "swagger": "2.0", "info": { "version": "0.3", "title": "required to write" }, "basePath": "/api", "paths": { "/pets": { "get": { "x-mojo-controller": "t::Api", "operationId": "listPets", "responses": { "200": {"description": "anything"} } } } } } Swagger2-0.73/t/swagger.t000644 000765 000024 00000001134 12656403247 016372 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::More; use Swagger2; my $swagger = Swagger2->new; isa_ok($swagger->url, 'Mojo::URL'); isa_ok($swagger->base_url, 'Mojo::URL'); isa_ok($swagger->api_spec, 'Mojo::JSON::Pointer'); isa_ok($swagger->tree, 'Mojo::JSON::Pointer'); isa_ok($swagger->ua, 'Mojo::UserAgent'); is $swagger->url, '', 'no default url'; $swagger = Swagger2->new('http://example.com/api-spec'); is $swagger->url, 'http://example.com/api-spec', 'url from new()'; like $swagger->javascript_client->slurp, qr{license Artistic License version}, 'javascript_client license'; done_testing; Swagger2-0.73/t/validate.t000644 000765 000024 00000001264 12656403247 016530 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use Swagger2; my $swagger = Swagger2->new('t/data/validate.json'); my @errors = $swagger->validate; is_deeply \@errors, [], 'petstore.json' or diag join "\n", @errors; $swagger = Swagger2->new('t/data/validate.json'); local $swagger->api_spec->data->{foo} = 123; @errors = $swagger->validate; is_deeply \@errors, ['/: Properties not allowed: foo.'], 'petstore.json with foo' or diag join "\n", @errors; $swagger = Swagger2->new('t/data/validate.json'); local $swagger->api_spec->data->{info}{'x-foo'} = 123; @errors = $swagger->validate; is_deeply \@errors, [], 'petstore.json with x-foo' or diag join "\n", @errors; done_testing; Swagger2-0.73/t/websocket.t000644 000765 000024 00000005653 12656403247 016733 0ustar00jhthorsenstaff000000 000000 use Mojo::Base -strict; use Test::Mojo; use Test::More; use File::Spec::Functions; use Mojolicious::Lite; use lib catdir qw( t lib ); my $ws = app->routes->websocket('/ws')->to( cb => sub { shift->on( json => sub { my ($c, $data) = @_; return if $c->dispatch_to_swagger($data); return $c->send({json => {errors => [{message => 'Unable to dispatch_to_swagger', path => ''}]}}); } ); } ); plugin Swagger2 => {url => 'data://main/petstore.json', ws => $ws}; app->routes->namespaces(['MyApp::Controller']); my $t = Test::Mojo->new; $t->websocket_ok('/ws'); $t->send_ok({json => {id => 42, op => 'foo', params => {}}})->message_ok->json_message_is('/id', 42) ->json_message_is('/code', 400)->json_message_is('/body/errors/0/message', 'Unknown operationId.'); $MyApp::Controller::Pet::RES = [{foo => 123, name => 'kit-cat'}]; $t->send_ok({json => {id => 43, op => 'listPets', params => {}}})->message_ok->json_message_is('/id', 43) ->json_message_is('/code', 200)->json_message_is('/body/0/name', 'kit-cat'); $MyApp::Controller::Pet::RES = [{id => '123', name => 'kit-cat'}]; $t->send_ok({json => {id => 44, op => 'listPets', params => {}}})->message_ok->json_message_is('/id', 44) ->json_message_is('/code', 500)->json_message_is('/body/errors/0/message', 'Expected integer - got string.'); $MyApp::Controller::Pet::RES = {id => 123, name => 'kit-cat'}; $t->send_ok({json => {id => 44, op => 'updatePetById', params => {petId => 'foo'}}}) ->message_ok->json_message_is('/id', 44)->json_message_is('/code', 400) ->json_message_is('/body/errors/0/path', '/petId') ->json_message_is('/body/errors/0/message', 'Expected integer - got string.'); $t->send_ok({json => {id => 45, op => 'updatePetById', params => {petId => 123}}}) ->message_ok->json_message_is('/id', 45)->json_message_is('/code', 200); done_testing; __DATA__ @@ petstore.json { "swagger": "2.0", "info": { "version": "1.0.0", "title": "Swagger Petstore" }, "basePath": "/api", "paths": { "/pets": { "get": { "operationId": "listPets", "responses": { "200": { "description": "pet response", "schema": { "type": "array", "items": { "$ref": "#/definitions/Pet" } } } } } }, "/pets/{petId}": { "post": { "operationId": "updatePetById", "parameters": [ { "name": "petId", "in": "path", "required": true, "description": "The id of the pet to receive", "type": "integer" } ], "responses": { "200": { "description": "Expected response to a valid request", "schema": { "$ref": "#/definitions/Pet" } } } } } }, "definitions": { "Pet": { "required": [ "id", "name" ], "properties": { "id": { "type": "integer", "format": "int64" }, "name": { "type": "string" }, "tag": { "type": "string" } } } } } Swagger2-0.73/t/lib/MyApp/000755 000765 000024 00000000000 12660346320 016334 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/lib/MyApp/Controller/000755 000765 000024 00000000000 12660346320 020457 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/lib/MyApp/Controller/Pet.pm000644 000765 000024 00000001157 12656403247 021560 0ustar00jhthorsenstaff000000 000000 package MyApp::Controller::Pet; use Mojo::Base 'Mojolicious::Controller'; our $RES = [{id => 123, name => 'kit-cat'}]; our $CODE = 200; sub list { my ($c, $args, $cb) = @_; $c->$cb($RES, $CODE); } sub show { my ($c, $args, $cb) = @_; $RES->{id} = $args->{petId}; $c->$cb($RES, $CODE); } sub get { my ($c, $args, $cb) = @_; return $c->$cb('', 201) if $CODE eq '201'; return $c->$cb($RES, $CODE); } sub add { my ($c, $args, $cb) = @_; $RES->{name} = $args->{data}{name} if ref $args->{data} eq 'HASH'; $c->$cb($RES, $CODE); } sub update { my ($c, $args, $cb) = @_; $c->$cb($RES, $CODE); } 1; Swagger2-0.73/t/data/petstore.json000644 000765 000024 00000006420 12656641075 020225 0ustar00jhthorsenstaff000000 000000 { "swagger": "2.0", "info": { "version": "1.0.0", "title": "Swagger Petstore", "contact": { "name": "wordnik api team", "url": "http://developer.wordnik.com" }, "license": { "name": "Creative Commons 4.0 International", "url": "http://creativecommons.org/licenses/by/4.0/" } }, "host": "petstore.swagger.wordnik.com", "basePath": "/api", "schemes": [ "http" ], "parameters": { "limit": { "name": "limit", "in": "query", "description": "How many items to return at one time (max 100)", "type": "integer", "format": "int32" } }, "paths": { "/pets": { "x-something-something": { "x-nothing-here" : "No, really!" }, "get": { "x-mojo-controller": "t::Api", "tags": [ "pets" ], "summary": "finds pets in the system", "operationId": "listPets", "parameters": [ { "$ref": "#/parameters/limit" } ], "responses": { "200": { "description": "pet response", "schema": { "type": "array", "items": { "$ref": "#/definitions/Pet" } }, "headers": { "x-expires": { "type": "string" } } }, "default": { "description": "unexpected error", "schema": { "$ref": "https://raw.githubusercontent.com/jhthorsen/swagger2/master/lib/Swagger2/error.json" } } } }, "post": { "x-mojo-controller": "t::Api", "tags": [ "pets" ], "summary": "add pets to the system", "operationId": "addPet", "parameters": [ { "name": "data", "in": "body", "required": true, "schema": { "type": "object", "properties": { "name": { "type": "string" }, "tag": { "type": "string" } } } } ], "responses": { "200": { "description": "pet response", "schema": { "$ref": "#/definitions/Pet" } }, "default": { "description": "unexpected error", "schema": { "$ref": "http://git.io/vcKD4#" } } } } }, "/pets/{petId}": { "post": { "x-mojo-controller": "t::Api", "tags": [ "pets" ], "summary": "Info for a specific pet", "operationId": "showPetById", "parameters": [ { "name": "petId", "in": "path", "required": true, "description": "The id of the pet to receive", "type": "integer" } ], "responses": { "200": { "description": "Expected response to a valid request", "schema": { "$ref": "#/definitions/Pet" } }, "default": { "description": "unexpected error", "schema": { "$ref": "http://git.io/vcKD4#" } } } } } }, "definitions": { "Pet": { "required": [ "id", "name" ], "properties": { "id": { "type": "integer", "format": "int64" }, "name": { "type": "string" }, "tag": { "type": "string" } } } } } Swagger2-0.73/t/data/petstore.yaml000644 000765 000024 00000004226 12656403247 020215 0ustar00jhthorsenstaff000000 000000 --- swagger: "2.0" info: version: 1.0.0 title: Swagger Petstore license: name: MIT host: petstore.swagger.wordnik.com basePath: /v1 schemes: - http consumes: - application/json produces: - application/json paths: /pets: x-something-something: x-nothing-here: No, really! get: x-mojo-controller: "t::Api" summary: List all pets operationId: listPets tags: - pets parameters: - name: limit in: query description: How many items to return at one time (max 100) type: integer format: int32 responses: 200: description: An paged array of pets headers: x-next: type: string description: A link to the next page of responses schema: $ref: Pets default: description: unexpected error schema: $ref: Error post: x-mojo-controller: "t::Api" summary: Create a pet operationId: createPets tags: - pets responses: 201: description: Null response default: description: unexpected error schema: $ref: Error "/pets/{petId}": get: x-mojo-controller: "t::Api" summary: Info for a specific pet operationId: showPetById tags: - pets parameters: - name: petId in: path description: The id of the pet to retrieve required: true type: string responses: 200: description: Expected response to a valid request schema: $ref: Pets default: description: unexpected error schema: $ref: Error definitions: Pet: required: - id - name properties: id: type: integer format: int64 name: type: string tag: type: string Pets: type: array items: $ref: Pet Error: required: - code - message properties: code: type: integer format: int32 message: type: string Swagger2-0.73/t/data/pod-as-string.json000644 000765 000024 00000004104 12656403247 021041 0ustar00jhthorsenstaff000000 000000 { "swagger" : "2.0", "info" : { "version" : "1.2", "title" : "To the pod racer!", "description" : "Test API for body parameters" }, "consumes" : [ "application/json" ], "produces" : [ "application/json" ], "schemes" : [ "http" ], "basePath" : "/api", "paths" : { "/any-of" : { "get": { "x-mojo-controller": "t::Api", "operationId" : "testAnyOf", "responses" : { "200": { "description": "any-of", "schema": { "type": "object", "properties": { "identifier": { "type": ["integer", "string"] } } } } } } }, "/file-example": { "post": { "x-mojo-controller": "t::Api", "operationId" : "testFile", "responses": { "200": { "description": "file", "schema": { "type": "file" } } } } }, "/pets" : { "post" : { "responses" : { "200": { "description": "pet response", "schema": { "type": "array", "items": { "$ref": "#/definitions/Pet" } }, "headers": { "x-expires": { "type": "string" } } } }, "tags" : [ "pet" ], "summary" : "Add a new pet to the store", "parameters" : [ { "name" : "pet", "schema" : { "$ref" : "#/definitions/Pet" }, "in" : "body", "description" : "Pet object that needs to be added to the store" } ], "description" : "", "x-mojo-controller": "t::Api", "operationId" : "addPet" } } }, "definitions" : { "Pet" : { "required" : [ "name" ], "properties" : { "id" : { "format" : "int64", "type" : "integer", "description" : "Pet ID" }, "name" : { "type" : "string", "description" : "Pet name" } } } } } Swagger2-0.73/t/data/pod-as-string.pod000644 000765 000024 00000002754 12656403247 020663 0ustar00jhthorsenstaff000000 000000 =head1 NAME To the pod racer! =head1 VERSION 1.2 =head1 DESCRIPTION Test API for body parameters =head1 BASEURL L =head1 RESOURCES =head2 addPet Add a new pet to the store =head3 Resource URL POST http://example.com/api/pets =head3 Parameters .----------------------------------------------------------------------------------. | Name | In | Type | Required | Description | |----------------------------------------------------------------------------------| | pet | body | schema | Yes | Pet object that needs to be added to the store | '----------------------------------------------------------------------------------' pet: { "id": int64, // Pet ID "name": string, // Pet name }, =head3 Responses =head4 200 - OK pet response [ { "id": int64, // Pet ID "name": string, // Pet name }, ... ] =head2 testAnyOf No description. =head3 Resource URL GET http://example.com/api/any-of =head3 Parameters This resource takes no parameters. =head3 Responses =head4 200 - OK any-of { "identifier": {integer,string}, }, =head2 testFile No description. =head3 Resource URL POST http://example.com/api/file-example =head3 Parameters This resource takes no parameters. =head3 Responses =head4 200 - OK file This response contains raw binary or text data. =head1 COPYRIGHT AND LICENSE Unknown author BSD - http://www.linfo.org/bsdlicense.html =cut Swagger2-0.73/t/data/validate.json000644 000765 000024 00000072656 12656403247 020164 0ustar00jhthorsenstaff000000 000000 { "securityDefinitions" : { "api_key" : { "in" : "header", "name" : "api_key", "type" : "apiKey" }, "petstore_auth" : { "authorizationUrl" : "http://petstore.swagger.io/api/oauth/dialog", "scopes" : { "write:pets" : "modify pets in your account", "read:pets" : "read your pets" }, "type" : "oauth2", "flow" : "implicit" } }, "swagger" : "2.0", "definitions" : { "Pet" : { "type" : "object", "required" : [ "name", "photoUrls" ], "xml" : { "name" : "Pet" }, "properties" : { "photoUrls" : { "xml" : { "wrapped" : true, "name" : "photoUrl" }, "type" : "array", "items" : { "type" : "string" } }, "name" : { "example" : "doggie", "type" : "string" }, "id" : { "format" : "int64", "type" : "integer" }, "status" : { "type" : "string", "description" : "pet status in the store", "enum" : [ "available", "pending", "sold" ] }, "tags" : { "items" : { "$ref" : "#/definitions/Tag" }, "type" : "array", "xml" : { "wrapped" : true, "name" : "tag" } }, "category" : { "$ref" : "#/definitions/Category" } } }, "Order" : { "type" : "object", "properties" : { "shipDate" : { "type" : "string", "format" : "date-time" }, "petId" : { "type" : "integer", "format" : "int64" }, "id" : { "format" : "int64", "type" : "integer" }, "complete" : { "type" : "boolean", "default" : false }, "status" : { "enum" : [ "placed", "approved", "delivered" ], "description" : "Order Status", "type" : "string" }, "quantity" : { "type" : "integer", "format" : "int32" } }, "xml" : { "name" : "Order" } }, "User" : { "properties" : { "userStatus" : { "format" : "int32", "description" : "User Status", "type" : "integer" }, "email" : { "type" : "string" }, "phone" : { "type" : "string" }, "id" : { "type" : "integer", "format" : "int64" }, "username" : { "type" : "string" }, "lastName" : { "type" : "string" }, "firstName" : { "type" : "string" }, "password" : { "type" : "string" } }, "xml" : { "name" : "User" }, "type" : "object" }, "ApiResponse" : { "type" : "object", "properties" : { "message" : { "type" : "string" }, "type" : { "type" : "string" }, "code" : { "type" : "integer", "format" : "int32" } } }, "Tag" : { "type" : "object", "properties" : { "name" : { "type" : "string" }, "id" : { "format" : "int64", "type" : "integer" } }, "xml" : { "name" : "Tag" } }, "Category" : { "type" : "object", "xml" : { "name" : "Category" }, "properties" : { "name" : { "type" : "string" }, "id" : { "type" : "integer", "format" : "int64" } } } }, "externalDocs" : { "url" : "http://swagger.io", "description" : "Find out more about Swagger" }, "schemes" : [ "http" ], "basePath" : "/v2", "host" : "petstore.swagger.io", "paths" : { "/pet/{petId}/uploadImage" : { "post" : { "consumes" : [ "multipart/form-data" ], "description" : "", "produces" : [ "application/json" ], "tags" : [ "pet" ], "security" : [ { "petstore_auth" : [ "write:pets", "read:pets" ] } ], "operationId" : "uploadFile", "summary" : "uploads an image", "parameters" : [ { "format" : "int64", "in" : "path", "required" : true, "name" : "petId", "description" : "ID of pet to update", "type" : "integer" }, { "in" : "formData", "type" : "string", "description" : "Additional data to pass to server", "name" : "additionalMetadata", "required" : false }, { "in" : "formData", "type" : "file", "description" : "file to upload", "name" : "file", "required" : false } ], "responses" : { "200" : { "description" : "successful operation", "schema" : { "$ref" : "#/definitions/ApiResponse" } } } } }, "/user" : { "post" : { "parameters" : [ { "in" : "body", "required" : true, "name" : "body", "description" : "Created user object", "schema" : { "$ref" : "#/definitions/User" } } ], "responses" : { "default" : { "description" : "successful operation" } }, "operationId" : "createUser", "summary" : "Create user", "tags" : [ "user" ], "produces" : [ "application/xml", "application/json" ], "description" : "This can only be done by the logged in user." } }, "/user/{username}" : { "get" : { "description" : "", "produces" : [ "application/xml", "application/json" ], "summary" : "Get user by user name", "operationId" : "getUserByName", "tags" : [ "user" ], "responses" : { "404" : { "description" : "User not found" }, "200" : { "schema" : { "$ref" : "#/definitions/User" }, "description" : "successful operation" }, "400" : { "description" : "Invalid username supplied" } }, "parameters" : [ { "name" : "username", "required" : true, "type" : "string", "description" : "The name that needs to be fetched. Use user1 for testing. ", "in" : "path" } ] }, "delete" : { "description" : "This can only be done by the logged in user.", "produces" : [ "application/xml", "application/json" ], "summary" : "Delete user", "operationId" : "deleteUser", "tags" : [ "user" ], "responses" : { "404" : { "description" : "User not found" }, "400" : { "description" : "Invalid username supplied" } }, "parameters" : [ { "in" : "path", "name" : "username", "required" : true, "type" : "string", "description" : "The name that needs to be deleted" } ] }, "put" : { "description" : "This can only be done by the logged in user.", "produces" : [ "application/xml", "application/json" ], "operationId" : "updateUser", "summary" : "Updated user", "tags" : [ "user" ], "parameters" : [ { "description" : "name that need to be deleted", "type" : "string", "required" : true, "name" : "username", "in" : "path" }, { "in" : "body", "schema" : { "$ref" : "#/definitions/User" }, "description" : "Updated user object", "required" : true, "name" : "body" } ], "responses" : { "404" : { "description" : "User not found" }, "400" : { "description" : "Invalid user supplied" } } } }, "/user/logout" : { "get" : { "operationId" : "logoutUser", "summary" : "Logs out current logged in user session", "tags" : [ "user" ], "parameters" : [], "responses" : { "default" : { "description" : "successful operation" } }, "description" : "", "produces" : [ "application/xml", "application/json" ] } }, "/user/createWithArray" : { "post" : { "produces" : [ "application/xml", "application/json" ], "description" : "", "parameters" : [ { "in" : "body", "required" : true, "name" : "body", "description" : "List of user object", "schema" : { "type" : "array", "items" : { "$ref" : "#/definitions/User" } } } ], "responses" : { "default" : { "description" : "successful operation" } }, "operationId" : "createUsersWithArrayInput", "tags" : [ "user" ], "summary" : "Creates list of users with given input array" } }, "/pet" : { "put" : { "produces" : [ "application/xml", "application/json" ], "description" : "", "consumes" : [ "application/json", "application/xml" ], "security" : [ { "petstore_auth" : [ "write:pets", "read:pets" ] } ], "tags" : [ "pet" ], "responses" : { "404" : { "description" : "Pet not found" }, "405" : { "description" : "Validation exception" }, "400" : { "description" : "Invalid ID supplied" } }, "parameters" : [ { "schema" : { "$ref" : "#/definitions/Pet" }, "required" : true, "name" : "body", "description" : "Pet object that needs to be added to the store", "in" : "body" } ], "summary" : "Update an existing pet", "operationId" : "updatePet" }, "post" : { "responses" : { "405" : { "description" : "Invalid input" } }, "parameters" : [ { "in" : "body", "schema" : { "$ref" : "#/definitions/Pet" }, "name" : "body", "required" : true, "description" : "Pet object that needs to be added to the store" } ], "operationId" : "addPet", "summary" : "Add a new pet to the store", "security" : [ { "petstore_auth" : [ "write:pets", "read:pets" ] } ], "tags" : [ "pet" ], "produces" : [ "application/xml", "application/json" ], "consumes" : [ "application/json", "application/xml" ], "description" : "" } }, "/pet/findByStatus" : { "get" : { "operationId" : "findPetsByStatus", "summary" : "Finds Pets by status", "parameters" : [ { "items" : { "enum" : [ "available", "pending", "sold" ], "type" : "string", "default" : "available" }, "description" : "Status values that need to be considered for filter", "type" : "array", "required" : true, "collectionFormat" : "csv", "name" : "status", "in" : "query" } ], "responses" : { "200" : { "schema" : { "items" : { "$ref" : "#/definitions/Pet" }, "type" : "array" }, "description" : "successful operation" }, "400" : { "description" : "Invalid status value" } }, "tags" : [ "pet" ], "security" : [ { "petstore_auth" : [ "write:pets", "read:pets" ] } ], "description" : "Multiple status values can be provided with comma seperated strings", "produces" : [ "application/xml", "application/json" ] } }, "/store/inventory" : { "get" : { "summary" : "Returns pet inventories by status", "operationId" : "getInventory", "responses" : { "200" : { "description" : "successful operation", "schema" : { "type" : "object", "additionalProperties" : { "format" : "int32", "type" : "integer" } } } }, "parameters" : [], "description" : "Returns a map of status codes to quantities", "produces" : [ "application/json" ], "tags" : [ "store" ], "security" : [ { "api_key" : [] } ] } }, "/pet/{petId}" : { "delete" : { "tags" : [ "pet" ], "security" : [ { "petstore_auth" : [ "write:pets", "read:pets" ] } ], "description" : "", "produces" : [ "application/xml", "application/json" ], "summary" : "Deletes a pet", "operationId" : "deletePet", "parameters" : [ { "type" : "string", "name" : "api_key", "required" : false, "in" : "header" }, { "type" : "integer", "description" : "Pet id to delete", "required" : true, "name" : "petId", "format" : "int64", "in" : "path" } ], "responses" : { "400" : { "description" : "Invalid pet value" } } }, "get" : { "security" : [ { "api_key" : [] } ], "tags" : [ "pet" ], "produces" : [ "application/xml", "application/json" ], "description" : "Returns a single pet", "responses" : { "200" : { "schema" : { "$ref" : "#/definitions/Pet" }, "description" : "successful operation" }, "404" : { "description" : "Pet not found" }, "400" : { "description" : "Invalid ID supplied" } }, "parameters" : [ { "format" : "int64", "in" : "path", "description" : "ID of pet to return", "type" : "integer", "name" : "petId", "required" : true } ], "summary" : "Find pet by ID", "operationId" : "getPetById" }, "post" : { "parameters" : [ { "format" : "int64", "in" : "path", "name" : "petId", "required" : true, "description" : "ID of pet that needs to be updated", "type" : "integer" }, { "in" : "formData", "required" : false, "name" : "name", "description" : "Updated name of the pet", "type" : "string" }, { "required" : false, "name" : "status", "description" : "Updated status of the pet", "type" : "string", "in" : "formData" } ], "responses" : { "405" : { "description" : "Invalid input" } }, "summary" : "Updates a pet in the store with form data", "operationId" : "updatePetWithForm", "produces" : [ "application/xml", "application/json" ], "description" : "", "consumes" : [ "application/x-www-form-urlencoded" ], "security" : [ { "petstore_auth" : [ "write:pets", "read:pets" ] } ], "tags" : [ "pet" ] } }, "/pet/findByTags" : { "get" : { "tags" : [ "pet" ], "security" : [ { "petstore_auth" : [ "write:pets", "read:pets" ] } ], "description" : "Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing.", "produces" : [ "application/xml", "application/json" ], "operationId" : "findPetsByTags", "summary" : "Finds Pets by tags", "responses" : { "200" : { "schema" : { "type" : "array", "items" : { "$ref" : "#/definitions/Pet" } }, "description" : "successful operation" }, "400" : { "description" : "Invalid tag value" } }, "parameters" : [ { "name" : "tags", "collectionFormat" : "csv", "required" : true, "description" : "Tags to filter by", "type" : "array", "items" : { "type" : "string" }, "in" : "query" } ] } }, "/user/login" : { "get" : { "summary" : "Logs user into the system", "operationId" : "loginUser", "tags" : [ "user" ], "responses" : { "200" : { "description" : "successful operation", "schema" : { "type" : "string" }, "headers" : { "X-Expires-After" : { "description" : "date in UTC when toekn expires", "type" : "string", "format" : "date-time" }, "X-Rate-Limit" : { "description" : "calls per hour allowed by the user", "type" : "integer", "format" : "int32" } } }, "400" : { "description" : "Invalid username/password supplied" } }, "parameters" : [ { "in" : "query", "required" : true, "name" : "username", "type" : "string", "description" : "The user name for login" }, { "type" : "string", "description" : "The password for login in clear text", "required" : true, "name" : "password", "in" : "query" } ], "description" : "", "produces" : [ "application/xml", "application/json" ] } }, "/user/createWithList" : { "post" : { "responses" : { "default" : { "description" : "successful operation" } }, "parameters" : [ { "in" : "body", "schema" : { "items" : { "$ref" : "#/definitions/User" }, "type" : "array" }, "name" : "body", "required" : true, "description" : "List of user object" } ], "operationId" : "createUsersWithListInput", "summary" : "Creates list of users with given input array", "tags" : [ "user" ], "produces" : [ "application/xml", "application/json" ], "description" : "" } }, "/store/order" : { "post" : { "description" : "", "produces" : [ "application/xml", "application/json" ], "summary" : "Place an order for a pet", "operationId" : "placeOrder", "tags" : [ "store" ], "responses" : { "200" : { "schema" : { "$ref" : "#/definitions/Order" }, "description" : "successful operation" }, "400" : { "description" : "Invalid Order" } }, "parameters" : [ { "in" : "body", "schema" : { "$ref" : "#/definitions/Order" }, "required" : true, "name" : "body", "description" : "order placed for purchasing the pet" } ] } }, "/store/order/{orderId}" : { "delete" : { "description" : "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", "produces" : [ "application/xml", "application/json" ], "operationId" : "deleteOrder", "tags" : [ "store" ], "summary" : "Delete purchase order by ID", "parameters" : [ { "description" : "ID of the order that needs to be deleted", "type" : "string", "name" : "orderId", "required" : true, "in" : "path", "minimum" : 1 } ], "responses" : { "404" : { "description" : "Order not found" }, "400" : { "description" : "Invalid ID supplied" } } }, "get" : { "description" : "For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions", "produces" : [ "application/xml", "application/json" ], "operationId" : "getOrderById", "summary" : "Find purchase order by ID", "tags" : [ "store" ], "responses" : { "400" : { "description" : "Invalid ID supplied" }, "200" : { "description" : "successful operation", "schema" : { "$ref" : "#/definitions/Order" } }, "404" : { "description" : "Order not found" } }, "parameters" : [ { "type" : "integer", "description" : "ID of pet that needs to be fetched", "required" : true, "name" : "orderId", "in" : "path", "minimum" : 1, "format" : "int64", "maximum" : 5 } ] } } }, "info" : { "contact" : { "email" : "apiteam@swagger.io" }, "version" : "1.0.0", "description" : "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.", "title" : "Swagger Petstore", "license" : { "name" : "Apache 2.0", "url" : "http://www.apache.org/licenses/LICENSE-2.0.html" }, "termsOfService" : "http://swagger.io/terms/" }, "tags" : [ { "externalDocs" : { "description" : "Find out more", "url" : "http://swagger.io" }, "name" : "pet", "description" : "Everything about your Pets" }, { "description" : "Access to Petstore orders", "name" : "store" }, { "description" : "Operations about user", "externalDocs" : { "url" : "http://swagger.io", "description" : "Find out more about our store" }, "name" : "user" } ] } Swagger2-0.73/t/blog/2015-yapc-eu-slides.pdf000644 000765 000024 00002121444 12656403247 021406 0ustar00jhthorsenstaff000000 000000 %PDF-1.3 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream x]AO [v{D=sӰn V6jd3c3"/)";Sj3*v;u]l"Ibe\.\w8GɆ޾C*ZT@adܰ*tS0֛ol]0) ]gm˖ cb&8%MX W/> endobj 6 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 10 0 R >> /XObject << /Im2 11 0 R /Im3 13 0 R /Im1 8 0 R >> >> endobj 11 0 obj << /Length 12 0 R /Type /XObject /Subtype /Image /Width 453 /Height 260 /Interpolate true /ColorSpace 7 0 R /Intent /Perceptual /BitsPerComponent 8 /Filter /FlateDecode >> stream xܝǕger,Yg[gپ߶ m9Hw;[!B dE`,9gvvA rvUĝaZjzޫz{^U[^/=ŠПBrfׂr}{j/ܗ"j3ihe%#wc%\][+ *| ^[_}| n3'z \(І"ȧL:J a{zcl_^KH@dysf>B6KH{5Mp&:͌A2Q,S0*yjKaIf "Y`o"uПFp/Ӡkf\()ldȊHHf c a00Md%C4k Zr(>HD_ۂ>d@AJ_ A0H`)ln.P2%a83pxg+^[,$v' yvRlI@^  'J]V3; Cz|q~\Y9:F^b͏'_ԜžAɟu ~YK@xe\)z|<^Ca# WF?24҅ҷX,]! A7jYc:~tȖ_ay} X1*~0`DX c⍸"b0{6|wS *6z݆W0 |fygS+ebf2Qf>EϒUxf̡`b(Q؆*Nibv|DƦ@aA$_MI>IT:q,M(35RkJ"Hipfչ剡RPAfz3 ƙ5 vְ |<,kp<݀jzP  REn'xd`P :́ 6U/u* Ohf] t T1̛*!"0H"f1w H##tkJ7_'4Oqe7 n ,f T*rPp/p_wNj`3qd bH n23k`p\8 kx9m;t6*_ó$CҖrD@z0roh 2s'<[0&R:G:=lfnxzT%9hx6wr #= ݆;!)[T)b l [G>e5HC<"$؋((Gk}\d\c~<%^؛۬j0`ɯSLt}&$)E1-tH[r@PkIӜ2[ n,AJ: _E( SbΓ!vH&2k=ȀbdŪj8(؏A"*nHs=t~o g VAy c 4yvP8UTf3ЎL8szf V, pJ$VR؜ I,Fȱ*Ud_9 >%[L)wm`aϣU2p^"*ؽ2]8Ò̺)L0MiIɔo+J _:G*`#Ɥ92# (!9F(ih4]zj5'% x&bI dw,,ڢ+^q_}\ђtP$q3ȃ8w$35 j∻h%a!R1IXp}MS&5:mV1y8LMHi҉N`f˘UN_LŅa>IN G0#xu) y\+`#Yݥ>0QU9[.ol>2d둑-G?Fu4 R]5|nޡ?M1ɘ\``V-+릿4B8\j &vPb_(af221kH"9yg)A?3/ v`w`Xi] ӣ-5 mM?&)3M.p"BMP 2S ؙul?tlU{zu_Qu %S>phFWHDs&0Nkf);^eLHRu!-N~ yePX|0 S 5ʢ@Nj=aPnop4GM$eާL &E_#&9fZ;Tiӽ/' /29"9a^ N); p*)m!V=#n[Kvt~| [Z&>"\np-coSא7#d T!/"vs ܕ$cM050زkr `ĦTA.vqA?[k r_Ƀ Teq&/$wgGH1gMD!xpiԬAL Ù.*3!A9M ln3m(]ofm/9Wx6556646e.0r}g)AGέ\o9vA\UA9djl˫753&Qs90ELH#ڋ4ܑf҄GpӉp؏4?heրA&` }~f1nOK<*`JsPqۿ% pw(0d2/09HݍϬ*Vƈԅ/ fXta: E ve± kpt M0t!'PhӅm'GlBkJn/ɧnȪ[qZ Tj:Z0 C^/t" ::j/)CAᡗgt&SU"k)lue Hf5θEH:e$)àVX*@U ,A+njO;(eR(jOΏJX EUm4u5a/՝ubo ˯`_F@UVzS=Wlf]ڂ*6VH) 0K] # pDPas: pʲ, Fi/4^Hĕڠ;x088-6s4`Z a jQ&[Au9imw/|7PKvpG硕7A3RP/qH&DKprI02'-#4k0 H0y0_Wډkcge34s b-̃0,xDha0L u.sF\DJA' $yn?WRo8TD[ί$ ldҽz&U(.eT|!{jw)Y ,@}b$&dDAScWW~8Sg V[ґm Gޏ F"R Gx1)A.R :f&;ءRlFfР f,kDyރ>W8t.8Xfa֫^[<}K3~to[xlN38m* ,V(YQ'bza knѠ]Uj1(,: x[XXՄ}yv툒S'CWIɔO-]}jԧ-pѕ`~COC%#|$ f 87B[h|WB=blB#. % m0N]/eU9%B$(40L? ǠRd(a<>N?7lݟ~Oa'wQ0`|UG) ӃfDա NBQdΠU7>9U;:F h$K-d†=SvgQEQ)(HQwz{\3X[Rh 6XjȺ\~D5xB!?0%#6<C\(W V6p8JY,եA*B2-MPB6%S>H]IԨj `M`S%oR١l Nsĩ|履{$lL`h_%Q.4Yo CC΄l`G~*:u=j:MZɋRO&{˄6ƴzǸW|`_oS\HT ]qOx\,"a&m˧ߙeL-V8jR'ubCH85Y:R;+,bAnxg xҁ3AF&zPAfHrf]&uExP;NcІÐ8e?p޹rmv*t#5! E@ =d* "$0&}J0yҀK-9t:ʬ[[`VT>v+aڃ` wi?5TA @A!wYwGM013m;e\%ҕ战6]_b0gm4 2p#PE-QozU$^xr腝G eT}>KpjQɢ,xa?)HXCMo7WڌO:*4u׶ҿ3kX tTWҰfe׶4Unq*Iھg$ip(_?:l.xPB0`!#Z*70A U: Ax5?6D;BQ0tӐ4LyjS eo_1ߐăS : B3)#)-þX CWvWm mڒ_.ژObA^߳( " d_PsB}.D5mv0pa;_|įUs*S?6q壂tc!U禝5PH9,Qš?JU&o3(lRZ~6(Nfj[ၺcMW֛.Z=be c,쾈K)( "bT0s6~s.<{^]%@YwCVʪ};YrZCT6+="*Bbp!Jq'k,Π0Y^DMh޳)iAчͩ8$2IS A ,1SzezThCK )<_ P PprF+f'Hѫj:9O˱,3gk/U_ݼOKM_ @\c;&i0-:GY`.U'/xC{kƮ=cnHML~LY0lF}q͎qK&rl#æT(T! N01D;L*ڹ:=tp8WxB(I׀^m;,$`E:f ѓb.΂#؊$l@I')¬yO}̍GKO>S]}jm]:ο|*LQ@Tc-HaH ,mK{c=AHAaXZmXߡ0ĥlNGKoYS)OI>4Ͷ,j`pSK`>nFO>viXBT ə @7Uy)'M "0ԐW|<©-v` ,%G:]Mxw_]~sǑgWA^9Wq8pP#3'.M799]x}3L8_lP3]x,렪7]Z"Q G-c[iy+?݉`Lk =z :pYLIa3/nfy?օьeh-O36Mmq!$3,֮S]goܼy_gvza?ǎO]z)6Z7 Bʠ[jH!cِ^TquվQliPT饋7 z] V W*;oVʡ(VGu+ m¾n+#b308pC ; Y:̀bg@x c6?~3pAg|R/pY2f*x8WW9_3*qL}G嶿5x{oܽ{ӏcxM6XU k\AӉS; Y9AhbVXzb-=>pecm=[gF:;-X=-DTz{ aDZ> T]&JYuZa[ aR@!I<+|8m`T_4C9#7_)P9q:(~}sF;6GD-m3lAeӶՁL`! yL:#Q .5Dbe?rm.:ؗ}XWi5{{~lMjuobZ9i!ڣc|6fk 63LeCt%+4iݵ՜6QJ*ڱr19ĉ G!5Slf(~.pĪL% 2zEShS_>7>NDCJD,Ooz d$2&VPXqcod.|d^nz`N7s vl9G|lBT04c` хdjyzϞ:OJGA$ i1`A*W@&e`UYk]D۟qhBڸ1`HMA=]P0p@c]̤0Ȋ `wE핆A˴\ aQB90PRWQ:yižbpX˻ K[cZ|wZ+bĈO>ZN؆` AT`.f_J;kt"kLRf%(3pșJw%m ]\$!>~HG {znM"2q8 2 w,6mՠ(+/hC`JIjuVAk|D&\o~}S[$WN9/.zA\i&&"״NQ5zI.VT^фo6|ķiR΍$NUttzv s"J," &ʼF@EvZl%Uf $g|_Qh1 TQx`D uQ#X~imE[);XCo m&F tb{@*x-ɿ:!a&/﨣Z@c=3dDRR/M@.SSӽvHFj1(I& 0`i@s4RA0<=\vhM\YjWvP52*2eo+hFLjNzZRܜ;4l}4 >&O[g2ePj1.b~νTкXs,z+A?[|ں Tyj9xb=S;z}޼#%~ { 31{APET6Ԟ˝'G2;N ֱtCD'"1 Rh>u85:Li uQ#CCt7,*ԁAHp,8j-md8 tO] yK-G5tb YĩQ,;O-ԈMq. iJY(܁dK!!a"e [k۾{bU`La5 d["YCi-!goζ5lJwiv庮z ڠy=?[9tב2 2 Xϲ/՞TxʵӁ e}pVhM?z!-y,>埂0cLU[Nk-kM*uÍɗa KU(HpZ3N8 -٬k ؞4Z.瑖[~P.<@Y{b:XvbIv@ AEDZRdzZު"0#PMA L,U- ïQ{zPP-QMwYo09jɣ VBQ%1EN_'U3ydEi.&}L'xJXj x ڗ=y-,r(DVpcfX]vYEA,ƜE~V | XvMU^'?-3h: nk8|aSn)0AM!WS8MjPGb )&^"f8>C10A3,%Ȳ)"qߴb BfA@@/Mis58K lcM#v 5~Fj" (n/:[u{KU>G. PqA ;;zfȥd|SW> )!UCCMsvΌDŽNO|,\Xd]&Cg ]JH z/Ȥ{GS5U!p[=LSxf(l5FLMf7"(F#OE,o =:U^k 瑲\IxMn-"O ,]OoyW)'Z*sE^OM[Ā߶ߚqjE>"He,OAN?ߜۧ/nc3I$u։<[K{|`*Ԝ*2S=)b1!.$Lu %,xkڬwAc+r13GN7=kPZѳKN1X=XءK8=*O/SxP_k45>.ٲQUQAuF@_D/P-Ͽ땐 .ӫ'aA5~3Iid8By&~5V2RWi`Ƈ٧GIVP.-ki m\i̮;ȏײsTQgt]]_szD;NK U_C@K1Um vdSǶpuۻ -N!h589 "( 56V`1c0Q8z5tM̎l`9) @U>Aid9xӑxթbC}߱1,u bS<[}D\wu$C;&JIQ@;U;/ॕh+ZsQ(|(|(Y}wFZ +s8: ҈bVh 5?aAۘR1L>p&̨LkwQN\(/74`܌xSqd0_C}sv978Q,KtjQj PɻpS^vt LmG%~@cM%ҡl0j}?S*ɍ2i}=znU2 RZAՎ8 C#Hca2N b KyW Y-AA"8%'탙ƛr!('\΋D 7#Z^+>\ڝpf=ĬNJ!:($M~Dun [zAuqp>uh"K9@;jΪf8vZ<ι,5?p -&-}VfָOkLXtv!iGh*2{GVQx|E _a`C}bBt#;IqW򠊓x2A&o\(!R ׭u;|ELfR *yD6iI`׃,!ڵygiL1VFv:pNC«SSx.|Ϗ*ZiI>.D 󜭿]B)aJŌ1ͅlVE!Ez64U1h@ 'N6{#Uxg)\w<>lA (o7 FX)U5Ŝg3 ckvyfINC-˭O}"ysw+QPSӁ(}q`W& @e駋xP:>bZ}\}i =ոSեZ,*J n\Q&?U42XPE8Y ULi xʉIHِ $ƤہYJJPQp r6>RgB].sƁ]2N 1hX Ct(J+**qo!R7o?Xv3ڱQ(b[B4~)oLnw]3ƫ ճ#~٫~o:1y[S>Er&   @&݆lQe-xAmfgEr)ŏ()Zq$_wLIHXfɉv غ(,)ձ˾dM<Ҥ'^JPfąMp*hϙZpixAB+d-E~N_@A#4^8}9קޡɜ[c'3LX.%1瑾1z6Td8 CgPHP= ā)S0S:mpzؒAʤdʧ@nxzb'݌xmLs"g12Μb&)2n\~Wn`BK"%I-xIi귋ξP X GɁhjz>:No4yF7NQW_(H= fjp`r" 8~ L*jOʠ4~GJ ;E&0b6UhOiR`Ye})b ?F1>@jYII-/GR|&y8+ ʮZwptt7q4N{0a))?%(튧g|JJ75'= 'qS_Evf盶UM2\1}輌cEiRPe,7CF@bQQ@o!L]>3ԩ0Dy ;!$G7 vN)+3PLo։Tcj4Ȥ\OΐoE/|t66+Pv[/wN`(Pix8v"Y|cC?@{AH3/h ՍCq毙UdӪN#rzl>4x!WPEk(1(T4GA@N0j!WFbLHf)oc=HJ&Vf jLLZlyr2 N! snIk/fx4Qkny-5KOp_a ~H=u󿹴+EI3;)}Oo1a!ZEZ4_Tpc}gk384OLYI^d2<b ]ft@ x8O5;0)?%$[zR/C(lhKTi4Y&Axi/ ІeWl$ 8-1qc^7bk7D\8k/:tR aѯ!(vgL:N YBߟwq _|mRho0!jnxgэ%*ղ">wPQy–6cu^e\KaÐHW]/ 8RWLy,U Π#Hu&0n S)@ğ6z'w1A,%$Izz0`Wfmxy'3%<>暯9D_> G}{z;3NVޫOo5o)kUFT`y%O3 H؁A(W5_$pvLp o@䠃~i,-^l)WPƞVl=/FS pd1e-44]>ua?cc N_ËN Y<_2dY?"= o!P_?gk~!>qn77*Y횶'Lm I-^ƚW_LXV,_K6)| i=}~y7mvpc9\w`6F+lກ|Wl;(|H-/$-N{5n|&a?xR{l=a>ܸ G32 |PQd$N-Z^bJ\#ÆcSh\'K5[9> =88=jc<]. 5>2~F"jە`Bv=6<ݕ  ɧ7f|#pv/FIUlz_޵ѡ 4q]Gʂ@4 .qoU8f,%y)aK? ĹVԳWL'3k_3Cp*𢍚8O}Cإ ]uțjhUkrk;P6RئcŭK57zCɂ]' N/zm%gMlH `i **W Έ <)fJ7Y9Џ/xAQ^y#HL)j $I Y+w1iUwpnt!E^8 Zqx)YȸII; E!v˻]Te&~4ylCuڪ'\gf(Ђ9?W> mW:ny-^-ͳ_;a2D4/,oc}v5o}I=œ \D9tϱJv[GQ ;vι:jZYN5{RXCh豂XFeE)3(-F7a쵅 p/p_p'U|Fˈ|ESg1!i~:PU᜙SYRpB 2b yJqq rp4f 4U:;LYuSrAl L//Xǖ= x[ZH B TAItEwp-k 6\$dñ[)=D-?Xx4b5٫üU}ݲxɯ/Q # zNma{r$}HXꞣ+cN-Sc;5o[PX@ܪpC\!獐A#4h[`XMpibYUDAe30 Tʡ.2N[fubh5+@NfLqpᎄL;P䴅-{ĝ66]40ݳ+bDf 9#4Ni $wFu]k?&.Xrܫ=\;/m ~A\[ ںeQ W~dnbmL05ӫCvJ-pѳPS˙GOos$r*%DK[d{E/D聥HTTX1&3bx6#gdfs C` J0 frvkMJG@-4C9ÅE|an"M+ih!}Ni@Yuf/ȁ). N֢3H~De-g3<pz}C㋴Qq Wfb.C ]J#wv^P jiџ=}aZ-U}` `hbW [/ub0X)IQ~MF, L4 '(3t'\!oǔ&N f-}Mwp]rbbsg;SZ ]pOD@`@1NXDfqW^~!l9?D,5nyq#v/aVճJNJ|k3ұu%P*w$[ߩg;.5Rx33"w8X &zT&qDS  Tisq b38kTQJ09CAp<'#Ô*HŬFivw0dPNisz=E|U~tlm5meJJs>`(W n"niQg 3~? lK_͓Sj&aq&8:)6i5 7 +ONQu3b^;QGY%MKaTop@3[ygpERSY0LU 1kA3Ssjp!t)ãTq[H?Y^Z~e'a":=O-ES;SݪN糱H]oR46U0Jhz=c!RaX.m æl0EL#8c*~ _Wʷ.DM﯏s}'f:P OEsH Y'Vjz}m;~$I`X 1tBp &g`Hhd2U/88x$K+-i]]>hؐ  xgP_20+P#I(VR?Y rG}tK$ ,M޼JqUv&qOyIe?P vDQEy=u-S,??o1nɳ2:L QSz45T4igG鋵G&onҗ!@@{4bR1豒PHBgvg, /@نALZzʇYz79FhmwI"D ո/V A?z5wj.C۽t+z/&;jΪfY1 b]{"}wON9'j/ S Yڕ$[r3KƬNX˱ 2 9~ )EAJ+oduK;Yn'>nƧqL P 7mw4W-dV Čw!S=*iz*{u˾(>UxA-\\C1z{30e/i\I 2-Eij49rY=9`&)?*"U`&vUV@VnG0*|F8j%z{UR3r/v:hcNW;վ0o:s Zk!dgf=ԬHP&w";ٸ=W>J!V°NalW™Ximք* 8(r(rdg &7%$L@:3"EF8[nULfj6,>2%`.{A@EFf Z!Ljқy+:n;:fLTN.4Ǽ#X= }]s|/MvSaCN(@AΌ<D {5Xzuwx#*m蠴w{+oElH (d = +;aH6Wi;7K*AG]ݏ9 ; C xD[cdAj榊_C Y=g"{]9~0GCTUMbMPg.= ISR7,R)>@K[ϟ[_?W}T%}li{?:ZL0˦pjjΠ]s`#O c/RO-T[l&D*^Sd LB(p&*R["X:空p['\ygYй3U2mΘSY#EaރFSfS yށ'K<:Tsμch04;Xc({1|-[d>P{g~?1K}gwPLӼA }I>Ä DC!Kȼ3 2vgX$AAXf< ((3C"6ѯa}B| ĖZfS2ΐ45h"r% S}s$r۶Dw| ߬(WoΚ/HAѣ8q4 K77#KQ $gqR9zP&~n_n;Ic^iO]ijRjm[N ?(l ޏ gbC g5*%[Eם!iMD f1KT&%S~haWƒUA@ B-M4Sf3:\(Ls1̊cQ<9f(idCns g]ճӃE4"LT pBYKVGxzuss4gzy-.)\;즃'QuP2 zWJ-}{{ h`td9*Y:lLsÐ+8c@bQۨ\~[UQP 1: Eft,Y!XC,1ƹxV=V$F@fRY#cA!o?VbA+,ŀx>)liECY΃7S܎ޔ<'=Wu]sY9皢DPV;n7#*oTԏ?I lW3 K*nLP48 Iu CT pht@2sy#Uuѡ2H<7;?"G4#&*.\RJchRp08 ʜg3ldFt}; ;VۿIJ1"ߜu=.֜ 1ftyPG[cկ27?<3z7/V0%~5ziۆ״$oR,o_ךx%I۠ykfâM M.%"ihg 9!4,s迤 ؔlx;  0e X[_AQމDjoI`vdt4_,(0Hs%A&{r|tJ`\A#u%K׽%w9y~qcZH9-jSV>MDVᎉI-=\8Xb{B!UBSo"  ~BEL ]o|D(__YnxTFj;OxM`I`I46N z/O(R %Uc{/lʷ 5Fͪ)M/'/nQi<%8I6)$AU8cA fTp BsDyi^#B2wy=H*hBƄ3;;3FTG+H A2 x#Hl2G `_, +"<i؁A(~8QAWe ҹ`ЃjOĒ3fLr28[Z\Q\<0hOTz6͢/2;xW2W>XA2(ό\_GXsxzKm\Ə a }mN+gT[8p]cf4Ag<7fT5 ڒ!efWM0M8pADQA5#1g^aeuCilM1,c} p g, ^e3 )48GI[{U܈*k}5ό@gL[Әx{ vUzs $Z5RkvfCJQmv~c$M gbME|qDQɒKY -5pT%+ghw*-OrwSiQZawEB294 bR! Fl|r&{ws왌Fk 9/h+rE]Rh0h×l9ޫ}w5o$LU'<:/9!: X`w٥,K[KY:KMB$q{erݲdM͖,ے*IVջ3-W$=8]7s̙)sYy|8iQā¤aQ8f/SRp1DkjlXاrARni$+GU6]T2!;HFvL:yaTz`) vnRf l჈mbEpȧ"(avؿ `Ϡ&/HQAB0ePpF)|1)r&TUbGl3gHG> A4qTaS1D5HTh|6|QT B̅*Ɋ`"qKE, \~ ގ?Z#ِ$Z$3 %%SOE9"0bĭ( A^C4e0Hc PppM / f9kI0֯~,7@hF!8$0 )7A!F3Ir"rX0ǑA,I&{}mɧ3`w}rTWC}#* ̸jtt5U=+c#qf4;v\|8 zr>zH)̉xRP8klzSÿT6j 0l:J)7aj06ggjyNf(~pd2-#<V|gA:E}l%Q *{%y`W何]~Ay&)|T .Q5_TKzD#ԯ_|Cu ㎥ܐy]3L7Ǽ= |YMzdn)4|~Yu$0Y= ck}ڠ:I3E% X 6!S6[0PHǯhREǟ cz9w67  <(䲂Vw[|. l]~_9R`͇#,pt᎟|KTY톒ѣvlE})[0R[ K>LQLr-CPA?lXczJ#N׉<6@AE(t! G` % xS\7h\x [_O?P#&AJQ#9nk?@Pݍbʫ v{tڵz<3i91=8a0o|z[˾b2e2Eףsߨ?k+ 9RJ_ؐ31A1pgd0>% |h-lR*C2FD Lґ"r %0P20(q,i 841xaD 4 ˑח`N<\{zC[FFMn7]XNGTؾ6y|mk2H@4a)zq{fxF {IǢt0}GRETnڟ~ ;iRpN@xHdiI XmKhi4 5ϋfb1D'Z- ,pGe$ GRBJy.¾FƜvs|Oj"͔& ={zm?=4K(?CPK_Y] l|&}lXzҶ e;63}AÅ3FX,l52,&Q+J3ae+Y5`bp(atLiv 1فYfA䪊U zgV <@6=cgyT v@B@mMvpD 2kDq q &J~#-U? 5^-_4iW@*EֿAWe" _>:Ry65 EXiuVO瞧)//;\SfW#q|6.fHlX7Vΰlf1 +@䅀3*^ǯ--Ў0cW3K e^3rǻ]ͅH,>oMfE}1xԘePhSo 4OSOv Ĩ!A?ڨʨo\*~`‹+>ۣ:9B >^FuTDRua`$J]ҙyΡ^,Ҩң+HN*]_F"e cgCV)@ LUY4[Ml B:tf76-`Q4)0"K7l@w ذáP޼fqGSߖœ66k {NK^e:or_ U5֗lsKqwNT.oǫ~ءޘ^{ Z|@{Wqx$qn襄a^FDuGt`gV7Jbp:3 6:ES#n9hfvI`0q(A5: @<@U d!a:AXv)0xy,8 T뜼-k6rCG h_:ej(dr|á_^؄*T5nbqQE˻J_\ԂW՗P5_Q*KNLk\/3ò"*mC@Ւ"X;cmVƠ*1 T6F 0akp_LnXURI_$|q64ya@3lJRtiSwxe*/ ӏHp%Jᔋg]0mI O9ܫ['W>Qz8ɛ,1*EOa?rG K*7,\<# $*;'BIq 50fX"# HS So8,=|^_}:2%I*:H4L L3b9o1eƞxx|a)Y]pɌKl?1( OTV1>J}{\o^>*{*U]~]k2@<,{m2[/o]S/d6ʻ4jh>\0Բ ^K<_yM#0 rf=FaC1OFP)pf !bxl*i8/ⷺGzyyHՎШd*!L2NEMSQʡ=tSsDȝ2 ,7BTeak hD<9B3,` ki|QW"sW,R"O2-B`)-A6#T8 FFCQi9{wN}^C1||Oww5))_1篳Ӿ5~g^|F~'\kVہpkx'q>=+s9Tun[go!=+$*(N A? CwXQm%:4H2Ř)p+@#SΔu1u ȇs[!wnآb#ct|&6o -l,ԑN,:="' P 82A*6G,7(TM:K"THeB.pޤl<#?ŤtdMn驔 v^jzWWwS>f^*ʓ[LᾦD[?+鎏2Kwo-k~NTЦ?RJ|@? !3' b~ }ҁ[}c#Aac%1}Nܖ M_M,RCj1WrP 51m1 8pB3(gJkcA@7I,C=?J\ZKe]=m~4jY tbJYnT;k mol;)A082c)ƼPRoA LtT L0)6Y,^> 1URH1hr`gxcX3{( f1/`6f <"1(Jk6QѠSNE-3O$Hd56Rp&ۣ3UṢ2g[\c/]l*#?ʏbfh c؊<pWc}i0y7RLWiC둂3/77Jgd$)KJa4hCx**W0B̉ +^1DX'eUʓjCj@I"18=2h~ 5ҍP-R#B `% ?)>x$޺1~ <}_҂x)Am>\\N>Tt۴ʕ3///޽;'pg 띔c~$I ( I8DD6L?id+% jE1ɂ [32~oiÏhSK0\86p̲f3e43 puj؁Gd^Ca  C-3\!kY!s>m_ܢoz@10fm!F3fƅ]d: 1 <T$q`N8c˸̔$m P!ES0DYAPePޅrn\݃gThmWPs:_þE or]IG~{>4T 5 H|9%02C9y X,`Bx/Z@z7KѾ cwyr!rWk ڤeڧz !CN1䆲+!ES{֋ 00",@R'y@UTGf/H xV;3%(,_ubqW7Hr>mpAsڦjdxbM'g E6& !*, $c;HORCQ=bGhޛwdX1H lR30|G0Gc~&Zzi9a^vdա JXv& DfmȐ2tU@fuVewN]5QZ3ܥ]7 U|&n95_X._@ *Q V"JTxI 9, F#* - "3 %1g i^E9n=UM D<C! è hf+ACz$"8n1MA)h\i0h ,L$״+0hYTf 2w*6ahxym n^؏sOp¼Ӎ[[+ں8*WǓe'6nD6f/)YQT5~Oie?z&z 3&-j~آgQVM }ݾ^),a՗=S "  C.Ͳ屡P;4@ cUkD3 -2 PBGCQ^sM=B Ǭ$|As8P`L/a5/}a0JM֐wGuld_sˢ-)x҂,+|/>} /$=%$=HDю4(j1DP ?Ac"b0.w, ze~e0" M QZz  A9< 8<_nI _tʘS`~{lYK%֠l_$A$rǛk<$ F+EJ 1@QGUFe ^j`/ ,`PeU$ @}0AG3xys̠ h|<)AT-W0r@?bI܆#;m*EБ / t6C% $-%<_% bY1#Ta i"{0< qG* 2zL!PXq`82с+70^TAO͓'I5XŪP)"J)) 4MpӍOfmH] ò2e r&͙~C ZGfP{4 67H~O0H8*țArb3hyI~S Erp(H$%j/EYPCai##"uʷTZ&K#V:|+b6CKU2zz7`DapD,IRkBDד`Y`ID5 bR tC68vq0odddpbhihPg0(L:KU$.Q`bA@piYt2-Dc% _qɍːK 3, N]7+ HCG Z :C38㠕sN`RDh,U6VeQǀր( Y;Fd`xK;r|1A_Z-R $BLd#A? 5P@Ig‘ΰo Pܬ#Waji`0u$##YC 0X2 <(a 6Ht= |)sk3x Ę懇3frV"bBࡹ H Kl Zp"HPkл!*q<Œc(^b Ch * /l- 2b*:Z`%g .U"-Ӌ^Z3N_\.dH `4k|er%KHH$!lrMo<UhX F5,2CˠV֠w1ؔ P"=1&-ѻT2ZpFI_ ATGpP:@yl ~]y<8J3ΰJQLdPe:FY"ӯfaĺ`Na `1bZ$x62 Kdw MA h0eKa[ i^ 1ht*](m %I!c0#䄎ȱDr U&+uAVxfJ ~M`Az΁_֋yu-%,lnt 1 zDk 88JGH)#}8d v"h# |v0D7ߍu! dgp;mK98 }#9oBIi QUL,=Z&:-DD ܑR=d%H1Gc+\]4$t:P3/GHRU BCL"@!5Fx.R1bEaQsti0GC9;}7.Fhi!f,$t 7*Rs.٤M f!^e~/<a\ gԒ2ļ3aϚv%82z`//?2 ֣b4"A!cX+1gdX80mX  e<L)&-/S*aU3bV( !0BJr<^Z-%Dp?وYk/hP,]?-L3UlZqPF԰ʋC\$E4 /$YA|w[A IVE5>Mu&8|"A'5pX!1f&&6|ɳʔeJ~e<#?ӬդdC09ئ ƩTjz~L Ax$x SFGʡyCe%IVȞ~ypӥ*z=S,C]#A ~K 3d4ߑ]$E&I2,վ0(rRp *JFhbLOԯB*e,p aAҊ>62̑)5D_ ҖV#aO89/.TK0$Q0U <gdИ0آ:|0i`roi+ 1(DB_2!kF[>ded/R)㰋*B2;Jqq8c!A 9+ Q:m$.CG<Us1^vOt};p&ϳ$>f*g0/S.lC!gq.Ȣ/@!(580R GoスJp3f5{U+I;q T1V1DY䃗)gzhaHB# _3͑3&Dk 8cXw#g Yz$!ث0 8`j RO5C`P0ȿ\s#λIPp Ύ[*GZÑM#nkaPrA7^P2@ ̊)38 L"8<F¢ֵ>/FVTRǬ?"a}5w?Ĕ Rw"iF=R^T2RBTu",9e, K6eFgrFBaHUH a6UUDbAD.rk0q8rp C"1Dk:Lq<}]JH初A !4  q} dP8 r=GUp#82Y,=>̗O& %60 ݌(S\ @ʊCM:g"6iD*4i`6y ߐ# sXV4©aCVZxХ1r <Q) ?dqWaBG4y({HV+pLԎfaBcPӤW+f bbkKuX.NĵzMw>*BhpDy$h (gj~L 9z h#A(υfQ7'aIpxvfOH23C6 9>Ga͞`j/6"{q3PJ]5)`ǢO?? ΨzDR DV.Tʁ ݆P^! ]t@Hu1 ?$&Z7+h0lƲ e5 0p<# AXրZUՉyf9 *[EmaؾGA6R353z+=XcV KG>EHQ_~( u6` FA8 la 10CoRT <grK\$ Z71>PIpB+D&1!@3š'@A~[i9IW(kZA\ 51 lTf22*CǼ2FEnA0~*@.>fQ"!%`aJdHJ 9<5XTD@d@!7 5 ):\Q|X,!9p:肦0i ƂQH!I.`;A !AkR /6[xBx `VY 9$qZ%3 Ed`i9̃ZP%G . rdzؾ0ʍ#( &`; $=!5byX3Fad`f F8O5&'U qxa&5DGA]btxӴLè5dIH,.rBKk Gh9 {*֊w40' /;SB *,k0>!+~?{<ʗB7sL71lpG, $(44F`V1q}ĿfSap1PbnK+8#~Rz}QSâ@1a'֑rchԿD/DqR c_OMe+kE̪G!\UE$ co|as= R/ss4rȰln~0k-? 髞2~z1fHqr[F#A.(ebd31% k[[:tt7tiiy9e_Iʽ)1 DF  &440{ʺu-ŭ];z{z}CW֮}}crndhia 2Ag_L| z3RF5-'sY7V5h1Ѡ/zԖ4;=M[PI(^[JsF(PZKz:x5%1v_2V}[ϵ- ƑƳv:v!uEѽ5[u#w^sh*9?eFSe#`$s~R4ݪi['B0S]N*-;))o:DMsnw_ -Ug,ё3H!7mQ̪}ʖUI(jL]޾ Vsoq$kޢ~Qzu6\}3Osuami8Yui[AՋ}qAѻ)#mBjv \k#߲ CjSIԵˋ>{َF ^V=suYp q$BِVw X5=PgOckw8El][WcSM'SLoȬdXP ѓmysfN  /!RA?U`XW%<ݑR{z=cl'ro/.38wܻӏ~匾+=~BBuѵ~3hzV25^wJTZ1v@u?;sԎu{s]%秮,DK# %H/C밸ȕ~ ]w\j? \n?Qy7$#%(yKZ]ntT&xRI97U5nhP^N":=vqy__ʺ@# 1[%Hd,̿9ޣoN@P@\oLp8E=1#:Ә6jPȎ#޲ 'g.f&_tU!P ;MF`k4G<=#U5ke HD8 fª1qUO&j E# UV}W"i=[+Tvu ;.Ic`#pᾏtwh-1'.p3o{E)T*ȷtTo,DA`H }u׎\0zUx ͗3a* 80TfC~ wBӾu?^DxSUk~”+WiV,`ImPɦ^ Afi+U&Y 69Id1UvG_O^ZBZh- È4'92:E/WHtssYX;GfYSxucܔ o]YyyX׎͹9@M+e65;?u &U568 bl315ˋmh+sJ>=';>(#nc>TLxQ]2cMvҖ "EƓ1(~qky Q>&S !@qFS SуcsXz{K,X݉)9J~x^?ZugOvP'I|4 X ~ ʿիXj lkEOzGt躥׼I[&᭘vd̒ 6(~ @11~AH^4Aj8cӸ&4zHC`Q)v^ΖDx@vg /c4 ioVA墹ܴ;4Գ`p:}ܮ_7 JްXONN)Ɗ=aNgDk 8 1z؁"1ry_v{ufk`vҖ$p lo?dG5`0O=e$KU!vwX2ttd~G:{D1]44a*aq&;Ѵ ;(V`C8nj뼘~WLAL"Rw"x;fdRbmB0}'f|Kcy]pu0ߑ$MHz.(3ƀ;`WG@hr G18"东{mZ;/n=Y f;YXQ눓e-0_X)z1xR0S+q n?t.X^-v`}cSSpAT=n ؐ Wtўp-#%`RQuɉŠڥBooWmvֶw鉚-l0qț]˸;Z0/喳0B򗦧ߥyg4 $-K{(Y`@*d7'7IԬ7BJ?ÝBN%?ͱ/7%F|oz e~0Sl`2r jY:xZ/0n^̧ǯAHh@/dvǡvz\ƱN{r+ǽA0}0V[-^TUCw:2]YjqJ׊ 9=>f6 x9eZ1_:atIOw)_@`OBʞzc,]cW:#Rm? U3ޣ‹[^{d$?VjHv;Bh)Sn0iDrIm" Tg 2k*poj7u?\pO/%_z̺dHq;_B$, ΁g^s~[Ŧҕ_ъFc` 7(a*OY36~Ϲ%&5-QrWZ))wqP#t0H dAT")Vѯ_S=}G_ F}B8ܸں Cd횆7(85{jML=5%PvVv}S2pZtjwiAhs#u?qg0,^z(k:xgtL/0uկDtCA#[Y8_mF|CbXg+2 *_z1+3Ah {:-SWwE\مF?у?]'hS 4@*N=-~b%ߐWLws\Gץ>,S83km yӌkR*L8X)@h@!flvPzZe?u]WrnM>ޙ/LwZFZ'.pK ۅc1FZ?svؾ]rb*  e->0cv8n8f`O†$bƻq=;3$fB4x۲X:HpqC}pTӘDfD؝iTH]ce%Gř@f Õy㇈`YR3N-jF"Q kBچD#օN+8E&Y/]0ݹu>[E $H`9rBY7_cI1DJұ l{̦X϶S͉[sCj"ET4J. P1VYwF9 G^ >cFj.)x;;N߹4kCqu.̲ K]RcR,xnRӋ͇R?chKɏ~G;*|E@s2[ZG)|vUD$T1I97o=f [ SngE$5/Pxl-hBWcay1T{zzڋK'E}g .<HG{g=g) ~9a W7s;_2ƛfgMKXePЧO(aα OJr}'{^TG-u5. ͺ>l;sk8yҚeE"l. wyg0S/Wz:}}t`ab/Q& jQC<,(gJԂָF:o0nY/MS(>y0(M܎5L@],gEA=3r 7t$)ԛr6 ;߉O`Fk de+?f\ǻ`/l(0g/8pJ3̾e=_UNS)߱З!>0jk}̊44DS PH5/Ԫ`/8~mɧ|>dD;EÖ#p]Z@GB+_ǽN 0hћ(ecwj]޷_9*6?\<|*V n5N zCfZEyw!Q1L{zqPG2vU~zHsY$m g;P{!~0)\Yu-EO<6?f"䅑9YWSVSwLNe!yk8%d 4\.磬2pD-/:i^y5wi+>T\\jM 'Zy罨1G| Q~8^gtur 1?d(H^ȣ ^~tbӡ{>iZV_45-9!*bҠݨ½E!AP?Hf~!vݪc;Qm۳Cyct:ݼuwCZ pփA l <:_ JONʠ2'{Tj38˜xMډ8}DڑiUIhl; :+.ָsR<e$ TҮ]i"g")֐(#:W\l*N\/ڗOߕ/ Gcb=:vֈ.R<$REY7ܽ;ҏd/Q`Nw]F)KͦѝNB҅1)m4G&I%rȄz^2^dU\06y0)ҕs2dotTv8)P%I%ΉDP;0 NjtT0݆Q 5uɅ)n{pfR^h=aX%+/KJK[{FNLOmƯ.=?"b u 뎨sdsƏu:uWܖ#pBXsf2]cNUa6%eZZwSn:r#o u͡Z~O_sQ a*xcT*p:uq{,Y7 @?U_*\ *!@QXH#C^.؀<ȸUEnR=e7ۀW`q$nOys>~ӔയJf+SߢT`X:j6E|&=݂_v~RmS yZᴾ|bԈ@pfO6Or)94Bΐ_ۜ})˓I=)PΧc< o P}ZzH%p0FC=AP;vV$< ڦּTfs_;1 8" gkm8Bj;Hhۂ|"*hG~ͼp :U(|5#Ȫxw?}19{S٩4q=,udž)FcZky8̿~-gV ]-Sҳ0l>i|_~JikQҟ[ڹپOBֵJ㤣ʋị-E9`D 8JsGUUߩ4ՋE#9ggϲB? 6I F2ڶ`C {>J;3ѱhh7f&}(?.q=/fc[T yG*>s &L?7I%-n ;fɊ/8 /}$- gLo6:mMpW`a)k *Tp_DYHM}2}NoYRYN tWw4ns|q@$ݟf5HqnwN8v4%%Ov:lϾqyYa{Lk?榅l+$p|\8HsGAS $Ux ݔM ^M7LS8³RYY b|xc };א5a 2-X<6->1WsPdp*FGl89N~l. ;פS@hw2fO*:AX?1K?V$-cKX5D1 ]t@sr7)Ebs{"# N_ݒ\)װ0wCgIS%izze ]W/cKI$tcw/9dR{ V78F_>TSyﻝ"6ࡗ=8)WcJT>FB_e e〦xuTp cf&V/Գⴥ*vņ8ām%u`JK88So fRk U-Ahj⳿yUjhήxQ vx%K20E 5kkxg ^<+($af|i n#Ff]Ygӝ܌"T ~cy7>FkCCY5cksIY{?[}١CWO{VJc9b L4t!M%N4%ݯ5,#쫝k#0n'O2<;,l0YbzNY6p긛c#TÄ異#lrM?@P6$] S3"8o'Nmv~bc!or&u\r&hvr1.鐵 ]@qֲOسEv/A[9Gv띛,Xϖi%m2媎Jř]?2k.(q*kBCMM?nUÝl>FNO7:̥gtH ¸Xw]kgvAG[]Cg9xj.o|[Š;;fCTR> )Ouh#Ֆԃ?"l 墼*}2`cqs\co[$qY&xqsy4 /O|mh:rn^ɒCN$[ ,KU/Ti!{0ҒdS=GTí(]>7RȲERe-/~Ƣo;*$9~ϳYN}}ϴupXDi[7uus4ډ%HDx:Rՠ6:ZwpKM$ 0Z,$YfO/l5S8ڲ ̣B$/atcl-yp "0>Rn?>; ߟ$q|w* R(!a(.P`扐|8PGx8}'\Sv$:f$VBhPNр%8/w]; !^?-;f3q)}B5L?lpj8K<]!QP*V[ ^z;M'p|αqM/?OXu?O="Ockܤ^tFc0IÈV=tVo*!{hao:2YHZcrED Hvv#  ,C,X =I&]̀`ʲGO$p,C **paNZZ6=f;,8$dT0-!J]9Nlt"ZF)'*2M?pkK:,pF GTDϠ-c15MɫV9*Y/ue fiQV=MppMO AvW VZܑN+v3}AF҇y%w1+RhmOgyĔ-ʱ CEɒP{eJN >|nŤ]?Ζfl‹K(`5}P <ή׸!ٜ49onwva޶IG.c8̇hM5QIq@Ayn+(VW49:De9 iu]p(ݓYeZQD g Z*f*Ύ;Vm#0s3Q #jq]MYSoRgBun<0@AyE5h1UM Gnל'yu2_# =u-5z4ȅ'b@xp$zUzЗ+=bLمx;Yu4G?fN:j}<&QP"f`2Z8ĬDE0HQݕm1l\tY߽͒hX; uw'z}C4N[SOR7Ii:N;iqg4$N@BӸm" B"@c$}_$@@9w=l{{5\|ﳽywwx4/tvk"畊-|0jՔy` pJPj1,XIw={aЄT=S;IϚ6j"TI]'m]rk@Xlv}Μ-inAK^r/:a3ƃGQͰRfyT.SorKHHTZ~Arl@} Fywk}Z.ݥb8U?A途|b4rJ"꭯LsQmNn cszW<2uikXfk37WpѨhSZ`R>ыpDyNIɏ+L?]%gS4XSA*`1TIezΰL`h*ygu`~u3~`:U+ɨLjz``|'tU$ujS$<NxplOvJ|jQRƞ-X7es$]4g~=k?TG~,,~oߑ=^)m;SNs YQkvC0AFN&s0gޫxhcd!鴗 ;&@֯t@763i4vrm܊X5ƥwAwO%оg/rbE-f^@_bm˄:c+2t.q-K[>>~r>1Ov3_jIo*foO~q_5\4/zA1?9}0R ^#^W=_&m P#ɁzpYfj2!:ֵnJjSEXݜP ߔwؐ;®^ycym=qw|fVꫛ|[D&"h9V2D+cXg@~>!hGU0?}*/UTMNk5+nMqE3bMbRiTrVs|ZJlI_`qZ+>F85D8+Ɋi˚{OS>6_ʏ[]u}MkC_*wީqtB&pd0>b3:[OVJn?4M@5J Y*~h?}дnWNy aHK3@xݗ4aeV6m2ؤ#/q 1mQ!AH@E=LME~<-W 9i2ۖ;o'Z^Xia@=r ʕ (L ~¯ ducf.sVXT!hr_EnYzLU@8nTЁWWXis9cϞmtrGt<³?_ɵuNg{ѯOfks0Nw/x>r֏94|P#Rru<픤գ/ 8ki.pY0g7`Uڌ5:5Rt=7( 'igI{^Vu!'9no{W_ oxwb!;c֪NNv|(=_ͭi V{1fW8 BS-"HOAh$8({YHZnU+|1#XZ))6}N4z,>Q[,y4 JvrHbݶ\'+z}@Ցڜp^SlVW{ChV9fZ i.+¿w/y),ʔc10jin]j0'5i5؂*Mw$< )۹"Uu O1X͟8]O&-RSBӦjcЭߡns}H2xp_Q<aK: ]UKvBb#W`K-OC"_5K_B›lϥl{;[ "2ԾaREo#ozt[1@=Tge+]M9n<2~Ş+jW(wߴbFxKܻ#jr %Uz;G`_ʿ_t?yKhm]r 7/9gr*h7?s>Eajrz& tswԷ792&󸚚?ӽmyt~e>zrfMhƑFl¬;SR+s`ԵЊ眯KӡlkX85h_&85.Θs{LX ֖7_joAXYQ"˯c_?ƪڜgQ}\s7^)xr,yƸK"=f =WEdtk8.FuLT[㸍ɝa4#F^ cKJ`<2ۗ7Cw{վc`ʒ LNK[4!xKS1,ߛo-| MR% 9yS$rrpj(G?.Zf\{cǪlYz>>^,9]#ċw^|e#wKwݳWpW4&H  Jd{ʍ%~}Ķi .,д*N7pzUųJ1hT/0cMk}crYtN&і5{չi*ojӵ;[C_[Efx ly~9#}_8jס9, @TRnxa!]⍆&8(/0ơ(Ц1"nZ:B=_,-q FZ2K3~#pTmWRcж2(irϘĠfZ \b9k6ֈ'Y aR}`Q"*nN6qt07nyGV&p>3ī$l#nVEݾ[Nm$|bs=O6ܚtae蠧h#wdNx$ p?M[EhcDpa%HekOoIM."I\ٜ'Oom}|="&-5&)\]cY.~d/i'/}?&@*E*4411{x{=}GegސJ ໧x?)Om9 ixg9ATz|w/d*Gr0y'#Laj:s{;c^* H~̵" y&K[_9f۹.*3 eC=F3>d؏ 4Ftԕj)=&wMVE>S}t&[Mܾyi^OqRɣQ}_k1*e, iZbJŠ}]0kKnWM?LԲ\6 mmX%u]4骧&ٗYS/Y3AH[@T 9BWs:TE#4I8a&C9I_Ԕs~M H_}a9J> *#d֊`k;MoZk­W8UƧ߃00~ørQ װz$ue3#+E_~2wUNƽSQgS{3Z"孒ad -K,A#V1{PWEk2i˒S|#U ƪ0L+tI6-LNEa҅Ӽh8KܥTTa^/i?‹(? V*&ŗ BM4ȿV@KEA-8*JfJc  I|]+cEH2) *HbP ˔dJ yP~b9֎VGIZ-tDbb;M/Pzl%,'Nzr)^WF$:4S4 6Z~I Ƭ@TJyU+pKD\IO;'Y2܌PXrhjm L& z$j-i*M$)=qZ*-}9%ֈ¯ŷn3]S~WV-kvt=;Vq+4!Hj&գ̋rx;6f-t DȀt :&H3KnjyO(Â6z 1-U *t-s"Q7.G l&G.Y%;N밳T'o \ HVJ44Dʐ8&aWT8 (%F"W4 jDQEŠ׈ĸbm@FUuv.IY_aȃԔa>n8aMn>_SCA/8F7=}W|ED6F-1 ;$9/! iEhxur1EmRUbfYB' KpQQw@9V05ʐTj OF,A0(J)1^UUzضO @=j ͞gB]̉V)XU bw0Jb~j ,SL  mN8^ vrAFBXKL@Zf@eg&ina')76vpU?\.)UMwHDC0]B8HigH,UM,f'DRq´Z8ִqBKƯ&Om6> KCct殛Dw.]u\q[Ɵ6х+&# Г6EkA"<I aPҒ٩^(?M= >nLkq"JJ+zP5,#H01D}i3%lH  E R_9&2'-[*D PQ`/?Ͷ^:bf v\o ʈО6i?՞̌[8"JFB0(àF=)"L,?ɺ[LTXR-Pw«bHWX&,׀=6DvO' ( _Z%`1{˻8fO:1˻ ~&`oJkbP K Z箏4;-z؋MeY#)D))4n74ܷ1$;llFS!g>"1%o p \L fDT"1% e'y-b܋xʓMQkk F(.,o2ۚ,wGyˢSC]p2he%;VS)ex/aG |~A׸ƣ쓝zV7&7#)B2 bʠ)`5ƄѪKo v?dwZ;|Gouܶ`Rgbh P%'q%b+B !w7sㄝ2$Wš>$P 2fPFZSHs\4fҡ4=M`^R;h!%ҡw]㾋 3E^# 1!uLVHSd޴" 4x!Ëfp]3IMq1Xt6kZ37XE8HlO8MkĠu'z"/t QaD1SN1NظbQQ , <+IIc" Ġn NF=椹vgRs2YB5mm4I:Y<2ѝ#S mYhV^QX>AH(:7LiԘp=L\PM@ X(KL k0].'4_C4: :hBq뚥b1ۉ HAg0h< ':b'=f)";t` iىAվt"`!qA6aʎ<7"m7'pFb@M)#R50ڼ 2y i4>)KtJqC4D p!S 3ijnx 3O9q @)D&j}zOq߯A'/ؖ,/_\L p mUu<R=0 aIZMaSR Wwki|ޞxÒzɆ0Q_&Nk3Jk$@mϴ`2HVqib4|S+ TccA 9eh'\|f̯pFh 39a]~ùZ&Ѐ1v`P@;uts!%+xeE.< Pv 3P|l wC0 ,t[ZQ`Xȯ0M 4.MthS)i9Cץ.eގ0EIѸ*"䑰F`@>+Ƌ" `;/Yi0؇f(Yqq+(jgk~H6Y*ƭMټ}ƃ}(]$p&AKcUMe%ـ]xATZ"~YU_9.R"`0C8 ٛc5Ce1c`P 1pwOQbP!0oG C!i4i8<x JñT+슜Ң1a.nc5 R."]և+j~JPҔdc54EMJl,j 1da8U2I_fF$7'oAYGbteXz"OG3Z0u?UZ|]cGP ݋ҡ]geU5UxPѡ TEGIԼfA<9K2\7F|T~l(NҔdE]Ԏap[4˸6z#ga@U_#8TF!`Ӊx< X()O5IccG RnqtqHgniR't(_g\CiVh0\nN' s0FHi|Pjȝ ;cW .k}4نբ-uB JcTo>ѯ? 'Fq"߄H̵AuA6bMQ+WZ`yq̿p2fh]R2`M8ZTN8hufٿU?vl>Evm=YL']+`pO&Gɹ6U ]d:ncDV*Ǡ|({e(f)FU/]q2Y F̘Loh@IB.kib endstream endobj 12 0 obj 68247 endobj 13 0 obj << /Length 14 0 R /Type /XObject /Subtype /Image /Width 125 /Height 115 /Interpolate true /ColorSpace 7 0 R /Intent /Perceptual /SMask 16 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xyI0}ߧܧ *WNe9 $nP7Y$ j AQ4]&뮬 .Z?T1MuU~ӿ3]uի>z$Oee%.X`[âYfG1cۏ=.aj P5R/#C 4sQ36:tFDe7o޹sɓ'c{X< j2!hh 9@N۷/*4l0yga]g͖R<]Q![&ZЂJ4hd#l##85"---4hPUUUmek9VQ LQ'؂hy/\,"SDV|S/EVkWE).VT}?=kDTjG$AB6$Ԣ"3#?Z WD`2鉚óG%%XA@BE"Sb/_#?9u zE+|0\pFvd@NE*KN$G~}hh@|5kv0TDag?Q "iٲƍɔMUgMUT`>VT)ܾ+W<+weJxOY&R\3>eE' jDb)Z; @,%K-J 0҆)+`y[XOӦM 笋 Z$["Q- DyM &эyɖ@xA9!?"@u 8)64J!˖-s|[ 7kEՖ2"q,2ιɅx&O|0+dsuYT{ERƗ,eT;zjLmϹks<| ir77E:݁'_ĉJRVVZ>}zVJܼRtѢEV7JJ<%3xIȟM4quUtK`!$۸Xr⏷ʉ~ ˀ؇̞гi3g[nyy5ٺuʇQJgkEQ:a?{,wȵ8D !_^ٳ }zăZ-9L6x6lh{z\G;C_3aMT/"5l`ajxU"\[Hͨщ Ze:vh:4ȯ Φ*;D$`nOỳ(_U Z<{駭:.MT yf[u9w-OXEmȘX,w; <\o&sn!f? +΃KOa Jm۶9uyD鿞(=cd|󮢢!Aȏ3B=0V#gF|B@%g_g'/~%'Vl*b-v^YXUU'ח#'cA3G>7L4n'2/KyuG!n Xea<{ɢ.a2|pk-7f`#).;}duuhȑnk?OyLrЊL#fad+y%vOW#;}q Fm-ThՕ<a ׮\!|Iu0=t1!///l= e ^ĸr?@"'IKom+S~Y~Z|T; ςC yj9u'e„ Bi3V!bR2 R/Yy!ϵ~ة 5R4/x0,ss~-qtfM44k N7Ks<#f86k&셟z{mG®\~Z|)ڱ@F& % {˜4O MrYlc`9c@|!4%hv/g?oݳ1Z}f͚U* sqo_`߉[nU|o endstream endobj 14 0 obj 4115 endobj 8 0 obj << /Length 9 0 R /Type /XObject /Subtype /Image /Width 515 /Height 326 /Interpolate true /ColorSpace 7 0 R /Intent /Perceptual /SMask 18 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xxzڮzzX@"  ( {'!t%$ *Rt)9Y;{$9I<3;3;y'                                                            ׯ_vڕ+W˗/_tŋ.\࿟z?[e ۗ/_>{#G߿k׮-ZSNŊCBBrE88JdϞ[4B2+F&i:Wޭ>J }6lؘ1cΝ/~oFtXfMӀMlyH1왛>#MSudя?yfџ}{4b; kC:6 4ȟNA@&c2j~]wuvXҥ 9z:_WuVњN ~eޘj0&7m*1Żaܸq(|I<ڌiyb mPHճ#pƮ *$\79+~"F 1ǹ&0CHAֹ/Cƍ7mۛoahh(oeo0נsDPV•F$5lq8޽7k իWc,ي+^#5  -[4 XH,]8:asCTQZu:MYLo,-Z][~g@ȬC%cT  uE|ݧO֭[[^>qɒ%SD~@l is?ʹF>]a؝ed&SPɭAO맅-0;wCSNu$ragWCQWe… p u.;eK а?Ç5;^  _#$ܹ3ؚ:_Eс$*O!YxbeC8B_~gȯ\H"H(FvVڡCiӦ6=#Oa-ZP\w΄ 3fH殾ݻ|F9avQ^W"RTH#` s_̜nHoBuaRk#T> @` @#›]vu}rbbbڵk el׭ B+33V§7g 2kR=C=dXc]3 W σ$ [eW0er'PF.R)p}]IdԨQtXѣGY*{+FuFPPGl- 3׍ N#`G>И(Q| _vmpeՆrFtyV)H*L%D]|zxA^+j,,Lo,؊2 J\B=i\2&~U]t )f|.LQ`w^~䑡uLJO.Xir( ?n|Qǎ0N\Ѓv CtS'PcbS87DX^P?>Dv51yi\R\Pnr57&IV :urB?3GʕɘyCA"=q͢ݮH 0e!cX4@Fkx\NXhϲe˔m maZΑ#mS,ֻjPXO .]jj0uU1i=1*CA׼D@ϳk@-yM&`ri7ZD(eʔq(Hn쁭¹gU::gw6vQo8 qZFj`iU3Y-SMYl+!ajHF3gaQȵ!tMdےӺ1ÛQ[{A@@^K8nW"I^HToa \ -%1_;F)L{HLF XG;jgQeje=;!C8w2e۶mO9BCxcw0tC&MCngj" Qn i0V' yYcOaܺ7>+ m0&025ގ2b W8qv91LveJF"ϝu`EsRPX0/_\y;C:/P%kn^D4,v9[* e>pVX,9މ)Z-,hL'ֱ]d; lO\s)}RPJ*5pgxs`'`38ckzq5kܸ1SC\P%D'A{O^$r0`Jʂ?0~S2+!b!Qo5{2ne?vJP+`*'U sam!Ō؂ZZgmal5jejC^lZFVp2@ZdqȊf [vCzA #ԅt`oTF n|Ѯ{|zcJ7;Yh:dOaWO:t8Dym<Q+M?~uE #pѶ)7n͸nŊF(./ rU&*C`,m21ɐP?8sv㲢w211Iİ5> [!2@N NgU0>u>K6D`UNpns5 w5SإŤ8ڐٛaNL瑳x4r92|hXSAM-s֤]u>wgqzkGD{6j}&p&ʾC9J)~Nx=]h$]ӫd3I7[dX &.@ˌ5<+gDy$<|,욹N,o#pg.?|H-kP00] Wob,`?sq02mxx#CHܹuU NMrlT8vXgzX%!snzx/c"Ź9gSbH?-UA5hn:58,,xHF?1qAc*i'Ȁ&,]3lCvΔ҇Xf_@$d>w ó0_̕خ "B5l2uc8qD0ZlZE=͵?fՌ 4Fx:[K4o y@جvI^xƛe/ix{Go"A `- ~25a]RҭJ{2m$508Iq }]@"ǁ( jj$ Hܵ0KxHWM Kb;ӧr]sWC/!v8(R{FVCB*5ǗT݇ݘ^֯_H)]G5.eЛX &n؈ 16Y;0*Gؿ>HpF28 LD2V D*\`V̊/!lg.?VOVUKuږ̌w|kbѸ9I򂱭.nJ(RHKl20>xŮ) d\O͵k&oS՞9wUAt@ =5g„ ԔX(#p"zB_}ba=*pXCM}:p[^LyX&ݴ*\QL+Y;F[9ׯW>DǮ&F>jpqЅ!HqU!c;w!k0R.Ҍ]aoΎY@h2hEv%C?,W\S _T: Eac wB6z2Cn-, Jl;3\v5X   hgV,v@ NG\ 0Nҹ!(_Z sg}ΨĦJ uR[ՙ` ͝qM"[Uc}Y!'ABП /v' ngº WYWSV c afR ӕ"su~hW=Y!#sBUM̋B$  d?kojhp^f}ulHwgϞRPb.FeG`kMbVc *i10}Vun|z944F֔;IYPjM֛HAH=0Ӝ|!huvHPk `7V~j]oĶ.A~;c?w%# _{r *_V+]w& 5U˦A+`$Vڼ'Y.`D>5-5pR4[[*-+-uCs&ko,ظ  `II8iBhr.m8Wf}L7 qK /9ͮmY;ȅX%qM]X0xؼy !똥& .߮RԟZ+6v FR9cEAz;s#4Ln4?9b'"g3.~2K|W51]#@Ϯ][7<$y  lD8T1f+ܯe38K;AkkAOJBFBt4jŴa̠>Ƭ9zctن@W#rFtYlB(Q꺚=C٫_te GFsh2 ,ʳH_{CHS (d]_./qZ#ӄu+A|ɒ%PâDXۭ-\HG:T" 3LAY@Y |2[ǷZi|1}yKf* |M~*>Յ;ZBfpxuS A۲C8׳wʹ*Ŋc `K 䟘aXRE)%%]KDdcǎ7dB*3:L/MV:DzRi΂A-??@uQ׉ʄ/-A ȉ%}S$luug):ԉ4h@D)F55裏bĵ+ޮ_,`;5vwLtדWW+Q EƋMe)J)}ӔR%gƟOEv* I 4PWnzo򐰽B\u?>l0`/T3hx'5@OVJ K}PN%DKE^e Ph`qԖ;r#g52AWREB[!ʲe\}:)+R)aS>1~g%y=P@K<,*fBS; bA"BK K2qD@ ׻YL͛g}L5(”>@DPWHzýW';\6ذ;P^ @FDt{/fM̋L=' FM)+8cWXV. b)g#4Q~ar唪+P"X7n.@.Y}j3,,ō[>!r!?%6z7Z5YrH WGQĒ # &ڵkyh9|$IY`zA\a*ϥQIYۛ[kԨ"s-^'^'4hN?TR DJM++~g&>CI;DٿT DRNDuSbE.{/Vl.@DN)9܁z+mѢ2Q\>b,[r+RcD׬vJmhǎƆzGu㕦2;H  ZAq`߄ 8ꑯYn3s\v]G c&`ЊIh"C𫲶42]!O$SJA@8x ˔`FPbqsUcdl%eA ͭT!'|-Z&6rb R+R#q4}ŋ7<}3~&bM岬bMJdaA\$syX2ۨA0v8vvO{q@8I˦,c11M6** [5iE ?^oPdfJD@!X R0i_J(iZl{&|z.r(~" Vt~x eׄz0l\@3zhWF–-[2P2wA  e?tV:K9n?edd@ x$MdR2 1Lbi g22td@FYfȎ_y_4&|#/YuF(G%%hanIWIZ"0eW-7K=r r 9¬\ra;yp̲&_ɂ 3gDw}W"m3e?Kcc׮]Id/v8nM} ;D111D(ҿMB9H2(j|L^$!<5.f$3.eٲexYf1Ξ駕*U!5ƶl >^JA @jժ!cʄ0e6:8LA@Ȳ % ѣ; ځ3g~ך8K"6 WbDCʂ d&` D7֭ֆC ѦBr fY\A@@;=0iM8^:M @fB`۶m'=yYƮ!3MP" ^$1G:TJ[s+9+ hҤ pE%x ,Fz iiIڵk'%nR)@AаaC>_jmK*uL3Y E243!!|%bCwqFA #@ :[SdA@L9Rc?ۍg/A@ȔtBc>|ȑ#SN]tD"ʔ]&%'OfϞ]$.ѤCĩ~/;#VRA s @(~ǎ,w雂5kdi,A@zC%5٬HOÚ%:#)5zA@́Z6/^< ?<3Y BCC5F#l(  d @UZիcj2 A@&qWJqRRXFyꌀ$ ʚɬA@(@wI(v޽[j1gBBBJ,Y"BPPPҥ˖-[R%bMWX\rPO> w;{}!Cٲe<$YjdWB)Y VՃt#'F߮/SVxΜ90saD5 Bx"OAzd @4h2lEW^yΟ?C)L$Rz!"5-G&@V@`ҤINohhذa'N@XDogkYsAOQBeʔ盩AԳgOͿ:ߩS' S:tuC~P`A@uw;甝 ޿?2:u 27hoZF^f'@ @1tĮF/`#/HgyѸzNS|۶m CL/jn3ڟ+y{MGlf̘!LA ]zڥKWϟrԕ~ztZ|imP4[V!cהXA@p\9y_~Wb=,85}CO s~X׏lw[o6?ҩ mpMCm _Hl<`%_;Ҍ)S3  \_p/N/:1z]th|E̓'5TBb_(\XB%_"~+oW׸Rys^G9zOwQ{ !wQ;ymA.֯*5 >A@|]xȡK?xfc}K/=|a υ$T NR*rɄJ%*+UW/ȟg~hDlJn?}?}:=ٵkW^C vI xYPZ ) A{bP9>ذ٬!Ybq[ o11V\QLy1y#c}zfOD>OD?.p/WT\#*.u9o1f0mUyrLXm§+Snpu~m=Q˖-:vHm-Y!>#GdT@A3'K|)EI!jA = X#)~mLnkԞ%w#>.~L&Psb͊1[`֔Y.gzs}Y=(_nYjȊ-Z7eǭ 5"G:*?]t:u14hpL#+5@Z"pm_o nF;>mh2OxB{b -gIoɴSEⲈ|c ̊)4[d-(oK}o;= <ZE-歫3zqqZ7P o3忏҈Ը?9"Z;͟?n!i^؈ u4(`#P#ׯ߸!n]ߕ°4/Sk_ S''x˜|>S?A>ܸǢbwTOȤ''-?rU_iǷ<Jy+^K7ԍ[T7r_i?֜^TRA޺Q+]ZGdG+#ϼ?qow>m FA)329u944gwwnL^6bk@aO_EZ[hWu"Ԍ8V+h'ԍy@ՙ_'*-F}Qڏi4+bOWl9ag۷ݺ"{Y\^}Bu}M6v-ZZ5vΝ0ylْ&*2;vOW)U:9,<AvxJ,wacjt~K:wX#T@ x6h{[vn=2tXTB|>n)#MվÛ.yM_>C |D[nDZToe2V ,5ٳêTǏvo>5.N#,dtgdAɖ9g >n~ϵ#&K{Xk?P7bYM{w.Fv\7CǭVQ!勽}Worp >V'u]w"Qv[j$d&pg}vŊlzj:p'xB }~LP2SNRH].'%} _RJx BZQ@Gi?#7ϟ`΁Q:=:a֏k3>7m mcF\S2J _/\Y$_eWҜ@$^~Yf޽ON݇߿x=|s.\HqAoqБnTpWOLVNϪ?6ǨUX4~ϨzM"4mo;Gm.[Xi )#f$zp~uLX+3 ;?O nS7q-'Si)nk FjO?MYJnѫ+ _)v.D)T #] u"3&~/ƶ5%KK}sxN]-[@(AM_ .S 7wrwA po=PIk.pr*DzG:=g9(Fy`f@#~xr&x h.*7.ojV\2AH!H{0pٳgfxrA +#p:&/L.D(Qv *6R]La@/>.HA`rǸb^مf?i\.V ٓJ ?СCh>yС8;.2[A@~˩̈́)  )ydg18).@ *;?lH9 C9нt E ̎m:fo#ív^a7v7I6oUsXNM6[|#[xGG^*YPH[` BӇ[S#T:X'"uT;< 1\8r=/B(De|.3fȾLcXRV|~槽47}4Pwסsm#Zo{YĹb ]ްAOĿ1*.0wJu.sƏ+β`˄w6Y2)YėRn+ ;vRr]]yT0#q /qd0ҐeY:<+bߎP\ILH_UJ\a劰rpTyKX@dl)A-箵7:ta6X1ؙf###9Re a3t3|!t30DOXP(ODL &_N/p/~f(`q3w^#|tҥ#@Iݔqݻ7qM,9xK[CL'ku Q [к$f/^cpm<9|y`XQŬS`O.?Z'լ`[fJ"|EA.0nusK1Sܦm|\wFϏg=BXg)1źtG\zwQU:1Lm)P'tiL~# 옼ȍc#)G8:`;']<1$ܟc2L%!X>#;Rr M_YeYS,?6qsb \,9*YfMj`tK)f\:s ^AJ- \M}02,A k pqփ MX5H|9,uKҿxJͷD1qSͣՎT8qm<=o-{۴iCPRR))WRj' )8˜P^4M@!T-`8cmc&vݶ@"pnF }L<5jTtt4L+ZJ@"]0p:'A@H9lJx6TSRAg-Ib\/ԋܫL@P{d, #HN:S(DzF ?l-H|믿:<$Qz 3elo6( 1WϞ=ҽ}L6qOJUY1y[\'R ԙs*`e@K]i5*1s "*?'#+cd@#p9~brjǁAՂN U|'dnL>Bߜ\S֖jsyw(L,Cb ˍ?ϕ+}1n .^H~{(W] {TAիV $o7 &dF7zTpqVȅph9⇑8`[DoYZF>?`F)3 r[f2 8W\IY")@lmPjG|(:Q^ d6iu&bLFg vi]7O`Nt%ȑ#ǓO>̪Xy$yA5@#GZ,rm=5?I$7nܘwR@Z"pmW(pdbБ!WS8$#VkV?bB[FGO~J .ׯ_?F "(LijfzbSԣGe!Gׯ饗c=}t$]i2˽A e58c*W*A5D]Qȅ ) &)\T\)ѥ]8} vہ AS 5m Cekвva-GkI@Q{v5Y M4IIx/^|%п?Ho'R#*>H  ׮_R(DpZAg樓H&=[vBgK6ޛJ/Lw+-WٳM&PXk2Ed}a~7EJc'iSF|LKj@F=52/9g2UȅmR~؊ڵS7#E&>Ѷ11ؾ{JlLX_uV^uk֬)\~q:H3zhԤ,#?Pv;rЩ&Af/Sa|JyWJQkh&^|QF;5 ӄEg]-$/̍{ƿᶱc& GG7&\83%2$ck'b8[R?;ЁJAF80*Zi;BG:_6)S")jZGr:ISc!~z"Y=/7,VNTx|S2 %Jdf?-A W&1՟-_؅+j|nYEs}1%ہd󡜃75[jŸ]cکcZy-2 .4q֭[w߾}0dAV"aKc+h0O/o/\A@H>s䭶 KhvAU`,Ď`u;#Sӕ!bQn"|Ғ_}tD6mڍfiJAFj^e2DFFf%s?[,Q4dIu.TG PQ]]~PHyeaoWZb,4 ;Odx5$y]1c&mȎpa6'H?2~?A@8_?F;Q5zsFSJq}>VWe,1V#v(ޛ 8S4 w# 4 HAO$(P㭀ZÇ~Ȣbc=nƝC)4Eŕu"; KN=_6sW(4Fn-Oq6f&2=h,:u*8 wa;xSy0Ru),Q}_^O`x_) @ #pţ !tEr/Uε$&G6aMثQm}wZo5j ~diG,L~400.z!ݻwgs~ ?3,%ۺBOM -oq|v=AF!Vz#x•0GP(,,L'Z݁1=qRP:k-[T^`WƛJY.{c|Y4djCϯPǔ Z .#x#ȅ0T` c[ybJђԧF(4bk9pCЩ4HE~ѢEүZV-+;fR@FҮ_|2h|n~Sjnl^ *.ǸUO7dvā>Wwzƿ%vdel7n$Nu5vAcǎeZ!1ʡV'Np6mژiÐ  ׮m8y;pvrbX A)7oIW( !j2vNǟ o'5Jxʖ-p^#P~TL2qgJm:t( xPt!tnw%A@9TY'Az^X NJ%1QBuZ8.h ]ncwB >rUo߾:fOHJcJvzjJ?%"Z 3g[Q5{+OdΝ~,usfė/ K6Jx.4Ut6jbBֆ7yH39jGΗvţ[DoS& `ʕFW={bH1"aH;H %6V0EÆϟx7xyqRAуVMCFQ 5>X\59O'FeܸFY?*YTS&UCA0Y/P6 O?aܬIsX,Y$^ kp2寱2c_;v[Qx{キSN.ds&Pd]<`@XB<{S*b`yۚ6q}!VSLɝ9U5h)m^it\R%j-[נ6G+ˌڵk;v4f"om޹/3Lɡ /ׯ\95UjAw{J̊m"Lon >UD%t}bkUv1DgO0AhI٣S%^'O<%$$/^\ZМM(SVz?5V22#Sr(i q5JRvGP9PBȅN{6x 9%L9^ۈ5࿓m+Fovzw~'F_3{6l0ͮ[n4IR/`2d^;da͹r(`ԴeeR)i+W_-@.T-1JaOH*#W?_GSO&W}ZA6fLKgQ#78j-vmFߧO*7oLb  _\94| M˾}k&NhCwNP @:"p6zusNrʾ>PZA;!t~;F}F r`og4%"ڻwn@$ Bi'u}I[~IXw I@HNGڄ\@;`)&sT4IAG{.Z/rҕW9{lbs}"! *F狫ڝwީmcAzo 225jD"3eRK<9n i%)%<tO] Nk *%)ƕ᤟Fnk2NfqCiF_|ō*pi ?\n]r21F\S0s8k֬\/_>\YR3Qav .) 4#^hjt5wP#dv!r=tH!BFDO\W1h8zѰ ZTx=ä96EC.@`JA@H ={*nb<3%+٨UG}i>*mc;1d^5&@H5oi$z&A+=f5B%*)AuVcC) @#p K;Ʌ<Ћddp~)1S@W Zʬd7׳W&vpZK U!,_|Q'Bvp=f@ x1%=]f엌 ,i˗2:lA'{A/[6J ? 7̏{Oԉ 7ڭ4:=帶ވ^/~K4F2ގI^&ݬ͛$z[@L# fN'+7 yB$sGpES֝sάC)&貏rj`"0"@";UV4 IsاEރA -8s\ B5?&C{<)5.x7oSLiX lw4vΫJ 8"MwM9sYfv+ HziZ'0J 6\;X.A tfS/EQq n1S+d(*;c*޲tϵhiTV 42ZzJĴj P=6SP"szeJ fXLBRN;7##8 p^(db9_)FS#_V,ҳc}%MAo/'ڡ. 5fʤʮ8xe \~*jf|(s0?N !: qp(̍{t:#ՉLPwmL{5?(f!_TIv"W+$-s(2ׯ\9ܢsN?tfm|!dh ?7V6G97g1n}tnԒTb:;| :wLz}Æ ydM"p]ϗv tuȹv0|y ۱~Nl~K;֌8P #fTz܉s79eiD(3,IRWN<&( M)cJA@HUNP5؅:1(B\iVyiӳz.~VQ;FP+@wem3xT$v\~֭ |X_+ *Tp]ɓF^!> GvU݄%뜀 >gw^g3qjgaO2(SO=E?`Pt⼒Glr.vY p  _TlB@sȅ|S')ɶBO3%9SL3']6|y/:o',܄5(/Xn80ȦVC؀# o|N ֡ &]&AI4PS~eDo1-=k'|?R9Knڴ;րD$GoB &2vXbbz+Z2`CA pH˻9W :+ā`8z>;:nM:E4NNfx BiRFjaI: sTq4D4U@`D&L0v"eA@HUp:sCޝεp 7FЯSC/,9?GzJ-rT bs\]#vbɚNixuv`lKpѓ'Ϝ|#QSL9wnئ2qDI=lŋ]I~|I2&n$ pzw{z5aw'/YOvf+M$Ï ů2|&1%|Oo<#s%9tE=!A?lkV<ݺg*=["G8\䡪2GpD\Rtzoa#=`I[[Ø OFvNkqś ,t`|m@ }ϛt3bYz ZjFr,YԴ_ ( ܹdC,ed#ȟ?hn3.:ԕWR*zڠsBD1vUETs =6w^@Gv::lMLYq|(-vϷ_[ -}#g`ELxvMD7Ұ_t)&⨉V+sνi&m०J4~aS.{ qqqPn-_lpdΣ|?)mESR-_{up`(_1c݇/% (r+*ɼQ3kh1ISlz^7 [O{|{p~ޟw;hCvH֪RBHWQ\ S^-Q({90mg~ i/%kJ o&.M]W"]Ŋݱ_JÖL]Xa)CW~\YrOBaZ)*9OxrmYu/4qr<_aY%ciAhnn^feͲL1K#66611QFVoVD@`ENzHw9)ȩ)xbOmVWk-mo5!O5R*&X,ASZ9Jd g]Ge}㡊vRzZ9Mۮ p͡$mPkȓSko0YG.nx5o4zA~Ø-7Km68k' c}on|Ԟ5jeUR5lJBX!Mnws]RR$]I=H])ɕ)et+HΎ\ݮw۫ߴ{.]j OG%/Ucv 33Suvv냤-}##BL^v:Dy=!Z 8'&gO_exg`o/4t?JZ oYjp 3PKqW\GrvKv{VݳyR}r{eǺیΝ6_1t}?eetX,8Y,/Ğz޻%T2e ]Yng0r~rf2d$OvA>t:礼ӳfd &ʸ62v˪S?\6Ӟ g>w||Lɳ?hiv|orff28<2dw?1%HZ2/8礞g_Yv [ˎ`v7 )e_.((hiiJ!rqlUâW@=3222#O qB111A9AXOz d3*d@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@HOqpI endstream endobj 9 0 obj 29209 endobj 16 0 obj << /Length 17 0 R /Type /XObject /Subtype /Image /Width 125 /Height 115 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x[klEݵ>-P"Dz }h, 4Аj cプрILM@ZђR@xْ!DJ %ZJ뺻w{7݇g󟹐>bp \ٳ4W-s7'.lfZ(嶉Cm-$q`u季f-UYH/*[,Q61&nkeh+dl86FbP;,̅[; ǎmȰ2ן"w uYO s\Z(lPZۋEH*nڍ79ݠR(f3wA o + stn.< cXzH-!l)z+)dj~*6ÊDubE[E}_7f8.Q*M} aibޥ^vî9Pav e-FZ\pA]6oa8AmA"1}Gx2qEՅI&C舟Ãg溴ю|vҗ1g\F|' ~"WVɋ3ZS8]Gc0\Rͩ"@*"m8"ڒ\l}K-0њEcU+ьaJYXU VjP\:ءeBp!c%Ԩ+kO҃cg * ?/4,D!wv{‹#˻c(aw[M{v<ьkư+Kt@lGzC߸e_/x$%;F_՟ w7ɗWA_zA Hdv[!* ЃFm2y lF( Gt(烯̋y!8Zڤ 5@4Иۿ X)y`mr h4ИGCQyLǍLFg!LٜcFH,MCs,Q3^#BJh+otJ۹ܙ2VeSm2>4oD:ȸ1#~FG鯸Mp0ǻ%;^s|˕j?=v k]k+&ZP(a^XʫgΜ~HNI&N-io=Z|L X7)!7nQsKU/=v k :,Ԛ"OՇk?I{6B;^Fe}-vt{ސt*`g'%nFb)g_kuE9Z_#o/(_z)Xz=rl(}fՍX\j%gv䆞(|oHߪ|f!lk.wI. $:=??˧ KRs7z4!/]S??m :b"9[?Ï9]q寊xS(z endstream endobj 17 0 obj 1458 endobj 18 0 obj << /Length 19 0 R /Type /XObject /Subtype /Image /Width 515 /Height 326 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x  o7@a 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0`y`*hr endstream endobj 19 0 obj 755 endobj 20 0 obj << /Length 21 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >> stream xwTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺PtX4X\XffGD=HƳ.d,P&s"7C$ E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI(L0_&l2E9r9hxgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/$ZUm@O ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h A1vjpԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a ٰ;GDxJ>,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf endstream endobj 21 0 obj 2612 endobj 7 0 obj [ /ICCBased 20 0 R ] endobj 23 0 obj << /Length 24 0 R /Filter /FlateDecode >> stream x= 0uM (%TlImo!/y8GuځF9 EIQC[^DIZ#e cDc{S˔HVyE;l:dJ]~8,ZUlLэN8] }RTe,ͅ.Fbnv8vַ8PY endstream endobj 24 0 obj 203 endobj 22 0 obj << /Type /Page /Parent 3 0 R /Resources 25 0 R /Contents 23 0 R /MediaBox [0 0 1024 768] >> endobj 25 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 10 0 R >> /XObject << /Im4 26 0 R >> >> endobj 26 0 obj << /Length 27 0 R /Type /XObject /Subtype /Image /Width 798 /Height 450 /Interpolate true /ColorSpace 7 0 R /Intent /Perceptual /SMask 29 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream x xU?w};s^GG $:.2¸ "* # (8.$BB@wCXdM[v9T/tWw;osS:ԩL>( ( ( ( ( ( ( ( ( ( ( ( .ۏpjNT&b^;M SUC"Q@,!t Nh5@PO+۔\en7,+dbhӯVADPRU' wuxO2:Fz]DhV;HvH˲ZgHm( {4}duCYnz]tdM4jRF37$,khTCDPq'MvHBƺ! @* ڵkZEEEyأGs|4˗[fq_|歌sss00MbvٳG-bɒ%GZꫯ:vוW[D Upt  W^y~GJ#G )5JOO|ƌ7|3F@ufk߾= շoߪC"M6 6 y׿'L lڴi| <3ΝCb;E_tÍ?K.('cǎ|(..޲eߏ"qjjj(1u=:?~< 0uKzb qذaƍQa3](SBL\PN:= mAʕ+Նpbbbx_u51ۘEĵ[o. /ꕀK 'JBO4}t,+]rC Hd!#Ά!>\rկ)))<Ao:9>\Pi,XJA}>ٳQ\>?CP(m;ڋ"7\P1_~%덮sC&'( Φp[sӨG+**8 <Ng};c}ƿ뿺T @ש/ ?B|J`ѻQ<(QL"##)qJp̙3}+2G7}tN0]l/^R3޵kR~駎 qܢuԜUT0.+xE4(B=I5sq?"4ԣd0W|8?? Dc g'c#? FRन?/Ta6>ƪ~*]3"r1'cű4UDSpg.*‘N Rb^Wd*[|""wߥt]x} %V ab/Q0G'cÑ(p dmsQV*^߿?6lPٳgsb/ C2>L3&@:3s6 ['CDSoedkS Duӂ*N81F  'N 5PSO=EI bA8LV_0WNj]jK@(N=_pѱ&Tپ};,X]c`(8ٶmpeK]1ށ>⧎^prGpA 8́RoC|MXBnF40,``05СCs8pv cj'OE5àZHO쳔HTŒ>  <QmRr֭8\QoՋˏ691pSLjY hQ_QWొdҨ9F\( `r0 Cs d/ E?<駟P7\ j)NmN,( nk>eJ_y8ķk8ĉ|+c…HV0PD# 2\"uLeeeʠxTr$yM*`pb b1dff"7ඨu&K)+WTMVG' ti$-`Єyx9EhG`$j8*3h0n<9=%%%HkI'dE<>aM5sY07fHXSt6)1LL0F/(*ArEaꫯ:QbPgA:Y]$! T OpJPb( ̘(~饗\!U p|+ xnVqtφ`J)4!Wux :;RWNY4W "Y7FQq@F7( Kq"4RJ00G2na)x1Wzep@jO]-7 8fjW)E$6L#&U$VpdȊ\e W`5%J˜,ūdU)R '>K6TUKmh%S/{wW=DŽ<N{qUF )OUG\\_mQc8( lvOOcBhBѣGՖb:}g,`#sux`CVL#:gePeP5NA4xxunu:ea!:JiΔ()abP5D-6mgvvLaTup3LǪT:#@鸅}-Ade` F>jӜ Za\S\!4N_!B䯒F3q5‰:O !*|`8m إr#Az@ z@>g40۟R>1wLFA\(=0Tt[j9l)Y\1DQ@lf1Z Dӟ6,p827t+HvIt,2C _JP<݆,&J2!AiXK} ÇܰED ȁi8gAUOrʢyKMx|%QagO|,G-Ԅ 2N P{jhZReL A.&ī8on/x#ge(8:s81.SzÝHQp3թt8vU}FPa>I <+iHO_7g+gg^ZSO3!NHQ@P5@4a:;M`? Gwac<\60pW"sN~GR40sd0 s%y^VB eː0..: IХZʟGB,fsb>5pp$fPΘőppq` dSPIrVg!7F>. _*NPѴ` U=2,DKL u@PWZJ@Ap X[7 TD2na<nLu/`bp/reLFJ= X[mf~a *>; H^Tؿj쭑EQ@&lan #,q̐#L ʢ@LAw_ & +BJ aBOڡ|\m`AMZxj V 3 DzC(dy:^NaI\<n` &$cpBv^2kAjdYXKE |IvٸqUD"<@cy:S`f! tQxm(ʥx"D yHM6P'iS/aOC>a| :)E P1`6O~C]Pp" s@Y kPg$څA("\ͳ%h>>`H>n;@ by*.` pR2OC&<H|l3fFq1h$%rYC{*$糚PV<.Eh;LJGG!q) ĥH A0rK.C@A\fClQ@E, ,5B[pb՗Xr962ClQ@EgJzCOP%gy8hRΆWQ@E&^$vTOb KD&]oĞ/iDQ@DUyڼCF7ט]!|i( @+;Sw(^Tځ" ( @YI>hzSb( ( +rl( ( ( ( ( ( ( ( ( ( ( W@(n@N_"kK EQ@DQ@NBW8x*/G( (Ќ *EQ@DQ@0(`X!C( ( ~UykS*d. ( -\?Le/i( ( @aO꣤r( ( ((!PP0( ($Bu MY( @+\4u"MDQ@D7 $XQnd]( (J X=ZH5Bʑ( @  6S= b( @P+`AhU kI*/ ( pZ2X-( eB**\VDQ@h @ Pɢ( zRTODQ@h! %>h!4SDQ@ UAǕ:ּؤV( @ 7lo"[uۡen/ ;ܻuY{.lSڳMi呷F݉d"v7p)K|(.Q@DQvEi;J{# +lSËP;OXITXY/Wjʓ:X?MȐ t!WPDQR dׇ{VΒ((wX) -MInW&A_RDQ*Pte=TOu'r6'NmhRA! n3V\.I, ( jk";gG ÅQwV`~u΅;xtևP]\RQ@D)oJznӜ}hZSIɰ 1|h;Z(7NL8r@HY܅bw~<^_~w?5>iZup+2!,p(  :xRyxjFx9PX蹍dmi%(ЈƄU`F?[61իƵאXR%Q@av=wUD&1ɰC঻+^PvQyoehŋ5rDiCYp)]Z4WUxʤ]jbA{_'V(7/?1ubhS9?h )CXlrr^}…j+ -Dޭ3Sr^mO'cfՖQHKÛKK.*K)ew] |åDQ@h! l_e}ZaviL$ęʀ[X:bҺ/4W'XDQ "M~@\8l% -DÑY*`:ֶ&=4=|Z]7g˸-q[aF͙Z6#j~g緭~JQ҄bp𾻫ezH"u^}}=aa`;*^1Uθ$ 2~xOM3|I02ZfySt^3oNϸummt:fd3s h[eTUU-۶z톥f@`~mȇl.ig|R*0[JZ{YUx ^g3+KmR%ޣTւw ~4ZuNl[>5S\/g |ɝ;C6YTɻ8p l4RR( v^mg_d"DYIk PT4߅BoݖQZFm*lϧk*\*۶oۊW-4wJL);A~baˆ pJ)E@+PEso؉7"jW:;uFm1tO*ec\gg1S1V\]lw곻*7L^W ==IKS pɇ1ucv97PD^]a5F7MM!?< P9R"C'6I@V펍j[qbȪ޶୅#\] \Y]@>TdZx~XYw$Q@yjnğ}~#X6cx2==Vipvi#Ocr;܉xPVU6^կٳgCOYDO> LC{jj^-W_Q( ""j.j` kiTf1[bx+?Y9V1VhԌvŪm B;kW  4乞\>|T8Ȋ  EW4R{ ͗e[pyYq⌛3~WM>k|E#*Sϊ ۺވ(6UT﮲wUt醁 """R1'GL#E@H*z 7)7&=Td*k^2uBBow'V*2: [ھj`YC=" [$1HRjc_5|(RbAF(5̙3Pn/ !JtneWUp_>1@&A ~mwԦVUTmf'>>}}PdqO;yvWl U|`8d`*W_p§ǏS2D>Gw$Q@Un2~\U?G`w>7/֙iLm0#7iu@Ve(2 TY!X]4TDVؖӶfPf,}XTn JDI 'Ob[}%¶PIj!R($J"媪|8LU܌څx[_WjjrIqCG/=]& ИK7GA\z **6Rq +}3:R8]]UUPpsЇMyy}( Y xcyoMVy)6ҚZKi)]E/. Dyk`'ƍ4TrToc[(֯Tz[#VٙW'?W}%N-hA +gJDQ ,?Wvz9#XG=S0kK7\%7nO^Mpjl|uҬ[d>ٞFJVUQ[*SC}펿j;\)(`TOD(u^MV3U`O7y^'< TbW,?-7bW<]Z&+F)`oc[bn˼uwf:WXա^gVU{\8u*zqCڕzC%~גDQ@%=K3xt9KbETmNVT1K?x"z}GrSܢ5ď6Nn +@Vn-`氲|z#mpŮ*a'+ C]Of[J%JDQ@Z?YY{N4g*T ~pR'e?|Xl;ªIVvbZs+˸ˑ4 'P@ {l>{諸?t<6h ,{( BxrF1*=/ Uaݸc6)V8iqF-vjC5r*c%ٷ.;uK+Vٙ Xu!#G"U [c-)X%a94p J( x@Q؍^3Ĝg,undfg*.&+UbȊ/Y?ik~UVqHpUXe'v`TUaQ-TwW Oғd&i>Vnbr( Qo3ʔU@Vާl6Pn0Aku%,b0`q}> ybo吙yDS|VG3v|:WcUQ8KǏ؇6F 敺I[(5DQ j+ ; 0Y=1fӱjJCb2LTp[Vd¢W~濲Ob? f;3 3h{!NOpewUNVUl_hMEM4%) (2c Oae*m- [6-R |X$659'Y1V8Otlx{Gom\XOh!a$ X(uDQ lAᵫ}媊_ Mƽ?z_ ɓ j*_^z~A@f*2m+;]UUpo:\ Tñ/>ǔd 4&EQ@h^6L<nrU3R; IsfAiYfվ'gEo s Va4ɊGaǪ^Yjzj?q@f*rZQHn}"U\BNMbVuPu_ǚ{cJ2QC&)(ڢUښM*L2%XQ፥'g2eװw7__ɜд_ɘZ7 i>@3|*RZ}bbҌn۝6hg*9)O\6ǁnt::%{̀%ǀ%EokLDR g? xW&`&VŚ^-F}bK2д0>)#M(zӝO>`xr24O.)G7nf'f*[EXtXUv.G^V]UTuPӗ/_KZʬ3gs*\Q@{צUgڦz)F)6yó<s*X@Uzz1×/#|8&>3 Ӕj8%gb+^^m<2a aMnlFYSٶ]F]TmE߻:b)7p( Rv?/J{mMXCzDb 41n_jV7 MDwQN=sX9am؂?9pqT`ՠo%~boXGqv{V]PpGqP]Ym[uҢfQ L)KD7 lxCU5#L̛>'a1cVKiLhkfX{u=V8tU\1PSqXzr[LEdu15mNʆX*unEe&{>}qs]( Faaѱ&`UizjA1ybjԄ"3-V〘aE++G\}=\ -1mדJ hnmU-cڴv-[ݙȊ `SYwۘ |әB}vïwUiXA{\:#4mJ)@WZ5YZ';1Ɣ,LD75}O8Êa0Y9byhKXEۙ/gL5k';^Tb`*XrȲzȈkwgenGf*;Yu;ظvdUuʇf5zs@ n)ن|EOir "CUiY TXur *`Uyު Oҝ3€}*&3V`c! jdl~fa7**fu1x@V*s1\8 T ngW]N Qk̺IJ>!]cOn)qk" Z}ntjOFMo,}DWԧ_J*GRa*d(VY_Ț! Xr!K";lF~r#js:3Sٌ.'w|@b:U=̊8SSTGUې9bÐ@6^k׮*ȊwA ^c[PRܪRӱoؙoL]aY3F/ߎɶAKʈbj2-Ų;Si@9aEXEsKU=lpUj;B~6zwQ.+Wur` {%l1Kۃ}z C @J%vS `*`UĪփY]_Ty i_˗W}7rͷ;g\nI|}ܧk~.…͞z׳f0uvX8 boc ^jtk3v?D[Ń"m+^^ٓ]U6*hgګXu!;¹U4"m]:]b^(j G,iThNNƆtHχᐪ!iPUz VV`Sߘ?ް3U3W?ekk_+VMjszq՗bˋ9Wu.oў)n_sAGLVNWٱ >ҽUL[Ȭ ^{%YW g QUU0V.k^ $mm|ǵ@ TR rD|O.oWlxpiIW͗Û]5}{7L[5#-& j1X5miCSg Nh@Ҥ__8my߽q@;V9ۑyRʎU^ҌlVVrr:{lpB~fwC=O?Kܕ2loۯTtp_ч")Ɠx:c=_ #WfOY/jyS֧tw7#SM>AzOwa߁_nHm*XϕvloGg{ $o1oG^I+*!GRùUOh#գή/*,-=ko$H*]єj'FW?ԪUyoWY ڧ-jκU'Ug/SUS>(mS\ݩSswļS04z- aĂaSV웹f#V\䇟Ldu1;D*S=еcQuw6h.W&[a'v*(C6l.dl8&]l8ij e%ӮL,Ǔf̭*6o)0[5`>3WV>x$3u91{/VOY7̰bocs&~}9+*ޮ(K*οpdu1G]rA@V%jz5x&j)&EKpYdkh<ܤĘLy!Sw9/fR IPk/y֔KiΘl7X׳)|f0aeTVQXY^sJV\ipuSFzr@v(AK\aHl=?M3EKj郀}NzizYX5su[S+V0_VM0gծ:ŋ׮8^6 :*լײgjs˰*MXW@e0w +-\^ֽI U6zꑫYG7k7#D>W/Z!_| "p% [6<@AW6(w :-{U_괈XU3W ܪoo}bմV}\ʈ38Ԧb֦S@l[e*fL,>}:Y! ;+)SٿX"~槲;๲|Ρ! 4@MI`Y@W6E;BϏmjz|WmeYb@Idq1'U?GęUߤ6aݪ&USKJO.Fn}6G2VdE@9;CUoaZ+|v (51m߳.A Wv"z[+eԒSR+O~Ƃ \rUomPz C˦ieʂWZҞfϭvr Xu:mbͦ< ^뫷jA7 }ŪKTwc~,n;&ϕ Lp5m uXEpÔOpec*UytՅ2{ RnP3fC~敛첲p= Qj5Uzaˆ'"ouVY7{MڴU2n;V5ӆܪagy~yY*eٺa>+*r[f{m~Va(TCW» ڳ:K1b~GT5:J* xQ… <*vQI +]Z\mmuԖ ަ~aoUms2n3g4,6G균t˜<_UITUFtTܱ:{mnU*sG LXB|%ꍤ丼*S^Yx Tgps.uh:lM;pb4ޝyV* W5VU&[ߡ݂QjS{!3UBIz~fز=AY򁬘'YIc5a X_t@5fZ/6N7m骏|yS6K.e9\ڋbq rU1Vad bȪWVQMy JBӏ^9uܶ+fV x[Qw.⟾e_zr.6( exO0/ʬf]}^J͡ddiKWmHVnէCݟFX9'LZ0止0yZC"ziewh6ym;\D<_+>W/PWF '' [*:֓4Ji&;9Dh>h*AmT(ݮ/62q,]B#r9P>}i:^^?xqPs S dAXܱ9sf/ʎUU/V}2UWPgU?'d:>~T@UBd pSP>-$'AJ-mI6<> ϏEJnA]`VajVIk,KW6iw ,L`_UL9S4SgV|QuUYiXexWT}9+;((T*BAԙ=qW'iuC%Ֆ\_Y.usN"x>D5dv(J*^9ԆUUjj>8dxW fTp*LLsܜڬ5F~#V xwXU@'=SlR(xXpJ'yiX\@Vo%(dT؁BnasJ* 'T+I^}ٺ:ɷnUf%+@$򏷶Fe˲/^Ocj'?4UFUO3t/jIO-q< =u>|2M+"+lywrVVaIubCڻW'$b}jw/CunuizcH>6xБ%EYY@A0`HN;CgѱzqE$jy~^eBGǙUi= Q£>bՀoMy1 6xǣM|{vm.>yU|߼q +a> NóCW(af*,Vd偓K_IV"vy\UU/'U#pՍUUIk#to{ڙ ۣ/<㥋Cc9<-K2+(-A/ J@yʬAkff.a3қ`-xYi ?y6ҽUU +=^V\MLZQ]*6Ұ u|d$j8]p"_&%++WR[6h/ ӷlუ&ƫ٪yRVߗ4{,]bÀM{ /\7 o4LY) %@uܚQp|9LqZ yCpqOP[Ǫig1* U>E (t"¶7ohRՓV~㒸yư 1LGl4,TԩSͨ f@sgaZ`^VQXu d:6:x'O6A⟚V6Ny_$g(3 ClZ<(@1Leឬ8 1T:H+PrVg2qzUt&W?xKM:b={}H߽UTy{V Xe ]t XEnTP^l!_wO}=5/Ȫ_dͨZp):J&>(ہgp9((=j(8Ge!|`i`SJ2x8#*f| 7`8Y/\V6oz `գ J֧ ]5:ޢsbɻPڱ\1VKґɫV$bv]:Vs>ϑɯ9 ,iڢ<+#qɽAO< `M^O)-*5[U3´M^55OX]:鋂>&ůrz-C~>VQj!&+`VŨXBѺWkԯS p=6?.?;I 7W7u9""$V+\]]x:ؒoJ\g0cnvJ#M~Mp:eÀ&Nq/|j7ӫ>οX맙j:)%_vc‰.:LEƫG>MÕTpv~~:PV'TsĔ:7 Kq\U7_*0***ZVUU5t\O-EVāT{ӫ*VhV:Ƒ_?W< }6wKvZ}DVU6zpT*u}7 d_E_vrcՑ-K"$Q@{n1}ӰjZkS^aL>L Vc_W'JtඌRxU1K*jNhRwM6ZO}=5/_GVk_xfk?gEQ (oI61Ԍ4 jۦfjꦡ1 `Հ>TlHZ.?C9{W}aU"+|T4fI ;`L9Zra W +5\ ;_LZߊA8yK'm*855ȿ[h[N6c}pEc\(J)[,1UʺnIk&풙dVSٽOĒޥ{?dMWpz+F!EҨ;M$+mӦWUc=OSVR.Yf-IC_oT|r*Yip5hL\ ^O*ph틳%vJ판n +QE,Ux _$`;f 5V_{kJ+ޕo[Z^SmX 6f.Y锵grⲄWM\Ӌ=W'z< Pxd7ͨ駫ǫٞxlTLV@Yص}C;ڻrSG\IvӐDQ\E*3-6צ6x:-bIӫfr2yxӖd %uc*?'s:J1P4[ܵ>)n "Zq_Wa4G VuΉ\aN{Vˢ?@V@Ïv?u34=s凶ؘ@>^pS;4;` ؐ{Kʁ%N/xz e( XPz<`߰asnp^ ,dz@ \VWwđ}ե=cRPj߶DnoY%j7%,LE|E.9j\MO B-z<+ #DϪ^ ggC\){j:PsXÊ]XDYۋVY1\bؠ-Ivec`]qL}^?&¦e^C$ (ć,ܺ7]=i^ {{dx¹S'Jkʶ,8'H:#1/5ДX:S8i?mvF6 @P]*cݰ"~S@]+K^7vTKU{wn] ڬ3TdG 62W@)\(kڹ16'ܔoWF5NvRl+W;0Q@Yn->+U~|gixxǯsX}LHGիk9V} rHi$mPOw=i>()2x-e͹JHw.?^qtӞ;;Ӈ̺EnKgO?XSi|Mv|ه(A\{&Rر>iWVQtZ0kJWp '5p_Զl+oJ:R͹՞?8^oW8 tm+(ȊvYA;_apFy|WFm m9($m @kkr,~_wCT\lQ@;,`z3jwi˭'yϯlpr/ 3|W/9UujWuڷ3Eu:td2e:@hUjz"Wܱ)E'(7x+ݝO2:T{ >++pÕJYi+ [wdE2oK<;xъ]gOWt{ސLۈ( ^(PbÀ^uڼw.cz^kFo{ps̀UBgF];u`Uɦ}Żl&;y^э'Đ]Rd4t[5B 4-+c?J}k&b*ڎ%] h:("dZ 7!l,mwl^}X3~뷮q~,8 9PfEJn6 ' g*>+$ jWmK83t_~US]؂F!(`_jӫ@VifvƑ_U^>8t~>T~6ɊeŅ_wG2}!2ʸKOit^.d{=DiLE|TÔ!|՜3׆앋OjҶ癩[@Od;7(%cೲaڰtjC (延f>yϯ,ՑC;ͥ"–Ɋʞ"gDR4Z|Yh(Wylު6@%mIv:|jwu#δ-N" tɫWazU{8~ʫq@yZ_dz^Cè)߶gjIIP䉲b^-%%%nu.vҽ. VNhӊV, ѱ;4ZLW–LVӢn +A,Jp\'8l)f5e+ں16G)1ART6ҝ`*B,Jc+rgi$ͶU\iK1OVP4Dp^P$h_D0\*|9\g<^nCo\lQ@zzɴ%&˸"_Ȫϧy@BV\t};9ge#T/WX6s9QQ0Ч8:zm6x4E[M֭YS9,[%;_];Y%+3zψP,@ [-o+aզB<◰.oYs7rc6/ٶa);6%|tAie4jpji6 <> 7 ]B_ު!AaETa&\JeD[&ӏUT沯k1c7.( XM6&^5qLt/Xc'kSQϞMjn{z>ò Tx=.uKw㦠ӥz:Y\Ri6ɶ&hdmJ۹~uiY,_h}YwsHȺ"UWLV_=}/ cR'}& o3RgYZaBN4((/fSRMmHTDӴTzNYTvJ- 4QC$cc_u.5:{2Nx6o1"{J#Ū&cH#V=;eX5-o^6G6|b•歲(Eޭy qWhO_ڳ [ a&ӑ"7 /x;Y*LfZ_~U0ǥ.I+l;et>jw[Y>y lS%RBX _NI6kqy 2\P ʊQZ*Zsc Lh_5 Wx6賂>4kxBPӓ|V:VdO ኱ ޜ^-!3(`tUr@Z7љ7 I+ /ꫧ4(_`-AU9sNS4K:⮙8FS4mI0\lQ1rg<|FXOT(|I?!y)L_S&Wgv_ȪU*}Lž>(qq3RK5٫M@EQZhkChƔC氲H& Zd{ D+^JזFg\©~KrفuNzwm{fQ3C,V"M<;Y \ߍ{±#VMlXEW_KUo~kpw0#HăY C6grIcT% }y\F\\Y`Zweɞ) c-^}עU6tLV|qݏ4ծ$ϘtZ/Mbee-`FwYXDYyyk, kU lߐ}CA\)>:M"}W6+iS ぴw kL5Ц+[ _J( 2Nc8`izM ߤjڬu`<5lٽ^fOMYQ'N4ՀR3hSArѾ2*hnj6`g(bVgN|:fEj\꜉~آ/Eoyqf=l2~@LjĢ.Nk_rg8ҭxj]߭ 6o\g+b\U/2Ri3O(@ e,rgGe-rgi.ƸᦵKc FVz.DB_iK0(0VN>J2ExXܻ-lo %g?RDQ@p@YpL X!>fS VawFz3qm:zoіMer5ZO ѳ]u{k{ 0m%e头a=(zjڪ _tFcV˿~=.}yN 6rxyAȘ-R"S*IR܍¾Q]vn[-,.fjܢ@K''_}jiW, R4LRZY6wV:;kX o{Ѫ~(ru{xQ@#~[njL,heV}OX]:]ތY5z@\ϯZey)س{K#GQņRW (>d(oQؒcPJl.Ji.X 9KϢy-Y_o.~an 6 tJKnW~w6aYc>_V|)XW宂Q mNY7F mY6_Q-hښcc"t@ުCٮK%K.Y.eGJlɖdJ E  Asw9K;DD"$A@wgͦݽN5ngoz PYp܇5;&̛hS~4~;8O Y&>a|iQuۧaJfqM$D x(`J(0*MlX=}1 9}jb>'7m\qnS}T4Vjg!s/^GK:1{{mT)EUnk/&_Yڭɇ|m7n\=|`3R( T&M()Bs<κS~n+Ԧ3W-Y0sjoj֔3M>4:񽦌=i`Qަ{߂FSKM-ѻm5cCW?t`~;H'@VWڽ i9: }SU0QX ]QXAʗMYj,fa,EYFtc5hE-ຳf;|Ǽ{@P+Z+SLڪ@]KN)~|?:U\t+X X Ԗd3v< Y%:֯s,.]dZ+%Dxr9*Z-TEZ|=1NyS5u\)z41=&>qT zl7cdGar_5cdX =t|OKw8v]rnJl~Niƪ k37MLl>wV*XtܑLիzg6t=sXyzC%K,9sv{JŜ|e-غnΆSV-'70 "0Ռ}>&A]Ǎ}#=>{Dy܇hW`'_9m%d/Zձ OcV;p-5AT̼;E@k3ZjS4TzNrgap !yCe-<) kgaưd슝 ¦jV⯮g5Y5; 5o@z[4/JVcZnL5\Uߠf̩юׯ}okKJ+TR;6ڶnŠD ,Sբ0W08Q~*t$c&Fw{JU1ISF yoc1{'zj;Mm0Ųp%%X؉Or?qҒ)ߝ7c'"MRn4z-QEKeZFh_-dtdTVTz[+Wp_Lإb㬠{[ X d%QZz4ww ;jڻ" B!y4ɒW.|~jOٲ]EJ·GAXaYp 0S)Wij耎Cu>oA{m-gE &trQIk>1eY3_ W<o:MQ؞|'Qo,*Ԥǝ2!|wΤk/4h,cAVZpU[U_=|JEw\kq@,p2 cn[W۪x!!ݫTr{_oWNJaJ aՠ]7HA6wnvД AF AY 7g 3`u+ДJgLP+\6H'R 3Gy[ZZ,p_K2 Xn}1~{t'AFG綬y X/LP:R|Yq-ji Z*@ˉR@kjEm^;t| @*N*m~:jNPVjPi]:|4PtdƾOf-`-. ow*Yn}ӓw գ'n!3An9Gg?__v܍7 gO:vڙ\І+٦ YNV 8k,(yaU3;ڱhisSX?'F=OJTݎ4R(ս5 JqT׹ڊ{.zSŽg1m{iv _~;j>vpرU<'?@򶊜W4EY-eqPu@YhXjrןYėe{@TÕrQ|Y&|f!&vU +5+r&5_yJO. jEf'ʃUX!+ǾDXnJBX;+}A~=k-`-F H2 ]xo^ != 7ksҾ}f^XUjX}KSCXJ.'NFvV&h9ulU]RRŝd@>*>-ٶp)#tCլ |GQjMȴ"{6ɽo1GYuZK9Q=?멇WG||h=7/L.]0rۆezeTW8Jŕv.JqXibS`-ޕ .J|IdW`끄b)&+؏ z~ss7O=me󬰇?ty>7 wjֳx̳8RM•WϦҠy߿?92K%= ٵ:g^ڠKY)(ܱ`ἑ}{ʙS)xjfݾq'w͆;{c;%CFtű۸4n?PO W+ :cS-{Ყ>s`-K`~ TW4D㰒 A]XNUdNPJa+UmpUqy+8 At;r+Rpur٩c;ܹ7? "ZkkO |p˶/*UӅӆ精Q(Noy{֯Ixejw-[o<LdR^W{oq\M[=rx?Xdϖ![撝_G䡛*B>RjU{dWPv幢۪$Pi\i!@ST$+`xDlY^aBUH0 g}C?}yn37`5)U߲ $mBTL Ij)f_ p]%˕?tFiiLovuVE;=9$xF7 /m-\`\N>rV/6-_<թy;MF@ l}S<[_S~!\81"3ST+GWUN=eFɿ)yHUASO9%G!!:i|LU_\|:|7kT_7[TcӚaxgN U/VAzgMk4;fzU㉛]aqN5J[9\=Y) V*Š0Ȼ\~M✠*jE;YIVT9Acx\׮^ZYغ VZZ i L} uSG0iʬ j<G11qs?Jw/OnlܹCLߨF4fR :VLEg{mݽ{ȁ: [S)*A 40NC48l(@];!}#tnM 5y^ Ͽ[A aO;hʥ3/ō2$2ɕƸ^N:** AV2d2BTV.jer^ɄKYn84V-`\<nbTr٨xa Z X Tk꺠gtM F!$DRYONPs7?\=7:jH`R,$DH!ק/>r8}5-#fyŏ3q&` R_sHAA,f'ۅHW-ڣkfk> ǖlY+⛊CO9j\nbKYA"PKZ)gP+p t}CPU%AgNP94 _E{@V*W8ܧ@qN,JUVhdL8q4>f*LS!u&=e/kAYuEkч.JF'Z}= ;eWk[qdRgj%ozȊaWt^:J!|Fuˎ܌3_R¨ɒ{RZ=V.^2B/"QN4!B O\>g~駾=h (r{>쬓!=W%0䥢dQTj!#ܸ~#K(\qYC`L/^)Qz3}-D/.N)a*,t>k*޷k 'OiRts$xVWaY9\sVb RyI\{Kzc,lE:Tg5G{/GVZ$1d"~ MXwܳhTu'\um[ο4zȹw߼V#NN-3D*Br$WjñkaJ;&=8R&d۷I;z6ECDqQYYOBPYN _\pPiEROBMIrPD 9~pt$̳L jpEjĂ_H Lŝ>+-t29.9N]r/BqCFE!u|Vү VV_9(spU!t[+ءmgu#ߝȦ["3ǪY X x,tPR Ir4D"@. T@x'=6]SpXǿcϟ)͛7I>YɲiHC_\%A\.(&"DS r CL䐩IAP` Fh}V*ώŠ"K0@|r<u)y]gj9AKVjy+:m%%+{7ĺo\'ر@)9ЅR<, 3,2y(C)E!LY2F_WM:6Q*۾uJRZr(B|5#EtzF0:&O>lb:mbCd' `SA0w#GR玫j(Na̦!JUgUfU cdP""/GM VF~}&\!5vc7p@*]|Ɂ%W8GCٱZZ Po +D 5@f=fL%ce Ԭ3$w7^ݒ5^3u_+`LZ6VTE=>8l orh!9D> A18I)̈J%U]Ud*d6!(e&VJy wDW8|(z+5.ǙTXK_4CRn+$T @8 ’Uҷ[1X Y jB" iQ4!t&{d-Sgx}z#*EՐ?(?7nhK"P[=EeFUGSYZ<0G} La;7Et$ .@=YAS=R*`.[01]UTK;V~8P2SN8TSr3d+;q0cV,D\>+o3cUN"+c !2Parc,92" -8KwJS]U*~;tb Ȋ(E ̯srPvOEY ݴ\\ }nX$ݮ{Ϡ“vY&?@Y%JAfdJͳRDlƝKS|%pH$Ws((ފ1 5<+lisϊif{5!%EKLD'(- ҉Ldw1| DF2!ʜcJ/U#J ϝr+^@ާ)abbG&S}Vf."Sy02ujRn+. "Ӆ/ iNd׷'W!zjrĪZ!ȐP+HQVv/JT]WHY34 |扳rb\ʡMA3X0S8\UaCJSB0S{ MVv)csF d ܢR4D!E".,_R/ FX@uJǑ٨O੾9d%РONdj*VZ - L%` 83f&JoAm*?KMh1!RYFW^%ACq(&.0˅@}bꐩp*zqȊ!Բ(RCQ|=p:Xǥ@z\‹rzN|UU߷  P9(ݮrZW[ObI.aN |R}2?F&5Pcb&MTP%gN ,˒nļ28[ dpSp7 lRdP 3f5:_FNNS&vՁgf= _ k_~*_|P4Fe" )OμtdEqԯWS9Ń"@XlIGU4P9+NTz(K S + Z5IK:RIRksuSpO'3H&PFOG?ߤ3g'Z ;-;4brK|~&(01ʅ)@HµksN;hH5'eX |eEr(iJ!QjWURu;Ul9,x>f nf u\r@#b!, ADr db1/@i#mNM9oC)d!H>pK_pEW m^Q4'&$")G2R9!?-b-AaAJpL唉+IM9!|Y-J̳H?zN!/e?rLR c8T$\]r%'Ʃ;Lej^mp7$zWzQ f*O9 95 k }.5)|"P`~B)z^,R:zuJg׃1r~ Oi-7=l⊟| ϑD9&y69Y!|=RDeEMaJU"{^#}JnϛȤ*vBҥKy5.&9V V׾E,7¥)jwQ*.b_D=RQSۮS=Y|JNJrS bquC{4M!!H3~ٮ i1|gᵀ<`-PG,{x ɗA_B R\!:j&D /UA@|걻uE >(lX}h \`w6 ǀlӠЅ{A&RR+C#XQL2YN.ATNI )T>W_uʆrJX9Ed;c-i )/=,TBJE{n.xLf2QFMVj* #3h?&G)2Уe8@%%$(or*&:zuhZ|2;0OW*ՊP-Sdr&Nkf0DS5&HJ:0,SƤ75O]q|Ѧ~i|eU׮^݌kZ6e{ V-m0nŤm_-< N\rO1*D83ρ+";wMe 0XMP) b ]~,M8_W&ԮnsYx&ܹh hMQfr(B$&MPMr721%n\@zoBN- ϙ>M˗_k5\E( e%RA&,EV(z`uRt\b=r(B.D}z&ǭ UsvZ Q v{nX).Bb5RYyrYg} 11{h֙Y6LғD ٠_TdE9MaWzvy9p-!BP~a^>ەj9dttSjiH ]>|ѳg^z"V_u6RVWd ~DGtTq 76$GIAʽ1ʙ3rbD8ԠJڳFCTMXLF( Ts)4WF/--:OG]N)qZMHUl"Y۪;}iV $4L|Oq94FE n̕YL:xVE0Kב""˚9Fcȹ[3B2( gRzQQG2 ?-EY&_9 jvU?*Yv Ӣ];!R5q7m# Das☞ C`FߜS"|6|Xsvر3g`do1/-o3o6 lRxSUR֬ǔ3QT2ɉԇs,KJV=u T"ּ<Q"5*QA *Ҥ?ME`9 d(ՐT uqJP鲅[4yy;^ETxJEp#}fJEP8H\>C'N@O0{~<ޓ@Y ĴGs 3 =RD J4-Bڤm:H"M/n~󯟝5YjqbI 2TTqԶ"4Ьl8L,"*ɏO2Sgup]AAL5v3W-^Wj]n&Ni޹.-=e|ךUSY5H=ria]$^8+N"P1ba! u?mX?,i:;8Wic##P!y6egm̳ad>PY2 dI0s㊳{4_-ݲnXElOp"iR,$XS9 Jӈ)'^jKnm^7I_lQ1W6F~%Lt6y׀. e3-WV("\@STB"Y}GN +kg 3S7+Vk-Uo^94u#!![{_mbH.U81kgܥ8TL-ROkoyu&G%(s$_ n9+גJ/RЫ[N훸Ny&>> KIpJ֫ƚF,2;6ūolŕ{">ݎʯ,x!Ẁ+R|V$+6ȟ}1@sSd7obT/4N~HqrJNPr(BD7 ̳e)"PAHqD3'~;v@o\%Y(qw*n`L2rƍ /r>TsT'>#*٦i jpZd¦5S i%Ӵ}3s(эtlQú^:aԁ*z @,jQ#0LQ!U`eT b'Yg%dȊWBVۧ~w ,aN<|l'ReAF)P U1NP$7lPAfYSNT,kf=edjМ` J6Yi(ZX *jro׺+Jŗ9':D,W\ur0%{vmz˗` 0qR7S·Za p±p(+Ґ.*!.E S#YOSyE?9- +9(pg oݺ4G!ek 1st6e2@W+#zW*g<12eNll'u7y;7C>ڵ+$qVU'xjʝDf7OwKv,䘇d*o\ۀ4 Ľu˗{wklXUp]^8-_4l0i[xI9t.6ؑgLeL٨zvr{z<}cf|eFVunJMy4hkE*†@w♜m'R 1I1sڂSGY&dLANcji꧒/Jخ 1óT`փv꿜LfpII:p].C,BƎM \Qv(u^W{6?\֊D[{WmtרsC(^7@\V!vz :N!r(PL<+RIV`*b|VtX@VU[1 X"\4X} \;wŋӐ?z~~ha=# r6hDγԙhDk9U~ %kW>Ȳ j=m9!*Kv!qyiΫ(PD!Bڴzm !J즻=hrc@M4 ֣Kg1sBOAnsVd+kMɊXEGT +lʮì (@bڱ!… +`|B,l72musaOCez d X%+=+x X d dEbzYoXALlNzLX 8!Btݓ9?q$sd9E&b$Ǖ4LsLd =ە =@ELs dAب tY<<""3%B=th #HV~EF WdUjIvYmEVYE8Š|(s՜Ck4Z "29Wc{nh"[-B袡PU{tͮϊAvgߌ8u9R"|ӚEW.9pj@E#j*rxmYtuF*GwA^7g׆ñhJ J_ti.=(KZL)s*P &YaXEe YTWvl@,Λ<~zJj5W$ (Z7/9\o0 /DN)'.e6i f4uhG,xvsO%wʼn4qLd Q^/b*Wlʘd(EJ}vIV1` un5#\)޶3}&Ayd8 HwVac8 ` XE 26 V*idڨQNΝ]oO?4/ff=D7`f́saЫW/4&xnݺ!&,X EC@0F˖-__*.g?åģk׮|7nYen2gՒ . SR 78S }r_=8yфS +d6n܈Fx_tOn~ߐL<ִٶm5jP}3gڵ(MΝ+M+Mn?\ĉ |em۶5fϞ߼yKCQOO{IbHE`RQ gl47>V%# (wIVV|ނ pJ-qܿC垂gŢFEW39y7)ٺD8l[*?5سSN8[8 +‹ڵLKՃ>LL VT_|Q4gΜUu^ OՀdžO)Q;vpgņy3E<46i:˅꺜 TLyF<;&찰'q$o?P*W,&͙6;sBY#wrP]Ms6B8b}Vf!GgOjY؂yFjj czo\=_s,:ςD!JAhިj}V&M*d AȸU!t^0t<&'ힵ@F-`Jple)Gby*p|"aÆr@Pߜ\!N!BCJ{QEiРM0A=z4343>,jfgv,#5`>.`:`b4i" }n***jSejbKxK/# ; <#^#+Lսݡ9_ ,Zg5%`$vyP\3wxM 9!HȊ$CLrSfcauj C )"N ,7e|_AMݲn&Ι>B 4|kn8>ys̓sY9+k6}VLYUxU-|_b{h-9 0x͑ZFdb FA@Pt_gT92'|ʈRiGzG%_jάX$z?o~G ʢj5@ȁIVYA:HE5jBDR~A[́ -ʆz)@4+MdOBxg ]tlXb0OR 1G@VyU_pX]$˙CMԀVL rX}l3M͞6BC m8:Te kӳfc*-_FY2k(wbY "\lHE@Cgu-0}VpX 谂C 1UVFi~uI+gZ C]s/NLrC Y7|,(b2e15'`=/3AnAM6۷&\x#2 d֬Y#MmX ÞY!S,6|cC=!k/LקSfA;X֌DJ4MM+R,wd? x܅tO(F+X 5 `bHFaESI UW\ɪ̕B~.]Do߾D|,ߔtX @VuP{D>hJ:!+ɯpW.Gd`BD8’>cq d"JrL;2/qh ׇ~|Et/W0 +Ɗz=P{T(;B΅L +A,5~m d=W>+5kU̗:Qds YOtخ ݷ[c:`(V='YoJӔC}flRVI80>Z3a<^l?kܧA+#!ԤI` Hڛ<M,w IOjV‰<YP"ϑɫH"ԒCYP&*5,`%Y:f.({M&]gsLQҙ\rk@IGثW} G^l׺2(/Z«4SUdZyc dٓP+iBIVzMA~@@"XEȄ۷m!1 ֽEvPt=aOkQ}͞Gظȡ \y~Z ķ79Y@HYFI7 2!cm(Q`B> N:IAL/E*Dp|S/ٳm媨S%դ6s S, 1~}† i+W$X%_-jgj!FG^GuB EȤɛ%WN@ig㑩tYd 1"WZO꥓"QHY +&)BAJt3!(HF)"s/>{4^W<[l?nFۘ02P h$ L͘1|DCX^1H-[f@&B&XϜ ֭L{4 Y>ydGC( ֩4%ֈ0+j6P&6\$Qw*KR0 Pi%'4>s+rEҘ19e*BEOEWRCʢxK. -|+G58jd0oKV*\GC޼ZE;T V eoTWkOAlu:ҍ(.վq~eG޸q595xNZ 0-S"PGEpʒԐHS [eeeK&KC0Bxo)٤ZxJEpj! = 栠)odzA^޺u+D%l|]m>IWH*Pmsޤn0㿊 W>2|'3x;julcuPEU>+Th+YdAqd1ޜm,[4RTCA!OI*E;xJ0E\ tcUUޏʤ3kVn-V8#I=9!~~`D_gPJ6@_'X *oiʦ>{4]mr^ w>qxJ"- DŽ›zdNP;S9V+3sY8eaz@dVQKڕ>+wV]HD$|,V-f)%8dhD] X =z0߇#/^fA_= b֎zc9vǗFRA_CPYfD җnCPYfD җn>[Z`k޾˟9qE,^E "-`RNFLx!@2MV^1aIHiӚ\TF{ 8@pǦw=y|͛vϹ)R_rJrn4 Ô Vatlo ʕ܆d{|xt* !(x "E*dJ+d*%I3OgdcW2bX~M+٢mlѪ{ej\NrtLݶHx"GؠE|Ϡ^IEL:2`ɈT5PFiR#VbAbRD 54ʗEM'GA++bBVأ|Y|bɟJq#"xokDz]ias5MX dm| OJrlIkw{̦.]#%b( 8irR|YG>O5,,ap"gI^Re E"uE|_隓'^~4nU`-P-@$q"PAE)7nW#Ur(B EM>N޽{qtHU"P_EHT%IͷCʅ#=BD,¡Y@XAOP]Q|RT MHeZwڷOݿ|?槇훵@-)`e!nB[ K?Cd  s8吂t[S"fNqy>űB]hG=:t[lx9Ǭ^8U͑?s?`> E,YcR|>flɓ8UH={ķ 0nӦMaaa6lOb28ķi<5"~3t>B&ݻc~D+XĆSLEQ~4\ XO[K)L 3ʄ+OWJ@H j25q1JʙFdq?M!}ٜhU-MmZ pCp A_FX55=""UȊ۷o/^С}8Q/_ٿ?dTFM7|҇^z!#@ySB|O:wOlڴ Pc6i۶->#}7nƌV.J|x=^z/":L&& r(`C)"Be5m8G)YXL4 A{Tl[L땒`r8$ 8Es܌;vWuUUr#{!<%X h7Ԡ\ï "PUEwBu\BԸqp'~ӟ 8i& Ju*@iQF$adb (T*[~D&䠪7x-M#qd]ZzWI٘.Zjr(B13Z, L j ։å+Vxf\og#(H3w"=}ۄ7)ť8a)dd$SF4!g=s%!][]n MSe:]hT2C.Pj0uXrD?,TۊYON|9?\ ɣe+"bpR~4\UXϳhّ%/&^R.Z9';Ikn‚ Q;~)"l߬#-|fYRMAjԇ,[BJ6-" K0՗HĂ8ʖXMigךݹ<.usܼ@Z> q=H~PYOS?hAAfaD 7@_uA:3B UpX4Y9aT% |cUUi~_͑ɚY.܉V %Ada#)ʞJ!!~Y_9R~M9%Bx)"BP fX$H?9_H 7>OOW|kG\c=jBSY~Y|ݳ-  2E9 D(9]C^L 9ͤjk̲Z yǂ(epꩭRmj'ɵ+!<6sw+‘. 'nJKk`-`-Fa t0:IWaꉣS1$ٜtR*lڣlo@} Y?l:H|w;SNlia,M&ԍlsЗwPI6WagSm7@]&yU$ Ȳ)Ѯ-xJ9@LYЯ ,>h ofYS̏Q Ϲc +rv,KH&ز󯓖!Gb,)A`Œ8Ao@@PY3l+ *?rpeJaVk6j- 9$lTHPDzeD&oT6(,$'ZrbwVQfZ Ĵf63=hZ X Y7Z)ui;qJ)"ANAڠSR$@`ݮ#r[%?j[YŠ 2xfkkD-["Z͔"T[$iiB&W- T Ӻ[L]Θ SND0RS"T(.j);. eh~{/ۤ6$۶@>IHNqʊn&tYekk,@?$c҅ * S6H'(l8J';O1=)D*%j斱:c?\X 6E\.YY5huG(xM}J,Ta"PdQDN$S=g) e7{RzTm<}}9pyaz .\@LC#RYJ~A7<cleS^WmSlqkk0Ar S5e0Ԥl'T9w` V'kkDZ ԺrVHx怯77O>A9A!✂D*WѬ_D&: "IE|,iX8ہZ3aOY X |t1C0DC9QAAC6}=鹂C(3!MNy`4Yria:.Tws ݰ- 0 :TS;3T;OǯX[BYw]~݄ڲyj7k{7k91ԭm/ZZZ z&deV8 x܁O> !=U3>Z _-P37mZZ ,gm71(;A(J >P80&8/ۜ3p $1^;DlEIX F:x$b1),hmЁфs[ ! -l/ZZ s1oH:"xLy2R%'jΡtJΉvZZZZ /-(fkΗ>e-`-`-`-+H nOܮz+@[ FFۙl@vh  @`>>4*xۻ9߅$(,9WO 0@kc$5 V- @<k~jPe& @E f9Uhv_ @ ir#Y @U9dQC !p)ȝ,>xRYX,^k_-"n  P Oc   @YFz& @V˿*l=E'@V ٔ  @D`n`o/{GN:K\ L2H18J^ ]W烗?̘/pp 7]< @#pQ1! 1|,?iܕ;5 @U`$ @V: le @ފ|:~3Vͷ P"cI[ɶKHJ. PC T-jN @@~&B}w @@]1D @qf f}jq6W$ @@/-VykKD(1yFD#m46K`S1cmh  @vM7ZcySDHL p:n$>`_@L#0VO5 D @  r$@ %z*L~ @]dB @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ Y?I9 endstream endobj 27 0 obj 58738 endobj 29 0 obj << /Length 30 0 R /Type /XObject /Subtype /Image /Width 798 /Height 450 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x]Teݥk%n$EB` AKFZ%$E1;PAb|eag;;/͛7qٯ د د د د د د دM%J,YTɒ%J\6܆Mnbo*b盽'v)Ux'\GaG+wWDRe9:A7fؔGY*QtYr˖.xBv٫q2%Jv(tNXfXo@7rppq(Э)QL97//reJY!~يY$NƓ'T*'XFD)'7Owsowꐿ#als+s)Y302&&2˩LBv[@_˔-[|D\dJvtKNwwޙrp (W}u*ݨ+P_tZUӢeҪ֬S!^#$!FJ ! 8:~Rbrt_$\ b1"kJ;zF=srL%JXMkS?ūgϾ.XR [;`M%>f)أTYgO/'Rh#Q_\SL@ײwWk@|6?<K71^jŹb_.OgA@&>tfqh_f> )߉Xt^fTOԎe 9&}d2lTt)B9`)U~Jpu(<I8N9g>4Rt>V:)]ʕsа +KoB ,(t ON_S[8;;5|9?U\-$OftX7Gfyo!VZr>15].ՌtQ3H<zD.#ފěac9OtYoLj >`趍ʖs@SOnn~QZ/.R#6OeY'tz]圌_/oƩopBHl;+>rsvrrqÒ7GJ7'г^rxww *QOfF]SJ !Y}C3v6T+1*2&)5%!&",,"|tDXHhDT&aɩIq1 MΦiMGDŧ&FOJIŋˇD&UP>7|bJJ" i˦zׯr}` (U3$bU*U\ϕTY!b 4Wz휾{Ѫ~DWe8fmsލfTת^Z+WZrzZZFzdשQ~Ǚ4]j4oڰFzbLlRf6oޤAĴ*uhӬiM4[FMHNHX- {4e} ݳAr ;W7W##5-F- 1q)ihޤnq'g{x2[ةiఘ 5-*D;{d?WFuUȨ\j*55j,vz 6\ATO Ϩ-;dUZ%qNN:+T#w֭۠q9iE;4nvK| inUq۷oتm[7wnԬg8\6wx μ{VjGrnA 5/9{/`[7ij7=5ufرy+o2'Q_~5[3mA\svk^F&[}|Ee:Y#zbo1l6n-4NʱmS)|Gޢ~]{+bޑ bݞwVoxŦ֝*_z5&[ejtջ죺+Vm\12<ɴU5Æg}NM \sxyNwNXڠ#&N216x- m䁎jKa#k^[}XbyR76L I;~x?=G^ůOɕm͜- 3|#<_^{,4}yܧ7|65ώ&_><D}5ocJk7U:mXϟ۰Nb% CÚGTnʬ!sZt]'w5#{<޺bDXnb}v] ^BXdFۅp]e1]XV?>84  \_/F=/۟\ӫVW!mUH )P o(Qֳ|n®WyںCAJ11ڰg_zdfXgO?,64 wO`/~> u}LGoazn<B&߯X>rg!M/- ߙ̘c#[V qQ=wnً^inxWް^~Z1ai-]ŭpy.Z&a B#^|=۞ĴgxHc.^"ܱxdj%zso`A*Q5RC.>oܱ;,+!?rii؉/t=k|ؾջ[ߥXIB?{xϦss‚i\:κͿaҼe\zfL-o%yug">5aLL+&N>Ʌ+GBwg}<1NtWˊᡉ 'p˥-zӲلZ3gDAIgqÜZ|H޼yY3cb ٓ'ᯅs_ϓ{4y􏎉y P̚Eqt2oPϰWrE$ތ>m2س ?7߇׎ ˺ &oH{'>.msЫ]!Z|_^;n!.u?__LǕtzjL}{'n'?ቱ>0^6o⳦_sXJ} EӅhf=Ӷ)qYctMcG8-?nڥCOdzgz9Lޞpz.э_^Ν\N0X}~T3ӉѧAG11uO p.m6wJ8xFWD7- '7k]~71`iPoﰌ ~C?%=:c3'3=j4 v$d`|6 rIR1l(_թR~k?<ǖ*>.1 ]|Czѻo5kMTOKdE.Gڎttv8g|a.}'rN_i߲,}ڵrL>څ]-Zu{THm?u;i8SdT|-[={%&wjߑ"}}BRa9dw(2"\=r[ZU8̹wfq]dLtT_W;u˦`͘9S{Ї[wbtC vj?@zFݲIxr xsƵlw#%Idw,]v֨YsgSȮWzxsg QjVA w߾Kf|dtJIsS9.<|źm~rƩn:%w*7h3uݓgm\Q'm-]JvM۠~gI)ӦQJ&n޿Ak=5wڨYr+l/$bS<}2k5nPj qQ2koؠv*ԯm*)1QR+VPtdGEťUj]flJSKƦ*jUIAB rtSf5hURFf8lW@mfFĤԘ g'7*ug7ή_+#!38a(ĈKL x~ZB 2pqv+b#<ʔFOPhh+?|gJ8rX yZyڞS%|y^6/rN3+GL|,óf˹xmnh{bQ:oAP'W{aC!ƘP(j\q|Wr%=H81gYBJ'(8^o[-6t,K?+o>uac=>= 1 )5eT]7ײQxK:)X:^ ]r#p)x,Nѱyc9ZH|]&n+Ȥg(zώHte:-qRahrXV`ށ &}TGVGVW +4e+7̪kӗ8 r(=Mf1/9ib?2Fޖb؝/rG0> rZ4Δ:;ZPG,l}4|<9ʚ'j,mE>SmJʼ)Z7 ^BcOaWWlq0wHLRr\8mɱSԮ gER1FYt`8N MKZ2EpdLȻ5ٺ>lm p)M};܇ZL6Uy\ :->>#f#K!"aPoHC )pQ8- ?bhvtQ--C@0(:-Jt88SᴧГ d*$15jz3$DBC]8#b_! T(qB N+l(j8;k NI ?BBC0F!jV4Hn"BD(|XvmչnhCX J2hD[ڙ!A@X@0F5]X-޳n{0hCI >TE `Ğ<ƛna|U\ `7  PPȲ0%|w;>nu?Sx٭ѣ{MkUoq`C{Ĥ֠Ac*0~/#qyxH0QOwYT".>..^=s 6DI3:NJ˫\X *WWvq}wۥE{Wb6$,Np0P6`Ѐp_<'.KS QAw BWP,yrG^o.ՑdC:%*[OJk ~!2,h@B"n9.-))14ލ\EȄfqmћD W(2QFln+<"z|pDQ;.\-76c>8m;o@A4 IIIxI@@4@(FҊ2xyr77IrtD!ol~;di6˛9] q + Cn E%Ҡ-Y! [HSRSSRSSPB%p8-DH K/p_ }(qOfx]-z7aSE!j\ ުToCCaPA% @6pa "-5`#TҸեX$.D0c#HJ"BG9ЇXW%oy~|1(pIiR%!PbQGEd A֠&gPaD@אZ GEL9SLbpH G%B g`! $X% ̾bz `R粯z \\RYEf51|1aTBˠւ2B阤g3m i""B`,,qD(2@H|{DUe @}@0rGZ9OTq77cC0 53 FZPH--C=22KpC2/B xD Ry|8;>(KºmΩͱ.MqT q8$G RP )HB` 6`8?݈…K$źX!*'ӯ\%WΩMuodq}7 8tx<_7i ږ1NY[UR/. p8K, nK NYCg[+K fa@A,Tfb4Ur%!ĈQBzy###" Q+wpp@h'ݺToTl^qyS%sv48\q$Bt\fd\qo8` T"Õg(.2@BժUU%F(@T P$D Kھ>yꃩWea}72Fz4 $ =]!^pU 6(-ސ8-*2 !*ժUV:M/cq$br)E "J3FNJ2xssYAXW= fw3F^17 |m8K9WA >\$[`HIE?kg c,(WG5jȿzף)ؕ !Dhi+KX| D%,F%+Xsw:ĺ%x 6e/ƍ*({W.)#@D|iu 7rݒo|ME89N8yi~,؈0cBo8DmТ{AM P.l<_?2֢4 .Z\!0V%N^S0ݥ8>+(fZɔ"ab- m3هofꄀGp*&DCe&A@C(|^OT5jOg'Hx" ZhP)XܣbnIPf>:Y,(qeCi9i][qhj*I4\ \x6 E1%A@ѸQM0ZSQˍوp!ZBB%E}+WG$WfJ|W^)笽6",X;+>|(`U 6{1\U8By2r>j Q78!,ƀCS՚5m֌Mdž-M  DHDࣶX VEpHT](l$^g5J$<XZ*o~"@oV/q 0xԩG(PE⦦OTʢԨSѰl)r^chοM-D @!D` A@ă# *>@+-8 cڕ+I`/ }>;ܸ+4}RSNG,20hMe p9Q! 4͛砵&-@s E9_fRa`ѽ9Rh]v->hGUثf\cۏTUuX~p8xWW!6uBfl@nPm(BTB rENsPhZLZࡐ݈B$D0[XqaQ0F$л+WW(yR3(%TؼH06}Z7j]7nhѢC Yu xteR*ɧ &T5ĕVRA z?p e֭׊2yl1`^1,PҐ^!ÁExp2z+A]s-͙.Œ4}q&݃oyavV0 /̭9r MTҢR)@CS ֭[iG|\n-D 4"ʢ N,,-J ]a_$U l#\d9"8ҼUQo9L)⋷o. Do]C1cs8:Nޛ3ب ^*%7RK 63(24c$ "m6ڵUm1'X`B_ed)B "LB {@ӵ+sDI-8P#~WOKy24qjo_}s݃oyAp+l>}pq8ĨP^*T̬L)¢Z{<ڷ%̭ ^S %hu *~^!Y~@畎 *m9vh% E,~NnMfxϿ~޾eSy  }{~19іTиApz,PiNЌ 0 :tбcGwPOlD!Dxc(ACC,QT)H-Iuq}"%-Q+2 쁤+)7/&{qGG߻Ÿ߼]46kXU2qN&8^zưŕt*8RᴧDCL A Etܩz`2T"$"ZD%1 :xIWu ."ʸ47؃ҜUbG1;.7 y=XG62drK/t&mTi-JxbCa2`DΝ;uܥs.%,c=BEB// !Wb^1;13IXQ6, YH?QQ' +m]UDdPks%iWß{P>n\݈N|tM+Ϭ2++5%q C@ 1$Q)І%&2C7H.z Klb4BࣥfR~4%R>2wweWL IWrAgW,- x=tӺ}1 tH ] @ P;ʫl3hT8WR\c *pm Bn{%zE^ qDdz;F +S5zU+uq i 2GQZC߼ȯ9-ŪākB"UD&hC,*bC7%M={]W4$VzRtCэ E Y5т)&MP~I֕91Q { DF]>X hD+;,r58,\ZӪ2Uʪ8xkxM%F=E 2 PF/>wA}2{ DzR̢T7[X +&(+e^Ib\e 9W2̮SbW涊M]):0*K5v̱ThThQ<1d(@'(ׯT >T]߮vD +f]ѱC)w0b({l"QeAIF#3@o=Oiq6(78) Q bQ5zjA 12l8;F""=>uA7B\CJ0\I$ ơC{tvAWva#`=HsPyvfK=nU7xR oڀPBC`6Zژ1cF?+^ QDKC|t1W:tެ BPE=ITPGxn% e]>6uQ͙󉎓#yqZU0Ǜh/ 8$ J\b *S4 cnjcqcٱaBXpC茠`'8J|WG=d%jQYGE\C@zTPuo}t8vw|֦^!; w6C s*UEA5*b7zi T pNQh Bn&+ADhD l,C !B&( > .]KDܜ%Z{f2nAss]5-zsB_ G˂l:o]US h!f[oxSIdc 6XA`wߍGBD?ĈPA.Ayt^qފ+aGcW0Hd:uRxnRpn3c3?ur?[ohPt乫YSL5%rV}^UtR4=5F(m=&LD, [-ZT"4F '>PG Xݺ!xbbκ+F3Kx`+5 ZEe(eӺ3fE8[ 湫)sj 8l禀8` 6@#kD&M$@hQ!"0(BD#Q敢2su ʘ>Ⱥ㊣0%@-mb"8%*aqc0ξiZo](:/=oV|@{sS !CP k6@ &M6m{'{/e D xa L}u%y-[bDh\! Ҽ:!Ղi!)%*]WUȼ#ޚUBa2TvS:_VYu\UthP_RA@ pqXZUw9;UTy! cŽ )L܁l",B# J],<+.qUg>65v*sVT*Cue+[ُ;д_ EǏq7]`>V7u?~t»nѴQ6}@E oP\p!!ADӜ8!TDM52UJ&NE++J.H9|R[K㊮]G3J[6S*Szsv̙m+AN(h=Gp(2x6+;ĺ}s{EDdul  q y>24̫Νv՞iWHqzPӶn]A W[ꈹmT} cE8i}wI,[lYr._@`P0;f'V'"(ꜱJ|0]]=U"Qs9U9GH$zob6_p:Pl1TbܪC3jDRe]=P#&&.w=KNPwಓʮ=kʓkq8;;CB :( E b3g?8ÆhB$fP2z!?~uC vkWA0 Pm^ìuCl+וL+.s=V>S:pwuXbX6V>ʍWW7î TvU4#>H;T9EyYνϓk!F`?;\XS aYx74AU &^@>'>oWYW]nKd(sVf.3JTJֵ]U;a \\hWQuU ' n^VRO[r)ϼ!xxWjl( S$f8dž `Z4>@gpH .D8gGHh>ʡx)m*izm%Uԕ6 W׹5~ƭ+13kps!舊.JQwv0z|ʬzv*(9Ф.h C`3{jn61rY CW>k]axZs4j r)QCI{ha*j~oչ3[o: u7l1'bJct)sS6F3BhcљEG# ¾>\s 2-+>q%j$R 9 WRf>Le吠W׻ջ꿿].T:|I!HE2&+vUUGw[*ѡOrq442llX#DBfͤP'@h`ρa蜾]ų˒\qŠy#hzT:;#!n]Ķ ]TĜ^]GIkf3׋?f>wt8 ZP'B~P8܉HϨT vC7nܪipUIEl@iAC7o'te`)\EWf1t$^!-6g\Cu LggCKU^!Af#¶_XsQ+@[4hW!JH$uH#%U*UY# YEaG m@ 6  .Xmb-[ !$iʼR7n̘Q$]$` +K۪y& pi[[ʃ\J䎂M|}~[w -%8y!\DCvUr "*Pn{V[D? p]Uʬ:ͪ+Gh@$ \A@,ZK0]\ (EЍE?/c 08^bPەvű۱*A9!WHgg%$\3182&:(Er[=w -8&_ Q+IW$]pPt9p޹C `MRU `|VWGH @\!X H,]t)eDLB Chb@>Dy\HKgWJ>RI%\Pr#&(VG8euPXcSۯsï)VC7RA&σK:X7sHJhxs)iWeRWsɪW > Hw[8>p|6`P%e2`[?Bd "f^d:9'd(ҹK mDa$ "e !QNۊ7M+`2mO{H?lJUth"ZuuLUtЮjޢU+cvX^0 w}$q34>6^*A! a˥`[.Ϙ'!Aċ9&c9ćΑˬDq천aCbVm%0e#\G؈6\'G/[UZBϗ(U b:L.#D˗GTQ@ 70!p\@;Hl&R1W>+0A[֓IB/!@h_1.+?`]Yc05U-zBZ[UUei:UnLvD%&Y~]kV+oXe=GB?l)dX:aCU""8`W1vGGܗwѫG {IEp%ph rRPXʇgnJMYXKt cFn.cK`>=UJk޸xO>2\)t} k֮Y)DYR}](`Rr( oۊ1AR"P RK-byT]jn!VM֜ k pd U Ӯjg.㮾}qL:fVokoQ%䓏6јA!2uhx*!A8yw>xv%JEc,HK6;ݺȷ\ n+OAȈ6Pޯ^=28|ʼCP*&g%y7yfTA]bZmuBuj'oeR(֨r85PBAMXG *%kIn:uڭE*0(όI"Dž7hU}l\9ePфZVa -֯t0W|ۅq(c+BKC JȜm]i0~렀<$9CcGYۋN(e[LY T+:@$fXIztL,GZJVIgiWAt(Eλ9q@F3I?E{abuBD#tC^v͕qJ㪭J%$rtD<$$(n+P꺁I#D@$t-իE0@ǜ9P(2 Dz[!sjJa.c0\]=t141,UN]+0~^K[; @ h$;!Q岠 o_Eg]} ܗ#rPW5i>Cs/@0.)h|V c˖̀m۶mݶKDM-Â"%RzHF J0WѼ<4OyHNP"Z*(ˁ m5:pF/W6yuVAK(=&z$C ES#De޺J>$837p)+q}Jx8>Mldv؁Nvp0lE@/9"@ڮ=X/enHT W<$Y7Gz{W+x(5g.b̙Nae+=-s=8"COB]Nt`xVAYiZA6&ƶvGk~2RGй~2Ȫ'ɰbV`:u_AA™Kwԁ枢q|HgU o|>S@]mLwI!!^QO8qp1> ]AG=ĭT7m*s?>Vu…08$!w=Fj$d9.|$bthAxp"iF4le|6_W招__vZk{-_..rİRK3MF2264V ه:hWI $pv|K:"15oh/w/l`%Bj3+҇麒=JJ͵`%$HH\ruM=QNœu*Jrq$Z1u]aUwMޚSH)LVǑJE|:eXaDDXBl&D"䌒@ *`W͘1 Ua@ W4ETY㫯=BC\ౖ+a(iΰdF-~+V y YwB1~"JnxñRYBPkLUj6}rb 1MϏoEݭcE0!@䮻CF b2:s1JMuRGGCCuHv'E¸#1)?"!a} ,=/ PDx2DAVו Ҹ3>CzЭ $#&hQ "Z݊0<ˈ rc 6Y@{%D-bpڻݰϷmC=VdM-ÂΙCe a[1a@GǎR%:&=yHÆSe8fymYPYɱ͞P=Vq E1Izʝ˺fXuPهHEI.)Ss!:@.HU}%1>ua>!3aB|:`t tWpºBxP@pb< QA@Qbe.g6 M+x )͑ˠ92Hj![1s "$( n+R9fe"ͭExۓα GCBi vA8:Zh`br#!RCgb|u-:`H+Yͪ/.i 8||(G=z"DXT.ڜ+{ e!ŴL)RARc=M)ȞlAeZɨk%rH]ޢYV`/$uRO[O^6#D'G[Е:u)V:(&G9$yb,VhWKEp]2.Ar|nY~9PWL E"11ZWڥgIjl+H 2V\AӴE@N] 4>@j8ݴ*v+XqFD?\@+4 _K~\7nC;(_*N8yB'9<#Ǔ\P틷O=u#0P zHLLp[J6 mlqUl\+}!4TȃF;ϮU€qF&S8 kRvȭs1&g191Pܻy:`W_ջ`(d'N,=q$"9BP9I"A$[lт2 HnB[Dd mb~oiEk$kQ+[:8BaXHT+`sz$)4`:?@ER9P*Hǒe9ׅYRp}Nq =' ! Ӂfn9_:Y2!sRd]e[aN-oĩ˱V(0gȃd@Pr$O".]x]k]ְ_딌m%JJv?ȱsUQ oI;=sYt]Tw09rs;7:o>ʅ_:a01$y鹬{A ˆc;`$jՁXe;ybF.ק/p_0r䙓<3ܑKy *JḺr50xv2E+AO"eaCy;aZQxJXAEAE쨠"^wEl#@ED%dwMd/eMl1ִ&l)f?MS,{wf 3^̝w<<9x@ BYy)u;BnNXK{)М8seJ9W6=|૯bxW^D~v;|ʿ>8$;yZkUV$m^ P2-rirWt:j] t@;L7@d6~rznƊl_3>k0__~Mya:ZyljrVPă!:HnhЌZ0sNǓ[|A)wܽv AL.oc m7 /I栟n,6>[|j$ұj<9F3PvF;v:V]5[7j_ȫ|P/jY_#llz"c,*u;9 Zg(kKskÅ6-ZhK,o?7MVĮSOu#@Cb{C]#5PrF]j:;i7v xr|?wECC+S=w|R[ b*˸8/[jZ5}7gWyr y$Tct!!bz-;|%-Sr . jh6VoWݎCTH_ʬIM7 UE~8]$QU*d%yƹXQ +nϞ]fw .yF@n^i#Q<6>WHw@zѡ@7Iv[C=`]B]IT"* P;~XF?Pxx$nx^;'t\_xB%+9Ydetw(r )?ѫ6EaMݎV" $0'B(wAUbU@pe*ZaxVYiCs:O rQEGᎊ.$ vxh%к'BvhSXz_KV`kBDΈ#2"x4"ryhC3'{رݦ=$-i#\^-564{t{17|RɊh֑SN9>iPܻx}pxckh5.fcoGtdu1KB큘|&ٳ"X~,50@Gsׯ J$j<|b LK4h;E=l;Pi7sKv=x`:EPkjM9%a(t7vcњ)WCr\8`2'HЬ BcO-Yz]_*q|s&t_YҧMH~$(|)njB(v@ÌDZgߣ[] ~tXLoXFBDlT: i7d%Z}=vG8.s,(Y"n5K+fo[CR]Җk/r&&T‹XΌmOkC]v?>FmU=!;V›?Ookx[^ijo/?Ol2 C f`*O&.YU>iRhE;34%٠#~K_бh ޒf- ӳnī5Z5iOt1b7:JOҪk/j(ۿ3+pc3׮iC>r!61rA )YjOj1Q^z)Ӯ 7xOKWb4},w>|6CJ+Ŏ4QZtbM4<?ylr|s[h}¶~Q+":u58>3qZ_2$$Q$;ƌI Ȭ DH3M)dY7{ m !:-z&V-,P2+tiʵ'&<}w%75ˉZ PZqR,j⋇ohU3]Z_B^v}{}ɬ 3a׃VK(2hIl) RнH%+2Tһվb}{ѐBǢE|PIv/ ;nvB4ht wKbbRK_ \im8}ϏeV0d`ĎBHBJ|[_?t5xTc>_u$Y퇎EM/-t^r 5@+ViA2bOcMV[iz<;i|4e-_zR^Z}`U}'+׏[gP@eV>!$;bs*Yǎs_*n#j}_J_gE; iixV`xO!ff,<;+$#__rVf2/ޛUmo>_UwN5ksӷOv mf*O4mN "vzY1qenj#5)jc튎E~H裏$ c3#C,֖';D{݋v`fU;~>'տ^{GWo󍿽;v̪lf%ގ\jf_~xҰOÎoc,L{,ʓ囑Y]2XH7*_ZWXcPWfU T/Q~w$#DˬEHfl8li;Y]yUyS=㪩kOAr|lVd} Afe,̪oy-soWl|e۪_ʝ1=zL;;ܪ5+y.$!C7ׅ˯F{\MXCU>kzO]/Hx~!M5=w#vr?+Y0Wt˱#gVK^٥E䓯,ڴ%_ ii2,]Ŏ&Lbb BVo>{Enlׄw_}6cvV:,aݚdVw YUb%tHIcwQU_ҁcѢ?$߽ps5]-=T"r7.xF9$:O+6 ?[ڟx1*`]Ďt/ճ.$WR +bI"]#k{w`Ȭ|++*jZ#*_I_{\ lh{C+r*w\{ݜv?~Qgo=;oD\:OjAEPfųAE7!їUK^~ 8sϿsګwȒd턨n X,#mae`‘SCߺI퉎|p}•@eVl)DfFөWN ;rv!xG  9vTtW]_.DX׫'NXpwh4FN;: % 58+z m[})툎<< c ~ޭ^)V!ﰒ(l%+7+ @; 1gVU5O/=h2I6 K_Zbv+*jVlZ'Ⱥjܞ$gLΪf|\\. O]}3o\ ĎyAbd:gY;vh9?i|Ygi#m:z][=O-pӯ,gɓ;v~V$){XP iwdRltRf5Ӟ$̻ .}>y*Y)vȱǮ ft\ v{4r,p2;!ڎ6^Qp)ϕg_y1 (w=R|~o0!{b<qV=Gtmnc@x_6x̞uЁBZLC ^Qp^o~V qםKg%?+ylXɼB\-;ri^<7V듗c?~bYEf% i3 ,ҵb!b睧*hɴKB Ջ<cC~VEjɬ nox&z"D %/č-UtأŁ'=]eb)V[޹Ti8reVmn\᣻/>km`,9=.\(ݴiR+;Xwz*^y׋X tCrmNjqA왃cؒ;$CmGahwBL[߁(;+/wZJf 6] t*Ŏ>8Gce+}-}I{}1Oߡء@bJGBd*Zfq炮t$hᆱ)*^v'~X9 صegeÞRCc$ LXg7_ɼk{H**'CnT 7}{z:fV%3mduࠃ6Պ.UӦV:*B;HS)O{]Ѕvd;g`<e+DIttA0]݁B]|nAX~E;mgvmםGʭr&dKɪ{Y}_β??ͮz?X t !tP5:H'XoӁtɬ{ϴ\د~ :D6xPio_tPύ+g_Яd(;N&FQn{AA.Y56GQק-^@4{?6f5KZo-n]س@V'wHiWN?Z}vDKvuʯ J q`~=\t5ݑ<K5 tǦd`~R]HykRfG}[W{)KsZ\rCnBGr%afΆN V[Zt-ZutCka=r I.<T#JVh?DMw3JVbFnwUW踨A|iz%бNFOvj_VlY(^3elc!⧚?/{EWD/m禭EJ*+$Vf@# 7y.4n\Ꚕ4NiFxqPIwh3曗VIþ<Qtz 5]V4Y':>#g~, Qt;blv9*YUôۆ֯q.! ABǪݸݱGqvѷXjd-YJ;$Vɼ׾lKs#8Q>] v5qם}b/ LVwtH+JVJ_U.$V*z2{}SpIjhrV;,G3qr.6.j5Q{|C_Y6AGbP4I^B@\t!nv_j2 VCIJj+Նr=hEhx݁v|r$TEd X;fV/= x{[IK2Y}r>vA; dJAW (Yi;;-OՇ ={8puU-@˽-$1\͖RRӝ1s&lUEGU}19HiNBxkPYoES=dJCL;bsJ͒~DHJV}I 3[@RjڃYը6#vHK(ot<$&aGa %ܹ>ࡴ#:^|PZ[gu 3ː RL9[,AJmDUA;zK60Btɪ;= w_h%ZСn9#t7xvY  Iy!1sʑɲ_?9$X(m6znFo bO>wstLiwE?NVZxH[Z%i =P˥D) y^Y *[=Ѵ#:D$:f] !^X_(5v_Īdn,ԌUݙv6KOUo^VtY$"\ [1>^:ŞraGu ]{eT$ɵ@a@buΙ~XX)teHbȦrObJcf`Nx|ho&xj=骦;N5= BS Tt}UnЎysS< IXG"y @Xn$jzF^/l ;viXaC1\^!&)j%^ ,ԕ[l%7#:{Ү+tL97|XFf乮h{i\a1c-^t JjB;Ly\q_sG~ژЁԪg^}$*r4*;Nw=#xE]*(:7tt7QeI -Qh5Q*vl{@f<#":]və.צ&'#پKCyX bXY]-$VG b'gBc tXbY- ӎv^b(=_*vf{! Zž߁n;ҎG~ӧcl| 3Oo%\ NJ-\pyKㄴIrYwdc֩a7ثgU}wy[}G~J :D4퀲֊J-KV^]J]YLr>jrm{֡1fץ%iYlaƋ0n>VH\V=㶳Q++kXJUWXvӛ 툈ސ6LZmȸji'`(ui 2AUʭls] D;@% ӵG^ ǹ1Hb3H*VÆy_zSG'w=[~oUU*˱bwC.CV)2/'xHH N3Ԗ0i(bD`aM3%ε,(tɛ+&;KӡcǔF;P n׽Un=4!z7NOx$gb Uر**p<T(uKC#n1vO1w8 s:'Dy"CB D9W<H+8k@ ZiZ|50 ՐGZ#x{kʃ~u8@}BGʫ䱃+M.N>n02[ڇfD zq_]~' y Ե \6}A͂ZAۼnuV꓋YZFڦtju">h {R-Cy<-{4B<ե uSWX*kSӐ FuA(Ur];P舙=]ݱbd65;x=F;H_ w}gPY u;0J$I(zO"_ЄƠ,eҲOvwHX>I{C?!!a,U̥Iի(qS8 XE#XyVto_iowY(T{am <"bȣZMj&A!(<A Ý$܊`Vx2.k{vjcx'܁НٳדVip9A2śl(t8t$z(J+c-6 J>y١]]l 'a+pD'PؒM U9wj^q` WZI$SC_>[!'aMl =I$e7ҳ4?>s:iU9*vIHxV0DȜ\Y.x !E*@ úgC4`Y=X%)'3mi{XrE8P`MiʧX:qcGY~PkEZrUjt_J*LV aDZe%Vfݽ+xyvf}rAؘ?JCpUa3bU*j. yΫ\B}X85$ڧɆ#X`cd6}}}/m bxYwEg5*w6hq́K:xQZ%9gGJòV鈩b2"6Us)jeG)t`W:KݽathYo4mʌ&%(iy[Obfc>JΤ+(o]qCtŬ9Ubs΅QJDTh;~I)nFH0*adUVYjUUhUFN|"Ṯjn꒳E34$uu: : [ގ+^|}oɭpED[b(ydVP5VCrDL=H4+u>5U!"?cP,3ahzU*xq*wê\8EJPN80!+FQ zu[Ņ,K^:J۫=*[Ghe9zy z(= Bx]ؔ`GaW+*v}P?kX#Txp0,1;jP2wl8ʴʁYؘ|#i[P )UxTfQrx+BYG<[..kh~yZV-oPver+Gwer8r~Cw%vN~%~NV;.bq->0 *2*IJU"'0)\Ì<\Hd(9(5 JU.X5r?oc3(-r@`dX"7R%$[}LpFES%!!]URטgZx|DہgeCUN ޿+f+rsSiox4Mktr:ÀAS”E[%fa]AMJsǡ]ᒨJ]`B`V|Nq58l\Âs=[CQuC PceU˖[hs4$y i(^wJj=CJj0(QnŨx\%fvKܜJ}ΗJūEEXzqD}0-LdP.rH(jc@<h!ZQ8BA ұUe^5Lɥ':V]yך  z?iOUU)x8?0 w+J,Gj bPLɕۂ,<]Pg*W~ kʱft! d[7n$ꭸPOqTAP >Ū4)rGd`B^2 4$т7=UOZJWVY}:TJzu7VMAWa(2'**7'|ʭA#(A`ACfL [}lN̸iW+j .2$Kni#:V P܊6 \,sk_$$4y+ҁxiV^|aO"xd_wPn=suE=< %W!g75g-q+|$z>$H+ ]€1b>}tk\&` UT $ʥ G9\Ձ2פCM$!K rFKЫP#eݘԃW=pf.ܜ4>Υ5@A!&.$JI|bJE6%`l5J q/D8B95mz"-48`䬱q*P|WafpX}XʫŽ*JIWǏoB%Ҡ% <,MrDڴ9|[A=R]mp7WzEPU 24Q"p"bnF4+Vz)sKJik=4 iCoҕ>^>(_~E !D)$ &Wo9e|J\ AÅ*Wq$pCVqWd}ܤ9"28NF6 !Ì5:YBR>ZyW] } U11c.A(w=6 zkcvG綠\{${5E$c9״ K!R+P(..~8J*oA7TEJF'Vuq*V)W7tH؃O["UFdY\H4K㲋]#?:IR`#͘9TpY75Q5r])< 5W0qxA> 琏PC?k7=>LХOT!CD4 BջCTPo\lpȴJ@ ɪ\  BfY*\]@}{]Ǵ0 ԈʭJ--ik]BE]W|gv-('X1 +9nN*v59ԯ$N GWD7K.+_܀.2QR6lXu5I]{ê\e#rgna_PZE$~<.2 =fWȬ{)07iZ@ĜZvui Ore+j&iU*SsP_C@WjWWS9`Tx2?9R1L@p!HppLv))(:c%RrxkA~DceEK]@ 9(WLH rwK>z[RWW@GcF?<.r cV޺6 ɕǮ=tʍAծx9]ui/ "((JɖEH*AҌݠKN%ሚ㡫*Bmww)בC\J۠eAShzI ښ^=( vE?`UaALB 7"aT$ A)SJPC*V'F0Y/GH$gH 25kI4@CtG1H8Q%Pp3 C .9L7772긚d\䉏#J۔Ҫ $-3 [uF>#F #PP\Cl!=$uC&n_Iwϋ1E'%B%( pS7ƸŸnqX{":0]jU^}a'3ș ұPIn"U9ש6%:8fzo۴zMgLh?mh F@\V,sy^n yD%(CFi:Z\w5diU C"ǶlviF:`51`@$9=V:?:-z&9[aԜJm.]1c]e|DysjV>Q͏ȯT-2TR0A&"ф? R.*j_eh9s񣎌G$UR8J\q7L:drvr|gpyTy˜9)æU^̲2=z=ýף|v79G]+# np)Br:4[7PU| 4Q0JC#\}}<́j]v9Dr 몔VEHJ,>lFȻ5rDCT*č6$JF#I|l?Ntևz9 `$F)NbIHnSQ 6ʅq{j<^Y՘ȪЬ+rCN,,y}:ylM3=ۿA(yo*yz-P3m\|XgN<ͣ17{AO=,!"~H^DF$(qcBp8@QxڌbF\EoH`<6*z8Z`sTU%ps$pLǪ9V-Vhfe l?G-P]wބ^W!+v$X0J>V> LFi4*k#F ƈR-'7c׈Qpq؏7= hG e4ZyQX1BiUwa <̻eru>>Nm04)IG{x{Cĝ>,,}PEZ%@@CV!I( (¥)BȰ!ņ*nPčAcPRj8eytJRiõHB]nm^ u>eoNjKIl?k:~$9󀇩*WATCm]AjWc؃j|9ۃ@De^+!ĵ,0lK!t9(oy\\)t4j*!±*|Gh&l,#dM%sx2C\˭2tCU?nZ_n/=<H=jtN#՞ p|WBIb A@do/BHo醚PEW`%pUmbݞqr 0UGfy5Zxwy[ԮJErju(D1h" x9.Q |$|@"â r ! " :8$SF !!J?"]GUm7օ\jU䊏Мc=raE7]€pB4qH )4_Рa*\BR87c8I*M:kzP;Y>BRn"Zq(*:!%=Dk9\Cp `r@0L8qx* S*U7Tj+Ԫ(u9F\59LWkxd+P1jnnRkfbTPGy7 XQ Nb B M 1 !|*FZnQ 6lQr 0YB9pB+*9ZvWъ!*I++F>]}Dz5]E?+h"\ݮf% #nc=zpR6h8U4!6YjCTT6Tڒg:p=.#ڙysxN6I2V*Qk+RqW4@ V@B&E >-B 2@nLܤR4 8qTrw|<T%mN RH&fď WD LoQٓ5҉04H<ޤ.jTQ$Uz#d:ux0k.nڝfpڣw$ D5,YZ+CvOMu!EI1%كHvݍORPK?G TFFLƓpJU ޵*(mUr }vGr%+|Dȹ+>$Ld,jHR~EK %RBhߩ,C -L Ȉp`)dl:.YrDVAO76j|PvEmWy7`|?AW!RMڄS$HA"."FQG3B< Re;F ::Q'eUwc~D*on#ևz.~1 eyAwV8R (jJ? 00"R6LE CjH<3lulsNq$ɵUY=1N7.*]ZWЕB-5?PuWPL@R褛Hd@(L*'ȅdN"2sJFo)AalS G$U.bjP\&mG$c ەh(jSQV&Z{U‡l n/$, q\ꉔoŇ n  EC[NE[J\;j8vܢT%6"WJYUut*)ڵ@[WզfFw+EmAHʲƒf"E/ _bnMC-Ȉn @aAGcǑg,y7b|\ذ)Gt~h RM+ w],Q RGQ%Kq@oF;c=[&d F7G 5FԩUJڑTy#uU b77|3ڮG(w=W>Q-H ^1\Ky70,ET"dPA6+J uT5qTVՇ&UѭaHTRm·?dTC($u ڊFD _t2)mRQ hl_jo+lؐpDN;fLA K^2q χY XV`)2@ȱH4!R1K !RoqzLg;f25L+QS9$@VT82flDҫ40'Xl ]%r!tn"2b%zxk]…BO)h nPqF6RR'Ohn9/#|sBЙlقKj붕IWDPp0ؔ|j$)C؀oH?# 1x)K>}DsP% (r-rS-] / 7<ƻ"K@l/Z)n6hp(nvDztoGbIzWjA> DwAYVB2-t͍=GQ&ʦT*ը *..nJG?@98۱?:+sh#D jL !y:Hb7442LɊSDtC?)S)nhƉYsرG7n%cQW}ɯ`:DA&&n"8b) n#04B26\Mۇ޸*qsk,‡W?H*XbbBHg1ҍ7l1F GT*)!RtlOq38:peUwty7`ʰD)XUS'W"D81DJKm0b} CC[EZ-f"n>†t#''A ~?nD!D.&.d:w?T(L[+LpqIhƈ8~D )*NSo<Eq 2Ƌb:Qd8ZBJ1i10L"NAm\ TBVg‘/N=(_UԯA%.B,]Y!Ⱥ2%"‰n agd3Sk5PO0V 2*q;\'=NəA] QtyձBGTDqD?8)nA`I f6h(hz˴TиSȚ|uvpw0c ss kU,CB5GI +­I!T8.aQcRW/z"nųްk\U(|ؗ $E "Mah CEpI 2L H 5$OWԐ`|㢿F( ~E @Z PE۷G Qх寛{ S ΦFP  9T+l$l䜪k] D}H$1QEDע,r$%[Jǀ$"RC#E|DHHt#S|9vPze:`@ nD ;ګ \B{+7Ҳ2 솣)T5@HaHh"kF Q-K,] Ip0p(I`4 E Χ$3t7|x2Wa?t+BDD !HIEͨg覐a.-A\Upf_"r!8rQ(Jq%D8QHMq."[<<5724򵷜J ADC(dcq`D.h! gAF:xj稱\e'@B .(ˢ?b#k(/xUrv >IũlpZe\*N<]N X"b( !n4PHɔB"VuEWVZY,+,1z!@ 0ĸ1PP]H) 5uh9<R"+HbBLA[ azAO E%_rk':+YB'э# 0@4:p־Y~,rwU OH1X(GX~u0L' ` Qeu psI*7=1?u9YK' PxoE/F'?o:팆w| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 'O @>| 4rs6 endstream endobj 30 0 obj 53654 endobj 32 0 obj << /Length 33 0 R /Filter /FlateDecode >> stream x]0 E~aMtB1QsRc$lɎ{):DA> A)rXo(0:`GapP> endobj 34 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 10 0 R >> /XObject << /Im5 35 0 R >> >> endobj 35 0 obj << /Length 36 0 R /Type /XObject /Subtype /Image /Width 1024 /Height 509 /Interpolate true /ColorSpace 7 0 R /Intent /Perceptual /SMask 38 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xxGowמ!+  rNe@("眓`qqqN3;׷r%d`sKuS}EϩS>/@&NA@A@ݻ|g_gfsÞ [}"3|s/8zѣG'   @*ЃӗsonMٸxB))ZD%Qu fV&-" UbcbFŌ[R_>zdhl ʩ5^zTonVRkRJ:0O7C2>!))_y{6 }ƪx1cLly_|%Ku]G;̙y挌[n9s*.eqqtwo}áw| p|v:eh`%*~I^L۩1tڵ2NԦM<҄oT   p}!ƕ ѹUm;ZuS6 `9e٣BG̫VdAjF,cSTOX?bZ9.C-㖎d\zN5c6ilX1Ĥ7L(n.yT\ k* pzNz z )2qUCS$Ԥy5()RFlNS\6,53LF3%=EbPZ:q|:?{Owo'z*7|s/;=y-r^Dݦoط?~:w_觡lsn۶3f߹sرc!,%`QBp zz'CU=nذܺ"z'?8\r߾}999-//gSWSeQ`?a555۹KĐ/cDjop{ڿ?[Uc9r0R1_nׅLzA@A@5t9 ʩin9mՏIuK \}ֱ%JfW-z`aMskj[! ?qDY*ʂO9p\ HLk ~pZ͜ISvONJNTΨkRnU([T״YGg5aO *TM9`\AqK3 쉥w"""mWXso;ufEZ||wk]wMux'8v"2r`v{u^uVH#[l{ǎb|[ \6hz}&jݽ{7i:*0(ÊXr)^x0iҤÇS$C[xj{okk:q%`ьСCv^&- ́[~ĘX|9]b}w f:$q1(\`E b1A y#̌1Я\A@A7yD'L)Ϟw <2#:" N'&;5*\܊Ȱ1cڶN]URܰaʮD';PZ> 8ɉSSU%-%'6nl\6tQsNVW}=|P e!SS6m]gͿaAW}7y|ߡ~8ƍI>BCGC>CPq `K.%@ e;voSnWhyr0?9{ b_z5"ȏ CI" p5s>ΝKʩG1c$(Q΁<X8|:V2$\aqLgA[YjM@FD X2B(ԋ1CdA@A@fҐOm٤u3m{ݢZB賏"I:FDIqxz4m22p`uFFegܜ_ON܁T7F7N(iՈzfA&eO6p,1(n*QWGܾ "$!eOf~&.b/jSs24ed y)o//X\^QP_0i$R/ÜytOtL g^zd|oxGvC+SmsSv=Ρ<ִ*k>x/B]ﵪdWCu?ܘx _{,X0VLw={/DO}9Cĉ!d02ydo-ZdAhh(ecA1fQ$gy/¸s\h\]0ɧwr@Dhc0 fY"p 0! S?K0yR# 9|<l->ۙ},2H# zp jIk{FܲqqZoiaqq˦f84? S'ϿqEݍ_6n83O/Hgm[+t=nw7l7Nտ~ SX=/86i<W^zKMMM1P3\?qo)FC+ Pw3gN M zP·SK@~>L3g'tϤ>L=30gH>|p:X)ءÇǿ`~ xfF98o[9#etO=%W+?}tF'1N+tL-[?-PWw#w}T^d   pu?qw- 4&^3Lb,q48?'`{"2mJMU`mmi̫fbFEvY6yԷmks2 ,:mv8<e~QKw5bҳY/0eϔ[Z@}:U1a]SRj"2)`:}`2,Ovh[l[w ^8FCc߁5^ TfjNvٳv _%dݺuj1F$w۩^I_W1H*rFHϳ/)Cc?Mɦ:u.1A؜ rd6~U&p(2L|޽01]\\ f_q& VaY(aF1E ?|=X0qsXU[.  \=z2dƁBÐɮ [)~e;.ǵ8-ewex<Pke-kPKH-:iu6o0~xibsDhl.8Ĕ$4S#.ZX+b ªDFL&󨦦˖ +ֳϹ*7n?{gf6a(FB; S;.o*I8g|c8ʕ.-6UNJ7A~z' b.0d}YKՒwX4VyV&;=_!paXoW9Xg߼D@aﳟٙS/,|5Qw)-7ꪉ/&C`ܻ:^8KzYoBaupU@^VWWyC 65b0C MA@kxUS]DاmbW;ԗz$O*^v{<_CC=ж&֝懏WZI|?P_@Gv1"  u sJYQ([w~n;?~G`Uͯ;TIu~ex  prrҽO_?i{-n\ Zt♩OəGC9A@{*++]900rP,A@pppϟ?ѢEYY1)i keW.]r [k)/勷H=Dt2*\fKB[Ѐ''Qs(xVF_i  @W\ɋ/]VZSWPUW.@vYkCO(@_G>zho<<<< vy6)>t"<PVR zG\‰(,,T 7vX)_H_p3&#pIv*CCCʪӗjpp0/;OOO///QMq!!!$(D- lq1^Ř*2w_/_l4 ,@/}ݺu|A8 ZӧZјL*M:BRRR d)JIQE  A@"!]p FEFB:`CHogܿp99 Tl=:TP\xWyqoŐaI8?54 j2(JƂ*\ADB  ;iFWR#\W߅1  e䂀 t"?+{0Xui&Ȭ3:C+mGQ>f_;ZulF'|DjBm7ut*0C&KꎲPEAWTi ژ` $;CJ2DE3:DЋfNws5]k AN/pQRS-Cj^.&KCoY1 N;گ R~nDB>W>dPNp?*2c$}=-AHA{UoU^Wbg"Qӏ| C--m,[J!`DV|A@z@%:_fEpA@(?J ǠQ&?Yq.Uisz~Qޞh͕Ӭn/F0TjeK͝Q.v b[{ƣ0;~f2ƅ0B~&k'*O?e t +`KKKVn2C/1rvuwrvuqsFβiz᪥]Vv6i©Zo"*1%c*`mxt۪ أ51z)iJi/gʤ P>-`#YYV.:M2TT  AĨt~ ~.daü|c(FʮJ:-}yz#x\݇r lC]XZ8QOt-A߳y  \yWV6< S<?(..qx؈$ 7~br ;}(G^'yb04Kzq[;G[)z<DŽ8]XةVsUɥ!m 0NJ+ss\4M0Mϵx>eXB[\tr} )@3bd 6XHTl0<*lhBw1ܲ4:6{Q VcQ5!I`M5S-y2AClj9 g斜<8s@(Dv]4jsUSWf( bͽFٕSՋa/J .!?ظ *qu~AN65&6ly Q;h9ޏ2RW(A `7/ߪ/(zA@,(馛pׯYC ~oVgzhR`j`̘\jEEehX8lqqiR?Eh[nn>WiBp[t]!xr\|bUUuyy'Ww2Ua%Dc([Lbb2J"c(C X=(h EC!;ԏ-"DW1 K ?-=%*7/nS^V¶%(፷%,f|BϘlK}L:F1R`)$081I(.jm|W 0ZqK'UI)&2|ÀklQȈQ  *.)?Wú? z ,++b\4ɨhKbR2`bf0[)$&0&6UTc(qpra0O4),Ն0fUУlPed)c~BƀYipI&!K<}KioAW.>(  pI[ 0d0nA虣34@IPMPrjLb ?RC䢥sjg||SR0:*0a>B}`tAFGdRUUޡ޾~7Ǎ/`/g `f>8r mN^>#D?8d8pTaV-G-XNtظl0*0G!o~0uP\5RIm-$7jLuvsL`wtaCV4B&=˛2CGk$]0V`*a^vʈȖHsSpDLS\:̋-:ql}Lv7nQ_WW=y DSe{ ߄>s!4J2WwD\ d?`E<8sSi9;. os#0b=c\P>l篫Rd_QA@^=oem]Y]Z`ȿ}CN!CBCƌɆoCM2Xx #@XEh]^EEēM(MmNQw'Qe*2_`aヤ*=#., ܼͥ|aĮ|c2Gg'ۧ- PT ul曆dh $<&456YR>`5<4M0TFDFžg,Pzta@LrWd EO\8 9MMLd@ǎ-F3CbBD 5qîaxL w&_m\sL:%+JKԴt aX3?MJ?n]@iZu%~6 1F<)4PF c3L7+ B)W~u;C\%e p?<РAD54ZZY]wT)H'RP_BkM6֐seE%)Qج<>F@FHp=%-tM J !u< g&1I/pN d CiBQl|10O-ED%8j"#c 3 n$@\\a4=AieDF&JQc0Tޯ FUD}5_) {>2LB!a̛$% ZZ!1..!$K&pXnC߼!^_SR p!pe _hBKKĉE%%fffSsس/}x#Ģ<%L(7exXQ?U4YUP;B#uBh ڶ?~b0p,2 LP]b(,tq @L!I B?)1!Cҁ q' XgffUW0ke}tҴX4-d`yUe5+ 9} !}8PiMw@zcau4f12y Ô 6!jtC3H)Ĥ( Ĕ~ I2;k ^,qҩA' D,C*%=pS 0YmA`tV3z4ǽ ȏM~X|tasmD;>ma2,& gsS *:&qi) c(~oV/A7w!.#A2_VƆ𿭵^m9C 6},8'+tAaq #.mH2Ax&&bD $h?:齣ŝ|Eh@ >]%^fm0\s A(M%ad UPdnslQsUSnDeuy"F x14QjcVb&\*a&xse<] M{)\fsѴ-7 ;kA/]޻Zh f iՐoumgtk Ыa*}{OIi"@/ny*MSX$/bČeLK/jYy`̥vt]\{NBBO`2 &M~-L̐SAAW_o o_#Y1j"a85{3gl8.9% A@,/ΤKw`[!.x)_<>//@Ds=wyԩSO<(~g?Gtu]駟LWwy#GnÇc[ow)1bO?}bI[9A:C?Kyׯ?UF<;zxQ 4z@6鞑dVB_6aADY;@45M:=f6Ooy|'!!! _ԨQ~~~/m_} \ suu팧O*6Bi^A@KzC]rxkZz:K{vL?;P7OUx=ݎ&lӹ&iga95nqr#%~ k3\7i)Xwp!f2^P?z-[nfncek;p^ BD WϞ=cgKa Uo///Uwk/XG_]_92{6rA@F_sdDDN~t>Y7l|X`aAx}P?7o%7M7?$>'$.Z>4R3,$ցw_FF38w8khBdhmh2VaaipڦRJO۶mz[X; up 7WܜT*kj2G߿~k P6;NM?҈Es[W'U.:4,(b`-[x#7i-GhbïO̒>i\[z3KN}?iwG'|zھ+d!3|ˣ3\6['}/9W4aGÓ{\˦Alouv*!e`*t>Uptz[И ̎Tbf6X؇|A@z k˗/'&&&&,,,!!'T\} \B?'/WyvP_^zm˖->3TS3A*U?o>** 9AG'47O9ӓӮ_ (} y %M7?T?Mlvy"'5 Oͼ .9{/> 3ut¹^R9}كߺxf>c^Z6o Ȩ;i `<סCٔ/X7m7^:gwAYG޴wP:;u+u-Xyۮ[nxł}*{ځ,JfOpw2̜`ecoeOFt}kyw[#m,88ۙ[ؐk@ο pvr[Pz[Pi^W%/HWlF Ukl3݁\\\O4lذ{L)'O ~;99-][گY`Am= e}0b]ňh?)1Y)A@offF`?!118$"تZVS ߰#!U!5M|jXGn[^)`x> F7.Yxv.Cs[V5oy$fNhbٕ\>#`Đ!f?IY0<)=yؾ_k;'mPA6/$yQNF8/ڃ,X7s/ &H=hK \O@?&_XXȃF}IOLLLKK#/AˣS rr֬Y?)>1 U&ϱcp+/j])Q]IYlŋKJJ"""kXrrdoK \\qχw< kjGVVɻi=Fd^?- 2B}Z=1u CӲjαvn9 X;uߟ}m9涭eځ3,` SIםpcR~`& 32yӁ{Wm X7`TsVQNf_ >B~6o=4akh W}]kEc%L Y#F7I,[d dSVVfDKzIG'y'ٳgC.^8? d]覦&([+!Pkk랙6t3 H@^s HyCpn#oC,yudA ^$)ͮ!N>n>05A`mS.]!dliӦ%~ƍlsad~Pv!3yp2ԫz ^]ד\aB}OcIMSA@٭[@ί¥!dffЯrTlcXJK)~{K %jvUUÌ3z7|̙3$@ɮ+I<<<Ǝ˻y駋ؙGm^KZ>{x {˅duؿ:tgd׮]hS5pI޽W^y @! ,sߒ]mI_b݆Wk',|޺SPV]v?Jȿ } <:?#?kl,%xՃ*N?Yⓟ؄Zd% Cq+p"ԋuyEug} "KYrg3 f(0VAUCCF,@G \0`@@``eu5 }fkҺm3lܒ$gZW mDa)cX7s_A@zA8/L￟2ZJ &?blIXF&G rO Ϯnyx ߖ?T?0&39b o2ZA1d5,Yc30`>)eTV5Z؍(ϞZk/9~.hr  \\<e 5zkT̬.+;f-]eBY&Ƽ.ͭ)e[а;߭[y|,^e}="/"qe~3y}i5xvх|V=~كs`ր!AHA@kr *W-`?FGGF]Xƃ pG^ZAy$q[4^ÍMl?yw죯ә`zuO tKz } +azVo545567׍?s:++}[033U?ۘ[: 8}Sx YG\xxv*mf~3,yw2~ʩ{u[aA#}J 2ڣ\+%!p5&xƴ_/wghp?Ώ[qGټ=ThDFHZe냣*|MІ1O[A%[Si(ۘYX"oi&Fî;@2A@  m;=/ շ:/gWse- %GWKBzGx% */9(‚ 5]L[ۍ#@ÃMV,;ԔX} p!5k-th8j,d+~kr @/m?9,,,zHQRd/ c, (+~>>6j[mH3sxtӮ66!p@'Wǡ!NG# ̰uZhށe046,ݞV?-"XD0Gr鈜#󇅤yXh wG>Kz } +YnޓN-[Z Ѓ plȌeG5lpX gwIx/lyܚ}!(w K3`na Z,4kQwK7o$ϲhQpN6ʞʚ d-NNtThȹ!~=:gZ8,^vҼc7|__y7Xݍs KY6ΣoHzA"V^Yigggoo{^U;?*)m1Eom[6ޡqS/N72JπYG^?9bZc9y`HZئ4O? .$c\Dՠ;_'xXJJDo0/BU2ƯZ \*Wg#GN1cذz{~lASL8|PtzTv=OW.:8=S*&/+b{4;x3X#0lHьmS<Z԰Ň=m;~5^.fZ^Pqp~Ѯ;KgDm_E˛@~sN2Yh635VprX|\5o&Ļ`eBq柎|gEfC<;'M{ 7ćϔ@8W{7|o$u> ˅R 8o=MFO?c?TԫNT*3G:tHoh#Ҵj>s5L*JӐCECeB@_n+@jZ <]#n:4S>rݻeߌmҥLa}ٲe3뀫 ofnNJ+|wy6%T*[S3}--Ʃoq. WC]\]oƘ --_ o;p@_7r΢]>?7;{Ϳ\%?3Dlznɐܨ1u#JIG[X؈rS[عح?%͟'#+VF77ڕ4%yOJ⪼P$+;-uhPniM%vXfrDNo󳈀n'c2; #eA@W+j}m^z…: n9u_'Κ5N>IŊ/_3Ϝ:uyƌac𨵯'2EkB+ֆ,Ïi^)G!qjᓔ97yPӽF:/z6.O=[I[bB!fm%t! 7U?Af3T js ' Ϝ9C=d ]x1,Ґ:x#ojG[ 0='N“i믯ZS0wD] $O DȄy}}=&AKJJD#<F9lSN5 ;bǏG!\~a>´x5 XGa΀F_ CC,.^q;w6x|CQKo3 9 /G hӦMTbLj x\Bpm@ơO?MʆJ p:,GPEPuSyZ[}nb*2XE[u;G?+8?~ 1/}?G-9?ddύot[ZϰQÂ"n!SRڇɏ%BF츢 AYJZ Z?y2.lge!YCS7 u>#&0 ?7 nN!a.:mXP̞ltLapvA!ē@# =#rY;tQ7Z. e“GoKҩ͒BOPS*sķ00y, c*x2Ē9pKAuQ:IU;H]v1q@`eTx;t;qķQ̙H5T50@1sp)WԐa=̰ ?1|5bO>$+UB0'NQpUQkZa*p^pU QKs&MO*'~pC  = 3:6wuP Zi8P\r\WI!毾/,hߝ{XTS-ېF x uHa/ 9ixAVaZ u9khm zEȣAիigT d> N]R *P2^BDqyx-lVx8]EpNdf e3i jM o7N~ϳEI!b?<DډCeTPDRNI:O~RH[z'JtOz0A-ץ8!#l@kq~*pq@*:WspF)xxf\WIrנ?ma(@?鸛A,*АoE)0z]CfO0(Sg?z8' / ; FJx2FUʷ \<׹t?  p*(1,& ,//WGlw@w~y@k!_YCdT.# &)74˥ Tb8$)2]e HIrݡtJJ$YZ\ 0jZub*20-O `!u5cg*; t+!i$`ȨX7JMj `!%dƄ2Pkcm sKTUNLbLO%oh<\C;? A \eڅ[L / lxLI:R.ŰޓO뤡$5Ʉ pEU?7D`Ranp]x5 $*└b”*L'T>L0YE PL ̙>l ~S:? ?4p{81yr~`x?Q![ ӄ4Ng*IR$F OtS0u)6@UCdTD㡸 bq8)Bug"//HPW1h<'t@$0|4ڪ?PڔDB3X2Z_:b &Ittq_C+&D)z1.xeN0_Ar=O~;\gNvx/IndAkb}&RCo&A溹`YayZі 4kog;EZ݃6fĆ~ ZK$=9ZQz:Xkޑ{\a "p5QB ѳ.HRv;ԓOHR$ ;Ju!U5tD *jQ Qǿĺأl&Gi3x&y/0X<y T z\E!n%FU UD>fhp~zTf7WC `| yVpImPht zsx , M.8"PFJ Fi66d_Ճ:$ik"1XYj ޅ8 K" *) #foY=ܸ L%[{.: jq6Czޯ<2j+;> ЖF@۴S[ATذ%4O: bajĨkɮv+)>kˠ֬5NuVX۲@_dƕj%BlМrTk3UrދP/hW)6J:'oj)zĹ wQ ŔTTifca!F',{+ۨ9on 2YpsPz;qA4y^#5Ufw-ftgD.YUn &Kёv:-PjHW NqUrDЯ;8! 7sZGیqn% Gd˟T8(6wV @s. s *;$ 냾'S40$.' l]@  ?h`[> U_h!p|BHx;.CR'y ehmdXk<UvԘi.<ԟ?q(x]_Dr!Q4qD\R0MkuխQqtu{! >7>fhh !ێC\|uӰbjڜêA@[8Cq" C%&u ZGOُİ}:)7Il4[طE#ȩH0x?uKn~cvźк-v;u] #ZxuC#a2Fq܍|]RBFaQ6dÆ;yD;*?%H`0ͬ>L,A#rǘgxE>Ln?Ծ~s77%iΪckn SBXArbږWUSX]glM]vYkl WBEu"r.7 *,a q{U \ \YK8eO;; 15)`jq68gC2kw=im԰Ω_hhH\6L;y[ϴyz!WOiZ6fzzA +x{B#%Ͼ|B۶?2iǓ{jZ>Ҽ_InѰ䲇{ǻ{IкɶO5 CjqɻUbP;jWɻ JgZm;TwXBa\p.y)>}߁ A+7 _zҗgێw1wGٻ:Dw:D:Ц QPPv%z*!s◿P=R Vn֢Dj#W4Hkw+ seK<#o  #i5G9%$9眃 1$p c9]}B A`BWWW:A?NU4&FA#<4Y0sJlҒc'8)(A>V>+t~ʞjNSְ2b.^Zo\vWGur7p pP. aiM+#0@|gwR?_ùl۾)l`ضpBϸ!"Nyx<%ml3;vrf2E>ٝ]^M/y/=khIeSX&,y7}?r8y)XͷF.8cɜ76sk}g=o l &{I}͐=lvZ;;xǔ\:wB'~oѣoQP%,eai 7Sf(4~qn IwD!k˂6 l<@6$h[ǖ/}/Θl/VD(s)i nG$0KG'2xJPh/4x€~qK1y/IDT| {4[ػ9W-n5bY3^Lx07 ?승T_y&<v A7ze3MqýO7Q,w>kY-~]"gԘ"/^:=5,`}W~]U8Ioh ~х==\]+e훢g{C;P?dUUVMdu g-s1sW 2Esinh^(lʴ'Ax6YUfP%W+>@zj]Ӭ u^JՅ:/}+em$^^Fռ8"]WȪY= C,_(@կ;]}Qݡ32dв3 'a-7،;dll $0}S$Ȝ5PU1WE" \\$_^YYs0qؙf;b9,}r⺛uuѷl9-8 xĂŻ-@ O/qx'"ҺNA:mǙpO?p,$)߬-#7Z=L80`0JȐ;/>7xbn`}UCSmKc͂ )T?4bNi$ nX>Q~&BW}W*n8?8k 3rQ"V̴g3@wr2寶;_>7@hq CC3yĝ]J;f?g@KF\foq ;m>a)L(nu:}ԸRGaMPm齘#ՓN[kkOP1EO$?F십7B,B2pSe6]x24rYLUӬQ!uI:]vl^QƌSlst˦X!uIĨF WS䢧s ksL^EF|yهĖ(A&dVxWlgˊ[?͊+Vyyň:EҖs7G ',i 9  E JJg)q"n5;DsM~: Q@&$l\D@" s@bY>x#"8\l>.k㶾:uQk IySv5r3|5e7u [;_! gM/;N.&tqp z?4Q?nɳ?>/b8qC\5|l4eQxVĤOmθܶ  %#,g>u;G6WFR=+za(|SI L]~,s[ LͶ+w*[Vb)f tu4.(}/yՋ¨B0Oۖd.|3mxqb2k I#z?r%TXvJSxƌgSo_r4 !W9Uu/z?m^38{kYh%"dKkg,uN#v.;ڤ,]y,3(&NG]|Zxs)CԬSfLدg3d M"V5d,iy`DA$o?Q{U ]K!*gmbNx ^ʴt\ʢJ|c{_!b_V ]Q'漖Q 8q89ʹedD鰤K[~/nT~-<_xDyL88@#`]ym\o>?g&W^(`i~Ni=>(}e薺*uH$-}lNvqu9g>'@p681]tغG96vDJ P}6Ѻ&6A8 k~!b*yc~*RҬћ^$t7"ٸoH%p!$1u); ˎCHuRTjGCzT:|; f :j'V֪3tZXt. gA U$qIoᓇ!~d-;Ti-ջ;!=hb*4M, =dtFه BŊd"iJEw-{,wJnzb( ˨9hdfRN"NvYn8KMX矞^PDpaq&!1zqp V(4v@2W: ?ڪLՓ/1W*&H..WU7]63i1 +9J\}8qP%TΩG&Àfa2daaNľ@k*g*]uOWմ]'ɧ"xpnT1cEn1{+B4ʾtFɥ OhUvnMtuVjg ``Y]9!gR+EuR|ĪN5S)U= d0$qR7aHS5tyE'oܸ㢺*O>Y~um?~ڵkycǎz/H$KE1vV_su͠g_ju H/F*rز^diݽm\<" XΞ>) Qlk-qs K-8(mtQ-¦c+{:{2"}]3;`:srQE|[ +oݺ#u&(2}`׮6g wDxZ·2 =,T@$k KU~a77={j}wt_~dP[":4uԶz5A!40aaV,]tժUfW\#хP@VH$W ܰaCo=8͝cd-"\rk0 |nHճ L밡jVMZ?rscnwDĺ\[At]i_lsਦvO@PQCp1@@mTrް;OnKie펐xWV\kFW" U.%!4B+** _~ĉSSS˟}Yr~Hի{ _068pɓ'3͛7Ϟ={޼yd׿d"wF|0>7ǏG e C駟#$`G޸qh'%G" \\ &%%ɱ3wp4T9>Ѿ>6om !1RKGR4oˇp@ox@ Vajl”ήqϧa~a3|QZ3jCr@ptNݬ?v d":qS H21Վ޸zu3$Υqܸ4Mpx`囃U6J# `ͶQSf vfA /7OmuI5~%bp{ŊP#Gg̘-[hZ=aHO>$% v}D(ݻ?FiӦ8<OfLL &hZpFyT/L'xb(BI4#/IgΜIӒ #{*; .<$$dk֬3g3̼())$`5Pтc ;$m ?XM@?̆D<H@>LK/ 2SO}Vc::c a/)C2(Ce0*(#N@Gy]0dS2-HJs9DDW();%H>ϡD(OK O1|~ P ,B.P_}ٳȗ$B@o=H$}l \囥gtaR^GCeh3~wu8}u^>gPQnԫ9VNHLOprqCfZ,Hy rfHh٥W%(YX" UZ* Z}ymZ^TDZW&$%JuݲwDBs6xcEeeYE33 zS)E޾$@@=(!!QqpTÖAX:CJKK3,,S=,<ŕ]z\<A!~zQKtj;r+@v%uqQFs.NaHC1.mMqc 566ᑑ"Ő롯%%% jM||b⑙_P:h +TBJ*hzV9v#Dwo_?Q!̭74765a7`c` #ONbR26ENn.†kT PV^A0UeeU!uj *;y AQQICcciY}sBZn^^cCc|be(!D_M#D@" [.5fLSK3O:N1fyj!UUxR<#Mɪ"j?3 |#F ONNU(Mnni -ft\ְ_h?&($ه؄df *#qGĦgvvOHx5D;^ OM"A8P}}3ҜсZ 755# w:¬94=EY9C"<GbVWV꼼XB҅+D7@8u?mp툨(q2p vtr!%3+Ȗ$%$iHs!ώ.cb%rqsG05ɕX%uu B[Z[q32ЄIOnFֆau^tKWjiG0{Gmv`ϊf D`ٸxf)b !OHLf @n~ba$xqP&MMM̞)QqӖҁspoo_LZōX\놴tB%5MN1;8AMQjeHppr& {ªN=,4KJIf3@[I %AALg|LDct0]C>W4ʄjX9c^z ;YaCa}ciIAO $M߂LK.1U?pJW."Hfff8>;8Ű #,#&4)L- Mr ɔh  )ҔEyR"- LrDj]QE-`i+#[-2=jHir; *zڞRLCI +R9ǫϪ#=$(O1ң.I[ъ*J&$KNMҺ7DZDD"W~mlN" \eHUײSDRD{H$/)H$ˍ++v[++y/5ci̔H$ZvJ" ccc(=D|߸E_8tABI gNi2.㎗lziRo%l cZ+--h!̾jcĒҙEtML*vUE*V 7Qx{TL1iD@" `yKƦ\ο\ID@" 8}a,2th--nngY )3lCn@9XƄ#Om0h0јconfV4lqvTW>;{8j 1쭭.5ΎV$lMSMz(Xb&D]Nav#\heiG&MVhB9wF0 dRvQ$hAB`!Ⲧ2!H=н{=}|ͮ]~qذa9/A>ӸsFQiӦMH_ۺu+.D֒H$@?64 r+j|iQU5U_bT0s{դu!X)w}KՎ6EM_Oa0(ok{c+h '/6sH;4sYClC-~qnuGWI^NCL{&e}dǖhHW躋Sᤠ 99chKn-:r_lp,qpv'qeCTН1#)vYD, kXc L{*En߾=::R8ϱc6l~| Ν;/m3J2-\78_7o^fͅ/.D+HR‚k I?[Z l_vl8|;]tw[5iCvW^ U#[&g6sɩ㍡kV ɩgwyS3^8ȔD Io=*w'pi-S25xOQ^aYmu~Ӯ7`gh[ayzǠMk*{_Sz-%g[#Nz<{E}}3f`Y~=S~guuum裏VSN%&ѣ<lN8qbB[nw1k,B/"޽{n8p` C+"?>##cݺuǏv]w!vٲeRݻw[o#^7^V+;[" [?z=?C%?.V;W,ꦿwr! K-GNx}-zyxغ'/E}[n@Ɉ%p="K3>ƭȑ},@`ҽ]Hb[lout7 xD'.~;iٱ$;c:G'Lϕ_fD~=eàۢ濓6`"1B&Lx$A&" :Xa37umRm&KO_LjJ:W,>YEצWZ"p&.܎=z۶mj/_7޿%%%\GA)Bhň Flaa!}ԨQH7Ʀ6^ZZJW_-(( tc=FK:3prtnn.г Nl wvv |O2F/yyy|hhh)ŠVr(]VccxJgQCJ!Ҷw9:V<}eX@|Vaؼ^ǁV%N~*I1b_ȻcܗO#(~Ʌ゘#JQ?R+48sg7~ޫ^+Hm'(w{QE߫'3%2 8xȉ؁Q3670aByy-[`1  g 9눉r'c2@YK\N?7FJ3&4w*G8M&_My>؉G"Ù 9s];)DB[- e4S/j@84ajcbpY I#p ¢0[0O'NZD@"p!DŽ^r;?KBbbRJˁ.JS%P_?n>g4/>+ :pBؾwp@[;F:GW]bIKyvZrZypXZ:#8? _V '@LSx=Q46IŔy5,H,r]\BFYS\@ܑ^a.F 4'B1BK&(:`_- GI6zAh`] UrXW_뎱e#.D"^f1@J/  nuС߂@;BCEㄇ̋p $3gx)@|M86Qꫯpqgʀ!"bg̘1ԅ9^;ND PÇS3#{MX#A#GωɡE;` EShXYwi@O7?P^c'vk, ńEx)&?DOg@|NyF1[6X mn21QyՍ|+po!t9 .0lڣ2Rt*w2n24%AT`xD&>nII(jm ɭhb(ȷT EhaA5dM2]eZ" fDRw: 90a@qr"YprB_(W[N { N&y B׮]K4!4SBD=3czPRC&XL1*!sǎPwVc WOt\DE9@@ , J}Da&&/0d`E@߱HS&!!UeB" 8?q/>_K} `I$=(s޵"%\X,eL:dgg3"z]'_9DC?19í{Mw3r2d#wt8ЯOh)yr1hwTsEH2ԽݤVI8F֭]qˡ$_v+'JQ5nW'lemh5 q#G6T4rU *kt0 ;ҋ[$2/ cB2Uպ`x_/)ľFݚD+ooo LN?n-`:Nuvuqu? 4[=*+V_\\DvIq{Xjx~vNNCCczf&.^>e 䜩uUZ@Pqos+ĤsKe%O1Mw=V,$u::9J 9$(bI7=oY= d.uٶv:/?Q-844,4<"($4,"Urmvӧ[]ѢZm7yjutR ={LH~fWse1N @`Jo4("_W-2ne`*D 1+RD@"p-#'4fxCZK}||:h#Y 1N1`1BbfeHMssבiʗŸ\_(YpҵL(`Ib$<bSt♱:I  kni:"=i[+8(QD3=촴,)9ʦ[uqKIN$]1M1n0neT֨oCI GU+UZ@(:|.MXt#ª(5Aq.q+e[CC$D_DӾm nkk%#"L MR]}=rTWTM[Yk:)?1w H+@ٓ?9bw)DuEE/EbM)4 |d5!x Ro"/*,.H.*!TRZ_US~7tJ3M?04 odt gf24afn 55nT;+;S5{U<ȧQw/ c{{II9)FxAk}9~UUʫϏb)I)LmTBbF ~9_KEEe~A^9sGu%@_![[[s/L-)9Y06,gW7^|bl F)/" OLȬ5ek"ȼ8+;8YU腍3/,,&oE^~\ 646aA hc4 {ոD_ܼ* @ aFIngkMlH,1qrtl0޾~9yyZo!1dfgi t:o_i[_D>V`׸y@]D( t=..?POfss ^$WFT='O>vKKГS<<(D .%TxSWWvPT 瑑C68ibPe!T X;#xY9t(O)7}pD_H`1[Ł9D(>‚" j`Skt3LK~$fD@" `f;_CSS\BBaq1[5#—Z[*}8,ǠFPMrݡWc+PVƹØɋrbH`KK+f8*u=up0 DBIYYuфXZ[Q+9Y=lvPe<$Г d%D&W|b2MCYnJX%f &-C,϶rlʂ GDF냃a񉉰kE A/9kk8iEU@$ 0rC* d -++ :7;IԈ(. i gFp: 3C+D*7@?\O8QbkkާX:t Ó-4R]- :Eb2D_ o [ A@sId#:r.H$} ?P&Wr+BSQ 72U wvCp!S[W] Ƀ!h^ tprF<N\`悤!*0ܼ|qgpQ1 gd⾶:)1<5X*0F?<}c @QA.4mo!CKbjPO M~fA!JBJ`h#!Ģ`aM@ baÇzpn=B r850$|avw(C@qq٫X)s(]_MjLLj1,ֱZ&&Z&YgCI~!$lcc: zWs5V-& DV!_" H!pr~ u.p;vQˈsOFp?G'/|V !\nHmD@"K@očG[$oMa~߱|_ }MKΎ=9#H$8 9?G'Ԝ3%Ν30sֱ}O%8y+H$=83?|WWڗ%~~WMn@kՁo̱0?xՏ'e Ul4J~Z%td+ZQ ߕ頖jK${s2G" H!p*,.4PtwpC[5*;[ qqW4bUz#5]|'w_ a&;fRovmg^ Of;F&"Zq1ث6(!'4P)ԑT&$8y+H$=Py$pms9X}rsС>>]㓔$0%PĒᙉ;ߌ/l0mOs$22yʜO>l 2F¤] Ug'z{NLq[MVդ L,i랚v=E g]H$6[D@" 艀J#!?k}!\EH_c3Ds*>ml~!>=±,-,\<|qNJX[g0f>dGk]aeqO=#d}QD[h%0",ֺzdpu7 ;C=vu]זy_<ka}H$8;?O'?5)oW9:X9亴xZ]{9DrFcɉ_wݶ;^w?˃cbȏD@" v I%D倳+JnoW{Ƶ3˞J$o?Dfvֶ2E" \>_AU} bu ^KJ/)D@"p"p v$_c8W3҇SR#k 5EYZj,-l4ʨeB" \\nllhvOs??j]%眛e>9WTVY㷰khjjf/P 9>0y[{K MX皯<6L+*&l2d 4`Kzr)UĸߕHT^" ?{ܾ}{\-Q4)(m{Fd%+ˊC`ͧ dϞ?䀫ou {͙؆cZYmf&:;Zn;w.=_?Pr"9466,,ozx℻lltwhŔe>%qs _+Lss`<g]s хyh'Th=΀3=Q;|c:nZeO3'=P4@C-ti7f 埤SGǒo̙?>gwW{047'v\=L;vxOzۣq=<|98:>߃MHy =$fD@"p.sfV7Bz[F(7ݰߖ B ߬W9<~}|͛9s# 3Jp(.M͟¿ℯmv6ea?SGB #!<|Mo饽Na:ԂI*J_?S kĤTOo_3RꖒJ5+_#Hb% Ũgjz|B8搐i  <."M-8nXЁ3@97 (8=}2"nemH}q?Ul(=8I&Mw w=qZk&מ"/mڨ^GBs&@@Q@~~+ Rc.$K> M^>!rk-*qi,]ĝ};3)A]FdfEĢ $VR%v&+*CfV6_6~kj6D.ɠk4@+,+P`2,:&c9ʜ]ֈb.)`8V&j,2@12AĖVQQnhGI{k4f%(M<"q T 2LA5w+MDdSP=#;,vT?,]KkiEEW9:9ɜ B"TYYِ5+/P k.#GttrFҢ"h AxJ%ꞗ'((90ið`B@?B m`3  6aJ#?/ն34;>p4?0';pvX(\ o 11P JJJsssS0 >@*--L]ϗ)ePp*@jH477Ϟ=;}ذr;"A!{tAoF 74Dܽ}}qؘqM.h)Y ``緱nBfNs . OLC1}CA MmEbKXS?! |``aD, pX>|Z-D aDEyŰa@w!z1_d74' Z6X`3d<P0.v7ii55L102|]X|)g`/Uf s*GwUk(s_.O* {k-D@_B r~WhþT*l%q¹RQf l ɸ%j@4EQقbE346}U 6v-ᐃ׌`P@`wvuufC5.j/@pr W I@(.3 Y‚YqbR2ȼz&W5=@صA^^>T!zQ \E0EžP4A6BW*#hʄ!pKۤڡ1 >~ej.&ߗb !@\bXzK+*J#""B!ةii 5uupaX] a 8q1|fpj GqAaCFaa ha à'55 x.G:X(3-9Ԗd|)Ү /`G .JR+X 7¿&zat\kfHB.]]Y_}l!Uz_)5@lCvll3c҆]oqi*Q`k4] 2`߲y8J-Qp+]NN|M4xi΁GO͔ؖl <eS fz#7 ]Wmq.kݘUMG{GUOU{\d(V- iP ~vڝo/4!@} nTם)}X{g'sG{S4χ&@ck,M m?؅&7=4 UO BKs"B!-ic8?oo~)#?X{MH6r &.8w؅ԱAH@[ci:!@E4Tox<b~y|>8?+JZ,93wjUA!52XLiqWjs{vSSz@b̬QdT9x3sxãU+:m{$Cﱴw1!\L6]6㛚l&&uliS@qZO$qt rq;)!p!s~~tF?K>͉ 5][i [McaǍDSQ_@BtdX6B 9H; <b a\ /BԱ{< Du'2Dd Ŭ Hl\ \#Ƕ[{ʘ-1u !//:[1}ssAobl$Tˤ;!@=@Z3 B ::VBo) ?2#ڲr߅4<#P֟+ K+Uغ玌᝼)[G<>z1Eaع8%/2I.Jeރ}Ù/aƬ~KV7e+_׆~\>q`kVvGpӺS#H!pl 枍,w61լ qFoݰ#;B+ax㟪l=,vBB zwLB@!9+d^ULseM{qiX"A>.9||U'\g^zXTEFeprF?[HRQHRaHJehUՒ}!sU?o ‡UNȜ1nO)'n>-v|%~O؜1iW[F6.>֟MYdre$61m x8 ç{N9 L2ɢj6P z=\dB  |#SpXmCCN^B=A] 1|rbŌ!>Ѹ>8xzy΁/U"y[Ư9SvR*\6=CuzȂJb fu!B蚟w @K_OTefgkjJIO7WҴ/e6.5_:i7g&*wؖ1,B1Y/}m#({|U>'n:$cИ k8*BR'oC}5e 6<VnllfTNI8{dg#MMh_5O{C1k *yΡRkwJ&B s%I&BAFNc y2?9x:RLA_8 lC)8hk\8k[p6>未#(+ "52A<|7uHأؐIOY>v6jމ̚el%Ti@?B]:Ӈ!so y>mll#JmlٖD"7 6 /0!9 K. N*pvtGT"Y;WBoe =G v %]gk!QwAv<!| '[C,$2OO @_6#aEO귿Qoi)nKY,>I@gٸɣ*2J+%7c {n!Ʉ!@} .ofnJNß9KXQۻ5zv04~^Ziڤi^\.Macjʤgc0\fn81G1w"!@åwUP@O4B zNiyUr^H|}?M  (H@Cר~.h/T&BDNiio^ȽQl#rn !蔖wQH9}D ~pnעn^+w'='!z_'o7dՀ-O0hc~!BGk~[KKKOooQ   {W{"g:|u 0q{u 3 ̫?tHzp_S(4HXZx̤;N!п}ek8`L 0nw}F-V=ݿ!FSZޭJyXFT04@j M^ uT`͒ȸB3 -9|Ȓ'Zya7e܃cPFSS3 lzxpvk7Vn8˜ 8x"@H8VQt@g?k YI|"m]ОeE h!p#pG]xm60^W0"U;]H[DB^@[TCc4!) LF&vr ΀X,f 3eeڳkߝa# G=קlP6]lㄳ'l8?iŨ=bҦ 8x/&<UUx{uGPySW#ӆsOF7qj85 (YV/푵'|/F4> j R@!pMk5tF [2nϸߜ:osmv!AΗ  :Pn= J}/ȿu]]QII>-\oll;X\<Ԭ# +gY}9~+O6ς $o}+x7G/D.;svM}|Ӕ;xM~ l8 ,=\ V%:6:akpo065NV8s<nB=DTH,!@v7h1v4c/zbݧ?@c7jya-|"ݣF=_K>#[bC!p!-ߡ1 T118|CSRSq4x<vÒHk\>ʦ ~q؃Pj#+e԰jUנGV~26Ѐ5C 3V^W=X5| B#\n|bb|B,ڢ>'??;725̟l<p)U ɝ|Ւް~ϚLӺb,3v}n4v䪙`uϽk`tK^!)sli;xG#(2oʶowDgXVdTȼ“g6(!oG8Wd Bh=RXB n/}W8e0郮]=P~;]ٱrqÛه㧿~rϓ+.Xzml }+Z.Fd\6?#ϼ7zcd?w]zFހWw컬nHhD!@{hn|;;Ҋښڒ2DP*jj*kj(fY0m4MNGǕ4e6-A N݉.Df7'|I.A&o>_ц`7e ֿ3#?wdܚמVBXqSƯ95DCH" K޼1 +ወ^~BB{?Q~D-rϣ&_j'GД IѥTO+WT}g|u>ݟ~#s4M:q/vgW/suׁO_}ڦg}t7oÍqrͶO̭72>HF=C_Lm܌^¬A/~BSumrOͲWRk牥"=އ$W[D VX@þ#2sC``ˇ(&‚1ñ!1@wGY+ᷴw剬(.B?!ղ]Ǘ:{>Af hyXmDG[7T=ĀGVXo }|̴}=YOf<|{m9t<G>߾ Nx/+ǿ5T~KeqyĞgZboߖoc<ԱcO =-.}Y A} iH),oa~v3l A (‰ !ЧC_'.&և8k 6u 6g->:Ƞe5OՃ_Wvկ6_; ~K֏'?qܼu~ۺ#7>1mM/^ZCǶo/`.AD?ߡ/&{c͂?<=nB n!7b7;ߍZ[]~6nܴRh`jG K-,?q曡lx􌷳^W s|l4~%_ /^oh׿L׀l,s GM _gT"{H,pOV̜g5㘚,xzx42yk=odevsؐkf Ӄs0nR{BS!j5|7Vu[?¥)J[|Zk{}vwm} kJW悔Ί?u+o}i3Wl"Y|_W>׹GmwSKx|ڂ3vܳf9Gg>Dxi_̙_^a:!]XzmcAkWv*D vm,VtVU8;Y_gµfG+GsO| vawGAxFڦO451AʐlC翈Ϛ iXH`t:1f\̇gnq@Q"k)+D\qjJFk` ]TjC}a`I^P5D߰a:vx! a߂^寻@xd;K Xt7kT][APqgph($Nc-Y:* vrILy6JHahfMُ1]SYaO(tZ W[w9* |^Y Kni@2`\Ӱt ʳc*]$bjIG$:DU8'ֻ[imƹ;X2L =#&ij->OnGB@>54[0|ҳ t]F^[@#ãp|?!@?!@܌Rk?N@~RLHJrus9;k۩@f.([xAy¿8M/˛^>!'v{)Gj8G h䫘˾h21>~hcވ06:M96o*BZ'?ED~ñgI&fY:3x-whӰ-Ӳ|EÞ"6]or'3+QEK}!~kaO|]9g#3+8߸_.sq|K.{!$zүb75S4cu[~jEN~7Xw"枉:LnԒ B.C~S⽝kRfU;}!@#)-ױRG?jGUU_ :L&wcnd}c^ 75@b/@nAw#˜M\KoD&(~گ~SЁ柏؉ 8O43E^L>PyF٘V,\~>>.3:\5yqZ_豋Q~I̶VR#.]X&]>4y?<3f/&8lZoa!B@SZc%X=ǃψ̬,LaaeevGg9z > xۥTf7o# W7/_*:$KND@yƑfk0\wdAVGPX `cwy7/9quqv}AE(_<]ႭEEJѧ"_R]?^8/k!@:RnoccnAG('gN;R XXgl\.5L E`ѰOy%HS^ G+ނ$&ءAqe@1Ԙ .xʗ' )j}Ь&v≄+gP֬\hbcc.{+V<1~PRGd/FNl @CI> czW/HalEp:Cw`byC8ضXa4?qBgt8<\/<,yC)|}1ȔK1F!p7"p=`'!p p#V Z?Q044c tᱰ#W(yW$-|Y2bޱ# eO1 ]$j=^b3cF,s1(QeC}fWН %k3}!@=@ؾoAQW{#a&"sAΙ x0s:0ƹH˧[<-ڴիGXi5_mء+‰c{$Ok K*:;fj;}J 2I BK@{-]5o\$~e&` !wn4 BKf B z^& fA}v]!d!p ЁGpdCsKi:F4 UeG8,!@ܥKf B z-߂#IEEPp0BR#FF VQ`ˬdměcf>9+P(\U9SV-?Ȯ764] Aj.?Z }/!p!@'LM]--xxxDTH"i?kÍԕpjh?~љ!%$WͱuF"q)3,1/'X1+<9N^h5K5NyӗL%q`B "%k3}!@=-} a7׏TT11,G%& `k zTT*CCCjP~ԬӶ_.hlx9aO n߼Ka08mǕ&xzaΏJk9^2w~ 9WdjzFhid^.w fGE>ٽ B9G?:#M BGtAok?ϯqrr240Ac6fOO_8%5?[e{tS4<X8zq}بt֔ʙOLaopƶVGh<)}? D B9ڵ_GgNG:@"x}==8Ӄ=4z&W.MAe x׻ULx&-} ! Ob6!@@O3k?ޗ`XqfHSFG,ų7@XJ b% :8ihFEF g` erX1uJD4!@,wui|t٥i!pАQGO++qr_(ُ>Hjz ( lggAPV ~\B >t524-X`[o,=H6׋)lJ[T4k C_ș'9eddV^os)v߈K>Hld#(寎Yvا=箝җ6W̡ 8_6akjzF,Ƿ|'lx'z>2JVB z lkm6@Հ3v;&h!П_Ӆzz**&r{{eQ1r7_"@P7?`Ϛ5H?<Ò[!u c2lr'o="c≛Iej Φ.Mz'<'n;[<+ c2FZںD7?ٸ=$+@^6qoI|ܜBf<~0!kT">bzo2/ Y9b4WB h(?*: \WP[?fLDT&3Pfӝ#p"ҧ MLo~էl}3׎ZA $VL ɛ?J(_A?X4kSzAuˏoe2~)jyb&)uϽQ>aoZd6yz *z0DT B}kzm&̟k?\́ k4^__T>epp.peM K~33MwtXFM~ v>Ǿ'|.ؖP1MođͰ_VO|hlG $-1a*%P$LFz!mrrXFg7=Gr BG}~?v{+ %/^ &1\}ia\RNI;ld͢xyF-z@h!Я蚟[]?kBl7NRw :yhX]!5}'o?}qw{Ooh㏍Kp/d3ny?~ZÖzkA'>@O3w߸;aBg_'O8T#ȿVQN' ~Pd{I o~ڹoOtn00nY}=$B?#5?-w1< 6{/ݮQL9!p!'7XO=^|7gf=Z0`=ßt}'xݫujN2nO;^&4wBܒ߲r)H}`?drttcuj;dRGk^CffH$$@Gx!@e˵aǹ=? ~_7^7==v]Xp8OվQu(>`t0÷<2بA+3kF&A.oaa8G]bdDPoTBX G[y?:7]b+3SffH s*l^'Gs..8\2.od4l_G}F]O_:ø}~{ ^xfߟ@%o3Qr5MoUN}]&r$mРAI))ٹ,^P\Y!]N?'UnZvl[. $N*yܚSkM~2sW{l\{2gr%^xW$ulWbr!#=]}CWҏ|ŏ~p7 \qߌ?sߞ LGF\Ϣ7myǼYF!@gnuge251Qť,GKӁ&Ax `n!uCT/EʤM ,mcl?:K?~ޯf8 _ X#o'+$gJU'!} Xg`~H^ނ`_é2hhڒoW%qtָ6ކ%&o3<+8(H AV+j33J͙$ySW[^ B)M)c3頹@@@w X**jq_(!i4NQꛙs$6ki\{~ל)ۛ֝vu\)7^@95x., &gO_]>`Њ8J G ?vL B -cc0]?ϲzx[;yOo;lp g>Ѱi`ʡ;!@ur`g?} !@B@GJCt\]̜˴/10X7j9hCu!;;Є!@t$7k?!_>?L Pt@7gZO.phPd+وyyÃwSek!at ]J9h.E&!>< Btϻ~ SdlKJKcn[?|pX%Սߖ- }F>JM/ya Cf2^mmT| >b#fgR_ Ō!RVgSEǜa0sQlĂ"'fDh- /p´4i2!@K$B"2 : 808ZQT\ú(PW?[`bj2i;>(i\)ϰ$OybݳK<Ƶ w鴝־;cׇ1E`\B哻qX/ZGb}MG<޴D.S^:x`ZcUOE<MrqxB+ax' C9g}ΐ#眉z4U. ɯ=EtWnƠ'>VM9򗄠aϿ)yF}/ ŬE#lQ,.5^SDW@`DLА ce_JL:5GQ({xl?9p_Q4Bd>q1 uZ9vwW$BDm[Bm&@F&B p#'V =>FVU+xc55+,_.?F(e|ItOy\p_,vro\{#zᄊφ +}̦ecVϭpPBSB+؜䒤QCh4ϳ'>0XSh'b2>| **olt Q3p8lZ*q9iwX gr淔+⌘5HO_Ą:o n_lj(pio(b!\B{J[A8/ǂobC(?,0 GMv 0rP à mE4d;@#@,4OB  b461AjNű~>R0_%Nl\{<43,nQѕ5KGdWQKk!O(_~AxfU)>>1tR-oY3g[;)m9=&OC}X9U(6H_^Tx챏TNFܦr8$4 4K(,XkH@/VNg# ;3}v`'u;EO12׹6W#܍]ةq{B ,6*oW5hCMeB S @'^*X---+kjp{x@T`OQP (7!֟˝O9s7Iiu7T3e7<,kǼ)K^>T@l }@9r b>G؏qO/zFMx"q-o5p' K2FV9SX?`XTO8ޠ%L[O*ݕ,<6{whóāG;?I YU } {y< x"!PMch䩯b|@ǔ-8k(.Y~4Fļbl]gR6&Tfd( t@/ @,4OB  7~l?~~ť 0 BY1jTrZ˽+]W;X]XcV^Zp&?Yq\!is^͏a\F(tZu\0A;0yaٌ{oƳ2taRǻ7r$| .hP6BHYoʙǕ$?B".@ `rmDm ~cܐX9/d#٤y"D'H |> $H$JN{sQ#`Pء8q:wQ4>WHUzun"DH>MN$H Ei(~yGI<- Kp-&ӷOJk l/S?MbMν[/Z-8#uz?\e Xrba~7K% $ %73@"D]T -Xfݺ+WVԈ#粕+P_fOm>!ޗv L|{P,~IpuV* 9^p󞍏!uWCrM4/^p1i/=: D*h`c@T a֠C@v7N]'+UJHn%@;{q/[j֒e3}[ $H$HdJ ŏl~ĉ}esիW^^̿2/+++---_=F,gr',zMYO-2iٍze)̫j^^?皇QV? #&qMmyXƑ&7 8PM7b2̾|࠼ʖSV|[/eוT75 &C'̉ 1D">yYk% w tʦsn{axAB:3IԍD'W ?/ФD |H%pCsYgq)S.K>_zueU&UTT\p]tOGPrnT ¹h^K}}C_wS׽CFMϿ^d.3N[|sw|>;_G]bm]w7=^ oyn~ 坟ri1i=oV[j9bw?EX|qKp۳?Ӥ/}mowLq &᰹ HV  $H$p2%ON>6onhhAS,# *{Yllq;3pc=36={{oo8T[X֧wŷ>wwֶY9G5WhٹW Kfl-@O{JkO?v0s?6nt Sùoy'U-#A|O8V_J.L\GN+?~$? $MJ$H TG3yYvۇS 2ElOf?oy/G]q+_ȗd+kr?nZ+,#&.!;Iy3N?u{WF\q/,f߯9yE0 u %H$k8a;@"D']hH!nqMcǍ3vlԁq_uK.ini:pO#'-ίU7C[_w~ޥVrݟ1mɼ?^MoWιɫ:tViA gGъ|=q[[u-տY}τ%[ϛOej'ѻw?~;>Ñ/2~Moу_ \ cc.@H @O 40@"DR )Ϭ1r#F7zQc(q -~f(o2uv 9˶>z ˊY8o69ጺde>2[8|ԦahV`s_K6|>N8a!ЀUM-qΖݿ#sriNq淤y;t,A`DRH>D L tGTOcfI:h!WCzMr/}FxoB!NG3n}~ -=0uگs ?I9Gu"m ?Wuv"DN?\/ݾ⛚>gP^on5#Jo+ሚΖ8K "Ɖ J I$H {^a|t.IpqBD|g+'#Cԑ GwG_~aRX;N 2of?õsD3ՁB矝GOGWQX2+@*Lt?G!B`kvK';NH @"%(~r͑۫ $ gvAzҷkOn+s^I%]XfR=~jpO~SIAك2@}ЪJ+{ꬲUWTcN؈sngc{ajY99ETd:ʤVn0Xtם/jjÀH9'o-7Ld5wy/4TE!F^0R߱AMZa*Esg=\qSe*HSr> Prnb/d&Qti&0Wx@ǟf6LzVX3-Y+cd!BV-is<>%yuWTk sNN43 j/,MM\"~e\Dg5#oP&3yP_4?\.drt>}k D $Z]no /Ϫ/_j͛ ګWnjY~k\YTT4k@==ּm^us͝5mhùݿiĘ"7r&?"2-ԻOh`۶~ϧ[o~ۭv 0 p'`1s K`s.(?TDu*yVl*!r k7KyzM,qK p7]r0 +BKm+ cuu5"(GyHMwkBJ.pGNP[KHQz^jNuzPoD܍" ? !xN\'?hugʅ *yeeV!k'E/9 lVr?:kSY-u&N< N چ^ڇ15S ?VYY/z[}LŜ*= oӫO6^_2 -mwד5WW_̳<Yj Qg7.*}a6bcUhTP4F>I|-~|ءS? G}D" MIb?q l(Iԩnv?b깋|5R~;ꆌ(TP7;5O$b:3ÒW?_뿺~^q_WUNH,H @"c@@~D?!ҲO?ɓ,^,NSs .(ǎ$ wmi-C /:,f4xW]72 3Hzk|qњ}者 WU޿ɫ*YG6( `kj+Pк>N䙥m\TZ>?E 3kQyai.tۃ 㧕@+6UzqÍ VTd``hjdE@海=\ z;m|w (Q4hފ 5a1i,]Wy TcuQ\rskDRR_|ЮUWRhQSvnS.-]j|i@vن*2;芛jyn{aUWVCۺ-55 yŹ,Y[ xG}AqxFĐ @+xԄД@=\ vii|gjZqkͦk۬љhx勃w>`&Vѭ7T#7ڼDt} ol\1_{k|;mNYhtӊMU;`n5@*=J~Fڪ6[puSMz$ẦvT *%.@iU7ͱ3A55GG^y4譴ŗWluN}hF-̣w-*@)) J꼢܇_l"SObf_OYM֨ N-]jG^l2몭=[xEQ6̵hbOi\ys:}e-\!zBkh)Y3M[nk,;x4^xռ[ .,'ۦ#+a6Rc^zg?RmZؔ)+=kVz_|K/fΜ9gΜ+Vp ַ܊v|ImBq<$M $H$@'|.1sg4h]CHu''eݷ^9 =4Pr3M ī->rv4-Yhm:lȹELQl M. rbXX}p_5r:V>\3@<$[73fM]sJ_uE*_tI)Ēb`)~ZY-{냡˖녱mofG]M}+_h[{?nۤKJ/RBCavN!,F[[vԎR֑cʫ`'^k79xUK:+wZYW[P-PSCՠ,}f̓ =cCRIe=Isx/[Z>Y~`ϡ#p ͋VW|򔬱Хwhϼ?j 㯴PLQ|l|sm-P>ju;ky{a͘_~r'\ T Sh:H+jėo*q06>iƥH5uV):xxċKlۤ饫d;L[ޠU=r3 ?z WkλXf5i\T#*oo^=btֲh-qb?LQfSOjRk>V ({Y=X_8xSMluPY C7'C h {Qi 39|t1 R" ?f#ѝ7UT2rn!PT\>/O9e-ճ$3yɁtg=Pf'9P.z"t{CFQsT&"~ADJ{K^q QC1&d+" 1v1i;xȤKJYGty|l9cLcMc}{mOQg _g 25ЅsDr}Yko'WH/~lxX̯  )"ADg5&Iyh%Gw?mtL OhNlYG☄7"ջMCxvInԫ_Ln\rr g@>KDp}1`+yha5",pC^yRvΨK' VZ$TС# k7JsṄ4c>_pꫯVVVN6u!yqe*]jE"D t!}O;snP[@@ xqVvHe5lwg0&n_r2pR4ӛeu< ӫY;_}U"*@ 9W.bll E` iŏ Dz2T|OPS}sAD@5DPPbI6ڦLLz mI|±|~>`WY6)~_WEP^G@kΒQ-ܶ-|F_Tpﳍv4: 8t޸"* ،{?-߸aH[$96Bn`!p> ܖi:n0tTkZH6-5hc洖"DYYF\ף)}:[e̹lv}ڪM/\2iz #0;;6kf.rYV٪JI'sFʶwR^dtAEmSj6 _i}5- 2] 킺MN۠ϼFP|^<@yve_()dK/(b5 n6UO/9Y]ǻ)(nO5ecf}{/ z lR f/*>5XHؑ%N,YiJ$t lj , rm2'.c> JK,ijjXGݹs&gϞ??yҭ2[o7Z/@"DB]qwm]eˢK.YwY;c՚5N:5:8nxpiϮ{};y+ l\c8 M8=>[-߀JYk&,- @ZYmg2#+qP% |ݮ:V#l^ueՓqGF.ͳܦSpj g~@1LɽO7B)0!49p~?1n,0'ȋ-@&a8IK<@\pHeWVM!R`07Ts_P˺ic.Z2fR؋4ȃ 栎ㅓ)8'gJ;%) 6 K׬! -P4|e+;D +z+uw3gIg:X- ;V mDixUYmcn֋xXY+ 1K# W"l!{-mTQ,?Uhk|{xg=n}cUE\3IFh1֘4*Y94qbQ7Tgťc?8iNC!l>`Zid|oDasa=/x,?*gyeWѩ}@_9Ɵ'QؼysCCßz)\|9S.^xȐ!=={6MK.2eʶm4_SS3}aÆM4I"lM<:\Lo喣x%M $H$HF]߅9VVUa/)-ȵ)?^-8A. ՀSf0LЙo0]P8dß2c~l[7ŷD6mܘ&deva1(&^\0L=8*{NdLaQFu(LR}Jw1M)m 0V̳z#@þ]3)DZe%e i9 MR-rK  S9 O>C&B&Ǣx}/Xv)Ǥe`ރ.7dI*7bC+V2‡BM 45ǡoCsR}sGtȇڦVlĻSB'SO8Z-2g+q 3X4qC l!WG9 `5V@ܸ"\p˃+ ^tgaYN-+Ѱ$Vaՙ"AH>Ad9nW!2B9bO@ÇO~o??뀀b?R H:[Q%(4}{*|ߦDy睚?&!}݇LXyȒxWGرcVq722t{pID  tϻKS?}/S"~st\.B R=Bڷr. e6D Bcted#S:UpKIBJ2HRt4Lq:*Iwy |Ʊ nĂäLI% dtu.d,\Ym4JQavV3{L_{@ ,D']W;J&Fj 0b UHEڡ3Vd&|ϵX8@}8(LV3{qn[?" L?0vT;w?5a<05wG"ES߱$$*Bg&~~o|k׮e۽ί-(853g&mh͚5/M \K_V+QVs߾}7t8%[nm&x:WP۰??^lfݹIJw]4yQd:IJ $H$p%5>?w{rwN .]VG.)oа{>rRLTMlp-'s=|袋F瓯/2_03O}J GJ[;;gy,"iOw)% F'y{&ׯ0k֬ݻwxх^h__R tdVϝ;Wי?}GF|\pᅬpa„ 3\??jjO'jŒ3HD  t{r7?|C~D6)?^paNѼyMG Ċ*':LC'-'5{^<"@j z'}p5.?`I8F{-a9wlẶV =۩3 8V%@hg~"2J˯`j]xHIs-c~~f!mh/?)QzrPW° fCݲx9A]D(bf]ȹ<w^1 M-:b~:_}5AM}+ݤ3&_~j8BUo~#D*B}BVRA$K$H I@ g}s;_*@nn_#Gϡ zJν"((af5dM2k:ڌ tC0O7iOc; ;_IȤ١ItId#epD(V Gӊ@GVuZ8ބ ?G,@E:)/J2{qlrH1l2gHN3c',gȟjJRjӬh.O_tAEgѹ>R%E%> (<H>j(,GVջH?V DB-3k=&NZe%xꖙV tr᧶N$ٙ;Cذ v1Z v$ꥨ,OiյuT@T*Cqj4xuc]x=@wO_ ' gxDxw3я~~)+7$]@MQJ^{-By@g85v6Aܢ.^Wݙ@}1)7nIYSEL$H @p׏_V7N &:1cΙ;w 7o6|#q\=}'b )5jy~"X"P!B#6,|7/)k=@3 k8+;*YϜ{HB_V4q K"L>+6DIEaы c`][<6AQ,?N _OQ?c Zii 4K'D~٢1k? e"6vqf9\uRaqiLGa6g-,3A=눬{&'"uaaN3sqVύB$!#.[oűvY=XR h:n-G䛴E E@j(AJ $H$p$pxl⢢SN9eĉ / r&OիWzj?Y?0CqEuK0$8뮭aW|6q%TZgV \T nSfD?hEqoӟjY}E2m==hb˲*{ #%׀m:T6Esm"o6 ̠Iqy=,_$_ :MS&L}{ (HQAxuHe:HrOu6t=Z  l&'~d w #"Q35 NbKbUw wr6I_dW-}edXNM 7`>Q7\uIkr3Cĝv@PS0|ih^jDbo%R_lP|'~+`< c,"@$ \g<#Bs?7ɰj/e[\㦖'r{$JjF3Xr *w`ZA,u9<5l5cmRJ"?F7֚zʣ$`oSː9Hn&B&'6Ӻ0;v(lFG2mᅷl{[L`y<, zfG?EC[x8𛮌zӾH!h@œҀXmp!?W^y%|(V4T-K$H @'x>}._GYF6n,.)Q :=''ȨUsW@l,kL31j%[n[$جB<){>W/*ɕ? B﫶B80ZD[vKc$}V? ,=q0%s`'g:.͞ dFv OF+zV WW3<+`wԊ/0|Kn/6"}-eM Ùph74bTŒUZ}ۃ#ɔpKL/^J,ax/0ekpò U:P/ea`'Rr.rg 614c`$}qPMvH pIb»t:1 tębT}CD7=Nۤ]TJIg/&/?#|2L;fBA+~OlVd{îmwSLӸjL&L+ыk' |zt9&[ú>NUӳW*Ն( I9Wֺ-)v6lOOġ,jt: w,s+ 3=M<``u2CeO֌ꮨTؘ(mu5Vw5̾fO)^{uG~z\Q^|4|o]'odڒuM-UΣ!G kjsėIOq+a%N*qxJB˥N0RF+Y2tîZiaL1Ɖ||">!Vno?Vzg`9;˾Ux/2c3fs Eyf3t GtA~QmSO=ţ>߱?t/X35cOAej#~ ~5Dx饗;/xTev `u}T#l(ɒo~@/@m ܴBD9nOQD~D 8 t{t+ĉK-ˑٶo3<åpxAtzO+;\Ӳ'_o6蓧Ă@;eM5̛ @杏7In{ͭ!=Q3U[n'&L-ŗWM u`6TJoz {?`.)@"00 v}6mN*S0fHZx[o\ 7@ѨeBo}sn}!d?Q Á7X ")05цy+*y覹- aTC1pҼ/;*/[jm$ N% D% dm95 65-9d#i*٢!mDK#ْs6v#Manhb F!H |2)As,0Ahi|ֶ,{٤A@ޤ^Ek_|c LgfС֍RWlFN"{tGȡ򟟳c{8DٳX w[:)v;`-}c3bly㫃/Z:@8:Q.5Ⱕb&M/a̷uBV|J)[("',zKˉH8 =kh1x̥_~`Kp<?{9\^OD"\[oa;)*@"%pHXB?8 p~A /\q/54|jfsPz]Z®?-*7YnY/JXk$4#'ٻndh7r˕7DbDG pB0ާywtHn*pa)>56mƀy_̕0H#stt5ͭ=\#8kQV!@eDnQc$B̛oǨ zd7{(t8oP8 Bl,t#Ut2 >oy3 ֺks0 Q+8`M9l)AOm~ύ\ZPhTb#-,JֆT ,q=xYWmqXr뇣%[nZLFfjTX;p"#*EF4eV)AA m@~Xcfaa&q^jpj鐑1s>݊Z:gq9Ւh)5ٴ$S NȆsWTvd3SZǭiJC>P=qJ EƭIDp˷`hHug 5^L}_go#<#>W+*~q\hͧ9dʥe'IRґY#Б.ihE9`SCGc6XK%Z>mbvV+28w;ϓIaԎ<$ $H$p!?\Rd(8\to?maΆyT љc?#~6W% (rA#AraU@;>BU`UXx (p2oX]$-xH`%L6+shZeh)_}4V7-V REDRdB 2*,cu 'c89!A!/JuFr\G>cIe $rrd8&"Zwwߩ|?9FJesy&= Fj|x֋}:JO܍qЏUWc"ߊGPRKV&~JcaakXǒrn̷wHxPyt@ݑNFR@hֆGL,^vtH*53e8hiJ gqx#WU;Ͱ5dibo, 8M<;1iH @"P^C/='ok:3 I vq ,LvPϜkCj}xx֑KC[d2!+豝L uKGTҙnwnKN& ۀdstйCL$$:R;Μtӡ Al_ /Bu+݅N RqlIş=7t"]i5;tEͣ‹;c"DQICg 77ysPܹf:7]*{O>W#S8ХH'Hv$Sp%oEesʌow`f4y'f4O$H GA'w讇ƺ =]+2;WB&ݖ0 HS{Ri]\2a>]u8]:= K{I0̞':ԉPßǑ(*6o*Ӿ.fsUq\rfgQHUM|XFt^ $H$pȏ'?h@'KO?k頮܉!} V!oqrn!wTp5SvQ`␔{Zӎ|;SWD.GI˂FKwQ?פr-n]otH=P"ecY,=$p3CO;b(钢Ax(R~?rk*I D9DaaKi@ Gtm|T1.(w[_[itˬpĤy"D> HC0iK/10F&Ot8>B>][I q5aH̓Ol;$y~'KBȦtha4'gfz8)n V/(,j쉸%+_h,$y1Ib8x݁3ҌcqRʚ|!VlW=v I*p-~xKt(!. ]JTHj 1%2ϡf ]Bw;T 4篽NRU3-$2)XRz9v龺6=MJڇ:P@lD0cI$aiETʼn 8}bUBr"e mG*gd5:͐O"׭A93HUbݟyx@晜urVfV@AF JRK:.7u"&.\pL^S@I> *E0XY _&TܱBsuзer=J~0fSQ!Q"c*X̓ e^8gTa$H3esMn`vXԷ tC$5 y8/(+1J$J͝X?Ag@Ĥy"D> !?\5?iM8q…\dK.-h8\hֽ L삐 v*1+&~3!5ކ'_kK\*pz?e-4FaE_hqA&׾<7s"bS_t)kgbB@x`7 CrK9CXU&xw? vWO6"+8',Q>z3ԁ{jQ' kԵ,6>q|w5F@-_|Y`r$=zYcıe|OE՝j0I.,QNeչoOI,ۙ'L @W_hs̄DhY#.e_dg} »m.NEqiɠlfAʧ; ^1f;\DYZNOֲeG O@Sr(jY60A&Ie2RFCeK*à7dbxmvsDZ~>7 Mp~'$FOւ2M W]QE[~YR9l/H}vS%[z˃zɂQb>FUq^LɢsM`O[~_WU o^ Y3]K`gR,l"S/}$0iOyeRYϼ*,’d@\=W$mZ`# 6=Lw]ÄyENP) %2? ktxQwBI@_6xpo6RX*9tT!f flI\nVF`3zZֆj/$A*4c^7xdwzo?KG[$|`%+m(\B $^V`qt~ zomy$-ot9e;pAQZ7giOji$L&JoF]A]`k>,kWK|I03G vʬ+rJ9Jچ.Z]i#j'r)VT2?5WWs1M L(w@O-!ۑc0ikDM3)!fNm].tɲ!;BbEQ-`3*"m,!TUy>WDŽR^ScqC9[FR J;,9.Zm(YULZJ=TOf!;7j7MGh-id}^E(#1eQ<3S]ol$2gϖӬXj\H;>8;QN־(V]Z-3Z$v|\;n6Md3ؠ0;Fd 6#8S+ؠ][o "FoaU6`7MhZ/-CE0Ybhg!k@&ϰD&6}=&f3U^~8鑺P1CsuyRp ;w{kӶ2)&tXnCa_f,7.9,npZ}1Sf ӌ]2?Ieuka "29p o:,c㺠fZJfv̡ͭ85@}ay`2)S/LȲPк3ݙ-K篪@׫WNY*p n Ȧk;LtP9 VW:DˀGCijG}cy!&m $H$[.oy~/ 1M\X@]B,x 8 ,"z%g!a tKB%@'e0ٚ0(耸Ҥ" l"4Ieroki{ ~([Pr%r'.MS!ǃ⃬BJW 4SHa)>I, *BN:6H,6'Mltd5D=x E }Ќ.V3(*`kWBz(kYrQ*D >AVH.ncrZaRq{LA1[:nLar@ _ n#ÊJ-0 BBê(Y{r )ӌe^iJ"QHU@-<'N8RCsIwh~??po3:Gmo*]x,omp ?O;'? $H$*mr٢so'Q/H5>?w{a~z_dI_PD^.+t߉!?nc}uv'60DѡBlҹ0͆2d̶֡״l?0!\~GJCM[ @tI>VS']p9$9SI/4v![',F)9oL@zW֮]hѢ{ ._x7|[re]Ǘ׾5^yщH9ܾo߾˗oذa۶m>={Ćcǎauz"d׮]/}@CAo~|֧oǑfH @" W!)s;ܫ7kƢO{iSF;wWOPgt@#6m{ZE;y0&-؈0_zw݇#Rb "LM41­0lܹs)oFܟ|s"9??GonnU݇J`_z3<{GD1dȐk뭷6o =:¹KqxW~Ȫ=ߴ;pwPXCēD |o~sC9/7zO/}ɟ\p(z9(6~Bx ~qE¤( }<{IB&{%yo#M܊)ZӣyqۀbQM:w$H$p"$'҆o":{۫8}š5kh'ٳgs= f̘{X|`wXn7{͛7/ġ(fW s:|E'nm4OWH. $H$ o7?uEutߔa;R* A ((6{c{I&1hL?WD]#e;νswII_r.y!ѧ]X~l6{!0흐dhddllMw^w$DzFY&HH<(W?UrM-/1yؑG?C^qGP"sRDFDaD xl9ޑd%Ɛ 12-!$7EM½^z5% 05[?DpCi;[G=b-ae# "9?r"Ex#9 B}TB D$AEu&ea<,Af0CvH'KE_x@j})3*z0@23FGbDA I0,cEYqF 9Bq!mCqlT`hY w:j)X: X S[V r5e49X*3\G}c#J Şe*qXz@R)(*sB1,j3) cG!< bhGa]~B93{ L#|bmH9Cj =E(\8%zbAp-YbRa#:BA(B$\R~GE"AyxtW0g<#W#\He{{˗F)D0DA7oF@ ^ ~@@B}&?^Ɓu=B}G(}6Ɓ-qf͚uՓ'Oր9ٳgPpLXEW@X#Ph0vT\AGZpuX! ʶ,gEf(`ԣ'C>|8t9Ta@_> {Ʊ !y3zTe-&da?=gͶH÷wՉM5сpgdG**!Ad=(*,)!g)/^9p@茉0&Z+C\=P(!mt }|}808$A!!Q6a̠$C}̵C e!Nk.PSB?Q -[aF<< 7.h?D`i v9a\@cr@|AA0Pڤ6V찟0rP pOnUZi10XvAo9 >;x = Y>,`:ۢIzaȔϵ- 68J0h^ +6A: ̑-anbUQr)xE:#@EPta sf>89 E1\-LD?= y[x-S`|_o^P4m1sy ! Á(0(' MͶ|X8@4&Uf>}MrIR}Z:1#C&`AT(ZPg_cegAp#23XpB1O@ܱElǙg0VeMRL9Nu<ufUs! ,8`H+Ǭ1̄xCa V@ O.tb@Y7$ǭ"#J g^@̏-3 >~8B.P;P3$޽ౠ%S%cq;f@[ 7>3Np cA9'GCE<2qo9AcF;{*1Wq wau 25%7*a L @B^ZȌ*+9gl1IXr|e`%Z6sEWm'<-=]Z ,@OIOzBP("R}\ukIQsCJ uԆ[[PogOPH8y<c2ba [\O?lCSDaHʪY|-RƧ(z hiՍS(@ $_rjd{|ۂ-ggd5ɼ#'&2&E"c^gtE"@)\KO|t#rq`E"P/经vP(9 /07kjjiDh3Q5H4qYuind:Hn!_qɻZ\.tۣϘD2 2_C%xyЫE̿jޢtLH*1; S(nt~.*|~3Q \'%-myLi P +=żG1OK#31D_#kVduȋUE::4ZHh <O)4bFw뗨L; lO@UU **08|t,g3,,@ߔ "@HGB5^[>,E"@x u55sKKTRPP0 !9'dpfN02>uuu-,,CF)o42*F64ǘ^C&ʘ;*N6O+ Ie'FkAEs2ȫbf&NZ]2u[ ,ÇV2n+ȼ/xHDr%LX^=< hb%>QYU[cGχb$8r540*GM !UE" @ӯ9BP(x^ߪ?D11bc4)%e (&&⫡jSGGG($C]Ў{8S|BK^2n%<# W=3G}?N9}@\WdQ\\2yՔ#W~3 NBƍkp\ܘ%y ?20sKTl"~ξ&vv|]'n'od:Нgbs=#R_iQ aun]P<_\v8,zѯE"4sUUyX^*'??,havttx G_??/o^}zԩ[a,oPs PT\|ƌC:xc[AKߌM?YF-@#}cӏ7] zx.=(@36|@J1܄ N..G0 r!"> h7'aa{M9p7v_N1l7A3I!/zsnjCRfLȭ ϙ1}o֬EkvΏMoؼ(| #M_lOƶnvݰt alnd5 Ӕ0$5$avt@Ek!Й]Qۇ=u7Ѓ"@o PFxZ%٥-;;;OURW?|} ێ__iX+z܃en9 5g>hU6,xˎZ}DŶ 7F-%Y 8P(]_įU_)$' ?0׽e_$R̊w p;>K^92[iih0e54[\eqIacE].p2z|W[vE#@r/Jt0GzOS33wkkkMMMPz;8#")4ʩi/?M,a,l'1s(  8FOnFu5zoѯ!iʊly\gi4[,RVP弻A:q MtUUGG\^܈|%'l_.|NE҃"@h]ÿ:)d"@h@Gss F *`&MJIKC >`)H~SfPl8aBzTH FbЮmht|U}s{\ 2:x0>1 .T_ fȂ?pr6Az5U& o|z|65N0YcBV[g;nvgyZ'P}uWR+δ⢿:Y.IE !@r/Jt$6ٳgpHJ@ _*VVV9(&&&777---F,$_/S#C+Cuo!KΜm=Fkd>|ugK6sE.dÅn?nj`bQ(0t1`b^I#xcƤQO?Tuτ+ 41u-?WEUg:U~_xun ^KH)eV^c;!:n$o0J`9XV>%*}Aj5 (NR8BemߗSz#2u^=Ew~ gbr2UP`\`<?,,JPJપ 7żh=җ9 `1wN!;clVj/s9{M<:tMBƌsА)w *'J^}/Q/X2PO=DC51԰kҏ}j4jh<=Wgk:@}km)F!l ̸&r1\n?`k_b+"zx\uQ =^!P:+]Zr_A{UIrV(o&iGM9:ެ7PK^`?k:r_bDPߊЯ@xa҆E Nz P $R\B C0Rs?\dbkBt5-tw(ץ:j)ȡ`)S.hQ{~V(exvE_ӧĮzHǽ OlKEO suf|+r0VVB%q]iQ q0m3\uU8GnY] FqigFL8bb$z+:?BtE6ۧ}eݐ=V1-Kl1p[4gRz:jq7쨇!!/x{DiZښˍӎ5`ykͮex>ہJ(Vt$'?2* !CᯤꚕZ ՗-Oڑ˔0m2xfe{xjZƂt T.((1cdɦ/dVQ3 %=#QDXMUpy[X<@6&g6*OGM @?¡eŽ/BzZYkr,rC_ܢN[4/M\^EwB\L\"id%6LXuѿ7X9soM/f* Yy#q6Ra;1pΏA'6v){ՠ/oBo[u)iEe_ @/`@,@P:]ʂB㷶ﺦugͯ-ceeG~䵪ta9jժkY,뿩)`=j猉'o7.?ȳze8.ew}z\ǡ=~i4kudЍ{mrm$s_=V{F㼯, ,Trg:.u'e]S?t_}: 3ѡ& K}V# @>iw:fAp"&kt7b у"@t$'#L.Жg_fxr]]cH^0,]Zz#@9 t ?d&3Aay3/yY<}!?Bcd(ڡ 4ieGFP8c@S?p^lhk9*AdBs7}6)(K 3;{Nu>u oվ5}g =l^\ǚQ >h9!]Z)j[=:O>ܒKun Z_u醟lp?6-;٠1)/mtߚ?hZZ9/7?:c, k'{u M n˅o4bqHU_V}=tCG[5}QtɵntF,Gj!4hwsG"4ow 42w.~J^ËNlÅNrqmCc M0vl@}1SƷ%QNG(?k0BGo6Ž -z̭Gw)#L;sq oL5\'5+N5 -rv~@7G?caKxK2;`yu]jLP(Ak0^(硷ћK9w&p ۂYc*39?OCXݒ:- W$Z2Tkxm?фPn=QE yX޼:DHO&-R@:xFv>R1w: E"@h 9lc]cS|zsA?pqYQ֍88_9?4t8Ə5ϣ5uI( g]maq fT|ۅկ|( A뛦mИQ/ɵ+O5\߈0a<$^ ^@P0B1,F}z}mRkN'A՜Y_GM& `81, x_t^t+:9_D/(hhG/3xY;y=.94-nm?#I '8,'do-hG#-/92#DrsCXo5=#Ȩ}>&}ֿ?Aq)n ?;B oY3U,C^-~1;c)0C!zdA A> ,3,C~\WlyאE a>' b 'zdT?,Sp˓<N(>n@Փ,V޽BBӧgRJ ˍvFo`ᐿب5''id릤7x]7V,w3jl50l"U9d;-89,Q&(ŋsz[Ugl TU8>m[mr we'xzřN=o⨫\2 "'Gh9]a D"mzJ=@7Q]il q;K|Ⱥ> #8D ls^юF|.|,iљh̽KLgf ƚ@;@V@OɌ%Q߭x}X<t0X(WAtرYÆcemc&@h&^֍^ O[eJkYu8Fe=WiL7f^('! /O3_0,xep咿BÍLt m~ՅIv&3C a;Pe}) ]KmKciI>aSHF05pKK.uCE[!_ Ej9Ĕ(8~~zzzQ IHPQEzϧ54 !R_ԩ[,Uc@tњ=ctS"_l-s\/U;xC=z혃ކbooԗUoc5k[:WKO=} N~ESN vr{ $ ~E{#@K;Ch@B#kNnnzF4@`jf94+ (+Ea#tU& Ni  ("24c"@6A p`yc\0P`deVWg7?K?~EQ>j<}S̕8_q6`O^zc@{1~!$^ L_=P9{nRA#?YcjEE~T G UUak ttT49شkߴ%JlK?S=/Q/}( -|s)>ڑs8<hv˯2;<fE/',N _ؿU|%2 8Q`bnOH[(6wN޾[:y$%ɗr.'גr8%ev8ZdFdE]Wl P}(1/Q/}( $T,y#^J$(Bq_(%ϰ;2E2K2,vnn)f)aa׃@3.0, PO։M}oo\iGӏ~@wG֟W6'✗*"XO|?P^\N*) GDYSP (^8x:UajL:GAE,][^p{ 8Z- Uj 4]I>&S$VZ'bq&,ʲ@cID}^ϗ:QMN -9k\Qy^,7%x̕.6~qĸ`8kENCK=?3ՙK ;WnXuxA~a}_Mу"@4YG&n??x> =lXJj18aС(!L y22;.g/|60 *"Ev ''''-p`󲛯?(&1 d4@Z/1,c"ND,.`5u8 `[2HeTY:FthMK1/9)% +ԑa0SNl PѠ|'D~.C BQ#>0u  **vfH2y0g٘ 1=k's"qdǷ$OhLroG־)fѓs<>[a( %@҉Ʊ7K_{(Ê36?,d"D&^!yR`,Y008VmQ2\ePa`=z2Zb1A׮@g.4.;ж;^P(Ƈ7e濮Cv\><>?.>&%'kkk# (N-OhqtOCKҐqw\vd1* ~$Io*Ύ̛u 0|@6O {vξYeC X<-א!#GY SP0&7bXzZh)A94dB2s=Hr L A\l<#S"#I)TC[N;4%HAQ Ha+9N3oF+cL"KًHm]s-/{'0qChkcG#`CUeW&[EO0jKD S4d*9\P騩bء6XS?cdL %Cs8|)`s2,d $vq:`B}yStЁ ʶH>DMogk~F\Q=O4l%1PVVMm?nXe-5H['&<{!;^h}BBC-3;-##Q ytkk @^/_Gf5*^.]sGǀAc|0quƯRUSG9I{nŌ^P숍W?_'g1NUl)\vLc®+_Ν_8q@$zĜ+> cg|֘埗nrRnji;cF/'-Ϝ{S|︔3@SrhՎ~͞}po.QS3ooXCDkYqڟ] >}^[g_4q-o=k@>c3䭼{.+lE=}6nrG6 ]FE<'}ᛳchHكPZ-9`τi _~3pB3~sZ|? %;G}%}`.ſZA&iJ>tܷ?8v %u%7 E2Waazo #mf_D#vz$U;rrN[X$=@4V#'?$;)Y?]k 3`RHbWAכ21;>-a;S ʱpןt7sKY=a%u'xڥ="GFY:raLخ˳[fr_x'$i GaK~%!@w$+)vA {ᄏWpVK`#F+*) SSat )c`ۀ .sv\ (KlOچf#gOqŪN"TC/|>vLT=RQUۧwFž}\J]tyc7/U0+}^m5RRW>=ߋpQ!1,^V)eF>f,HOrނ[[, :8~#rJ7ݢj'cTW#aX<ۉAgXpUٷ&^]e;ξ$L2]#xin~6V8,zg;DV"$ Xu) ms5Y|.ZUh~VFM-N0r;l'E6ᆰu>q]2tBa/Ú 0X[}^3W:xƚ̹ 3WA;2G+XGf/UC?uHꘒMgܶK%5E N) :)8e,_\Y2azp~DbxM=' :ȿ8j9PɆX3ÓzB}asb~59a#V6D1iUNW=<% t-3}J/Wk\-f^eY{'be^ :l TT(g=gkϷE2 O?;Yͽku 0vp+7dbm7c"?PMGLR9Ʀ#ִWi'BQe7Z aLbcZ*1+9g+GIw-=4cˀ+ [BuJXlRmR ~W ŇQgG>š 3~^/Tv@]7a_@Tq>yBJZst vt[p-7 bU߉l >d& fUm@X[ԏ傹Tڀd6 Gm`_2ELt@z# y1IR. \$]3iN n3xk7?uGG<~KKbX._Xhkg$NQ#ӽ/HT?aAxT ^3j; CRK'(!'L\W?xKϟbM)pobQ~.bHp.s%A(TqC-vx론-t!#}z):t\Rٺҭ Ls\fXuؼ[]irp;#R_ ׋ (.[I98\ǐ , idAUU  8$ϊr׻Zډ ;5d`P|FX/#N{-C-<,tBā$)( ३ F9C9@c^r^W^ @(AQoD)?B@Jm~_Kpdsojnv+o:'߫Oi\GcglR>~{c9CO 6i-1'lHſDXZ}Eddv6uKk֚*5ab/>",o(?ݖ߉җ`yM7H.MCl6o5Ѽe)ZP.o:E"НvNngsy{ytެpfoy:nϠبظAx<Z]\O+_LyxK ,@5H#6wy 2 kO&2vEc@TFşDm`cd903F~Θ;{>x*3-^0|ps*/{e F#R*!K׀ԱX'1(yDbjFF9]s7mtOe(d(aܒ;B ?pO }~;.8h6j6wafF:=2~8ud 0stХB&43aZW8)F!U>mo5wI7T J ݿDBe$p( Rd38̃r,a@r[9`N9kSPIS/"#81;loy,=Y, '?f90؞ ZŀC nkV+_;P oQP\FVLj:sD&$Ϙ^L/}yӑ)vD-֭}uO#MLW_]k^yHX;wv萻Јm ׽>͗:@o_Ͼ}A e{dv{\:Q<,6_B`đA#{9QIF Y2IL P05{D)ƀl`|^HvZ(oG@P' _taˋ5~C"4A8a{tN_}k}ktuc OV!vMwZ 0:ts q2גއGf 0A$kIFD$&lyrG9_pl7K/B:?o!l|f( $)%ii55GF&O8 Yoy>O?iaj-gG~graOCxa-Vj'xVg^խհkAd]IiSS(r" |w/S_f!_۷_]+W>ڬ|c߾KOdg}5}ݽ'o֭l֭{l 9ֶm06smժ/_~p¹)w}X_}﫯:빳Aln[["=żUښl)Ͽ<Ƃ4L^ ::b Ň"н_;FPB@:v=q# u#v4oltO##O]OEk߻PUQp_=xO\>8cu{nʔ?_?|<%Hh?o$>s_Ϟ}~{{5NNXoJy'LyRv4w@w@^贝"@ȉӡC|㵿[Ocrw6v ݼYL Afىys;,t﷩"oBu>ez:W鵯?jLV q*#珎$$?`GGWWELc[9eev7S"@C7<ΉPG X8kp%r#]̓<(D ^x^R 4h9N$ #SYhiyThuK+E"9e]99FtO";|Ok\\6UX+ukSmlիE"C}ڛ[\xpܺ7o07xaڴ.l%(ЂY|܃gֿ?lQ{j̘߿YчBX $_#T_O/=#Q )@rssBlPtx%I8ŌdUCbT~䨗H'DۃLqc!Wڏp;*yq;⅑J18sRpn <շUO,qJuŘ,M%M5M .W -j,Ԉ%̂Jj<60-hE"U{@;" CersA qsc[TU~eּEEӧ]XX{N>noF}mfFMz 6||rSMxc q`[^hzksDWWE޽{!(.!aPL ._Lyxs%hp0dϘ3O[7v*\&Zx?J}iY 'WK%(fH3<jʿ~YwDg#GPĵI78@[_F qr77n"%8zz?>Y4/AJAlvHhha~ɩ^>>P,%-1O#q妓A6gq'uꆹ'F1s ˘T;~Iqc _@tKz ̜z^Pbqx_s'ߣ32CϰԷ/ ?Ր1}_loJ~584(d1n>j0?۵DR" 6 PMmZRPϬ >Qepޮ==>AQ_DZF ۵RE2`[vE @+)vD_qtgf$ y?BN}OKWz;o?!OOyCgJK!̿:3v, #..LQ`ߖ,p??y11)){{{$X!$ QUPVVWĊcw\/]=hկOrI+͝P(;fE u=\[x<}^6D7| ˜0_ɓ7&oGǀ%zPt f*u uV7ߙ3kpko@ү |G] pΆ83}K ʻVÇAĦi:kկ~<P@D- ?޴8E'8a;n!9]L4JΙ3Grs"t,C[WOO[GWϞJJP(gaaI))0!=O:t6%%E$K޿`鑢'E1 SM _ˏ&+{G]7f>Mg`}pJqGf9G [o8ノ„BöFC@Gr}b?K8g]І) g \Օf q~7<szKVQV1iA[(']OM#ΞM>]`#@O8!&Gp{gayybcs kem=0>1qxA֘-U+R^W$S/_A3gQVV]MM90̙fAfIe➛Y3M(3t_ͯԤ=?u9ȨGn7K2g!,VlΘqI;z:}*JsU!>O/뫡:"Nҝ-aۖ{~ A-HK;; {!d@IӓJ5ѫKE3~QF{hy_5`,JP(kuyf1;ݰ!;_6G|/ooGG_ -ffn3NasT6>{u̝|S%6Ci ~eI4ѻ.]Q&KчddX[H0'?eAIE0sߥi i? qn\pHst7bz%WE&L" sA]=K*tpE}x?43&5}@BROn)_E#?UV?0jFMg>_?=v ۇ2??ޗC!M*,k2s nr< IΩd'}h55 ~ W@<#ԸŒan'`,茻0O2yjjUY,yRT`ڛHXw-C)ΏsU>xp54444<ХQ(hlhj~+s$n=/<ɐ/]# ߪZp|R{|2\ⁱq%ҲF<[4(%}bմw}#D^;R HP!d;t)C/@+ j|_i^⯃."|UT#LH2}?|qrDP(B?#iW̟*/4 W$+TxHOO(*ruMπ#N<ͭ~^2!/z3R)@; Б ML $))U /#L9Pm I¼_OCȂCM u UMrK5Tqc#3 2>%Ikcӆ/ց xjtE"o aAFY0rdpH@ @!R#cc|m/_fzOmr(LmsA@_9<޼\-]< z68VUM )}ĜLn i#䖹'x\ȞIR_|)tpcgMu'#rqgXšPVCaaqG3sSfr.k[[r4i4{fA@ (R"Xb4j1{KTMqߞ#&:7}gV#b|c3ww։-tE߸a}궫W;1QREr7t0 Ϳg//zԙn/S+δYetL_F[~ק-"g' ɜ_dG/3+S.O'-t AyRFfBڰEG#> {Сi8_O_ xXB$t;8v=,`~|)^u:(#:,ck>1nsެ]=@RHomѷh?|,6ָ1D0qOr7>߽pu&am!Cmn ˵>gg(N;2xnIKpL< C(>@B9 @7A??rӇ!=zݧP(jpb;:9[oi tUM?m9lEƯT2XKkR&,ě"(xܪSw~3nIl=BJZS%3%xeZ,h10`Ѵ!\ 0~D3KFK/Bڌ^!Zmt๷#Vz!=VX}!x!k]6߽tw #]=]1E#%Ȕc1_G/[:2E"@`P'|==# q kbaq5b#dGZL}m=mdc5sX*!ǐ93NX6")"@x-)7 X8.^lͻ/-g3P(:?CA?Z4w O\Amɺ˱5}ㆷ?a_L8[@uS !Qf'ǭL~iAU'hc[YO@kAC&MÇXb-qwm?ޭ|Q \7xl@]/NGP!U90{D?SeY<&R,֫rL;xO/P(Eon:53;wMMMЀ}KZJ.vYvw^?x@4T@<HiĶ73;p  F nі&VߎNIxJfi5ΞSRo /oKTޜQ*rٰM1dVe;r?//ttE"b`%S_eXQQAA|>''vl5?rƦUp%^[?Ŏ0$!0lU) A*"1 @OQ9|C.ⳠT iHzegю/R ͼaՇD:Ш1'>B0m-a" B)@$|PN.!?~rE74;,Lb\Wie.^zELJMrriU[S7_?y%y'f bI{S\A1븼t|q[2fy>O嗾m ygr t/Җa):y;G#2B$7Cȅďaabi9zG qPo @f{Yz[M=0DbpB {4#}}#kqDsc=]#$2o9-__-("la#7}(@'owVY-ohd(uLc:YԫZj8Cʚ!}sTkg1"Ӥ8v(VP0Oַ^f0C !ohz:HKi``Y]D,d,fen:B`6\LAI#4} B;''m?!p]_Nz{҆kSwpDQm&R(\nS*Yw2"cݷF-<cA#tȓܡʌ@F޳>h+cKCuč7²yB4y`xކIN˽`.Ẹbh#򡺫96@oUͅI/( E"Ew2':R_RP콩&|ږxb #ϕb#& 2\sv6uQiѝYxCPԁ?ttƩe~L%BKA4X^;? 0\ҧ5sO26`#,+0`#%0oLz*Wg}0` #YBwq"*8QMlb)"#C/xxH>#jU@k D$Y7ܔ RKDG[Jp`˨>9ph~Ab=B/,ζBq᪓U'C\-vU# *QFh,Wj2h>/R,mL{dB^DR)*鈝<{C뙧@R(vp[Ss&g&!+:b)cdoT=Q))9f=ra`5J)K J"@PU753 +(022B,B7wTi,]gL}7* ,ŃGjjhʖf֎AI7^a8F^ cr9=zmua ;H(f <8 WKJo?18|s"z"Ek,C0޼5ޅ;gq03l>0ѹϛU΄[gs |GmAd (geؔcA9+FNmt?z'hEz:g/(jX)J=M[͗ow`nKd3}52&R`ӥG9*NK?FetXԧVz~V@`,icRS.Rޚ&ݡTa|>]-M sbdnmɛ('E"n?T"/7aBIItlԴsigV^ 9f!3+ǔs !d>$%lu2 `x㖤qscki̚AɋJ֟0:nܪ,6Z2k7[X9[Hƴh\j𧨰<;DſDz c:̽eS0N}yמ -XC G(sr{;c_$2ipE77aW@iPo5 hKn@PѴ%ϫ)=U $q7KTJ|lEMfJh%'<) 1k7򇡫e`T<,8\)ϖ_/設i>"@xPѱB/<^ #njϏg?@@?.8B qz!\B Agl=??xVDƄ%C7V:e%ˈXlVJ1ߪ>ǭDAh^98v+r]ӡ>K̷NPv4Ჸ`7׌ ?D񥎍W$UCl̈́k·V .ץAQh~gV QOʦ&N+GU2_N1@Ӥٲ+5E컥ݼ8t[!Z Gtgdh jb⫟_{AP<Z7bȁ6Z~!b>'yN=vWgsPwŧwx!Y= ͬ8|=?#o!B[0_1؜onIO~-lae02An(y!W׌ԝP*yCޮS`ۛ 5(x>Rͱt1CzOCe(8-=n<(H'z"e ˇJL;!#PGVj@xqp]2:)\NT N.-?#KCq,W4~,)~ 4zFn ~Q!{!iC+nB1v+AOcbGTP("7Y U|%U=Ct;]ɻUN$1G}g\IaFrJjr'8Dm[o-CCɻ%E[!У?Hy9bl睐CNCk.}=~W;dzKivT/jrYΔ¼d K3PhXvdGЯiuM'Rl"G2"|Óx,iOG`0vF?E@0.?k?\\.EAN;^$`z"@tsz4W:GuAʰVV@VT)Ej}Vvp_4L s bBv?x[^Ew @]9>lFɿi Q mWK1 JP^$P@;Dw+>쬋NvK sVxf/@1_Ƅr( SdS!3Orc!OF)/r5}XhMŐM!LzFGLPԇ?>KLJ1Ya װ,$$%q\?j*W :υ/23?Yp\_ynң[B@\=#@s-9*N[А %QA.Hn(+)L0)+F>cASj]u0r/ NH\0Hk}5-u`5(_G9Nwz_mk-HLj{(}E"@xj(mii$$dzD&&&Z p8hА1P nStځ!C|*ol1S@TjXP}) *&28e$g᛹&u 6tO8G?`,kjXh-')}QRzު>o"fsdkc9%0U3Gr1a H%̖>nUYnv6і&YcL NNt,b #*Wtwg+^`m/GWW=fϏūN\G<86|u <5{~*YpQpx# o6YowH2?^x璒=Dy -yu%K|c?i6%h64яS7:sĽZ} }oHP l #-Zʣ!#Vy_ G{: EI(wvEY <,<2?p+8"@Y+#mP(6뻻;i:1dB T===|_mC6ה 7ĊϷ %=[OȬI= zy{lKu Ϯ7aUWP;5~twcl曶' mِvoM $1c?}d9CuWŎb&kF_|Yw*NC#nۇ0dkȐW¥e?7ٺRo#>FqOvImt $lCPj(PjAlmm!)5f# D,vpr+(W_u?$$xU#!Y9bt59iU+Wp$ZwCAιKF.Iv'sJ'Ǐ7C$,$> \O]CAE[}!8@pC<ԦT09;ph!A? 0w/"k'nQC6ۭXAy˼lX%T8-)ʢ pّO%9 G2O?+|t1ì,"@&PS(WMLM @AP; i]]w*Cg7QA#qI,e*ҷyI7n`&lNvDZ_RQ#Vd7q.=G-Hq1sĂ-~w KKGn[ʏ\ci(cZT)i^Q(g!6>z ?㗑cSh?Or-/B?EN;zv|@[KuWWGKSP(;hz* =I̽$e(x"OǨ#${[GHz@Aq/9$$lA Y$ACE O,wf x?T/8 W1Ff9 5X @t`5L8"@PS(Wu?-W+c)\.Tl6_v-OLgu O@aIޢ5ot6DcWJӣg$-?Ƥ@w@W{qoGP:@@_{6jd>vlM/)YR`B(]q rbŊKnٲ`c.) ܅5k̜9MMM܅?L&SٵkײeVZ;๻wFUz@Pz 'Ti(@`RtСUUU~nn)ST.}\ŇYnEu8qb'ONu6l3fqpեTJPԃ?"ΗBB}v@W]TiFlnm ٻ,=1?Yy O{~1QHroO\mNU=["@x?33X+O:5hР?|ڴi )))ׯ_):$&&7/D7RVV:}W \:v؜9s>|xeL<٪6mڄ>*S[x1Zйfa ,ZhÆ s?Cc}Fq8L>HJJھ};:`XjPԉ?(教?jX??񪧇߈QPQ"*NR=/r T"VÈkX`` F%Eami vI aX2?9ƁQi%}-`@AT 9bZ"@x?;;Nx]߽{7444N{pup?~>66v۶m'Mt́cͅgȑ_5ž7|Â8y?v]OD˽{`)=z[OA;1N}}ѣ13ҥK(m9ߺu ŖS(A@M_OI~̼}|zJ # amOo!0zFg̭:EsҫֈRRsf| qЎsM1(4T)2(u걣:EY"!s o׈ٷ/؊Sdj=rAхFrVOp{x[RFF  G '55ʕ+Gok׮1/6AۆܹsNz x1NG@b!//k׮󇉁ͅ{y(P(j@@MWOl~""`1^^^YY|ccm Z$F+[fwJʲ7\ Ge8"y+߱o6dd3݉Ϸv:dҾ)2vFX &jOv3kB N3ڗrytu1#çCz}Ao*OtQ&l+ "@xRCɃӶn|Pqx ۇuPXXC̀O  8-//Gd1n8vΝ;1y'3h_E@ۯP)*?`0'77y@W7G;9;bFo6t֮Z}2VA_xfν}a_9FK =WݤJ].&KP{KKðhPLCqwBɢBsl5z篣*7}9_B dSnnRWEgVLx!a8<@.r@SZZ =2AuNII T=F-? A(G@v]ưx"?~!.rrr}jjj >"G$e`&@uu5JGh;>=P(/p{cqFbH>4=A%'<FOs Rs:brqN{;; a6ebO^-UB,AIycs >BhϷ:KW97ݣ,й8fCX#F *7ዼ߉p@8Â.d>z"@x b{ߙU z*Qن aʕ+QF -]P2jظq#Uzl "hgb&MPk& Z0L0êF)P(5 6񏏯/~`PPFf&`<B?]4g@:[VFF{B0m_r/RZЈe s]p7bHkmɸ9fړ%(X/nIu>SVzAKGED\6Ma?S(7=aq#}CsQtvڇ"@Y"'D>AmX[[WcIAmtiyN;t+݉;㘘"@"C6ɀN>!G">Hۼ@lNp(iFIX6fFvpt6A L׻%Y!ה#Yq$MkB-nk릯$z~`C f°NP^`I~߶-mOzUbԢS:B2Q@K-_Ș w X41+2 b'h ' Lv?\Pv0Cp{CAlnRoaq C~)Šh۷o/S(:SY}!r[6o}:{\ /DHog/DܮrM#\-ILU? "set|E"=x}~ǰd_@Q;P^I(2E"@xC|TmmaZ:r6bݩvs@_̭]95 |Y#@MԾᙢnyveY ɈYFf(Fԕa|ꮮ}sޔgrjw/DŽ5C=}rbLJ}iD)@D@ ,,,\D66722llm;6MO:h_`C ?% -m"۵0G,"8 1CڙAX @p!I Vѳ|m~p#D<yrd4>9pcGLe0RlRnR@0 _l[:@D+'A:q,|2k:ĐdCR=c [6 1O)e2%/69Vf"1cpI␀PeNygfR΄k08^ hd_\9̢xBOĕ6®` .<۠#@zr"1BI5+0UXs{c>|%ag`$p2d06|ݦ">59~s I/^/vpr<2|J 7cx}O37)/` 5TTbd<axJZw&DZH[0<VX|㌫y qķFkdb<@;y fcL؊?pGyw<PĎw[?ނts( Dޅv( }Edrl[o% D- oR~*f&B7d˭,Ywxi}coYZkW`mm-~E+sr䂏$:Z ūM\{!~)|qp#sw? 'cںQ }GP/sf1U;ob/ 2kR/n9 l3xyǏm0-G=/i\Ud8E_GfڈmW5DŽE-6XC ~(OȨ1`` sE m{5*OZk1,0 du7Qqao7'A C&Ԑt n"o '<eVxM;l^jY_vOz9;EFDX Gs!H4f/L > 7¢i\Q`eȘ" w#],NumW0c{@YY^ W`i]^ t>vGZo&"3s>ծQK k΃!1MDGBX &; ^UdH{IxG0+^8xp^q™w$m11cK%Oa\pEbd NgE;l}+> |C]N2{"ވ=_u5E"@Pֆ t==lS33pSҘ*)xU-jijDfN^j,xu[ (6 {8v&O` Nkv`ZZXoۗ LW>cg1XB ټ~IgoAaϏo'jmΌ}zcIxF ʬ{/xf^ofc( ?rSL(6 ΨP AN鮀96uCYPј4 Vҽi6s w_*&NGutX8eSX~`Z~$ $Flģp|OlI,ݔhu_4 h[2cJrNgUM?`H96ӯݢ-' JO0" Wq28bC!o]iT݈L0(tL=Or\ j6{'ZT8.2~)V/Ep A0[W?,7O?8M4r8:[ UG7?٪c0 ,}3 hm8bu ,5pM>Y=t`L.v0`bӤ|!ix%.NY\׮``~\ xXƳr? D?[Z98ET}fN_=x#Icĝo'fqJRc-A S}S1X0^vn Sj\f yM;5 `wNDK)aa#T?u2/t* '@o?THd=ȿO6\}1 ! 'IH/h|woezspϹxdяQ0?C>-~ޝ sHr0iOŞS(ᗽQ 7%xwrlG %q6oJR'OG؛պK!6ښ/dk@xPBHӬ·U&>}kE">2rEE1/66( F pWCCc,rSU;ٸ\!/\~h&VRNt=()~hm )^}m=C8oMp /zhűy-l1_}tcpʷ|1x2rw$΂XPP'sK{? ˳]ktE1IM^74fʑ S es (ȝD"@;"pN0OoSN*W RhpCD\H}¦Yx?Rinpʣ!An gܻGb)DPQRYȜ{'8" &> Nh)t4CQ̻aU'B|;/[}CT8MWĥK wh[R%O.??5^gcd* Y<03l? zq ̱0}7àz.v )M捰ς!165\L$a@ Yٙᘤ1066 xG*kj = pw Z<&xFsDa)V0ٿ+2?6ް ߈v*AvnD ܂<1"\~IVΊ3H |y0C2BEA0 ˌC~ yl!јxIJ6$~#7ǘ rkl3!nj%gtpRBkh0Xd`R B O1Ht_HЙ׺OH;9 l02&C*coq8V0YwcBd0+)Dx5܂vP}. h9x}"m膉~˽)4" [ܣ6$lU)Wu0U|b OuYU]_e -Y|cFϴ0AlKtćk'5ڱT˃ KiBۯlĥ֫ndtLO%pJL~Fp`ox1F2&I|n1j (Bsi{f0I +B(.(1/@1cj̴vOipKƖ>&n-Oi}5r=}ڟ㱻MɿK9FnmlyS>ªKmދvCJQ('jmwN1+Rs?\vЧY KOkjn!3.r  A?kLv 9^)]Go|ͿԱԼ|er2gOE21|YE"@zpW@*Ci<5G , HVKJ#|CW[O2' 6#Lzm2tnav +e>ouKݖJiczmLAvy8"@ on:59ߦطj~!~ʜ_t~m9qm܅/Bcan襒贝A>7van¿v̳E)@O GZ/IVLH5U`0ͅ3;&JeOq[;^pJO( E@m=,"? N* ѧ Xi,F]c%_'{CPjn  otsw[ S{.;\MGqIyC5+ͮWGQ#ih6s6u(Wd1vs@)oo{\}ְ"@t?Һ#א'_(ܗR ~ޤl.(?Wt>x[xL^_>|-_[(W/9-~_ݯN?OFvHg)ᄀW9+l R}H~yes>K]Ȗ&6.q;9zGpL^_>w-S3s_9,sMV?E zzHo%엏oVNΠ]X( s-owܖvv_"9rpM-!أ %89@Hnli5Y"X=@Տ^nԝ#o@jWGq1HY9yK.ͮ `aDzz<: ,/C KHF.DXp|)$BNs.I\FlPaO6R(WO=D>a֬z,!.†/vx_ȓ˚;!VξE+N kh䰒Npqh*}Ư>=rWGMOǯ9Y}PlQhnwѰzװ52dqpux{;xbdnOp NYޓ,Þ{'}`LN"$gP;-<KW.ML@WW8._Ap/SӏȿcW4cw~] X*tS-t;76_6 NUB7^R|s3!`5 A/*J#ߕ}1Ck7CzA6/YwAqgoLz/aC 0+~Vc[ic [ *lO-t5O[G;:{ʨPDA[K+$eԬ?( Y~U}G5UH2tIKgcتxKϜyB濩n }YDm4{}tXG?l6o>/;agdB@DP`AkR4ƃohbMpiSUWH7_Wϛ%ÍiL MRi?U-\N>}6 %2X ܸ͔hBP0&|f2RI67~ e(@@}_WAhhh^Aia0 GQ0tx N;`5DBZ\c3k7doR {;ǯ9=tyZ'.r{V#O/̜?wO{ *`~45ăǢt/D}ubGTvH;SVĵ' ̄oN6@j`DxɴEv\7Bͭ>zAX}/=A _n%+b6. ]TWh'ϡPDm?!$\8Hn9KirY&M NʡrQln9|{}0%>oUInns1UC?)ˠ5 N45f5nOxVzYZ), sj[(?Ap{b 2x0AòGw8s?GJI*WOtK5ҮrWG[{mBZ,RTGMqLUEeZtV2׾wtj͞|-X7a+jC9 ۉǀ5dIO1 ? ɀaOOGw1s<{WG8ﭧ=ͿTiKuc̓I/~c(::<ɯh E;#jJj㦿UHӶ4Aҟ ~~P{4bGsr,g))҆d(Ṷ?7FG=dRd"OC_N~f$e2舠P:E"::"> ?t,(ĕ:t(NsmAw`]ÖI*T4xͪ3~ͩwN&΂?bM܂ 󧫙GO^>^% Ck㪧jSɧEo_mă!zӉώ%tJE"}q*#wr"eSӿ¥/no>iv_ y"L˟w~lX+G(v;_A ΏcF 8;twkMLIa)=}S+GSK{#3@\~Fvf=ha 8ReGu\)L>۸&B; q ͭq,r)q3S4 B4*IjPCs"]2lG&jz@tz:9Dp#z D ] ϖ[(GjͿAOBkB ۃCa7^R?Tw:/f$Ɓ]GƷ'C"<+^D@ۏ_(?;)FНNA5져 HR"Ѣi[G_#Q(3Iyϓ-OڲVO;թV F^} #zR|Ð^5&VddC[--kQ=1c,E ?x _pYq趂⴮oDEQ`Y9/$1aG ?h{G'䗾S= OV8rQl.xqs̐uGSݑ;-{44=P(_9AݑOAN;^.gu0^iHS(߁@OxCcs!k;!Mc&g[`^3GxO (}.nJϐ$*eEPԌ:?t>Z::eܘ .ЈQ- F-UT)oeͫ?(V5?HP<Ay<^|BBN^١%&6vXVVaYY3Y/q`%Doac{[@O${0WѮP Z퉘F![їSCKtF/ÈW,WZmPp{߈@&8@<?a52#km=Ԛ#MJ,w05r4f ouxX~&B^pۺˡ-L `v $;۰De$x&U:; i`5(%N"@}+k䄤$o>}ef?OOsGwEө{1:΁+q8ƌ]7QSsP !wW&i 8EF-:T0ܙG/9h,vkh1Zmp_o҇QUC> y+mt(0ZY{ղ_K9$kg*>sބnV&.lp^q6`L- $i%!=7-<-{Ȳt b?>sf֬Y3[[kϞ=hn8jEukzk_7=7_&]ύ:e[)GN$X zFS!R hthH濨M;vTLYzu޽4iRKOunYg:_s+ۗ7vy 79,Oڔt=k׽37]'_lקr^%AWU1fqo9W?3/A;6yLؿe©Zز@2BR H-,`YӹKiӧ^.7/Oȑ+Vąkp,xsKs^6d^'693eӖ\}sVoV)v=e;zS?v%:yE:1K1f͚zoh$_TtY|a}w̘nz'F)=+J=;rx=|;{\ &1au'䬸kƲ)[WuL TR ԋAlO9ӆ?ٳ@͚5ۯY,u.3Z:ԪK_u!%-|kon.B'T6mꛞpKPخ}FsWp!~q_? M7&vwooBxَGYXIm];`׷\Wh4wªcP)8,LR 4: 4[ǂ'uٮς!t53C_o}<\Ut׷۴QѨ+hެy7BR8ZNjڲe^S#7WT+Y\[d>{Wl_6O+|Q$4"=}GNSR 3HM٩©R  4$<5~fB5:e R ZC}3n{nh̍=O8)Cni^D^cz>Xs=wPjJzZ jF_񟕇_?K9MdѦWr(׿ƼdsfJЖ*\5__unF`Zχۉ <׏0NaU&:T8k`UK?O U?#|ՐzS>,_辠=@>7!o`hz5uN5 4R7/-ZbŊ˗/^xժUz7tӜlU'$Xl… |IUį5([|7l꯵~`r g>_w}^eᗿu~)uV;Rf_OJ2< 6?T<ӯzf}hί* .x'>r / !]cC{W_ sk'LjLt}ٿ/_\?W;ޑ52VzufN2P{޿˿Hj$C'F׍7hu]8Ӟybl^_o;C9jpyRԂ;`[Փ͛ܜ 꽀&A73U @j:-xd/j{'~gYf5\qo.-- իW_zeM3?C|k_oۏvҥKkSWW:b+wFjueLP1nw{X-%:1yhW_[e;,T[q#8#[~=}4ߧz˅;8 7nxU{~4$vmÇG]t󫶢9sX/q5bje]o|[r~=סƜ۶m}3DK/R=ke?\C2 [_7gu.35KoٲU]ۿ~+3 {2k{̩8G#dvݟXųRs35zꡠPϳ+ ^!)Oy+oʈF lKzv7BTw!R }O-9~œe+f/Z}5(Z&<_ox%-guVd0e]+xꩧĽ/&K>D&ofaoۉ!߿1$b|w4Ht$Ix$b!1OMD3_>ۿ (?Op׸q@~;QGaX&h3x|EO͝w),E|+?я \'곟UW] /رtg(2￟>aD~_ɝ0‰:l#IaÆ]znveT.O%!JSyN~0zesptb u(~aUS&jᒰ =CXDd:/JXGsH[~> ߖd=O?t@>-;MRA]FJ' 4c=fTk[n=z4RL"ѐP)KM5N?VRA}j1McI}G_WBUp{kƌ_җhCV]n޼gepJAŌlQ*FnUbdjdw\gqƮ]\u^؄BG'jTf\nLfZ2{L)1kTѿĺY iBs"|-3UI!_zIE0H>߀VE2ĥGQ1Ji b|#<Iޫ jq?PQuF/xȐ!."dpR0N=ڮ]Ү^m!C6mڴCK/_yVҥ<,s Vdz_6u1liy(`s 38yG@nN~_m:'SP_ -(]7M_Jg~Q{ g0EܼB1*o<Ӿ T_UjBs׍0~y3"}ٓ&M:s%vڕDG8TfRFXHbr1[IitAf*-X`,Y6NĆ HK`FU/h͌T+;v,h4 \Eױe]r7s_PON:Ӈ4DWBhN vp]ꕟXH~bisgd:=Y)hKO ZN)ӱFe@he|>` UXKyVXɢ&FؠMƬY8}Zg<4D,fdjRQ.:o|"Kg^=TXP*?.p.rk<ޓ<8vjJtBOh.F(O^$֍5AP/= 1 Hn+_P/3D6T\︝@W Kg~15RK^8Waj~\Gl4ŕ 7u|O?=!VRR dԸ}vc`М5?Dйgd_gN7Z_k:~jvh+N8IS`~?n9gyqǝ~3fͪ}#l(WYPq5{ ,͘W/W^ԦCW5::efZt#O[޻l)g_4{Mzcn}v1uww+vѶSIW/T1mU4o)vz:c2{.c;_#tgw]}X{>y]/ߢy)F+m׭W,y2q~<|Y1AIkzyhج}vmSyS# H-h,p9}̙8ef4A\&SY"Bh1?Bt ~5xbcCYBIu`K tN?<' ӑ grG{J 9ʍ졡#!Bʒp[ny ,%ˈ F碚 uP Dfj4 p S""ra_>@8ڕ'@ephzX_~YEIC5> I n$@/(GZWt*"pX}L Ov%Jku@QX:kS[*R흈óp(LP6G'%033rt'ҝ$ԭ PCdECVAcPwttʇLahmڴzG$Ѝh Ԡ:D[Hd)#S Ao5BaB}Zr*~<#hD ɅN%y!u5ye D)#Y_suE13<̔gy8̀:en V91z903t?rH}"bl k3]>j}@ D)M2<5rуٸi_F -L7VJ>8sZ-Xrr_ڽ &M2xqe4;ŗ>2̵&hޢ} zo_)~gث_V{h]}o:_Nua5 ;.ձw=yWp<'nrs{o&oɉ-,'ʗrXwouVa'yYMHR 4 {ozX̿ 6G{W\A8C_yh7`J§˛gqz G%-ʦR3l! V0Y3sf&_V-~Ig 6:U]|XT,%?QQ"b邱"xBbȁŴSS9!35k)kg VfMUQpG"bvCC!b:ǽu=37 M$9CDԹ5VFmyRC}xL'5Tx7u. soVVִYZv͖?oYNO ym?1y5cOߡ[f͚^Y^p>u%|go)O-2ۆ4v{ЫwPrjg7sJ oxg¨y]/xvԌ/amS;[mzl<8㖖6o[ؾ_V[Θ;MPMkjGU1Y/&Y  ՚͞*4>} Ŭ\+ Oe&ЌN}riX+!Jy%'wX`]S?V?^T1LMVD AE2S`K$ 'Me30;*~+U; DMbh) @ 5p"AH5!_v0 ԂZAy%ШHUlA}T$ "Jؖp\軸YXűIfmnc]Ѣ%PJ~1~:yrOa w'?ra%?4$8"8_N]#<4NU~d"h`ǕrPEᄶr)r:GK^0\ nz=u\u+cUrQ#%Go.\e0wYӸUFW"ӯFw=I0Z2G4W=4ͺ/ }ѪSd ! \.FḂ 3M(@ #i?7OD.RH$|`<۶ifɲe}?=z̘gշCQ'_x}\ JoUy`KN8SO{%g8y 49x?s5'd+ٗL;kDzw8S:3fyæεvy58EnWW /}s靗|c7У N(uF_s2h^qϐ \NyCVȑM\cܒRg!YDL /)+!"xN+>ԟ)9LjbFPU@e3)dD8,@,NCN c :@&yXN+0*~,OLQ)i9&?ȉF0g00tA%8` ) bεKI@8N،q(GP*SW8 3LEUk((j) *e`e|Y'ޓ/TFdK/Q'ӓ(g9j=NA*ք816Tg66l] Q;c8=-V M)FN$߰wcįxRNCIbyX\*9Ģ$"J}Lэ$;4"~$蠸-eS{&3DaÒUmLGEjϾ}t n-RgPiƥAˁ@w m2'ݘpϏH+v@AXרB걞+(ԓ_E !|mtI︥ޱ]q|LWU] pQL]ﳰ GJisUG%rJ&7b(b5$h cƣYӦ/ZtĨQ.t#UVvڼXxٳߏY\SgPU3jꔳz}hѢ帹v=^a Pu[X[`w܉$IoNSʩ &L4Ę젻6 vE(Գ6c`IEWF.1[BiiҩZ3+7t2HTb$) ]̂ou(UgBщ>bHzٰP+gMm7Ƴ:Z%y<(bp3Q1>$/P~h 4}U8˦G E 0AEn?m:^Q_ `3 '*%'zhR:¢蒑GR~JЙAP:۴F]5HZuW!1T=z;dG۝8.+ :Q1܀Ak-|JiBOf N23a}JBbXEgOA ~&JU^ byy W^mEc!Æy`y6;6e"3u& Yc>xl^CD{3<;f6Zlݡom[$6Z޵_YC}ȸ}uR>o+.P>OdAżMW_n{ƪNWKlYu-[S6KmZ4DO'5-[ŝzZ <>g;1&\E c3龊Yx<̈́pbfjH^qzH0 H"4"lHF_)9PR++$_XsRU>UH4L ;"a2^w7);.3RJabQ1뉍9` m qWt ̒КHP084BSW_("*ffW]x\TU֯rF'3aϰ TH/^`ar謳hK0M"=s -ȔAIņ4a4)e Z,MU&1vFtRXKه4Htn~kJp%ÍV0o5.و%`V)髶 YSM?$Khi%9T;*i,j2Y`H: 6wr3BD>Ū3? ''Muťh{2vɀч),Ł?A= cg4w%0ѐ@b iT\FB +*\M̤4!F 9(€QD'uNJ 5f?p]?>cOÄl?7?7vs{:3_UCXc=̀9[ 2.t$ڏ8HyO21G)xNe-5CM>3j^-<:k >m:*/AAh&[NR6r,J'l`UKL#gVxƃzpd</YP.CT"q#` :um_Ə_z5^b}39u onҤIխ7yQTTÙӶK%}}{~ʙot+<7غ'so??`So㛛yuv7q(Z糫ozQ5ʤH- 'cE8V5W^1QЖ}W=-QJGH"m g'|Ie/hRl<:7Z/bzYya QAr-uVWc?o^文uNfԨQhN/8xGߪJFӛbT Tq9Vjc#wxZ&WWEPIo'K̘5kt ^-X])c~Sz_Dz6W:pdIAޱ;e#/esj=MXwח_d^Aƻ_\^'N\}Qgϭi pHZ QbƫsjS}ީ$kmQ(6`ܪn7 #pxX%N(ZYoS nmADv++B`f좎v25{Ki  ,oYo\2Sj*N).߶ Ǯ۴Hb-{Pn_c+ }Խ4M8d"cu\<:KxS iٮLqL['XWJI+B*ehUnj&~!:z'm}6b ˪ Nm 1pJ6sD)/39FKl_ UfQ]|jMUݩxh5 s;ۇZ'd25/ʺL'\+n*0 A5$w%4I ŀ\cwS% 1  2)$r`Ivh- F-ҕ%GGԭ1Z(%w_N49f^KLK\Dƌ"-:"lu:݋̘N~^D*RB)5V+ Qo"Pʯ4..WP $p\dJ f;2G)(07<+ɳ=br1v>Π glk8Od^Y7gn]^<Y[@Q2jH-Z/iW( 3xGd&Nx+9787KF2RzŪ -! rٿeVWEDŽ,o~!H[Y@b7`E{Aw‚:| YC=aI!U պX`1>$'lU5Fe㡰sU"U{ywoQfG4͋wD7-b g"<:mڴ{{h&4,#!ڮvWgI]CԓA-2{i,zjf7\X SRԹظTlE[7*#d(QWD%:n.x?7H bI2彆UC⡘sobөQ<b0O6l\Q$&KC ͡|cǎSCGm1u r֬Y) ! K c!vQ;Jw&Wo5մ q -=,F+ڪSޤh\CHd}WYz^`-F;b/f1;!Cg4'Dx T[e9 HT6젙4hxp%Đ%1) ӕlKV0zޜbx/⃐,%'2w\ 0VU?ƑH ߧ>)s˶mEEi&g-Xpʩ6i4ߧû$>,9Oq9E=~eӖv8;ҁw=k4=&)Ǖ |[oy9WK&ߜ_Tf HH-pTXQ\x} g%1j6ļGtexRf%hʜ J `lf7Gj`I2#jvpbiݹ@BebUc X. ⥭+9f\jsP! T%hd8F3SBwȠ`3` ; U$Z&i(LdU+@(d 8 03gD:Dn"Bʐ/L#n)ŻS!pss)--w%DQYu@tjU*6x (fIA`7wA,sLLaCȘ1$Ø3Q@[YQ^ ?LdϞ=5z ve Ƨ y!Ƨ߯:KȓYI@k8}"K'+uM۝6o%W)bi+EI46̴-:{RK,_9Cšo$KF)3aĕ! 204-WqFgRPEr*NU'."2ޙó'1EN?]\Չ?is{$c6qK(M*5Y ׿uYi)Ӧ0|ŪU+WpU*"W~m/qO=ֆ;^XǷ.zM7fgV^=t0rўG~{]菇f=zv3Gzh0)1oB&(b Oŝts@.EfK>LW$vqI\fϤ O981`i!A  # @&K2NxU@ҝy\4Jԯ$ $cfP"6@1%9 dC|H Ks(К; nW!HFHX63q^DIIf1#7)$%m?4KU hk5T( 'Qj+dF!^UHy"ؼ+$G@/ɫBINjB^BU`RI~il$ Ԍ[^:HlTb1^s S BK e;f67H8LzQ etSWE<_l+'Ov9tm ՊF,L?d05# 荛;X #tժЉ]nQž[]5΋L& xv!ISD1s:dE7#K=Wi\:z#h:l!E4SX=Bm#$ ,~uCAunyD-J:Tw!` qhSQ]Du"Qucf'c\1]sx0.4j2odL06-q]`~$"Xljkƭ VR/+K%:*=hc\b.UWG h.c߅G6 1k|]HF.7b%|/b#Sz .~PrQ!{4$yG/O>ɖss>?ve`m>{m֖\;oDc 0FBR |,Ш=xb³G350Ӵ H[MB2?;XA%܇m ,$a4sH !DjE17#ƀm*9 ~xH!FBGA)("HBO3 Z{"? k$s^\t*Q310bg1aYA2(izGA@I_k?oe4J)qOt7$ ;MC?W khP̓;t!Nxg92t? ǜj.HJBnlQ*iANg;I.8hjW ,S-e[1.cCC,Ye0 {E$2!J-)*ۧd&h'ꂝ< m\H++љh6R^ӹDe.鬏HP~#?,9qQ+<NyW{4Fչ,2Ҋz܀̼6DNבazyӴRf6HgQ^эå :ܪ:Ql<: `Iօc#%]D+D7b1'ROqNEr*Gls#7)F?QwBMG8!0o\Ƨ;̒6$.P?=G?_='} 64oޢeۆW㯵'lgPy_S H-,Шl(w1E##hP7^ၨE9l Ē_ 4:EDN@2d* Pb._-:e"ELD ] E"ᢈ1Ń^y 3fp) JD<yq.]V4A (Ce֣[%DJDY$D]dbBr)Z@Q$S"%2II8BD~}TIC$Ll+ɂ Ø!'Qȟ>KO&Q+iR)j*.RXLF_((r L)'2;eu_}UiXOJR09 l;Gq Uh8pjU1\TЩO3Kxi{N\N>CQonxl{:~??2`Ʈ}h'w9c&Owo_\\9oġ3۵vnPt]Pjl {L|x/TJ=}z4u=Ud/*ԤFUz #{itlGWk,9K^yʔk.\Sy>|ѶZdI:יA8enCei2pj'& NTٲ;߭y^c:ޤ:y\:^#;􋉽vޟgF-e஗Gh׾[k1 /k?3w9{D56=!E\r?T?+znQJDJ$@jacmaSʏiRYP=@JdA#s`l%PFK#=jli'ކ`_PNVRMèV*v_dŊmiOv_&} mPjK^W-n 5lvyd䉔3KM;?v,g 6cFfnO僷-bu TTػu^lݬI25O0D~ r oPܥ7zh?j^srm=4gFm{wƜH]ʘMOy`ұJkL[~3ϘhQf>_Z%ڸ;Oao?)H-Z;[!fhoSx,mE8t$\0+ D% )c7V`'͵B J^z饬gK%Q(O4~mAM[:A_JhWk0Zt jI_x0ft1gjmkƉ*ъ/N 3ίxz^EauEq!AP> k{%$ㆅu/Kc@]$k#CdL^jP^]':D"xF Sс0PSN 2qh! 9_%,STޖ}SI,aW^m`(.5E G|񯃑)9 F!? ߢ@ Ws~R| uI6{gos2TMv(rLzAkӉC2;k~:?'@bkJwKӲUz2o%ݲoE3@jcM@@0_S=P M2 /   bAoT\z%RnAky(l^{뭷B;Ao*< +u^^H@ Ǥcǎ@`x LIP} + t.oJ%.;7[G۶mKrO,Qʉ@1TF" Xɳ 6$TS ձ*UJN)%$ CII7N`|F(vOMR;YCș4] ûA^ .qLGO29|)C]Ў|!(]R@n%@Yz.д+)LR(!M"dk b 4鬬Wr蕸VPY6Y E Q g}le!b{[ѿ16kg :0:7hENYF x`.=ƴ85&RqPUmb02YXpuG֓b=˗tcg UV/z|uʕ+ J.GcwzcR:&e17)#@ͳP'ɺFR Ԓte~~]?A8 TK=k=P$cDU};*Ld̟Z @j@S> ] Dps~mlcD5oC=i`BT[R"  @>bcUDI܏w DE -" TᬳΊ̑0?vBn#+$ڐ'"x .X§0[CR@K ׉SOamHП `ޓ..bb #}$'&I?śdUV9$A'ǢEU+| M@6cRAt$3 Rte Qµ+޾.mic@AHɏðS+kz0OUhڅXZZ(x !DjwcEtP 9EN>x\`~"%&5~ A,֭TNh q=o4 x)š.^B,݌7`S4׼/$Y4S)!r _׻ǵJ8Q |↓+-撗Ȱ$h]2d ׿ z<3.@"^Wn#i.a?&^ Wtڕ~ Y?t/,l@r'j)31/@jǮ/dt #H@ Po)YP!%dP!ݵ7}C))3#̓ʢnĈ6AY>WT ^)#P_6-g R)n4`_To( ]**KP]T)nA*. )N8w} K' '*ӜYQ%;ٜk29Tב e5A~90.¤F,:1\hTѥKq#K`Ts C@<>f*cNl$ϥo@8 9liae'ѹUKR.nF s?-am:%))@%N25/O)nQ$]QF'2,[qy BOKk 磊 QEԻo>H:D~1԰sybu(SDVuq *6a7Wa:S}U\$Ou9[i i|@ҴQ]n̙3ҏ@FǑ>`_gNkeZ 5syCf=VGٿ+uR H-pZQomvxI*PLfX` E4C c!L_㥈?QD.zDb?!tU^" RD93f :6Hc|_mQ%j8R tY W^A*bte[P;S{Y[A0@(Ac !\pV3B3 u_ [Bpv ⢃t[R#&O%O%+mK9ts "@mѿ`/e.!ΕDH\ 0yę _,*DasHO=0bR4Z+O Ѹ5CIV3l[oH,>Uud ;%0t0s{wGݪ$nENW"S?u ק/ OHaXӉvËIO9.Cn ^C<4:ék#B ]Rb 4!VpRAxc"}߅ 7%6}<ۼy<Y-g+@jFmFn#7? Wִc?v,-0w.&1 ,;0P4T@UNay3U"O֜@=(C5’xgJ! Xq-`4%QtP[:u$ h(`KUiaj`#C- xc:.]#A XkMXEH3Sƹ ȡnu9܆nU8PsgMW\l_?BL'jNh UpNV4Kׄq# HQ΁+|bqS|[ViKJ,vYE5:s>ECăU9gj3fxH[FgZdvDѥ_XM ^ 00ތcugF@ iTY9tŌIg[T62EY4<kih6=5V:ZfCװ\9e`:b4VUL+|;l@&'MqNA21<[+gV)kCvp;4U#wEq)tP:pA d<Ȧ Yd;(/6r=~3RC$+ka u~6$-Z>n7rԨYn##8zuO9"[|ʿʔ̯R*O ՊdYYdB~FB~>Lٿh"5ٟ]60@j#gzR#OlEKoڿHLmA|7Oarb^fGSN>'~S1K4c;@(W<@ aO,FJ@l.+$_ sJ9A T$<O~NV20'R` M>UEJwX¤=vk@]H BJ)ȊpD- V8T;n/>BrVN@.RhQW_YBPpIUm!*A&DR]&s9oeXqI/6dZ⢥zRt`,5 0t*i2v!zYBy7Q2t ?W%ТN)bBઍzA4BQ0*e)6b $zawi^e# Rk$,91Tf!ŝ yt:b9ftd(#0^;?$[H4a@CKZ%5ʨػw/3Q+|<2bIpƔn ,'fZ1k?E 0*\\\#F"'k 9;';q3.(4֨KnL=duu(v%@@?1o|uGD/4iҤhԩ[=W֭[GzT̒ަCnGT1KI'٪mPң9[gn6e^qIiN~a=+?sC1ڪuNQeI-[u=kC&9J+j7pgm5l|na"O]0nΆ]{gj-(8-&^Ԯflg).(h1SK9TH%H-pYQYJ!/:2C dY: 9DQtd* E-NPOŢ )(4;bB*K2: !ԠsŃ'Vš#_RɊ)4FIQ>A]eD9Y :I +%JtUǯo4ʩ*A)}}!O5J15͡*F_6oZCqT|JMՊ^z@xLTRP:k^]/[JX_S= !V_G?)+zѭ*ҡQ\ Et\ضj/H!h9U[i9S):UHwd5Œp4U 'ORXZPND,7R=<_/w4eN߼Yoz ߂Sz$@j÷@cvbF1@UVlo&N ?z4.eX>X><%UUekDXqX ?ϚqX @׍u7v팹sF; pS-"G?تu67՞9͚59c/v3͛;fe/n~=~v=nqsܧxejo:༇^7w9:e9#wx 0nF'} L^8Ճ'_S%Ƅq겂:ٿv+H-pl[ @;I,GvgY#WQ.p5Z؇V9. w GdcUE>iEy> /޲mG{wy>@?Ia}oִYtȄܛ2iE_7Xͬ7Va;z[or\hQ.'~ ,@Y[m hh߂v5ܽ'|-)}_ylR .}_gnzS?g^p9w(kOOH-pH6M-Z @Xzկg-X͛mM[7S'/[r k=YӬiKw=%_%=z9{䔩v4{i21EɹTRsK% 3)|/Ԣ -ź"ˋ I?{6gox[M$@&i endstream endobj 36 0 obj 173156 endobj 38 0 obj << /Length 39 0 R /Type /XObject /Subtype /Image /Width 1024 /Height 509 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream x1 go@a 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0`o`U endstream endobj 39 0 obj 2296 endobj 41 0 obj << /Length 42 0 R /Filter /FlateDecode >> stream x;@{~Ŕ**krT n63N !pۃ͙"}~7> endobj 43 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 10 0 R >> /XObject << /Im6 44 0 R >> >> endobj 44 0 obj << /Length 45 0 R /Type /XObject /Subtype /Image /Width 275 /Height 183 /Interpolate true /ColorSpace 7 0 R /Intent /Perceptual /BitsPerComponent 8 /Filter /DCTDecode >> stream JFIFHHtExifMM*>F(iNHH8Photoshop 3.08BIM8BIM%ُ B~" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC  C  ?,D:'P}c>WX,ǨS(c3oJ,pzFLAen_i{}jIžӿr1]-տ&˗?/]UxZx#څ~"ke]Ij \3Xǵ J+iiz^{-: RP+OO5n6?]d>*|I˿Z_-́iZ3孼o~ZG /;rhsNUOj.E"|F><|ώ_/X`%ēG4\Cc#>}%q> Bulֵ:HΧu-kh"|~I<ngܓG7zzli];Q'%{iWj/MslϧkrLv"W>Fu}SCWe[ϢA <=IYfU/?C_9~PZ_eŽ5Kh=5;1Y}j`|QOC"Hk]Kdd\5o_+٣4| 'otYбK8e[g/e|}[mk w~?xVe.W-mi!l|}3n?J='?/o t5eWnɄ$]gU!c?x᷆]. Cq +iRS:l7{Ñړƾ7bx^)0/FH+n5;MOO6UόoгgBσ>(|j iKq3nr7MޛҼT~mqrzO~ !;;xwJ<(.&H-.- [}T<ϓJ]u-򻤏goO|j/ |mGÏcm|e]O|ڻ|i~2k[v? a"Tqiˡ6ip[_\{Wc\]k-lſaO<H}K?7cx{ÇXL_jO4?7r!SZiE]_E{%Ȃq d3~8a/τ`}7Ś9./ّmr_ x~5MK:'&O/[K:#'"}~,|A?b_ /'~X:vKeDìn~V>|V ._JW[]صrKx?Eu+k)Աޝ`R?")?vǷ5^|k6~?tK7J.cuInVKO3Q"Iy+<%o^,߁>g};kium-|Xm\IDfx/Pֿhk;hlu{I+H}./?"foƿ~2Y9XB4MO~8u0h|@í?KçR.WL_g,dvL&OX_|m<<%ԏs vۣWw omR}1֬;崺ƜqLrwZ]ivFz?JtMlt}:6a=ԐI?~t ?4WP''z֗ ÿXPÌtBr}⽺3֬, CלV7ߗnh $cNq;V-oAۯpSd}k6ֿ6^\hHb"NO>{ =ZZAu9@otk盿?[RDo43YY;iv9pxc֣v\1؞`O'Sth]j;H辟 KGii^#Ҵ4HltD7Y_:O!lúwbO{ojSiMi] mmeY%kx?o[X旦[I o,H/q:mWۿ'cMo/WDžu]Z4]ێ+ڟbq<ϲżqR!_-ž*Q zoegS[/~O67;]W?g]W[>)}GʒB.'QΙywjI|/gZx$8|QAE$Vi;Ά-twU5G' <D澒MCqO%w:wmJI^kci^Tɯ'Wtk Ϙ!gN?'/ޅϙ>_|{4/_NO|z,x.1[Է1m{YH<yGʟ˽zO~ x_@h˵?mGנr,g_o~׵m?[Wԯ;[{Yu|d<1oYz\xkT7ؠԭ#JC~Aҿ~ ӝKJ𖟧<!cEվ7-mgҾ!x_Mb\=[|;:]Tg5L,~r6f{.o5˄yuF)^q&ٲNj_okcX?|m[-NVr:;#/|D񷌴|U_x~![[$#/suި;gsOЮ-~v^\˟׮@>&@0i1Zkm^8s]Tir푬 [{jʑȒWKof |#xD}< mwC4.DSDF^^qq*?F-݋sKW>7[r/pࠟ|k߃: zw-O]Tq#;t^L}]31 #w.MywzOĻ'JLw#5s?7GǀbyINڶXO |K+ǾkZ#67qmr66o,[xdkv^'%[3'¹,E@?AڽZ495%ɡN'. 'g+.mI8/lu>BLc=G+gL868CHM= OTӯJЂ}`q ey?κ)̫Y-_I>z|#8?J!oNڪ48ۂNH?ֶ~>ikms9=}kN{Cqj.cZRI<=Gï p/Z-c 7nGuoO?~'^kGivK| uv[uNj?K }yiius#/ z%og%|gauzKem1w gih[lmxS#| ?5w弴i]oϏf޵MƩK)/yixu+y*fW?O_ߏK]3L"O-c'gkδ?l *[ 'l|Ei' vVr}^ǷZ_%Gu/㯁5ºܙ.ֿmO7gW? >'A\4Uy PۋTP%ʋKoC'ެ>_ًDw?y>FK7PzO Yѭ>bxa_φ<7m.VlrOqsm ϳ~~b<1pX?(WZo'z_^W=l$})@Ϳ tO /i𯈼a izĞ3ݻ}^ς_Ox 6-RA9H!xf_hobzmΩ,-A(,et.䁖̭zקxgUԾ.i߳gM/_O-ݎG)ﲸN7D+[J,hq|6Lj\Zj﹍uEGwOJ???g~~*xN/]z; ;w<7ZeKors~ «i4K>Krms<(}۾?_?(UMk wŏ ih:{Cu?z\y;Zeu/ë_"hpZf%G$G;K;slqU=Ih:,Nrccѥ(Kv_ƾX|PF8tsJ?ϥ]//= ɮ1|ًx?J頃짯=;ץPKSzzދ)m?sGzKH<?ңlqqֹ ttsyT/4h{Һki^߉<~u@3;u9ѧ>~DSps898nGPxtU}'^\Ϡ>V_2t[vf'؃ר}_R,`qp^m1uqFK#729?֫/wڤ}&j&N~?O$~UStǷG?|&:<'}?XGc>9霌s\~W.'s_o:֐m9랄}W9v8 Ү-.{Ï__]ůA;ZS79=9EhY܏ gߎ}+KHr1׌~ZW[@^}>ֺC_'Ϫ}Ud"އ⹸(${sN|C.i&be֛߿޸OsT< _OuT >9G~$[iÿZxd)>֖WjSq|r[?ז:Ni6/$tӣؾ[~7jX?woN1^acsq?*Vi:garO_AGůφ7g&q5mCs,rS|luc?;?g$',Z |+zu`lcecN?ϭ%֜Q&}=_3H焴ޙB r)Ԛ^abHc"f',{Oͫ.oI/yOgmi؊\y2ϸ^S:׿Br.i6Ď[x^_ϿOrU}[/]txG:G7v҉Z?N+#Qrr8xki;V?kv<~< ^i\ N1[pɌp1=:ZUwm6ہ7U7`w NֺŪJͺ?N;sN+&g#1/Czw#8ϯ׹~B:{{,`vZc&Bb2~AUֽX@F#؜Zgjڢn[g?i>?>Pv=?Jk33iק)qu^n:ZɌף'R[K@?#jkЁjqӃ~'\֙8>ޟf&tȺ>^+m9_X-=p\[l6]}+jUNv}{KeʟCwۭ{0#I< KMCzVԥH&Gӟx×:{>7NN+K?v\9{ubGO]?JDm3S #a'Q]Ԯ~˦ 3~r:tޛq6$uNq~Ӱq־GT> KhAuqq sІZͥsG$Oxэ,~?CV|ww[Jx-Ǘ,r+zuk̩J%?Lf8^cs[[OS/OSW|&ľ{G:;qs0ZCFMn<7J|kk]CZjuGONWFL!M-z׾Yyٚ-O/q齟w/?}"{j+13?x4CuZZ\]leOOQ^4\q/㑏]q4͠<@a۩kAUdzc_|z>qx^Iv-m-|5><Ē=H?s\?/}~CKg9s SmlUhu{Zzu:99Ͽ^NVޗ&W0z'U~_}֮JЭ~eFzzz՛[u}´+Qt;?Ͻs6bөNJfc߹Ǜ9NߕT;t>G$Z/ֲ-Hϧ?|V9;__q'xuW?ҷFfFlg= bzQyq`&؎bA!Ig|)w<Ԭyc/|PH Oís&T1k*:?l5 p1|?Zܘpޘϧ="Bmps|%ixTlZqr|Ѵ}.8N'bְ|_8l@1Ow]Zzh?{q{'iֺ.n38>_hWOP>A mn| Y?_νV>ӗ6^|?{yûk[x0z_<ou\yⳤ|mcLe՜Qz/+/]Ww 8u1Yޗ[3Am+Z|(զO$GG=+T~iw6__U~?G9zsLg=(G<#y՗?>G_TSJ#G҆(<ӟRyǯӯO_ZfHaߥY=??O犿j;&c?Z76DZ8Te?G ;Xrss_޳oc(>}+M.>ߧLԚ@<NZ{';QxV!?V%Y^{!վt`]/W[{orM9<`=WtXLu?ti9=1W- uaڳ}ykz2|Ghr0{+Lc*n`sW8N~u|:N+#T9q$֢0Gl}jwjA\ _Vwy`zF?u5BP1cin-yxs3-o.4-nm.]Hv?R켌~믒0hiw5OFGi○+=,#Swt}G'1?MݞLH }JviӸ<ǷS*.4~L<^d'Oۮ+=V(EfJu-wē\N?y<{+6p$hٝ?礄WxK_=SLUՇm_.A?íok#sA~u(i&r/~?گ&wn-ozgA?͞gɗҾ>x_උ7~/krkqe6ț{_|+jpEa{OEox?Ӫү̕XN4|e^c.'1S޻}XZ@-:_5P4;swuf1qrmm~;#^5*|=:}äoOv?ӷܙ#)p>ֽW@B'/NoƩĉ57WZqoug? ?zW`+{?9Jsҿ(~"xj^{o2g~_ӟO?"I>z^I$>j;t\q>N+gox[Zs\`b/oߴ5]Fc8UHnڪe?.1Ǿ*k>G`=?O󎵭d$t1'9xZ=TppFK{s3"1ᒻsCyiUzyo³6NG~Ak*&ӯ¨OzGZ״I;+F.s~?&ҀGO^s5>Y~:xj5Hҥ&ZgOnj FC}*Kx1suu m88_x,fs=+Wr1qW]r`:xC&O=rz1WQ.i088?ک%_NvyF`rx>Ҹ/PU<ۯZďXԵ(1~$?5s<sW= [xsi'Nyks):u6iao cJ-maS[[GW:Ν^~?=ҼImKrٷgGnHlgbg1| ~9|b.`.BdK]'ϱv_eY|_}ֻGXR?mMg-;S>3]Qsq6ryzzޱ,hm|QKkfIȶll?5xU-ti@}=_r5aekV7C+{~OoO\{_N4?;ǖxww{#ᶸ }RRR8:*J{p@}k1lWxGqsql猟Ym%G?1I=z~{~'R0GǠNg{c]Z>|/>^~1|F|jr\B:Gr~ОLٱ=>Xz gZ~ٍ#m _-'<#s~-e58}OԵ~Qi\٨7lb3ۏ\ZT 9zO¶ٷ$#ߎT~aK7<}CPqҾ0-N?IvޞS֥#Q 0ֳF6n:_i?3IXaYz[vmv=3~Uxb>gZZkڎ[6ښ爯ONoF#uZbzMϮ_NG\8W_'['5~.:[x5kgDǽ7̿wc`+_WiվdZuO7꽑>i'x'?W.uo#ި|.ό>8xIXto5=.}^95[m![H+y~zx{K獼G x]WQ>.bM,W4e>zTRyv52T?ҽ9Ͱϡ?皋WO?KP~('SHF]ŨO?ٖ;/+Bۗuzgw-}Omu ><ٿbּN_> [|tƇqEm-ݘٽ G#yԮ #)1cBQpZm!ܵŊ)ԇ<@-ϑq1Hۮ~.a L ,' y#Kp҃?jyYf/~Z>$_]=-5M ]SӦKX5 ̉soTdϣgƖd\DH89ϧ>7u+aig?t<ڵO'#~0umyê^zǶ;DWy+i+%'#ÿycQB}'Mwg㢞URW93´+_>s<ߧZ"qҽSi ¾: 퇊nKT.&`yAR?1DUo.iG&Odm{<7LZ<q]Wֿwfe#Ft}⟵hytp_86g_JWS5~|[ƴuȮ4幏}Dy[C❺Z-΍ak־Gu"6}6ol5>CqX|M|7?p#J̋uWZxoQD:i1L%>M&meOgνkfo_ |5K >mJY5oBv1HLֺ!w)9S?ULd?Qr;_ -W(85KMF_qؾ&HoO?O8oGLrb槨N:!/͔|M%<lCK\=k'/7u泧nnuͭ*>X^D_!\d?^M?#:TWuˏeCH:G5|_< 3M x{Pk i9/.6}OU| ~Mn: sgVD'_𷙲@>CgN|}k?f߳Fi76Fi#"܈dX^=%@=:@{}6#S+/&[_z o_=kzdX}%;!]y<\Sڏ?x \eEr 4/|V{7?3E\qP?.3ױ{6j:VoCP }{O'5y鞵]ϲj>5Zj|w'͍Z;{Y.Ȓ9aU$v~\_^G=Sw:ÿ=~(t}n@-mMrbF'|?krë TYfO/ٽGGy{7 UYXsH[# UOUyCOoyMjӟn4z쉬^8z,5K-2}T[kIwſ=|?G3~ڄo%h3goŸS_I4MNM2K'[x;:ԗ CYA~! >+kwF/|Οg_-ϓspx>R^D,d0Nm.bҷgIi}wT]N_/??ܯO~ޟ>A|3x:[]?=ʳ}/_67Q{/м76O$_WSyg˸}y٘XC_sf4yy_%2+WU- ¦5u=SP80n漿#o G@4/ N1weu#ƥ{5 wq,6OͷOtYOV`O"&$&O`i)gߎ\iVZƕ#Ȏ&^K ]6 _O 7_[mu o?7n'Ka|/lzyWßxZ#ZR[;ൎ?wڼC$~Ⱦ>|3^ ~siC3In}̒ޙ>٣?c~~ߺZ5oX~HY=Z͵DvGmAIִA|[ӾylNpb~vj?RO/P~u]/M}" 5m N_9oJ(ƏZYtz/5?Zi:e\}3otw6ՙ7k k]:KC8SLoEO6Ͽ_{9wZ h_n'd~6_r-o 0z/Qк0|.fƗzESO㛣M>;hþBҴxH[mdmkݟV_>h-5x34}ߛ/~+Sn~!؟xGZߴg^+W]h{wmu7d/3Cgz  sA|/[/xYo-?,KK͢vwb>b?[k{?xv3Yj1լ|_%Y>͎l>aXCk majX2vɿ/5|ogƯ/ xJ:(XTgV[s6$M"|4 .F{Þ(67mu%O.hng\w6o{*˰vL.O|.uo^xTh}FS%լ1_8$~ E:! :n?Yy$g^x)b34*!GƿC 8Wu WMxbHIwYc5[I3 O| j%/|1>(ִM屒_w?R,;}D7.qYiqZ])P.f+|]h|]k:žP}SΎo=Z_|Gw쿠0;/ ¾+ӯWWQFLA0dxD~b!vv:UC~?g~5N4ROkwt-4Iw﷙>.O#J<lU$>韦ICOHt*Öoiz\ okmw]s#~DJF[p2St Xdd'7Tw?cKmz:Ꮜ=_kXqjx1u{F𹅚ݯlzW\p~ߝ~~<&C[5ya 90=ޑͳ>jubYG/_ 6\xh>ӯIYq4>[W^ϸ'mk_x-/FIc 'dx ?Z$_[ |I{H>.N-Wh}֟ͩ xf?Fׂ,ȵr?WmN/|Q2}M[s$tw/E6~F&=K࿉puH~+[W}&>$Y>DdV Ccscs`la7㦯XԬ>jѭŔiVl̍qGw^5u}^/nim;A5 Ɉ,#_ 5h~W b <2Bip'M~@ ~?į3&O-Ӯi2,e!_s~`].xi%u;fI&{}| _wg{K G5K>̱ $<&㯗>~"~ɣ\wAtow#L$^us>'w_[xy3͑αKW<Ǎ__Z]GP#=xnڪۤiyS2|+`:ww4;v_?.C^"9Kil6.(QՆ+g;h-3횆퇇e9: E-w;d:_Nּ!N—qM[M>MEˬGީ|Y?~(A{o.Drˊ;m.j$V?nٿ7? i.}._U,~S_6_KO>u*'{gg8Z~ۮ؇oԓ_ne/O3qho~]jOkksV:s7Ͼm#ow߯h׿VK\7t+[??$Glھa.?/!rIyqs fZ~(keforV?0~CLkow1hX-n lEk~?(_نW h]ˡ3i}Ԙ~xGH3t^U|!x⾵d߆f\uv6F|_}61PMٗNj|#i&]ӛ-疿~Zh&^lOGN,j#_e1y־MY6j_;N+_x+nȵ4")囟__-~F]zyӼy??K?׋Gmb{Vv/>t(~Sc|tQ?ldb_hvߡ:_XgEީexE}_7JNtbw8੖_?m? X]nLmE/ʅFr}___5'|k?h#$js߻PW8VSOgLjg/koMOú^_G X ﲻʿ*\F|͏ u} 6 ~%h 4|4UP3Z^;rs$,dhSrt2 |O= |IѬ$k+}irdl3Ʒlk>2O?Ҿ0 fZ;KH"/N@h|^2]/ƶqKۗmC4lWZam// A2 #ú{- Y-X_KM7?>j3?MGNغ5~ԣŝ_k^Ҁ<7C(cy_q:\??bQA8_jKkٮ KwW|34H9~NFht:ˏ?^}=K?7ϋ+7Eu#:x1Վ=j\Պ"B[_6VwǷAVl(KҴ}/Lce Q?QWKnY*1g]EׅůI1]L$,立/oէ|Nb~v:uduԿ3VoFtqo6:ޡoSu,wIu ? <WB[7VuvDl|EZiZqgF^$}q]'^FĚq{aKXWGj?|iu{QG;)og{X; x⹫O֟:o'3> @g}k:dh}O_I[uC.u 5,o*b+@;Z֕-YY{M*.{O[HP(֯RkkGΉ'okqKH{ ;vV9Kk0+? ?X|?';> trL-n.tk٠.w!7St71PK7ZMѵO_Gi7מݒcHɦZy'xqொC+MRWJKQpX|Umm3ڎHeuT{P7>LI3TQ/5Y$ww^5}6HWMquofwum~g'˯kBO[@:~b[Y0ɿWZqeL.%0F4jΡFxV-&?O! mR-T]Ko9 &ϻq~cD?#ڴCo\v6<𷉢]vLym%˺(NA=Xؿ CG|N$ (|,U/ {IVAJK; endstream endobj 45 0 obj 23788 endobj 48 0 obj << /Length 49 0 R /Filter /FlateDecode >> stream xn0Fw LZu)37I0M6RB~a/"Sv D/JGhčǹc agL5W(4 9ӷ,4\"B'񜀇.GNERc$_eq@R١k+ ^;W 7BZ[0O8>ڲкkӏ[J}$rYG;v0ʦæW{Veve#QJUb+ g cZsXcޅ5Y -Z g}-d7 2GhRBd,Lj#˼ˈ.5Ѷ}%5JhV %ڽhm*uN` cT endstream endobj 49 0 obj 366 endobj 47 0 obj << /Type /Page /Parent 3 0 R /Resources 50 0 R /Contents 48 0 R /MediaBox [0 0 1024 768] >> endobj 50 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 10 0 R >> >> endobj 53 0 obj << /Length 54 0 R /Filter /FlateDecode >> stream x]o0Rrn7&NͼXv@]0ϵI/JH,I!*UFˆx l_א"s7`Ab |jA"soY>`.9Q dFRJr )6XU>ʳ!=> endobj 55 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 10 0 R >> >> endobj 58 0 obj << /Length 59 0 R /Filter /FlateDecode >> stream x];0 aimBبD/?I@lYwyD03,A}3sHe e(!?YW  HwE>/Ӽ Lf,{)3Q*d6Uk ttB=qTurn'˫1Bar.|9YyCA endstream endobj 59 0 obj 185 endobj 57 0 obj << /Type /Page /Parent 3 0 R /Resources 60 0 R /Contents 58 0 R /MediaBox [0 0 1024 768] >> endobj 60 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 10 0 R >> /XObject << /Im7 61 0 R >> >> endobj 61 0 obj << /Length 62 0 R /Type /XObject /Subtype /Image /Width 400 /Height 400 /Interpolate true /ColorSpace 7 0 R /Intent /Perceptual /BitsPerComponent 8 /Filter /DCTDecode >> stream JFIFHHtExifMM*>F(iN``8Photoshop 3.08BIM8BIM%ُ B~" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC  C  ?3;x'~x``v} xqFp1Ǿ1wҀpx8;:ָH7rN ߧ^(Br:;qQAL{q~䎸w$~u⁁'#tǷ?J HZr~l ߧ^)2vl1Z.l~j_-x/&qiOg;(nȐw~5p݈++!9#<~D} xWxAG):m2$w<ק #ߗGq޿b?SᇋQ> F{ė:UkqhP)Hּ e|4χן OMv.-{2<ϮE>~`$!!"[ ,[B;Q~>nws<߶zu˹'#5 |R%QxW}{UtPhUźI.p#ҾY~foEAͯY9kaTr kaWPĜ?_ t>uDPqׯNu?U|cv y~{ c8'#qҽ}߄'xEeF-:tˇqyqMr@ 1cI+ƽݏܓ'z qr>v ;~85>~MOvjZV6 Z^4-P A;n¢sx'^F1߈NG~;qҿQZXsQ݋ˣr6%n6g/u~_ ?j>$_DKtl ),ǯ5N%Vr[ *>}1ƿsn_'gO/Z.5[a*T;ֽg8^?K`i6:ɪ68nlc'W#mA$w#㯽'ߑ߷t_0~R _[Ag \cKF8Wꆥ>R[Y7M|ǝ٣ۮ9<_sA~gМq~~'Gϖ>"YꏫKZ"A ,1,#C~':E]7$y=;}Or:;qWѿ |uOKdq/*;ug;FWWwdO?N:@ی:cۏ|cpv$uǭIAwdO?N:@ی:cۏ|cpv$uǭ'vOӯ ߏ9O( =?P`oG\z3;x'~x``v} xqFp1Ǿ1wҀpx8;:ָH7rN ߧ^(Br:;qQAL{q~䎸w$~u⁁'#tǷ?J HZ7vOSg>.mR7/|/&fʦql {c^l{~xNfɁO#̙֮.[?#]>6Wů{X".{}ȳ7+ 2 >+s C^,5V_]N4Y tOcGG`Z34 {xZPoGOeqh%3o!+#WֿI?tvuN?XE?g|W[4cGݥ' B̎"_i4;?|G]=;K!rI9P3xW?k/l!y'tKhang;Bq_T~"ou?x^מK{i3i%W93[ɟe4K/}("zqucodU;XKF ʣ""!_Lڛ ĝ?{P#y1oTmm?6>iv_\f ?1,G읦sNk? 94tя@9,ͯ~u+4ڕLedm0㡯UæI|G# nr]Ff9z?H>9My?ԼeOWe_ {'zhY>VXӤYju; {YhVbxruPksRvqc,fP'ƒ*Fea8$ ̬A.}=þk)h %?5,e1r}OnzU۬x3~ڮ~pkG:N7x&i1[q7p>z'piR i6}/2.z: c<YV_ 4j n,$8gŸ}cGEu6cl{?HE7x6}+ 'E}/ܟ|]GNF8mWok??bZݧzO#8uh2O?Q?/?QG'VJ?~/>5~߲{ 9t$\m5#<; wGӕJ#ofMw>߈wn)00LuYͩ[~X[_\ޣsڒ0;r+ڣW('5E3]c޹xc so+0b}K>~ Y|7rꭧ.V{|\I1qp!8;+o~#gi7UZ0Q1d+׻!Ju}+9牴O|mFumnDn Xg  n+ϊ>$Q׍u{S1e1FFX`8zr:1mGſďxQ4ۛFIm]Vcv0 uA HZ㨵;K@;x'~x``v} xqFp1Ǿ1wҀpx8;:֠;x'~x``v} xqFp1Ǿ1wҀpx8;:ր ܓ'yw׊oМggq{|(0~#=h3;x'~x``v} xqFp1Ǿ1wҀpx8;:ָH7rN ߧ^(Br:;qQAL{q~䎸w$~u⁁'#tǷ?J HZ7rN ߧ^*:zw9O~jl:cۏ|cC/1>0R~sT7~#0AF=~_Hȭ_uQ3G|c-ioyw W̎F#$WG/mQ}=ͮ{b4˲#~9ֺ𳊟~lKn>\A!;OƼ eGѵ]KsA X^]f٭-W/.F'[}[֧]?|AӹFHxͼE࿉1cdx1Ѿ?^N?b yL,Uu& ,0*8 -~`yk/ocğɦx{(Y%[+s5+rI9{⛝G sP( .2^jL|'yD(CZw_ x7 mwx2XݻM [),r1&d+)7?$4g|н岭0F;xQ82/> *O_kr?ି4|R sǀ־Ky쥹9pX py_/[_.K66_\G`d9FVX8<S;Ə543g7WxOu1e}[΂TH Ih?X۟~8^)PmSڍC--oiN sqR9ds~"QI-w TP xt9^jg'#`د*i4RYHas~kPࣟ'9ouhWVP{eE2K ds_͈dX>cִ˳}^ zӯj/ݯm/Ure7 :ؓ 燠Y9nm/]@W, 67RJ5kcMIҶ](i#FI68&z컠XH]s0 }gɛ|(`zo^o~KY25w -̪LNؓ$˕_ӏ' %'<>1]շt)Cm G*H>&7xIW !FEj Q o R3Q}lMBڿ.Si~κߴM%O dhoP &<̜#{w1wKEL_89a% iqkqqQcoH[vWUwc7gJ [ŏ0e_Űi:[ LXrIg?fqwSSiz@u|!t_t*>CcǗw>ж? x_WhVZ\YSg9O }-TW",ZwجM;X߅u9=z`pv$uǭrTVgm9]Iݓ<;NGSn338n=þ~?An<ӿNP00;~>uu=qpL⁍8~rs܌Tk ) OU;=8=?~1p_:?i.rN ߧ^(Br:;qS<` w=wW1ztuܓ'yw׊oМg1T($ =F*c3NNܓ'yw׊oМgˎ:czcQ?x܃Ls:`KwdO?N:HN?r;یQv>H98??_J`oG\zq4w$~u⁁'#tǷ?J HZ7rN ߧ^(Br:;qQAL{q~䎸w$~u⁁'#tǷ?J HZ7rN ߧ^(Br:;qQAL{q~䎸w$~u⁁'#tǷ?J HZ7rN ߧ^(Br:;qQAL{q~䎸w$~u⁁'#tǷ?J HZ7rN ߧ^(Br:;qQAL{q~䎸w$~u⁁'#tǷ?J HZ3;x'~x``v} xqFp1Ǿ1wҀpx8;:ָH@y'vOS0:}>)#$cd#^1}vrŨhV6"bpUF@#VisCzrx($М=HǷ]g#y‘/~Tp]2+Ӵ|ȶqFEG0Z_ϹoGO(H9<{%p8ӷJKOm<}Fw*Ǥٜq>Xךȹ74ښUuMR0}?@I!GځG~LuێZx{ÿu mj6t}z|&{| GGMBKkWHեnѸ#Ws丹ie h>g}BUG&-?ak+okagGd1c;[(__>/g1u \ ]xM4o \xzEywe-"\K4,y$ z>5~:N tXSͭ _n/$Pmp*8.M<;-a\*.[ ,m|x'8s֥;،7^NP[ =|I[iޅNnqr{RU8*G՚O>#FM>!EZCo=ƗTWWy;26-# ?g}Cƿ|uCyf2\dM̋]q߭} 'Ar wbuRVmh#\0b !?fO%6 PC~O"oֿO ZT3G̊A*A23i _~_;| |ukY-Xܕ }O(մφvך~}<$P;+CFk |4}Zu=sw1+twrR4dcO~.)<ēQݤ355Ø/_K,mQobMEgM+2nd)S(G~>-8|D}㹘< &ZG G{:~ 2+,vQ7(l?P(QNM .No|W{/^\ngLB,n0 _Fռ7j~ t[n&;g1ȤU8oOtbI6I}{oχjSkqXKb{ՒWNaP%K{5=$;=<};}kuOn Hw? lk LkO7As.huȝuc?0Y5 s  @*ϏV L*Ӂ(Y+I 'R1H0p9>w濱 voJm=:ZI;?:6&eMLI//)od9NScڐv~qߚQU\#1x@R2N4A5t)K,+H<0==}xK'#+ۋAoJ+N_nF׏F>tf wlι* ~־~ҞKTʀt됿?tS)z3xSZǨ( UC wu˿xB;-7TP\,~"x~mgKyH)zpҽ@n4 Fgn?^Ѵ>?bx*rU$At_!~ }ӊwFKk fa$vQbs*-V $_^x|,4pI;¼HӦ}U/qr7vN?k}AZTv=+˄wGV1Юw߻pzCil?sZnwkpeb88>4C/ caVoÒ|7k_??F5O'jiHo ,g xsR~x?Iuo⦋K_xwQ6ieT4@Y(p*/s)FǕ5b/Ǯmos_S{x{Nߚ_߲'? M/VYgFh~s5,Y\$H99 ޞP6i?Ӑ?/A'zWyl~/CsSH]cUUG͐9"kF"D#g'ּ<{ m&Cwu [Z[i^xBI%E)T/S5Xڏ$눺Q_10[sy&jTyd#XuJοw4h:չPc^D˷=]u縊6$^W~!rʍn%IsONⳋs:(0W^OaU:uJxE$q2*x93nַ~DS:t#܎x?RTuۯ*HN=J8zNV}E>"N[9<z~pRPQU7z`P?swe,1ϡ+JJ3mJ'Z{W=t5#Ӟt 3ڞ=_p3~q__G]ܓ'yw׊oМggq{|(0~#=k?3;x'~x``v} xqFp1Ǿ1wҀpx8;:ָHLJ~Xe-?_Q1ԃcp_0n dc~־giOYp5\٧0}ӄ,=N\_~%B5X6|HG$8rV_ixsĪ r(B?VN,F`u=9x'PjX+<ys &Gw>I-.<\iG %G񎁬.Y^"WOUXȵkP6Hec;9/j^Z< +}'H,IO5ہ؟^[iݞȜ#Ix9ןh'Ɔ`LH(q?ϭvqˆ_`$yT.}YqTI%uٹ|s^;9f2\ܨ2۵xBY칔L秠漼MeaGx$ c ?y/;z8VVax;-/m#:( {:ib}t #c^gma\"MH W?Szg-3lfa{ğ^sK.s ~nj/:Y'r~.0<(@LC~Uc\ a1u9:zu!gcƾ|Y?g/ڗCm?Qod q0|;Y9 0̤x{T<~UdS@s-.]lmFs3sU %\%MK ;Kn>HC_WhψAEK7.n$ 2mr~_߻ÕʷB:N+-3p??f_FdzĦ~[P4+LfX#GΥAS_>Ua9Oo{<)o`,[qLJ꧆SNS`o_&Eq.m+^%^I1Hk$F1 Fɯ#X!e[q!;Wo,w_+2hsmF|`g:魎 *?ů)&߲FאW{=3O2q0l: VDLa?|%Y⏅bZv69Y=űs-7MWPӼ5-2{=kxs%1<3m ⺰T`軜jATV=36jچ<.3uuNLIV= jc2*Fz?|x]m]{5q %Okܾg;Tq<+4ek%Tmlopqþ%{/Ͱc;w޾n4;-b=6>7\w<gF{4>o|u2;; `sON\ĉ0~T##洵mRLĀS'j+؛u4$rpڑ\sVTZ9==ZQ:ep~RBry+ .Pry}GV;Ï©_O ܴ/_Pcc|ר:eqZcۏ}~׾?vJ{gL=s_ xoXK|/;w$~u⁁'#tǷ?J HZ:O3;x'~x``v} xqFp1Ǿ1wҀpx8;:ָH`nƾ4ڷ!ԃ`g ^< H1;{ҟ%оiͲuP,#WV9Zӗ vdGcse`NOXg|Y?4k&I\|}F9К}_FIm|>]jxeFyq=:u> Q{ u$!X@+[k[H[tmG0:N}2L. ]gt6ӤH$GGEOoZKj>cҒfFG13_{yZ/]m)%%QqONƼ _ֵRc0=oQեE?6q-۷!rH}k8>V8B5h_F8ݹ\sܟ+<9p.[u;Wn^8x_Yκ[)NQ0OON54[3rױiV$wr|1ؖvd}x~f׳aw|boV7JLkz&.>>K&3eG:G‘Pqu׬-u\Ҽhcyo27-sIǿǭxZ`^:gG9W w?+ۿssz~Paߑ>]irbryZƿtK3^c\E LjJc_ӽy5ym>˻>$_^XiSv]Z^ZƼ rzk/LU! tJV+X/$$Ձ&s זH0A!;?RlX"{>=sK#<{b>Z;9/=N+/$7=}8uRc{"߇[TCwC~{Ȁ*rǠOG˯x]NYwF.H[`&@8z¯[[F{"y >{zߊ <0M4Gi07$0ҤF2H+Mu_XnP\^b6݌A8Ue#Tֹ&8SOuShamtVV]9=)[AeMBx4{[H෺ 2r[^Oz&*i2 |Č5)+!\axЧv~`O#?5_umQ1oj!{XP\[>Q\<UIK6YN?ZR1ET}j:Dqwi,R;+#R$S đ!om DQ#J 1Cz^?&աgGF p=&b".89IcEM}u3qeq ƞĐ3:48tO梖ҾӼYEi.2۬`qx[f6J0#]_Qǭ|&3> 8;x'~x``v} xqFp1Ǿ1wҀpx8;:ֹ3;x'~x``v} xqFp1Ǿ1wҀpx8;:ָHeOd A4'ߐ|?*8=?I>@YjB,.Z HؿĽ߉ F :oqS7[.`vN~<f#oOǭt6Y/Ѱx_}Zm-ϏI!kZJJ={`W+|:+)-VGۻ܏ξԴb˚Ec?ׄz/o-P;+b9u>*#5[QI.qqPiZޫ<*]_ڻ1}a&c㯯j xF@FeǦ:n(?eM~) TBڛbs'}}^q-$d o{gC$UOJCemv 弊s_eXNq"6w2F2'=:C1X԰?׽}yqɰ93ޥ~E]+C }kũ5zrr6ZJȰ߂H\|'wˆ.Ow__|$J0G\_ l`VIĵq^:G ]\]5?.++kfd\=nrN8Iwns4ʀmݴ;ߕ~t騟甾Y͚ }w&+2 [c!{I0':UzZD$ca$@9/)bX3 <@\Dmd1j({eh|ˤ%4#$;]|-cX<* j_ kvV yO9RTG${FK. >MޒI3v8<+=~ik"𗸆"NN7na_Ĉ :z3?4~;Y5 1̛ tMlϟ[W?dXmuCĉ,1r{}}a8_b,UFNr9*n$>Q,K.c>|)ɡ6;偹U=7 B Īh?w-m#Khp7u1Px&h-|e&+M2$g9ڸ[گඁu-oi0Tck|F|4L$1o&h\^絙&QdsUzg\v\Mc[d}ou죌*ptA+c{SΣUCRrUb~e]V DA21?;13?{'r> =W1[*)%@ny Wdݢ},K=/pYv$ gpHZ( $% ^$ &{fm;F}^W|Zi} ;kmTpy35;.o1Ouyn˓9yg_ AXM\$~e'q8-~ .4yCKvc x"_nAfׅpNa{D13}DG_ ZHgW~_pO5&խT E 8#Ǧx"\iN<~Hv澕a-=Xˍ. hÌr3aɿ{s)F-# ?hwNmb9^zjc߉'#qҾL+|U--EoA;k0~ǭ|&_>wdO?N:@ی:cۏ|cpv$uǭbn3;x'~x``v} xqFp1Ǿ1wҀpx8;:ָH@y@9u?axj ;kύKhn >fK0HL񎝏ҾV=ˌI uuHcZIZc1=13{axmd|r?%^]>8 Dj5~CK1qzfCU|Pow^pyNFqjV F9#}MOiXOvu8 /s[ÆOo/OaSs3F"WGeh{og~m|?xEB$NONO7Q$ nol^8Ugnth,n,r2c].e{K;y6n X wue-RjKF }toA i@[.p ׍aε1yuw<-$nu>mmDR5CL`GEF Bw=H]+K6v`yq9 N5*N۞.g1T)MΟ=X_ ]bKf>&a|:xW? ChpZ쁤-+lF ~VҾϋyd:hѝNJhrǹk8k'pwJ "JJlr8}uH#Gqǯs^|cjWڭE=1z^9 13j&V̤gͭb$}N8=]rP]e '}>->Qm$.:~}+ߣ>C}ž&״J7G7 vCbmeª)gN^QO-?.LS>OJ% ^'{iR0$puֽyE;OaqP&fXB[ָySsк+1,B0܀==>/pYkl"}ؽ71SWG,.B@"k7h55@ZIyXy\ 2ᵕq 7o^}W iɼEnFsTuOWz}£y sHXdt&m?ÿ7'7vg4k2 (d`th:|*%k#w|_ax'DŽGsu9}"sӓr{Sy74B ~H|HH,qpk^۷5k,]M=ʉ!]ג,7w1hfqA's+q.t hSɭTdfc4͎ 1`>=^stB l'7xcO&fb:;v¸5Ƴ{ž;dާp"ۻq}yH\VEt4tHQ$\@vY#Pӝ'+6\X[.600>VRFw+QR'NێHq 꾠 W9O*ݰ_~`T窜v4InWFeְ{|6r§r^q[fxDJyU#+b А8 zMJkD߫ՔA&*pNOIBjǪiD'l'j eqn7s^xږ\-Č[qo*(>} xgxH=$S/h$cWp;Ӯ=kzɝ]ܓ'yw׊oМggq{|(0~#=j ?3;x'~x``v} xqFp1Ǿ1wҀpx8;:ָHMvHGy|1Gf>Ȭv&X=OG5恰|c_Ḛ8l8>iOZI]s8m %Ў" 3{u5[_|iG`n%Syb1_|3׋t&s>`??:Usw^03C*Φ-TUC[\G6?$xlKEV#S}:?Z}v&ǟ9jr߳~%P_ ٖќu}k¾wTM᧷}(r̻x ל|CG^0`"G=I=o Sog,uPeh?8 rqۏ/)SW= 9^fʞwE[.܃ڸ_]ǪE `R7y72#9+wk}xdj\(#޼ڦkk7ٖwmSָ)0)ʚV T_EծeBdvW9ns6m ?#LRW$9ݱ̖_1m5;[զܡG_^1_h]c~)3~@NopnoRNsӭd|)5-Džt@n%aܬXP2~^k+7Z+ 'isv{O =GKW#$S&yӵX&м.qjBT\R }:nتD/? Z`MF4b GlaMY /ʅǾ1+YϪ]2\F<Z^}{NWOSOMU*_,>ksk< JYKdR Ot۝U 9׊OiH8;c8۞'ѵ_ wמX=`v_ ӾꚇR_=UHt %3+#4x{N Wc38'a쭮ERqs4#?kn5{7YT#3,7/Vn@==ΦԵYȷndh;8^Tg|=OSq -#kQ{Ҹf缹kby/nfm->ÚѴq1JC8SעhuqU!O:qN5ȩ8o" 3ĂE#9=Emz5nB8`@'#/N|E_N>C;c +tܰ| ^Zo2bJ3Gj%s*;W| 14D=uC)QdDwwf4t@(b}Z>&]9Ԯ5;Dm7@a}ZrOEs(eӍ:x~"k<[x 8n@9u7|etxV|H>eV?/=xz׼xYk\^iGמ\/k*D۹0L)Wu"<|4c'FwUIԎ~U|#Ԇjl}2}pl^vj&Xܑҹ߃s|gP]9"J(trI݀q^gE+Ug qooڷ? ~=גjr@Z/=#ӓ*k{k|u׈t 7Ec8@?zD|M;&Svn!8C>2ޚSO>FйR֕ w*eU$F8">2XSonm&dCH? e,q R_GUwQ}F2f{C?~1.\mZ[>UQ'vݞx@^/CԵZ[`[D!~ǚbZ{XrJqbz>5[O]>_X:W12\gv?㞝#^oGEW$dL/z Gv8U׏R p xC}>Ukw,^[^=DI d9~왩.]7qO$||+Z Xy~k -HӒ+¥Xc}oV'Tas , x׌] KPQ$~?WAƿxW.^h]0=2HڦVQsV\7b7:|iSex=@TSO9k#Ժ_-{NEJ.:ˌ\. ZZkm$~* O37Anr U/S|f̶;e-\JV03.yҼS\^j؏=I pzw5zmDDZ2p=xwjܰ)QIULܦ+1Gg;u$b88&88ߌe.Alv~ҡԊiÀ|a9v K,pʁIdW_ |5>[cDqR5\ ?N9ynVG] \5<;xd@U2N scOF[:)=ŧIJ*o6.ITp?jGYXPcуF%*",T<gg6P¦;(HxJ9{Ve61u^9kaDk'댒=;*u*!0\nﰓ9RkFBlͼ%dw_GC)=J4K e$vxux{$k`)l T |  |A?/DnW嶮G'SrjFm]WO|ξ^^J' 瓂};{⺨TyX=Q}6+܆U#SP 7$e|q($ӵ"s瓷*F::'s|]OCϋ꺆_:K2[9 mԾ0 H|:y0,\̷&d?{{㎣zuF'#+Kh 'oE7;~9qǭb ;x'~x``v} xqFp1Ǿ1wҀpx8;:֑g3;x'~x``v} xqFp1Ǿ1wҀpx8;:ָHM=O9ӯf `Gc( v8Ƿ?O0C>ZqZ:[>t|{ky3Ŷ 9#kg߉[g GOņ9$ _;He+nֺ❏x?7[g?ܛR68n8W#m_E,#s3JEº}GpBv?"T cWө&<'fYOl?~tYZL> _|@m݅YX .AZ$CVO@;Sj~%9x^ccY/+?Z8T (]>d B{IOG[D-O^UmJZ@/nǣs]]̰<i1t}#)M]_|-ӼG-L>d`}߯_@-<- xLYiBvȻ2sV'ۇ>:m6ʸڸ'$sD>9𦑦O%ifW c?5rץ*]G/XoD}/ڳšnUͥGLD*@#ǥ~ROj:vdi$}f'#TiWB*(.w6}񮝥Ǫm@F:u>W"ൃ6X!8ڊi> $QG*F:zbM:i}$(2P;u=E(pU1p~B?~6Iyǯ׻ZngΔj)ꏷGK]hZ&M[ȏ+#9N2+?e⧉!xrR1>Ok;Q}Bc_!M#YI*U⯆x~rj#?& 1x,|ue}y)F8?jw#HԵ6KĻbW=wMz+_goR9W'l/K30HZ3(&S15R=텋yzeE@5'Oجl8`GS_[iЦ1>믍h;k{]r L@AzcR#pq4b*Yh|Ǩ;k,OYgo~3<i4}Nm- 0⽿-=|E&=@'T^04oD5?i~Gb?nsWn\|sw= ^jm_(\Dž|ssq}titFDc1W-BV5\'$H%y`YR/ʗ@:E> gճxNڇ+=7K@2]X( уH 98=k¼{̖΅F{2c=O5o39^ό|2KP z#nzc3zp[a!_Ԗ37/]r~SӾ+WWr4EYdjr. z[A2Dʷ j'%=>;ϿK {3ſUOzi]܆$A.0?θ2|zF:gҽ5(=,z6iaLaJBK~2yYe}רY^d <=8JQo`Ѿ|gxx,B13Mo㷍N:z|mW뚎Kow/.䄑ھoJEh*>s3PQmij3++8?x1Z^ MjQ{+ H2ƻG\ԼK_E>$I&T>~p(<9wP@8V >γ'N7GTHiwk>_>$hEr| ֗W \xW]K{eZ4۫62abH'=1w ւfY}JTgBmjQXsֵ>(x^7x/GR1qDҡtyvD(׮sZ-Z-y'G_k踏lG,^Y?7nu ekG%'bORҽR+'iͼWbs_۽bZxcTn B+r~ҽﴍfZhxcn֊gI;$}c|_մ鼣nU{c?zOa`ԭfuC)883mf_3)8RZxqS^E,lIa%>LzL uc3kJD N1ݎJ" T .eGG_gY`Alg^cR#=+TiLR"2\ީ\Θ# Tc,>6l9I`==h[:`Q*'SƌϤ o.tj.jy xόt&Ã%L6 8__x "[o$?j0xyg(z͖KQB'=k 56ЌFJ:߷|-O j*g=_(1ҫ1+Xt}soG0_xWĭPZyJ@$c_#g>U=M4=:αc7{U+6dx'Cnc@Qt_JFѤaN |d+&]y<S0G.^}p;wԹ=;w89S Z1xy(JSӿSY (({c|ţr-zX  n~yUG=84WX4֮.$ٞ)ɤïd$׮%'>jI*Hap=*;];^?g*{>O]&DN8G'n;JR[3dLsJCذƾP4ֆ~U|׃=+qgEllX|O}!?MZRLW8YD.0z܌Ta`\p튂h$H#OH'<9Vu.m9 ǭH$2Nyb1V3qrrGnrHLcϹ>?Fǰ=q 8<;">CܟR?W>B,i+mtКA^f},oQ-{9a~O%RVa9֓W{'?|u %08`'¿-_>]dB]9ѱ_OK_c7>kZ-İ$xa FR]ZnGrN.SBI?oe ?YPN֒Nz}_w_gěhMvyt@*WҳO1 `ɂ7+|WBR<)nb^ 9~r~Wowex[+4-Xv,bK9|qZB22q )= :B=qEGV$+ѕۓqe۳3H1{ Cxi9\:Ү-M2(azH[Rx9߿9TAb+ϯ0[ar980:PqOVBOs5H>WO7SGrђOG8bVbĈhauGqT5fY3!.JIZȾ?g5餕DVΘ¢gktX"SFU GN5j0b*;qǷ5>$P03\;?z=賞GϪX rO˭ki_nEr]3 Pq{jg V]C׊ǞoZZ?%ser-;qZ)+ܚB[lxWY69Sc?Y c^ [Wc*~Uo<%̪vzkPkCХ_&|gRJB6pwdӟWzvK^I8^ۡ[xxG$ҼR5;-li%6?.sN8it TzؗNdgO,XUzKgxð SֹOxc^fmi&|B0'9>ߕxk|.n-Ǔ*zW:\G<^E 0 ݼpq꣮GQ_xg-Em$&L]^ŮJ$G^Ƿ\Vў%̮}՘y}Ppxf pG[ߋX8g'J):6v3= |5<+6=0NG~174go\c*@÷:⸧; .Iݓ<;NGSn338n=þ~?A?3;x'~x``v} xqFp1Ǿ1wҀpx8;:ָHN2Hnzx{է|7\hk0NyzH9`~}s];idN6퍛`W5ԙEs=AUͼsAR=r:^F,nc/i庎:SҴl,X`O]6.w۩=~j% v^pYݼc}GJli>$#^͐8>8ǵGsğH{F N޸ls+aF*4`EpcuBc ato H98^~,Sǹ^f;F %v>W0S&˩:wkZXR صI٦e-O>Roh_+2:mk䩼57otg|;Ivڣ:84fL 8뙛hiqT%tTQ=j!7{+5Cq>_YN.HrLm\1^ - g*[4$`2s {?J/ɷb`y#r$u/Ï xvX4pF#vs~2(ء㑜o_DHZ~|5RRBb;+`+ohXn3ڽ д֞ssq`~ *0=k0Tm$`v:iGK_CWdcm=ּſŬ}֟;nuҾm䐞U'lau {ֱ=Ѷxa18 Lד/<;cVn>~|+![OÝ6ȍТ%G^Fl%|5oJ1iРqZ-+&h!cӊ-MJ 2:qzV&-FW?ϭL`G˾+"(P"'9JN Z=nFH= g;`zd5 D`NG\~xZ۝ y"ɀ{,@\-X/le~k-v-?cjРgڤ X~X?+=9oBݴr]#V"60ϽzDmgg(qQA152YGsɮOO6M>j889gb[!cW>B8~9f>f:⾮Ƕmx'L568㞟8xxǹ➯U;BҋNʟ{Ҥp@QIoX03tJJQ}hMeR=yQ r8ݳʳ'/H< v>:BϘI_ӭd\Z_\u],=1OBl/U9g沰M[FsCu$qv1__ˊʇi#5֏{ِooR:o>zzr+K-̶v ps[{Y]X:q\Ljt&Ѓltaʼš=\ŲN 3y{8 WΆjǜq_խS}N sӞv4۫fB4>dG@ބ~"8Ş>T;%9ZtȯVwA}}_,xWQ𽎹²K)?ʛmM@[I)Pa*;l>!iv<BXdTw ROo9+?j֕t\9 ~l?740Վ)p@ji.Œ!џޙmNVu/QUt?_GZ:/#Hk<_h6$cnǟN52(JX ['(1+A+_<97%BvugLicН?qZ*Ϝ;uO\xjI\z)23A9{I e_\wne H]>+HMP ;N zW!#{f@c=IfkW<6:?䬵3;B%=w8\Ozn]U {: Ѣh DC֯?e@V19-b9/m#xʮs3IJLhI:c<J5$I!Y[ala x͸];GdikC ы<ϹS|\d梅ǔ>\cǹTpKWw=)s9\^4{қNaBۨ"bul 1*+횎C8㞟CUGڝy>d)K[oyæErr(#~^"GD=?Ϯ) RHI8=yJRq{qΤ~Xx==z.Mfgs[aO֨IF Lt>nd $R*sӟҶ⹳rdV{ ە5dIe6@H'ۿ0 Wg2Ro5$qZxF||נ=CXb=&ylGz.}p1ϥiIG6 5}vaǹcz&a'3.P+imRԖ)܅yyWS 8y,l'mG|(cn|#r߼/IYψ{'$^E_X[}JP.mHK4{}cmwtkTy08\oZXJrGnyJo G1r;Ƽ:5怶ZcPٰ0W75h)P^Eݞ "/sGӔI( b{Mf_Z^y~]́~ `cU^:4a@9e O^Qn$&'B(Qߕ|E!?qٝy? !psp/uVA'ǭe\_\5bx?)0f(!?ҩun6G9^rZ?$ʇ5#{o0^v^iozLdAid=RG5q.k="a,j8ұ&ePd܌UhVhq#lb9ҏفpX,&3.Gǐ?:/Xy?L})#b(ϘȭwjLˌ^W6J ?3[Q_\ȪLo''uKe'sr!w\ tu#%Y]PC?zQ(F(#hl nzs]2:8ܣ\?`.c~'[XnmǦ@֥"ذTu_z9oӯZ"b. /L<8䞿J:&0b8M3 QӞ+>k!mUHJƛX7OON>Rġuilt>)1MKMǖ9ZݒG!{{&` v{樏$!{zZat__'OOS|pq\Z3:H۷zl-H߻EN5=n$y;O?ናUcy~kOqǩUc=(W:⯙ͨZ3v\Njmx Xt+8:KD\r[]KKUCo:zc?4k]kW6aM ~Τ#ū?"(x8q)d03N^Fŷ!P 0Z iG v{fϒT/oIm278NǍmEѼN0y?=CGΒHo-n`fw%I'5Ǎ\i׋u{:!%F9Sɣ\@4Q$1F.>W@PiX{Ld0MZPP,'q~ӎ H%[8E?E`K+m. ; =$1ScA ͎sc؆uwIJdךno_0=}k)2)Rsi3ڑF*2@/o:vLƹ{n PӯQ9;bx[-V&+ȜƹKo#XAe\=UCc>jVm5_e63^8e#޹X3v5ۙ*Uq59yv8qY:rnb9'=떻BZF@x' Z\%.57}0knn&C$ܴ;= +ߛj~nל[),P:KN.^><=}ўGҭ`S~_ΐ]R[:ּW66aA'{UEq'5nh,ryg櫘miݴgU&ɘnj`~$U(?OO*[V]\) i'犹м dI#GϚ209€cޘ~\>N4)3u(8o@cOJȶ%ղ {c֮j0Tczq^[1r'EwCaԕeKpvߍP:vv8x+ow.?zTpE͙}N=Rˁuqd` rGN3~VhޝAd~u0tfS6a1pIbIilm^֩Bs3߼_]eyRPr \S_D/eP~ބï_.mkum Ci>˫(,ѯ-qWT{^mɟlxe*չ:K/5 @;snv#w+TV$מyH8.z)G?zQB!-JjT`U'ݏj"-!KqeϦyķKre*V.ͿF?vg(ʻMcT+(xIc^p^K@Twcbxp^2J$QowƁ}oZ?kgPa{ M=>|`q}:C1cϱv8늟'?sƩdDqă?95KD^.=:+st8iA39qhyb{zRopb֤_nM{}39s: {48\qOIsܛ^h w|5TjV`Gξ_J`zq}(p=os4AAr9E?x[."\1^A:cǾ0Ɣp;u7K>#cN[,9&xB:c8? :]r[8wc֦[;.>=39=p :jaeGiLy{.R{"$:}k@zq}(v:֏Gkvoi Xُ,u jq/#+ߵ ?xOÐ鶾-ukq;Cu$rZUFHZ=98)p;Aۿ?Z婈S[>xAhsVQx?oíe^j: 0٪Z?S}kM8N0~8?A;eCTas9ϷZPmBKΙ0q$c0SLTe+e opk%3el`qʽ9N0~~ 81ZV̢hX׬F]*XPx1 q8uuc+  z5?'w=|3>,x}MHhaew4LUx;W˿5|/dZGt,@8nRFb`_'Gms2fǥ7Z\EpN3=McJ)zi _ů ZG}lw?/(]V݀'ؑ>6/ͣ<)nWoqq,v( ryE>z o:xY DŽ\0Hl̎0^wg><RS3Kq,@]F)Nr@Q'؎g$~|g>=ԼCخ}bR&:FO<^ yP1>"xÏxfQ9#+Sn;A gп)޾_4%mx F͇_¿GlU iº€uj2kh۾1&g$ pCUY?Sy|F9ǯ٫?~|xq؇nu ;NgkFT_(lj/|9g{y,$J#; Gŝ^=3IKjq#NhFrC `u7.3߅dIz&N?c溛e.21P-N+ WN! {uksB4%6Ie c|~2 a͠56x@؃hpyE rE/8}1.'>XZi^SY^ y$RI%)ܪm,e6$d/_Wm/ï $6WCH> 8|%;W}rJe흼ΪgbBlq8U_Zv]<'L_Ήe[4UOI?ڳ:sx1WzXS[xeD'|I~ÿa> ie`3MoHA0tX,I;C⿢_(g_ oÝ^MWm,߼L8e!??c6QcZ,jφ儠!eUqOٮ?OٿSOT=;JNjR)"bT$Re^s6"?kB'Zx~TGKoۙ';DfO3|Q`~@{r%k8tdqqbnO.G~GVۧ+PiȻE=? xPO3X#B$j@׽>n?!qǵ|o?]%Z^U`|Wn_]-if& (t) eax""7s xj~n Im&>b^rX>5 uswo ۟|#CAWI%PzWyj~}af= sW=u))ToF{i_7?oQ5b]U`SomM[Eal./cYWözW칩x"E׼Cy#3(bXU'׍5۳ {]τ;hRl;y7]r0:Wi#U*~x5M57 59V]9WV*{uz~ߴal|5ᛐZPe!t(FPˍUNrܿZi:Tжz3 ; I&luH+ ZRk@,TGnm-[ V4? ^x'v|F-y8%`(FYe8%hî?Q~ſa/(|>ߏG5N]^O&x`Qsrk]|5cS⯅ ]OȈA-pU@Pm1*jZҌvg|~~|Qsy"kpp[ _1" şceNj/jo.{VUD%ctc?F zK{I<8Ŭuølv85|R w H- cfLau!-xc9 *dJ~_'W_I4k#ٿu̲0xc s^%Wh86#muafUe pN?*5_bmh<#E$#9Eqi஧rSʶ}m ~s~4G;i k-gw-˥멡!9 &_(U=xnG~ؖ0yú* IuƿJ)g/ANJ?g_cX|ju_ys=<"[{}v>`)"6 8eq'"O;?/<{\h$ۣp IJ:02+o J~^އmcW൝4 aYJWeUaʖ[fWzCE%$*Cq!nk:JIwq6>R9&iOl-eŭAnk1,H8UȄ3Cr< tQY$rѣB[XzWo';|6Ծ*AХ Qcy4bB ?3 ~J?Ƕo.,.#1F'!Y~0>GN`ud<oS˭WQR#V [~gtY=Y׈-՜Y\ ԡŬM2I(Lc q!Vf>#Zίs1_5RWFI# +/۳M7;_?;Eu4z^C ĕ2hTOG?fxXWTRѥTw_$"cJg$Z2`+uqߌq^k]G'qڳF*7?+⍧Ȓ6Wq?Ue]1˿|rnbM͉u8]IIW?5\|cs_ٟq \֙o+ZAsYQnz /z-xwI@.Ѿ >#n@ȵۂ{WC5׬<=K*>l|{n_+KEw⋉`$I~"Lc}B%=A3d c'js/?]mG IoHID Qͫ<zCϯ @-W [ƞ):6m-+82HP3 ‚}1??$Ǧ–0![BÒ@>f@990t"z_=01x7Q5tEtYe Xp@5 ̺c_x4WIuU6H%D< ?,iN'Îjo/aJN1_wA̽HX&^?Ű[?[/ 8O9p&pI`,I01~gg{''izG(71'e"Cg.r ;F,lZ?M4 ! D3pFr9\ca]c_r\)8&W̟>CSƻ\DO$+y=+k 'س?jp{wB>wTu$P@gkpg??OW1Iqc;¿>[?.I «0:V,d_D6񃵹uEOD4mϥ߱?> eVq?o?~+g;įÝ##!~Ǐ5+Xľ-bkI̞tQ|эs_[ğg2bE& kl'ʋgS~pҕ'srgm>00kPw9r1_/?ÿ>:,l& +dNkuWUy|澽s'̒3n럭gY{?:'zOޜ%د{joWB3iQc_!M3E,D\u[jX~zf@wsrIq{σ?(?/"f:͌(F 9bTW0??__?.u۽ZOit5+63 89sH? |i?I4I3}n?yo{HK6?~:?> >-A<[K%TrO&?~c}os_.nNGȧ# C=)l1@9 v=~;6gψ1Yu+ð3;ٛ~c~QM~ |C&Lx1y=ջ)nҿsPtmK_d,-eGl`G3xFO>P؉YŹ4ߏoc=KT+ OKuᐝb=i> |Z'ɼ=yh7u  eO,vzK3_#P>{pAG?V\GY5}^K[wO#+> PӵdʚxZ d̍7 +&NjZɁFn浸pó2|B "|O/_=M(ך9aܭsGxJ~xYEF$k ojO r2QXgG ˣ0ؔ߷5oۓ|YOz5uL.5& akGCꄎs.;WϢ.E3k-Fڢ +l4x&8'9zw~)~ߴƯ |L{2:-ogA JmȠ K Kky᷸RAUUe p0 8#kDՎPkV2oH#y=H+o_Pڃíg=2=CIRn4PJ0gO!8n=þ~@;c (ڟw &lu {;tHXJ&Ur oU9>}9a3Pϯ {c8?( ;c^D(|Uψ-IXŲj/C(3T.}a)_a'Z^=k {c8?( ;c_ſ_|uj6Cƾx-p30pۼVA/SYJu!H,Rq"Ntv၆={Z s=@o~~:~Zf%n#vrDM`ǯ?`NXOF[I%RP[tLsqqKpv$uǭKa%{29'9`q=+7=N1{҃?AFL%|D?^f75U{;xHEQ@'& e:»TeWd~ra|q~@v{YĿۛ:&ZI"EfG]Ш㯨f$_E 랿ҿ8w 1?Ԡx cW\S=O>&Dkߊ(#Qui :/`3cbbSg?887L7;S~jQ~'2{ilzg~#MWvg{9 !RkZu/ deY͛+M4]T(]mbP?Y ;98_.tz:NU@ϣh?_Emz ̖ij5Ѝd,S;@ko/Kk&iqri u >K%@I3ܒO;S~JPpx8;:֗w:'W~د/|KBM9!E[fVO06 FN2 #^:nW~9AMV[K ]0?)q瀾#հlfӥv9smu@Xv@Zv<g xb EK=Դwmnv#=֠Y}o^3gſ(Ҽ=qTǁ5O]O/ʸ*3 u<?FYI'ď jo+Uɷ(Mʃa5~?4?ƱjpՠuEB?ƚd׷Z&$.->@J@PrsIU"]+}u 9%]=sLӴoZ}mo}-ˀv8E^?? ǟxSQ_[Cqf]$?+IsRbpk>m|?? *~mKKȈWO'3nv#ߴō"Bݤݺdte?sOڋt,=~+էug#[##M2P'ex/MxǮkGn5ט/1޾MaoOϋ5;/\¬q55@CD>b|'HWAե֞=%![hlb#I,'GS NXl[iZD\G |"+`08ǽ|$R|_<]5ek%OY-ZH@($OCĭ_ T:X/V"ݼ1H9@5F;?6!O]>ͼ 6ʞ^͇2W9j]MJZ9jᏂ#IbKͿW-10±eߏ?eS:7w̸[t?t:]z0_ŏ`}>csdp^ \ZX~q'$(~,x)/\>صLJbHee.nH\NUD|Y_ koǟANjǔy幆w,IXwe؅3Q|wj_"-PtKlM6Ҭ|ڃ4&64۩l3@̌& \\ⰴϏ _@gQ[hdpXw9V#(>\rέIt?oźuơs^ H`_2%]o0ŔWU{uoiz5 " o"yn! X9]J1~t A{/KKaemzj6ev!xѡ}$W^|De;e귆5 {c`ĈPy8SUF>>+mhz|1jhnJi5̊T+> stream xKo@|9] RƖK61Q.,c wv0Xi ;c cx0=Ue㻏iL) O)8.m~pO)d})5.y}V?x(.$E߉sE@ AQnq4^ $p&M9 H < VV_.JߞI\:Ң2)9Wa_Ґ^Hd ʧA8(2kxCϬ,fFhr(I 79 {) 72v&SO>k5՝Y CO8;]@-[Yt{8MurN7 ai3:9!sT0=on ]-D2[%ޮ> /p>Y`s+' |voF`JZ{0PoH <"l\Evh7LhuFMZ/x=4,Dm<Ǜtr?&v̖Ɋx8N?Ӎܢ~9<J.G*z1b]4dSb"kfr endstream endobj 66 0 obj 604 endobj 64 0 obj << /Type /Page /Parent 3 0 R /Resources 67 0 R /Contents 65 0 R /MediaBox [0 0 1024 768] /Annots 71 0 R >> endobj 67 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R /Cs3 69 0 R >> /Font << /TT2 68 0 R >> >> endobj 71 0 obj [ 72 0 R ] endobj 73 0 obj << /Length 74 0 R /N 1 /Alternate /DeviceGray /Filter /FlateDecode >> stream xWTS[@ W)#̀tDJ 6bH Ć.łeEE]l+kłŊe-tQPł W5rp矿,RH2v2+s|frh<W$e%&A )׿WBP^3_Pă\( @@h܄tr)Cl.kd`H2qKlnAHjb++E)!@ @xHC|_* q "?YT!/* qG05b(C%S _Kȱ8W3eBȓ=d gH!~.sRU+*N!6|I03yܘD!M fU*O$d9["'tA\!(R3raj4{@֗RrD(qB,C R`L2E2;˕E!H"J;A:P¿< ݀+Q.878ؐK r (2@"\-9W T|8g\"S{etrTRW0W!WڧNRZ%&8 GLHd>FIUGhb;aigӀ+Uu߉8!U (ZJޭj\fpJ$q&)-Vư\6EĻt`oU䋠 UzouIvw b}[aS9ح|NiU2}e=}h `oNR/DIws/yPeSfLIXɂ+W -2W( H(w%굤L|UҞ fj6()D{hQudT:lH ?W܍|y;8}2S> Dõ~f>O9!!?1oS,Rם@Ut ݅Cg |amqtMwGG|ǧ!"MeB+?Uɔa#D2iDh44S/T5th ƕeU!0ѽ`B&(s^s:s`GK aØrcC8Uźp5G$;#Nue!GQA$Q.`/^(-rr L bz¯q!xx  H$WR CO%M'UIuӰ^dc?Lry&y1y#y82yBQ\) "TPQvSQPz(o445444$;5j\x1,\MEfUD Rk ;ZZZZZIZ"Zkjz=Q[D{q[/h4#-EӖi'ihot:ΧϡWOu4utX:uJuu\u ֭mֽ;g穗WXo9^}~>_V 0;p|m z ɆN<* ; 􍼍ҍf12ƌ9b34aL4\1ym:4T`ZiǴ,,l!渹ytMGQ9b_-P d[---,ٖRu'-¬VY6Y>fa`1ČS h!['4r=wvv9vZٗAAơᵣcBCNNR]NwiΡӜk$?rK.Х+*rzٍ&qur/vaQq(QYj/mO}r^.^<kiF4{Mq> }Z}6emol)`lo}r;i`̶1m[B!!߇tڄrCkCمFXYO2:<0|V,Q>^mTnԮ{&x4):6zy %ǩ ̊9>~K,e:.fqw%@'aeDi?'j&{&%LIٙ*uliit3"2Vdt5~ 晢̦,JVzV] 'LX1$I3&l>Y<))I;sykxOaU>A`QNpΊܕ}Pa_.Z/z9u~B f$_rЪpFeB5-piXY]R4In)lW8+Qt> %.%JF0ɛZfS6{k֖쩳[Y0g.{yy~)g(9?c~s<ͮ z ſ}۱hu>T+W1/->wk$gIRߥI]_| +qcU媗>W]y ubMڸM-[~p}gؚ=,6,z#Ma6[n{74:Vo%o-p[3sd{׎wZ\ ݥշ{K?Fްe񞪽`b}z@O?m8hpi,i8$<Քt9%?o?lsёGGxq'Ni}rkNu=}Lԙmcg>xC|/4痃.6] ryWBq5ε 񝗯]yc⍮ķZz^yWn={=]]G#ܿoEY^}Q}OxDdw7> stream x]A 0E=_&Mښ4 .P1JRIÊ SRp (9,%Fxz`F\ZW )&D()c)پTC-lv׉ZS#_F5_}|a L 3" endstream endobj 78 0 obj 151 endobj 75 0 obj << /Type /Page /Parent 76 0 R /Resources 79 0 R /Contents 77 0 R /MediaBox [0 0 1024 768] >> endobj 79 0 obj << /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 10 0 R >> >> endobj 82 0 obj << /Length 83 0 R /Filter /FlateDecode >> stream xKO0g.p}e3 X1jYX(LAIiFE,oP}Jː1+UҳyHwL"adIuXr$+Q`kSIfJ^ý,>z4=~.GU׹ո v.J29mYJ.~7-S+U10Foۡӛ7^֎S}L0 뎢fcs9˶gmTAd8m7ΒD3!ĘH ل7QrdR.4opdD7jUuGovh0ܧ> endobj 84 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 10 0 R >> /XObject << /Im8 85 0 R >> >> endobj 88 0 obj [ 89 0 R ] endobj 85 0 obj << /Length 86 0 R /Type /XObject /Subtype /Image /Width 512 /Height 288 /Interpolate true /ColorSpace 7 0 R /Intent /Perceptual /BitsPerComponent 8 /Filter /DCTDecode >> stream JFIFHHtExifMM*>F(iNHH 8Photoshop 3.08BIM8BIM%ُ B~ " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzC  C  ?_I?Ofb=[/'xy1o/p}sEq\8˼{ON};\=F4xC2=#קc˨\ij42zGw&0/zRu9<)\-ݜpaqҽ" н@/uCNWb|=r9kfKF9H}1pjJ'Ca]q4h|鎵\qۿ5O]B^w):˴ҧI\=:~S M Z\ijs-=kXhO+l(SWmjDC(zzup4t;92/Ʊ]7Rob[a=HNG^84nN\ݽZz^ڽϑxcZk w-o >,; o[0C7o]ǽr>2]H QۭD/oq/|/[7!qz)9#pV',*r8c8.T0xqwk''tgMG:]Ÿ6;xv?2 ?~iouo]Nw3"G׭s~}cZ2s'ZA_l:q_Jko>[#p?w2X{ׅx÷ho >p@= W*#p1Gbr:qv0Ct\qt9ʃ@:u֦"$6H=zc<}:4: z؜;qph݌1{;wir1㎝|v49 0x^Nv'#Ng7c7L`N\8 `x_(bNCd;#צ3ӣAǩӷ =qǾ1ӷ|*<8c@ #p1Gbr:qv0Ct\qt9ʃ@:u$6H=zc<}:4: z؜;qph݌1{;whg t:Omyqar};]&WN7s^rFn|VƓ%6:6cZږ:U,w!#n.LdHϡϯ] m$\.1u<rqt8A⢨"|=S_қ[~DPq`;\T, Ԍ=Dj!=zqJO?;q9=?YϸrH3tU"_ NN2\\wUW`C۱0z|cn!;rp>Rq1]D Q#6^bc8Ӟ^kl^Zv+=.daps}>p$uU8ReA c:^iNW9>psǩ7ұ?yG~ڙ!c8:v}NNm1%tqpj[[GAgn6p!Dy6G9E`cw}F3sDg)RƦٗhl}O8_Wɺ|gݚ/+pst>^1<چ.zְehvNy:]|ys3rj揤%G.o(IrGθJ1:=jZQ]瓏ӚCworiXP:wk~:ջ[@X ?m:c5W1\GL{ ~֯țN#!<ዐ;bQA;<i8?Ag?rGIlzxTC46uҡ n:vխ>*Bq0:oFxo`~[/yס9һ6F-0gpjjv58 tR(ߓO7nd O|:ϦI]kAXkBٮ.3ӽ~ver =HNG^84nn=񎝻4PpN׾;PĜ =99[O&:kk e68Ywvg>pkU{{FWt0pGޑZb^(m]N%-m?,.P.?&s^nc#L̺2|'?< ~t;W(/f᥌yƾ~":cd_* %##c| [7Gq&Y #3eJG-ql%5 7AQr}MZybuvo>9x2\dX!6q-%tu+0ƴIkM֒]F0\&u&c p0goklRh]r"~F~]Q_k>Ul:p;UG_2(Wt}\_lg$9ˊIZ{9e $pS?^vqt8A#2c{gW݌1{;wjtʶH}26fsO:S嗡tO̎{:gq=~=A''}EFNOQߎt4h Y݀(Ho\VӇ1.FI=sgS^>wxIyv>aM|`N1{ӯw6]5Z p3ǿ9\_/}pApsate䷯o¾}3 <=5Zk=Ο.x~; /w3bc#=zc<}:(Fhr;vxt(F% ӧ?Ԑʒh=>sֱqf CXsEqm vwϮ}r+oe =qǾ1ӷ|4;{{0pG=x uOn|?%P'kΉ_l< To෷id;>}i|+&$(F÷_2&?p5ۋۉ7Ƿ?zŲ-k=4F~\Ny>CW?اQ|</]- v>G= ,h1][zMvj箵|9?&jݦ-\{\VUj{g|9O|Y%*i}p ձoᆈV$y2IRQ_|q'3qHsx:Ѽ=Y4$ >+͕nhypOh:C%c\rq-P.ۋhyF[SҮ׏a;xPibY5oăϛ|cGznxH-t;I|.wn:׿ qxÁDpIھPėؾX#np{ǟW]_eu|c{88G{a)r{U@ Ѽ\RCz׿_X|ktx~0cx|GAֵ V><7/H 1s1AR;קn3 l`@z#|Ӳ1㎝|v5$6HGLgi1ޝqW;u?Ӯ+HK yVmn-nbDC/^-= =qǾ1ӷ|t 1Plaol:'u>#z7t0A}8>G=z㱯_իOƆ)^ 1s1AR;קn3 0z|cn.T0xeW|=Fuq\]K]Kc-HX8QlH]z.S0R=^,lcȲE{ç* d_7[˂<8zs\Ʃ7.+Pe%WDDKG,Juc?0Ig P'uXWͿusxI2ۛ%JɕW(՞2W'־$α K%UӣI˛7=Q "_W~8֧mn@ˌ4T_'γk#QWo )N4`{m3 c{Q˛z6uf1\F aוk^\"bX@w=Tw-tCoe\0x'x޲oqRNG!Zⅈȗ>bY}9sTTON=zϋ-e}p8̹}~7>L v{P182" Ilzxth8t#9zv8֫Go䓴m@8޲1㎝|v4 Ilzxtjcxvѻ!c8:vA c:^hԺy8`"8t#9zv8ѻ!c8:vA c:^hCr$`1>=HNG^84nn=񎝻5ng;v~?OS@:耎Ϧr:;qӭu'E3p[J1 >3ޱ+P_lчY?D)KD~=k%|ns^.pd>gc^+qrzU؜|y'9ǧZ DlKnSp#9|M_>#ںW<0#o1+Hac@J1eW74yO7x|O&ʞtF]s~K1chOs>mfFyn| N1kSt)%o#uQSqFInsT2 #k/ڷlFmPw{Ka_+Y-Qܝ[:5|2V21,Z}'M$'zGcR7;=;ut[>@D)TgϾGҾge[X7v׏ֵ8ǘ^3)9 0x^NEWG?GJv0Ct\qt9>Qv?5ÊGQמOnY?l9+׾OcOMwÏ|c~΀?^@9sk< {SO\ 0nk^?ӭi r-Ħ{׬5.X B1ԟ¼fXB}OZ^$s a&ӍJQGk~Oԝ/$LDz|+GVo'V[1'<ݟ+߯#i {~d3s'5_ m<ڰ:|ROΊ^>-yoyӧ?׏z }B(<~j׶'?zyO6#Nb:z\wsy$}Q\'G?ϭc)'12rwdG|~5Kb{ޞ q1qPp(>l\>fECyxG^Q"AcS^-"-;*GN5߄yzܾOU,\<O%OC8_:~]GSn:'wŻ Cm4!9=qڣC$6H=zc<}:4: z؜;qph݌1{;wir1㎝|v5h(bNCd;#צ3ӣAǩӷ =qǾ1ӷ|本zur$`1>=HNG^84sGL{uiPpN׾;PĜ Dɂ=z_y[\M| ]}YIMի(Q'9^H^0z=|Ip<%NEɝvx+Rr!v>x_͗=^ 2zKM3q#Q̕ھkN- W"T.:u95I"l>:~l_q3[D<@`Wȗ߳CXK/*n g*>Yr᧗on-cˌex?Qa0=~x?K{qgUdb 溏x_GѢ-d e|&;6eGq̤z48~2x>}"ns=i)_V??_^$X-ghRq$Ⱦ9# .8ҫά.!ܕtPvF}ьqca.=k-`eklN}:.Rr󱱌cw?zo?*ÖF?glFO8t#9zv8ѻ!c8:vA c:^j!Cr$`1>=HNG^84nn=񎝻4PpN׾;PĜ*q }8㜌Vzֺ}J|[vXz'M+B $$Z[$J#}CNO6c) ۂ_⾷"˽?x}YS)[h'-u>֦?2ەߵu:᰼x3t5j%iXʋOFǰˈN*=7Z\zج[8wa֎CGO0>1z{W~[_1P{zb&5-ݒK:HrWa5<>טc)˖&Ÿ-NQa`L߯;vO,BW¯o~wme7 ßm&L}bTWw`gaB:y^U=oOy+*j!oIL_]C΅]Jȸ·ߏdfCzv.b^qWgxw-)yUxUqvx?5=3\?'!kmH/?q7w7/y?O_֦ i㇈9#jGA^mG)GN1I<S3RļW {~tӭpGI#i|Q9~rƘ&^ vrzF|>c>C?|yǕ/Ziql!U.ZO'7is7ȋ~d~Sx?Z]ίf2cvz_W}  ֐Z$'>Wӊm%Dv|{i'-P#md2=:I=+ng8c?OzvT0xvxzlگ$jYJ/F8?Ϫ˔eSݝOE nZީ ˵7}kS]v7[u%=4]sPx펬-UT4Q)WЯ}.>όw%}2*{ߴXҮmʊ@[[#'+M~8>N>?zx57ƚڎ<1ᨎ]XFF/ĺυi^KPri.I玜i;ZFa:ZpPi7vx{Qmt@IȄNzox0>+V,HpOx5Ʊab1-r־oX.ϯzw mHa[aQXї| [_ɕAu'&_EQc]'=1޾t}KĚ3/#ẆlMlhJ6{J6y$09#?>(O!;px>~,N(>Џ&r?z9C$v9p1Gbr:q3 1^sתPpN׾;PĜ$A?#J`LN=񎝻4) O󎵬% gxfx-Cۜ#kݗRgu|_? Ƿһ!N#Yӯ_wJ<<<^S1Zj::vneoTgw8=1_S?9iOh73bsy~~ʚ>36~[HN!EOBI5dxG@ŭ2ntqzqKJS##NO_]ʢbRFd; %^-kGTԵ ̌oG?N(k+mBߵX=95-}Ecw*`_wuriK9P{>$1cwryY}?X}cX.r3GfMsLt偂{CYqndq۹ϫOxg/kt>/O𽿆'bxcsN29qf:»˘hbVG^ #tgDY[Nҿqth5仂UX܀~Z53R#д0[qw#$GnSĿ Q,kDn[1ۯ~CnjuTm]]<7^"ou=2?#-\Fmӄ}LVU9dOGg7HNV=yߌ |-qԴ{D";?u_5cZτ5O]#l~hNI]g,k'{AD$O^ YXTO[46sQW- }cX̖Q>qWt|!\ۜ`ƾith@$2ˎz`W-nXGS'i:Ʊu6݊ 8C:W>AX; J3a^*h.|^x3Y}?5g'zS|Gj>Xw7;߆ӟri|GVpR|֭˩m0G Au;lFp#Bz}IR>lJ\ҵ.\;$࿠j͌nzw« m1.{,8z5 E*WK?g⋤MBHzg8=}OXXQ&)}s_u"LpQHjƽ{F[ ︒]t 2rS6hG+9_zquO*pWo?ށo8 nbNCd;#צ3ӣAǩӷ{;"t8瞟TB;8U9ahnS19~faǙ!lIһ,:i3m3F^&h|ܸGHS =Լ#?j]W?>'[\ٚ_t2?*01Z/_>,扤(;r;7<ڥƟp8?Q^uzv8[^!' :sӿSޱA0Xu*Cr$`1>=HNG^84nn=񎝻4PpN׾;1'!FѠcԎuیR$#PeHzaq_\v$6H=zc<}:4: z؜;qpkI=1ǧoz悑&O=:p?O_Wx߉^+@dvPpl8(V~~}1Ҿo#u>3=ٖ\mxHr WǛᖌԗͣx?<#$Lq_CI#X ԭkomt+dJيo%A5K-WcMy:Űxݕnvrkϣ^+1O[߆ζtK$({aӼ=In- Dx꩗ǷS/jqy::'帆k﯅5 }+r]Rid+ҫK' R5Dҭ6)*d;/qki|b=z ď{f,C=ׇ>Iaÿs֯} }ӃZKkihUM{ظ<%|Є 1s1AR;קn3 l`@z#|Ӳ1㎝|v5Ǯ9 0x^c9zv8  {לӉ LOֈ9xҫ# ǍK]#x~0W 'ͽw )s%ҿ^:,iewQ $qҿ>4x>;Et8kkfX8 O- g?~~4y}FV_+)9ҿ2m-H?W4|={_mUc~~Cw0t #Jf4.#φ,C~krj4~p1ῇ]8F^WGq=~?|=5 ,&`Qߐ~~5|vFuT#?ʽpxPHm%*7@G̜g+zA(|>T)֓e:~}虨Wxǀ5[m"7X?ƾ)'n4vuf=_kY(q4ƒÌt *x z늱ψ/e}aݡ}AN?Z>Ws?>fyμOV^U"{<9iR=O1O%m*c_qzg?ֺNYFU7>wY%^ƴ'O%Ï@IV ?#M8o[ąJmaMqyڧkk|^Мl\ v*?.QrvH6nRܝx?Aj-"zrAXs>in7qboNq99sӴ?(2cAҧԾ/k3NUv<א$_|~f t88?Hн5Kv9|{K!c8:vA c:^j@_rHNbv϶sD!?JvBg<9c|^!-LԢW;[xɷ?vG\?]'칶#*'NWGk?mΡߢwiimOG___ %tOko-ԑK|lϭ|Vo*O2<Ξ"a߳k]F_ec19x!5VqtO-b_, 0%1_ZI" qloZ%h'8 s:+ӧ[> xcAѵo;Ph"\)cU߀^/يtӵ}bc?3 #~yѭH"D.6SZC^N]ܤ01?Zr*UhGݢ|| qhN̊'WûC3Rn2?jNͼ"O gqqOxO|5 9/!PbnO0qO{U- ]#~?_񭈾_~G=r=}<;',?<}ߋ^"~I|+)F\F+Ͷ4`qR{_şŝ@jCz0 څdnf$qA~v89S#EoTϵpұ8kRY#Lr;ߕqFGmDRagsO=HNG^855ɝ`8~5T0xǁ/ǭ?>ξlo#H_j9i8t @x29ϵ8)k8ͪX$y*FDq־9R|Q.<?.|=`$7_3ο> ?BׁMNOKcgseq }~)Aif }qkFXryOכsGٞ.iU_2wᧃ,yM_x[b˟~ƿ%`>Oc+7>X|g]_E#w<׵~>xLhUuf5hGTVQ>߆.nQ|?ߥw:On.5sn&~x7ಊmW 8\x_7, T2 Dקyq\hv{1z}=ku,h}^+Ҵ.^cri˞GjYHKvH?C i(W#H?6}z*ڏ_'B tKTfNIZk(t~Eš~y|OA\pGC^=ѼEa|Hel\+ܓ{>qp/?Cc- F/ }{u1F?XxQT啋> W&Q+r}J-'lts%ĭˌgy $_ʦ@1і@SS ~5( uF`W8⾉/_OmB$'嗡=OULhLGHcD}5&q.V%{=eJqU$#o*d( Sv* %Z(瞹+Ή:64 _}L^mᣖ]p#ytП?> ^=|A3u?乵{wq?g1`wr;ҿdxtP$_9MTFq[쌇cp1Gbr:qn?}GQeA c:^h8E Ilzxth8t#9zv8ѻ!c8:vA c:^h s S^(Do07eqc{~xOZG g!>QJ\k X/nm]"-ӭe? 9 $}u,gB[־xǙ\vOJ'>aS0Ĝ!)\bj?Pƿ 502[KXV1Xҗ,g.sRO|yO.)B\9H9$`sӷ$up,`?.E9Hǘַ PR`~p1ӟ|c~~*5Lj*T%8\随UY,P2dny$ ~<|(cqZˡx|e4mT2(K[Wu6ڼmugv}c|W"HL;z_kQm>)ET N힇?ָi^03 ;;ă9TT'j??hoitҫq/MI#ҹτZ23>^\倌1_x_돮A>]|V/#`o|7xn? [ Xd1%?Hc6c_'>g99?5Id[JNM_Wٿ |Q$㜔OӭZơ}quq׌ҹv'?-f^y%Hv2.$_CL7':vu/&t!HW$ϿOޫGbr:N r,$t(x7^C@6RrA_ VZlL4dz] cO?f|98_J/Z|^]6.+Wm)H0A<JFͮ-szW}/StFf7"ō:|Ì^E @֖oq|\dv^I?\_~4EX=!_+_O]x\eu­IG[EI   H5Q,K@q_?Z {,_wg zLōbIX$K&8Q8'Hҥ9Hs~q49CxҼV>+m8~G8s_^ bKX>\ט7 >>+ yn5P$aP>Ҽߴ١ǃOAnILe՟¼VMn}CNЀUgu?-]-Pd;pOaZ.yFzKkm=bdo<}s\]&9-8ΨsrsWƿc}~Nz|.۫ #}~Q8mA{.aIOnqǥskGrg?cg1X`ǎ5e;w?*(ۋFYrX\7N}>׏^ipàjzpxPqR#9O_ON?z=HNG^85e s~gA c:^h$PĜ=HNG^84nn=񎝻4PpN׾;9Ï'aSG1qvʿO(~m[nB Ox,Pzgc X!do?|u'J<#ǃxb7Xjs Z+m̥HsN3W5vtJ[> KTY]FT!x8\義{NӼYq {hFTXuic)!?{ğ^^E|46𘤻yFct?ho./j{4wES;W GjWԼ?.I2 qW"G>8ƟΡei.}A,[?vG :ư2?Z74?x3TƆ1 [(f'z?g/هEI{Y𕆋eZ][r׉x쑯W uq}S ΎwO\uRO?i<_][UGU.f[s90 Yk"FӣoJۡe2C oHOF _2?;d?(Aj#_&tdž9yEF =bsD;'EO ;MBnb˔?0c=& aOxf4wA(ᦒ䴞=1믗^'w|:Bg~:6Ws{v=z=h=y5 HtxDZcG82<) 4;w6rOzg=NG?½.tIu,UdSl8K84:TerCnS&kkȮD L?ֿB<WӼ;o%Hj=09#|i̿?z;L,wbps/l}?tgge;|[_dW%}9+ . -E} 7}9<{\ QNUyOֿFdXdơ,1PM(sTN4j/ x'ͻ w$ #ڿ|_2-VFmCNgqs+gm^]~/4{|$2O^1ECgCm=ߵw >Gmy~뀻8{_Nh |7?Lg汎3*'?u돮LK+ˊu?iJ LN,q+[?Ӏ9Qvuo`̱y" k2G#|؇j qa}p`_O8=kCϫ=/XZ\zuJ<ǽB3?x񝆟ﳲh\uK$V"V:wy|cGfdd[(=1)o%>Pk|Au?R}bG?-SUr:W1"is =I^zۙO9ޝj/٦fv~~qG^+(@sbϞ*|Ɯu?ҳ``u9cBRpB1hp2w'&3 {e?\uf (c>޾ư̱MR:#oNr*Y_tX.r^AǮ;u9&| 8ϰ=}/PĜ;2HU-REmo 9.}s'n-Fy].-&KZ3>gcҾ241 Kx擗KlHUEF5ޝB(C*/|ni*~eSej_CQ/7o$$le#NOO~ˋ \o?n=.qG?"=e|[cqJ;(7C<иf[y+W]WF5\,$?kxOK4|zʠvyO5;q->].#!,PxW捇#'8>Ooc n4IFk (s_ez<惤 u+[{kD$a q_f6r^ېR'T>pʞO)|`s5ӥ جTi bdS#ߏOjmA`^ nX7c+~ꞟk|=1<ќPwu?Gg}mW1OjU&xB  On<W p5D{encsJ1)eq㏉Z ^Is󿿽~l㧯LWgG%tdE-ȄsAq^625CrB$6H=zc<}:4: z؜;qph݌1{;wir1㎝|v5w-G۴/sʨ^-~!}qH_VE}AOӅf;}fOD@ZkKkgX`womd0?k9c G gǶ-pU^9oxm_̊("3WW`o,`{g>ԵMDiPk+`Ms>ciL_>(N?[oB1^a˭9,d㩯qoml67i6DvsQ*F=,< H&ۈ+;Re<6{cޖoP0T#J;ѯo ㉟T1\C+!מ|KeGi&!ojhbeO3:`q/_|z<-z!ui8QRSGR r /YH$Y?xL?wݧj+_ӹWoOGPޱNA-^` 3_E&%y̋˯8翭y\)sF[֤'ş894Lq3vj&ѯ,up͵ӑԂ0x4F-GFxX4r+Fq??k+`b{"H˚RˤO>sƟWE-mݢSc_jEw{1#ڵA&Im\st_=m- G&xӪj\H#%G˞?z/js`y;G=%/<?Q?&:q#G r>ڳ|MC@Ԥ$QpG) {oϘ3kjM_C|"ńM'Td䞝+P98ݻw5v$ҦsάxqVotr2ssWGX\\[͞U.wnKgW`,|En#kd!bsYQriVy7* h՟ۯ^ojl֚qlsn0YE's[$?gZ>?5#f1vk}_{Pzm39Oy?|;Tl+sKn^ǩǧ~yi3\^J1~zt  g$uZ5q b&uN;w^FrTGsYs|`vx(9>& [I} @!F=kU}yO2XXՕe[ko~,O좃l qjiK ?H#}$&PSj]ݷO埭|19l2~IW)F<Ǟ,NI}.9GXcMp-mB-_EwqVfR85hC?uk/ v.ˆswǷj˵rnDoiJ4wEVA7-r ܍6R~_OOWnGA \uOѼ l- ]Bcぎ޼FNF׭f-˸ rC`Osy RW?w>qӥIf-{k ݤ߸Au{=z׏$c<矯ODv'#Ng؛LbM07=I;{k5p~\c?ǧǯN=O^?kdQ}k35GK\gvO~zXBs[\\_?7ӯEïdUzV_-}9=5)}Wg#5+4B|珯⹥IrU >"i?΢|u|{4kwQW$Vm6 >7H=Ο7}C{==;uW*Q8yr{F28lP7lk0Sϡ_wgT@,Op SC=;WgT9#OrKCJ]oۯ/W <I[AgG\rJ1|.xh?7#']y=8F=>nu4LO>Z[N<+źKo2<۶A>Jb\HTվ{:Ys{Xz< JmAg(c ;qҿ_7}0&Nw}?ƿtmB0us{~|;kdO-~ex+\gyL=|[{ I 89^Irqÿk.[dOH 3h$u/:vc$}qL+&k/oC|eټ%"s :׵_=T%lk |6%G_c_W70=Lp,6#ҵ土+ kH-qK|!ůۭHqzW^56z7@-isQ͓䜑w_&^h:ӥK%BP۔ΎF8'=Os uPf\|y9Ѥ77hjֱ&>ǪF>E}Es}OpzWOƛm/7f-?Ss[̱+Wie6#z F9QT_Ϳo7l%:cy9_?hp!¨϶~\4AhZ~qȥaQ%'~upY^y^!~w+^$95W9qrx?zU<xjگ$[[{Á'^=F&S}J 1q5ng3Ēc1z}sVw z¨#~\d4~A=qEQlsI^zuY{0z|cn.T0x9Ju[iւ^9?3x<VUirajߧW0􃿿ӟjŏDg_:3i\@u>_ N\j&ĎOמ 4/@y)2y}jM$i{lpa]ÝfYdӤ`\KK Sxľ0odj 6$n*o5 ur>a!_^JώxGK" j9믠c _ͧyȶscgxUhǫnjW^_̧$OD-˿hc?%f>2A&8y|CXMc!;`u>c9r_'kv5]ϖzƺ߀~[9FI瞾P{{ r#zO JWӿO޼eDוYoAk!ii uyh9?Q_2Ikx?"4{$w+څ#TӿSt^ O$1mu,^*Rbgtco U~f0o6Ոuώ4a ={Gӵ}-i^/-ZB\޳GHAÌt ZQ,b}f |􏓾4|<tָ(A|3hƞ&#辢Ocv>'Frǔ7'P9<漻őxY}G\1]).|Aѩ^ vrϞ?rssxOX ϕ'ªgqW֖&FRc_+k+r<ג)tm\m@׌/&5maGO1ue/v'dXsH/[sĒ.#}2:{yi8T\gn8z_H7ӎCsn#e9Z|DSd.H;0=KFʳ'?|Ӷ!(#"]Co?XPZO=>_#XJREcS|sqopZGϹ?Zqꮫh7ݷ~"?5xABf%v ]k+G|t|/iG]Wy`sxqnc';.l/t,ZZnA#\狍K) /OOw024Mv$8럯q+ o ~ZTW2+Z\چnOp0sk/:GY1i q^}yU_z':?w?^wkgkWr6szL_7&6?ιT=;xYTxuH^ \Vz˿RT|ڶ–g }GC3~_Zwn mgY?q&iSm Fdܿ.̷J9=kr'u~$ïJy>)O{y|q*X0-Ӝ| |dv9Zg~ k>7^O?Sgy搞2Pz*+`F8`)Oϳ,x^G|Js!ja׹2ApOv5q9ӊ:;CO{'[-lcn*_P,Kz]ɮJG4&dʎ[*$S99+<Qh'/+nxtP9:3l}+W!zc9ꬩzis y Ν:# G*^o|COI 3k;zaygq~^xU{;G]{Jm?eY%>H;ڙ,g.dIMA:Vcݷc9D;/J>$ M+꺡)c!KYE-4UFv6ݷ?~=C_ u_j/l&)0؏ұ"1+ĜUY Q~=Sռe Uw泚Li߻z\:L$G_c==zu*).F8q1Sd脀9ʶq>@|0=}'"@}1=_,98<{Lr$`1>=HNG^85xS  !![6HηG㧃Pwÿ薐k"5\u-4HrHNd ={sO#UHBT*CoOrupN8;c=sx?ҾW៷hz?(8 lOŘS7zs1법X{K>:6o2[(G u!;3g*>_}GW+xd KK3! q~BE{vؾSv^M_ >`SIM?Ԟ$שƚ|4m2REьӯҽ\Q|<_6~.>c^~Ђx俑X׉ b_޻=8Wĥ: <ԥZQ>woHu&3ӟ~|&n. {B^\W(V 鑎I!<ฒhH2 coޢT){|%)q5i,SvHֿ2OkҾzcOWܿ~!Zqq%xjN{׍ak.&ap8?OR5x]փj0\_a[\hoM.q>ڀ?S%l^ wh#$J|e߃3b+ڴOi>|OCz]?|K=//YYhhV ob[i#9{W?d`aNx3 ;W?0Ǽ̴:,P}A??|xNX]'MhŹ!B˞p>N~&\zgnƿ+~'}y"*3CXcwr<=g'~ sOibۗ͑Dxi<¿=~__ /{SE w&Ia][z=!O+|GB{çJu+ ]ZM]]ȇD*ghSczH\~ m@_O ?>xk:ژQ,.eD,3?t W߲W{i=C^ 9(n~'?}59\W _ 'xᮮ1]3cbQd Q_eoنZ5<,YihԖɃ$翽~b>?h3}F;/>87pX%LGU^el?GW~ʗ#ÿxsTVӣzngip"VFk#¿uOIaњj}~aN3_WGoxϘo8QoG{@? ';?_Q%<xLj?'OG,m 7sz5PnyjZΛc;M̺\[?iz?a<B]fI]2[\"$#0,o;w;zS?ŲIuqqKs4d&{OM7/Mļ*_C~.+ڵN4+) dE= 5o ~.cL+qO{5XX 0#37ޯ.oMD_|6a Zw<"GZIctdRiT+ ,O pogXĚe@K#!TbT ym%|j7xcD״NѬn>ӈu-O8BR7Oe{=N) .s5rQu].W/tk}( r)R?"j@J?tߵvxJ״-N5[ehʬy`}5;X_S {N#kY?|g:[n >|3zs]@͗I3U |3 αϥiS<E 'V o!// I]sR֢[+ELH3QJdR7+7i_CNG[As>w/ ;)JgᷴEQ1^: MM;[{eTHQq誠`Z5Cg_ ]\Y>+b}6!õ|S7G]kb(~q H#f?Up韵'^:k_]kX |Jp<5uiVS/kv FP۞¾]|#~^:Ǖ%ťn_1Niucz~=/kō{>Ҽ9k fC1gW&3l)F5ך`%Dd~U ֿ9Nj5 !nEm0ξ\=1ꯇue9i2/_<>Ne2ŗR;5U|BX|s9:3g޿? f{m}ebz}q_Qc+ƅxqr|ܟ2^~SIDۤkӢж;%}}z2cp6w'8X32'x]C#E8' 0!'@?~Un/{n>Kνڱf1+ªBs>ѣ됀.F>ϭmZ7z^dj{±χICð~syJ&qEhbK)?ZV1G \^5)\39n+1Uw#ھ =#Դ#lqF? ؇}F)h S)(coƿcȯ_zq}x;Z ?үR:Ÿʌ8CYPu嵣B־Vjr_N55A:LlZ졊39H#G2f;S5~W?ɚ%:ZW5{ʯ _ds޿4|Ci AZ&g7w| xV@aU.lbo0͵OEl$s'w ?wxjD#|$qa$!όeLXB_(# iϏWP{e? '%e?rC}-_v5+'Mgͷ#V/˧+{S߶ ~+!v'$j dֿPா-YWg$..6%q@JOASO~W'_J{+J?/[/}|O{W.m cVU;[sl/ h6~?;K4'AsE 5H]+Jd8wcqtTw85":,qbz[}?߽򯴿Q?1!>pC댏?#§M?WQP-wM_$DY􇃸 s@ _ΟCNtZ-=0۫p좿0?no:Nūk =#oNhI<A? ^y>OϞa|~8I"H]0@~) кKZxIw3t5z+p*o Ejw7k-v.p<0P R29wag7Ź2[PY\[@2{W3G&U?\[za[h2({}#O^|1ÿ luTK:ue+=4miYO钻f ܒ3ɯZ؏Nod&sK*߉@v֭9; >+0I2>%jӟOc~_ |}5<0佸?5KmF~8x=: vd-fO>oY'σ7^@)OK_7OO?c2_zhO 6t+{_ο߃ 6@tq+?/kh'N}zU SG] u}_ k:$#Ө}+.` qמ] Y< 8O_9(mK6bCW>r<sߊZao#Nyu4jiN=b+*HP}~tkH)>gӒ8zק/2g:wg?i:OgJޞ-< _ˮ+ROqOGy5I6nXO_L_VwK&2(?,}9=ʫBJL81 QC'sM|sW(ھ~2[|6֝/srQqھ gm?,+O>h+{j[=/|p{/m Vn_꾿s>su$f*?^ox[.&?Iҕ^hޕܕ)YNݾ#ƞӵ 4[AXqcڼ7=mio3%{>Oeeo+}FםJ}7h >[yoO} n׋c'_ߩMX}}z4 %ՐTHd n*?Oe\kZ'赥ޏir|*[߷ҳ)q P?:Wħ6!w kox> $d4{7oU*叺eJ#:GRh|xL=j ѣo6OqOJiӴԴ|צM_5ˆ?A^ >x\->nZ>}x]̘~ZmΑ&xǚW#⹹Z ܑ#k]PD2=*Upg8Zt(GdLwPkJfɟ#>5?OJu&jW ~OGӑҿ/.1GT/_?X?<ڛֿ5<@~ľsq3,ȭCqYZ'g>AZǽ~~~ȟPOמ4< j:΍h>4vi?Űۚ*-/Nq46I܈=y{*կk wQo/6:~3r2gnƿZnxX_T^]q?rY(@$?gq_px3C"]ymFdžkxZP|eq5/Ʊ+fMx*<+M+^a坽HncYc=za޺:Y|W?doiy..4)<"kn8A,i ~P8ԈΖ#{uƯio~ʾ?c}DgKǮ|Ư''?‹}2>{kzuu +YIoF: y/'t+=5^}nc}_G@ Mm4__ia?~Z+ xUVPo3s[#-vO;y}ԪD`B3߹Xdr+^9t`Aq*κJA?"/-?߉&,,J9 0Vgi5+ן #`{;u$QpT_?WwKi7xO)EUÏ*WXLWǨO?b<O̚y'>hV[~_.$QGucW@!?œgD/Ͽ"(?~%Zzg+_3I'k_Dd LpiOv5[\o,Jf൷+ {!^98/@eBGOC yde߃wF57O;Gi?SDO{}A?,(+1Kzug=u QM~ǧҿ,?e=gtQ|G9e%H)2vQm^YCjȇ*+Z0 d\$qޟ/'t9?i.$c+㷹#k:vG~+m a6|8$םͣOH[:]8.YsH e<|Zp7=;;ۋc#R=F9vAJ? WR.n-`f~ZQ o-(Kg}X?{G>MF a*͙RvgJUb}g{6b #o jX:%2`89:qy&Xv:Ξ?C~J #фfHř]c8;FμZQQF.'_S\Xac0 s]Go_-CvP>SߏUz|eoq;TӧjӶo;5O+oc?{˘i.5_2%/>l}GGӵbW7 b_zcREXYM5q'Ȏq׭X kC! 'ӟ,z߻5>S)y猌k mI"ݬ9ߗx?#T%4ff?bk~{y B1g+8I&Je'!/+C372(^~Wu 挏;5e(~LJu&jbןPwŏ[Y_[{\\nFo¿F?䟱0>)Y#W|au' HL~y7W} )߂k)O/i!㏅:k/=4FRdF!ڿ?-LsD>x"q~_R؆Ml!%`tOkM?atf.sI3w/w5A_(Kg~,7}|=j:.OfheTG~);\ ??-vt56xkᏅK֕ U uƿ_gF7_5L֞kK+~ls<)w7;W}WE60< T>+7:_B;[6v0ݘmk_z7.Y.?O:߉zeҼOsaq#mP(' 92xTx) (JK-F<--)Hz7.Y.?+$SǟB[:m#Vx{<KP*?O*ӓP9 8Hff?W_Y~~о4MSYF"G⿨3y?WsR#:Yȍ+!-}*i¯Ki)lW*b}5/%:j_.1?ǯťm|߳ѓ=n1~޴@7[M#)x~Y-ߧm$NQ_t095Om+ KWy5tؾmuo 9LQn?hWֽxo4< b ww$FϺwgSV8.uJEM#¿+?c(٧^ѼQlWFAX.|CjzP)h5OZ~Es=][w1ȹ);rGc8}Wmx?ioxֶK4zsn#VR3|"T^8:g}q@ Nxn;{_~/o5AN{t-3$A|HUZ'F+WSOsL?"~?s-oZThĐHRUG^;0=}xkǚxn<7jq.qIes,|}+~[#ZuI z 88_|7%vd2,6 BYb1ܮ0`w_X>0|$i6hy2O &n{~5'%j?/_kZ_5o18c|̳`#6/;`Ӿ%iLbCc$7!F,^05<ZL5]/[C%nð/?ͫfKH~o^ݫW7o|~Nw[Te#mE I/ 3͹7 /=nJRwj, ?֧thӜ׃M>4^ϭyB~"_NjB1v:̀GA z}8pm=o.*(-+w#cz$u?V>`pq[PӶzzV#mn)eA! uǭ~音5w(..mỊ̇:n~M3quHPqϽ}y⿋x: OiqhŰEpFONO_񬫮otK:GRDa0yɯ4x]!wMFFA⎅OO;\\G_~i(<%njrrFq{&H5'FS¿qۮ PVxl`ݑ\5yn|3[k_le`F;G;?44N<. u9Q+ޝ{hHʛc $1<_uٯ5R*}gbBϯO >\-ۈv#$|rc_Oxkmf ]}h/J0F~j#ѼCc{qo5ԣ\ҵbǟ'LYF%P>U_ GڢJ,%:8t^HȲs\1^Ho~K)EQX W{\D#r* ~\|٪yK$Xl*zk5[-n K-DOR#_*Yj殯LWVQhTBJ\giمUm[Jyy5=-j7()aH,3{)m?J+y|sF!=o~ۘ{X:nve޼C.ck0 j-ɈY#̅|~mQOGc5ZDx-ԭSΖm2FB7{W_i iVrU[)1A+n~#{zoep֒:6m44vM.X2J }b+Wоկ[: ޵Ww58gy"|j#7wDz|l\1' t_qx{Hn4bi2BLnFC珸x]OMN%pC@j9ʢ+2@v߯jA J}(<c#?ҭ ={S oc?Iy'?QZ]HRos'?h&.Ӂӯ@bxz~P#ӓw 8\9=x?NMAc9z>V Ǐ;ֶTӯ$u1ր3cpyyx$.3};}:T8L~4Wlcc1ӿ4O^~ߊ,9xǧziʍ ?t==hH,sx[Xm<,<vOo"1J>4ߊwqq?@38Cm_8#oNwSawe zgALvuXxɦ8,v ulj2{h=1( ߰c Gc9'c*=kд({`bp~ƀ,}":玵j66?ӯֽ t6cq1^}|x>r&pm$}hE2#޻oѽޕ_)[ӿ"+Tj':͆n#6n1N} /܏pO8OOEI{Xp}rgg9=+Oጮ*;UҼ5:\v>ۿ_e? }kG&ݭt#MfH +׸:],,jBT @<J~Ο>;qbv@w<+..J;`||t~_l~xQ]J1)`[:ct>i%j/6້m%d[ślj'ӥ;ۇ+9 LfI 0x,\H^Eʨqw>{ {kAa}']=}@_oCz_kC@#<> endobj 76 0 obj << /Type /Pages /Parent 90 0 R /Count 2 /Kids [ 75 0 R 81 0 R ] >> endobj 90 0 obj << /Type /Pages /MediaBox [0 0 1024 768] /Count 10 /Kids [ 3 0 R 76 0 R ] >> endobj 91 0 obj << /Type /Catalog /Pages 90 0 R /Version /1.4 >> endobj 15 0 obj [ 2 0 R /XYZ 0 768 0 ] endobj 37 0 obj [ 31 0 R /XYZ 0 768 0 ] endobj 28 0 obj [ 22 0 R /XYZ 0 768 0 ] endobj 51 0 obj [ 47 0 R /XYZ 0 768 0 ] endobj 56 0 obj [ 52 0 R /XYZ 0 768 0 ] endobj 46 0 obj [ 40 0 R /XYZ 0 768 0 ] endobj 63 0 obj [ 57 0 R /XYZ 0 768 0 ] endobj 80 0 obj [ 75 0 R /XYZ 0 768 0 ] endobj 87 0 obj [ 81 0 R /XYZ 0 768 0 ] endobj 70 0 obj [ 64 0 R /XYZ 0 768 0 ] endobj 89 0 obj << /A 92 0 R /Border [ 0 0 0 ] /Type /Annot /Subtype /Link /Rect [509.3125 138.7812 718.75 190.7812] >> endobj 92 0 obj << /Type /Action /S /URI /URI 93 0 R >> endobj 93 0 obj (http://irc.perl.org) endobj 72 0 obj << /A 94 0 R /Border [ 0 0 0 ] /Type /Annot /Subtype /Link /Rect [250.4688 599.6562 963.9688 634.6562] >> endobj 94 0 obj << /Type /Action /S /URI /URI 95 0 R >> endobj 95 0 obj (https://github.com/jhthorsen/swagger2.git) endobj 10 0 obj << /Type /Font /Subtype /TrueType /BaseFont /JDTSSV+Helvetica-Light /FontDescriptor 96 0 R /Encoding /MacRomanEncoding /FirstChar 32 /LastChar 165 /Widths [ 278 0 0 0 0 0 0 0 0 0 0 0 278 0 278 278 0 0 556 0 0 0 0 0 0 0 278 0 660 0 660 500 800 0 667 722 722 0 0 0 722 0 500 667 0 833 722 778 611 0 0 611 556 0 611 889 0 0 0 0 0 0 0 0 0 556 611 556 611 556 0 611 556 222 222 500 222 833 556 556 611 0 333 500 278 556 500 722 0 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 ] >> endobj 96 0 obj << /Type /FontDescriptor /FontName /JDTSSV+Helvetica-Light /Flags 32 /FontBBox [-453 -355 1345 1206] /ItalicAngle 0 /Ascent 770 /Descent -230 /CapHeight 718 /StemV 68 /XHeight 524 /StemH 58 /AvgWidth 597 /MaxWidth 1445 /FontFile2 97 0 R >> endobj 97 0 obj << /Length 98 0 R /Length1 11088 /Filter /FlateDecode >> stream xZyp#Wu%eɲ:,ɒlYlcx{fdA2dBp G&*R`H#Y8lB`?@QKK֌'U?+U_~}~*kcO]8qݿ0}XsLؙg/`LrHsϭ8-`?x1`;waAXŻ9%oVgDZm'.bO4{[Y?r|s $MF13X g^fcT3ct\9]%74e&*4+0Ҭ ҫOcddHE` у=+*6mgXez ׁ!H>"ka-6?Y`ޫ[7\N1tDhburwuuyeפ܉jlj+ :[Z>\]Y8j+؋]-\ͺUKUzbw]/.,XWVp.)$&H2 6M(Ke:[|\Z/]l = -Q;SuCΕ*]ZnCZW׶AV? rC]қ 7BfA!fy#56cIj OpGb!lQ6Kb=[wPUas8Wp S,1 wB8'c/4"*YC3mij:6I*K6%M}Po BpFU~h5!`ߊz;Fd 1$n9Nü,(n"HH@Go%đCa)#ğzyZs!#MsM/7ǛdZZmp"msm?jiN__ҿ1L >Úx&!<|@ x@Il06Y:6:6\EUZhQX"w!0؁ ,RZ-h%SF]&sA~?_{?^ȕ++W緪wx ?Ę3`_a˰oTM&z(=FcZ]G7JfL;cY 4Ɠ'k%㥳i˙eS%TpK"^Z ^S:yj$*=5&'C7Zd~WbGG i@:%"Q6eJBz)XzNҹ-ϕ4L\zBׄx0]9ҕXcZ=Ռ;w{ a98LSXgnmH1E<So#DXtlLAFjh^{}G+M(:XԞX X7*owM|7qq9 dogPnԎaێ#8l?J|vZepqa!GC6 CE__t7xlV0אHQݸ]5 Je[t@en Z!%4|DޟJ/|jT w{kHlt0u>GXhA}M6ZyzĖ}vlA t0E#0&1!黎 z[}uU^O\*tA=Wz]Jϝ<=P…-f'$bg|b ?ΩD3>6Y\\;wf;&#wޡd,AՓA ]" mL-g.vF`(**҉h}SE&@;Q!QkP>kf6\iq$ UΞ٥>̞1S^GF7W+{RHU”Dip]1vqPGI\Uf٘FI6zPW!zxv+O>CZ?#76a3C$4%$ad%w,Lln`:$ebRN$`b9e#3akaм'VP@Q?HGkD݅nG!.$\x{xW{-վs/y_<н'y  #|?Bjւ+Zz^TvIVVm%EULiث8w5gk_J z6:?I,S9U7 HE}ryp"rt "k4'bz?.T yam#1-iAL3!!6 [Re咐F]Xpric9ShC-4l`4zᥥDj?y4}_e|8|b죯gFgq 66Z^[@%D<*Gz }zt2יDыv~s+; p{;'ʍ&)5uGܩ?Trowĺpݕ;k/܅xu#Y6IQ>ME͎G2d,"S%Im:TNET89FG}#NJ#GJ@ٓ1h! sr^p o`_Aъ3.6"6X '`^'#A̒{E(U,xbZ(yrœ \g3b٫TLfkBs0T9\pb/lUUcC7<ٗ #*_a6H:{U8Y&rEd]BIsí~O6ڏ&}BhR > tJlFas[>brN Zb!Gq4[n.z"1>Ű07`,Ex[Q=!BjsPQP70'b z늍E]0&Jwػ>\pGmT]ǞMڷ_IgONOG=AzYbu+*HzWdEQ h`Ef`k[\1>1"cr77U:2+ GO U\?SI;"ӧ : a?lOH †-u0|ZﱡVlşCpMcpJ ahɆN$x,ے2v8/wW‰j,ؓ@d,U, T6\qV{&6?Rgx< EPN(~`L߻/:I@ h&ըԦUbo Έ,p,z'x90ܥ4>U(~#`/؟oQ%(4Lcs!0 1%.PzF:\P\7O:@[Wq".q!_"qAMXy-*`ZJ7/`ڕ/78z5!:e-3;/L}~T-9>ezHPc$`)W[vsI=6P*GOh8ɛjs-:PJɅ(MrZ )D-;k~r2A1N}&]4{tjD_cU?9it̶3F85Ó4Ӡ/HDkВFB.F] ƴQ,FZS\, ڭ7wO@0M8 Gr4΅CO吟Iu6draR} x&nUZ>թ#uxJ4 KUp'sJ甊荈WfҜ2֙*Z/a-VfYS죢-+S'XDyHY3RIiCM0P(Q ґ>+CE%k@167N|KŘF=F޷%Xq ndCi߀p>;i-&&s gI`*?/:۽If%tȱQ8^4T}C,؅lk)FP|wBR}lz_[}yl#CiiSZX6_I;R=CQo C?4+fѺWwi2y9+@7*U͉kX!txPg3/Eɥ˩K?]u' C3oi-+/3bkbzxb1kjOMjz:\ Ut[)zvF"*t5㺬fQy*?ß.ۜ'35K{!+Sz؛gfWFtؽ"tf-X+*~ DŽcv:hI(}5dF@4y%^ M}s[oTGԹ?LBY-d21%:M0P'0`nsY:>CoG?eZj5Ro L$0Ux~'/;0WRG 8#E<?bMvK}IDq7@ w^* H}q/ްαykY?'; ؇ćҪ[=XZ:ZյN=-/ endstream endobj 98 0 obj 5979 endobj 68 0 obj << /Type /Font /Subtype /TrueType /BaseFont /GHKWZL+Courier /FontDescriptor 99 0 R /Encoding /MacRomanEncoding /FirstChar 32 /LastChar 119 /Widths [ 600 0 0 0 600 0 0 0 0 0 0 0 0 0 600 600 600 0 600 600 0 0 0 0 0 0 600 0 0 600 0 0 600 600 600 0 0 600 0 600 0 0 0 0 600 0 0 600 600 0 600 600 0 600 0 600 0 0 0 0 600 0 0 600 0 600 600 600 600 600 0 600 600 600 600 0 600 600 600 600 600 600 600 600 600 600 0 600 ] >> endobj 99 0 obj << /Type /FontDescriptor /FontName /GHKWZL+Courier /Flags 32 /FontBBox [-655 -409 764 1089] /ItalicAngle 0 /Ascent 754 /Descent -246 /CapHeight 595 /StemV 76 /XHeight 462 /StemH 67 /MaxWidth 823 /FontFile2 100 0 R >> endobj 100 0 obj << /Length 101 0 R /Length1 17016 /Filter /FlateDecode >> stream x{cTս9Y>̒ bd5 $yH0REJQM JҺ`Vm<Va3 y|~Ͻ{9iu\RD&"4cy,$[W9+ڝzw?z};n\2:MHٝn^ѐJoU%/eN_g,}{#ԝ7^<7;~x7/eY{>KnO8hIȈ@$E4(Ky?|i*sT=uf_0~tD1]"r>u2N\~hCp7m :")D:di-r 9t(oդ-Ud+J^ۓ -qR("0BI/;}sN"6j%WDZH-dE51H5VIЖm##k,/dI ҿ?%aO,n<'r?g|"?x{GY;E[!o" ^;=#=KJ>)^~55H&oa 9zVɛ RdN䗼Zۥ_zDN"yLǬY_29NHnǬ~)K"ܺ;I//^,~}a"  GD?~ GD}ܚX"MF>g_t/C$OySOy*OH3'L gee?8)"ylG"G<{@b֢g o32! id] !~s%+<> ,{yϏ9e4qY6OE_ E^!j#2^XY$+yoO 5VR^",IzXYD2, !dHn$C#38ocҍom#-|t߅9`LFYY̙]-C^+:|7dfnޙ)þiZniSéo 56-"v=;TkW&DNyL&{[d/2a Yy(.FIn>w $W??"Wg`="z>OOkyZӡq 19$&H*\|t 1r- Q% _{󊟍j Ioe3y)|7DCc*lH6+mk,s f&B 5kgX"Z!X* R2bhzr,[(3banOE ȸ`el4tCd]!MTNH)|"#@LJPAB>J>#Kd3]O_mt=} .)4xm!O?Ig@d8=+st8vRI0Bl8=K@7=M1zqx_^27m;s`^o~L{bs<-l;o ÷ghiΗэiGjDfntcL:EXtD9ؘS}-F@ 0 Poc|{l,Zh| =6Db{n߆L냟BHNNR:<!ehCv:y)_%5!uHWx+KdBZT }eE wN @HA|Mt$#T o 1%~(͗Ҳ[QH+ˋ罓O; Z Y]UUOuNfwڇtuҿgh3_*͓RS*O"r ; >Ιw:Ksi\$һL9UQoQf\N`jְT}؊D<y 'Zl/0\ O[suI*}=ҝ}#t V.[HL:Jb`\|^ 7Oa*k ・{8u "DQF-}n?Ǐ:w;~Ch%ّ9Dz|1?ad]jWRttm!_b7*CJcz cGG-[wvi**JϚw*)ɏYKeX"+S} :}&hLWZI{o0Bz >>=kSre1ͯxfBg1{2WR/ifUm)rh/5Z+阇*uý.+>ѕ9vUHY/ G>(& H q?GmG RlwrL%%ū[`lIl>TE`]]EOz$W.1;1bHY%!!6;͂9Ϟhht!N=9ųܛ"`olCZA㢰|w'}qh>oaLv&Z1w;Oݷh*L5Ro [ 3;#NߔhBR>SNu9^̀©Kg-yt4OBBw *!XURAR+VN9Q{q++08uU_^#\1,~|>@>*MM 'S*6Xc%Ϥ?Ɗ=BB#-j4xvSIfFslxV3u@:Mk[~nJ{z!*xJBM9k=*7ɕjյ IJ6n&̉~11MoG̷ڋ\R?+dxJ6OfЗ[i''[Rfa ţO1MTuqXE`w8]2}eh4>}"AbiS2KF0̠F O`'zD(Fl\\!SiuZ2ez:i..`*@$&,jRJ Z6̢!5WSWf5HSfG+"h]ّ;B~GOJ;'"-ĒdEP犿XGfҥBO҃+ŕG6VY'9JQmȯΧ VN_*4VHvIsBc= IZ_@Y&!$~rGxwv&Dv&Dnz'-19q|uf\7{ޠM\y|r?p[V3@HxFOM ".àΫUoHѯc45MݝPtU Z |R3HZ_h nW$el+ٝj]ʭ$SAL瀬z K3hExEvu4: D(?QؘY-1/2!j.ZQ4ۼd.zF^W?n|P ]Nؔy:\dF zUcgf"4[S33 wW7ş?{yYySJDC4CU%UЮȗ.%댕j}.B.T eLHBDU*)۝7J{=֞dk P[}UQMjrT$5Ok4kTJ}t.*~I|uq}SsÕ&̷a]5+8]~fVb1t Rй%)]S2?S<⼅HւdR*,3v]Ww["IFOZگ҇cYJ6bK@8sk&F7d ?^ܽc^od]w5z"ZQ4d^~ 7e޻@@kALKE DmWApW5E4J]NQQ'PUD E83*4* ܴ䮁VZy﫿eޥ=_?=O?LOgtN5BJGJc2MJkL RQRۘץޙBBqbtjɤS)Sy0@TV HsհH[akˣ\t_.pʱw<Ø2&[3fZoz/yI/_޻ :};+bg]k:ה"?OMe -a^rEY= ֗ȋ`##䨫;fVW+%0& Ru{TD*dEAk`L"UP=I&l|@H=r4[%䈗1av32ބ'N4B߱apmf,w6G=g#&t4{54q/MkuF,Esc9)rͲNUКy%^hM} $EN~[u[;?LŨ=5GG4rkAwźs(KmECe Í&mUm5 u MUUuꍺ{S_XؘUZ[bs'C!ܪ 2Fam=wkjZ^YwZ &e91r:R Cb/R_ZXyd͹~˻\|y;ꖊ*[q+W>_x2ObxpJ8f_9Xo{6ci|O)lHV>{40$+5hn1 mv}Vs^&+prVtW#ހq[Lu@@2R8THJ+ʃ J&,@ G̼my̫mkzxD]_*ZyEPkU#?{}⳿?7I niV3ZumgOSnn&|>Sg%v/^E~نk s -‰p6av~ǹSN)Y >h;oQ?ZcD3b͠g" f70ȕ0ֆgDĒ8 3?b?mXy40nBT}6՝El2{@v7+Xt!GX@MW|l9`x45.6Y[mqS*~L}Pլ,։?} !_5]q[ k/,CNO|y'p|BptwPb8.8-%9+9>-e[.$fi-[oB;w"qcxWeVmP Z앏 K#F 'E q:}!6skb6)>YZDe;*ƨ56ߓC F\jü,abxlh=@h#?]<*#VЬTY |Qrd!EOJpG@NRh|ĸ ^Q @A$(zc"_~p D B~ 5=YȲ s`уX=! &,՗  ܙ(!9BيMSBnꈣ)X^;"24o6׳2:ܽ$368FLlZUy,3_&q=/6|DdznFQEDZ yR MG Bf](f{n3^}e [ᓘlߵ"OBrR>-\S1P&C_,4ԳĿ9I/[-Z\Bo;$}8k!퀤9R A3\F]cA g\&uT%93|:]Ҩh,h5EKLLWW۴Sө;l:\myAf (.=zOv ?|/oىG9ym3>χRU@FZ {+06]e]`W=\e*ԠF Ck t jЉ t"@Ye`y#@%v%ymQbqM}8:x 70e8G3#P87xs@rYѻ#|?/,~`LU]c,G(11_O߼1͙1cf;;DLO?8S 1PSg咎d+e,YF8`72*cT9:ҦY($vֆx)8%ӽ<.EeZ0GGpD3k⭁`(\x m^ۦܐ }4D vm8N%4_ e̫Ĝ5`7n\\U.N e  4?Fu]t+ 3,؇X΀[~\F8u=(π}ٳ&qk|uQxל!| .une+NڙC5IjpFs T7L3{y(H&W*?;Z?~nCc2zcKԾa>}{]>446 yKq|1K},|Ւ3 #X 7 nva%p\Q8T@M%%*qZOcBvY'*1 \J-D}FP3EIR!ag<8a~[V ;zPNzG"o%,RJN.!)tzG8az 1bȚ~Ä@V+rޠya_O FYoMA0 ]VBÛ(ioƇӛpp{$.>M'%LCP|Nᢎ51+044bbՐF‚ M1^V,d|IɠS@#bVl~2v\#nY~낹zXK.@7<Ghj ˟@p` ` p 8K= 4Zmv=-]C.@7<"/h~RkeAu1KW TO 7 T=>vPyAI,*7p~ endstream endobj 101 0 obj 11300 endobj 102 0 obj (mojo-swagger) endobj 103 0 obj (Mac OS X 10.10.5 Quartz PDFContext) endobj 104 0 obj (Keynote) endobj 105 0 obj (D:20150903101502Z00'00') endobj 1 0 obj << /Title 102 0 R /Producer 103 0 R /Creator 104 0 R /CreationDate 105 0 R /ModDate 105 0 R >> endobj xref 0 106 0000000000 65535 f 0000563661 00000 n 0000000370 00000 n 0000543322 00000 n 0000000022 00000 n 0000000351 00000 n 0000000475 00000 n 0000108300 00000 n 0000073478 00000 n 0000102905 00000 n 0000544537 00000 n 0000000647 00000 n 0000069100 00000 n 0000069122 00000 n 0000073457 00000 n 0000543686 00000 n 0000102926 00000 n 0000104576 00000 n 0000104597 00000 n 0000105544 00000 n 0000105564 00000 n 0000108279 00000 n 0000108635 00000 n 0000108336 00000 n 0000108615 00000 n 0000108743 00000 n 0000108893 00000 n 0000167851 00000 n 0000543765 00000 n 0000167873 00000 n 0000221719 00000 n 0000222018 00000 n 0000221741 00000 n 0000221998 00000 n 0000222126 00000 n 0000222276 00000 n 0000395653 00000 n 0000543725 00000 n 0000395676 00000 n 0000398165 00000 n 0000398478 00000 n 0000398186 00000 n 0000398458 00000 n 0000398586 00000 n 0000398736 00000 n 0000422728 00000 n 0000543885 00000 n 0000423212 00000 n 0000422750 00000 n 0000423192 00000 n 0000423320 00000 n 0000543805 00000 n 0000423880 00000 n 0000423419 00000 n 0000423860 00000 n 0000423988 00000 n 0000543845 00000 n 0000424368 00000 n 0000424087 00000 n 0000424348 00000 n 0000424476 00000 n 0000424626 00000 n 0000484767 00000 n 0000543925 00000 n 0000485489 00000 n 0000484789 00000 n 0000485469 00000 n 0000485612 00000 n 0000551424 00000 n 0000489192 00000 n 0000544045 00000 n 0000485723 00000 n 0000544299 00000 n 0000485750 00000 n 0000489171 00000 n 0000489476 00000 n 0000543445 00000 n 0000489229 00000 n 0000489456 00000 n 0000489585 00000 n 0000543965 00000 n 0000490170 00000 n 0000489684 00000 n 0000490150 00000 n 0000490294 00000 n 0000490471 00000 n 0000543300 00000 n 0000544005 00000 n 0000490444 00000 n 0000544085 00000 n 0000543528 00000 n 0000543621 00000 n 0000544205 00000 n 0000544261 00000 n 0000544421 00000 n 0000544477 00000 n 0000545077 00000 n 0000545333 00000 n 0000551403 00000 n 0000551856 00000 n 0000552089 00000 n 0000563482 00000 n 0000563505 00000 n 0000563537 00000 n 0000563591 00000 n 0000563618 00000 n trailer << /Size 106 /Root 91 0 R /Info 1 0 R /ID [ ] >> startxref 563771 %%EOF Swagger2-0.73/t/blog/api.json000644 000765 000024 00000006412 12656403247 017141 0ustar00jhthorsenstaff000000 000000 { "swagger": "2.0", "info": { "title": "Blog", "description": "Blog example", "version": "0.63" }, "consumes": [ "application/json" ], "produces": [ "application/json" ], "host": "localhost", "schemes": [ "http" ], "basePath": "/api", "paths": { "/posts": { "get": { "operationId": "listPosts", "parameters": [], "responses": { "200": { "description": "Success", "schema": { "type": "array", "items": { "$ref": "#/definitions/Entry" } } }, "default": { "description": "Error.", "schema": { "$ref": "http://git.io/vcKD4#" } } } }, "post": { "operationId": "storePost", "parameters": [ { "$ref": "#/parameters/entry" } ], "responses": { "200": { "description": "Success", "schema": { "$ref": "#/definitions/Entry" } }, "default": { "description": "Error.", "schema": { "$ref": "http://git.io/vcKD4#" } } } } }, "/posts/{id}": { "get": { "operationId": "showPost", "parameters": [ { "$ref": "#/parameters/entry_id" } ], "responses": { "200": { "description": "Success", "schema": { "$ref": "#/definitions/Entry" } }, "default": { "description": "Error.", "schema": { "$ref": "https://raw.githubusercontent.com/jhthorsen/swagger2/master/lib/Swagger2/error.json" } } } }, "put": { "operationId": "updatePost", "parameters": [ { "$ref": "#/parameters/entry_id" }, { "$ref": "#/parameters/entry" } ], "responses": { "200": { "description": "Success", "schema": { "$ref": "#/definitions/Void" } }, "default": { "description": "Error.", "schema": { "$ref": "https://raw.githubusercontent.com/jhthorsen/swagger2/master/lib/Swagger2/error.json" } } } }, "delete": { "operationId": "removePost", "parameters": [ { "$ref": "#/parameters/entry_id" } ], "responses": { "200": { "description": "Success", "schema": { "$ref": "#/definitions/Void" } }, "default": { "description": "Error.", "schema": { "$ref": "https://raw.githubusercontent.com/jhthorsen/swagger2/master/lib/Swagger2/error.json" } } } } } }, "parameters": { "entry": { "name": "entry", "in": "body", "required": true, "schema": { "$ref": "#/definitions/Entry" }, "description": "A blog post" }, "entry_id": { "name": "id", "in": "path", "required": true, "type": "integer", "description": "A blog id" } }, "definitions": { "Entry": { "required": [ "body", "title" ], "properties": { "id": { "type": "integer" }, "body": { "type": "string" }, "title": { "type": "string" } } }, "Void": { "properties": {} } } } Swagger2-0.73/t/blog/blog.conf000644 000765 000024 00000000076 12656403247 017267 0ustar00jhthorsenstaff000000 000000 {pg => 'postgresql://postgres@/test', secrets => ['s3cret']}; Swagger2-0.73/t/blog/lib/000755 000765 000024 00000000000 12660346320 016231 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/blog/migrations/000755 000765 000024 00000000000 12660346320 017637 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/blog/script/000755 000765 000024 00000000000 12660346320 016767 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/blog/templates/000755 000765 000024 00000000000 12660346320 017461 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/blog/templates/layouts/000755 000765 000024 00000000000 12660346320 021161 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/blog/templates/post/000755 000765 000024 00000000000 12660346320 020446 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/blog/templates/post/_form.html.ep000644 000765 000024 00000000346 12656403247 023053 0ustar00jhthorsenstaff000000 000000 %= form_for $target => begin %= label_for title => 'Title'
%= text_field title => $post->{title}
%= label_for body => 'Body'
%= text_area body => $post->{body}
%= submit_button $caption % end Swagger2-0.73/t/blog/templates/post/create.html.ep000644 000765 000024 00000000176 12656403247 023215 0ustar00jhthorsenstaff000000 000000 % layout 'blog', title => 'New post';

New post

%= include 'posts/_form', caption => 'Create', target => 'store_post' Swagger2-0.73/t/blog/templates/post/edit.html.ep000644 000765 000024 00000000333 12656403247 022672 0ustar00jhthorsenstaff000000 000000 % layout 'blog', title => 'Edit post';

Edit post

%= include 'posts/_form', caption => 'Update', target => 'update_post' %= form_for remove_post => {id => $post->{id}} => begin %= submit_button 'Remove' % end Swagger2-0.73/t/blog/templates/post/list.html.ep000644 000765 000024 00000000331 12656403247 022716 0ustar00jhthorsenstaff000000 000000 % layout 'blog', title => 'Blog'; % for my $post (@$posts) {

<%= link_to $post->{title} => show_post => {id => $post->{id}} %>

%= $post->{body}

% } %= link_to 'New post' => 'create_post' Swagger2-0.73/t/blog/templates/post/show.html.ep000644 000765 000024 00000000233 12656403247 022724 0ustar00jhthorsenstaff000000 000000 % layout 'blog', title => $post->{title};

<%= $post->{title} %>

<%= $post->{body} %>

%= link_to 'Edit' => edit_post => {id => $post->{id}} Swagger2-0.73/t/blog/templates/layouts/blog.html.ep000644 000765 000024 00000000724 12656403247 023407 0ustar00jhthorsenstaff000000 000000 <%= title %>

<%= link_to 'Blog' => 'posts' %>

%= content Swagger2-0.73/t/blog/script/blog000755 000765 000024 00000000270 12656403247 017646 0ustar00jhthorsenstaff000000 000000 #!/usr/bin/env perl use strict; use warnings; use lib 'lib'; # Start command line interface for application require Mojolicious::Commands; Mojolicious::Commands->start_app('Blog'); Swagger2-0.73/t/blog/migrations/blog.sql000644 000765 000024 00000000214 12656403247 021307 0ustar00jhthorsenstaff000000 000000 -- 1 up create table if not exists posts ( id serial primary key, title text, body text ); -- 1 down drop table if exists posts; Swagger2-0.73/t/blog/lib/Blog/000755 000765 000024 00000000000 12660346320 017114 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/blog/lib/Blog.pm000644 000765 000024 00000003632 12656403247 017465 0ustar00jhthorsenstaff000000 000000 package Blog; use Mojo::Base 'Mojolicious'; use Blog::Model::Posts; use Mojo::Pg; $ENV{BLOG_PG_URL} ||= 'postgresql://postgres@/test'; sub startup { my $self = shift; # Configuration $self->secrets([split /:/, $ENV{BLOG_SECRETS} || 'super:s3cret']); # Model $self->helper(pg => sub { state $pg = Mojo::Pg->new($ENV{BLOG_PG_URL}) }); $self->helper(posts => sub { state $posts = Blog::Model::Posts->new(pg => shift->pg) }); # Migrate to latest version if necessary my $path = $self->home->rel_file('migrations/blog.sql'); $self->pg->migrations->name('blog')->from_file($path)->migrate; # Swagger API endpoints # /api * api # +/posts POST "store" # +/posts GET "list" # +/posts/(:id) PUT "update" # +/posts/(:id) DELETE "remove" # +/posts/(:id) GET "show" $self->plugin(swagger2 => {url => $self->home->rel_file('api.json')}); # Regular web pages # / GET # /posts GET posts # /posts/create GET "create_post" # /posts POST "store_post" # /posts/:id GET "show_post" # /posts/:id/edit GET "edit_post" # /posts/:id PUT "update_post" # /posts/:id DELETE "remove_post" my $r = $self->routes; $r->get('/' => sub { shift->redirect_to('posts') }); $r->get('/posts')->to('post#list'); $r->get('/posts/create')->to('post#create')->name('create_post'); $r->post('/posts')->to('post#store')->name('store_post'); $r->get('/posts/:id')->to('post#show')->name('show_post'); $r->get('/posts/:id/edit')->to('post#edit')->name('edit_post'); $r->put('/posts/:id')->to('post#update')->name('update_post'); $r->delete('/posts/:id')->to('post#remove')->name('remove_post'); require Swagger2::Editor; my $editor = Swagger2::Editor->new(specification_file => $self->home->rel_file('api.json')); $r->route('/editor')->detour(app => $editor); } 1; Swagger2-0.73/t/blog/lib/Blog/Controller/000755 000765 000024 00000000000 12660346320 021237 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/blog/lib/Blog/Model/000755 000765 000024 00000000000 12660346320 020154 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/t/blog/lib/Blog/Model/Posts.pm000644 000765 000024 00000001277 12656403247 021640 0ustar00jhthorsenstaff000000 000000 package Blog::Model::Posts; use Mojo::Base -base; has 'pg'; sub add { my ($self, $post) = @_; my $sql = 'insert into posts (title, body) values (?, ?) returning id'; return $self->pg->db->query($sql, $post->{title}, $post->{body})->hash->{id}; } sub all { shift->pg->db->query('select * from posts')->hashes->to_array } sub find { my ($self, $id) = @_; return $self->pg->db->query('select * from posts where id = ?', $id)->hash; } sub remove { shift->pg->db->query('delete from posts where id = ?', shift) } sub save { my ($self, $id, $post) = @_; my $sql = 'update posts set title = ?, body = ? where id = ?'; $self->pg->db->query($sql, $post->{title}, $post->{body}, $id); } 1; Swagger2-0.73/t/blog/lib/Blog/Controller/Post.pm000644 000765 000024 00000004425 12656403247 022536 0ustar00jhthorsenstaff000000 000000 package Blog::Controller::Post; use Mojo::Base 'Mojolicious::Controller'; sub create { shift->stash(post => {}) } sub edit { my $self = shift; # Web request $self->stash(post => $self->posts->find($self->param('id'))); } sub list { my ($self, $args, $cb) = @_; if ($cb) { # Swagger2 request $self->$cb($self->posts->all, 200); } else { # Web request $self->render(posts => $self->posts->all); } } sub remove { my ($self, $args, $cb) = @_; if ($cb) { # Swagger2 request $self->posts->remove($args->{id}); $self->$cb({}, 200); } else { # Web request $self->posts->remove($self->param('id')); $self->redirect_to('posts'); } } sub show { my ($self, $args, $cb) = @_; if ($cb) { # Swagger2 request my $entry = $self->posts->find($args->{id}); return $self->$cb($entry, 200) if $entry; return $self->$cb({errors => [{message => 'Blog post not found.', path => '/id'}]}, 404); } else { # Web request $self->render(post => $self->posts->find($self->param('id'))); } } sub store { my ($self, $args, $cb) = @_; my $validation = $self->_validation($args->{entry}); if ($cb) { # Swagger2 request $args->{entry}{id} = int $self->posts->add($validation->output); return $self->$cb($args->{entry}, 200); } else { # Web request return $self->render(action => 'create', post => {}) if $validation->has_error; my $id = $self->posts->add($validation->output); return $self->redirect_to('show_post', id => $id); } } sub update { my ($self, $args, $cb) = @_; my $validation = $self->_validation($args->{entry}); if ($cb) { # Swagger2 request $self->posts->save($args->{id}, $validation->output); return $self->$cb({}, 200); } else { # Web request return $self->render(action => 'edit', post => {}) if $validation->has_error; my $id = $self->param('id'); $self->posts->save($id, $validation->output); $self->redirect_to('show_post', id => $id); } } sub _validation { my ($self, $input) = @_; my $validation = $self->validation; $validation->input($input) if $input; $validation->required('title'); $validation->required('body'); return $validation; } 1; Swagger2-0.73/lib/Mojolicious/000755 000765 000024 00000000000 12660346320 017337 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/lib/Swagger2/000755 000765 000024 00000000000 12660346320 016524 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/lib/Swagger2.pm000644 000765 000024 00000016454 12660346317 017102 0ustar00jhthorsenstaff000000 000000 package Swagger2; use Mojo::Base -base; use Mojo::Asset::File; use Mojo::JSON; use Mojo::JSON::Pointer; use Mojo::URL; use Mojo::Util 'deprecated'; use File::Basename (); use File::Spec; use Swagger2::SchemaValidator; our $VERSION = '0.73'; # Should be considered internal our $SPEC_FILE = File::Spec->catfile(File::Basename::dirname(__FILE__), 'Swagger2', 'schema.json'); our $JS_CLIENT = File::Spec->catfile(File::Basename::dirname(__FILE__), 'Swagger2', 'swagger2-client.js'); has api_spec => sub { my $self = shift; return $self->_validator->_load_schema($self->url) if '' . $self->url; return Mojo::JSON::Pointer->new({}); }; has base_url => sub { my $self = shift; my $url = Mojo::URL->new; my ($schemes, $v); $self->load if !$self->{api_spec} and '' . $self->url; $schemes = $self->api_spec->get('/schemes') || []; $url->host($self->api_spec->get('/host') || 'example.com'); $url->path($self->api_spec->get('/basePath') || '/'); $url->scheme($schemes->[0] || 'http'); return $url; }; sub specification { deprecated 'specification() will be removed.'; shift->_specification; } sub tree { deprecated 'tree() is replaced by api_spec().'; shift->api_spec(@_); } has _specification => sub { shift->_validator->schema($SPEC_FILE)->schema }; has _validator => sub { Swagger2::SchemaValidator->new->cache_dir($ENV{SWAGGER2_CACHE_DIR} || File::Spec->catdir(File::Basename::dirname(__FILE__), qw( Swagger2 public cache ))); }; sub ua { shift->_validator->ua(@_) } sub url { shift->{url} } sub expand { my $self = shift; my $class = Scalar::Util::blessed($self); $class->new(%$self)->api_spec($self->_validator->schema($self->api_spec->data)->schema); } sub javascript_client { Mojo::Asset::File->new(path => $JS_CLIENT) } sub load { my $self = shift; delete $self->{base_url}; $self->{url} = Mojo::URL->new(shift) if @_; $self->{api_spec} = $self->_validator->_load_schema($self->{url}); $self; } sub new { my $class = shift; my $url = @_ % 2 ? shift : ''; my $self = $class->SUPER::new(@_); $url =~ s!^file://!!; $self->{url} ||= $url; $self->{url} = Mojo::URL->new($self->{url}) unless ref $self->{url}; $self; } sub parse { my ($self, $doc, $namespace) = @_; delete $self->{base_url}; $namespace ||= 'http://127.0.0.1/#'; $self->{url} = Mojo::URL->new($namespace); $self->{api_spec} = Mojo::JSON::Pointer->new($self->_validator->_load_schema_from_text($doc)); $self; } sub pod { my $self = shift; my $resolved = $self->_validator->schema($self->api_spec->data)->schema; require Swagger2::POD; Swagger2::POD->new(base_url => $self->base_url, api_spec => $resolved); } sub to_string { my $self = shift; my $format = shift || 'json'; if ($format eq 'yaml') { return DumpYAML($self->api_spec->data); } else { return Mojo::JSON::encode_json($self->api_spec->data); } } sub validate { my $self = shift; $self->_validator->validate($self->expand->api_spec->data, $self->_specification->data); } sub _is_true { return $_[0] if ref $_[0] and !Scalar::Util::blessed($_[0]); return 0 if !$_[0] or $_[0] =~ /^(n|false|off)/i; return 1; } 1; =encoding utf8 =head1 NAME Swagger2 - Swagger RESTful API Documentation =head1 VERSION 0.73 =head1 DESCRIPTION L is a module for generating, parsing and transforming L API specification. It has support for reading swagger specification in JSON notation and as well YAML format. Please read L for an introduction to Swagger and reasons for why you would to use it. =head2 Mojolicious server side code generator This distribution comes with a L plugin, L, which can set up routes and perform input and output validation. =head2 Mojolicious client side code generator Swagger2 also comes with a L generator, which converts the client spec to perl code in memory. =head1 RECOMMENDED MODULES =over 4 =item * YAML parser A L parser is required if you want to read/write spec written in the YAML format. Supported modules are L, L, L and L. =back =head1 SYNOPSIS use Swagger2; my $swagger = Swagger2->new("/path/to/api-spec.yaml"); # Access the raw specification values print $swagger->api_spec->get("/swagger"); # Returns the specification as a POD document print $swagger->pod->to_string; =head1 ATTRIBUTES =head2 api_spec $pointer = $self->api_spec; $self = $self->api_spec(Mojo::JSON::Pointer->new({})); Holds a L object containing your API specification. =head2 base_url $mojo_url = $self->base_url; L object that holds the location to the API endpoint. Note: This might also just be a dummy URL to L. =head2 specification DEPRECATED. If you need to change this, then you probably want L instead. =head2 tree DEPRECATED. Use L instead. =head2 ua $ua = $self->ua; $self = $self->ua(Mojo::UserAgent->new); A L used to fetch remote documentation. =head2 url $mojo_url = $self->url; L object that holds the location to the documentation file. This can be both a location on disk or an URL to a server. A remote resource will be fetched using L. =head1 METHODS =head2 expand $swagger = $self->expand; This method returns a new C object, where all the L are resolved. =head2 javascript_client $file = $self->javascript_client; Returns a L object which points to a file containing a custom JavaScript file which can communicate with L. See L for source code. C is currently EXPERIMENTAL! =head2 load $self = $self->load; $self = $self->load($url); Used to load the content from C<$url> or L. This method will try to guess the content type (JSON or YAML) by looking at the content of the C<$url>. =head2 new $self = Swagger2->new($url); $self = Swagger2->new(%attributes); $self = Swagger2->new(\%attributes); Object constructor. =head2 parse $self = $self->parse($text); Used to parse C<$text> instead of L data from L. The type of input text can be either JSON or YAML. It will default to YAML, but parse the text as JSON if it starts with "{". =head2 pod $pod_object = $self->pod; Returns a L object. =head2 to_string $json = $self->to_string; $json = $self->to_string("json"); $yaml = $self->to_string("yaml"); This method can transform this object into Swagger spec. =head2 validate @errors = $self->validate; Will validate L against L, and return a list with all the errors found. See also L. =head1 COPYRIGHT AND LICENSE Copyright (C) 2014-2015, Jan Henning Thorsen This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0. =head1 AUTHOR Jan Henning Thorsen - C =cut Swagger2-0.73/lib/Swagger2/Client.pm000644 000765 000024 00000016632 12660346210 020306 0ustar00jhthorsenstaff000000 000000 package Swagger2::Client; use Mojo::Base -base; use Mojo::JSON; use Mojo::UserAgent; use Mojo::Util; use Carp (); use Swagger2; use Swagger2::SchemaValidator; use constant DEBUG => $ENV{SWAGGER2_DEBUG} || 0; has base_url => sub { Mojo::URL->new(shift->_swagger->base_url) }; has ua => sub { Mojo::UserAgent->new }; has _validator => sub { Swagger2::SchemaValidator->new; }; sub generate { my $class = shift; my ($swagger, $url) = _swagger_url(shift); my $paths = $swagger->api_spec->get('/paths') || {}; my $generated; $generated = 40 < length $url ? Mojo::Util::md5_sum($url) : $url; # 40 is a bit random: not too long $generated =~ s!\W!_!g; $generated = "$class\::$generated"; return $generated->new if $generated->isa($class); # already generated _init_package($generated, $class); Mojo::Util::monkey_patch($generated, _swagger => sub {$swagger}); for my $path (keys %$paths) { for my $http_method (keys %{$paths->{$path}}) { my $op_spec = $paths->{$path}{$http_method}; my $method = $op_spec->{operationId} || $path; my $code = $generated->_generate_method(lc $http_method, $path, $op_spec); $method =~ s![^\w]!_!g; warn "[$generated] Add method $generated\::$method()\n" if DEBUG; Mojo::Util::monkey_patch($generated, $method => $code); my $snake = Mojo::Util::decamelize(ucfirst $method); warn "[$generated] Add method $generated\::$snake()\n" if DEBUG; Mojo::Util::monkey_patch($generated, $snake => $code); } } return $generated->new; } sub _generate_method { my ($class, $http_method, $path, $op_spec) = @_; my @path = grep {length} split '/', $path; return sub { my $cb = ref $_[-1] eq 'CODE' ? pop : undef; my $self = shift; my $args = shift || {}; my $req = [$self->base_url->clone]; my @e = $self->_validate_request($args, $op_spec, $req); if (@e) { unless ($cb) { return _invalid_input_res(\@e) if $self->return_on_error; Carp::croak('Invalid input: ' . join ' ', @e); } $self->$cb(\@e, undef); return $self; } push @{$req->[0]->path->parts}, map { local $_ = $_; s,\{(\w+)\},{$args->{$1}//''},ge; $_; } @path; if ($cb) { Scalar::Util::weaken($self); $self->ua->$http_method( @$req, sub { my ($ua, $tx) = @_; return $self->$cb('', $tx->res) unless my $err = $tx->error; return $self->$cb($err->{message}, $tx->res); } ); return $self; } else { my $tx = $self->ua->$http_method(@$req); return $tx->res if !$tx->error or $self->return_on_error; Carp::croak(join ': ', grep {defined} $tx->error->{message}, $tx->res->body); } }; } sub _init_package { my ($package, $base) = @_; eval <<"HERE" or die "package $package: $@"; package $package; use Mojo::Base '$base'; has return_on_error => 0; 1; HERE } sub _invalid_input_res { my $res = Mojo::Message::Response->new; $res->body(Mojo::JSON::encode_json({errors => $_[0]})); $res->code(400)->message($res->default_message); $res->error({message => 'Invalid input', code => 400}); } sub _swagger_url { if (UNIVERSAL::isa($_[0], 'Swagger2')) { my $swagger = shift->load->expand; return ($swagger, $swagger->url); } else { my $url = shift; return (Swagger2->new->load($url)->expand, $url); } } sub _validate_request { my ($self, $args, $op_spec, $req) = @_; my $query = $req->[0]->query; my (%data, $body, @e); for my $p (@{$op_spec->{parameters} || []}) { my ($in, $name) = @$p{qw( in name )}; my $value = exists $args->{$name} ? $args->{$name} : $p->{default}; if (defined $value or Swagger2::_is_true($p->{required})) { my $type = $p->{type} || 'object'; if (defined $value) { $value += 0 if $type =~ /^(?:integer|number)/ and $value =~ /^\d/; $value = ($value eq 'false' or !$value) ? Mojo::JSON->false : Mojo::JSON->true if $type eq 'boolean'; } if ($in eq 'body' or $in eq 'formData') { warn "[Swagger2::Client] Validate $in\n" if DEBUG; push @e, map { $_->{path} = $_->{path} eq "/" ? "/$name" : "/$name$_->{path}"; $_; } $self->_validator->validate($value, $p->{schema}); } else { warn "[Swagger2::Client] Validate $in $name=$value\n" if DEBUG; push @e, $self->_validator->validate({$name => $value}, {properties => {$name => $p}}); } } if (not defined $value) { next; } elsif ($in eq 'query') { $query->param($name => $value); } elsif ($in eq 'file') { $body = $value; } elsif ($in eq 'header') { $req->[1]{$name} = $value; } elsif ($in eq 'body') { $data{json} = $value; } elsif ($in eq 'formData') { $data{form} = $value; } } push @$req, map { ($_ => $data{$_}) } keys %data; push @$req, $body if defined $body; return @e; } 1; =encoding utf8 =head1 NAME Swagger2::Client - A client for talking to a Swagger powered server =head1 DESCRIPTION L is a base class for autogenerated classes that can talk to a server using a swagger specification. Note that this is a DRAFT, so there will probably be bugs and changes. =head1 SYNOPSIS =head2 Swagger specification The input L given to L need to point to a valid L document. --- swagger: 2.0 basePath: /api paths: /foo: get: operationId: listPets parameters: - name: limit in: query type: integer responses: 200: { ... } =head2 Client The swagger specification will the be turned into a sub class of L, where the "parameters" rules are used to do input validation. use Swagger2::Client; $ua = Swagger2::Client->generate("file:///path/to/api.json"); # blocking (will croak() on error) $pets = $ua->listPets; # blocking (will not croak() on error) $ua->return_on_error(1); $pets = $ua->listPets; # non-blocking $ua = $ua->listPets(sub { my ($ua, $err, $pets) = @_; }); # with arguments, where the key map to the "parameters" name $pets = $ua->listPets({limit => 10}); The method name added will both be the original C, but a "snake case" version will also be added. Example: "operationId": "listPets" => $client->listPets() => $client->list_pets() =head2 Customization If you want to request a different server than what is specified in the swagger document: $ua->base_url->host("other.server.com"); =head1 ATTRIBUTES =head2 base_url $base_url = $self->base_url; Returns a L object with the base URL to the API. =head2 ua $ua = $self->ua; Returns a L object which is used to execute requests. =head1 METHODS =head2 generate $client = Swagger2::Client->generate(Swagger2->new($specification_url)); $client = Swagger2::Client->generate($specification_url); Returns an object of a generated class, with the rules from the C<$specification_url>. Note that the class is cached by perl, so loading a new specification from the same URL will not generate a new class. =head1 COPYRIGHT AND LICENSE Copyright (C) 2014-2015, Jan Henning Thorsen This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0. =head1 AUTHOR Jan Henning Thorsen - C =cut Swagger2-0.73/lib/Swagger2/Editor.pm000644 000765 000024 00000020220 12645227636 020317 0ustar00jhthorsenstaff000000 000000 package Swagger2::Editor; use Mojo::Base 'Mojolicious'; use Mojo::Util; use File::Basename; use Swagger2; has specification_file => sub { $ENV{SWAGGER_API_FILE} || '' }; has _swagger => sub { Swagger2->new }; sub _get { my $c = shift; $c->respond_to( txt => {data => $c->app->_swagger->pod->to_string, layout => undef}, any => sub { my $c = shift; $c->stash(layout => undef) if $c->req->is_xhr; $c->render(template => 'editor'); } ); } sub _post { my $c = shift; my $spec = $c->req->body || '{}'; my $file = $c->app->specification_file; eval { my $s = Swagger2->new->parse($spec); Mojo::Util::spurt($spec, $file) if $file and -w $file; $c->render(text => $c->podify($s->pod), layout => undef); } or do { my $e = $@; $c->app->log->error($e); $e =~ s!^(Could not.*?:)\s+!$1\n\n!s; $e =~ s!\s+at \S+\.pm line \d\S+!!g; $c->render(template => 'error', error => $e); }; } sub startup { my $self = shift; my $raw = ''; if (my $file = $self->specification_file) { $raw = $file =~ /^https?:/ ? $self->ua->get($file)->res->body : Mojo::Util::slurp(File::Spec->catfile(split '/', $file)); $self->_swagger->parse($raw, $file); } unshift @{$self->renderer->classes}, __PACKAGE__; unshift @{$self->static->paths}, File::Spec->catdir(File::Basename::dirname(__FILE__), 'public'); $self->routes->get('/' => \&_get); $self->routes->post('/' => \&_post); $self->defaults(raw => $raw, swagger => $self->_swagger, layout => 'default'); $self->plugin('PODRenderer'); $self->helper(podify => \&_podify); } sub _podify { my ($c, $pod) = @_; my $dom = Mojo::DOM->new($c->pod_to_html($pod->to_string)); my $ul = '
    '; my ($sub, @parts); for my $e ($dom->find('h1, h2')->each) { my $id = $e->{id}; my $text = $e->all_text; my $anchor = $c->tag(a => href => "#$id", sub {$text}); if ($e->type eq 'h1') { $ul .= '
' if $sub; $sub = 0; } else { $ul .= '
    ' unless $sub; $sub = 1; } $ul .= "
  • $anchor
  • "; $e->content($c->link_to($text => Mojo::URL->new->fragment('toc'), id => $id)); } $ul .= '
' if $ul; return $c->b(qq(

TABLE OF CONTENTS

$ul$dom
)); } $ENV{SWAGGER_LOAD_EDITOR} ? __PACKAGE__->new : 1; __DATA__ @@ error.html.ep % title "Error in specification";

Error in specification

<%= $error %>
@@ editor.html.ep % title "Editor";
<%= stash('raw') || '---' %>
 
<%= podify $swagger->pod %>
% my $ace_url = $c->req->url->base->path->clone; % push @{$ace_url->parts}, 'ace.js'; %= javascript begin (function(ace) { var localStorage = window.localStorage || {}; var draggable = document.getElementById("resizer"); var editor = document.getElementById("editor"); var preview = document.getElementById("preview"); var focusId = location.href.split("#")[1] || ""; var initializing = true; var tid, xhr, i; var loaded = function() { if (initializing) { ace.focus(); ace.gotoLine(2); } initializing = false; ace.session.setMode("ace/mode/" + (ace.getValue().match(/^\s*\{/) ? "json" : "yaml")); preview.scrollTop = scrollSave(); }; var render = function() { scrollSave(); xhr = new XMLHttpRequest(); xhr.open("POST", "<%= url_for("/") %>", true); xhr.onload = function() { preview.firstChild.innerHTML = xhr.responseText; loaded(); }; localStorage["swagger-spec"] = ace.getValue(); xhr.send(localStorage["swagger-spec"]); }; var scrollSave = function() { var elem = document.getElementById(location.href.split("#")[1] || "toc"); if (!elem) return 0; var last = scrollSave.last; scrollSave.last = preview.scrollTop || elem.offsetTop; return last || scrollSave.last; }; ace.commands.addCommand({ bindKey: { win: "Ctrl-L", mac: "Command-L" }, command: "passKeysToBrowser" }); ace.commands.addCommand({ name: "find", bindKey: { win: "Ctrl-F", mac: "Command-F" }, exec: function(editor) { editor.find(prompt("Find:", editor.getCopyText())); } }); ace.setTheme("ace/theme/solarized_dark"); ace.getSession().on("change", function(e) { if (initializing) return; if (tid) clearTimeout(tid); tid = setTimeout(render, 600); }); if (!focusId) { location.href = location.href + "#toc"; } if (focusId.indexOf("/") == 0) { xhr = new XMLHttpRequest(); xhr.open("GET", focusId, true); xhr.onload = function() { if (!xhr.responseText.match(/^\s*(---|{)/)) return alert("Could not load specification from " + focusId); ace.setValue(xhr.responseText); render(); }; xhr.send(false); location.href = location.href.replace(/\#.*/, "#toc"); } else if (localStorage["swagger-spec"]) { ace.setValue(localStorage["swagger-spec"]); render(); } else { loaded(); } var resize = function(width, done) { draggable.style.left = width + "px"; editor.style.width = width + "px"; preview.style.marginLeft = width + "px"; if(done) ace.resize(); }; resize.x = false; resize.w = localStorage["swagger-editor-width"]; if (resize.w) resize(resize.w, true); draggable.addEventListener("mousedown", function(e) { resize.x = e.clientX; resize.w = editor.offsetWidth; }); window.addEventListener("resize", function(e) { if (resize.w > this.innerWidth) resize(this.innerWidth - 30, true); }) window.addEventListener("mouseup", function(e) { if (resize.x === false) return; resize(resize.w + e.clientX - resize.x, true); resize.w = editor.offsetWidth; resize.x = false; localStorage["swagger-editor-width"] = resize.w; }); window.addEventListener("mousemove", function(e) { if (resize.x === false) return; e.preventDefault(); resize(resize.w + e.clientX - resize.x); }); })(ace.edit("editor")); % end @@ layouts/default.html.ep Swagger2 - <%= title %> %= stylesheet begin html, body { background: #f5f5f5; font-family: sans-serif; font-size: 14px; color: #111; margin: 0; padding: 0; height: 100%; width: 100%; } a { color: #222; } p { margin: 0.5em 0; } h1, h2, h3 { padding: 0; margin: 1em 0 0 0; } h1 { font-size: 2em; } h2 { font-size: 1.5em; border-bottom: 1px solid #bbb; } h3 { font-size: 1.2em; } h4 { font-size: 1em; } h1 a, h2 a, h3 a, h4 a { text-decoration: none; } h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover { text-decoration: underline; } #editor, #resizer { position: fixed; top: 0; bottom: 0; } #editor { font-size: 14px; left: 0; width: 620px; } #resizer { border-left: 4px solid rgba(25, 63, 73, 0.99); left: 620px; width: 4px; cursor: ew-resize; } #preview { overflow: auto; margin-left: 620px; height: 100%; } #preview .pod-container { padding-left: 10px; padding-bottom: 100px; } #preview .link:hover { color: #679; cursor: pointer; } @media print { #editor, #resizer { display: none; } #preview { margin: 0; width: 100%; height: auto; } #preview .pod-container { padding: 0; } } % end %= content 1; =encoding utf8 =head1 NAME Swagger2::Editor - A WEB based Swagger2 API editor =head1 DESCRIPTION L is a WEB based Swagger2 API editor. =head1 SYNOPSIS $ mojo swagger2 edit /path/to/api.json --listen http://*:3000 =head1 ATTRIBUTES =head2 specification_file Returns path to swagger specification file. Defaults to C environment variable. =head1 ROUTES =head2 GET / Will render the editor and any Swagger specification given as input. Can also just render the POD if requested as C instead. =head2 POST / Will L the JSON/YAML in the HTTP body and render it as POD. =head1 METHODS =head2 startup Used to set up the L. =head1 COPYRIGHT AND LICENSE Copyright (C) 2014-2015, Jan Henning Thorsen This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0. =head1 AUTHOR Jan Henning Thorsen - C =cut Swagger2-0.73/lib/Swagger2/error.json000644 000765 000024 00000000513 12656641071 020555 0ustar00jhthorsenstaff000000 000000 { "type" : "object", "required": [ "errors" ], "properties": { "errors": { "type": "array", "items": { "type" : "object", "required": [ "message", "path" ], "properties": { "message": { "type": "string" }, "path": { "type": "string" } } } } } } Swagger2-0.73/lib/Swagger2/Guides/000755 000765 000024 00000000000 12660346320 017744 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/lib/Swagger2/POD.pm000644 000765 000024 00000025732 12654122334 017515 0ustar00jhthorsenstaff000000 000000 package Swagger2::POD; use Mojo::Base -base; use Mojo::JSON 'encode_json'; use Mojo::Message::Response; use Scalar::Util 'blessed'; use constant NO_DESCRIPTION => 'No description.'; require Swagger2; my $MOJO_MESSAGE_RESPONSE = Mojo::Message::Response->new; sub to_string { my $self = shift; join('', $self->_header_to_string, $self->_api_endpoint_to_string, $self->_paths_to_string, $self->_footer_to_string, ); } sub _api_endpoint_to_string { my $self = shift; my @schemes = @{$self->{api_spec}->get('/schemes') || []}; my $url = $self->{base_url}->clone; my $str = "=head1 BASEURL\n\n"; unless (@schemes) { return $str . "No default URL is defined to this application.\n\n"; } while (my $scheme = shift @schemes) { $url->scheme($scheme); $str .= sprintf "L<%s>\n\n", $url; } return $str; } sub _footer_to_string { my $self = shift; my $contact = $self->{api_spec}->get('/info/contact'); my $license = $self->{api_spec}->get('/info/license'); my $str = ''; unless ($license->{name}) { $license->{name} = 'BSD'; $license->{url} = 'http://www.linfo.org/bsdlicense.html'; } $contact->{name} ||= 'Unknown author'; $str .= sprintf "=head1 COPYRIGHT AND LICENSE\n\n%s", $contact->{name}; $str .= sprintf " - %s", $contact->{email} || $contact->{url} if $contact->{email} || $contact->{url}; $str .= sprintf "\n\n%s", $license->{name}; $str .= sprintf " - %s", $license->{url} if $license->{url}; $str .= "\n\n=cut\n"; $str; } sub _header_to_string { my $self = shift; my $info = $self->{api_spec}->get('/info'); my $str = ''; $info->{title} ||= 'Noname API'; $info->{description} ||= 'This API has no description.'; $info->{version} ||= '0.01'; $str .= sprintf "=head1 NAME\n\n%s\n\n", $info->{title}; $str .= sprintf "=head1 VERSION\n\n%s\n\n", $info->{version}; $str .= sprintf "=head1 DESCRIPTION\n\n%s\n\n", $info->{description}; $str .= sprintf "=head1 TERMS OF SERVICE\n\n%s\n\n", $info->{termsOfService} if $info->{termsOfService}; $str; } sub _path_request_to_string { my ($self, $info) = @_; my @table = ([qw( Name In Type Required Description )]); my $str = ''; my %body; for my $p (@{$info->{parameters} || []}) { $p->{description} ||= NO_DESCRIPTION; if ($p->{in} eq 'body') { %body = (name => 'body', %$p); push @table, [$p->{name}, 'body', 'schema', 'Yes', $p->{description}]; } else { push @table, [@$p{qw( name in type )}, Swagger2::_is_true($p->{required}) ? 'Yes' : 'No', $p->{description}]; } } $str .= sprintf "=head3 Parameters\n\n"; $str .= (@table == 1) ? "This resource takes no parameters.\n\n" : sprintf "%s\n", _ascii_table(\@table, ' '); $str .= " $body{name}:\n\n" . $self->_schema_to_string_dispatch($body{schema}, 0) . "\n" if %body; $str; } sub _path_response_to_string { my ($self, $info) = @_; my $responses = $info->{responses} || {}; my $str = ''; $str .= sprintf "=head3 Responses\n\n"; for my $code (sort keys %$responses) { my $res = $responses->{$code}; $str .= sprintf "=head4 %s\n\n", _status_code_to_string($code); $str .= $self->_summary_and_description($res); $str .= $self->_schema_to_string_dispatch($res->{schema}, 0) . "\n"; } return $str; } sub _paths_to_string { my $self = shift; my $paths = $self->{api_spec}->get('/paths') || {}; my $str = "=head1 RESOURCES\n\n"; my %info; for my $path (keys %$paths) { for my $method (sort keys %{$paths->{$path}}) { my $operationId = $paths->{$path}{$method}{operationId} || join ' ', uc $method, $path; $info{$operationId} and die "Overlapping operationId in swagger specification: $operationId"; $info{$operationId} = {%{$paths->{$path}{$method}}, _path => $path, _method => $method,}; } } for my $operationId (sort keys %info) { my $url = $self->{base_url}->clone; my $info = $info{$operationId}; push @{$url->path->parts}, grep { length $_ } split '/', $info->{_path}; my $ext = $info->{externalDocs}; my $resource_url; $str .= sprintf "=head2 %s\n\n", $operationId; $str .= " THIS RESOURCE IS DEPRECATED!\n\n" if $info->{deprecated}; $str .= $self->_summary_and_description($info); $str .= sprintf "See also L<%s>\n\n", $ext->{url} if $ext; next METHOD if $info->{deprecated}; $url->query(Mojo::Parameters->new); $resource_url = $url->to_abs; $resource_url =~ s!/%7B([^%]+)%7D!/{$1}!g; $str .= sprintf "=head3 Resource URL\n\n"; $str .= sprintf " %s %s\n\n", uc $info->{_method}, $resource_url; $str .= $self->_path_request_to_string($info); $str .= $self->_path_response_to_string($info); } return $str; } sub _schema_anyof_to_string { my ($self, $schema, $depth) = @_; my $str = "\n" . _sprintf($depth + 1, "// Any of the below:\n"); for my $s (@{$schema->{anyOf}}) { $str .= _sprintf($depth + 1, ""); $str .= $self->_schema_to_string_dispatch($s, $depth + 1); } $str; } sub _schema_allof_to_string { my ($self, $schema, $depth) = @_; my $str = "\n" . _sprintf($depth + 1, "// All of the below:\n"); for my $s (@{$schema->{allOf}}) { $str .= _sprintf($depth + 1, ""); $str .= $self->_schema_to_string_dispatch($s, $depth + 1); } $str; } sub _schema_oneof_to_string { my ($self, $schema, $depth) = @_; my $str = "\n" . _sprintf($depth + 1, "// One of the below:\n"); for my $s (@{$schema->{oneOf}}) { $str .= _sprintf($depth + 1, ""); $str .= $self->_schema_to_string_dispatch($s, $depth + 1); } $str; } sub _schema_array_to_string { my ($self, $schema, $depth) = @_; my $description = _type_description($schema, qw( minItems maxItems multipleOf uniqueItems )); my $str = ''; $description = $description eq NO_DESCRIPTION ? "" : "// $description"; $str .= _sprintf($depth, "[%s\n", $description); $str .= $self->_schema_to_string_dispatch($schema->{items}, $depth + 1); $str .= _sprintf($depth + 1, "...\n"); $str .= _sprintf($depth, "]\n"); $str; } sub _schema_boolean_to_string { my ($self, $schema, $depth) = @_; sprintf "%s, // %s\n", 'boolean', _type_description($schema); } sub _schema_enum_to_string { my ($self, $schema, $depth) = @_; sprintf "%s, // %s\n", 'enum', _type_description($schema, qw( enum )); } sub _schema_integer_to_string { my ($self, $schema, $depth) = @_; sprintf "%s, // %s\n", $schema->{format} || 'integer', _type_description($schema, qw( default )); } sub _schema_number_to_string { my ($self, $schema, $depth) = @_; sprintf "%s, // %s\n", $schema->{format} || 'number', _type_description($schema, qw( default )); } sub _schema_file_to_string { my ($self, $schema, $depth) = @_; my $str = $schema->{description} || 'This response contains raw binary or text data.'; return " $str\n"; } sub _schema_object_to_string { my ($self, $schema, $depth) = @_; my $description = _type_description($schema, qw( minProperties maxProperties )); my $str = ''; $description = $description eq NO_DESCRIPTION ? "" : "// $description"; $str .= _sprintf($depth, "{%s\n", $description); for my $k (sort keys %$schema) { $str .= _sprintf($depth + 1, qq("%s": ), $k); $str .= $self->_schema_to_string_dispatch($schema->{$k}, $depth + 1) if ref $schema->{$k} eq 'HASH'; } $str .= _sprintf($depth, "},\n"); $str; } sub _schema_string_to_string { my ($self, $schema, $depth) = @_; sprintf "%s, // %s\n", $schema->{format} || 'string', _type_description($schema, qw( minLength maxLength pattern default )); } sub _schema_to_string_dispatch { my ($self, $schema, $depth) = @_; my $required = $schema->{required}; my $method; if ($schema->{properties}) { $schema = $schema->{properties}; } if ($required and ref $required eq 'ARRAY') { $schema->{$_}{required} = 1 for @$required; } if ($schema->{anyOf}) { $method = '_schema_anyof_to_string'; } elsif ($schema->{allOf}) { $method = '_schema_allof_to_string'; } elsif ($schema->{oneOf}) { $method = '_schema_oneof_to_string'; } elsif (ref $schema->{type} eq 'ARRAY') { return sprintf "{%s},\n", join ',', @{$schema->{type}}; } else { $method = '_schema_' . ($schema->{type} || 'object') . '_to_string'; } return "Cannot translate '$schema->{type}' into POD." unless $self->can($method); return $self->$method($schema, $depth); } sub _summary_and_description { my ($self, $data) = @_; my $str = ''; $str .= "$data->{summary}\n\n" if $data->{summary}; $str .= "$data->{description}\n\n" if $data->{description}; $str .= NO_DESCRIPTION . "\n\n" unless $data->{summary} or $data->{description}; $str; } # FUNCTIONS sub _ascii_table { my ($rows, $pad) = @_; my $width = 1; my (@spec, @table); $pad //= ''; for my $row (@$rows) { for my $i (0 .. $#$row) { $row->[$i] //= ''; $row->[$i] =~ s/[\r\n]//g; my $len = length $row->[$i]; $spec[$i] = $len if $len >= ($spec[$i] // 0); } } my $format = sprintf '%s| %s |', $pad, join ' | ', map { $width += $_ + 3; "\%-${_}s" } @spec; @table = map { sprintf "$format\n", @$_ } @$rows; unshift @table, "$pad." . ('-' x ($width - 2)) . ".\n"; splice @table, 2, 0, "$pad|" . ('-' x ($width - 2)) . "|\n"; push @table, "$pad'" . ('-' x ($width - 2)) . "'\n"; return join '', @table; } sub _sprintf { my ($level, $format, @args) = @_; sprintf "%s$format", (" " x (($level + 1) * 2)), @args; } sub _status_code_to_string { my ($code) = @_; my $message = $MOJO_MESSAGE_RESPONSE->code($code)->default_message; return sprintf '%s - %s', $code, $message if $message; return ucfirst $code; } sub _stringify { my ($k, $obj) = @_; return 'required' if $k eq 'required' and Swagger2::_is_true($obj->{$k}); return "$k=true" if blessed $obj->{$k} and $obj->{$k} eq Mojo::JSON->true; return "$k=false" if blessed $obj->{$k} and $obj->{$k} eq Mojo::JSON->false; return sprintf '%s=%s', $k, encode_json $obj->{$k} if ref $obj->{$k}; return sprintf '%s=%s', $k, $obj->{$k}; } sub _type_description { my ($schema) = (shift, shift); return $schema->{description} if $schema->{description}; my @keys = grep { defined $schema->{$_} } 'required', @_; my @description = map { _stringify($_, $schema) } @keys; return $schema->{title} || NO_DESCRIPTION unless @description; return join ', ', @description; } 1; =encoding utf8 =head1 NAME Swagger2::POD - Convert swagger API spec to Perl documentation =head1 DESCRIPTION L is a module that can convert from L
to L. =head1 SYNOPSIS use Swagger2; my $swagger = Sswagger2->new("file:///path/to/api-spec.yaml"); print $swagger->pod->to_string; =head1 METHODS =head2 to_string $str = $self->to_string; Will convert swagger API spec to plain old documentation. =head1 COPYRIGHT AND LICENSE Copyright (C) 2014-2015, Jan Henning Thorsen This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0. =head1 AUTHOR Jan Henning Thorsen - C =cut Swagger2-0.73/lib/Swagger2/public/000755 000765 000024 00000000000 12660346320 020002 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/lib/Swagger2/schema.json000644 000765 000024 00000116050 12645227324 020667 0ustar00jhthorsenstaff000000 000000 { "title": "A JSON Schema for Swagger 2.0 API.", "id": "http://swagger.io/v2/schema.json#", "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "required": [ "swagger", "info", "paths" ], "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "swagger": { "type": "string", "enum": [ "2.0" ], "description": "The Swagger version of this document." }, "info": { "$ref": "#/definitions/info" }, "host": { "type": "string", "pattern": "^[^{}/ :\\\\]+(?::\\d+)?$", "description": "The host (name or ip) of the API. Example: 'swagger.io'" }, "basePath": { "type": "string", "pattern": "^/", "description": "The base path to the API. Example: '/api'." }, "schemes": { "$ref": "#/definitions/schemesList" }, "consumes": { "description": "A list of MIME types accepted by the API.", "$ref": "#/definitions/mediaTypeList" }, "produces": { "description": "A list of MIME types the API can produce.", "$ref": "#/definitions/mediaTypeList" }, "paths": { "$ref": "#/definitions/paths" }, "definitions": { "$ref": "#/definitions/definitions" }, "parameters": { "$ref": "#/definitions/parameterDefinitions" }, "responses": { "$ref": "#/definitions/responseDefinitions" }, "security": { "$ref": "#/definitions/security" }, "securityDefinitions": { "$ref": "#/definitions/securityDefinitions" }, "tags": { "type": "array", "items": { "$ref": "#/definitions/tag" }, "uniqueItems": true }, "externalDocs": { "$ref": "#/definitions/externalDocs" } }, "definitions": { "info": { "type": "object", "description": "General information about the API.", "required": [ "version", "title" ], "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "title": { "type": "string", "description": "A unique and precise title of the API." }, "version": { "type": "string", "description": "A semantic version number of the API." }, "description": { "type": "string", "description": "A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed." }, "termsOfService": { "type": "string", "description": "The terms of service for the API." }, "contact": { "$ref": "#/definitions/contact" }, "license": { "$ref": "#/definitions/license" } } }, "contact": { "type": "object", "description": "Contact information for the owners of the API.", "additionalProperties": false, "properties": { "name": { "type": "string", "description": "The identifying name of the contact person/organization." }, "url": { "type": "string", "description": "The URL pointing to the contact information.", "format": "uri" }, "email": { "type": "string", "description": "The email address of the contact person/organization.", "format": "email" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "license": { "type": "object", "required": [ "name" ], "additionalProperties": false, "properties": { "name": { "type": "string", "description": "The name of the license type. It's encouraged to use an OSI compatible license." }, "url": { "type": "string", "description": "The URL pointing to the license.", "format": "uri" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "paths": { "type": "object", "description": "Relative paths to the individual endpoints. They must be relative to the 'basePath'.", "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" }, "^/": { "$ref": "#/definitions/pathItem" } }, "additionalProperties": false }, "definitions": { "type": "object", "additionalProperties": { "$ref": "#/definitions/schema" }, "description": "One or more JSON objects describing the schemas being consumed and produced by the API." }, "parameterDefinitions": { "type": "object", "additionalProperties": { "$ref": "#/definitions/parameter" }, "description": "One or more JSON representations for parameters" }, "responseDefinitions": { "type": "object", "additionalProperties": { "$ref": "#/definitions/response" }, "description": "One or more JSON representations for parameters" }, "externalDocs": { "type": "object", "additionalProperties": false, "description": "information about external documentation", "required": [ "url" ], "properties": { "description": { "type": "string" }, "url": { "type": "string", "format": "uri" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "examples": { "type": "object", "additionalProperties": true }, "mimeType": { "type": "string", "description": "The MIME type of the HTTP message." }, "operation": { "type": "object", "required": [ "responses" ], "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "tags": { "type": "array", "items": { "type": "string" }, "uniqueItems": true }, "summary": { "type": "string", "description": "A brief summary of the operation." }, "description": { "type": "string", "description": "A longer description of the operation, GitHub Flavored Markdown is allowed." }, "externalDocs": { "$ref": "#/definitions/externalDocs" }, "operationId": { "type": "string", "description": "A unique identifier of the operation." }, "produces": { "description": "A list of MIME types the API can produce.", "$ref": "#/definitions/mediaTypeList" }, "consumes": { "description": "A list of MIME types the API can consume.", "$ref": "#/definitions/mediaTypeList" }, "parameters": { "$ref": "#/definitions/parametersList" }, "responses": { "$ref": "#/definitions/responses" }, "schemes": { "$ref": "#/definitions/schemesList" }, "deprecated": { "type": "boolean", "default": false }, "security": { "$ref": "#/definitions/security" } } }, "pathItem": { "type": "object", "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "$ref": { "type": "string" }, "get": { "$ref": "#/definitions/operation" }, "put": { "$ref": "#/definitions/operation" }, "post": { "$ref": "#/definitions/operation" }, "delete": { "$ref": "#/definitions/operation" }, "options": { "$ref": "#/definitions/operation" }, "head": { "$ref": "#/definitions/operation" }, "patch": { "$ref": "#/definitions/operation" }, "parameters": { "$ref": "#/definitions/parametersList" } } }, "responses": { "type": "object", "description": "Response objects names can either be any valid HTTP status code or 'default'.", "minProperties": 1, "additionalProperties": false, "patternProperties": { "^([0-9]{3})$|^(default)$": { "$ref": "#/definitions/responseValue" }, "^x-": { "$ref": "#/definitions/vendorExtension" } }, "not": { "type": "object", "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } } }, "responseValue": { "oneOf": [ { "$ref": "#/definitions/response" }, { "$ref": "#/definitions/jsonReference" } ] }, "response": { "type": "object", "required": [ "description" ], "properties": { "description": { "type": "string" }, "schema": { "oneOf": [ { "$ref": "#/definitions/schema" }, { "$ref": "#/definitions/fileSchema" } ] }, "headers": { "$ref": "#/definitions/headers" }, "examples": { "$ref": "#/definitions/examples" } }, "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "headers": { "type": "object", "additionalProperties": { "$ref": "#/definitions/header" } }, "header": { "type": "object", "additionalProperties": false, "required": [ "type" ], "properties": { "type": { "type": "string", "enum": [ "string", "number", "integer", "boolean", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormat" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "vendorExtension": { "description": "Any property starting with x- is valid.", "additionalProperties": true, "additionalItems": true }, "bodyParameter": { "type": "object", "required": [ "name", "in", "schema" ], "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "body" ] }, "required": { "type": "boolean", "description": "Determines whether or not this parameter is required or optional.", "default": false }, "schema": { "$ref": "#/definitions/schema" } }, "additionalProperties": false }, "headerParameterSubSchema": { "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "required": { "type": "boolean", "description": "Determines whether or not this parameter is required or optional.", "default": false }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "header" ] }, "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "type": { "type": "string", "enum": [ "string", "number", "boolean", "integer", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormat" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } } }, "queryParameterSubSchema": { "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "required": { "type": "boolean", "description": "Determines whether or not this parameter is required or optional.", "default": false }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "query" ] }, "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "allowEmptyValue": { "type": "boolean", "default": false, "description": "allows sending a parameter by name only or with an empty value." }, "type": { "type": "string", "enum": [ "string", "number", "boolean", "integer", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormatWithMulti" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } } }, "formDataParameterSubSchema": { "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "required": { "type": "boolean", "description": "Determines whether or not this parameter is required or optional.", "default": false }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "formData" ] }, "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "allowEmptyValue": { "type": "boolean", "default": false, "description": "allows sending a parameter by name only or with an empty value." }, "type": { "type": "string", "enum": [ "string", "number", "boolean", "integer", "array", "file" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormatWithMulti" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } } }, "pathParameterSubSchema": { "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "required": [ "required" ], "properties": { "required": { "type": "boolean", "enum": [ true ], "description": "Determines whether or not this parameter is required or optional." }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "path" ] }, "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "type": { "type": "string", "enum": [ "string", "number", "boolean", "integer", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormat" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } } }, "nonBodyParameter": { "type": "object", "required": [ "name", "in", "type" ], "oneOf": [ { "$ref": "#/definitions/headerParameterSubSchema" }, { "$ref": "#/definitions/formDataParameterSubSchema" }, { "$ref": "#/definitions/queryParameterSubSchema" }, { "$ref": "#/definitions/pathParameterSubSchema" } ] }, "parameter": { "oneOf": [ { "$ref": "#/definitions/bodyParameter" }, { "$ref": "#/definitions/nonBodyParameter" } ] }, "schema": { "type": "object", "description": "A deterministic version of a JSON Schema object.", "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "$ref": { "type": "string" }, "format": { "type": "string" }, "title": { "$ref": "http://json-schema.org/draft-04/schema#/properties/title" }, "description": { "$ref": "http://json-schema.org/draft-04/schema#/properties/description" }, "default": { "$ref": "http://json-schema.org/draft-04/schema#/properties/default" }, "multipleOf": { "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" }, "maximum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" }, "exclusiveMaximum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" }, "minimum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" }, "exclusiveMinimum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" }, "maxLength": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minLength": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "pattern": { "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" }, "maxItems": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minItems": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "uniqueItems": { "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" }, "maxProperties": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minProperties": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "required": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" }, "enum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" }, "additionalProperties": { "anyOf": [ { "$ref": "#/definitions/schema" }, { "type": "boolean" } ], "default": {} }, "type": { "$ref": "http://json-schema.org/draft-04/schema#/properties/type" }, "items": { "anyOf": [ { "$ref": "#/definitions/schema" }, { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/schema" } } ], "default": {} }, "allOf": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/schema" } }, "properties": { "type": "object", "additionalProperties": { "$ref": "#/definitions/schema" }, "default": {} }, "discriminator": { "type": "string" }, "readOnly": { "type": "boolean", "default": false }, "xml": { "$ref": "#/definitions/xml" }, "externalDocs": { "$ref": "#/definitions/externalDocs" }, "example": {} }, "additionalProperties": false }, "fileSchema": { "type": "object", "description": "A deterministic version of a JSON Schema object.", "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "format": { "type": "string" }, "title": { "$ref": "http://json-schema.org/draft-04/schema#/properties/title" }, "description": { "$ref": "http://json-schema.org/draft-04/schema#/properties/description" }, "default": { "$ref": "http://json-schema.org/draft-04/schema#/properties/default" }, "required": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" }, "type": { "type": "string", "enum": [ "file" ] }, "readOnly": { "type": "boolean", "default": false }, "externalDocs": { "$ref": "#/definitions/externalDocs" }, "example": {} }, "additionalProperties": false }, "primitivesItems": { "type": "object", "additionalProperties": false, "properties": { "type": { "type": "string", "enum": [ "string", "number", "integer", "boolean", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormat" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "security": { "type": "array", "items": { "$ref": "#/definitions/securityRequirement" }, "uniqueItems": true }, "securityRequirement": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" }, "uniqueItems": true } }, "xml": { "type": "object", "additionalProperties": false, "properties": { "name": { "type": "string" }, "namespace": { "type": "string" }, "prefix": { "type": "string" }, "attribute": { "type": "boolean", "default": false }, "wrapped": { "type": "boolean", "default": false } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "tag": { "type": "object", "additionalProperties": false, "required": [ "name" ], "properties": { "name": { "type": "string" }, "description": { "type": "string" }, "externalDocs": { "$ref": "#/definitions/externalDocs" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "securityDefinitions": { "type": "object", "additionalProperties": { "oneOf": [ { "$ref": "#/definitions/basicAuthenticationSecurity" }, { "$ref": "#/definitions/apiKeySecurity" }, { "$ref": "#/definitions/oauth2ImplicitSecurity" }, { "$ref": "#/definitions/oauth2PasswordSecurity" }, { "$ref": "#/definitions/oauth2ApplicationSecurity" }, { "$ref": "#/definitions/oauth2AccessCodeSecurity" } ] } }, "basicAuthenticationSecurity": { "type": "object", "additionalProperties": false, "required": [ "type" ], "properties": { "type": { "type": "string", "enum": [ "basic" ] }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "apiKeySecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "name", "in" ], "properties": { "type": { "type": "string", "enum": [ "apiKey" ] }, "name": { "type": "string" }, "in": { "type": "string", "enum": [ "header", "query" ] }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2ImplicitSecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "flow", "authorizationUrl" ], "properties": { "type": { "type": "string", "enum": [ "oauth2" ] }, "flow": { "type": "string", "enum": [ "implicit" ] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" }, "authorizationUrl": { "type": "string", "format": "uri" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2PasswordSecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "flow", "tokenUrl" ], "properties": { "type": { "type": "string", "enum": [ "oauth2" ] }, "flow": { "type": "string", "enum": [ "password" ] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" }, "tokenUrl": { "type": "string", "format": "uri" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2ApplicationSecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "flow", "tokenUrl" ], "properties": { "type": { "type": "string", "enum": [ "oauth2" ] }, "flow": { "type": "string", "enum": [ "application" ] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" }, "tokenUrl": { "type": "string", "format": "uri" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2AccessCodeSecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "flow", "authorizationUrl", "tokenUrl" ], "properties": { "type": { "type": "string", "enum": [ "oauth2" ] }, "flow": { "type": "string", "enum": [ "accessCode" ] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" }, "authorizationUrl": { "type": "string", "format": "uri" }, "tokenUrl": { "type": "string", "format": "uri" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2Scopes": { "type": "object", "additionalProperties": { "type": "string" } }, "mediaTypeList": { "type": "array", "items": { "$ref": "#/definitions/mimeType" }, "uniqueItems": true }, "parametersList": { "type": "array", "description": "The parameters needed to send a valid API call.", "additionalItems": false, "items": { "oneOf": [ { "$ref": "#/definitions/parameter" }, { "$ref": "#/definitions/jsonReference" } ] }, "uniqueItems": true }, "schemesList": { "type": "array", "description": "The transfer protocol of the API.", "items": { "type": "string", "enum": [ "http", "https", "ws", "wss" ] }, "uniqueItems": true }, "collectionFormat": { "type": "string", "enum": [ "csv", "ssv", "tsv", "pipes" ], "default": "csv" }, "collectionFormatWithMulti": { "type": "string", "enum": [ "csv", "ssv", "tsv", "pipes", "multi" ], "default": "csv" }, "title": { "$ref": "http://json-schema.org/draft-04/schema#/properties/title" }, "description": { "$ref": "http://json-schema.org/draft-04/schema#/properties/description" }, "default": { "$ref": "http://json-schema.org/draft-04/schema#/properties/default" }, "multipleOf": { "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" }, "maximum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" }, "exclusiveMaximum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" }, "minimum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" }, "exclusiveMinimum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" }, "maxLength": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minLength": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "pattern": { "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" }, "maxItems": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minItems": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "uniqueItems": { "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" }, "enum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" }, "jsonReference": { "type": "object", "required": [ "$ref" ], "additionalProperties": false, "properties": { "$ref": { "type": "string" } } } } }Swagger2-0.73/lib/Swagger2/SchemaValidator.pm000644 000765 000024 00000007363 12656313433 022145 0ustar00jhthorsenstaff000000 000000 package Swagger2::SchemaValidator; use Mojo::Base 'JSON::Validator'; use Scalar::Util (); use constant IV_SIZE => eval 'require Config;$Config::Config{ivsize}'; our %COLLECTION_RE = (pipes => qr{\|}, csv => qr{,}, ssv => qr{\s}, tsv => qr{\t}); sub validate_input { my $self = shift; local $self->{validate_input} = 1; $self->validate(@_); } sub _validate_type_array { my ($self, $data, $path, $schema) = @_; if (ref $data eq 'ARRAY' and ref $schema->{items} eq 'HASH' and $schema->{items}{collectionFormat}) { $self->_coerce_by_collection_format($data, $schema->{items}); } return $self->SUPER::_validate_type_array(@_[1, 2, 3]); } # always valid sub _validate_type_file { } sub _validate_type_object { return shift->SUPER::_validate_type_object(@_) unless $_[0]->{validate_input}; my ($self, $data, $path, $schema) = @_; my $properties = $schema->{properties} || {}; my (%ro, @e); for my $p (keys %$properties) { next unless $properties->{$p}{readOnly}; push @e, JSON::Validator::E("$path/$p", "Read-only.") if exists $data->{$p}; $ro{$p} = 1; } local $schema->{required} = [grep { !$ro{$_} } @{$schema->{required} || []}]; return @e, $self->SUPER::_validate_type_object($data, $path, $schema); } sub _build_formats { my $formats = shift->SUPER::_build_formats; $formats->{byte} = \&_is_byte_string; $formats->{date} = \&_is_date; $formats->{double} = \&Scalar::Util::looks_like_number; $formats->{float} = \&Scalar::Util::looks_like_number; $formats->{int32} = sub { _is_number($_[0], 'l'); }; $formats->{int64} = IV_SIZE >= 8 ? sub { _is_number($_[0], 'q'); } : sub {1}; return $formats; } sub _coerce_by_collection_format { my ($self, $data, $schema) = @_; my $re = $COLLECTION_RE{$schema->{collectionFormat}} || ','; my $type = $schema->{type} || ''; for my $i (0 .. @$data - 1) { my @d = split /$re/, $data->[$i]; $data->[$i] = ($type eq 'integer' or $type eq 'number') ? [map { $_ + 0 } @d] : \@d; } } sub _is_byte_string { $_[0] =~ /^[A-Za-z0-9\+\/\=]+$/ } sub _is_date { $_[0] =~ /^(\d+)-(\d+)-(\d+)$/ } sub _is_number { return unless $_[0] =~ /^-?\d+(\.\d+)?$/; return $_[0] eq unpack $_[1], pack $_[1], $_[0]; } 1; =encoding utf8 =head1 NAME Swagger2::SchemaValidator - Sub class of JSON::Validator =head1 DESCRIPTION This class is used to validate Swagger specification. It is a sub class of L and adds some extra functionality specific for L. =head1 ATTRIBUTES L inherits all attributes from L. =head2 formats Swagger support the same formats as L, but adds the following to the set: =over 4 =item * byte A padded, base64-encoded string of bytes, encoded with a URL and filename safe alphabet. Defined by RFC4648. =item * date An RFC3339 date in the format YYYY-MM-DD =item * double Cannot test double values with higher precision then what the "number" type already provides. =item * float Will always be true if the input is a number, meaning there is no difference between L and L. Patches are welcome. =item * int32 A signed 32 bit integer. =item * int64 A signed 64 bit integer. Note: This check is only available if Perl is compiled to use 64 bit integers. =back =head1 METHODS L inherits all attributes from L. =head2 validate_input This method will make sure "readOnly" is taken into account, when validating data sent to your API. =head1 COPYRIGHT AND LICENSE Copyright (C) 2014-2015, Jan Henning Thorsen This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0. =head1 AUTHOR Jan Henning Thorsen - C =cut Swagger2-0.73/lib/Swagger2/swagger2-client.js000644 000765 000024 00000017103 12656175267 022100 0ustar00jhthorsenstaff000000 000000 (function() { /** * @file Generate object for communicating with a Swagger backend. * @version 0.70.0 * @author Jan Henning Thorsen * @copyright Jan Henning Thorsen 2016 * @license Artistic License version 2.0. */ /** * Generates a new client from a Swagger specification. * Note that the specification specification cannot contain "$ref" and need * to be in JSON format. * @class * @param {(string|Object)} spec - Either an object representing a Swagger spec or the URL to the Swagger specification file. * @param {function} [cb] - Function to call when the spec URL is downloaded. * @example * var client = new swaggerClient(url, function(err) { * if (err) throw err; * this.listPets({limit: 10}, function(err, xhr) { * console.log(xhr.code, xhr.body); * }); * }); */ window.swaggerClient = function(spec, cb) { this._id = 1; this._xhr = {}; if (typeof spec == 'object') return this._generate(spec); if (typeof spec == 'string') return this._load(spec, cb); }; var proto = window.swaggerClient.prototype; var cache = {}, makeErr; /** * Get cached XMLHttpRequest object * @param {string} operationId - Name of operationId from Swagger specification * @return {Object} xhr - A XMLHttpRequest object * @example * xhr = client.cached("listPets"); */ proto.cached = function(operationId) { return cache[operationId]; }; /** * Force getting fresh data from server * @return {Object} client - Self. * @example * client.fresh().listPets({}, function(err, xhr) {}); */ proto.fresh = function() { this._fresh = true; return this; }; /** * Used to set a WebSocket object which can talk Swagger. * The WebSocket object must fire a "json" event. * @return {Object} client - Self. * @example * client.fresh().listPets({}, function(err, xhr) {}); */ proto.ws = function(ws) { var self = this; self._ws = ws; ws.on('json', function(res) { if (!res.id || !res.code) return; var xhr = self._xhr[res.id]; if (!xhr) return; delete self._xhr[res.id]; xhr.status = res.code; xhr.body = res.body; if (window.DEBUG) console.log('[Swagger] ' + xhr.op + ' ' + xhr.status + ' ' + JSON.stringify(xhr.body)); xhr.call(self, makeErr(xhr), xhr); }); return self; }; // Generate methods from spec proto._generate = function(spec) { var self = this; this.baseUrl = (spec.basePath || '').replace(/\/$/, ''); this._fresh = false; Object.keys(spec.paths).forEach(function(path) { if (path.indexOf('/') != 0) return; Object.keys(spec.paths[path]).forEach(function(httpMethod) { if (!httpMethod.match(/^\w+$/)) return; var opSpec = spec.paths[path][httpMethod]; var pathList = path.split('/'); httpMethod = httpMethod.toUpperCase(); pathList.shift(); // first element is empty string if (window.DEBUG == 2) console.log('[Swagger] Add method ' + opSpec.operationId); self[opSpec.operationId] = function(input, cb) { var xhr = this._fresh ? false : this.cached(opSpec.operationId); if (xhr) { if (window.DEBUG) console.log('[Swagger] ' + xhr.url + ' is cached'); setTimeout(function() { cb.call(this, null, xhr) }.bind(this), 0); } else if(this._ws && this._ws.readyState == WebSocket.OPEN) { this._ws.send({id: this._id, op: opSpec.operationId, params: input}); this._xhr[this._id++] = cb; cb.op = opSpec.operationId; } else { xhr = this._xhrReq(httpMethod, pathList, input, opSpec.parameters || []); this._fresh = false; // reset on each request if (xhr.errors) { setTimeout(function() { cb.call(this, xhr.errors, xhr) }.bind(this), 0); } else { xhr.onreadystatechange = function() { if (xhr.readyState != 4) return; if (httpMethod == 'GET' && xhr.status == 200) cache[httpMethod + ':' + xhr.url] = xhr; if (window.DEBUG) console.log('[Swagger] ' + xhr.url + ' ' + xhr.status + ' ' + xhr.responseText); xhr.body = xhr.responseText.match(/^[\{\[]/) ? JSON.parse(xhr.responseText) : xhr.responseText; cb.call(this, makeErr(xhr), xhr); }.bind(this); xhr.send(xhr.body); delete xhr.body; } } }; }); }); return this; }; // Load Swagger specification from URL proto._load = function(url, cb) { var xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onreadystatechange = function() { if (xhr.readyState != 4) return; if (xhr.status != 200) return cb.call(this, xhr.status); if (window.DEBUG == 1) console.log('[Swagger] Generate methods from ' + url); this._generate(xhr.responseText.match(/^[\{\[]/) ? JSON.parse(xhr.responseText) : {}); cb.call(this, ''); }.bind(this); xhr.send(null); return this; }; // Create a request proto._xhrReq = function(httpMethod, pathList, input, parameters) { var xhr = new XMLHttpRequest(); var form = [], headers = [], json = null, query = [], str; var url = [this.baseUrl]; var errors = []; pathList.forEach(function(p) { url.push(p.replace(/\{(\w+)\}/, function(m, n) { if (typeof input[n] == 'undefined') errors.push({message: 'Missing input: ' + n, path: '/' + n}); return input[n]; })); }); xhr.body = null; xhr.url = url.join('/'); for (i = 0; i < parameters.length; i++) { var p = parameters[i]; var name = p.name; var value = input[name]; if (typeof value == 'undefined') { value = p['default']; } if (typeof value == 'undefined') { if (p.required) errors.push({message: 'Missing input: ' + name, path: '/' + name}); continue; } switch (p['in']) { case 'body': json = value; break; case 'file': xhr.body = value; break; case 'formData': form.push([name, value]); break; case 'header': headers.push([name, value]); break; case 'query': query.push([name, value]); break; } } if (errors.length) { if (window.DEBUG) console.log('[Swagger] ' + xhr.url + ' = ' + JSON.stringify(errors)); xhr.errors = errors; return xhr; } if (query.length) { str = []; query.forEach(function(i) { str.push(encodeURIComponent(i[0]) + '=' + encodeURIComponent(i[1])); }); xhr.url += '?' + str.join('&'); } if (json) { headers.unshift(['Content-Type', 'application/json']); xhr.body = JSON.stringify(json); if (window.DEBUG == 2) console.log('[Swagger] ' + xhr.url + ' <<< ' + xhr.body); } else if(form.length) { str = []; headers.unshift(['Content-Type', 'application/x-www-form-urlencoded']); form.forEach(function(i) { str.push(encodeURIComponent(i[0]) + '=' + encodeURIComponent(i[1])); }); xhr.body = str.join('&'); if (window.DEBUG == 2) console.log('[Swagger] ' + xhr.url + ' <<< ' + xhr.body); } xhr.open(httpMethod, xhr.url); headers.forEach(function(i) { xhr.setRequestHeader(i[0], i[1]); }); return xhr; }; var makeErr = function(xhr) { var errors = xhr.body.errors || []; if (xhr.status == 200) return null; if (errors.length) return errors; if (!xhr.status) xhr.status = 408; return [{message: "Something very bad happened! Try again later. (" + xhr.status + ")", path: xhr.url}]; }; })(); Swagger2-0.73/lib/Swagger2/public/ace.js000644 000765 000024 00002307613 12645227324 021111 0ustar00jhthorsenstaff000000 000000 /* ***** BEGIN LICENSE BLOCK ***** * Distributed under the BSD license: * * Copyright (c) 2010, Ajax.org B.V. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Ajax.org B.V. nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * ***** END LICENSE BLOCK ***** */ /** * Define a module along with a payload * @param module a name for the payload * @param payload a function to call with (require, exports, module) params */ (function() { var ACE_NAMESPACE = "ace"; var global = (function() { return this; })(); if (!ACE_NAMESPACE && typeof requirejs !== "undefined") return; var _define = function(module, deps, payload) { if (typeof module !== 'string') { if (_define.original) _define.original.apply(window, arguments); else { console.error('dropping module because define wasn\'t a string.'); console.trace(); } return; } if (arguments.length == 2) payload = deps; if (!_define.modules) { _define.modules = {}; _define.payloads = {}; } _define.payloads[module] = payload; _define.modules[module] = null; }; /** * Get at functionality ace.define()ed using the function above */ var _require = function(parentId, module, callback) { if (Object.prototype.toString.call(module) === "[object Array]") { var params = []; for (var i = 0, l = module.length; i < l; ++i) { var dep = lookup(parentId, module[i]); if (!dep && _require.original) return _require.original.apply(window, arguments); params.push(dep); } if (callback) { callback.apply(null, params); } } else if (typeof module === 'string') { var payload = lookup(parentId, module); if (!payload && _require.original) return _require.original.apply(window, arguments); if (callback) { callback(); } return payload; } else { if (_require.original) return _require.original.apply(window, arguments); } }; var normalizeModule = function(parentId, moduleName) { // normalize plugin requires if (moduleName.indexOf("!") !== -1) { var chunks = moduleName.split("!"); return normalizeModule(parentId, chunks[0]) + "!" + normalizeModule(parentId, chunks[1]); } // normalize relative requires if (moduleName.charAt(0) == ".") { var base = parentId.split("/").slice(0, -1).join("/"); moduleName = base + "/" + moduleName; while(moduleName.indexOf(".") !== -1 && previous != moduleName) { var previous = moduleName; moduleName = moduleName.replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, ""); } } return moduleName; }; /** * Internal function to lookup moduleNames and resolve them by calling the * definition function if needed. */ var lookup = function(parentId, moduleName) { moduleName = normalizeModule(parentId, moduleName); var module = _define.modules[moduleName]; if (!module) { module = _define.payloads[moduleName]; if (typeof module === 'function') { var exports = {}; var mod = { id: moduleName, uri: '', exports: exports, packaged: true }; var req = function(module, callback) { return _require(moduleName, module, callback); }; var returnValue = module(req, exports, mod); exports = returnValue || mod.exports; _define.modules[moduleName] = exports; delete _define.payloads[moduleName]; } module = _define.modules[moduleName] = exports || module; } return module; }; function exportAce(ns) { var require = function(module, callback) { return _require("", module, callback); }; var root = global; if (ns) { if (!global[ns]) global[ns] = {}; root = global[ns]; } if (!root.define || !root.define.packaged) { _define.original = root.define; root.define = _define; root.define.packaged = true; } if (!root.require || !root.require.packaged) { _require.original = root.require; root.require = require; root.require.packaged = true; } } exportAce(ACE_NAMESPACE); })(); ace.define("ace/lib/regexp",["require","exports","module"], function(require, exports, module) { "use strict"; var real = { exec: RegExp.prototype.exec, test: RegExp.prototype.test, match: String.prototype.match, replace: String.prototype.replace, split: String.prototype.split }, compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups compliantLastIndexIncrement = function () { var x = /^/g; real.test.call(x, ""); return !x.lastIndex; }(); if (compliantLastIndexIncrement && compliantExecNpcg) return; RegExp.prototype.exec = function (str) { var match = real.exec.apply(this, arguments), name, r2; if ( typeof(str) == 'string' && match) { if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) { r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", "")); real.replace.call(str.slice(match.index), r2, function () { for (var i = 1; i < arguments.length - 2; i++) { if (arguments[i] === undefined) match[i] = undefined; } }); } if (this._xregexp && this._xregexp.captureNames) { for (var i = 1; i < match.length; i++) { name = this._xregexp.captureNames[i - 1]; if (name) match[name] = match[i]; } } if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index)) this.lastIndex--; } return match; }; if (!compliantLastIndexIncrement) { RegExp.prototype.test = function (str) { var match = real.exec.call(this, str); if (match && this.global && !match[0].length && (this.lastIndex > match.index)) this.lastIndex--; return !!match; }; } function getNativeFlags (regex) { return (regex.global ? "g" : "") + (regex.ignoreCase ? "i" : "") + (regex.multiline ? "m" : "") + (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3 (regex.sticky ? "y" : ""); } function indexOf (array, item, from) { if (Array.prototype.indexOf) // Use the native array method if available return array.indexOf(item, from); for (var i = from || 0; i < array.length; i++) { if (array[i] === item) return i; } return -1; } }); ace.define("ace/lib/es5-shim",["require","exports","module"], function(require, exports, module) { function Empty() {} if (!Function.prototype.bind) { Function.prototype.bind = function bind(that) { // .length is 1 var target = this; if (typeof target != "function") { throw new TypeError("Function.prototype.bind called on incompatible " + target); } var args = slice.call(arguments, 1); // for normal call var bound = function () { if (this instanceof bound) { var result = target.apply( this, args.concat(slice.call(arguments)) ); if (Object(result) === result) { return result; } return this; } else { return target.apply( that, args.concat(slice.call(arguments)) ); } }; if(target.prototype) { Empty.prototype = target.prototype; bound.prototype = new Empty(); Empty.prototype = null; } return bound; }; } var call = Function.prototype.call; var prototypeOfArray = Array.prototype; var prototypeOfObject = Object.prototype; var slice = prototypeOfArray.slice; var _toString = call.bind(prototypeOfObject.toString); var owns = call.bind(prototypeOfObject.hasOwnProperty); var defineGetter; var defineSetter; var lookupGetter; var lookupSetter; var supportsAccessors; if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) { defineGetter = call.bind(prototypeOfObject.__defineGetter__); defineSetter = call.bind(prototypeOfObject.__defineSetter__); lookupGetter = call.bind(prototypeOfObject.__lookupGetter__); lookupSetter = call.bind(prototypeOfObject.__lookupSetter__); } if ([1,2].splice(0).length != 2) { if(function() { // test IE < 9 to splice bug - see issue #138 function makeArray(l) { var a = new Array(l+2); a[0] = a[1] = 0; return a; } var array = [], lengthBefore; array.splice.apply(array, makeArray(20)); array.splice.apply(array, makeArray(26)); lengthBefore = array.length; //46 array.splice(5, 0, "XXX"); // add one element lengthBefore + 1 == array.length if (lengthBefore + 1 == array.length) { return true;// has right splice implementation without bugs } }()) {//IE 6/7 var array_splice = Array.prototype.splice; Array.prototype.splice = function(start, deleteCount) { if (!arguments.length) { return []; } else { return array_splice.apply(this, [ start === void 0 ? 0 : start, deleteCount === void 0 ? (this.length - start) : deleteCount ].concat(slice.call(arguments, 2))) } }; } else {//IE8 Array.prototype.splice = function(pos, removeCount){ var length = this.length; if (pos > 0) { if (pos > length) pos = length; } else if (pos == void 0) { pos = 0; } else if (pos < 0) { pos = Math.max(length + pos, 0); } if (!(pos+removeCount < length)) removeCount = length - pos; var removed = this.slice(pos, pos+removeCount); var insert = slice.call(arguments, 2); var add = insert.length; if (pos === length) { if (add) { this.push.apply(this, insert); } } else { var remove = Math.min(removeCount, length - pos); var tailOldPos = pos + remove; var tailNewPos = tailOldPos + add - remove; var tailCount = length - tailOldPos; var lengthAfterRemove = length - remove; if (tailNewPos < tailOldPos) { // case A for (var i = 0; i < tailCount; ++i) { this[tailNewPos+i] = this[tailOldPos+i]; } } else if (tailNewPos > tailOldPos) { // case B for (i = tailCount; i--; ) { this[tailNewPos+i] = this[tailOldPos+i]; } } // else, add == remove (nothing to do) if (add && pos === lengthAfterRemove) { this.length = lengthAfterRemove; // truncate array this.push.apply(this, insert); } else { this.length = lengthAfterRemove + add; // reserves space for (i = 0; i < add; ++i) { this[pos+i] = insert[i]; } } } return removed; }; } } if (!Array.isArray) { Array.isArray = function isArray(obj) { return _toString(obj) == "[object Array]"; }; } var boxedString = Object("a"), splitString = boxedString[0] != "a" || !(0 in boxedString); if (!Array.prototype.forEach) { Array.prototype.forEach = function forEach(fun /*, thisp*/) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, thisp = arguments[1], i = -1, length = self.length >>> 0; if (_toString(fun) != "[object Function]") { throw new TypeError(); // TODO message } while (++i < length) { if (i in self) { fun.call(thisp, self[i], i, object); } } }; } if (!Array.prototype.map) { Array.prototype.map = function map(fun /*, thisp*/) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, length = self.length >>> 0, result = Array(length), thisp = arguments[1]; if (_toString(fun) != "[object Function]") { throw new TypeError(fun + " is not a function"); } for (var i = 0; i < length; i++) { if (i in self) result[i] = fun.call(thisp, self[i], i, object); } return result; }; } if (!Array.prototype.filter) { Array.prototype.filter = function filter(fun /*, thisp */) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, length = self.length >>> 0, result = [], value, thisp = arguments[1]; if (_toString(fun) != "[object Function]") { throw new TypeError(fun + " is not a function"); } for (var i = 0; i < length; i++) { if (i in self) { value = self[i]; if (fun.call(thisp, value, i, object)) { result.push(value); } } } return result; }; } if (!Array.prototype.every) { Array.prototype.every = function every(fun /*, thisp */) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, length = self.length >>> 0, thisp = arguments[1]; if (_toString(fun) != "[object Function]") { throw new TypeError(fun + " is not a function"); } for (var i = 0; i < length; i++) { if (i in self && !fun.call(thisp, self[i], i, object)) { return false; } } return true; }; } if (!Array.prototype.some) { Array.prototype.some = function some(fun /*, thisp */) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, length = self.length >>> 0, thisp = arguments[1]; if (_toString(fun) != "[object Function]") { throw new TypeError(fun + " is not a function"); } for (var i = 0; i < length; i++) { if (i in self && fun.call(thisp, self[i], i, object)) { return true; } } return false; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function reduce(fun /*, initial*/) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, length = self.length >>> 0; if (_toString(fun) != "[object Function]") { throw new TypeError(fun + " is not a function"); } if (!length && arguments.length == 1) { throw new TypeError("reduce of empty array with no initial value"); } var i = 0; var result; if (arguments.length >= 2) { result = arguments[1]; } else { do { if (i in self) { result = self[i++]; break; } if (++i >= length) { throw new TypeError("reduce of empty array with no initial value"); } } while (true); } for (; i < length; i++) { if (i in self) { result = fun.call(void 0, result, self[i], i, object); } } return result; }; } if (!Array.prototype.reduceRight) { Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, length = self.length >>> 0; if (_toString(fun) != "[object Function]") { throw new TypeError(fun + " is not a function"); } if (!length && arguments.length == 1) { throw new TypeError("reduceRight of empty array with no initial value"); } var result, i = length - 1; if (arguments.length >= 2) { result = arguments[1]; } else { do { if (i in self) { result = self[i--]; break; } if (--i < 0) { throw new TypeError("reduceRight of empty array with no initial value"); } } while (true); } do { if (i in this) { result = fun.call(void 0, result, self[i], i, object); } } while (i--); return result; }; } if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) { Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) { var self = splitString && _toString(this) == "[object String]" ? this.split("") : toObject(this), length = self.length >>> 0; if (!length) { return -1; } var i = 0; if (arguments.length > 1) { i = toInteger(arguments[1]); } i = i >= 0 ? i : Math.max(0, length + i); for (; i < length; i++) { if (i in self && self[i] === sought) { return i; } } return -1; }; } if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) { Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) { var self = splitString && _toString(this) == "[object String]" ? this.split("") : toObject(this), length = self.length >>> 0; if (!length) { return -1; } var i = length - 1; if (arguments.length > 1) { i = Math.min(i, toInteger(arguments[1])); } i = i >= 0 ? i : length - Math.abs(i); for (; i >= 0; i--) { if (i in self && sought === self[i]) { return i; } } return -1; }; } if (!Object.getPrototypeOf) { Object.getPrototypeOf = function getPrototypeOf(object) { return object.__proto__ || ( object.constructor ? object.constructor.prototype : prototypeOfObject ); }; } if (!Object.getOwnPropertyDescriptor) { var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " + "non-object: "; Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) { if ((typeof object != "object" && typeof object != "function") || object === null) throw new TypeError(ERR_NON_OBJECT + object); if (!owns(object, property)) return; var descriptor, getter, setter; descriptor = { enumerable: true, configurable: true }; if (supportsAccessors) { var prototype = object.__proto__; object.__proto__ = prototypeOfObject; var getter = lookupGetter(object, property); var setter = lookupSetter(object, property); object.__proto__ = prototype; if (getter || setter) { if (getter) descriptor.get = getter; if (setter) descriptor.set = setter; return descriptor; } } descriptor.value = object[property]; return descriptor; }; } if (!Object.getOwnPropertyNames) { Object.getOwnPropertyNames = function getOwnPropertyNames(object) { return Object.keys(object); }; } if (!Object.create) { var createEmpty; if (Object.prototype.__proto__ === null) { createEmpty = function () { return { "__proto__": null }; }; } else { createEmpty = function () { var empty = {}; for (var i in empty) empty[i] = null; empty.constructor = empty.hasOwnProperty = empty.propertyIsEnumerable = empty.isPrototypeOf = empty.toLocaleString = empty.toString = empty.valueOf = empty.__proto__ = null; return empty; } } Object.create = function create(prototype, properties) { var object; if (prototype === null) { object = createEmpty(); } else { if (typeof prototype != "object") throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'"); var Type = function () {}; Type.prototype = prototype; object = new Type(); object.__proto__ = prototype; } if (properties !== void 0) Object.defineProperties(object, properties); return object; }; } function doesDefinePropertyWork(object) { try { Object.defineProperty(object, "sentinel", {}); return "sentinel" in object; } catch (exception) { } } if (Object.defineProperty) { var definePropertyWorksOnObject = doesDefinePropertyWork({}); var definePropertyWorksOnDom = typeof document == "undefined" || doesDefinePropertyWork(document.createElement("div")); if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { var definePropertyFallback = Object.defineProperty; } } if (!Object.defineProperty || definePropertyFallback) { var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: "; var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: " var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " + "on this javascript engine"; Object.defineProperty = function defineProperty(object, property, descriptor) { if ((typeof object != "object" && typeof object != "function") || object === null) throw new TypeError(ERR_NON_OBJECT_TARGET + object); if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor); if (definePropertyFallback) { try { return definePropertyFallback.call(Object, object, property, descriptor); } catch (exception) { } } if (owns(descriptor, "value")) { if (supportsAccessors && (lookupGetter(object, property) || lookupSetter(object, property))) { var prototype = object.__proto__; object.__proto__ = prototypeOfObject; delete object[property]; object[property] = descriptor.value; object.__proto__ = prototype; } else { object[property] = descriptor.value; } } else { if (!supportsAccessors) throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); if (owns(descriptor, "get")) defineGetter(object, property, descriptor.get); if (owns(descriptor, "set")) defineSetter(object, property, descriptor.set); } return object; }; } if (!Object.defineProperties) { Object.defineProperties = function defineProperties(object, properties) { for (var property in properties) { if (owns(properties, property)) Object.defineProperty(object, property, properties[property]); } return object; }; } if (!Object.seal) { Object.seal = function seal(object) { return object; }; } if (!Object.freeze) { Object.freeze = function freeze(object) { return object; }; } try { Object.freeze(function () {}); } catch (exception) { Object.freeze = (function freeze(freezeObject) { return function freeze(object) { if (typeof object == "function") { return object; } else { return freezeObject(object); } }; })(Object.freeze); } if (!Object.preventExtensions) { Object.preventExtensions = function preventExtensions(object) { return object; }; } if (!Object.isSealed) { Object.isSealed = function isSealed(object) { return false; }; } if (!Object.isFrozen) { Object.isFrozen = function isFrozen(object) { return false; }; } if (!Object.isExtensible) { Object.isExtensible = function isExtensible(object) { if (Object(object) === object) { throw new TypeError(); // TODO message } var name = ''; while (owns(object, name)) { name += '?'; } object[name] = true; var returnValue = owns(object, name); delete object[name]; return returnValue; }; } if (!Object.keys) { var hasDontEnumBug = true, dontEnums = [ "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "constructor" ], dontEnumsLength = dontEnums.length; for (var key in {"toString": null}) { hasDontEnumBug = false; } Object.keys = function keys(object) { if ( (typeof object != "object" && typeof object != "function") || object === null ) { throw new TypeError("Object.keys called on a non-object"); } var keys = []; for (var name in object) { if (owns(object, name)) { keys.push(name); } } if (hasDontEnumBug) { for (var i = 0, ii = dontEnumsLength; i < ii; i++) { var dontEnum = dontEnums[i]; if (owns(object, dontEnum)) { keys.push(dontEnum); } } } return keys; }; } if (!Date.now) { Date.now = function now() { return new Date().getTime(); }; } var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" + "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + "\u2029\uFEFF"; if (!String.prototype.trim || ws.trim()) { ws = "[" + ws + "]"; var trimBeginRegexp = new RegExp("^" + ws + ws + "*"), trimEndRegexp = new RegExp(ws + ws + "*$"); String.prototype.trim = function trim() { return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, ""); }; } function toInteger(n) { n = +n; if (n !== n) { // isNaN n = 0; } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) { n = (n > 0 || -1) * Math.floor(Math.abs(n)); } return n; } function isPrimitive(input) { var type = typeof input; return ( input === null || type === "undefined" || type === "boolean" || type === "number" || type === "string" ); } function toPrimitive(input) { var val, valueOf, toString; if (isPrimitive(input)) { return input; } valueOf = input.valueOf; if (typeof valueOf === "function") { val = valueOf.call(input); if (isPrimitive(val)) { return val; } } toString = input.toString; if (typeof toString === "function") { val = toString.call(input); if (isPrimitive(val)) { return val; } } throw new TypeError(); } var toObject = function (o) { if (o == null) { // this matches both null and undefined throw new TypeError("can't convert "+o+" to object"); } return Object(o); }; }); ace.define("ace/lib/fixoldbrowsers",["require","exports","module","ace/lib/regexp","ace/lib/es5-shim"], function(require, exports, module) { "use strict"; require("./regexp"); require("./es5-shim"); }); ace.define("ace/lib/dom",["require","exports","module"], function(require, exports, module) { "use strict"; if (typeof document == "undefined") return; var XHTML_NS = "http://www.w3.org/1999/xhtml"; exports.getDocumentHead = function(doc) { if (!doc) doc = document; return doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement; } exports.createElement = function(tag, ns) { return document.createElementNS ? document.createElementNS(ns || XHTML_NS, tag) : document.createElement(tag); }; exports.hasCssClass = function(el, name) { var classes = (el.className || "").split(/\s+/g); return classes.indexOf(name) !== -1; }; exports.addCssClass = function(el, name) { if (!exports.hasCssClass(el, name)) { el.className += " " + name; } }; exports.removeCssClass = function(el, name) { var classes = el.className.split(/\s+/g); while (true) { var index = classes.indexOf(name); if (index == -1) { break; } classes.splice(index, 1); } el.className = classes.join(" "); }; exports.toggleCssClass = function(el, name) { var classes = el.className.split(/\s+/g), add = true; while (true) { var index = classes.indexOf(name); if (index == -1) { break; } add = false; classes.splice(index, 1); } if(add) classes.push(name); el.className = classes.join(" "); return add; }; exports.setCssClass = function(node, className, include) { if (include) { exports.addCssClass(node, className); } else { exports.removeCssClass(node, className); } }; exports.hasCssString = function(id, doc) { var index = 0, sheets; doc = doc || document; if (doc.createStyleSheet && (sheets = doc.styleSheets)) { while (index < sheets.length) if (sheets[index++].owningElement.id === id) return true; } else if ((sheets = doc.getElementsByTagName("style"))) { while (index < sheets.length) if (sheets[index++].id === id) return true; } return false; }; exports.importCssString = function importCssString(cssText, id, doc) { doc = doc || document; if (id && exports.hasCssString(id, doc)) return null; var style; if (doc.createStyleSheet) { style = doc.createStyleSheet(); style.cssText = cssText; if (id) style.owningElement.id = id; } else { style = doc.createElementNS ? doc.createElementNS(XHTML_NS, "style") : doc.createElement("style"); style.appendChild(doc.createTextNode(cssText)); if (id) style.id = id; exports.getDocumentHead(doc).appendChild(style); } }; exports.importCssStylsheet = function(uri, doc) { if (doc.createStyleSheet) { doc.createStyleSheet(uri); } else { var link = exports.createElement('link'); link.rel = 'stylesheet'; link.href = uri; exports.getDocumentHead(doc).appendChild(link); } }; exports.getInnerWidth = function(element) { return ( parseInt(exports.computedStyle(element, "paddingLeft"), 10) + parseInt(exports.computedStyle(element, "paddingRight"), 10) + element.clientWidth ); }; exports.getInnerHeight = function(element) { return ( parseInt(exports.computedStyle(element, "paddingTop"), 10) + parseInt(exports.computedStyle(element, "paddingBottom"), 10) + element.clientHeight ); }; if (window.pageYOffset !== undefined) { exports.getPageScrollTop = function() { return window.pageYOffset; }; exports.getPageScrollLeft = function() { return window.pageXOffset; }; } else { exports.getPageScrollTop = function() { return document.body.scrollTop; }; exports.getPageScrollLeft = function() { return document.body.scrollLeft; }; } if (window.getComputedStyle) exports.computedStyle = function(element, style) { if (style) return (window.getComputedStyle(element, "") || {})[style] || ""; return window.getComputedStyle(element, "") || {}; }; else exports.computedStyle = function(element, style) { if (style) return element.currentStyle[style]; return element.currentStyle; }; exports.scrollbarWidth = function(document) { var inner = exports.createElement("ace_inner"); inner.style.width = "100%"; inner.style.minWidth = "0px"; inner.style.height = "200px"; inner.style.display = "block"; var outer = exports.createElement("ace_outer"); var style = outer.style; style.position = "absolute"; style.left = "-10000px"; style.overflow = "hidden"; style.width = "200px"; style.minWidth = "0px"; style.height = "150px"; style.display = "block"; outer.appendChild(inner); var body = document.documentElement; body.appendChild(outer); var noScrollbar = inner.offsetWidth; style.overflow = "scroll"; var withScrollbar = inner.offsetWidth; if (noScrollbar == withScrollbar) { withScrollbar = outer.clientWidth; } body.removeChild(outer); return noScrollbar-withScrollbar; }; exports.setInnerHtml = function(el, innerHtml) { var element = el.cloneNode(false);//document.createElement("div"); element.innerHTML = innerHtml; el.parentNode.replaceChild(element, el); return element; }; if ("textContent" in document.documentElement) { exports.setInnerText = function(el, innerText) { el.textContent = innerText; }; exports.getInnerText = function(el) { return el.textContent; }; } else { exports.setInnerText = function(el, innerText) { el.innerText = innerText; }; exports.getInnerText = function(el) { return el.innerText; }; } exports.getParentWindow = function(document) { return document.defaultView || document.parentWindow; }; }); ace.define("ace/lib/oop",["require","exports","module"], function(require, exports, module) { "use strict"; exports.inherits = function(ctor, superCtor) { ctor.super_ = superCtor; ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }); }; exports.mixin = function(obj, mixin) { for (var key in mixin) { obj[key] = mixin[key]; } return obj; }; exports.implement = function(proto, mixin) { exports.mixin(proto, mixin); }; }); ace.define("ace/lib/keys",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/oop"], function(require, exports, module) { "use strict"; require("./fixoldbrowsers"); var oop = require("./oop"); var Keys = (function() { var ret = { MODIFIER_KEYS: { 16: 'Shift', 17: 'Ctrl', 18: 'Alt', 224: 'Meta' }, KEY_MODS: { "ctrl": 1, "alt": 2, "option" : 2, "shift": 4, "super": 8, "meta": 8, "command": 8, "cmd": 8 }, FUNCTION_KEYS : { 8 : "Backspace", 9 : "Tab", 13 : "Return", 19 : "Pause", 27 : "Esc", 32 : "Space", 33 : "PageUp", 34 : "PageDown", 35 : "End", 36 : "Home", 37 : "Left", 38 : "Up", 39 : "Right", 40 : "Down", 44 : "Print", 45 : "Insert", 46 : "Delete", 96 : "Numpad0", 97 : "Numpad1", 98 : "Numpad2", 99 : "Numpad3", 100: "Numpad4", 101: "Numpad5", 102: "Numpad6", 103: "Numpad7", 104: "Numpad8", 105: "Numpad9", '-13': "NumpadEnter", 112: "F1", 113: "F2", 114: "F3", 115: "F4", 116: "F5", 117: "F6", 118: "F7", 119: "F8", 120: "F9", 121: "F10", 122: "F11", 123: "F12", 144: "Numlock", 145: "Scrolllock" }, PRINTABLE_KEYS: { 32: ' ', 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5', 54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 61: '=', 65: 'a', 66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h', 73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o', 80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v', 87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.', 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`', 219: '[', 220: '\\',221: ']', 222: '\'' } }; var name, i; for (i in ret.FUNCTION_KEYS) { name = ret.FUNCTION_KEYS[i].toLowerCase(); ret[name] = parseInt(i, 10); } for (i in ret.PRINTABLE_KEYS) { name = ret.PRINTABLE_KEYS[i].toLowerCase(); ret[name] = parseInt(i, 10); } oop.mixin(ret, ret.MODIFIER_KEYS); oop.mixin(ret, ret.PRINTABLE_KEYS); oop.mixin(ret, ret.FUNCTION_KEYS); ret.enter = ret["return"]; ret.escape = ret.esc; ret.del = ret["delete"]; ret[173] = '-'; (function() { var mods = ["cmd", "ctrl", "alt", "shift"]; for (var i = Math.pow(2, mods.length); i--;) { ret.KEY_MODS[i] = mods.filter(function(x) { return i & ret.KEY_MODS[x]; }).join("-") + "-"; } })(); ret.KEY_MODS[0] = ""; ret.KEY_MODS[-1] = "input"; return ret; })(); oop.mixin(exports, Keys); exports.keyCodeToString = function(keyCode) { var keyString = Keys[keyCode]; if (typeof keyString != "string") keyString = String.fromCharCode(keyCode); return keyString.toLowerCase(); }; }); ace.define("ace/lib/useragent",["require","exports","module"], function(require, exports, module) { "use strict"; exports.OS = { LINUX: "LINUX", MAC: "MAC", WINDOWS: "WINDOWS" }; exports.getOS = function() { if (exports.isMac) { return exports.OS.MAC; } else if (exports.isLinux) { return exports.OS.LINUX; } else { return exports.OS.WINDOWS; } }; if (typeof navigator != "object") return; var os = (navigator.platform.match(/mac|win|linux/i) || ["other"])[0].toLowerCase(); var ua = navigator.userAgent; exports.isWin = (os == "win"); exports.isMac = (os == "mac"); exports.isLinux = (os == "linux"); exports.isIE = (navigator.appName == "Microsoft Internet Explorer" || navigator.appName.indexOf("MSAppHost") >= 0) ? parseFloat((ua.match(/(?:MSIE |Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]) : parseFloat((ua.match(/(?:Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]); // for ie exports.isOldIE = exports.isIE && exports.isIE < 9; exports.isGecko = exports.isMozilla = (window.Controllers || window.controllers) && window.navigator.product === "Gecko"; exports.isOldGecko = exports.isGecko && parseInt((ua.match(/rv\:(\d+)/)||[])[1], 10) < 4; exports.isOpera = window.opera && Object.prototype.toString.call(window.opera) == "[object Opera]"; exports.isWebKit = parseFloat(ua.split("WebKit/")[1]) || undefined; exports.isChrome = parseFloat(ua.split(" Chrome/")[1]) || undefined; exports.isAIR = ua.indexOf("AdobeAIR") >= 0; exports.isIPad = ua.indexOf("iPad") >= 0; exports.isTouchPad = ua.indexOf("TouchPad") >= 0; exports.isChromeOS = ua.indexOf(" CrOS ") >= 0; }); ace.define("ace/lib/event",["require","exports","module","ace/lib/keys","ace/lib/useragent"], function(require, exports, module) { "use strict"; var keys = require("./keys"); var useragent = require("./useragent"); exports.addListener = function(elem, type, callback) { if (elem.addEventListener) { return elem.addEventListener(type, callback, false); } if (elem.attachEvent) { var wrapper = function() { callback.call(elem, window.event); }; callback._wrapper = wrapper; elem.attachEvent("on" + type, wrapper); } }; exports.removeListener = function(elem, type, callback) { if (elem.removeEventListener) { return elem.removeEventListener(type, callback, false); } if (elem.detachEvent) { elem.detachEvent("on" + type, callback._wrapper || callback); } }; exports.stopEvent = function(e) { exports.stopPropagation(e); exports.preventDefault(e); return false; }; exports.stopPropagation = function(e) { if (e.stopPropagation) e.stopPropagation(); else e.cancelBubble = true; }; exports.preventDefault = function(e) { if (e.preventDefault) e.preventDefault(); else e.returnValue = false; }; exports.getButton = function(e) { if (e.type == "dblclick") return 0; if (e.type == "contextmenu" || (useragent.isMac && (e.ctrlKey && !e.altKey && !e.shiftKey))) return 2; if (e.preventDefault) { return e.button; } else { return {1:0, 2:2, 4:1}[e.button]; } }; exports.capture = function(el, eventHandler, releaseCaptureHandler) { function onMouseUp(e) { eventHandler && eventHandler(e); releaseCaptureHandler && releaseCaptureHandler(e); exports.removeListener(document, "mousemove", eventHandler, true); exports.removeListener(document, "mouseup", onMouseUp, true); exports.removeListener(document, "dragstart", onMouseUp, true); } exports.addListener(document, "mousemove", eventHandler, true); exports.addListener(document, "mouseup", onMouseUp, true); exports.addListener(document, "dragstart", onMouseUp, true); return onMouseUp; }; exports.addMouseWheelListener = function(el, callback) { if ("onmousewheel" in el) { exports.addListener(el, "mousewheel", function(e) { var factor = 8; if (e.wheelDeltaX !== undefined) { e.wheelX = -e.wheelDeltaX / factor; e.wheelY = -e.wheelDeltaY / factor; } else { e.wheelX = 0; e.wheelY = -e.wheelDelta / factor; } callback(e); }); } else if ("onwheel" in el) { exports.addListener(el, "wheel", function(e) { var factor = 0.35; switch (e.deltaMode) { case e.DOM_DELTA_PIXEL: e.wheelX = e.deltaX * factor || 0; e.wheelY = e.deltaY * factor || 0; break; case e.DOM_DELTA_LINE: case e.DOM_DELTA_PAGE: e.wheelX = (e.deltaX || 0) * 5; e.wheelY = (e.deltaY || 0) * 5; break; } callback(e); }); } else { exports.addListener(el, "DOMMouseScroll", function(e) { if (e.axis && e.axis == e.HORIZONTAL_AXIS) { e.wheelX = (e.detail || 0) * 5; e.wheelY = 0; } else { e.wheelX = 0; e.wheelY = (e.detail || 0) * 5; } callback(e); }); } }; exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbackName) { var clicks = 0; var startX, startY, timer; var eventNames = { 2: "dblclick", 3: "tripleclick", 4: "quadclick" }; exports.addListener(el, "mousedown", function(e) { if (exports.getButton(e) !== 0) { clicks = 0; } else if (e.detail > 1) { clicks++; if (clicks > 4) clicks = 1; } else { clicks = 1; } if (useragent.isIE) { var isNewClick = Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5; if (!timer || isNewClick) clicks = 1; if (timer) clearTimeout(timer); timer = setTimeout(function() {timer = null}, timeouts[clicks - 1] || 600); if (clicks == 1) { startX = e.clientX; startY = e.clientY; } } e._clicks = clicks; eventHandler[callbackName]("mousedown", e); if (clicks > 4) clicks = 0; else if (clicks > 1) return eventHandler[callbackName](eventNames[clicks], e); }); if (useragent.isOldIE) { exports.addListener(el, "dblclick", function(e) { clicks = 2; if (timer) clearTimeout(timer); timer = setTimeout(function() {timer = null}, timeouts[clicks - 1] || 600); eventHandler[callbackName]("mousedown", e); eventHandler[callbackName](eventNames[clicks], e); }); } }; var getModifierHash = useragent.isMac && useragent.isOpera && !("KeyboardEvent" in window) ? function(e) { return 0 | (e.metaKey ? 1 : 0) | (e.altKey ? 2 : 0) | (e.shiftKey ? 4 : 0) | (e.ctrlKey ? 8 : 0); } : function(e) { return 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0) | (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0); }; exports.getModifierString = function(e) { return keys.KEY_MODS[getModifierHash(e)]; }; function normalizeCommandKeys(callback, e, keyCode) { var hashId = getModifierHash(e); if (!useragent.isMac && pressedKeys) { if (pressedKeys[91] || pressedKeys[92]) hashId |= 8; if (pressedKeys.altGr) { if ((3 & hashId) != 3) pressedKeys.altGr = 0; else return; } if (keyCode === 18 || keyCode === 17) { var location = "location" in e ? e.location : e.keyLocation; if (keyCode === 17 && location === 1) { ts = e.timeStamp; } else if (keyCode === 18 && hashId === 3 && location === 2) { var dt = -ts; ts = e.timeStamp; dt += ts; if (dt < 3) pressedKeys.altGr = true; } } } if (keyCode in keys.MODIFIER_KEYS) { switch (keys.MODIFIER_KEYS[keyCode]) { case "Alt": hashId = 2; break; case "Shift": hashId = 4; break; case "Ctrl": hashId = 1; break; default: hashId = 8; break; } keyCode = -1; } if (hashId & 8 && (keyCode === 91 || keyCode === 93)) { keyCode = -1; } if (!hashId && keyCode === 13) { var location = "location" in e ? e.location : e.keyLocation; if (location === 3) { callback(e, hashId, -keyCode); if (e.defaultPrevented) return; } } if (useragent.isChromeOS && hashId & 8) { callback(e, hashId, keyCode); if (e.defaultPrevented) return; else hashId &= ~8; } if (!hashId && !(keyCode in keys.FUNCTION_KEYS) && !(keyCode in keys.PRINTABLE_KEYS)) { return false; } return callback(e, hashId, keyCode); } var pressedKeys = null; var ts = 0; exports.addCommandKeyListener = function(el, callback) { var addListener = exports.addListener; if (useragent.isOldGecko || (useragent.isOpera && !("KeyboardEvent" in window))) { var lastKeyDownKeyCode = null; addListener(el, "keydown", function(e) { lastKeyDownKeyCode = e.keyCode; }); addListener(el, "keypress", function(e) { return normalizeCommandKeys(callback, e, lastKeyDownKeyCode); }); } else { var lastDefaultPrevented = null; addListener(el, "keydown", function(e) { pressedKeys[e.keyCode] = true; var result = normalizeCommandKeys(callback, e, e.keyCode); lastDefaultPrevented = e.defaultPrevented; return result; }); addListener(el, "keypress", function(e) { if (lastDefaultPrevented && (e.ctrlKey || e.altKey || e.shiftKey || e.metaKey)) { exports.stopEvent(e); lastDefaultPrevented = null; } }); addListener(el, "keyup", function(e) { pressedKeys[e.keyCode] = null; }); if (!pressedKeys) { pressedKeys = Object.create(null); addListener(window, "focus", function(e) { pressedKeys = Object.create(null); }); } } }; if (window.postMessage && !useragent.isOldIE) { var postMessageId = 1; exports.nextTick = function(callback, win) { win = win || window; var messageName = "zero-timeout-message-" + postMessageId; exports.addListener(win, "message", function listener(e) { if (e.data == messageName) { exports.stopPropagation(e); exports.removeListener(win, "message", listener); callback(); } }); win.postMessage(messageName, "*"); }; } exports.nextFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame; if (exports.nextFrame) exports.nextFrame = exports.nextFrame.bind(window); else exports.nextFrame = function(callback) { setTimeout(callback, 17); }; }); ace.define("ace/lib/lang",["require","exports","module"], function(require, exports, module) { "use strict"; exports.last = function(a) { return a[a.length - 1]; }; exports.stringReverse = function(string) { return string.split("").reverse().join(""); }; exports.stringRepeat = function (string, count) { var result = ''; while (count > 0) { if (count & 1) result += string; if (count >>= 1) string += string; } return result; }; var trimBeginRegexp = /^\s\s*/; var trimEndRegexp = /\s\s*$/; exports.stringTrimLeft = function (string) { return string.replace(trimBeginRegexp, ''); }; exports.stringTrimRight = function (string) { return string.replace(trimEndRegexp, ''); }; exports.copyObject = function(obj) { var copy = {}; for (var key in obj) { copy[key] = obj[key]; } return copy; }; exports.copyArray = function(array){ var copy = []; for (var i=0, l=array.length; i 1); return ev.preventDefault(); }; this.startSelect = function(pos, waitForClickSelection) { pos = pos || this.editor.renderer.screenToTextCoordinates(this.x, this.y); var editor = this.editor; if (this.mousedownEvent.getShiftKey()) editor.selection.selectToPosition(pos); else if (!waitForClickSelection) editor.selection.moveToPosition(pos); if (!waitForClickSelection) this.select(); if (editor.renderer.scroller.setCapture) { editor.renderer.scroller.setCapture(); } editor.setStyle("ace_selecting"); this.setState("select"); }; this.select = function() { var anchor, editor = this.editor; var cursor = editor.renderer.screenToTextCoordinates(this.x, this.y); if (this.$clickSelection) { var cmp = this.$clickSelection.comparePoint(cursor); if (cmp == -1) { anchor = this.$clickSelection.end; } else if (cmp == 1) { anchor = this.$clickSelection.start; } else { var orientedRange = calcRangeOrientation(this.$clickSelection, cursor); cursor = orientedRange.cursor; anchor = orientedRange.anchor; } editor.selection.setSelectionAnchor(anchor.row, anchor.column); } editor.selection.selectToPosition(cursor); editor.renderer.scrollCursorIntoView(); }; this.extendSelectionBy = function(unitName) { var anchor, editor = this.editor; var cursor = editor.renderer.screenToTextCoordinates(this.x, this.y); var range = editor.selection[unitName](cursor.row, cursor.column); if (this.$clickSelection) { var cmpStart = this.$clickSelection.comparePoint(range.start); var cmpEnd = this.$clickSelection.comparePoint(range.end); if (cmpStart == -1 && cmpEnd <= 0) { anchor = this.$clickSelection.end; if (range.end.row != cursor.row || range.end.column != cursor.column) cursor = range.start; } else if (cmpEnd == 1 && cmpStart >= 0) { anchor = this.$clickSelection.start; if (range.start.row != cursor.row || range.start.column != cursor.column) cursor = range.end; } else if (cmpStart == -1 && cmpEnd == 1) { cursor = range.end; anchor = range.start; } else { var orientedRange = calcRangeOrientation(this.$clickSelection, cursor); cursor = orientedRange.cursor; anchor = orientedRange.anchor; } editor.selection.setSelectionAnchor(anchor.row, anchor.column); } editor.selection.selectToPosition(cursor); editor.renderer.scrollCursorIntoView(); }; this.selectEnd = this.selectAllEnd = this.selectByWordsEnd = this.selectByLinesEnd = function() { this.$clickSelection = null; this.editor.unsetStyle("ace_selecting"); if (this.editor.renderer.scroller.releaseCapture) { this.editor.renderer.scroller.releaseCapture(); } }; this.focusWait = function() { var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y); var time = Date.now(); if (distance > DRAG_OFFSET || time - this.mousedownEvent.time > this.$focusTimout) this.startSelect(this.mousedownEvent.getDocumentPosition()); }; this.onDoubleClick = function(ev) { var pos = ev.getDocumentPosition(); var editor = this.editor; var session = editor.session; var range = session.getBracketRange(pos); if (range) { if (range.isEmpty()) { range.start.column--; range.end.column++; } this.setState("select"); } else { range = editor.selection.getWordRange(pos.row, pos.column); this.setState("selectByWords"); } this.$clickSelection = range; this.select(); }; this.onTripleClick = function(ev) { var pos = ev.getDocumentPosition(); var editor = this.editor; this.setState("selectByLines"); var range = editor.getSelectionRange(); if (range.isMultiLine() && range.contains(pos.row, pos.column)) { this.$clickSelection = editor.selection.getLineRange(range.start.row); this.$clickSelection.end = editor.selection.getLineRange(range.end.row).end; } else { this.$clickSelection = editor.selection.getLineRange(pos.row); } this.select(); }; this.onQuadClick = function(ev) { var editor = this.editor; editor.selectAll(); this.$clickSelection = editor.getSelectionRange(); this.setState("selectAll"); }; this.onMouseWheel = function(ev) { if (ev.getAccelKey()) return; if (ev.getShiftKey() && ev.wheelY && !ev.wheelX) { ev.wheelX = ev.wheelY; ev.wheelY = 0; } var t = ev.domEvent.timeStamp; var dt = t - (this.$lastScrollTime||0); var editor = this.editor; var isScrolable = editor.renderer.isScrollableBy(ev.wheelX * ev.speed, ev.wheelY * ev.speed); if (isScrolable || dt < 200) { this.$lastScrollTime = t; editor.renderer.scrollBy(ev.wheelX * ev.speed, ev.wheelY * ev.speed); return ev.stop(); } }; }).call(DefaultHandlers.prototype); exports.DefaultHandlers = DefaultHandlers; function calcDistance(ax, ay, bx, by) { return Math.sqrt(Math.pow(bx - ax, 2) + Math.pow(by - ay, 2)); } function calcRangeOrientation(range, cursor) { if (range.start.row == range.end.row) var cmp = 2 * cursor.column - range.start.column - range.end.column; else if (range.start.row == range.end.row - 1 && !range.start.column && !range.end.column) var cmp = cursor.column - 4; else var cmp = 2 * cursor.row - range.start.row - range.end.row; if (cmp < 0) return {cursor: range.start, anchor: range.end}; else return {cursor: range.end, anchor: range.start}; } }); ace.define("ace/tooltip",["require","exports","module","ace/lib/oop","ace/lib/dom"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var dom = require("./lib/dom"); function Tooltip (parentNode) { this.isOpen = false; this.$element = null; this.$parentNode = parentNode; } (function() { this.$init = function() { this.$element = dom.createElement("div"); this.$element.className = "ace_tooltip"; this.$element.style.display = "none"; this.$parentNode.appendChild(this.$element); return this.$element; }; this.getElement = function() { return this.$element || this.$init(); }; this.setText = function(text) { dom.setInnerText(this.getElement(), text); }; this.setHtml = function(html) { this.getElement().innerHTML = html; }; this.setPosition = function(x, y) { this.getElement().style.left = x + "px"; this.getElement().style.top = y + "px"; }; this.setClassName = function(className) { dom.addCssClass(this.getElement(), className); }; this.show = function(text, x, y) { if (text != null) this.setText(text); if (x != null && y != null) this.setPosition(x, y); if (!this.isOpen) { this.getElement().style.display = "block"; this.isOpen = true; } }; this.hide = function() { if (this.isOpen) { this.getElement().style.display = "none"; this.isOpen = false; } }; this.getHeight = function() { return this.getElement().offsetHeight; }; this.getWidth = function() { return this.getElement().offsetWidth; }; }).call(Tooltip.prototype); exports.Tooltip = Tooltip; }); ace.define("ace/mouse/default_gutter_handler",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/event","ace/tooltip"], function(require, exports, module) { "use strict"; var dom = require("../lib/dom"); var oop = require("../lib/oop"); var event = require("../lib/event"); var Tooltip = require("../tooltip").Tooltip; function GutterHandler(mouseHandler) { var editor = mouseHandler.editor; var gutter = editor.renderer.$gutterLayer; var tooltip = new GutterTooltip(editor.container); mouseHandler.editor.setDefaultHandler("guttermousedown", function(e) { if (!editor.isFocused() || e.getButton() != 0) return; var gutterRegion = gutter.getRegion(e); if (gutterRegion == "foldWidgets") return; var row = e.getDocumentPosition().row; var selection = editor.session.selection; if (e.getShiftKey()) selection.selectTo(row, 0); else { if (e.domEvent.detail == 2) { editor.selectAll(); return e.preventDefault(); } mouseHandler.$clickSelection = editor.selection.getLineRange(row); } mouseHandler.setState("selectByLines"); mouseHandler.captureMouse(e); return e.preventDefault(); }); var tooltipTimeout, mouseEvent, tooltipAnnotation; function showTooltip() { var row = mouseEvent.getDocumentPosition().row; var annotation = gutter.$annotations[row]; if (!annotation) return hideTooltip(); var maxRow = editor.session.getLength(); if (row == maxRow) { var screenRow = editor.renderer.pixelToScreenCoordinates(0, mouseEvent.y).row; var pos = mouseEvent.$pos; if (screenRow > editor.session.documentToScreenRow(pos.row, pos.column)) return hideTooltip(); } if (tooltipAnnotation == annotation) return; tooltipAnnotation = annotation.text.join("
"); tooltip.setHtml(tooltipAnnotation); tooltip.show(); editor.on("mousewheel", hideTooltip); if (mouseHandler.$tooltipFollowsMouse) { moveTooltip(mouseEvent); } else { var gutterElement = gutter.$cells[editor.session.documentToScreenRow(row, 0)].element; var rect = gutterElement.getBoundingClientRect(); var style = tooltip.getElement().style; style.left = rect.right + "px"; style.top = rect.bottom + "px"; } } function hideTooltip() { if (tooltipTimeout) tooltipTimeout = clearTimeout(tooltipTimeout); if (tooltipAnnotation) { tooltip.hide(); tooltipAnnotation = null; editor.removeEventListener("mousewheel", hideTooltip); } } function moveTooltip(e) { tooltip.setPosition(e.x, e.y); } mouseHandler.editor.setDefaultHandler("guttermousemove", function(e) { var target = e.domEvent.target || e.domEvent.srcElement; if (dom.hasCssClass(target, "ace_fold-widget")) return hideTooltip(); if (tooltipAnnotation && mouseHandler.$tooltipFollowsMouse) moveTooltip(e); mouseEvent = e; if (tooltipTimeout) return; tooltipTimeout = setTimeout(function() { tooltipTimeout = null; if (mouseEvent && !mouseHandler.isMousePressed) showTooltip(); else hideTooltip(); }, 50); }); event.addListener(editor.renderer.$gutter, "mouseout", function(e) { mouseEvent = null; if (!tooltipAnnotation || tooltipTimeout) return; tooltipTimeout = setTimeout(function() { tooltipTimeout = null; hideTooltip(); }, 50); }); editor.on("changeSession", hideTooltip); } function GutterTooltip(parentNode) { Tooltip.call(this, parentNode); } oop.inherits(GutterTooltip, Tooltip); (function(){ this.setPosition = function(x, y) { var windowWidth = window.innerWidth || document.documentElement.clientWidth; var windowHeight = window.innerHeight || document.documentElement.clientHeight; var width = this.getWidth(); var height = this.getHeight(); x += 15; y += 15; if (x + width > windowWidth) { x -= (x + width) - windowWidth; } if (y + height > windowHeight) { y -= 20 + height; } Tooltip.prototype.setPosition.call(this, x, y); }; }).call(GutterTooltip.prototype); exports.GutterHandler = GutterHandler; }); ace.define("ace/mouse/mouse_event",["require","exports","module","ace/lib/event","ace/lib/useragent"], function(require, exports, module) { "use strict"; var event = require("../lib/event"); var useragent = require("../lib/useragent"); var MouseEvent = exports.MouseEvent = function(domEvent, editor) { this.domEvent = domEvent; this.editor = editor; this.x = this.clientX = domEvent.clientX; this.y = this.clientY = domEvent.clientY; this.$pos = null; this.$inSelection = null; this.propagationStopped = false; this.defaultPrevented = false; }; (function() { this.stopPropagation = function() { event.stopPropagation(this.domEvent); this.propagationStopped = true; }; this.preventDefault = function() { event.preventDefault(this.domEvent); this.defaultPrevented = true; }; this.stop = function() { this.stopPropagation(); this.preventDefault(); }; this.getDocumentPosition = function() { if (this.$pos) return this.$pos; this.$pos = this.editor.renderer.screenToTextCoordinates(this.clientX, this.clientY); return this.$pos; }; this.inSelection = function() { if (this.$inSelection !== null) return this.$inSelection; var editor = this.editor; var selectionRange = editor.getSelectionRange(); if (selectionRange.isEmpty()) this.$inSelection = false; else { var pos = this.getDocumentPosition(); this.$inSelection = selectionRange.contains(pos.row, pos.column); } return this.$inSelection; }; this.getButton = function() { return event.getButton(this.domEvent); }; this.getShiftKey = function() { return this.domEvent.shiftKey; }; this.getAccelKey = useragent.isMac ? function() { return this.domEvent.metaKey; } : function() { return this.domEvent.ctrlKey; }; }).call(MouseEvent.prototype); }); ace.define("ace/mouse/dragdrop_handler",["require","exports","module","ace/lib/dom","ace/lib/event","ace/lib/useragent"], function(require, exports, module) { "use strict"; var dom = require("../lib/dom"); var event = require("../lib/event"); var useragent = require("../lib/useragent"); var AUTOSCROLL_DELAY = 200; var SCROLL_CURSOR_DELAY = 200; var SCROLL_CURSOR_HYSTERESIS = 5; function DragdropHandler(mouseHandler) { var editor = mouseHandler.editor; var blankImage = dom.createElement("img"); blankImage.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; if (useragent.isOpera) blankImage.style.cssText = "width:1px;height:1px;position:fixed;top:0;left:0;z-index:2147483647;opacity:0;"; var exports = ["dragWait", "dragWaitEnd", "startDrag", "dragReadyEnd", "onMouseDrag"]; exports.forEach(function(x) { mouseHandler[x] = this[x]; }, this); editor.addEventListener("mousedown", this.onMouseDown.bind(mouseHandler)); var mouseTarget = editor.container; var dragSelectionMarker, x, y; var timerId, range; var dragCursor, counter = 0; var dragOperation; var isInternal; var autoScrollStartTime; var cursorMovedTime; var cursorPointOnCaretMoved; this.onDragStart = function(e) { if (this.cancelDrag || !mouseTarget.draggable) { var self = this; setTimeout(function(){ self.startSelect(); self.captureMouse(e); }, 0); return e.preventDefault(); } range = editor.getSelectionRange(); var dataTransfer = e.dataTransfer; dataTransfer.effectAllowed = editor.getReadOnly() ? "copy" : "copyMove"; if (useragent.isOpera) { editor.container.appendChild(blankImage); blankImage.scrollTop = 0; } dataTransfer.setDragImage && dataTransfer.setDragImage(blankImage, 0, 0); if (useragent.isOpera) { editor.container.removeChild(blankImage); } dataTransfer.clearData(); dataTransfer.setData("Text", editor.session.getTextRange()); isInternal = true; this.setState("drag"); }; this.onDragEnd = function(e) { mouseTarget.draggable = false; isInternal = false; this.setState(null); if (!editor.getReadOnly()) { var dropEffect = e.dataTransfer.dropEffect; if (!dragOperation && dropEffect == "move") editor.session.remove(editor.getSelectionRange()); editor.renderer.$cursorLayer.setBlinking(true); } this.editor.unsetStyle("ace_dragging"); this.editor.renderer.setCursorStyle(""); }; this.onDragEnter = function(e) { if (editor.getReadOnly() || !canAccept(e.dataTransfer)) return; x = e.clientX; y = e.clientY; if (!dragSelectionMarker) addDragMarker(); counter++; e.dataTransfer.dropEffect = dragOperation = getDropEffect(e); return event.preventDefault(e); }; this.onDragOver = function(e) { if (editor.getReadOnly() || !canAccept(e.dataTransfer)) return; x = e.clientX; y = e.clientY; if (!dragSelectionMarker) { addDragMarker(); counter++; } if (onMouseMoveTimer !== null) onMouseMoveTimer = null; e.dataTransfer.dropEffect = dragOperation = getDropEffect(e); return event.preventDefault(e); }; this.onDragLeave = function(e) { counter--; if (counter <= 0 && dragSelectionMarker) { clearDragMarker(); dragOperation = null; return event.preventDefault(e); } }; this.onDrop = function(e) { if (!dragCursor) return; var dataTransfer = e.dataTransfer; if (isInternal) { switch (dragOperation) { case "move": if (range.contains(dragCursor.row, dragCursor.column)) { range = { start: dragCursor, end: dragCursor }; } else { range = editor.moveText(range, dragCursor); } break; case "copy": range = editor.moveText(range, dragCursor, true); break; } } else { var dropData = dataTransfer.getData('Text'); range = { start: dragCursor, end: editor.session.insert(dragCursor, dropData) }; editor.focus(); dragOperation = null; } clearDragMarker(); return event.preventDefault(e); }; event.addListener(mouseTarget, "dragstart", this.onDragStart.bind(mouseHandler)); event.addListener(mouseTarget, "dragend", this.onDragEnd.bind(mouseHandler)); event.addListener(mouseTarget, "dragenter", this.onDragEnter.bind(mouseHandler)); event.addListener(mouseTarget, "dragover", this.onDragOver.bind(mouseHandler)); event.addListener(mouseTarget, "dragleave", this.onDragLeave.bind(mouseHandler)); event.addListener(mouseTarget, "drop", this.onDrop.bind(mouseHandler)); function scrollCursorIntoView(cursor, prevCursor) { var now = Date.now(); var vMovement = !prevCursor || cursor.row != prevCursor.row; var hMovement = !prevCursor || cursor.column != prevCursor.column; if (!cursorMovedTime || vMovement || hMovement) { editor.$blockScrolling += 1; editor.moveCursorToPosition(cursor); editor.$blockScrolling -= 1; cursorMovedTime = now; cursorPointOnCaretMoved = {x: x, y: y}; } else { var distance = calcDistance(cursorPointOnCaretMoved.x, cursorPointOnCaretMoved.y, x, y); if (distance > SCROLL_CURSOR_HYSTERESIS) { cursorMovedTime = null; } else if (now - cursorMovedTime >= SCROLL_CURSOR_DELAY) { editor.renderer.scrollCursorIntoView(); cursorMovedTime = null; } } } function autoScroll(cursor, prevCursor) { var now = Date.now(); var lineHeight = editor.renderer.layerConfig.lineHeight; var characterWidth = editor.renderer.layerConfig.characterWidth; var editorRect = editor.renderer.scroller.getBoundingClientRect(); var offsets = { x: { left: x - editorRect.left, right: editorRect.right - x }, y: { top: y - editorRect.top, bottom: editorRect.bottom - y } }; var nearestXOffset = Math.min(offsets.x.left, offsets.x.right); var nearestYOffset = Math.min(offsets.y.top, offsets.y.bottom); var scrollCursor = {row: cursor.row, column: cursor.column}; if (nearestXOffset / characterWidth <= 2) { scrollCursor.column += (offsets.x.left < offsets.x.right ? -3 : +2); } if (nearestYOffset / lineHeight <= 1) { scrollCursor.row += (offsets.y.top < offsets.y.bottom ? -1 : +1); } var vScroll = cursor.row != scrollCursor.row; var hScroll = cursor.column != scrollCursor.column; var vMovement = !prevCursor || cursor.row != prevCursor.row; if (vScroll || (hScroll && !vMovement)) { if (!autoScrollStartTime) autoScrollStartTime = now; else if (now - autoScrollStartTime >= AUTOSCROLL_DELAY) editor.renderer.scrollCursorIntoView(scrollCursor); } else { autoScrollStartTime = null; } } function onDragInterval() { var prevCursor = dragCursor; dragCursor = editor.renderer.screenToTextCoordinates(x, y); scrollCursorIntoView(dragCursor, prevCursor); autoScroll(dragCursor, prevCursor); } function addDragMarker() { range = editor.selection.toOrientedRange(); dragSelectionMarker = editor.session.addMarker(range, "ace_selection", editor.getSelectionStyle()); editor.clearSelection(); if (editor.isFocused()) editor.renderer.$cursorLayer.setBlinking(false); clearInterval(timerId); onDragInterval(); timerId = setInterval(onDragInterval, 20); counter = 0; event.addListener(document, "mousemove", onMouseMove); } function clearDragMarker() { clearInterval(timerId); editor.session.removeMarker(dragSelectionMarker); dragSelectionMarker = null; editor.$blockScrolling += 1; editor.selection.fromOrientedRange(range); editor.$blockScrolling -= 1; if (editor.isFocused() && !isInternal) editor.renderer.$cursorLayer.setBlinking(!editor.getReadOnly()); range = null; dragCursor = null; counter = 0; autoScrollStartTime = null; cursorMovedTime = null; event.removeListener(document, "mousemove", onMouseMove); } var onMouseMoveTimer = null; function onMouseMove() { if (onMouseMoveTimer == null) { onMouseMoveTimer = setTimeout(function() { if (onMouseMoveTimer != null && dragSelectionMarker) clearDragMarker(); }, 20); } } function canAccept(dataTransfer) { var types = dataTransfer.types; return !types || Array.prototype.some.call(types, function(type) { return type == 'text/plain' || type == 'Text'; }); } function getDropEffect(e) { var copyAllowed = ['copy', 'copymove', 'all', 'uninitialized']; var moveAllowed = ['move', 'copymove', 'linkmove', 'all', 'uninitialized']; var copyModifierState = useragent.isMac ? e.altKey : e.ctrlKey; var effectAllowed = "uninitialized"; try { effectAllowed = e.dataTransfer.effectAllowed.toLowerCase(); } catch (e) {} var dropEffect = "none"; if (copyModifierState && copyAllowed.indexOf(effectAllowed) >= 0) dropEffect = "copy"; else if (moveAllowed.indexOf(effectAllowed) >= 0) dropEffect = "move"; else if (copyAllowed.indexOf(effectAllowed) >= 0) dropEffect = "copy"; return dropEffect; } } (function() { this.dragWait = function() { var interval = Date.now() - this.mousedownEvent.time; if (interval > this.editor.getDragDelay()) this.startDrag(); }; this.dragWaitEnd = function() { var target = this.editor.container; target.draggable = false; this.startSelect(this.mousedownEvent.getDocumentPosition()); this.selectEnd(); }; this.dragReadyEnd = function(e) { this.editor.renderer.$cursorLayer.setBlinking(!this.editor.getReadOnly()); this.editor.unsetStyle("ace_dragging"); this.editor.renderer.setCursorStyle(""); this.dragWaitEnd(); }; this.startDrag = function(){ this.cancelDrag = false; var editor = this.editor; var target = editor.container; target.draggable = true; editor.renderer.$cursorLayer.setBlinking(false); editor.setStyle("ace_dragging"); var cursorStyle = useragent.isWin ? "default" : "move"; editor.renderer.setCursorStyle(cursorStyle); this.setState("dragReady"); }; this.onMouseDrag = function(e) { var target = this.editor.container; if (useragent.isIE && this.state == "dragReady") { var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y); if (distance > 3) target.dragDrop(); } if (this.state === "dragWait") { var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y); if (distance > 0) { target.draggable = false; this.startSelect(this.mousedownEvent.getDocumentPosition()); } } }; this.onMouseDown = function(e) { if (!this.$dragEnabled) return; this.mousedownEvent = e; var editor = this.editor; var inSelection = e.inSelection(); var button = e.getButton(); var clickCount = e.domEvent.detail || 1; if (clickCount === 1 && button === 0 && inSelection) { if (e.editor.inMultiSelectMode && (e.getAccelKey() || e.getShiftKey())) return; this.mousedownEvent.time = Date.now(); var eventTarget = e.domEvent.target || e.domEvent.srcElement; if ("unselectable" in eventTarget) eventTarget.unselectable = "on"; if (editor.getDragDelay()) { if (useragent.isWebKit) { this.cancelDrag = true; var mouseTarget = editor.container; mouseTarget.draggable = true; } this.setState("dragWait"); } else { this.startDrag(); } this.captureMouse(e, this.onMouseDrag.bind(this)); e.defaultPrevented = true; } }; }).call(DragdropHandler.prototype); function calcDistance(ax, ay, bx, by) { return Math.sqrt(Math.pow(bx - ax, 2) + Math.pow(by - ay, 2)); } exports.DragdropHandler = DragdropHandler; }); ace.define("ace/lib/net",["require","exports","module","ace/lib/dom"], function(require, exports, module) { "use strict"; var dom = require("./dom"); exports.get = function (url, callback) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { callback(xhr.responseText); } }; xhr.send(null); }; exports.loadScript = function(path, callback) { var head = dom.getDocumentHead(); var s = document.createElement('script'); s.src = path; head.appendChild(s); s.onload = s.onreadystatechange = function(_, isAbort) { if (isAbort || !s.readyState || s.readyState == "loaded" || s.readyState == "complete") { s = s.onload = s.onreadystatechange = null; if (!isAbort) callback(); } }; }; exports.qualifyURL = function(url) { var a = document.createElement('a'); a.href = url; return a.href; } }); ace.define("ace/lib/event_emitter",["require","exports","module"], function(require, exports, module) { "use strict"; var EventEmitter = {}; var stopPropagation = function() { this.propagationStopped = true; }; var preventDefault = function() { this.defaultPrevented = true; }; EventEmitter._emit = EventEmitter._dispatchEvent = function(eventName, e) { this._eventRegistry || (this._eventRegistry = {}); this._defaultHandlers || (this._defaultHandlers = {}); var listeners = this._eventRegistry[eventName] || []; var defaultHandler = this._defaultHandlers[eventName]; if (!listeners.length && !defaultHandler) return; if (typeof e != "object" || !e) e = {}; if (!e.type) e.type = eventName; if (!e.stopPropagation) e.stopPropagation = stopPropagation; if (!e.preventDefault) e.preventDefault = preventDefault; listeners = listeners.slice(); for (var i=0; i 1) base = parts[parts.length - 2]; var path = options[component + "Path"]; if (path == null) { path = options.basePath; } else if (sep == "/") { component = sep = ""; } if (path && path.slice(-1) != "/") path += "/"; return path + component + sep + base + this.get("suffix"); }; exports.setModuleUrl = function(name, subst) { return options.$moduleUrls[name] = subst; }; exports.$loading = {}; exports.loadModule = function(moduleName, onLoad) { var module, moduleType; if (Array.isArray(moduleName)) { moduleType = moduleName[0]; moduleName = moduleName[1]; } try { module = require(moduleName); } catch (e) {} if (module && !exports.$loading[moduleName]) return onLoad && onLoad(module); if (!exports.$loading[moduleName]) exports.$loading[moduleName] = []; exports.$loading[moduleName].push(onLoad); if (exports.$loading[moduleName].length > 1) return; var afterLoad = function() { require([moduleName], function(module) { exports._emit("load.module", {name: moduleName, module: module}); var listeners = exports.$loading[moduleName]; exports.$loading[moduleName] = null; listeners.forEach(function(onLoad) { onLoad && onLoad(module); }); }); }; if (!exports.get("packaged")) return afterLoad(); net.loadScript(exports.moduleUrl(moduleName, moduleType), afterLoad); }; init(true);function init(packaged) { options.packaged = packaged || require.packaged || module.packaged || (global.define && define.packaged); if (!global.document) return ""; var scriptOptions = {}; var scriptUrl = ""; var currentScript = (document.currentScript || document._currentScript ); // native or polyfill var currentDocument = currentScript && currentScript.ownerDocument || document; var scripts = currentDocument.getElementsByTagName("script"); for (var i=0; i [" + this.end.row + "/" + this.end.column + "]"); }; this.contains = function(row, column) { return this.compare(row, column) == 0; }; this.compareRange = function(range) { var cmp, end = range.end, start = range.start; cmp = this.compare(end.row, end.column); if (cmp == 1) { cmp = this.compare(start.row, start.column); if (cmp == 1) { return 2; } else if (cmp == 0) { return 1; } else { return 0; } } else if (cmp == -1) { return -2; } else { cmp = this.compare(start.row, start.column); if (cmp == -1) { return -1; } else if (cmp == 1) { return 42; } else { return 0; } } }; this.comparePoint = function(p) { return this.compare(p.row, p.column); }; this.containsRange = function(range) { return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0; }; this.intersects = function(range) { var cmp = this.compareRange(range); return (cmp == -1 || cmp == 0 || cmp == 1); }; this.isEnd = function(row, column) { return this.end.row == row && this.end.column == column; }; this.isStart = function(row, column) { return this.start.row == row && this.start.column == column; }; this.setStart = function(row, column) { if (typeof row == "object") { this.start.column = row.column; this.start.row = row.row; } else { this.start.row = row; this.start.column = column; } }; this.setEnd = function(row, column) { if (typeof row == "object") { this.end.column = row.column; this.end.row = row.row; } else { this.end.row = row; this.end.column = column; } }; this.inside = function(row, column) { if (this.compare(row, column) == 0) { if (this.isEnd(row, column) || this.isStart(row, column)) { return false; } else { return true; } } return false; }; this.insideStart = function(row, column) { if (this.compare(row, column) == 0) { if (this.isEnd(row, column)) { return false; } else { return true; } } return false; }; this.insideEnd = function(row, column) { if (this.compare(row, column) == 0) { if (this.isStart(row, column)) { return false; } else { return true; } } return false; }; this.compare = function(row, column) { if (!this.isMultiLine()) { if (row === this.start.row) { return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0); }; } if (row < this.start.row) return -1; if (row > this.end.row) return 1; if (this.start.row === row) return column >= this.start.column ? 0 : -1; if (this.end.row === row) return column <= this.end.column ? 0 : 1; return 0; }; this.compareStart = function(row, column) { if (this.start.row == row && this.start.column == column) { return -1; } else { return this.compare(row, column); } }; this.compareEnd = function(row, column) { if (this.end.row == row && this.end.column == column) { return 1; } else { return this.compare(row, column); } }; this.compareInside = function(row, column) { if (this.end.row == row && this.end.column == column) { return 1; } else if (this.start.row == row && this.start.column == column) { return -1; } else { return this.compare(row, column); } }; this.clipRows = function(firstRow, lastRow) { if (this.end.row > lastRow) var end = {row: lastRow + 1, column: 0}; else if (this.end.row < firstRow) var end = {row: firstRow, column: 0}; if (this.start.row > lastRow) var start = {row: lastRow + 1, column: 0}; else if (this.start.row < firstRow) var start = {row: firstRow, column: 0}; return Range.fromPoints(start || this.start, end || this.end); }; this.extend = function(row, column) { var cmp = this.compare(row, column); if (cmp == 0) return this; else if (cmp == -1) var start = {row: row, column: column}; else var end = {row: row, column: column}; return Range.fromPoints(start || this.start, end || this.end); }; this.isEmpty = function() { return (this.start.row === this.end.row && this.start.column === this.end.column); }; this.isMultiLine = function() { return (this.start.row !== this.end.row); }; this.clone = function() { return Range.fromPoints(this.start, this.end); }; this.collapseRows = function() { if (this.end.column == 0) return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0) else return new Range(this.start.row, 0, this.end.row, 0) }; this.toScreenRange = function(session) { var screenPosStart = session.documentToScreenPosition(this.start); var screenPosEnd = session.documentToScreenPosition(this.end); return new Range( screenPosStart.row, screenPosStart.column, screenPosEnd.row, screenPosEnd.column ); }; this.moveBy = function(row, column) { this.start.row += row; this.start.column += column; this.end.row += row; this.end.column += column; }; }).call(Range.prototype); Range.fromPoints = function(start, end) { return new Range(start.row, start.column, end.row, end.column); }; Range.comparePoints = comparePoints; Range.comparePoints = function(p1, p2) { return p1.row - p2.row || p1.column - p2.column; }; exports.Range = Range; }); ace.define("ace/selection",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/range"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var lang = require("./lib/lang"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Range = require("./range").Range; var Selection = function(session) { this.session = session; this.doc = session.getDocument(); this.clearSelection(); this.lead = this.selectionLead = this.doc.createAnchor(0, 0); this.anchor = this.selectionAnchor = this.doc.createAnchor(0, 0); var self = this; this.lead.on("change", function(e) { self._emit("changeCursor"); if (!self.$isEmpty) self._emit("changeSelection"); if (!self.$keepDesiredColumnOnChange && e.old.column != e.value.column) self.$desiredColumn = null; }); this.selectionAnchor.on("change", function() { if (!self.$isEmpty) self._emit("changeSelection"); }); }; (function() { oop.implement(this, EventEmitter); this.isEmpty = function() { return (this.$isEmpty || ( this.anchor.row == this.lead.row && this.anchor.column == this.lead.column )); }; this.isMultiLine = function() { if (this.isEmpty()) { return false; } return this.getRange().isMultiLine(); }; this.getCursor = function() { return this.lead.getPosition(); }; this.setSelectionAnchor = function(row, column) { this.anchor.setPosition(row, column); if (this.$isEmpty) { this.$isEmpty = false; this._emit("changeSelection"); } }; this.getSelectionAnchor = function() { if (this.$isEmpty) return this.getSelectionLead(); else return this.anchor.getPosition(); }; this.getSelectionLead = function() { return this.lead.getPosition(); }; this.shiftSelection = function(columns) { if (this.$isEmpty) { this.moveCursorTo(this.lead.row, this.lead.column + columns); return; } var anchor = this.getSelectionAnchor(); var lead = this.getSelectionLead(); var isBackwards = this.isBackwards(); if (!isBackwards || anchor.column !== 0) this.setSelectionAnchor(anchor.row, anchor.column + columns); if (isBackwards || lead.column !== 0) { this.$moveSelection(function() { this.moveCursorTo(lead.row, lead.column + columns); }); } }; this.isBackwards = function() { var anchor = this.anchor; var lead = this.lead; return (anchor.row > lead.row || (anchor.row == lead.row && anchor.column > lead.column)); }; this.getRange = function() { var anchor = this.anchor; var lead = this.lead; if (this.isEmpty()) return Range.fromPoints(lead, lead); if (this.isBackwards()) { return Range.fromPoints(lead, anchor); } else { return Range.fromPoints(anchor, lead); } }; this.clearSelection = function() { if (!this.$isEmpty) { this.$isEmpty = true; this._emit("changeSelection"); } }; this.selectAll = function() { var lastRow = this.doc.getLength() - 1; this.setSelectionAnchor(0, 0); this.moveCursorTo(lastRow, this.doc.getLine(lastRow).length); }; this.setRange = this.setSelectionRange = function(range, reverse) { if (reverse) { this.setSelectionAnchor(range.end.row, range.end.column); this.selectTo(range.start.row, range.start.column); } else { this.setSelectionAnchor(range.start.row, range.start.column); this.selectTo(range.end.row, range.end.column); } if (this.getRange().isEmpty()) this.$isEmpty = true; this.$desiredColumn = null; }; this.$moveSelection = function(mover) { var lead = this.lead; if (this.$isEmpty) this.setSelectionAnchor(lead.row, lead.column); mover.call(this); }; this.selectTo = function(row, column) { this.$moveSelection(function() { this.moveCursorTo(row, column); }); }; this.selectToPosition = function(pos) { this.$moveSelection(function() { this.moveCursorToPosition(pos); }); }; this.moveTo = function(row, column) { this.clearSelection(); this.moveCursorTo(row, column); }; this.moveToPosition = function(pos) { this.clearSelection(); this.moveCursorToPosition(pos); }; this.selectUp = function() { this.$moveSelection(this.moveCursorUp); }; this.selectDown = function() { this.$moveSelection(this.moveCursorDown); }; this.selectRight = function() { this.$moveSelection(this.moveCursorRight); }; this.selectLeft = function() { this.$moveSelection(this.moveCursorLeft); }; this.selectLineStart = function() { this.$moveSelection(this.moveCursorLineStart); }; this.selectLineEnd = function() { this.$moveSelection(this.moveCursorLineEnd); }; this.selectFileEnd = function() { this.$moveSelection(this.moveCursorFileEnd); }; this.selectFileStart = function() { this.$moveSelection(this.moveCursorFileStart); }; this.selectWordRight = function() { this.$moveSelection(this.moveCursorWordRight); }; this.selectWordLeft = function() { this.$moveSelection(this.moveCursorWordLeft); }; this.getWordRange = function(row, column) { if (typeof column == "undefined") { var cursor = row || this.lead; row = cursor.row; column = cursor.column; } return this.session.getWordRange(row, column); }; this.selectWord = function() { this.setSelectionRange(this.getWordRange()); }; this.selectAWord = function() { var cursor = this.getCursor(); var range = this.session.getAWordRange(cursor.row, cursor.column); this.setSelectionRange(range); }; this.getLineRange = function(row, excludeLastChar) { var rowStart = typeof row == "number" ? row : this.lead.row; var rowEnd; var foldLine = this.session.getFoldLine(rowStart); if (foldLine) { rowStart = foldLine.start.row; rowEnd = foldLine.end.row; } else { rowEnd = rowStart; } if (excludeLastChar === true) return new Range(rowStart, 0, rowEnd, this.session.getLine(rowEnd).length); else return new Range(rowStart, 0, rowEnd + 1, 0); }; this.selectLine = function() { this.setSelectionRange(this.getLineRange()); }; this.moveCursorUp = function() { this.moveCursorBy(-1, 0); }; this.moveCursorDown = function() { this.moveCursorBy(1, 0); }; this.moveCursorLeft = function() { var cursor = this.lead.getPosition(), fold; if (fold = this.session.getFoldAt(cursor.row, cursor.column, -1)) { this.moveCursorTo(fold.start.row, fold.start.column); } else if (cursor.column === 0) { if (cursor.row > 0) { this.moveCursorTo(cursor.row - 1, this.doc.getLine(cursor.row - 1).length); } } else { var tabSize = this.session.getTabSize(); if (this.session.isTabStop(cursor) && this.doc.getLine(cursor.row).slice(cursor.column-tabSize, cursor.column).split(" ").length-1 == tabSize) this.moveCursorBy(0, -tabSize); else this.moveCursorBy(0, -1); } }; this.moveCursorRight = function() { var cursor = this.lead.getPosition(), fold; if (fold = this.session.getFoldAt(cursor.row, cursor.column, 1)) { this.moveCursorTo(fold.end.row, fold.end.column); } else if (this.lead.column == this.doc.getLine(this.lead.row).length) { if (this.lead.row < this.doc.getLength() - 1) { this.moveCursorTo(this.lead.row + 1, 0); } } else { var tabSize = this.session.getTabSize(); var cursor = this.lead; if (this.session.isTabStop(cursor) && this.doc.getLine(cursor.row).slice(cursor.column, cursor.column+tabSize).split(" ").length-1 == tabSize) this.moveCursorBy(0, tabSize); else this.moveCursorBy(0, 1); } }; this.moveCursorLineStart = function() { var row = this.lead.row; var column = this.lead.column; var screenRow = this.session.documentToScreenRow(row, column); var firstColumnPosition = this.session.screenToDocumentPosition(screenRow, 0); var beforeCursor = this.session.getDisplayLine( row, null, firstColumnPosition.row, firstColumnPosition.column ); var leadingSpace = beforeCursor.match(/^\s*/); if (leadingSpace[0].length != column && !this.session.$useEmacsStyleLineStart) firstColumnPosition.column += leadingSpace[0].length; this.moveCursorToPosition(firstColumnPosition); }; this.moveCursorLineEnd = function() { var lead = this.lead; var lineEnd = this.session.getDocumentLastRowColumnPosition(lead.row, lead.column); if (this.lead.column == lineEnd.column) { var line = this.session.getLine(lineEnd.row); if (lineEnd.column == line.length) { var textEnd = line.search(/\s+$/); if (textEnd > 0) lineEnd.column = textEnd; } } this.moveCursorTo(lineEnd.row, lineEnd.column); }; this.moveCursorFileEnd = function() { var row = this.doc.getLength() - 1; var column = this.doc.getLine(row).length; this.moveCursorTo(row, column); }; this.moveCursorFileStart = function() { this.moveCursorTo(0, 0); }; this.moveCursorLongWordRight = function() { var row = this.lead.row; var column = this.lead.column; var line = this.doc.getLine(row); var rightOfCursor = line.substring(column); var match; this.session.nonTokenRe.lastIndex = 0; this.session.tokenRe.lastIndex = 0; var fold = this.session.getFoldAt(row, column, 1); if (fold) { this.moveCursorTo(fold.end.row, fold.end.column); return; } if (match = this.session.nonTokenRe.exec(rightOfCursor)) { column += this.session.nonTokenRe.lastIndex; this.session.nonTokenRe.lastIndex = 0; rightOfCursor = line.substring(column); } if (column >= line.length) { this.moveCursorTo(row, line.length); this.moveCursorRight(); if (row < this.doc.getLength() - 1) this.moveCursorWordRight(); return; } if (match = this.session.tokenRe.exec(rightOfCursor)) { column += this.session.tokenRe.lastIndex; this.session.tokenRe.lastIndex = 0; } this.moveCursorTo(row, column); }; this.moveCursorLongWordLeft = function() { var row = this.lead.row; var column = this.lead.column; var fold; if (fold = this.session.getFoldAt(row, column, -1)) { this.moveCursorTo(fold.start.row, fold.start.column); return; } var str = this.session.getFoldStringAt(row, column, -1); if (str == null) { str = this.doc.getLine(row).substring(0, column); } var leftOfCursor = lang.stringReverse(str); var match; this.session.nonTokenRe.lastIndex = 0; this.session.tokenRe.lastIndex = 0; if (match = this.session.nonTokenRe.exec(leftOfCursor)) { column -= this.session.nonTokenRe.lastIndex; leftOfCursor = leftOfCursor.slice(this.session.nonTokenRe.lastIndex); this.session.nonTokenRe.lastIndex = 0; } if (column <= 0) { this.moveCursorTo(row, 0); this.moveCursorLeft(); if (row > 0) this.moveCursorWordLeft(); return; } if (match = this.session.tokenRe.exec(leftOfCursor)) { column -= this.session.tokenRe.lastIndex; this.session.tokenRe.lastIndex = 0; } this.moveCursorTo(row, column); }; this.$shortWordEndIndex = function(rightOfCursor) { var match, index = 0, ch; var whitespaceRe = /\s/; var tokenRe = this.session.tokenRe; tokenRe.lastIndex = 0; if (match = this.session.tokenRe.exec(rightOfCursor)) { index = this.session.tokenRe.lastIndex; } else { while ((ch = rightOfCursor[index]) && whitespaceRe.test(ch)) index ++; if (index < 1) { tokenRe.lastIndex = 0; while ((ch = rightOfCursor[index]) && !tokenRe.test(ch)) { tokenRe.lastIndex = 0; index ++; if (whitespaceRe.test(ch)) { if (index > 2) { index--; break; } else { while ((ch = rightOfCursor[index]) && whitespaceRe.test(ch)) index ++; if (index > 2) break; } } } } } tokenRe.lastIndex = 0; return index; }; this.moveCursorShortWordRight = function() { var row = this.lead.row; var column = this.lead.column; var line = this.doc.getLine(row); var rightOfCursor = line.substring(column); var fold = this.session.getFoldAt(row, column, 1); if (fold) return this.moveCursorTo(fold.end.row, fold.end.column); if (column == line.length) { var l = this.doc.getLength(); do { row++; rightOfCursor = this.doc.getLine(row); } while (row < l && /^\s*$/.test(rightOfCursor)); if (!/^\s+/.test(rightOfCursor)) rightOfCursor = ""; column = 0; } var index = this.$shortWordEndIndex(rightOfCursor); this.moveCursorTo(row, column + index); }; this.moveCursorShortWordLeft = function() { var row = this.lead.row; var column = this.lead.column; var fold; if (fold = this.session.getFoldAt(row, column, -1)) return this.moveCursorTo(fold.start.row, fold.start.column); var line = this.session.getLine(row).substring(0, column); if (column === 0) { do { row--; line = this.doc.getLine(row); } while (row > 0 && /^\s*$/.test(line)); column = line.length; if (!/\s+$/.test(line)) line = ""; } var leftOfCursor = lang.stringReverse(line); var index = this.$shortWordEndIndex(leftOfCursor); return this.moveCursorTo(row, column - index); }; this.moveCursorWordRight = function() { if (this.session.$selectLongWords) this.moveCursorLongWordRight(); else this.moveCursorShortWordRight(); }; this.moveCursorWordLeft = function() { if (this.session.$selectLongWords) this.moveCursorLongWordLeft(); else this.moveCursorShortWordLeft(); }; this.moveCursorBy = function(rows, chars) { var screenPos = this.session.documentToScreenPosition( this.lead.row, this.lead.column ); if (chars === 0) { if (this.$desiredColumn) screenPos.column = this.$desiredColumn; else this.$desiredColumn = screenPos.column; } var docPos = this.session.screenToDocumentPosition(screenPos.row + rows, screenPos.column); if (rows !== 0 && chars === 0 && docPos.row === this.lead.row && docPos.column === this.lead.column) { if (this.session.lineWidgets && this.session.lineWidgets[docPos.row]) docPos.row++; } this.moveCursorTo(docPos.row, docPos.column + chars, chars === 0); }; this.moveCursorToPosition = function(position) { this.moveCursorTo(position.row, position.column); }; this.moveCursorTo = function(row, column, keepDesiredColumn) { var fold = this.session.getFoldAt(row, column, 1); if (fold) { row = fold.start.row; column = fold.start.column; } this.$keepDesiredColumnOnChange = true; this.lead.setPosition(row, column); this.$keepDesiredColumnOnChange = false; if (!keepDesiredColumn) this.$desiredColumn = null; }; this.moveCursorToScreen = function(row, column, keepDesiredColumn) { var pos = this.session.screenToDocumentPosition(row, column); this.moveCursorTo(pos.row, pos.column, keepDesiredColumn); }; this.detach = function() { this.lead.detach(); this.anchor.detach(); this.session = this.doc = null; }; this.fromOrientedRange = function(range) { this.setSelectionRange(range, range.cursor == range.start); this.$desiredColumn = range.desiredColumn || this.$desiredColumn; }; this.toOrientedRange = function(range) { var r = this.getRange(); if (range) { range.start.column = r.start.column; range.start.row = r.start.row; range.end.column = r.end.column; range.end.row = r.end.row; } else { range = r; } range.cursor = this.isBackwards() ? range.start : range.end; range.desiredColumn = this.$desiredColumn; return range; }; this.getRangeOfMovements = function(func) { var start = this.getCursor(); try { func.call(null, this); var end = this.getCursor(); return Range.fromPoints(start,end); } catch(e) { return Range.fromPoints(start,start); } finally { this.moveCursorToPosition(start); } }; this.toJSON = function() { if (this.rangeCount) { var data = this.ranges.map(function(r) { var r1 = r.clone(); r1.isBackwards = r.cursor == r.start; return r1; }); } else { var data = this.getRange(); data.isBackwards = this.isBackwards(); } return data; }; this.fromJSON = function(data) { if (data.start == undefined) { if (this.rangeList) { this.toSingleRange(data[0]); for (var i = data.length; i--; ) { var r = Range.fromPoints(data[i].start, data[i].end); if (data.isBackwards) r.cursor = r.start; this.addRange(r, true); } return; } else data = data[0]; } if (this.rangeList) this.toSingleRange(data); this.setSelectionRange(data, data.isBackwards); }; this.isEqual = function(data) { if ((data.length || this.rangeCount) && data.length != this.rangeCount) return false; if (!data.length || !this.ranges) return this.getRange().isEqual(data); for (var i = this.ranges.length; i--; ) { if (!this.ranges[i].isEqual(data[i])) return false; } return true; }; }).call(Selection.prototype); exports.Selection = Selection; }); ace.define("ace/tokenizer",["require","exports","module"], function(require, exports, module) { "use strict"; var MAX_TOKEN_COUNT = 2000; var Tokenizer = function(rules) { this.states = rules; this.regExps = {}; this.matchMappings = {}; for (var key in this.states) { var state = this.states[key]; var ruleRegExps = []; var matchTotal = 0; var mapping = this.matchMappings[key] = {defaultToken: "text"}; var flag = "g"; var splitterRurles = []; for (var i = 0; i < state.length; i++) { var rule = state[i]; if (rule.defaultToken) mapping.defaultToken = rule.defaultToken; if (rule.caseInsensitive) flag = "gi"; if (rule.regex == null) continue; if (rule.regex instanceof RegExp) rule.regex = rule.regex.toString().slice(1, -1); var adjustedregex = rule.regex; var matchcount = new RegExp("(?:(" + adjustedregex + ")|(.))").exec("a").length - 2; if (Array.isArray(rule.token)) { if (rule.token.length == 1 || matchcount == 1) { rule.token = rule.token[0]; } else if (matchcount - 1 != rule.token.length) { this.reportError("number of classes and regexp groups doesn't match", { rule: rule, groupCount: matchcount - 1 }); rule.token = rule.token[0]; } else { rule.tokenArray = rule.token; rule.token = null; rule.onMatch = this.$arrayTokens; } } else if (typeof rule.token == "function" && !rule.onMatch) { if (matchcount > 1) rule.onMatch = this.$applyToken; else rule.onMatch = rule.token; } if (matchcount > 1) { if (/\\\d/.test(rule.regex)) { adjustedregex = rule.regex.replace(/\\([0-9]+)/g, function(match, digit) { return "\\" + (parseInt(digit, 10) + matchTotal + 1); }); } else { matchcount = 1; adjustedregex = this.removeCapturingGroups(rule.regex); } if (!rule.splitRegex && typeof rule.token != "string") splitterRurles.push(rule); // flag will be known only at the very end } mapping[matchTotal] = i; matchTotal += matchcount; ruleRegExps.push(adjustedregex); if (!rule.onMatch) rule.onMatch = null; } if (!ruleRegExps.length) { mapping[0] = 0; ruleRegExps.push("$"); } splitterRurles.forEach(function(rule) { rule.splitRegex = this.createSplitterRegexp(rule.regex, flag); }, this); this.regExps[key] = new RegExp("(" + ruleRegExps.join(")|(") + ")|($)", flag); } }; (function() { this.$setMaxTokenCount = function(m) { MAX_TOKEN_COUNT = m | 0; }; this.$applyToken = function(str) { var values = this.splitRegex.exec(str).slice(1); var types = this.token.apply(this, values); if (typeof types === "string") return [{type: types, value: str}]; var tokens = []; for (var i = 0, l = types.length; i < l; i++) { if (values[i]) tokens[tokens.length] = { type: types[i], value: values[i] }; } return tokens; }, this.$arrayTokens = function(str) { if (!str) return []; var values = this.splitRegex.exec(str); if (!values) return "text"; var tokens = []; var types = this.tokenArray; for (var i = 0, l = types.length; i < l; i++) { if (values[i + 1]) tokens[tokens.length] = { type: types[i], value: values[i + 1] }; } return tokens; }; this.removeCapturingGroups = function(src) { var r = src.replace( /\[(?:\\.|[^\]])*?\]|\\.|\(\?[:=!]|(\()/g, function(x, y) {return y ? "(?:" : x;} ); return r; }; this.createSplitterRegexp = function(src, flag) { if (src.indexOf("(?=") != -1) { var stack = 0; var inChClass = false; var lastCapture = {}; src.replace(/(\\.)|(\((?:\?[=!])?)|(\))|([\[\]])/g, function( m, esc, parenOpen, parenClose, square, index ) { if (inChClass) { inChClass = square != "]"; } else if (square) { inChClass = true; } else if (parenClose) { if (stack == lastCapture.stack) { lastCapture.end = index+1; lastCapture.stack = -1; } stack--; } else if (parenOpen) { stack++; if (parenOpen.length != 1) { lastCapture.stack = stack lastCapture.start = index; } } return m; }); if (lastCapture.end != null && /^\)*$/.test(src.substr(lastCapture.end))) src = src.substring(0, lastCapture.start) + src.substr(lastCapture.end); } return new RegExp(src, (flag||"").replace("g", "")); }; this.getLineTokens = function(line, startState) { if (startState && typeof startState != "string") { var stack = startState.slice(0); startState = stack[0]; if (startState === "#tmp") { stack.shift() startState = stack.shift() } } else var stack = []; var currentState = startState || "start"; var state = this.states[currentState]; if (!state) { currentState = "start"; state = this.states[currentState]; } var mapping = this.matchMappings[currentState]; var re = this.regExps[currentState]; re.lastIndex = 0; var match, tokens = []; var lastIndex = 0; var matchAttempts = 0; var token = {type: null, value: ""}; while (match = re.exec(line)) { var type = mapping.defaultToken; var rule = null; var value = match[0]; var index = re.lastIndex; if (index - value.length > lastIndex) { var skipped = line.substring(lastIndex, index - value.length); if (token.type == type) { token.value += skipped; } else { if (token.type) tokens.push(token); token = {type: type, value: skipped}; } } for (var i = 0; i < match.length-2; i++) { if (match[i + 1] === undefined) continue; rule = state[mapping[i]]; if (rule.onMatch) type = rule.onMatch(value, currentState, stack); else type = rule.token; if (rule.next) { if (typeof rule.next == "string") { currentState = rule.next; } else { currentState = rule.next(currentState, stack); } state = this.states[currentState]; if (!state) { this.reportError("state doesn't exist", currentState); currentState = "start"; state = this.states[currentState]; } mapping = this.matchMappings[currentState]; lastIndex = index; re = this.regExps[currentState]; re.lastIndex = index; } break; } if (value) { if (typeof type === "string") { if ((!rule || rule.merge !== false) && token.type === type) { token.value += value; } else { if (token.type) tokens.push(token); token = {type: type, value: value}; } } else if (type) { if (token.type) tokens.push(token); token = {type: null, value: ""}; for (var i = 0; i < type.length; i++) tokens.push(type[i]); } } if (lastIndex == line.length) break; lastIndex = index; if (matchAttempts++ > MAX_TOKEN_COUNT) { if (matchAttempts > 2 * line.length) { this.reportError("infinite loop with in ace tokenizer", { startState: startState, line: line }); } while (lastIndex < line.length) { if (token.type) tokens.push(token); token = { value: line.substring(lastIndex, lastIndex += 2000), type: "overflow" }; } currentState = "start"; stack = []; break; } } if (token.type) tokens.push(token); if (stack.length > 1) { if (stack[0] !== currentState) stack.unshift("#tmp", currentState); } return { tokens : tokens, state : stack.length ? stack : currentState }; }; this.reportError = function(msg, data) { var e = new Error(msg); e.data = data; if (typeof console == "object" && console.error) console.error(e); setTimeout(function() { throw e; }); }; }).call(Tokenizer.prototype); exports.Tokenizer = Tokenizer; }); ace.define("ace/mode/text_highlight_rules",["require","exports","module","ace/lib/lang"], function(require, exports, module) { "use strict"; var lang = require("../lib/lang"); var TextHighlightRules = function() { this.$rules = { "start" : [{ token : "empty_line", regex : '^$' }, { defaultToken : "text" }] }; }; (function() { this.addRules = function(rules, prefix) { if (!prefix) { for (var key in rules) this.$rules[key] = rules[key]; return; } for (var key in rules) { var state = rules[key]; for (var i = 0; i < state.length; i++) { var rule = state[i]; if (rule.next || rule.onMatch) { if (typeof rule.next != "string") { if (rule.nextState && rule.nextState.indexOf(prefix) !== 0) rule.nextState = prefix + rule.nextState; } else { if (rule.next.indexOf(prefix) !== 0) rule.next = prefix + rule.next; } } } this.$rules[prefix + key] = state; } }; this.getRules = function() { return this.$rules; }; this.embedRules = function (HighlightRules, prefix, escapeRules, states, append) { var embedRules = typeof HighlightRules == "function" ? new HighlightRules().getRules() : HighlightRules; if (states) { for (var i = 0; i < states.length; i++) states[i] = prefix + states[i]; } else { states = []; for (var key in embedRules) states.push(prefix + key); } this.addRules(embedRules, prefix); if (escapeRules) { var addRules = Array.prototype[append ? "push" : "unshift"]; for (var i = 0; i < states.length; i++) addRules.apply(this.$rules[states[i]], lang.deepCopy(escapeRules)); } if (!this.$embeds) this.$embeds = []; this.$embeds.push(prefix); }; this.getEmbeds = function() { return this.$embeds; }; var pushState = function(currentState, stack) { if (currentState != "start" || stack.length) stack.unshift(this.nextState, currentState); return this.nextState; }; var popState = function(currentState, stack) { stack.shift(); return stack.shift() || "start"; }; this.normalizeRules = function() { var id = 0; var rules = this.$rules; function processState(key) { var state = rules[key]; state.processed = true; for (var i = 0; i < state.length; i++) { var rule = state[i]; if (!rule.regex && rule.start) { rule.regex = rule.start; if (!rule.next) rule.next = []; rule.next.push({ defaultToken: rule.token }, { token: rule.token + ".end", regex: rule.end || rule.start, next: "pop" }); rule.token = rule.token + ".start"; rule.push = true; } var next = rule.next || rule.push; if (next && Array.isArray(next)) { var stateName = rule.stateName; if (!stateName) { stateName = rule.token; if (typeof stateName != "string") stateName = stateName[0] || ""; if (rules[stateName]) stateName += id++; } rules[stateName] = next; rule.next = stateName; processState(stateName); } else if (next == "pop") { rule.next = popState; } if (rule.push) { rule.nextState = rule.next || rule.push; rule.next = pushState; delete rule.push; } if (rule.rules) { for (var r in rule.rules) { if (rules[r]) { if (rules[r].push) rules[r].push.apply(rules[r], rule.rules[r]); } else { rules[r] = rule.rules[r]; } } } if (rule.include || typeof rule == "string") { var includeName = rule.include || rule; var toInsert = rules[includeName]; } else if (Array.isArray(rule)) toInsert = rule; if (toInsert) { var args = [i, 1].concat(toInsert); if (rule.noEscape) args = args.filter(function(x) {return !x.next;}); state.splice.apply(state, args); i--; toInsert = null; } if (rule.keywordMap) { rule.token = this.createKeywordMapper( rule.keywordMap, rule.defaultToken || "text", rule.caseInsensitive ); delete rule.defaultToken; } } } Object.keys(rules).forEach(processState, this); }; this.createKeywordMapper = function(map, defaultToken, ignoreCase, splitChar) { var keywords = Object.create(null); Object.keys(map).forEach(function(className) { var a = map[className]; if (ignoreCase) a = a.toLowerCase(); var list = a.split(splitChar || "|"); for (var i = list.length; i--; ) keywords[list[i]] = className; }); if (Object.getPrototypeOf(keywords)) { keywords.__proto__ = null; } this.$keywordList = Object.keys(keywords); map = null; return ignoreCase ? function(value) {return keywords[value.toLowerCase()] || defaultToken } : function(value) {return keywords[value] || defaultToken }; }; this.getKeywords = function() { return this.$keywords; }; }).call(TextHighlightRules.prototype); exports.TextHighlightRules = TextHighlightRules; }); ace.define("ace/mode/behaviour",["require","exports","module"], function(require, exports, module) { "use strict"; var Behaviour = function() { this.$behaviours = {}; }; (function () { this.add = function (name, action, callback) { switch (undefined) { case this.$behaviours: this.$behaviours = {}; case this.$behaviours[name]: this.$behaviours[name] = {}; } this.$behaviours[name][action] = callback; } this.addBehaviours = function (behaviours) { for (var key in behaviours) { for (var action in behaviours[key]) { this.add(key, action, behaviours[key][action]); } } } this.remove = function (name) { if (this.$behaviours && this.$behaviours[name]) { delete this.$behaviours[name]; } } this.inherit = function (mode, filter) { if (typeof mode === "function") { var behaviours = new mode().getBehaviours(filter); } else { var behaviours = mode.getBehaviours(filter); } this.addBehaviours(behaviours); } this.getBehaviours = function (filter) { if (!filter) { return this.$behaviours; } else { var ret = {} for (var i = 0; i < filter.length; i++) { if (this.$behaviours[filter[i]]) { ret[filter[i]] = this.$behaviours[filter[i]]; } } return ret; } } }).call(Behaviour.prototype); exports.Behaviour = Behaviour; }); ace.define("ace/unicode",["require","exports","module"], function(require, exports, module) { "use strict"; exports.packages = {}; addUnicodePackage({ L: "0041-005A0061-007A00AA00B500BA00C0-00D600D8-00F600F8-02C102C6-02D102E0-02E402EC02EE0370-037403760377037A-037D03860388-038A038C038E-03A103A3-03F503F7-0481048A-05250531-055605590561-058705D0-05EA05F0-05F20621-064A066E066F0671-06D306D506E506E606EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA07F407F507FA0800-0815081A082408280904-0939093D09500958-0961097109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E460E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EC60EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10A0-10C510D0-10FA10FC1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317D717DC1820-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541AA71B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C7D1CE9-1CEC1CEE-1CF11D00-1DBF1E00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FBC1FBE1FC2-1FC41FC6-1FCC1FD0-1FD31FD6-1FDB1FE0-1FEC1FF2-1FF41FF6-1FFC2071207F2090-209421022107210A-211321152119-211D212421262128212A-212D212F-2139213C-213F2145-2149214E218321842C00-2C2E2C30-2C5E2C60-2CE42CEB-2CEE2D00-2D252D30-2D652D6F2D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE2E2F300530063031-3035303B303C3041-3096309D-309F30A1-30FA30FC-30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A48CA4D0-A4FDA500-A60CA610-A61FA62AA62BA640-A65FA662-A66EA67F-A697A6A0-A6E5A717-A71FA722-A788A78BA78CA7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2A9CFAA00-AA28AA40-AA42AA44-AA4BAA60-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADB-AADDABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB00-FB06FB13-FB17FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF21-FF3AFF41-FF5AFF66-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC", Ll: "0061-007A00AA00B500BA00DF-00F600F8-00FF01010103010501070109010B010D010F01110113011501170119011B011D011F01210123012501270129012B012D012F01310133013501370138013A013C013E014001420144014601480149014B014D014F01510153015501570159015B015D015F01610163016501670169016B016D016F0171017301750177017A017C017E-0180018301850188018C018D019201950199-019B019E01A101A301A501A801AA01AB01AD01B001B401B601B901BA01BD-01BF01C601C901CC01CE01D001D201D401D601D801DA01DC01DD01DF01E101E301E501E701E901EB01ED01EF01F001F301F501F901FB01FD01FF02010203020502070209020B020D020F02110213021502170219021B021D021F02210223022502270229022B022D022F02310233-0239023C023F0240024202470249024B024D024F-02930295-02AF037103730377037B-037D039003AC-03CE03D003D103D5-03D703D903DB03DD03DF03E103E303E503E703E903EB03ED03EF-03F303F503F803FB03FC0430-045F04610463046504670469046B046D046F04710473047504770479047B047D047F0481048B048D048F04910493049504970499049B049D049F04A104A304A504A704A904AB04AD04AF04B104B304B504B704B904BB04BD04BF04C204C404C604C804CA04CC04CE04CF04D104D304D504D704D904DB04DD04DF04E104E304E504E704E904EB04ED04EF04F104F304F504F704F904FB04FD04FF05010503050505070509050B050D050F05110513051505170519051B051D051F0521052305250561-05871D00-1D2B1D62-1D771D79-1D9A1E011E031E051E071E091E0B1E0D1E0F1E111E131E151E171E191E1B1E1D1E1F1E211E231E251E271E291E2B1E2D1E2F1E311E331E351E371E391E3B1E3D1E3F1E411E431E451E471E491E4B1E4D1E4F1E511E531E551E571E591E5B1E5D1E5F1E611E631E651E671E691E6B1E6D1E6F1E711E731E751E771E791E7B1E7D1E7F1E811E831E851E871E891E8B1E8D1E8F1E911E931E95-1E9D1E9F1EA11EA31EA51EA71EA91EAB1EAD1EAF1EB11EB31EB51EB71EB91EBB1EBD1EBF1EC11EC31EC51EC71EC91ECB1ECD1ECF1ED11ED31ED51ED71ED91EDB1EDD1EDF1EE11EE31EE51EE71EE91EEB1EED1EEF1EF11EF31EF51EF71EF91EFB1EFD1EFF-1F071F10-1F151F20-1F271F30-1F371F40-1F451F50-1F571F60-1F671F70-1F7D1F80-1F871F90-1F971FA0-1FA71FB0-1FB41FB61FB71FBE1FC2-1FC41FC61FC71FD0-1FD31FD61FD71FE0-1FE71FF2-1FF41FF61FF7210A210E210F2113212F21342139213C213D2146-2149214E21842C30-2C5E2C612C652C662C682C6A2C6C2C712C732C742C76-2C7C2C812C832C852C872C892C8B2C8D2C8F2C912C932C952C972C992C9B2C9D2C9F2CA12CA32CA52CA72CA92CAB2CAD2CAF2CB12CB32CB52CB72CB92CBB2CBD2CBF2CC12CC32CC52CC72CC92CCB2CCD2CCF2CD12CD32CD52CD72CD92CDB2CDD2CDF2CE12CE32CE42CEC2CEE2D00-2D25A641A643A645A647A649A64BA64DA64FA651A653A655A657A659A65BA65DA65FA663A665A667A669A66BA66DA681A683A685A687A689A68BA68DA68FA691A693A695A697A723A725A727A729A72BA72DA72F-A731A733A735A737A739A73BA73DA73FA741A743A745A747A749A74BA74DA74FA751A753A755A757A759A75BA75DA75FA761A763A765A767A769A76BA76DA76FA771-A778A77AA77CA77FA781A783A785A787A78CFB00-FB06FB13-FB17FF41-FF5A", Lu: "0041-005A00C0-00D600D8-00DE01000102010401060108010A010C010E01100112011401160118011A011C011E01200122012401260128012A012C012E01300132013401360139013B013D013F0141014301450147014A014C014E01500152015401560158015A015C015E01600162016401660168016A016C016E017001720174017601780179017B017D018101820184018601870189-018B018E-0191019301940196-0198019C019D019F01A001A201A401A601A701A901AC01AE01AF01B1-01B301B501B701B801BC01C401C701CA01CD01CF01D101D301D501D701D901DB01DE01E001E201E401E601E801EA01EC01EE01F101F401F6-01F801FA01FC01FE02000202020402060208020A020C020E02100212021402160218021A021C021E02200222022402260228022A022C022E02300232023A023B023D023E02410243-02460248024A024C024E03700372037603860388-038A038C038E038F0391-03A103A3-03AB03CF03D2-03D403D803DA03DC03DE03E003E203E403E603E803EA03EC03EE03F403F703F903FA03FD-042F04600462046404660468046A046C046E04700472047404760478047A047C047E0480048A048C048E04900492049404960498049A049C049E04A004A204A404A604A804AA04AC04AE04B004B204B404B604B804BA04BC04BE04C004C104C304C504C704C904CB04CD04D004D204D404D604D804DA04DC04DE04E004E204E404E604E804EA04EC04EE04F004F204F404F604F804FA04FC04FE05000502050405060508050A050C050E05100512051405160518051A051C051E0520052205240531-055610A0-10C51E001E021E041E061E081E0A1E0C1E0E1E101E121E141E161E181E1A1E1C1E1E1E201E221E241E261E281E2A1E2C1E2E1E301E321E341E361E381E3A1E3C1E3E1E401E421E441E461E481E4A1E4C1E4E1E501E521E541E561E581E5A1E5C1E5E1E601E621E641E661E681E6A1E6C1E6E1E701E721E741E761E781E7A1E7C1E7E1E801E821E841E861E881E8A1E8C1E8E1E901E921E941E9E1EA01EA21EA41EA61EA81EAA1EAC1EAE1EB01EB21EB41EB61EB81EBA1EBC1EBE1EC01EC21EC41EC61EC81ECA1ECC1ECE1ED01ED21ED41ED61ED81EDA1EDC1EDE1EE01EE21EE41EE61EE81EEA1EEC1EEE1EF01EF21EF41EF61EF81EFA1EFC1EFE1F08-1F0F1F18-1F1D1F28-1F2F1F38-1F3F1F48-1F4D1F591F5B1F5D1F5F1F68-1F6F1FB8-1FBB1FC8-1FCB1FD8-1FDB1FE8-1FEC1FF8-1FFB21022107210B-210D2110-211221152119-211D212421262128212A-212D2130-2133213E213F214521832C00-2C2E2C602C62-2C642C672C692C6B2C6D-2C702C722C752C7E-2C802C822C842C862C882C8A2C8C2C8E2C902C922C942C962C982C9A2C9C2C9E2CA02CA22CA42CA62CA82CAA2CAC2CAE2CB02CB22CB42CB62CB82CBA2CBC2CBE2CC02CC22CC42CC62CC82CCA2CCC2CCE2CD02CD22CD42CD62CD82CDA2CDC2CDE2CE02CE22CEB2CEDA640A642A644A646A648A64AA64CA64EA650A652A654A656A658A65AA65CA65EA662A664A666A668A66AA66CA680A682A684A686A688A68AA68CA68EA690A692A694A696A722A724A726A728A72AA72CA72EA732A734A736A738A73AA73CA73EA740A742A744A746A748A74AA74CA74EA750A752A754A756A758A75AA75CA75EA760A762A764A766A768A76AA76CA76EA779A77BA77DA77EA780A782A784A786A78BFF21-FF3A", Lt: "01C501C801CB01F21F88-1F8F1F98-1F9F1FA8-1FAF1FBC1FCC1FFC", Lm: "02B0-02C102C6-02D102E0-02E402EC02EE0374037A0559064006E506E607F407F507FA081A0824082809710E460EC610FC17D718431AA71C78-1C7D1D2C-1D611D781D9B-1DBF2071207F2090-20942C7D2D6F2E2F30053031-3035303B309D309E30FC-30FEA015A4F8-A4FDA60CA67FA717-A71FA770A788A9CFAA70AADDFF70FF9EFF9F", Lo: "01BB01C0-01C3029405D0-05EA05F0-05F20621-063F0641-064A066E066F0671-06D306D506EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA0800-08150904-0939093D09500958-096109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E450E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10D0-10FA1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317DC1820-18421844-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C771CE9-1CEC1CEE-1CF12135-21382D30-2D652D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE3006303C3041-3096309F30A1-30FA30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A014A016-A48CA4D0-A4F7A500-A60BA610-A61FA62AA62BA66EA6A0-A6E5A7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2AA00-AA28AA40-AA42AA44-AA4BAA60-AA6FAA71-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADBAADCABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF66-FF6FFF71-FF9DFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC", M: "0300-036F0483-04890591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DE-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0903093C093E-094E0951-0955096209630981-098309BC09BE-09C409C709C809CB-09CD09D709E209E30A01-0A030A3C0A3E-0A420A470A480A4B-0A4D0A510A700A710A750A81-0A830ABC0ABE-0AC50AC7-0AC90ACB-0ACD0AE20AE30B01-0B030B3C0B3E-0B440B470B480B4B-0B4D0B560B570B620B630B820BBE-0BC20BC6-0BC80BCA-0BCD0BD70C01-0C030C3E-0C440C46-0C480C4A-0C4D0C550C560C620C630C820C830CBC0CBE-0CC40CC6-0CC80CCA-0CCD0CD50CD60CE20CE30D020D030D3E-0D440D46-0D480D4A-0D4D0D570D620D630D820D830DCA0DCF-0DD40DD60DD8-0DDF0DF20DF30E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F3E0F3F0F71-0F840F860F870F90-0F970F99-0FBC0FC6102B-103E1056-1059105E-10601062-10641067-106D1071-10741082-108D108F109A-109D135F1712-17141732-1734175217531772177317B6-17D317DD180B-180D18A91920-192B1930-193B19B0-19C019C819C91A17-1A1B1A55-1A5E1A60-1A7C1A7F1B00-1B041B34-1B441B6B-1B731B80-1B821BA1-1BAA1C24-1C371CD0-1CD21CD4-1CE81CED1CF21DC0-1DE61DFD-1DFF20D0-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66F-A672A67CA67DA6F0A6F1A802A806A80BA823-A827A880A881A8B4-A8C4A8E0-A8F1A926-A92DA947-A953A980-A983A9B3-A9C0AA29-AA36AA43AA4CAA4DAA7BAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE3-ABEAABECABEDFB1EFE00-FE0FFE20-FE26", Mn: "0300-036F0483-04870591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DF-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0902093C0941-0948094D0951-095509620963098109BC09C1-09C409CD09E209E30A010A020A3C0A410A420A470A480A4B-0A4D0A510A700A710A750A810A820ABC0AC1-0AC50AC70AC80ACD0AE20AE30B010B3C0B3F0B41-0B440B4D0B560B620B630B820BC00BCD0C3E-0C400C46-0C480C4A-0C4D0C550C560C620C630CBC0CBF0CC60CCC0CCD0CE20CE30D41-0D440D4D0D620D630DCA0DD2-0DD40DD60E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F71-0F7E0F80-0F840F860F870F90-0F970F99-0FBC0FC6102D-10301032-10371039103A103D103E10581059105E-10601071-1074108210851086108D109D135F1712-17141732-1734175217531772177317B7-17BD17C617C9-17D317DD180B-180D18A91920-19221927192819321939-193B1A171A181A561A58-1A5E1A601A621A65-1A6C1A73-1A7C1A7F1B00-1B031B341B36-1B3A1B3C1B421B6B-1B731B801B811BA2-1BA51BA81BA91C2C-1C331C361C371CD0-1CD21CD4-1CE01CE2-1CE81CED1DC0-1DE61DFD-1DFF20D0-20DC20E120E5-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66FA67CA67DA6F0A6F1A802A806A80BA825A826A8C4A8E0-A8F1A926-A92DA947-A951A980-A982A9B3A9B6-A9B9A9BCAA29-AA2EAA31AA32AA35AA36AA43AA4CAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE5ABE8ABEDFB1EFE00-FE0FFE20-FE26", Mc: "0903093E-09400949-094C094E0982098309BE-09C009C709C809CB09CC09D70A030A3E-0A400A830ABE-0AC00AC90ACB0ACC0B020B030B3E0B400B470B480B4B0B4C0B570BBE0BBF0BC10BC20BC6-0BC80BCA-0BCC0BD70C01-0C030C41-0C440C820C830CBE0CC0-0CC40CC70CC80CCA0CCB0CD50CD60D020D030D3E-0D400D46-0D480D4A-0D4C0D570D820D830DCF-0DD10DD8-0DDF0DF20DF30F3E0F3F0F7F102B102C10311038103B103C105610571062-10641067-106D108310841087-108C108F109A-109C17B617BE-17C517C717C81923-19261929-192B193019311933-193819B0-19C019C819C91A19-1A1B1A551A571A611A631A641A6D-1A721B041B351B3B1B3D-1B411B431B441B821BA11BA61BA71BAA1C24-1C2B1C341C351CE11CF2A823A824A827A880A881A8B4-A8C3A952A953A983A9B4A9B5A9BAA9BBA9BD-A9C0AA2FAA30AA33AA34AA4DAA7BABE3ABE4ABE6ABE7ABE9ABEAABEC", Me: "0488048906DE20DD-20E020E2-20E4A670-A672", N: "0030-003900B200B300B900BC-00BE0660-066906F0-06F907C0-07C90966-096F09E6-09EF09F4-09F90A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BF20C66-0C6F0C78-0C7E0CE6-0CEF0D66-0D750E50-0E590ED0-0ED90F20-0F331040-10491090-10991369-137C16EE-16F017E0-17E917F0-17F91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C5920702074-20792080-20892150-21822185-21892460-249B24EA-24FF2776-27932CFD30073021-30293038-303A3192-31953220-32293251-325F3280-328932B1-32BFA620-A629A6E6-A6EFA830-A835A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19", Nd: "0030-00390660-066906F0-06F907C0-07C90966-096F09E6-09EF0A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BEF0C66-0C6F0CE6-0CEF0D66-0D6F0E50-0E590ED0-0ED90F20-0F291040-10491090-109917E0-17E91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C59A620-A629A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19", Nl: "16EE-16F02160-21822185-218830073021-30293038-303AA6E6-A6EF", No: "00B200B300B900BC-00BE09F4-09F90BF0-0BF20C78-0C7E0D70-0D750F2A-0F331369-137C17F0-17F920702074-20792080-20892150-215F21892460-249B24EA-24FF2776-27932CFD3192-31953220-32293251-325F3280-328932B1-32BFA830-A835", P: "0021-00230025-002A002C-002F003A003B003F0040005B-005D005F007B007D00A100AB00B700BB00BF037E0387055A-055F0589058A05BE05C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F3A-0F3D0F850FD0-0FD4104A-104F10FB1361-13681400166D166E169B169C16EB-16ED1735173617D4-17D617D8-17DA1800-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD32010-20272030-20432045-20512053-205E207D207E208D208E2329232A2768-277527C527C627E6-27EF2983-299829D8-29DB29FC29FD2CF9-2CFC2CFE2CFF2E00-2E2E2E302E313001-30033008-30113014-301F3030303D30A030FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFD3EFD3FFE10-FE19FE30-FE52FE54-FE61FE63FE68FE6AFE6BFF01-FF03FF05-FF0AFF0C-FF0FFF1AFF1BFF1FFF20FF3B-FF3DFF3FFF5BFF5DFF5F-FF65", Pd: "002D058A05BE140018062010-20152E172E1A301C303030A0FE31FE32FE58FE63FF0D", Ps: "0028005B007B0F3A0F3C169B201A201E2045207D208D23292768276A276C276E27702772277427C527E627E827EA27EC27EE2983298529872989298B298D298F299129932995299729D829DA29FC2E222E242E262E283008300A300C300E3010301430163018301A301DFD3EFE17FE35FE37FE39FE3BFE3DFE3FFE41FE43FE47FE59FE5BFE5DFF08FF3BFF5BFF5FFF62", Pe: "0029005D007D0F3B0F3D169C2046207E208E232A2769276B276D276F27712773277527C627E727E927EB27ED27EF298429862988298A298C298E2990299229942996299829D929DB29FD2E232E252E272E293009300B300D300F3011301530173019301B301E301FFD3FFE18FE36FE38FE3AFE3CFE3EFE40FE42FE44FE48FE5AFE5CFE5EFF09FF3DFF5DFF60FF63", Pi: "00AB2018201B201C201F20392E022E042E092E0C2E1C2E20", Pf: "00BB2019201D203A2E032E052E0A2E0D2E1D2E21", Pc: "005F203F20402054FE33FE34FE4D-FE4FFF3F", Po: "0021-00230025-0027002A002C002E002F003A003B003F0040005C00A100B700BF037E0387055A-055F058905C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F850FD0-0FD4104A-104F10FB1361-1368166D166E16EB-16ED1735173617D4-17D617D8-17DA1800-18051807-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD3201620172020-20272030-2038203B-203E2041-20432047-205120532055-205E2CF9-2CFC2CFE2CFF2E002E012E06-2E082E0B2E0E-2E162E182E192E1B2E1E2E1F2E2A-2E2E2E302E313001-3003303D30FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFE10-FE16FE19FE30FE45FE46FE49-FE4CFE50-FE52FE54-FE57FE5F-FE61FE68FE6AFE6BFF01-FF03FF05-FF07FF0AFF0CFF0EFF0FFF1AFF1BFF1FFF20FF3CFF61FF64FF65", S: "0024002B003C-003E005E0060007C007E00A2-00A900AC00AE-00B100B400B600B800D700F702C2-02C502D2-02DF02E5-02EB02ED02EF-02FF03750384038503F604820606-0608060B060E060F06E906FD06FE07F609F209F309FA09FB0AF10B700BF3-0BFA0C7F0CF10CF20D790E3F0F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-139917DB194019E0-19FF1B61-1B6A1B74-1B7C1FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE20442052207A-207C208A-208C20A0-20B8210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B2140-2144214A-214D214F2190-2328232B-23E82400-24262440-244A249C-24E92500-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE27C0-27C427C7-27CA27CC27D0-27E527F0-29822999-29D729DC-29FB29FE-2B4C2B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F309B309C319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A700-A716A720A721A789A78AA828-A82BA836-A839AA77-AA79FB29FDFCFDFDFE62FE64-FE66FE69FF04FF0BFF1C-FF1EFF3EFF40FF5CFF5EFFE0-FFE6FFE8-FFEEFFFCFFFD", Sm: "002B003C-003E007C007E00AC00B100D700F703F60606-060820442052207A-207C208A-208C2140-2144214B2190-2194219A219B21A021A321A621AE21CE21CF21D221D421F4-22FF2308-230B23202321237C239B-23B323DC-23E125B725C125F8-25FF266F27C0-27C427C7-27CA27CC27D0-27E527F0-27FF2900-29822999-29D729DC-29FB29FE-2AFF2B30-2B442B47-2B4CFB29FE62FE64-FE66FF0BFF1C-FF1EFF5CFF5EFFE2FFE9-FFEC", Sc: "002400A2-00A5060B09F209F309FB0AF10BF90E3F17DB20A0-20B8A838FDFCFE69FF04FFE0FFE1FFE5FFE6", Sk: "005E006000A800AF00B400B802C2-02C502D2-02DF02E5-02EB02ED02EF-02FF0375038403851FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE309B309CA700-A716A720A721A789A78AFF3EFF40FFE3", So: "00A600A700A900AE00B000B60482060E060F06E906FD06FE07F609FA0B700BF3-0BF80BFA0C7F0CF10CF20D790F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-1399194019E0-19FF1B61-1B6A1B74-1B7C210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B214A214C214D214F2195-2199219C-219F21A121A221A421A521A7-21AD21AF-21CD21D021D121D321D5-21F32300-2307230C-231F2322-2328232B-237B237D-239A23B4-23DB23E2-23E82400-24262440-244A249C-24E92500-25B625B8-25C025C2-25F72600-266E2670-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE2800-28FF2B00-2B2F2B452B462B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A828-A82BA836A837A839AA77-AA79FDFDFFE4FFE8FFEDFFEEFFFCFFFD", Z: "002000A01680180E2000-200A20282029202F205F3000", Zs: "002000A01680180E2000-200A202F205F3000", Zl: "2028", Zp: "2029", C: "0000-001F007F-009F00AD03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-0605061C061D0620065F06DD070E070F074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17B417B517DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF200B-200F202A-202E2060-206F20722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-F8FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFD-FF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFFBFFFEFFFF", Cc: "0000-001F007F-009F", Cf: "00AD0600-060306DD070F17B417B5200B-200F202A-202E2060-2064206A-206FFEFFFFF9-FFFB", Co: "E000-F8FF", Cs: "D800-DFFF", Cn: "03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-05FF06040605061C061D0620065F070E074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF2065-206920722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-D7FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFDFEFEFF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFF8FFFEFFFF" }); function addUnicodePackage (pack) { var codePoint = /\w{4}/g; for (var name in pack) exports.packages[name] = pack[name].replace(codePoint, "\\u$&"); }; }); ace.define("ace/token_iterator",["require","exports","module"], function(require, exports, module) { "use strict"; var TokenIterator = function(session, initialRow, initialColumn) { this.$session = session; this.$row = initialRow; this.$rowTokens = session.getTokens(initialRow); var token = session.getTokenAt(initialRow, initialColumn); this.$tokenIndex = token ? token.index : -1; }; (function() { this.stepBackward = function() { this.$tokenIndex -= 1; while (this.$tokenIndex < 0) { this.$row -= 1; if (this.$row < 0) { this.$row = 0; return null; } this.$rowTokens = this.$session.getTokens(this.$row); this.$tokenIndex = this.$rowTokens.length - 1; } return this.$rowTokens[this.$tokenIndex]; }; this.stepForward = function() { this.$tokenIndex += 1; var rowCount; while (this.$tokenIndex >= this.$rowTokens.length) { this.$row += 1; if (!rowCount) rowCount = this.$session.getLength(); if (this.$row >= rowCount) { this.$row = rowCount - 1; return null; } this.$rowTokens = this.$session.getTokens(this.$row); this.$tokenIndex = 0; } return this.$rowTokens[this.$tokenIndex]; }; this.getCurrentToken = function () { return this.$rowTokens[this.$tokenIndex]; }; this.getCurrentTokenRow = function () { return this.$row; }; this.getCurrentTokenColumn = function() { var rowTokens = this.$rowTokens; var tokenIndex = this.$tokenIndex; var column = rowTokens[tokenIndex].start; if (column !== undefined) return column; column = 0; while (tokenIndex > 0) { tokenIndex -= 1; column += rowTokens[tokenIndex].value.length; } return column; }; }).call(TokenIterator.prototype); exports.TokenIterator = TokenIterator; }); ace.define("ace/mode/text",["require","exports","module","ace/tokenizer","ace/mode/text_highlight_rules","ace/mode/behaviour","ace/unicode","ace/lib/lang","ace/token_iterator","ace/range"], function(require, exports, module) { "use strict"; var Tokenizer = require("../tokenizer").Tokenizer; var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var Behaviour = require("./behaviour").Behaviour; var unicode = require("../unicode"); var lang = require("../lib/lang"); var TokenIterator = require("../token_iterator").TokenIterator; var Range = require("../range").Range; var Mode = function() { this.HighlightRules = TextHighlightRules; this.$behaviour = new Behaviour(); }; (function() { this.tokenRe = new RegExp("^[" + unicode.packages.L + unicode.packages.Mn + unicode.packages.Mc + unicode.packages.Nd + unicode.packages.Pc + "\\$_]+", "g" ); this.nonTokenRe = new RegExp("^(?:[^" + unicode.packages.L + unicode.packages.Mn + unicode.packages.Mc + unicode.packages.Nd + unicode.packages.Pc + "\\$_]|\\s])+", "g" ); this.getTokenizer = function() { if (!this.$tokenizer) { this.$highlightRules = this.$highlightRules || new this.HighlightRules(); this.$tokenizer = new Tokenizer(this.$highlightRules.getRules()); } return this.$tokenizer; }; this.lineCommentStart = ""; this.blockComment = ""; this.toggleCommentLines = function(state, session, startRow, endRow) { var doc = session.doc; var ignoreBlankLines = true; var shouldRemove = true; var minIndent = Infinity; var tabSize = session.getTabSize(); var insertAtTabStop = false; if (!this.lineCommentStart) { if (!this.blockComment) return false; var lineCommentStart = this.blockComment.start; var lineCommentEnd = this.blockComment.end; var regexpStart = new RegExp("^(\\s*)(?:" + lang.escapeRegExp(lineCommentStart) + ")"); var regexpEnd = new RegExp("(?:" + lang.escapeRegExp(lineCommentEnd) + ")\\s*$"); var comment = function(line, i) { if (testRemove(line, i)) return; if (!ignoreBlankLines || /\S/.test(line)) { doc.insertInLine({row: i, column: line.length}, lineCommentEnd); doc.insertInLine({row: i, column: minIndent}, lineCommentStart); } }; var uncomment = function(line, i) { var m; if (m = line.match(regexpEnd)) doc.removeInLine(i, line.length - m[0].length, line.length); if (m = line.match(regexpStart)) doc.removeInLine(i, m[1].length, m[0].length); }; var testRemove = function(line, row) { if (regexpStart.test(line)) return true; var tokens = session.getTokens(row); for (var i = 0; i < tokens.length; i++) { if (tokens[i].type === 'comment') return true; } }; } else { if (Array.isArray(this.lineCommentStart)) { var regexpStart = this.lineCommentStart.map(lang.escapeRegExp).join("|"); var lineCommentStart = this.lineCommentStart[0]; } else { var regexpStart = lang.escapeRegExp(this.lineCommentStart); var lineCommentStart = this.lineCommentStart; } regexpStart = new RegExp("^(\\s*)(?:" + regexpStart + ") ?"); insertAtTabStop = session.getUseSoftTabs(); var uncomment = function(line, i) { var m = line.match(regexpStart); if (!m) return; var start = m[1].length, end = m[0].length; if (!shouldInsertSpace(line, start, end) && m[0][end - 1] == " ") end--; doc.removeInLine(i, start, end); }; var commentWithSpace = lineCommentStart + " "; var comment = function(line, i) { if (!ignoreBlankLines || /\S/.test(line)) { if (shouldInsertSpace(line, minIndent, minIndent)) doc.insertInLine({row: i, column: minIndent}, commentWithSpace); else doc.insertInLine({row: i, column: minIndent}, lineCommentStart); } }; var testRemove = function(line, i) { return regexpStart.test(line); }; var shouldInsertSpace = function(line, before, after) { var spaces = 0; while (before-- && line.charAt(before) == " ") spaces++; if (spaces % tabSize != 0) return false; var spaces = 0; while (line.charAt(after++) == " ") spaces++; if (tabSize > 2) return spaces % tabSize != tabSize - 1; else return spaces % tabSize == 0; return true; }; } function iter(fun) { for (var i = startRow; i <= endRow; i++) fun(doc.getLine(i), i); } var minEmptyLength = Infinity; iter(function(line, i) { var indent = line.search(/\S/); if (indent !== -1) { if (indent < minIndent) minIndent = indent; if (shouldRemove && !testRemove(line, i)) shouldRemove = false; } else if (minEmptyLength > line.length) { minEmptyLength = line.length; } }); if (minIndent == Infinity) { minIndent = minEmptyLength; ignoreBlankLines = false; shouldRemove = false; } if (insertAtTabStop && minIndent % tabSize != 0) minIndent = Math.floor(minIndent / tabSize) * tabSize; iter(shouldRemove ? uncomment : comment); }; this.toggleBlockComment = function(state, session, range, cursor) { var comment = this.blockComment; if (!comment) return; if (!comment.start && comment[0]) comment = comment[0]; var iterator = new TokenIterator(session, cursor.row, cursor.column); var token = iterator.getCurrentToken(); var sel = session.selection; var initialRange = session.selection.toOrientedRange(); var startRow, colDiff; if (token && /comment/.test(token.type)) { var startRange, endRange; while (token && /comment/.test(token.type)) { var i = token.value.indexOf(comment.start); if (i != -1) { var row = iterator.getCurrentTokenRow(); var column = iterator.getCurrentTokenColumn() + i; startRange = new Range(row, column, row, column + comment.start.length); break; } token = iterator.stepBackward(); } var iterator = new TokenIterator(session, cursor.row, cursor.column); var token = iterator.getCurrentToken(); while (token && /comment/.test(token.type)) { var i = token.value.indexOf(comment.end); if (i != -1) { var row = iterator.getCurrentTokenRow(); var column = iterator.getCurrentTokenColumn() + i; endRange = new Range(row, column, row, column + comment.end.length); break; } token = iterator.stepForward(); } if (endRange) session.remove(endRange); if (startRange) { session.remove(startRange); startRow = startRange.start.row; colDiff = -comment.start.length; } } else { colDiff = comment.start.length; startRow = range.start.row; session.insert(range.end, comment.end); session.insert(range.start, comment.start); } if (initialRange.start.row == startRow) initialRange.start.column += colDiff; if (initialRange.end.row == startRow) initialRange.end.column += colDiff; session.selection.fromOrientedRange(initialRange); }; this.getNextLineIndent = function(state, line, tab) { return this.$getIndent(line); }; this.checkOutdent = function(state, line, input) { return false; }; this.autoOutdent = function(state, doc, row) { }; this.$getIndent = function(line) { return line.match(/^\s*/)[0]; }; this.createWorker = function(session) { return null; }; this.createModeDelegates = function (mapping) { this.$embeds = []; this.$modes = {}; for (var i in mapping) { if (mapping[i]) { this.$embeds.push(i); this.$modes[i] = new mapping[i](); } } var delegations = ['toggleBlockComment', 'toggleCommentLines', 'getNextLineIndent', 'checkOutdent', 'autoOutdent', 'transformAction', 'getCompletions']; for (var i = 0; i < delegations.length; i++) { (function(scope) { var functionName = delegations[i]; var defaultHandler = scope[functionName]; scope[delegations[i]] = function() { return this.$delegator(functionName, arguments, defaultHandler); }; } (this)); } }; this.$delegator = function(method, args, defaultHandler) { var state = args[0]; if (typeof state != "string") state = state[0]; for (var i = 0; i < this.$embeds.length; i++) { if (!this.$modes[this.$embeds[i]]) continue; var split = state.split(this.$embeds[i]); if (!split[0] && split[1]) { args[0] = split[1]; var mode = this.$modes[this.$embeds[i]]; return mode[method].apply(mode, args); } } var ret = defaultHandler.apply(this, args); return defaultHandler ? ret : undefined; }; this.transformAction = function(state, action, editor, session, param) { if (this.$behaviour) { var behaviours = this.$behaviour.getBehaviours(); for (var key in behaviours) { if (behaviours[key][action]) { var ret = behaviours[key][action].apply(this, arguments); if (ret) { return ret; } } } } }; this.getKeywords = function(append) { if (!this.completionKeywords) { var rules = this.$tokenizer.rules; var completionKeywords = []; for (var rule in rules) { var ruleItr = rules[rule]; for (var r = 0, l = ruleItr.length; r < l; r++) { if (typeof ruleItr[r].token === "string") { if (/keyword|support|storage/.test(ruleItr[r].token)) completionKeywords.push(ruleItr[r].regex); } else if (typeof ruleItr[r].token === "object") { for (var a = 0, aLength = ruleItr[r].token.length; a < aLength; a++) { if (/keyword|support|storage/.test(ruleItr[r].token[a])) { var rule = ruleItr[r].regex.match(/\(.+?\)/g)[a]; completionKeywords.push(rule.substr(1, rule.length - 2)); } } } } } this.completionKeywords = completionKeywords; } if (!append) return this.$keywordList; return completionKeywords.concat(this.$keywordList || []); }; this.$createKeywordList = function() { if (!this.$highlightRules) this.getTokenizer(); return this.$keywordList = this.$highlightRules.$keywordList || []; }; this.getCompletions = function(state, session, pos, prefix) { var keywords = this.$keywordList || this.$createKeywordList(); return keywords.map(function(word) { return { name: word, value: word, score: 0, meta: "keyword" }; }); }; this.$id = "ace/mode/text"; }).call(Mode.prototype); exports.Mode = Mode; }); ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Anchor = exports.Anchor = function(doc, row, column) { this.$onChange = this.onChange.bind(this); this.attach(doc); if (typeof column == "undefined") this.setPosition(row.row, row.column); else this.setPosition(row, column); }; (function() { oop.implement(this, EventEmitter); this.getPosition = function() { return this.$clipPositionToDocument(this.row, this.column); }; this.getDocument = function() { return this.document; }; this.$insertRight = false; this.onChange = function(e) { var delta = e.data; var range = delta.range; if (range.start.row == range.end.row && range.start.row != this.row) return; if (range.start.row > this.row) return; if (range.start.row == this.row && range.start.column > this.column) return; var row = this.row; var column = this.column; var start = range.start; var end = range.end; if (delta.action === "insertText") { if (start.row === row && start.column <= column) { if (start.column === column && this.$insertRight) { } else if (start.row === end.row) { column += end.column - start.column; } else { column -= start.column; row += end.row - start.row; } } else if (start.row !== end.row && start.row < row) { row += end.row - start.row; } } else if (delta.action === "insertLines") { if (start.row === row && column === 0 && this.$insertRight) { } else if (start.row <= row) { row += end.row - start.row; } } else if (delta.action === "removeText") { if (start.row === row && start.column < column) { if (end.column >= column) column = start.column; else column = Math.max(0, column - (end.column - start.column)); } else if (start.row !== end.row && start.row < row) { if (end.row === row) column = Math.max(0, column - end.column) + start.column; row -= (end.row - start.row); } else if (end.row === row) { row -= end.row - start.row; column = Math.max(0, column - end.column) + start.column; } } else if (delta.action == "removeLines") { if (start.row <= row) { if (end.row <= row) row -= end.row - start.row; else { row = start.row; column = 0; } } } this.setPosition(row, column, true); }; this.setPosition = function(row, column, noClip) { var pos; if (noClip) { pos = { row: row, column: column }; } else { pos = this.$clipPositionToDocument(row, column); } if (this.row == pos.row && this.column == pos.column) return; var old = { row: this.row, column: this.column }; this.row = pos.row; this.column = pos.column; this._signal("change", { old: old, value: pos }); }; this.detach = function() { this.document.removeEventListener("change", this.$onChange); }; this.attach = function(doc) { this.document = doc || this.document; this.document.on("change", this.$onChange); }; this.$clipPositionToDocument = function(row, column) { var pos = {}; if (row >= this.document.getLength()) { pos.row = Math.max(0, this.document.getLength() - 1); pos.column = this.document.getLine(pos.row).length; } else if (row < 0) { pos.row = 0; pos.column = 0; } else { pos.row = row; pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column)); } if (column < 0) pos.column = 0; return pos; }; }).call(Anchor.prototype); }); ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Range = require("./range").Range; var Anchor = require("./anchor").Anchor; var Document = function(text) { this.$lines = []; if (text.length === 0) { this.$lines = [""]; } else if (Array.isArray(text)) { this._insertLines(0, text); } else { this.insert({row: 0, column:0}, text); } }; (function() { oop.implement(this, EventEmitter); this.setValue = function(text) { var len = this.getLength(); this.remove(new Range(0, 0, len, this.getLine(len-1).length)); this.insert({row: 0, column:0}, text); }; this.getValue = function() { return this.getAllLines().join(this.getNewLineCharacter()); }; this.createAnchor = function(row, column) { return new Anchor(this, row, column); }; if ("aaa".split(/a/).length === 0) this.$split = function(text) { return text.replace(/\r\n|\r/g, "\n").split("\n"); }; else this.$split = function(text) { return text.split(/\r\n|\r|\n/); }; this.$detectNewLine = function(text) { var match = text.match(/^.*?(\r\n|\r|\n)/m); this.$autoNewLine = match ? match[1] : "\n"; this._signal("changeNewLineMode"); }; this.getNewLineCharacter = function() { switch (this.$newLineMode) { case "windows": return "\r\n"; case "unix": return "\n"; default: return this.$autoNewLine || "\n"; } }; this.$autoNewLine = ""; this.$newLineMode = "auto"; this.setNewLineMode = function(newLineMode) { if (this.$newLineMode === newLineMode) return; this.$newLineMode = newLineMode; this._signal("changeNewLineMode"); }; this.getNewLineMode = function() { return this.$newLineMode; }; this.isNewLine = function(text) { return (text == "\r\n" || text == "\r" || text == "\n"); }; this.getLine = function(row) { return this.$lines[row] || ""; }; this.getLines = function(firstRow, lastRow) { return this.$lines.slice(firstRow, lastRow + 1); }; this.getAllLines = function() { return this.getLines(0, this.getLength()); }; this.getLength = function() { return this.$lines.length; }; this.getTextRange = function(range) { if (range.start.row == range.end.row) { return this.getLine(range.start.row) .substring(range.start.column, range.end.column); } var lines = this.getLines(range.start.row, range.end.row); lines[0] = (lines[0] || "").substring(range.start.column); var l = lines.length - 1; if (range.end.row - range.start.row == l) lines[l] = lines[l].substring(0, range.end.column); return lines.join(this.getNewLineCharacter()); }; this.$clipPosition = function(position) { var length = this.getLength(); if (position.row >= length) { position.row = Math.max(0, length - 1); position.column = this.getLine(length-1).length; } else if (position.row < 0) position.row = 0; return position; }; this.insert = function(position, text) { if (!text || text.length === 0) return position; position = this.$clipPosition(position); if (this.getLength() <= 1) this.$detectNewLine(text); var lines = this.$split(text); var firstLine = lines.splice(0, 1)[0]; var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0]; position = this.insertInLine(position, firstLine); if (lastLine !== null) { position = this.insertNewLine(position); // terminate first line position = this._insertLines(position.row, lines); position = this.insertInLine(position, lastLine || ""); } return position; }; this.insertLines = function(row, lines) { if (row >= this.getLength()) return this.insert({row: row, column: 0}, "\n" + lines.join("\n")); return this._insertLines(Math.max(row, 0), lines); }; this._insertLines = function(row, lines) { if (lines.length == 0) return {row: row, column: 0}; while (lines.length > 0xF000) { var end = this._insertLines(row, lines.slice(0, 0xF000)); lines = lines.slice(0xF000); row = end.row; } var args = [row, 0]; args.push.apply(args, lines); this.$lines.splice.apply(this.$lines, args); var range = new Range(row, 0, row + lines.length, 0); var delta = { action: "insertLines", range: range, lines: lines }; this._signal("change", { data: delta }); return range.end; }; this.insertNewLine = function(position) { position = this.$clipPosition(position); var line = this.$lines[position.row] || ""; this.$lines[position.row] = line.substring(0, position.column); this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length)); var end = { row : position.row + 1, column : 0 }; var delta = { action: "insertText", range: Range.fromPoints(position, end), text: this.getNewLineCharacter() }; this._signal("change", { data: delta }); return end; }; this.insertInLine = function(position, text) { if (text.length == 0) return position; var line = this.$lines[position.row] || ""; this.$lines[position.row] = line.substring(0, position.column) + text + line.substring(position.column); var end = { row : position.row, column : position.column + text.length }; var delta = { action: "insertText", range: Range.fromPoints(position, end), text: text }; this._signal("change", { data: delta }); return end; }; this.remove = function(range) { if (!(range instanceof Range)) range = Range.fromPoints(range.start, range.end); range.start = this.$clipPosition(range.start); range.end = this.$clipPosition(range.end); if (range.isEmpty()) return range.start; var firstRow = range.start.row; var lastRow = range.end.row; if (range.isMultiLine()) { var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1; var lastFullRow = lastRow - 1; if (range.end.column > 0) this.removeInLine(lastRow, 0, range.end.column); if (lastFullRow >= firstFullRow) this._removeLines(firstFullRow, lastFullRow); if (firstFullRow != firstRow) { this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length); this.removeNewLine(range.start.row); } } else { this.removeInLine(firstRow, range.start.column, range.end.column); } return range.start; }; this.removeInLine = function(row, startColumn, endColumn) { if (startColumn == endColumn) return; var range = new Range(row, startColumn, row, endColumn); var line = this.getLine(row); var removed = line.substring(startColumn, endColumn); var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length); this.$lines.splice(row, 1, newLine); var delta = { action: "removeText", range: range, text: removed }; this._signal("change", { data: delta }); return range.start; }; this.removeLines = function(firstRow, lastRow) { if (firstRow < 0 || lastRow >= this.getLength()) return this.remove(new Range(firstRow, 0, lastRow + 1, 0)); return this._removeLines(firstRow, lastRow); }; this._removeLines = function(firstRow, lastRow) { var range = new Range(firstRow, 0, lastRow + 1, 0); var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1); var delta = { action: "removeLines", range: range, nl: this.getNewLineCharacter(), lines: removed }; this._signal("change", { data: delta }); return removed; }; this.removeNewLine = function(row) { var firstLine = this.getLine(row); var secondLine = this.getLine(row+1); var range = new Range(row, firstLine.length, row+1, 0); var line = firstLine + secondLine; this.$lines.splice(row, 2, line); var delta = { action: "removeText", range: range, text: this.getNewLineCharacter() }; this._signal("change", { data: delta }); }; this.replace = function(range, text) { if (!(range instanceof Range)) range = Range.fromPoints(range.start, range.end); if (text.length == 0 && range.isEmpty()) return range.start; if (text == this.getTextRange(range)) return range.end; this.remove(range); if (text) { var end = this.insert(range.start, text); } else { end = range.start; } return end; }; this.applyDeltas = function(deltas) { for (var i=0; i=0; i--) { var delta = deltas[i]; var range = Range.fromPoints(delta.range.start, delta.range.end); if (delta.action == "insertLines") this._removeLines(range.start.row, range.end.row - 1); else if (delta.action == "insertText") this.remove(range); else if (delta.action == "removeLines") this._insertLines(range.start.row, delta.lines); else if (delta.action == "removeText") this.insert(range.start, delta.text); } }; this.indexToPosition = function(index, startRow) { var lines = this.$lines || this.getAllLines(); var newlineLength = this.getNewLineCharacter().length; for (var i = startRow || 0, l = lines.length; i < l; i++) { index -= lines[i].length + newlineLength; if (index < 0) return {row: i, column: index + lines[i].length + newlineLength}; } return {row: l-1, column: lines[l-1].length}; }; this.positionToIndex = function(pos, startRow) { var lines = this.$lines || this.getAllLines(); var newlineLength = this.getNewLineCharacter().length; var index = 0; var row = Math.min(pos.row, lines.length); for (var i = startRow || 0; i < row; ++i) index += lines[i].length + newlineLength; return index + pos.column; }; }).call(Document.prototype); exports.Document = Document; }); ace.define("ace/background_tokenizer",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var BackgroundTokenizer = function(tokenizer, editor) { this.running = false; this.lines = []; this.states = []; this.currentLine = 0; this.tokenizer = tokenizer; var self = this; this.$worker = function() { if (!self.running) { return; } var workerStart = new Date(); var currentLine = self.currentLine; var endLine = -1; var doc = self.doc; while (self.lines[currentLine]) currentLine++; var startLine = currentLine; var len = doc.getLength(); var processedLines = 0; self.running = false; while (currentLine < len) { self.$tokenizeRow(currentLine); endLine = currentLine; do { currentLine++; } while (self.lines[currentLine]); processedLines ++; if ((processedLines % 5 === 0) && (new Date() - workerStart) > 20) { self.running = setTimeout(self.$worker, 20); break; } } self.currentLine = currentLine; if (startLine <= endLine) self.fireUpdateEvent(startLine, endLine); }; }; (function(){ oop.implement(this, EventEmitter); this.setTokenizer = function(tokenizer) { this.tokenizer = tokenizer; this.lines = []; this.states = []; this.start(0); }; this.setDocument = function(doc) { this.doc = doc; this.lines = []; this.states = []; this.stop(); }; this.fireUpdateEvent = function(firstRow, lastRow) { var data = { first: firstRow, last: lastRow }; this._signal("update", {data: data}); }; this.start = function(startRow) { this.currentLine = Math.min(startRow || 0, this.currentLine, this.doc.getLength()); this.lines.splice(this.currentLine, this.lines.length); this.states.splice(this.currentLine, this.states.length); this.stop(); this.running = setTimeout(this.$worker, 700); }; this.scheduleStart = function() { if (!this.running) this.running = setTimeout(this.$worker, 700); } this.$updateOnChange = function(delta) { var range = delta.range; var startRow = range.start.row; var len = range.end.row - startRow; if (len === 0) { this.lines[startRow] = null; } else if (delta.action == "removeText" || delta.action == "removeLines") { this.lines.splice(startRow, len + 1, null); this.states.splice(startRow, len + 1, null); } else { var args = Array(len + 1); args.unshift(startRow, 1); this.lines.splice.apply(this.lines, args); this.states.splice.apply(this.states, args); } this.currentLine = Math.min(startRow, this.currentLine, this.doc.getLength()); this.stop(); }; this.stop = function() { if (this.running) clearTimeout(this.running); this.running = false; }; this.getTokens = function(row) { return this.lines[row] || this.$tokenizeRow(row); }; this.getState = function(row) { if (this.currentLine == row) this.$tokenizeRow(row); return this.states[row] || "start"; }; this.$tokenizeRow = function(row) { var line = this.doc.getLine(row); var state = this.states[row - 1]; var data = this.tokenizer.getLineTokens(line, state, row); if (this.states[row] + "" !== data.state + "") { this.states[row] = data.state; this.lines[row + 1] = null; if (this.currentLine > row + 1) this.currentLine = row + 1; } else if (this.currentLine == row) { this.currentLine = row + 1; } return this.lines[row] = data.tokens; }; }).call(BackgroundTokenizer.prototype); exports.BackgroundTokenizer = BackgroundTokenizer; }); ace.define("ace/search_highlight",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"], function(require, exports, module) { "use strict"; var lang = require("./lib/lang"); var oop = require("./lib/oop"); var Range = require("./range").Range; var SearchHighlight = function(regExp, clazz, type) { this.setRegexp(regExp); this.clazz = clazz; this.type = type || "text"; }; (function() { this.MAX_RANGES = 500; this.setRegexp = function(regExp) { if (this.regExp+"" == regExp+"") return; this.regExp = regExp; this.cache = []; }; this.update = function(html, markerLayer, session, config) { if (!this.regExp) return; var start = config.firstRow, end = config.lastRow; for (var i = start; i <= end; i++) { var ranges = this.cache[i]; if (ranges == null) { ranges = lang.getMatchOffsets(session.getLine(i), this.regExp); if (ranges.length > this.MAX_RANGES) ranges = ranges.slice(0, this.MAX_RANGES); ranges = ranges.map(function(match) { return new Range(i, match.offset, i, match.offset + match.length); }); this.cache[i] = ranges.length ? ranges : ""; } for (var j = ranges.length; j --; ) { markerLayer.drawSingleLineMarker( html, ranges[j].toScreenRange(session), this.clazz, config); } } }; }).call(SearchHighlight.prototype); exports.SearchHighlight = SearchHighlight; }); ace.define("ace/edit_session/fold_line",["require","exports","module","ace/range"], function(require, exports, module) { "use strict"; var Range = require("../range").Range; function FoldLine(foldData, folds) { this.foldData = foldData; if (Array.isArray(folds)) { this.folds = folds; } else { folds = this.folds = [ folds ]; } var last = folds[folds.length - 1]; this.range = new Range(folds[0].start.row, folds[0].start.column, last.end.row, last.end.column); this.start = this.range.start; this.end = this.range.end; this.folds.forEach(function(fold) { fold.setFoldLine(this); }, this); } (function() { this.shiftRow = function(shift) { this.start.row += shift; this.end.row += shift; this.folds.forEach(function(fold) { fold.start.row += shift; fold.end.row += shift; }); }; this.addFold = function(fold) { if (fold.sameRow) { if (fold.start.row < this.startRow || fold.endRow > this.endRow) { throw new Error("Can't add a fold to this FoldLine as it has no connection"); } this.folds.push(fold); this.folds.sort(function(a, b) { return -a.range.compareEnd(b.start.row, b.start.column); }); if (this.range.compareEnd(fold.start.row, fold.start.column) > 0) { this.end.row = fold.end.row; this.end.column = fold.end.column; } else if (this.range.compareStart(fold.end.row, fold.end.column) < 0) { this.start.row = fold.start.row; this.start.column = fold.start.column; } } else if (fold.start.row == this.end.row) { this.folds.push(fold); this.end.row = fold.end.row; this.end.column = fold.end.column; } else if (fold.end.row == this.start.row) { this.folds.unshift(fold); this.start.row = fold.start.row; this.start.column = fold.start.column; } else { throw new Error("Trying to add fold to FoldRow that doesn't have a matching row"); } fold.foldLine = this; }; this.containsRow = function(row) { return row >= this.start.row && row <= this.end.row; }; this.walk = function(callback, endRow, endColumn) { var lastEnd = 0, folds = this.folds, fold, cmp, stop, isNewRow = true; if (endRow == null) { endRow = this.end.row; endColumn = this.end.column; } for (var i = 0; i < folds.length; i++) { fold = folds[i]; cmp = fold.range.compareStart(endRow, endColumn); if (cmp == -1) { callback(null, endRow, endColumn, lastEnd, isNewRow); return; } stop = callback(null, fold.start.row, fold.start.column, lastEnd, isNewRow); stop = !stop && callback(fold.placeholder, fold.start.row, fold.start.column, lastEnd); if (stop || cmp === 0) { return; } isNewRow = !fold.sameRow; lastEnd = fold.end.column; } callback(null, endRow, endColumn, lastEnd, isNewRow); }; this.getNextFoldTo = function(row, column) { var fold, cmp; for (var i = 0; i < this.folds.length; i++) { fold = this.folds[i]; cmp = fold.range.compareEnd(row, column); if (cmp == -1) { return { fold: fold, kind: "after" }; } else if (cmp === 0) { return { fold: fold, kind: "inside" }; } } return null; }; this.addRemoveChars = function(row, column, len) { var ret = this.getNextFoldTo(row, column), fold, folds; if (ret) { fold = ret.fold; if (ret.kind == "inside" && fold.start.column != column && fold.start.row != row) { window.console && window.console.log(row, column, fold); } else if (fold.start.row == row) { folds = this.folds; var i = folds.indexOf(fold); if (i === 0) { this.start.column += len; } for (i; i < folds.length; i++) { fold = folds[i]; fold.start.column += len; if (!fold.sameRow) { return; } fold.end.column += len; } this.end.column += len; } } }; this.split = function(row, column) { var pos = this.getNextFoldTo(row, column); if (!pos || pos.kind == "inside") return null; var fold = pos.fold; var folds = this.folds; var foldData = this.foldData; var i = folds.indexOf(fold); var foldBefore = folds[i - 1]; this.end.row = foldBefore.end.row; this.end.column = foldBefore.end.column; folds = folds.splice(i, folds.length - i); var newFoldLine = new FoldLine(foldData, folds); foldData.splice(foldData.indexOf(this) + 1, 0, newFoldLine); return newFoldLine; }; this.merge = function(foldLineNext) { var folds = foldLineNext.folds; for (var i = 0; i < folds.length; i++) { this.addFold(folds[i]); } var foldData = this.foldData; foldData.splice(foldData.indexOf(foldLineNext), 1); }; this.toString = function() { var ret = [this.range.toString() + ": [" ]; this.folds.forEach(function(fold) { ret.push(" " + fold.toString()); }); ret.push("]"); return ret.join("\n"); }; this.idxToPosition = function(idx) { var lastFoldEndColumn = 0; for (var i = 0; i < this.folds.length; i++) { var fold = this.folds[i]; idx -= fold.start.column - lastFoldEndColumn; if (idx < 0) { return { row: fold.start.row, column: fold.start.column + idx }; } idx -= fold.placeholder.length; if (idx < 0) { return fold.start; } lastFoldEndColumn = fold.end.column; } return { row: this.end.row, column: this.end.column + idx }; }; }).call(FoldLine.prototype); exports.FoldLine = FoldLine; }); ace.define("ace/range_list",["require","exports","module","ace/range"], function(require, exports, module) { "use strict"; var Range = require("./range").Range; var comparePoints = Range.comparePoints; var RangeList = function() { this.ranges = []; }; (function() { this.comparePoints = comparePoints; this.pointIndex = function(pos, excludeEdges, startIndex) { var list = this.ranges; for (var i = startIndex || 0; i < list.length; i++) { var range = list[i]; var cmpEnd = comparePoints(pos, range.end); if (cmpEnd > 0) continue; var cmpStart = comparePoints(pos, range.start); if (cmpEnd === 0) return excludeEdges && cmpStart !== 0 ? -i-2 : i; if (cmpStart > 0 || (cmpStart === 0 && !excludeEdges)) return i; return -i-1; } return -i - 1; }; this.add = function(range) { var excludeEdges = !range.isEmpty(); var startIndex = this.pointIndex(range.start, excludeEdges); if (startIndex < 0) startIndex = -startIndex - 1; var endIndex = this.pointIndex(range.end, excludeEdges, startIndex); if (endIndex < 0) endIndex = -endIndex - 1; else endIndex++; return this.ranges.splice(startIndex, endIndex - startIndex, range); }; this.addList = function(list) { var removed = []; for (var i = list.length; i--; ) { removed.push.call(removed, this.add(list[i])); } return removed; }; this.substractPoint = function(pos) { var i = this.pointIndex(pos); if (i >= 0) return this.ranges.splice(i, 1); }; this.merge = function() { var removed = []; var list = this.ranges; list = list.sort(function(a, b) { return comparePoints(a.start, b.start); }); var next = list[0], range; for (var i = 1; i < list.length; i++) { range = next; next = list[i]; var cmp = comparePoints(range.end, next.start); if (cmp < 0) continue; if (cmp == 0 && !range.isEmpty() && !next.isEmpty()) continue; if (comparePoints(range.end, next.end) < 0) { range.end.row = next.end.row; range.end.column = next.end.column; } list.splice(i, 1); removed.push(next); next = range; i--; } this.ranges = list; return removed; }; this.contains = function(row, column) { return this.pointIndex({row: row, column: column}) >= 0; }; this.containsPoint = function(pos) { return this.pointIndex(pos) >= 0; }; this.rangeAtPoint = function(pos) { var i = this.pointIndex(pos); if (i >= 0) return this.ranges[i]; }; this.clipRows = function(startRow, endRow) { var list = this.ranges; if (list[0].start.row > endRow || list[list.length - 1].start.row < startRow) return []; var startIndex = this.pointIndex({row: startRow, column: 0}); if (startIndex < 0) startIndex = -startIndex - 1; var endIndex = this.pointIndex({row: endRow, column: 0}, startIndex); if (endIndex < 0) endIndex = -endIndex - 1; var clipped = []; for (var i = startIndex; i < endIndex; i++) { clipped.push(list[i]); } return clipped; }; this.removeAll = function() { return this.ranges.splice(0, this.ranges.length); }; this.attach = function(session) { if (this.session) this.detach(); this.session = session; this.onChange = this.$onChange.bind(this); this.session.on('change', this.onChange); }; this.detach = function() { if (!this.session) return; this.session.removeListener('change', this.onChange); this.session = null; }; this.$onChange = function(e) { var changeRange = e.data.range; if (e.data.action[0] == "i"){ var start = changeRange.start; var end = changeRange.end; } else { var end = changeRange.start; var start = changeRange.end; } var startRow = start.row; var endRow = end.row; var lineDif = endRow - startRow; var colDiff = -start.column + end.column; var ranges = this.ranges; for (var i = 0, n = ranges.length; i < n; i++) { var r = ranges[i]; if (r.end.row < startRow) continue; if (r.start.row > startRow) break; if (r.start.row == startRow && r.start.column >= start.column ) { if (r.start.column == start.column && this.$insertRight) { } else { r.start.column += colDiff; r.start.row += lineDif; } } if (r.end.row == startRow && r.end.column >= start.column) { if (r.end.column == start.column && this.$insertRight) { continue; } if (r.end.column == start.column && colDiff > 0 && i < n - 1) { if (r.end.column > r.start.column && r.end.column == ranges[i+1].start.column) r.end.column -= colDiff; } r.end.column += colDiff; r.end.row += lineDif; } } if (lineDif != 0 && i < n) { for (; i < n; i++) { var r = ranges[i]; r.start.row += lineDif; r.end.row += lineDif; } } }; }).call(RangeList.prototype); exports.RangeList = RangeList; }); ace.define("ace/edit_session/fold",["require","exports","module","ace/range","ace/range_list","ace/lib/oop"], function(require, exports, module) { "use strict"; var Range = require("../range").Range; var RangeList = require("../range_list").RangeList; var oop = require("../lib/oop") var Fold = exports.Fold = function(range, placeholder) { this.foldLine = null; this.placeholder = placeholder; this.range = range; this.start = range.start; this.end = range.end; this.sameRow = range.start.row == range.end.row; this.subFolds = this.ranges = []; }; oop.inherits(Fold, RangeList); (function() { this.toString = function() { return '"' + this.placeholder + '" ' + this.range.toString(); }; this.setFoldLine = function(foldLine) { this.foldLine = foldLine; this.subFolds.forEach(function(fold) { fold.setFoldLine(foldLine); }); }; this.clone = function() { var range = this.range.clone(); var fold = new Fold(range, this.placeholder); this.subFolds.forEach(function(subFold) { fold.subFolds.push(subFold.clone()); }); fold.collapseChildren = this.collapseChildren; return fold; }; this.addSubFold = function(fold) { if (this.range.isEqual(fold)) return; if (!this.range.containsRange(fold)) throw new Error("A fold can't intersect already existing fold" + fold.range + this.range); consumeRange(fold, this.start); var row = fold.start.row, column = fold.start.column; for (var i = 0, cmp = -1; i < this.subFolds.length; i++) { cmp = this.subFolds[i].range.compare(row, column); if (cmp != 1) break; } var afterStart = this.subFolds[i]; if (cmp == 0) return afterStart.addSubFold(fold); var row = fold.range.end.row, column = fold.range.end.column; for (var j = i, cmp = -1; j < this.subFolds.length; j++) { cmp = this.subFolds[j].range.compare(row, column); if (cmp != 1) break; } var afterEnd = this.subFolds[j]; if (cmp == 0) throw new Error("A fold can't intersect already existing fold" + fold.range + this.range); var consumedFolds = this.subFolds.splice(i, j - i, fold); fold.setFoldLine(this.foldLine); return fold; }; this.restoreRange = function(range) { return restoreRange(range, this.start); }; }).call(Fold.prototype); function consumePoint(point, anchor) { point.row -= anchor.row; if (point.row == 0) point.column -= anchor.column; } function consumeRange(range, anchor) { consumePoint(range.start, anchor); consumePoint(range.end, anchor); } function restorePoint(point, anchor) { if (point.row == 0) point.column += anchor.column; point.row += anchor.row; } function restoreRange(range, anchor) { restorePoint(range.start, anchor); restorePoint(range.end, anchor); } }); ace.define("ace/edit_session/folding",["require","exports","module","ace/range","ace/edit_session/fold_line","ace/edit_session/fold","ace/token_iterator"], function(require, exports, module) { "use strict"; var Range = require("../range").Range; var FoldLine = require("./fold_line").FoldLine; var Fold = require("./fold").Fold; var TokenIterator = require("../token_iterator").TokenIterator; function Folding() { this.getFoldAt = function(row, column, side) { var foldLine = this.getFoldLine(row); if (!foldLine) return null; var folds = foldLine.folds; for (var i = 0; i < folds.length; i++) { var fold = folds[i]; if (fold.range.contains(row, column)) { if (side == 1 && fold.range.isEnd(row, column)) { continue; } else if (side == -1 && fold.range.isStart(row, column)) { continue; } return fold; } } }; this.getFoldsInRange = function(range) { var start = range.start; var end = range.end; var foldLines = this.$foldData; var foundFolds = []; start.column += 1; end.column -= 1; for (var i = 0; i < foldLines.length; i++) { var cmp = foldLines[i].range.compareRange(range); if (cmp == 2) { continue; } else if (cmp == -2) { break; } var folds = foldLines[i].folds; for (var j = 0; j < folds.length; j++) { var fold = folds[j]; cmp = fold.range.compareRange(range); if (cmp == -2) { break; } else if (cmp == 2) { continue; } else if (cmp == 42) { break; } foundFolds.push(fold); } } start.column -= 1; end.column += 1; return foundFolds; }; this.getFoldsInRangeList = function(ranges) { if (Array.isArray(ranges)) { var folds = []; ranges.forEach(function(range) { folds = folds.concat(this.getFoldsInRange(range)); }, this); } else { var folds = this.getFoldsInRange(ranges); } return folds; } this.getAllFolds = function() { var folds = []; var foldLines = this.$foldData; for (var i = 0; i < foldLines.length; i++) for (var j = 0; j < foldLines[i].folds.length; j++) folds.push(foldLines[i].folds[j]); return folds; }; this.getFoldStringAt = function(row, column, trim, foldLine) { foldLine = foldLine || this.getFoldLine(row); if (!foldLine) return null; var lastFold = { end: { column: 0 } }; var str, fold; for (var i = 0; i < foldLine.folds.length; i++) { fold = foldLine.folds[i]; var cmp = fold.range.compareEnd(row, column); if (cmp == -1) { str = this .getLine(fold.start.row) .substring(lastFold.end.column, fold.start.column); break; } else if (cmp === 0) { return null; } lastFold = fold; } if (!str) str = this.getLine(fold.start.row).substring(lastFold.end.column); if (trim == -1) return str.substring(0, column - lastFold.end.column); else if (trim == 1) return str.substring(column - lastFold.end.column); else return str; }; this.getFoldLine = function(docRow, startFoldLine) { var foldData = this.$foldData; var i = 0; if (startFoldLine) i = foldData.indexOf(startFoldLine); if (i == -1) i = 0; for (i; i < foldData.length; i++) { var foldLine = foldData[i]; if (foldLine.start.row <= docRow && foldLine.end.row >= docRow) { return foldLine; } else if (foldLine.end.row > docRow) { return null; } } return null; }; this.getNextFoldLine = function(docRow, startFoldLine) { var foldData = this.$foldData; var i = 0; if (startFoldLine) i = foldData.indexOf(startFoldLine); if (i == -1) i = 0; for (i; i < foldData.length; i++) { var foldLine = foldData[i]; if (foldLine.end.row >= docRow) { return foldLine; } } return null; }; this.getFoldedRowCount = function(first, last) { var foldData = this.$foldData, rowCount = last-first+1; for (var i = 0; i < foldData.length; i++) { var foldLine = foldData[i], end = foldLine.end.row, start = foldLine.start.row; if (end >= last) { if(start < last) { if(start >= first) rowCount -= last-start; else rowCount = 0;//in one fold } break; } else if(end >= first){ if (start >= first) //fold inside range rowCount -= end-start; else rowCount -= end-first+1; } } return rowCount; }; this.$addFoldLine = function(foldLine) { this.$foldData.push(foldLine); this.$foldData.sort(function(a, b) { return a.start.row - b.start.row; }); return foldLine; }; this.addFold = function(placeholder, range) { var foldData = this.$foldData; var added = false; var fold; if (placeholder instanceof Fold) fold = placeholder; else { fold = new Fold(range, placeholder); fold.collapseChildren = range.collapseChildren; } this.$clipRangeToDocument(fold.range); var startRow = fold.start.row; var startColumn = fold.start.column; var endRow = fold.end.row; var endColumn = fold.end.column; if (!(startRow < endRow || startRow == endRow && startColumn <= endColumn - 2)) throw new Error("The range has to be at least 2 characters width"); var startFold = this.getFoldAt(startRow, startColumn, 1); var endFold = this.getFoldAt(endRow, endColumn, -1); if (startFold && endFold == startFold) return startFold.addSubFold(fold); if (startFold && !startFold.range.isStart(startRow, startColumn)) this.removeFold(startFold); if (endFold && !endFold.range.isEnd(endRow, endColumn)) this.removeFold(endFold); var folds = this.getFoldsInRange(fold.range); if (folds.length > 0) { this.removeFolds(folds); folds.forEach(function(subFold) { fold.addSubFold(subFold); }); } for (var i = 0; i < foldData.length; i++) { var foldLine = foldData[i]; if (endRow == foldLine.start.row) { foldLine.addFold(fold); added = true; break; } else if (startRow == foldLine.end.row) { foldLine.addFold(fold); added = true; if (!fold.sameRow) { var foldLineNext = foldData[i + 1]; if (foldLineNext && foldLineNext.start.row == endRow) { foldLine.merge(foldLineNext); break; } } break; } else if (endRow <= foldLine.start.row) { break; } } if (!added) foldLine = this.$addFoldLine(new FoldLine(this.$foldData, fold)); if (this.$useWrapMode) this.$updateWrapData(foldLine.start.row, foldLine.start.row); else this.$updateRowLengthCache(foldLine.start.row, foldLine.start.row); this.$modified = true; this._emit("changeFold", { data: fold, action: "add" }); return fold; }; this.addFolds = function(folds) { folds.forEach(function(fold) { this.addFold(fold); }, this); }; this.removeFold = function(fold) { var foldLine = fold.foldLine; var startRow = foldLine.start.row; var endRow = foldLine.end.row; var foldLines = this.$foldData; var folds = foldLine.folds; if (folds.length == 1) { foldLines.splice(foldLines.indexOf(foldLine), 1); } else if (foldLine.range.isEnd(fold.end.row, fold.end.column)) { folds.pop(); foldLine.end.row = folds[folds.length - 1].end.row; foldLine.end.column = folds[folds.length - 1].end.column; } else if (foldLine.range.isStart(fold.start.row, fold.start.column)) { folds.shift(); foldLine.start.row = folds[0].start.row; foldLine.start.column = folds[0].start.column; } else if (fold.sameRow) { folds.splice(folds.indexOf(fold), 1); } else { var newFoldLine = foldLine.split(fold.start.row, fold.start.column); folds = newFoldLine.folds; folds.shift(); newFoldLine.start.row = folds[0].start.row; newFoldLine.start.column = folds[0].start.column; } if (!this.$updating) { if (this.$useWrapMode) this.$updateWrapData(startRow, endRow); else this.$updateRowLengthCache(startRow, endRow); } this.$modified = true; this._emit("changeFold", { data: fold, action: "remove" }); }; this.removeFolds = function(folds) { var cloneFolds = []; for (var i = 0; i < folds.length; i++) { cloneFolds.push(folds[i]); } cloneFolds.forEach(function(fold) { this.removeFold(fold); }, this); this.$modified = true; }; this.expandFold = function(fold) { this.removeFold(fold); fold.subFolds.forEach(function(subFold) { fold.restoreRange(subFold); this.addFold(subFold); }, this); if (fold.collapseChildren > 0) { this.foldAll(fold.start.row+1, fold.end.row, fold.collapseChildren-1); } fold.subFolds = []; }; this.expandFolds = function(folds) { folds.forEach(function(fold) { this.expandFold(fold); }, this); }; this.unfold = function(location, expandInner) { var range, folds; if (location == null) { range = new Range(0, 0, this.getLength(), 0); expandInner = true; } else if (typeof location == "number") range = new Range(location, 0, location, this.getLine(location).length); else if ("row" in location) range = Range.fromPoints(location, location); else range = location; folds = this.getFoldsInRangeList(range); if (expandInner) { this.removeFolds(folds); } else { var subFolds = folds; while (subFolds.length) { this.expandFolds(subFolds); subFolds = this.getFoldsInRangeList(range); } } if (folds.length) return folds; }; this.isRowFolded = function(docRow, startFoldRow) { return !!this.getFoldLine(docRow, startFoldRow); }; this.getRowFoldEnd = function(docRow, startFoldRow) { var foldLine = this.getFoldLine(docRow, startFoldRow); return foldLine ? foldLine.end.row : docRow; }; this.getRowFoldStart = function(docRow, startFoldRow) { var foldLine = this.getFoldLine(docRow, startFoldRow); return foldLine ? foldLine.start.row : docRow; }; this.getFoldDisplayLine = function(foldLine, endRow, endColumn, startRow, startColumn) { if (startRow == null) startRow = foldLine.start.row; if (startColumn == null) startColumn = 0; if (endRow == null) endRow = foldLine.end.row; if (endColumn == null) endColumn = this.getLine(endRow).length; var doc = this.doc; var textLine = ""; foldLine.walk(function(placeholder, row, column, lastColumn) { if (row < startRow) return; if (row == startRow) { if (column < startColumn) return; lastColumn = Math.max(startColumn, lastColumn); } if (placeholder != null) { textLine += placeholder; } else { textLine += doc.getLine(row).substring(lastColumn, column); } }, endRow, endColumn); return textLine; }; this.getDisplayLine = function(row, endColumn, startRow, startColumn) { var foldLine = this.getFoldLine(row); if (!foldLine) { var line; line = this.doc.getLine(row); return line.substring(startColumn || 0, endColumn || line.length); } else { return this.getFoldDisplayLine( foldLine, row, endColumn, startRow, startColumn); } }; this.$cloneFoldData = function() { var fd = []; fd = this.$foldData.map(function(foldLine) { var folds = foldLine.folds.map(function(fold) { return fold.clone(); }); return new FoldLine(fd, folds); }); return fd; }; this.toggleFold = function(tryToUnfold) { var selection = this.selection; var range = selection.getRange(); var fold; var bracketPos; if (range.isEmpty()) { var cursor = range.start; fold = this.getFoldAt(cursor.row, cursor.column); if (fold) { this.expandFold(fold); return; } else if (bracketPos = this.findMatchingBracket(cursor)) { if (range.comparePoint(bracketPos) == 1) { range.end = bracketPos; } else { range.start = bracketPos; range.start.column++; range.end.column--; } } else if (bracketPos = this.findMatchingBracket({row: cursor.row, column: cursor.column + 1})) { if (range.comparePoint(bracketPos) == 1) range.end = bracketPos; else range.start = bracketPos; range.start.column++; } else { range = this.getCommentFoldRange(cursor.row, cursor.column) || range; } } else { var folds = this.getFoldsInRange(range); if (tryToUnfold && folds.length) { this.expandFolds(folds); return; } else if (folds.length == 1 ) { fold = folds[0]; } } if (!fold) fold = this.getFoldAt(range.start.row, range.start.column); if (fold && fold.range.toString() == range.toString()) { this.expandFold(fold); return; } var placeholder = "..."; if (!range.isMultiLine()) { placeholder = this.getTextRange(range); if(placeholder.length < 4) return; placeholder = placeholder.trim().substring(0, 2) + ".."; } this.addFold(placeholder, range); }; this.getCommentFoldRange = function(row, column, dir) { var iterator = new TokenIterator(this, row, column); var token = iterator.getCurrentToken(); if (token && /^comment|string/.test(token.type)) { var range = new Range(); var re = new RegExp(token.type.replace(/\..*/, "\\.")); if (dir != 1) { do { token = iterator.stepBackward(); } while(token && re.test(token.type)); iterator.stepForward(); } range.start.row = iterator.getCurrentTokenRow(); range.start.column = iterator.getCurrentTokenColumn() + 2; iterator = new TokenIterator(this, row, column); if (dir != -1) { do { token = iterator.stepForward(); } while(token && re.test(token.type)); token = iterator.stepBackward(); } else token = iterator.getCurrentToken(); range.end.row = iterator.getCurrentTokenRow(); range.end.column = iterator.getCurrentTokenColumn() + token.value.length - 2; return range; } }; this.foldAll = function(startRow, endRow, depth) { if (depth == undefined) depth = 100000; // JSON.stringify doesn't hanle Infinity var foldWidgets = this.foldWidgets; if (!foldWidgets) return; // mode doesn't support folding endRow = endRow || this.getLength(); startRow = startRow || 0; for (var row = startRow; row < endRow; row++) { if (foldWidgets[row] == null) foldWidgets[row] = this.getFoldWidget(row); if (foldWidgets[row] != "start") continue; var range = this.getFoldWidgetRange(row); if (range && range.isMultiLine() && range.end.row <= endRow && range.start.row >= startRow ) { row = range.end.row; try { var fold = this.addFold("...", range); if (fold) fold.collapseChildren = depth; } catch(e) {} } } }; this.$foldStyles = { "manual": 1, "markbegin": 1, "markbeginend": 1 }; this.$foldStyle = "markbegin"; this.setFoldStyle = function(style) { if (!this.$foldStyles[style]) throw new Error("invalid fold style: " + style + "[" + Object.keys(this.$foldStyles).join(", ") + "]"); if (this.$foldStyle == style) return; this.$foldStyle = style; if (style == "manual") this.unfold(); var mode = this.$foldMode; this.$setFolding(null); this.$setFolding(mode); }; this.$setFolding = function(foldMode) { if (this.$foldMode == foldMode) return; this.$foldMode = foldMode; this.removeListener('change', this.$updateFoldWidgets); this._emit("changeAnnotation"); if (!foldMode || this.$foldStyle == "manual") { this.foldWidgets = null; return; } this.foldWidgets = []; this.getFoldWidget = foldMode.getFoldWidget.bind(foldMode, this, this.$foldStyle); this.getFoldWidgetRange = foldMode.getFoldWidgetRange.bind(foldMode, this, this.$foldStyle); this.$updateFoldWidgets = this.updateFoldWidgets.bind(this); this.on('change', this.$updateFoldWidgets); }; this.getParentFoldRangeData = function (row, ignoreCurrent) { var fw = this.foldWidgets; if (!fw || (ignoreCurrent && fw[row])) return {}; var i = row - 1, firstRange; while (i >= 0) { var c = fw[i]; if (c == null) c = fw[i] = this.getFoldWidget(i); if (c == "start") { var range = this.getFoldWidgetRange(i); if (!firstRange) firstRange = range; if (range && range.end.row >= row) break; } i--; } return { range: i !== -1 && range, firstRange: firstRange }; } this.onFoldWidgetClick = function(row, e) { e = e.domEvent; var options = { children: e.shiftKey, all: e.ctrlKey || e.metaKey, siblings: e.altKey }; var range = this.$toggleFoldWidget(row, options); if (!range) { var el = (e.target || e.srcElement) if (el && /ace_fold-widget/.test(el.className)) el.className += " ace_invalid"; } }; this.$toggleFoldWidget = function(row, options) { if (!this.getFoldWidget) return; var type = this.getFoldWidget(row); var line = this.getLine(row); var dir = type === "end" ? -1 : 1; var fold = this.getFoldAt(row, dir === -1 ? 0 : line.length, dir); if (fold) { if (options.children || options.all) this.removeFold(fold); else this.expandFold(fold); return; } var range = this.getFoldWidgetRange(row, true); if (range && !range.isMultiLine()) { fold = this.getFoldAt(range.start.row, range.start.column, 1); if (fold && range.isEqual(fold.range)) { this.removeFold(fold); return; } } if (options.siblings) { var data = this.getParentFoldRangeData(row); if (data.range) { var startRow = data.range.start.row + 1; var endRow = data.range.end.row; } this.foldAll(startRow, endRow, options.all ? 10000 : 0); } else if (options.children) { endRow = range ? range.end.row : this.getLength(); this.foldAll(row + 1, range.end.row, options.all ? 10000 : 0); } else if (range) { if (options.all) range.collapseChildren = 10000; this.addFold("...", range); } return range; }; this.toggleFoldWidget = function(toggleParent) { var row = this.selection.getCursor().row; row = this.getRowFoldStart(row); var range = this.$toggleFoldWidget(row, {}); if (range) return; var data = this.getParentFoldRangeData(row, true); range = data.range || data.firstRange; if (range) { row = range.start.row; var fold = this.getFoldAt(row, this.getLine(row).length, 1); if (fold) { this.removeFold(fold); } else { this.addFold("...", range); } } }; this.updateFoldWidgets = function(e) { var delta = e.data; var range = delta.range; var firstRow = range.start.row; var len = range.end.row - firstRow; if (len === 0) { this.foldWidgets[firstRow] = null; } else if (delta.action == "removeText" || delta.action == "removeLines") { this.foldWidgets.splice(firstRow, len + 1, null); } else { var args = Array(len + 1); args.unshift(firstRow, 1); this.foldWidgets.splice.apply(this.foldWidgets, args); } }; } exports.Folding = Folding; }); ace.define("ace/edit_session/bracket_match",["require","exports","module","ace/token_iterator","ace/range"], function(require, exports, module) { "use strict"; var TokenIterator = require("../token_iterator").TokenIterator; var Range = require("../range").Range; function BracketMatch() { this.findMatchingBracket = function(position, chr) { if (position.column == 0) return null; var charBeforeCursor = chr || this.getLine(position.row).charAt(position.column-1); if (charBeforeCursor == "") return null; var match = charBeforeCursor.match(/([\(\[\{])|([\)\]\}])/); if (!match) return null; if (match[1]) return this.$findClosingBracket(match[1], position); else return this.$findOpeningBracket(match[2], position); }; this.getBracketRange = function(pos) { var line = this.getLine(pos.row); var before = true, range; var chr = line.charAt(pos.column-1); var match = chr && chr.match(/([\(\[\{])|([\)\]\}])/); if (!match) { chr = line.charAt(pos.column); pos = {row: pos.row, column: pos.column + 1}; match = chr && chr.match(/([\(\[\{])|([\)\]\}])/); before = false; } if (!match) return null; if (match[1]) { var bracketPos = this.$findClosingBracket(match[1], pos); if (!bracketPos) return null; range = Range.fromPoints(pos, bracketPos); if (!before) { range.end.column++; range.start.column--; } range.cursor = range.end; } else { var bracketPos = this.$findOpeningBracket(match[2], pos); if (!bracketPos) return null; range = Range.fromPoints(bracketPos, pos); if (!before) { range.start.column++; range.end.column--; } range.cursor = range.start; } return range; }; this.$brackets = { ")": "(", "(": ")", "]": "[", "[": "]", "{": "}", "}": "{" }; this.$findOpeningBracket = function(bracket, position, typeRe) { var openBracket = this.$brackets[bracket]; var depth = 1; var iterator = new TokenIterator(this, position.row, position.column); var token = iterator.getCurrentToken(); if (!token) token = iterator.stepForward(); if (!token) return; if (!typeRe){ typeRe = new RegExp( "(\\.?" + token.type.replace(".", "\\.").replace("rparen", ".paren") .replace(/\b(?:end|start|begin)\b/, "") + ")+" ); } var valueIndex = position.column - iterator.getCurrentTokenColumn() - 2; var value = token.value; while (true) { while (valueIndex >= 0) { var chr = value.charAt(valueIndex); if (chr == openBracket) { depth -= 1; if (depth == 0) { return {row: iterator.getCurrentTokenRow(), column: valueIndex + iterator.getCurrentTokenColumn()}; } } else if (chr == bracket) { depth += 1; } valueIndex -= 1; } do { token = iterator.stepBackward(); } while (token && !typeRe.test(token.type)); if (token == null) break; value = token.value; valueIndex = value.length - 1; } return null; }; this.$findClosingBracket = function(bracket, position, typeRe) { var closingBracket = this.$brackets[bracket]; var depth = 1; var iterator = new TokenIterator(this, position.row, position.column); var token = iterator.getCurrentToken(); if (!token) token = iterator.stepForward(); if (!token) return; if (!typeRe){ typeRe = new RegExp( "(\\.?" + token.type.replace(".", "\\.").replace("lparen", ".paren") .replace(/\b(?:end|start|begin)\b/, "") + ")+" ); } var valueIndex = position.column - iterator.getCurrentTokenColumn(); while (true) { var value = token.value; var valueLength = value.length; while (valueIndex < valueLength) { var chr = value.charAt(valueIndex); if (chr == closingBracket) { depth -= 1; if (depth == 0) { return {row: iterator.getCurrentTokenRow(), column: valueIndex + iterator.getCurrentTokenColumn()}; } } else if (chr == bracket) { depth += 1; } valueIndex += 1; } do { token = iterator.stepForward(); } while (token && !typeRe.test(token.type)); if (token == null) break; valueIndex = 0; } return null; }; } exports.BracketMatch = BracketMatch; }); ace.define("ace/edit_session",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/config","ace/lib/event_emitter","ace/selection","ace/mode/text","ace/range","ace/document","ace/background_tokenizer","ace/search_highlight","ace/edit_session/folding","ace/edit_session/bracket_match"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var lang = require("./lib/lang"); var config = require("./config"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Selection = require("./selection").Selection; var TextMode = require("./mode/text").Mode; var Range = require("./range").Range; var Document = require("./document").Document; var BackgroundTokenizer = require("./background_tokenizer").BackgroundTokenizer; var SearchHighlight = require("./search_highlight").SearchHighlight; var EditSession = function(text, mode) { this.$breakpoints = []; this.$decorations = []; this.$frontMarkers = {}; this.$backMarkers = {}; this.$markerId = 1; this.$undoSelect = true; this.$foldData = []; this.$foldData.toString = function() { return this.join("\n"); } this.on("changeFold", this.onChangeFold.bind(this)); this.$onChange = this.onChange.bind(this); if (typeof text != "object" || !text.getLine) text = new Document(text); this.setDocument(text); this.selection = new Selection(this); config.resetOptions(this); this.setMode(mode); config._signal("session", this); }; (function() { oop.implement(this, EventEmitter); this.setDocument = function(doc) { if (this.doc) this.doc.removeListener("change", this.$onChange); this.doc = doc; doc.on("change", this.$onChange); if (this.bgTokenizer) this.bgTokenizer.setDocument(this.getDocument()); this.resetCaches(); }; this.getDocument = function() { return this.doc; }; this.$resetRowCache = function(docRow) { if (!docRow) { this.$docRowCache = []; this.$screenRowCache = []; return; } var l = this.$docRowCache.length; var i = this.$getRowCacheIndex(this.$docRowCache, docRow) + 1; if (l > i) { this.$docRowCache.splice(i, l); this.$screenRowCache.splice(i, l); } }; this.$getRowCacheIndex = function(cacheArray, val) { var low = 0; var hi = cacheArray.length - 1; while (low <= hi) { var mid = (low + hi) >> 1; var c = cacheArray[mid]; if (val > c) low = mid + 1; else if (val < c) hi = mid - 1; else return mid; } return low -1; }; this.resetCaches = function() { this.$modified = true; this.$wrapData = []; this.$rowLengthCache = []; this.$resetRowCache(0); if (this.bgTokenizer) this.bgTokenizer.start(0); }; this.onChangeFold = function(e) { var fold = e.data; this.$resetRowCache(fold.start.row); }; this.onChange = function(e) { var delta = e.data; this.$modified = true; this.$resetRowCache(delta.range.start.row); var removedFolds = this.$updateInternalDataOnChange(e); if (!this.$fromUndo && this.$undoManager && !delta.ignore) { this.$deltasDoc.push(delta); if (removedFolds && removedFolds.length != 0) { this.$deltasFold.push({ action: "removeFolds", folds: removedFolds }); } this.$informUndoManager.schedule(); } this.bgTokenizer && this.bgTokenizer.$updateOnChange(delta); this._signal("change", e); }; this.setValue = function(text) { this.doc.setValue(text); this.selection.moveTo(0, 0); this.$resetRowCache(0); this.$deltas = []; this.$deltasDoc = []; this.$deltasFold = []; this.setUndoManager(this.$undoManager); this.getUndoManager().reset(); }; this.getValue = this.toString = function() { return this.doc.getValue(); }; this.getSelection = function() { return this.selection; }; this.getState = function(row) { return this.bgTokenizer.getState(row); }; this.getTokens = function(row) { return this.bgTokenizer.getTokens(row); }; this.getTokenAt = function(row, column) { var tokens = this.bgTokenizer.getTokens(row); var token, c = 0; if (column == null) { i = tokens.length - 1; c = this.getLine(row).length; } else { for (var i = 0; i < tokens.length; i++) { c += tokens[i].value.length; if (c >= column) break; } } token = tokens[i]; if (!token) return null; token.index = i; token.start = c - token.value.length; return token; }; this.setUndoManager = function(undoManager) { this.$undoManager = undoManager; this.$deltas = []; this.$deltasDoc = []; this.$deltasFold = []; if (this.$informUndoManager) this.$informUndoManager.cancel(); if (undoManager) { var self = this; this.$syncInformUndoManager = function() { self.$informUndoManager.cancel(); if (self.$deltasFold.length) { self.$deltas.push({ group: "fold", deltas: self.$deltasFold }); self.$deltasFold = []; } if (self.$deltasDoc.length) { self.$deltas.push({ group: "doc", deltas: self.$deltasDoc }); self.$deltasDoc = []; } if (self.$deltas.length > 0) { undoManager.execute({ action: "aceupdate", args: [self.$deltas, self], merge: self.mergeUndoDeltas }); } self.mergeUndoDeltas = false; self.$deltas = []; }; this.$informUndoManager = lang.delayedCall(this.$syncInformUndoManager); } }; this.markUndoGroup = function() { if (this.$syncInformUndoManager) this.$syncInformUndoManager(); }; this.$defaultUndoManager = { undo: function() {}, redo: function() {}, reset: function() {} }; this.getUndoManager = function() { return this.$undoManager || this.$defaultUndoManager; }; this.getTabString = function() { if (this.getUseSoftTabs()) { return lang.stringRepeat(" ", this.getTabSize()); } else { return "\t"; } }; this.setUseSoftTabs = function(val) { this.setOption("useSoftTabs", val); }; this.getUseSoftTabs = function() { return this.$useSoftTabs && !this.$mode.$indentWithTabs; }; this.setTabSize = function(tabSize) { this.setOption("tabSize", tabSize); }; this.getTabSize = function() { return this.$tabSize; }; this.isTabStop = function(position) { return this.$useSoftTabs && (position.column % this.$tabSize === 0); }; this.$overwrite = false; this.setOverwrite = function(overwrite) { this.setOption("overwrite", overwrite); }; this.getOverwrite = function() { return this.$overwrite; }; this.toggleOverwrite = function() { this.setOverwrite(!this.$overwrite); }; this.addGutterDecoration = function(row, className) { if (!this.$decorations[row]) this.$decorations[row] = ""; this.$decorations[row] += " " + className; this._signal("changeBreakpoint", {}); }; this.removeGutterDecoration = function(row, className) { this.$decorations[row] = (this.$decorations[row] || "").replace(" " + className, ""); this._signal("changeBreakpoint", {}); }; this.getBreakpoints = function() { return this.$breakpoints; }; this.setBreakpoints = function(rows) { this.$breakpoints = []; for (var i=0; i 0) inToken = !!line.charAt(column - 1).match(this.tokenRe); if (!inToken) inToken = !!line.charAt(column).match(this.tokenRe); if (inToken) var re = this.tokenRe; else if (/^\s+$/.test(line.slice(column-1, column+1))) var re = /\s/; else var re = this.nonTokenRe; var start = column; if (start > 0) { do { start--; } while (start >= 0 && line.charAt(start).match(re)); start++; } var end = column; while (end < line.length && line.charAt(end).match(re)) { end++; } return new Range(row, start, row, end); }; this.getAWordRange = function(row, column) { var wordRange = this.getWordRange(row, column); var line = this.getLine(wordRange.end.row); while (line.charAt(wordRange.end.column).match(/[ \t]/)) { wordRange.end.column += 1; } return wordRange; }; this.setNewLineMode = function(newLineMode) { this.doc.setNewLineMode(newLineMode); }; this.getNewLineMode = function() { return this.doc.getNewLineMode(); }; this.setUseWorker = function(useWorker) { this.setOption("useWorker", useWorker); }; this.getUseWorker = function() { return this.$useWorker; }; this.onReloadTokenizer = function(e) { var rows = e.data; this.bgTokenizer.start(rows.first); this._signal("tokenizerUpdate", e); }; this.$modes = {}; this.$mode = null; this.$modeId = null; this.setMode = function(mode, cb) { if (mode && typeof mode === "object") { if (mode.getTokenizer) return this.$onChangeMode(mode); var options = mode; var path = options.path; } else { path = mode || "ace/mode/text"; } if (!this.$modes["ace/mode/text"]) this.$modes["ace/mode/text"] = new TextMode(); if (this.$modes[path] && !options) { this.$onChangeMode(this.$modes[path]); cb && cb(); return; } this.$modeId = path; config.loadModule(["mode", path], function(m) { if (this.$modeId !== path) return cb && cb(); if (this.$modes[path] && !options) return this.$onChangeMode(this.$modes[path]); if (m && m.Mode) { m = new m.Mode(options); if (!options) { this.$modes[path] = m; m.$id = path; } this.$onChangeMode(m); cb && cb(); } }.bind(this)); if (!this.$mode) this.$onChangeMode(this.$modes["ace/mode/text"], true); }; this.$onChangeMode = function(mode, $isPlaceholder) { if (!$isPlaceholder) this.$modeId = mode.$id; if (this.$mode === mode) return; this.$mode = mode; this.$stopWorker(); if (this.$useWorker) this.$startWorker(); var tokenizer = mode.getTokenizer(); if(tokenizer.addEventListener !== undefined) { var onReloadTokenizer = this.onReloadTokenizer.bind(this); tokenizer.addEventListener("update", onReloadTokenizer); } if (!this.bgTokenizer) { this.bgTokenizer = new BackgroundTokenizer(tokenizer); var _self = this; this.bgTokenizer.addEventListener("update", function(e) { _self._signal("tokenizerUpdate", e); }); } else { this.bgTokenizer.setTokenizer(tokenizer); } this.bgTokenizer.setDocument(this.getDocument()); this.tokenRe = mode.tokenRe; this.nonTokenRe = mode.nonTokenRe; if (!$isPlaceholder) { if (mode.attachToSession) mode.attachToSession(this); this.$options.wrapMethod.set.call(this, this.$wrapMethod); this.$setFolding(mode.foldingRules); this.bgTokenizer.start(0); this._emit("changeMode"); } }; this.$stopWorker = function() { if (this.$worker) { this.$worker.terminate(); this.$worker = null; } }; this.$startWorker = function() { try { this.$worker = this.$mode.createWorker(this); } catch (e) { if (typeof console == "object") { console.log("Could not load worker"); console.log(e); } this.$worker = null; } }; this.getMode = function() { return this.$mode; }; this.$scrollTop = 0; this.setScrollTop = function(scrollTop) { if (this.$scrollTop === scrollTop || isNaN(scrollTop)) return; this.$scrollTop = scrollTop; this._signal("changeScrollTop", scrollTop); }; this.getScrollTop = function() { return this.$scrollTop; }; this.$scrollLeft = 0; this.setScrollLeft = function(scrollLeft) { if (this.$scrollLeft === scrollLeft || isNaN(scrollLeft)) return; this.$scrollLeft = scrollLeft; this._signal("changeScrollLeft", scrollLeft); }; this.getScrollLeft = function() { return this.$scrollLeft; }; this.getScreenWidth = function() { this.$computeWidth(); if (this.lineWidgets) return Math.max(this.getLineWidgetMaxWidth(), this.screenWidth); return this.screenWidth; }; this.getLineWidgetMaxWidth = function() { if (this.lineWidgetsWidth != null) return this.lineWidgetsWidth; var width = 0; this.lineWidgets.forEach(function(w) { if (w && w.screenWidth > width) width = w.screenWidth; }); return this.lineWidgetWidth = width; }; this.$computeWidth = function(force) { if (this.$modified || force) { this.$modified = false; if (this.$useWrapMode) return this.screenWidth = this.$wrapLimit; var lines = this.doc.getAllLines(); var cache = this.$rowLengthCache; var longestScreenLine = 0; var foldIndex = 0; var foldLine = this.$foldData[foldIndex]; var foldStart = foldLine ? foldLine.start.row : Infinity; var len = lines.length; for (var i = 0; i < len; i++) { if (i > foldStart) { i = foldLine.end.row + 1; if (i >= len) break; foldLine = this.$foldData[foldIndex++]; foldStart = foldLine ? foldLine.start.row : Infinity; } if (cache[i] == null) cache[i] = this.$getStringScreenWidth(lines[i])[0]; if (cache[i] > longestScreenLine) longestScreenLine = cache[i]; } this.screenWidth = longestScreenLine; } }; this.getLine = function(row) { return this.doc.getLine(row); }; this.getLines = function(firstRow, lastRow) { return this.doc.getLines(firstRow, lastRow); }; this.getLength = function() { return this.doc.getLength(); }; this.getTextRange = function(range) { return this.doc.getTextRange(range || this.selection.getRange()); }; this.insert = function(position, text) { return this.doc.insert(position, text); }; this.remove = function(range) { return this.doc.remove(range); }; this.undoChanges = function(deltas, dontSelect) { if (!deltas.length) return; this.$fromUndo = true; var lastUndoRange = null; for (var i = deltas.length - 1; i != -1; i--) { var delta = deltas[i]; if (delta.group == "doc") { this.doc.revertDeltas(delta.deltas); lastUndoRange = this.$getUndoSelection(delta.deltas, true, lastUndoRange); } else { delta.deltas.forEach(function(foldDelta) { this.addFolds(foldDelta.folds); }, this); } } this.$fromUndo = false; lastUndoRange && this.$undoSelect && !dontSelect && this.selection.setSelectionRange(lastUndoRange); return lastUndoRange; }; this.redoChanges = function(deltas, dontSelect) { if (!deltas.length) return; this.$fromUndo = true; var lastUndoRange = null; for (var i = 0; i < deltas.length; i++) { var delta = deltas[i]; if (delta.group == "doc") { this.doc.applyDeltas(delta.deltas); lastUndoRange = this.$getUndoSelection(delta.deltas, false, lastUndoRange); } } this.$fromUndo = false; lastUndoRange && this.$undoSelect && !dontSelect && this.selection.setSelectionRange(lastUndoRange); return lastUndoRange; }; this.setUndoSelect = function(enable) { this.$undoSelect = enable; }; this.$getUndoSelection = function(deltas, isUndo, lastUndoRange) { function isInsert(delta) { var insert = delta.action === "insertText" || delta.action === "insertLines"; return isUndo ? !insert : insert; } var delta = deltas[0]; var range, point; var lastDeltaIsInsert = false; if (isInsert(delta)) { range = Range.fromPoints(delta.range.start, delta.range.end); lastDeltaIsInsert = true; } else { range = Range.fromPoints(delta.range.start, delta.range.start); lastDeltaIsInsert = false; } for (var i = 1; i < deltas.length; i++) { delta = deltas[i]; if (isInsert(delta)) { point = delta.range.start; if (range.compare(point.row, point.column) == -1) { range.setStart(delta.range.start); } point = delta.range.end; if (range.compare(point.row, point.column) == 1) { range.setEnd(delta.range.end); } lastDeltaIsInsert = true; } else { point = delta.range.start; if (range.compare(point.row, point.column) == -1) { range = Range.fromPoints(delta.range.start, delta.range.start); } lastDeltaIsInsert = false; } } if (lastUndoRange != null) { if (Range.comparePoints(lastUndoRange.start, range.start) === 0) { lastUndoRange.start.column += range.end.column - range.start.column; lastUndoRange.end.column += range.end.column - range.start.column; } var cmp = lastUndoRange.compareRange(range); if (cmp == 1) { range.setStart(lastUndoRange.start); } else if (cmp == -1) { range.setEnd(lastUndoRange.end); } } return range; }; this.replace = function(range, text) { return this.doc.replace(range, text); }; this.moveText = function(fromRange, toPosition, copy) { var text = this.getTextRange(fromRange); var folds = this.getFoldsInRange(fromRange); var toRange = Range.fromPoints(toPosition, toPosition); if (!copy) { this.remove(fromRange); var rowDiff = fromRange.start.row - fromRange.end.row; var collDiff = rowDiff ? -fromRange.end.column : fromRange.start.column - fromRange.end.column; if (collDiff) { if (toRange.start.row == fromRange.end.row && toRange.start.column > fromRange.end.column) toRange.start.column += collDiff; if (toRange.end.row == fromRange.end.row && toRange.end.column > fromRange.end.column) toRange.end.column += collDiff; } if (rowDiff && toRange.start.row >= fromRange.end.row) { toRange.start.row += rowDiff; toRange.end.row += rowDiff; } } toRange.end = this.insert(toRange.start, text); if (folds.length) { var oldStart = fromRange.start; var newStart = toRange.start; var rowDiff = newStart.row - oldStart.row; var collDiff = newStart.column - oldStart.column; this.addFolds(folds.map(function(x) { x = x.clone(); if (x.start.row == oldStart.row) x.start.column += collDiff; if (x.end.row == oldStart.row) x.end.column += collDiff; x.start.row += rowDiff; x.end.row += rowDiff; return x; })); } return toRange; }; this.indentRows = function(startRow, endRow, indentString) { indentString = indentString.replace(/\t/g, this.getTabString()); for (var row=startRow; row<=endRow; row++) this.insert({row: row, column:0}, indentString); }; this.outdentRows = function (range) { var rowRange = range.collapseRows(); var deleteRange = new Range(0, 0, 0, 0); var size = this.getTabSize(); for (var i = rowRange.start.row; i <= rowRange.end.row; ++i) { var line = this.getLine(i); deleteRange.start.row = i; deleteRange.end.row = i; for (var j = 0; j < size; ++j) if (line.charAt(j) != ' ') break; if (j < size && line.charAt(j) == '\t') { deleteRange.start.column = j; deleteRange.end.column = j + 1; } else { deleteRange.start.column = 0; deleteRange.end.column = j; } this.remove(deleteRange); } }; this.$moveLines = function(firstRow, lastRow, dir) { firstRow = this.getRowFoldStart(firstRow); lastRow = this.getRowFoldEnd(lastRow); if (dir < 0) { var row = this.getRowFoldStart(firstRow + dir); if (row < 0) return 0; var diff = row-firstRow; } else if (dir > 0) { var row = this.getRowFoldEnd(lastRow + dir); if (row > this.doc.getLength()-1) return 0; var diff = row-lastRow; } else { firstRow = this.$clipRowToDocument(firstRow); lastRow = this.$clipRowToDocument(lastRow); var diff = lastRow - firstRow + 1; } var range = new Range(firstRow, 0, lastRow, Number.MAX_VALUE); var folds = this.getFoldsInRange(range).map(function(x){ x = x.clone(); x.start.row += diff; x.end.row += diff; return x; }); var lines = dir == 0 ? this.doc.getLines(firstRow, lastRow) : this.doc.removeLines(firstRow, lastRow); this.doc.insertLines(firstRow+diff, lines); folds.length && this.addFolds(folds); return diff; }; this.moveLinesUp = function(firstRow, lastRow) { return this.$moveLines(firstRow, lastRow, -1); }; this.moveLinesDown = function(firstRow, lastRow) { return this.$moveLines(firstRow, lastRow, 1); }; this.duplicateLines = function(firstRow, lastRow) { return this.$moveLines(firstRow, lastRow, 0); }; this.$clipRowToDocument = function(row) { return Math.max(0, Math.min(row, this.doc.getLength()-1)); }; this.$clipColumnToRow = function(row, column) { if (column < 0) return 0; return Math.min(this.doc.getLine(row).length, column); }; this.$clipPositionToDocument = function(row, column) { column = Math.max(0, column); if (row < 0) { row = 0; column = 0; } else { var len = this.doc.getLength(); if (row >= len) { row = len - 1; column = this.doc.getLine(len-1).length; } else { column = Math.min(this.doc.getLine(row).length, column); } } return { row: row, column: column }; }; this.$clipRangeToDocument = function(range) { if (range.start.row < 0) { range.start.row = 0; range.start.column = 0; } else { range.start.column = this.$clipColumnToRow( range.start.row, range.start.column ); } var len = this.doc.getLength() - 1; if (range.end.row > len) { range.end.row = len; range.end.column = this.doc.getLine(len).length; } else { range.end.column = this.$clipColumnToRow( range.end.row, range.end.column ); } return range; }; this.$wrapLimit = 80; this.$useWrapMode = false; this.$wrapLimitRange = { min : null, max : null }; this.setUseWrapMode = function(useWrapMode) { if (useWrapMode != this.$useWrapMode) { this.$useWrapMode = useWrapMode; this.$modified = true; this.$resetRowCache(0); if (useWrapMode) { var len = this.getLength(); this.$wrapData = Array(len); this.$updateWrapData(0, len - 1); } this._signal("changeWrapMode"); } }; this.getUseWrapMode = function() { return this.$useWrapMode; }; this.setWrapLimitRange = function(min, max) { if (this.$wrapLimitRange.min !== min || this.$wrapLimitRange.max !== max) { this.$wrapLimitRange = { min: min, max: max }; this.$modified = true; this._signal("changeWrapMode"); } }; this.adjustWrapLimit = function(desiredLimit, $printMargin) { var limits = this.$wrapLimitRange; if (limits.max < 0) limits = {min: $printMargin, max: $printMargin}; var wrapLimit = this.$constrainWrapLimit(desiredLimit, limits.min, limits.max); if (wrapLimit != this.$wrapLimit && wrapLimit > 1) { this.$wrapLimit = wrapLimit; this.$modified = true; if (this.$useWrapMode) { this.$updateWrapData(0, this.getLength() - 1); this.$resetRowCache(0); this._signal("changeWrapLimit"); } return true; } return false; }; this.$constrainWrapLimit = function(wrapLimit, min, max) { if (min) wrapLimit = Math.max(min, wrapLimit); if (max) wrapLimit = Math.min(max, wrapLimit); return wrapLimit; }; this.getWrapLimit = function() { return this.$wrapLimit; }; this.setWrapLimit = function (limit) { this.setWrapLimitRange(limit, limit); }; this.getWrapLimitRange = function() { return { min : this.$wrapLimitRange.min, max : this.$wrapLimitRange.max }; }; this.$updateInternalDataOnChange = function(e) { var useWrapMode = this.$useWrapMode; var len; var action = e.data.action; var firstRow = e.data.range.start.row; var lastRow = e.data.range.end.row; var start = e.data.range.start; var end = e.data.range.end; var removedFolds = null; if (action.indexOf("Lines") != -1) { if (action == "insertLines") { lastRow = firstRow + (e.data.lines.length); } else { lastRow = firstRow; } len = e.data.lines ? e.data.lines.length : lastRow - firstRow; } else { len = lastRow - firstRow; } this.$updating = true; if (len != 0) { if (action.indexOf("remove") != -1) { this[useWrapMode ? "$wrapData" : "$rowLengthCache"].splice(firstRow, len); var foldLines = this.$foldData; removedFolds = this.getFoldsInRange(e.data.range); this.removeFolds(removedFolds); var foldLine = this.getFoldLine(end.row); var idx = 0; if (foldLine) { foldLine.addRemoveChars(end.row, end.column, start.column - end.column); foldLine.shiftRow(-len); var foldLineBefore = this.getFoldLine(firstRow); if (foldLineBefore && foldLineBefore !== foldLine) { foldLineBefore.merge(foldLine); foldLine = foldLineBefore; } idx = foldLines.indexOf(foldLine) + 1; } for (idx; idx < foldLines.length; idx++) { var foldLine = foldLines[idx]; if (foldLine.start.row >= end.row) { foldLine.shiftRow(-len); } } lastRow = firstRow; } else { var args = Array(len); args.unshift(firstRow, 0); var arr = useWrapMode ? this.$wrapData : this.$rowLengthCache arr.splice.apply(arr, args); var foldLines = this.$foldData; var foldLine = this.getFoldLine(firstRow); var idx = 0; if (foldLine) { var cmp = foldLine.range.compareInside(start.row, start.column); if (cmp == 0) { foldLine = foldLine.split(start.row, start.column); if (foldLine) { foldLine.shiftRow(len); foldLine.addRemoveChars(lastRow, 0, end.column - start.column); } } else if (cmp == -1) { foldLine.addRemoveChars(firstRow, 0, end.column - start.column); foldLine.shiftRow(len); } idx = foldLines.indexOf(foldLine) + 1; } for (idx; idx < foldLines.length; idx++) { var foldLine = foldLines[idx]; if (foldLine.start.row >= firstRow) { foldLine.shiftRow(len); } } } } else { len = Math.abs(e.data.range.start.column - e.data.range.end.column); if (action.indexOf("remove") != -1) { removedFolds = this.getFoldsInRange(e.data.range); this.removeFolds(removedFolds); len = -len; } var foldLine = this.getFoldLine(firstRow); if (foldLine) { foldLine.addRemoveChars(firstRow, start.column, len); } } if (useWrapMode && this.$wrapData.length != this.doc.getLength()) { console.error("doc.getLength() and $wrapData.length have to be the same!"); } this.$updating = false; if (useWrapMode) this.$updateWrapData(firstRow, lastRow); else this.$updateRowLengthCache(firstRow, lastRow); return removedFolds; }; this.$updateRowLengthCache = function(firstRow, lastRow, b) { this.$rowLengthCache[firstRow] = null; this.$rowLengthCache[lastRow] = null; }; this.$updateWrapData = function(firstRow, lastRow) { var lines = this.doc.getAllLines(); var tabSize = this.getTabSize(); var wrapData = this.$wrapData; var wrapLimit = this.$wrapLimit; var tokens; var foldLine; var row = firstRow; lastRow = Math.min(lastRow, lines.length - 1); while (row <= lastRow) { foldLine = this.getFoldLine(row, foldLine); if (!foldLine) { tokens = this.$getDisplayTokens(lines[row]); wrapData[row] = this.$computeWrapSplits(tokens, wrapLimit, tabSize); row ++; } else { tokens = []; foldLine.walk(function(placeholder, row, column, lastColumn) { var walkTokens; if (placeholder != null) { walkTokens = this.$getDisplayTokens( placeholder, tokens.length); walkTokens[0] = PLACEHOLDER_START; for (var i = 1; i < walkTokens.length; i++) { walkTokens[i] = PLACEHOLDER_BODY; } } else { walkTokens = this.$getDisplayTokens( lines[row].substring(lastColumn, column), tokens.length); } tokens = tokens.concat(walkTokens); }.bind(this), foldLine.end.row, lines[foldLine.end.row].length + 1 ); wrapData[foldLine.start.row] = this.$computeWrapSplits(tokens, wrapLimit, tabSize); row = foldLine.end.row + 1; } } }; var CHAR = 1, CHAR_EXT = 2, PLACEHOLDER_START = 3, PLACEHOLDER_BODY = 4, PUNCTUATION = 9, SPACE = 10, TAB = 11, TAB_SPACE = 12; this.$computeWrapSplits = function(tokens, wrapLimit) { if (tokens.length == 0) { return []; } var splits = []; var displayLength = tokens.length; var lastSplit = 0, lastDocSplit = 0; var isCode = this.$wrapAsCode; function addSplit(screenPos) { var displayed = tokens.slice(lastSplit, screenPos); var len = displayed.length; displayed.join(""). replace(/12/g, function() { len -= 1; }). replace(/2/g, function() { len -= 1; }); lastDocSplit += len; splits.push(lastDocSplit); lastSplit = screenPos; } while (displayLength - lastSplit > wrapLimit) { var split = lastSplit + wrapLimit; if (tokens[split - 1] >= SPACE && tokens[split] >= SPACE) { addSplit(split); continue; } if (tokens[split] == PLACEHOLDER_START || tokens[split] == PLACEHOLDER_BODY) { for (split; split != lastSplit - 1; split--) { if (tokens[split] == PLACEHOLDER_START) { break; } } if (split > lastSplit) { addSplit(split); continue; } split = lastSplit + wrapLimit; for (split; split < tokens.length; split++) { if (tokens[split] != PLACEHOLDER_BODY) { break; } } if (split == tokens.length) { break; // Breaks the while-loop. } addSplit(split); continue; } var minSplit = Math.max(split - (isCode ? 10 : wrapLimit-(wrapLimit>>2)), lastSplit - 1); while (split > minSplit && tokens[split] < PLACEHOLDER_START) { split --; } if (isCode) { while (split > minSplit && tokens[split] < PLACEHOLDER_START) { split --; } while (split > minSplit && tokens[split] == PUNCTUATION) { split --; } } else { while (split > minSplit && tokens[split] < SPACE) { split --; } } if (split > minSplit) { addSplit(++split); continue; } split = lastSplit + wrapLimit; if (tokens[split] == CHAR_EXT) split--; addSplit(split); } return splits; }; this.$getDisplayTokens = function(str, offset) { var arr = []; var tabSize; offset = offset || 0; for (var i = 0; i < str.length; i++) { var c = str.charCodeAt(i); if (c == 9) { tabSize = this.getScreenTabSize(arr.length + offset); arr.push(TAB); for (var n = 1; n < tabSize; n++) { arr.push(TAB_SPACE); } } else if (c == 32) { arr.push(SPACE); } else if((c > 39 && c < 48) || (c > 57 && c < 64)) { arr.push(PUNCTUATION); } else if (c >= 0x1100 && isFullWidth(c)) { arr.push(CHAR, CHAR_EXT); } else { arr.push(CHAR); } } return arr; }; this.$getStringScreenWidth = function(str, maxScreenColumn, screenColumn) { if (maxScreenColumn == 0) return [0, 0]; if (maxScreenColumn == null) maxScreenColumn = Infinity; screenColumn = screenColumn || 0; var c, column; for (column = 0; column < str.length; column++) { c = str.charCodeAt(column); if (c == 9) { screenColumn += this.getScreenTabSize(screenColumn); } else if (c >= 0x1100 && isFullWidth(c)) { screenColumn += 2; } else { screenColumn += 1; } if (screenColumn > maxScreenColumn) { break; } } return [screenColumn, column]; }; this.lineWidgets = null; this.getRowLength = function(row) { if (this.lineWidgets) var h = this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0; else h = 0 if (!this.$useWrapMode || !this.$wrapData[row]) { return 1 + h; } else { return this.$wrapData[row].length + 1 + h; } }; this.getRowLineCount = function(row) { if (!this.$useWrapMode || !this.$wrapData[row]) { return 1; } else { return this.$wrapData[row].length + 1; } }; this.getScreenLastRowColumn = function(screenRow) { var pos = this.screenToDocumentPosition(screenRow, Number.MAX_VALUE); return this.documentToScreenColumn(pos.row, pos.column); }; this.getDocumentLastRowColumn = function(docRow, docColumn) { var screenRow = this.documentToScreenRow(docRow, docColumn); return this.getScreenLastRowColumn(screenRow); }; this.getDocumentLastRowColumnPosition = function(docRow, docColumn) { var screenRow = this.documentToScreenRow(docRow, docColumn); return this.screenToDocumentPosition(screenRow, Number.MAX_VALUE / 10); }; this.getRowSplitData = function(row) { if (!this.$useWrapMode) { return undefined; } else { return this.$wrapData[row]; } }; this.getScreenTabSize = function(screenColumn) { return this.$tabSize - screenColumn % this.$tabSize; }; this.screenToDocumentRow = function(screenRow, screenColumn) { return this.screenToDocumentPosition(screenRow, screenColumn).row; }; this.screenToDocumentColumn = function(screenRow, screenColumn) { return this.screenToDocumentPosition(screenRow, screenColumn).column; }; this.screenToDocumentPosition = function(screenRow, screenColumn) { if (screenRow < 0) return {row: 0, column: 0}; var line; var docRow = 0; var docColumn = 0; var column; var row = 0; var rowLength = 0; var rowCache = this.$screenRowCache; var i = this.$getRowCacheIndex(rowCache, screenRow); var l = rowCache.length; if (l && i >= 0) { var row = rowCache[i]; var docRow = this.$docRowCache[i]; var doCache = screenRow > rowCache[l - 1]; } else { var doCache = !l; } var maxRow = this.getLength() - 1; var foldLine = this.getNextFoldLine(docRow); var foldStart = foldLine ? foldLine.start.row : Infinity; while (row <= screenRow) { rowLength = this.getRowLength(docRow); if (row + rowLength > screenRow || docRow >= maxRow) { break; } else { row += rowLength; docRow++; if (docRow > foldStart) { docRow = foldLine.end.row+1; foldLine = this.getNextFoldLine(docRow, foldLine); foldStart = foldLine ? foldLine.start.row : Infinity; } } if (doCache) { this.$docRowCache.push(docRow); this.$screenRowCache.push(row); } } if (foldLine && foldLine.start.row <= docRow) { line = this.getFoldDisplayLine(foldLine); docRow = foldLine.start.row; } else if (row + rowLength <= screenRow || docRow > maxRow) { return { row: maxRow, column: this.getLine(maxRow).length }; } else { line = this.getLine(docRow); foldLine = null; } if (this.$useWrapMode) { var splits = this.$wrapData[docRow]; if (splits) { var splitIndex = Math.floor(screenRow - row); column = splits[splitIndex]; if(splitIndex > 0 && splits.length) { docColumn = splits[splitIndex - 1] || splits[splits.length - 1]; line = line.substring(docColumn); } } } docColumn += this.$getStringScreenWidth(line, screenColumn)[1]; if (this.$useWrapMode && docColumn >= column) docColumn = column - 1; if (foldLine) return foldLine.idxToPosition(docColumn); return {row: docRow, column: docColumn}; }; this.documentToScreenPosition = function(docRow, docColumn) { if (typeof docColumn === "undefined") var pos = this.$clipPositionToDocument(docRow.row, docRow.column); else pos = this.$clipPositionToDocument(docRow, docColumn); docRow = pos.row; docColumn = pos.column; var screenRow = 0; var foldStartRow = null; var fold = null; fold = this.getFoldAt(docRow, docColumn, 1); if (fold) { docRow = fold.start.row; docColumn = fold.start.column; } var rowEnd, row = 0; var rowCache = this.$docRowCache; var i = this.$getRowCacheIndex(rowCache, docRow); var l = rowCache.length; if (l && i >= 0) { var row = rowCache[i]; var screenRow = this.$screenRowCache[i]; var doCache = docRow > rowCache[l - 1]; } else { var doCache = !l; } var foldLine = this.getNextFoldLine(row); var foldStart = foldLine ?foldLine.start.row :Infinity; while (row < docRow) { if (row >= foldStart) { rowEnd = foldLine.end.row + 1; if (rowEnd > docRow) break; foldLine = this.getNextFoldLine(rowEnd, foldLine); foldStart = foldLine ?foldLine.start.row :Infinity; } else { rowEnd = row + 1; } screenRow += this.getRowLength(row); row = rowEnd; if (doCache) { this.$docRowCache.push(row); this.$screenRowCache.push(screenRow); } } var textLine = ""; if (foldLine && row >= foldStart) { textLine = this.getFoldDisplayLine(foldLine, docRow, docColumn); foldStartRow = foldLine.start.row; } else { textLine = this.getLine(docRow).substring(0, docColumn); foldStartRow = docRow; } if (this.$useWrapMode) { var wrapRow = this.$wrapData[foldStartRow]; if (wrapRow) { var screenRowOffset = 0; while (textLine.length >= wrapRow[screenRowOffset]) { screenRow ++; screenRowOffset++; } textLine = textLine.substring( wrapRow[screenRowOffset - 1] || 0, textLine.length ); } } return { row: screenRow, column: this.$getStringScreenWidth(textLine)[0] }; }; this.documentToScreenColumn = function(row, docColumn) { return this.documentToScreenPosition(row, docColumn).column; }; this.documentToScreenRow = function(docRow, docColumn) { return this.documentToScreenPosition(docRow, docColumn).row; }; this.getScreenLength = function() { var screenRows = 0; var fold = null; if (!this.$useWrapMode) { screenRows = this.getLength(); var foldData = this.$foldData; for (var i = 0; i < foldData.length; i++) { fold = foldData[i]; screenRows -= fold.end.row - fold.start.row; } } else { var lastRow = this.$wrapData.length; var row = 0, i = 0; var fold = this.$foldData[i++]; var foldStart = fold ? fold.start.row :Infinity; while (row < lastRow) { var splits = this.$wrapData[row]; screenRows += splits ? splits.length + 1 : 1; row ++; if (row > foldStart) { row = fold.end.row+1; fold = this.$foldData[i++]; foldStart = fold ?fold.start.row :Infinity; } } } if (this.lineWidgets) screenRows += this.$getWidgetScreenLength(); return screenRows; }; this.$setFontMetrics = function(fm) { }; this.destroy = function() { if (this.bgTokenizer) { this.bgTokenizer.setDocument(null); this.bgTokenizer = null; } this.$stopWorker(); }; function isFullWidth(c) { if (c < 0x1100) return false; return c >= 0x1100 && c <= 0x115F || c >= 0x11A3 && c <= 0x11A7 || c >= 0x11FA && c <= 0x11FF || c >= 0x2329 && c <= 0x232A || c >= 0x2E80 && c <= 0x2E99 || c >= 0x2E9B && c <= 0x2EF3 || c >= 0x2F00 && c <= 0x2FD5 || c >= 0x2FF0 && c <= 0x2FFB || c >= 0x3000 && c <= 0x303E || c >= 0x3041 && c <= 0x3096 || c >= 0x3099 && c <= 0x30FF || c >= 0x3105 && c <= 0x312D || c >= 0x3131 && c <= 0x318E || c >= 0x3190 && c <= 0x31BA || c >= 0x31C0 && c <= 0x31E3 || c >= 0x31F0 && c <= 0x321E || c >= 0x3220 && c <= 0x3247 || c >= 0x3250 && c <= 0x32FE || c >= 0x3300 && c <= 0x4DBF || c >= 0x4E00 && c <= 0xA48C || c >= 0xA490 && c <= 0xA4C6 || c >= 0xA960 && c <= 0xA97C || c >= 0xAC00 && c <= 0xD7A3 || c >= 0xD7B0 && c <= 0xD7C6 || c >= 0xD7CB && c <= 0xD7FB || c >= 0xF900 && c <= 0xFAFF || c >= 0xFE10 && c <= 0xFE19 || c >= 0xFE30 && c <= 0xFE52 || c >= 0xFE54 && c <= 0xFE66 || c >= 0xFE68 && c <= 0xFE6B || c >= 0xFF01 && c <= 0xFF60 || c >= 0xFFE0 && c <= 0xFFE6; }; }).call(EditSession.prototype); require("./edit_session/folding").Folding.call(EditSession.prototype); require("./edit_session/bracket_match").BracketMatch.call(EditSession.prototype); config.defineOptions(EditSession.prototype, "session", { wrap: { set: function(value) { if (!value || value == "off") value = false; else if (value == "free") value = true; else if (value == "printMargin") value = -1; else if (typeof value == "string") value = parseInt(value, 10) || false; if (this.$wrap == value) return; if (!value) { this.setUseWrapMode(false); } else { var col = typeof value == "number" ? value : null; this.setWrapLimitRange(col, col); this.setUseWrapMode(true); } this.$wrap = value; }, get: function() { if (this.getUseWrapMode()) { if (this.$wrap == -1) return "printMargin"; if (!this.getWrapLimitRange().min) return "free"; return this.$wrap; } return "off"; }, handlesSet: true }, wrapMethod: { set: function(val) { val = val == "auto" ? this.$mode.type != "text" : val != "text"; if (val != this.$wrapAsCode) { this.$wrapAsCode = val; if (this.$useWrapMode) { this.$modified = true; this.$resetRowCache(0); this.$updateWrapData(0, this.getLength() - 1); } } }, initialValue: "auto" }, firstLineNumber: { set: function() {this._signal("changeBreakpoint");}, initialValue: 1 }, useWorker: { set: function(useWorker) { this.$useWorker = useWorker; this.$stopWorker(); if (useWorker) this.$startWorker(); }, initialValue: true }, useSoftTabs: {initialValue: true}, tabSize: { set: function(tabSize) { if (isNaN(tabSize) || this.$tabSize === tabSize) return; this.$modified = true; this.$rowLengthCache = []; this.$tabSize = tabSize; this._signal("changeTabSize"); }, initialValue: 4, handlesSet: true }, overwrite: { set: function(val) {this._signal("changeOverwrite");}, initialValue: false }, newLineMode: { set: function(val) {this.doc.setNewLineMode(val)}, get: function() {return this.doc.getNewLineMode()}, handlesSet: true }, mode: { set: function(val) { this.setMode(val) }, get: function() { return this.$modeId } } }); exports.EditSession = EditSession; }); ace.define("ace/search",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"], function(require, exports, module) { "use strict"; var lang = require("./lib/lang"); var oop = require("./lib/oop"); var Range = require("./range").Range; var Search = function() { this.$options = {}; }; (function() { this.set = function(options) { oop.mixin(this.$options, options); return this; }; this.getOptions = function() { return lang.copyObject(this.$options); }; this.setOptions = function(options) { this.$options = options; }; this.find = function(session) { var iterator = this.$matchIterator(session, this.$options); if (!iterator) return false; var firstRange = null; iterator.forEach(function(range, row, offset) { if (!range.start) { var column = range.offset + (offset || 0); firstRange = new Range(row, column, row, column+range.length); } else firstRange = range; return true; }); return firstRange; }; this.findAll = function(session) { var options = this.$options; if (!options.needle) return []; this.$assembleRegExp(options); var range = options.range; var lines = range ? session.getLines(range.start.row, range.end.row) : session.doc.getAllLines(); var ranges = []; var re = options.re; if (options.$isMultiLine) { var len = re.length; var maxRow = lines.length - len; var prevRange; outer: for (var row = re.offset || 0; row <= maxRow; row++) { for (var j = 0; j < len; j++) if (lines[row + j].search(re[j]) == -1) continue outer; var startLine = lines[row]; var line = lines[row + len - 1]; var startIndex = startLine.length - startLine.match(re[0])[0].length; var endIndex = line.match(re[len - 1])[0].length; if (prevRange && prevRange.end.row === row && prevRange.end.column > startIndex ) { continue; } ranges.push(prevRange = new Range( row, startIndex, row + len - 1, endIndex )); if (len > 2) row = row + len - 2; } } else { for (var i = 0; i < lines.length; i++) { var matches = lang.getMatchOffsets(lines[i], re); for (var j = 0; j < matches.length; j++) { var match = matches[j]; ranges.push(new Range(i, match.offset, i, match.offset + match.length)); } } } if (range) { var startColumn = range.start.column; var endColumn = range.start.column; var i = 0, j = ranges.length - 1; while (i < j && ranges[i].start.column < startColumn && ranges[i].start.row == range.start.row) i++; while (i < j && ranges[j].end.column > endColumn && ranges[j].end.row == range.end.row) j--; ranges = ranges.slice(i, j + 1); for (i = 0, j = ranges.length; i < j; i++) { ranges[i].start.row += range.start.row; ranges[i].end.row += range.start.row; } } return ranges; }; this.replace = function(input, replacement) { var options = this.$options; var re = this.$assembleRegExp(options); if (options.$isMultiLine) return replacement; if (!re) return; var match = re.exec(input); if (!match || match[0].length != input.length) return null; replacement = input.replace(re, replacement); if (options.preserveCase) { replacement = replacement.split(""); for (var i = Math.min(input.length, input.length); i--; ) { var ch = input[i]; if (ch && ch.toLowerCase() != ch) replacement[i] = replacement[i].toUpperCase(); else replacement[i] = replacement[i].toLowerCase(); } replacement = replacement.join(""); } return replacement; }; this.$matchIterator = function(session, options) { var re = this.$assembleRegExp(options); if (!re) return false; var self = this, callback, backwards = options.backwards; if (options.$isMultiLine) { var len = re.length; var matchIterator = function(line, row, offset) { var startIndex = line.search(re[0]); if (startIndex == -1) return; for (var i = 1; i < len; i++) { line = session.getLine(row + i); if (line.search(re[i]) == -1) return; } var endIndex = line.match(re[len - 1])[0].length; var range = new Range(row, startIndex, row + len - 1, endIndex); if (re.offset == 1) { range.start.row--; range.start.column = Number.MAX_VALUE; } else if (offset) range.start.column += offset; if (callback(range)) return true; }; } else if (backwards) { var matchIterator = function(line, row, startIndex) { var matches = lang.getMatchOffsets(line, re); for (var i = matches.length-1; i >= 0; i--) if (callback(matches[i], row, startIndex)) return true; }; } else { var matchIterator = function(line, row, startIndex) { var matches = lang.getMatchOffsets(line, re); for (var i = 0; i < matches.length; i++) if (callback(matches[i], row, startIndex)) return true; }; } return { forEach: function(_callback) { callback = _callback; self.$lineIterator(session, options).forEach(matchIterator); } }; }; this.$assembleRegExp = function(options, $disableFakeMultiline) { if (options.needle instanceof RegExp) return options.re = options.needle; var needle = options.needle; if (!options.needle) return options.re = false; if (!options.regExp) needle = lang.escapeRegExp(needle); if (options.wholeWord) needle = "\\b" + needle + "\\b"; var modifier = options.caseSensitive ? "gm" : "gmi"; options.$isMultiLine = !$disableFakeMultiline && /[\n\r]/.test(needle); if (options.$isMultiLine) return options.re = this.$assembleMultilineRegExp(needle, modifier); try { var re = new RegExp(needle, modifier); } catch(e) { re = false; } return options.re = re; }; this.$assembleMultilineRegExp = function(needle, modifier) { var parts = needle.replace(/\r\n|\r|\n/g, "$\n^").split("\n"); var re = []; for (var i = 0; i < parts.length; i++) try { re.push(new RegExp(parts[i], modifier)); } catch(e) { return false; } if (parts[0] == "") { re.shift(); re.offset = 1; } else { re.offset = 0; } return re; }; this.$lineIterator = function(session, options) { var backwards = options.backwards == true; var skipCurrent = options.skipCurrent != false; var range = options.range; var start = options.start; if (!start) start = range ? range[backwards ? "end" : "start"] : session.selection.getRange(); if (start.start) start = start[skipCurrent != backwards ? "end" : "start"]; var firstRow = range ? range.start.row : 0; var lastRow = range ? range.end.row : session.getLength() - 1; var forEach = backwards ? function(callback) { var row = start.row; var line = session.getLine(row).substring(0, start.column); if (callback(line, row)) return; for (row--; row >= firstRow; row--) if (callback(session.getLine(row), row)) return; if (options.wrap == false) return; for (row = lastRow, firstRow = start.row; row >= firstRow; row--) if (callback(session.getLine(row), row)) return; } : function(callback) { var row = start.row; var line = session.getLine(row).substr(start.column); if (callback(line, row, start.column)) return; for (row = row+1; row <= lastRow; row++) if (callback(session.getLine(row), row)) return; if (options.wrap == false) return; for (row = firstRow, lastRow = start.row; row <= lastRow; row++) if (callback(session.getLine(row), row)) return; }; return {forEach: forEach}; }; }).call(Search.prototype); exports.Search = Search; }); ace.define("ace/keyboard/hash_handler",["require","exports","module","ace/lib/keys","ace/lib/useragent"], function(require, exports, module) { "use strict"; var keyUtil = require("../lib/keys"); var useragent = require("../lib/useragent"); var KEY_MODS = keyUtil.KEY_MODS; function HashHandler(config, platform) { this.platform = platform || (useragent.isMac ? "mac" : "win"); this.commands = {}; this.commandKeyBinding = {}; this.addCommands(config); this.$singleCommand = true; } function MultiHashHandler(config, platform) { HashHandler.call(this, config, platform); this.$singleCommand = false; } MultiHashHandler.prototype = HashHandler.prototype; (function() { this.addCommand = function(command) { if (this.commands[command.name]) this.removeCommand(command); this.commands[command.name] = command; if (command.bindKey) this._buildKeyHash(command); }; this.removeCommand = function(command, keepCommand) { var name = command && (typeof command === 'string' ? command : command.name); command = this.commands[name]; if (!keepCommand) delete this.commands[name]; var ckb = this.commandKeyBinding; for (var keyId in ckb) { var cmdGroup = ckb[keyId]; if (cmdGroup == command) { delete ckb[keyId]; } else if (Array.isArray(cmdGroup)) { var i = cmdGroup.indexOf(command); if (i != -1) { cmdGroup.splice(i, 1); if (cmdGroup.length == 1) ckb[keyId] = cmdGroup[0]; } } } }; this.bindKey = function(key, command, asDefault) { if (typeof key == "object") key = key[this.platform]; if (!key) return; if (typeof command == "function") return this.addCommand({exec: command, bindKey: key, name: command.name || key}); key.split("|").forEach(function(keyPart) { var chain = ""; if (keyPart.indexOf(" ") != -1) { var parts = keyPart.split(/\s+/); keyPart = parts.pop(); parts.forEach(function(keyPart) { var binding = this.parseKeys(keyPart); var id = KEY_MODS[binding.hashId] + binding.key; chain += (chain ? " " : "") + id; this._addCommandToBinding(chain, "chainKeys"); }, this); chain += " "; } var binding = this.parseKeys(keyPart); var id = KEY_MODS[binding.hashId] + binding.key; this._addCommandToBinding(chain + id, command, asDefault); }, this); }; this._addCommandToBinding = function(keyId, command, asDefault) { var ckb = this.commandKeyBinding, i; if (!command) { delete ckb[keyId]; } else if (!ckb[keyId] || this.$singleCommand) { ckb[keyId] = command; } else { if (!Array.isArray(ckb[keyId])) { ckb[keyId] = [ckb[keyId]]; } else if ((i = ckb[keyId].indexOf(command)) != -1) { ckb[keyId].splice(i, 1); } if (asDefault || command.isDefault) ckb[keyId].unshift(command); else ckb[keyId].push(command); } }; this.addCommands = function(commands) { commands && Object.keys(commands).forEach(function(name) { var command = commands[name]; if (!command) return; if (typeof command === "string") return this.bindKey(command, name); if (typeof command === "function") command = { exec: command }; if (typeof command !== "object") return; if (!command.name) command.name = name; this.addCommand(command); }, this); }; this.removeCommands = function(commands) { Object.keys(commands).forEach(function(name) { this.removeCommand(commands[name]); }, this); }; this.bindKeys = function(keyList) { Object.keys(keyList).forEach(function(key) { this.bindKey(key, keyList[key]); }, this); }; this._buildKeyHash = function(command) { this.bindKey(command.bindKey, command); }; this.parseKeys = function(keys) { var parts = keys.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(x){return x}); var key = parts.pop(); var keyCode = keyUtil[key]; if (keyUtil.FUNCTION_KEYS[keyCode]) key = keyUtil.FUNCTION_KEYS[keyCode].toLowerCase(); else if (!parts.length) return {key: key, hashId: -1}; else if (parts.length == 1 && parts[0] == "shift") return {key: key.toUpperCase(), hashId: -1}; var hashId = 0; for (var i = parts.length; i--;) { var modifier = keyUtil.KEY_MODS[parts[i]]; if (modifier == null) { if (typeof console != "undefined") console.error("invalid modifier " + parts[i] + " in " + keys); return false; } hashId |= modifier; } return {key: key, hashId: hashId}; }; this.findKeyCommand = function findKeyCommand(hashId, keyString) { var key = KEY_MODS[hashId] + keyString; return this.commandKeyBinding[key]; }; this.handleKeyboard = function(data, hashId, keyString, keyCode) { var key = KEY_MODS[hashId] + keyString; var command = this.commandKeyBinding[key]; if (data.$keyChain) { data.$keyChain += " " + key; command = this.commandKeyBinding[data.$keyChain] || command; } if (command) { if (command == "chainKeys" || command[command.length - 1] == "chainKeys") { data.$keyChain = data.$keyChain || key; return {command: "null"}; } } if (data.$keyChain && keyCode > 0) data.$keyChain = ""; return {command: command}; }; }).call(HashHandler.prototype); exports.HashHandler = HashHandler; exports.MultiHashHandler = MultiHashHandler; }); ace.define("ace/commands/command_manager",["require","exports","module","ace/lib/oop","ace/keyboard/hash_handler","ace/lib/event_emitter"], function(require, exports, module) { "use strict"; var oop = require("../lib/oop"); var MultiHashHandler = require("../keyboard/hash_handler").MultiHashHandler; var EventEmitter = require("../lib/event_emitter").EventEmitter; var CommandManager = function(platform, commands) { MultiHashHandler.call(this, commands, platform); this.byName = this.commands; this.setDefaultHandler("exec", function(e) { return e.command.exec(e.editor, e.args || {}); }); }; oop.inherits(CommandManager, MultiHashHandler); (function() { oop.implement(this, EventEmitter); this.exec = function(command, editor, args) { if (Array.isArray(command)) { for (var i = command.length; i--; ) { if (this.exec(command[i], editor, args)) return true; } return false; } if (typeof command === "string") command = this.commands[command]; if (!command) return false; if (editor && editor.$readOnly && !command.readOnly) return false; var e = {editor: editor, command: command, args: args}; e.returnValue = this._emit("exec", e); this._signal("afterExec", e); return e.returnValue === false ? false : true; }; this.toggleRecording = function(editor) { if (this.$inReplay) return; editor && editor._emit("changeStatus"); if (this.recording) { this.macro.pop(); this.removeEventListener("exec", this.$addCommandToMacro); if (!this.macro.length) this.macro = this.oldMacro; return this.recording = false; } if (!this.$addCommandToMacro) { this.$addCommandToMacro = function(e) { this.macro.push([e.command, e.args]); }.bind(this); } this.oldMacro = this.macro; this.macro = []; this.on("exec", this.$addCommandToMacro); return this.recording = true; }; this.replay = function(editor) { if (this.$inReplay || !this.macro) return; if (this.recording) return this.toggleRecording(editor); try { this.$inReplay = true; this.macro.forEach(function(x) { if (typeof x == "string") this.exec(x, editor); else this.exec(x[0], editor, x[1]); }, this); } finally { this.$inReplay = false; } }; this.trimMacro = function(m) { return m.map(function(x){ if (typeof x[0] != "string") x[0] = x[0].name; if (!x[1]) x = x[0]; return x; }); }; }).call(CommandManager.prototype); exports.CommandManager = CommandManager; }); ace.define("ace/commands/default_commands",["require","exports","module","ace/lib/lang","ace/config","ace/range"], function(require, exports, module) { "use strict"; var lang = require("../lib/lang"); var config = require("../config"); var Range = require("../range").Range; function bindKey(win, mac) { return {win: win, mac: mac}; } exports.commands = [{ name: "showSettingsMenu", bindKey: bindKey("Ctrl-,", "Command-,"), exec: function(editor) { config.loadModule("ace/ext/settings_menu", function(module) { module.init(editor); editor.showSettingsMenu(); }); }, readOnly: true }, { name: "goToNextError", bindKey: bindKey("Alt-E", "Ctrl-E"), exec: function(editor) { config.loadModule("ace/ext/error_marker", function(module) { module.showErrorMarker(editor, 1); }); }, scrollIntoView: "animate", readOnly: true }, { name: "goToPreviousError", bindKey: bindKey("Alt-Shift-E", "Ctrl-Shift-E"), exec: function(editor) { config.loadModule("ace/ext/error_marker", function(module) { module.showErrorMarker(editor, -1); }); }, scrollIntoView: "animate", readOnly: true }, { name: "selectall", bindKey: bindKey("Ctrl-A", "Command-A"), exec: function(editor) { editor.selectAll(); }, readOnly: true }, { name: "centerselection", bindKey: bindKey(null, "Ctrl-L"), exec: function(editor) { editor.centerSelection(); }, readOnly: true }, { name: "gotoline", bindKey: bindKey("Ctrl-L", "Command-L"), exec: function(editor) { var line = parseInt(prompt("Enter line number:"), 10); if (!isNaN(line)) { editor.gotoLine(line); } }, readOnly: true }, { name: "fold", bindKey: bindKey("Alt-L|Ctrl-F1", "Command-Alt-L|Command-F1"), exec: function(editor) { editor.session.toggleFold(false); }, scrollIntoView: "center", readOnly: true }, { name: "unfold", bindKey: bindKey("Alt-Shift-L|Ctrl-Shift-F1", "Command-Alt-Shift-L|Command-Shift-F1"), exec: function(editor) { editor.session.toggleFold(true); }, scrollIntoView: "center", readOnly: true }, { name: "toggleFoldWidget", bindKey: bindKey("F2", "F2"), exec: function(editor) { editor.session.toggleFoldWidget(); }, scrollIntoView: "center", readOnly: true }, { name: "toggleParentFoldWidget", bindKey: bindKey("Alt-F2", "Alt-F2"), exec: function(editor) { editor.session.toggleFoldWidget(true); }, scrollIntoView: "center", readOnly: true }, { name: "foldall", bindKey: bindKey("Ctrl-Alt-0", "Ctrl-Command-Option-0"), exec: function(editor) { editor.session.foldAll(); }, scrollIntoView: "center", readOnly: true }, { name: "foldOther", bindKey: bindKey("Alt-0", "Command-Option-0"), exec: function(editor) { editor.session.foldAll(); editor.session.unfold(editor.selection.getAllRanges()); }, scrollIntoView: "center", readOnly: true }, { name: "unfoldall", bindKey: bindKey("Alt-Shift-0", "Command-Option-Shift-0"), exec: function(editor) { editor.session.unfold(); }, scrollIntoView: "center", readOnly: true }, { name: "findnext", bindKey: bindKey("Ctrl-K", "Command-G"), exec: function(editor) { editor.findNext(); }, multiSelectAction: "forEach", scrollIntoView: "center", readOnly: true }, { name: "findprevious", bindKey: bindKey("Ctrl-Shift-K", "Command-Shift-G"), exec: function(editor) { editor.findPrevious(); }, multiSelectAction: "forEach", scrollIntoView: "center", readOnly: true }, { name: "selectOrFindNext", bindKey: bindKey("Alt-K", "Ctrl-G"), exec: function(editor) { if (editor.selection.isEmpty()) editor.selection.selectWord(); else editor.findNext(); }, readOnly: true }, { name: "selectOrFindPrevious", bindKey: bindKey("Alt-Shift-K", "Ctrl-Shift-G"), exec: function(editor) { if (editor.selection.isEmpty()) editor.selection.selectWord(); else editor.findPrevious(); }, readOnly: true }, { name: "find", bindKey: bindKey("Ctrl-F", "Command-F"), exec: function(editor) { config.loadModule("ace/ext/searchbox", function(e) {e.Search(editor)}); }, readOnly: true }, { name: "overwrite", bindKey: "Insert", exec: function(editor) { editor.toggleOverwrite(); }, readOnly: true }, { name: "selecttostart", bindKey: bindKey("Ctrl-Shift-Home", "Command-Shift-Up"), exec: function(editor) { editor.getSelection().selectFileStart(); }, multiSelectAction: "forEach", readOnly: true, scrollIntoView: "animate", aceCommandGroup: "fileJump" }, { name: "gotostart", bindKey: bindKey("Ctrl-Home", "Command-Home|Command-Up"), exec: function(editor) { editor.navigateFileStart(); }, multiSelectAction: "forEach", readOnly: true, scrollIntoView: "animate", aceCommandGroup: "fileJump" }, { name: "selectup", bindKey: bindKey("Shift-Up", "Shift-Up"), exec: function(editor) { editor.getSelection().selectUp(); }, multiSelectAction: "forEach", readOnly: true }, { name: "golineup", bindKey: bindKey("Up", "Up|Ctrl-P"), exec: function(editor, args) { editor.navigateUp(args.times); }, multiSelectAction: "forEach", readOnly: true }, { name: "selecttoend", bindKey: bindKey("Ctrl-Shift-End", "Command-Shift-Down"), exec: function(editor) { editor.getSelection().selectFileEnd(); }, multiSelectAction: "forEach", readOnly: true, scrollIntoView: "animate", aceCommandGroup: "fileJump" }, { name: "gotoend", bindKey: bindKey("Ctrl-End", "Command-End|Command-Down"), exec: function(editor) { editor.navigateFileEnd(); }, multiSelectAction: "forEach", readOnly: true, scrollIntoView: "animate", aceCommandGroup: "fileJump" }, { name: "selectdown", bindKey: bindKey("Shift-Down", "Shift-Down"), exec: function(editor) { editor.getSelection().selectDown(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "golinedown", bindKey: bindKey("Down", "Down|Ctrl-N"), exec: function(editor, args) { editor.navigateDown(args.times); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "selectwordleft", bindKey: bindKey("Ctrl-Shift-Left", "Option-Shift-Left"), exec: function(editor) { editor.getSelection().selectWordLeft(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "gotowordleft", bindKey: bindKey("Ctrl-Left", "Option-Left"), exec: function(editor) { editor.navigateWordLeft(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "selecttolinestart", bindKey: bindKey("Alt-Shift-Left", "Command-Shift-Left"), exec: function(editor) { editor.getSelection().selectLineStart(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "gotolinestart", bindKey: bindKey("Alt-Left|Home", "Command-Left|Home|Ctrl-A"), exec: function(editor) { editor.navigateLineStart(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "selectleft", bindKey: bindKey("Shift-Left", "Shift-Left"), exec: function(editor) { editor.getSelection().selectLeft(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "gotoleft", bindKey: bindKey("Left", "Left|Ctrl-B"), exec: function(editor, args) { editor.navigateLeft(args.times); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "selectwordright", bindKey: bindKey("Ctrl-Shift-Right", "Option-Shift-Right"), exec: function(editor) { editor.getSelection().selectWordRight(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "gotowordright", bindKey: bindKey("Ctrl-Right", "Option-Right"), exec: function(editor) { editor.navigateWordRight(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "selecttolineend", bindKey: bindKey("Alt-Shift-Right", "Command-Shift-Right"), exec: function(editor) { editor.getSelection().selectLineEnd(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "gotolineend", bindKey: bindKey("Alt-Right|End", "Command-Right|End|Ctrl-E"), exec: function(editor) { editor.navigateLineEnd(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "selectright", bindKey: bindKey("Shift-Right", "Shift-Right"), exec: function(editor) { editor.getSelection().selectRight(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "gotoright", bindKey: bindKey("Right", "Right|Ctrl-F"), exec: function(editor, args) { editor.navigateRight(args.times); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "selectpagedown", bindKey: "Shift-PageDown", exec: function(editor) { editor.selectPageDown(); }, readOnly: true }, { name: "pagedown", bindKey: bindKey(null, "Option-PageDown"), exec: function(editor) { editor.scrollPageDown(); }, readOnly: true }, { name: "gotopagedown", bindKey: bindKey("PageDown", "PageDown|Ctrl-V"), exec: function(editor) { editor.gotoPageDown(); }, readOnly: true }, { name: "selectpageup", bindKey: "Shift-PageUp", exec: function(editor) { editor.selectPageUp(); }, readOnly: true }, { name: "pageup", bindKey: bindKey(null, "Option-PageUp"), exec: function(editor) { editor.scrollPageUp(); }, readOnly: true }, { name: "gotopageup", bindKey: "PageUp", exec: function(editor) { editor.gotoPageUp(); }, readOnly: true }, { name: "scrollup", bindKey: bindKey("Ctrl-Up", null), exec: function(e) { e.renderer.scrollBy(0, -2 * e.renderer.layerConfig.lineHeight); }, readOnly: true }, { name: "scrolldown", bindKey: bindKey("Ctrl-Down", null), exec: function(e) { e.renderer.scrollBy(0, 2 * e.renderer.layerConfig.lineHeight); }, readOnly: true }, { name: "selectlinestart", bindKey: "Shift-Home", exec: function(editor) { editor.getSelection().selectLineStart(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "selectlineend", bindKey: "Shift-End", exec: function(editor) { editor.getSelection().selectLineEnd(); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "togglerecording", bindKey: bindKey("Ctrl-Alt-E", "Command-Option-E"), exec: function(editor) { editor.commands.toggleRecording(editor); }, readOnly: true }, { name: "replaymacro", bindKey: bindKey("Ctrl-Shift-E", "Command-Shift-E"), exec: function(editor) { editor.commands.replay(editor); }, readOnly: true }, { name: "jumptomatching", bindKey: bindKey("Ctrl-P", "Ctrl-P"), exec: function(editor) { editor.jumpToMatching(); }, multiSelectAction: "forEach", readOnly: true }, { name: "selecttomatching", bindKey: bindKey("Ctrl-Shift-P", "Ctrl-Shift-P"), exec: function(editor) { editor.jumpToMatching(true); }, multiSelectAction: "forEach", readOnly: true }, { name: "passKeysToBrowser", bindKey: bindKey("null", "null"), exec: function() {}, passEvent: true, readOnly: true }, { name: "cut", exec: function(editor) { var range = editor.getSelectionRange(); editor._emit("cut", range); if (!editor.selection.isEmpty()) { editor.session.remove(range); editor.clearSelection(); } }, scrollIntoView: "cursor", multiSelectAction: "forEach" }, { name: "removeline", bindKey: bindKey("Ctrl-D", "Command-D"), exec: function(editor) { editor.removeLines(); }, scrollIntoView: "cursor", multiSelectAction: "forEachLine" }, { name: "duplicateSelection", bindKey: bindKey("Ctrl-Shift-D", "Command-Shift-D"), exec: function(editor) { editor.duplicateSelection(); }, scrollIntoView: "cursor", multiSelectAction: "forEach" }, { name: "sortlines", bindKey: bindKey("Ctrl-Alt-S", "Command-Alt-S"), exec: function(editor) { editor.sortLines(); }, scrollIntoView: "selection", multiSelectAction: "forEachLine" }, { name: "togglecomment", bindKey: bindKey("Ctrl-/", "Command-/"), exec: function(editor) { editor.toggleCommentLines(); }, multiSelectAction: "forEachLine", scrollIntoView: "selectionPart" }, { name: "toggleBlockComment", bindKey: bindKey("Ctrl-Shift-/", "Command-Shift-/"), exec: function(editor) { editor.toggleBlockComment(); }, multiSelectAction: "forEach", scrollIntoView: "selectionPart" }, { name: "modifyNumberUp", bindKey: bindKey("Ctrl-Shift-Up", "Alt-Shift-Up"), exec: function(editor) { editor.modifyNumber(1); }, multiSelectAction: "forEach" }, { name: "modifyNumberDown", bindKey: bindKey("Ctrl-Shift-Down", "Alt-Shift-Down"), exec: function(editor) { editor.modifyNumber(-1); }, multiSelectAction: "forEach" }, { name: "replace", bindKey: bindKey("Ctrl-H", "Command-Option-F"), exec: function(editor) { config.loadModule("ace/ext/searchbox", function(e) {e.Search(editor, true)}); } }, { name: "undo", bindKey: bindKey("Ctrl-Z", "Command-Z"), exec: function(editor) { editor.undo(); } }, { name: "redo", bindKey: bindKey("Ctrl-Shift-Z|Ctrl-Y", "Command-Shift-Z|Command-Y"), exec: function(editor) { editor.redo(); } }, { name: "copylinesup", bindKey: bindKey("Alt-Shift-Up", "Command-Option-Up"), exec: function(editor) { editor.copyLinesUp(); }, scrollIntoView: "cursor" }, { name: "movelinesup", bindKey: bindKey("Alt-Up", "Option-Up"), exec: function(editor) { editor.moveLinesUp(); }, scrollIntoView: "cursor" }, { name: "copylinesdown", bindKey: bindKey("Alt-Shift-Down", "Command-Option-Down"), exec: function(editor) { editor.copyLinesDown(); }, scrollIntoView: "cursor" }, { name: "movelinesdown", bindKey: bindKey("Alt-Down", "Option-Down"), exec: function(editor) { editor.moveLinesDown(); }, scrollIntoView: "cursor" }, { name: "del", bindKey: bindKey("Delete", "Delete|Ctrl-D|Shift-Delete"), exec: function(editor) { editor.remove("right"); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "backspace", bindKey: bindKey( "Shift-Backspace|Backspace", "Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H" ), exec: function(editor) { editor.remove("left"); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "cut_or_delete", bindKey: bindKey("Shift-Delete", null), exec: function(editor) { if (editor.selection.isEmpty()) { editor.remove("left"); } else { return false; } }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "removetolinestart", bindKey: bindKey("Alt-Backspace", "Command-Backspace"), exec: function(editor) { editor.removeToLineStart(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "removetolineend", bindKey: bindKey("Alt-Delete", "Ctrl-K"), exec: function(editor) { editor.removeToLineEnd(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "removewordleft", bindKey: bindKey("Ctrl-Backspace", "Alt-Backspace|Ctrl-Alt-Backspace"), exec: function(editor) { editor.removeWordLeft(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "removewordright", bindKey: bindKey("Ctrl-Delete", "Alt-Delete"), exec: function(editor) { editor.removeWordRight(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "outdent", bindKey: bindKey("Shift-Tab", "Shift-Tab"), exec: function(editor) { editor.blockOutdent(); }, multiSelectAction: "forEach", scrollIntoView: "selectionPart" }, { name: "indent", bindKey: bindKey("Tab", "Tab"), exec: function(editor) { editor.indent(); }, multiSelectAction: "forEach", scrollIntoView: "selectionPart" }, { name: "blockoutdent", bindKey: bindKey("Ctrl-[", "Ctrl-["), exec: function(editor) { editor.blockOutdent(); }, multiSelectAction: "forEachLine", scrollIntoView: "selectionPart" }, { name: "blockindent", bindKey: bindKey("Ctrl-]", "Ctrl-]"), exec: function(editor) { editor.blockIndent(); }, multiSelectAction: "forEachLine", scrollIntoView: "selectionPart" }, { name: "insertstring", exec: function(editor, str) { editor.insert(str); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "inserttext", exec: function(editor, args) { editor.insert(lang.stringRepeat(args.text || "", args.times || 1)); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "splitline", bindKey: bindKey(null, "Ctrl-O"), exec: function(editor) { editor.splitLine(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "transposeletters", bindKey: bindKey("Ctrl-T", "Ctrl-T"), exec: function(editor) { editor.transposeLetters(); }, multiSelectAction: function(editor) {editor.transposeSelections(1); }, scrollIntoView: "cursor" }, { name: "touppercase", bindKey: bindKey("Ctrl-U", "Ctrl-U"), exec: function(editor) { editor.toUpperCase(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "tolowercase", bindKey: bindKey("Ctrl-Shift-U", "Ctrl-Shift-U"), exec: function(editor) { editor.toLowerCase(); }, multiSelectAction: "forEach", scrollIntoView: "cursor" }, { name: "expandtoline", bindKey: bindKey("Ctrl-Shift-L", "Command-Shift-L"), exec: function(editor) { var range = editor.selection.getRange(); range.start.column = range.end.column = 0; range.end.row++; editor.selection.setRange(range, false); }, multiSelectAction: "forEach", scrollIntoView: "cursor", readOnly: true }, { name: "joinlines", bindKey: bindKey(null, null), exec: function(editor) { var isBackwards = editor.selection.isBackwards(); var selectionStart = isBackwards ? editor.selection.getSelectionLead() : editor.selection.getSelectionAnchor(); var selectionEnd = isBackwards ? editor.selection.getSelectionAnchor() : editor.selection.getSelectionLead(); var firstLineEndCol = editor.session.doc.getLine(selectionStart.row).length var selectedText = editor.session.doc.getTextRange(editor.selection.getRange()); var selectedCount = selectedText.replace(/\n\s*/, " ").length; var insertLine = editor.session.doc.getLine(selectionStart.row); for (var i = selectionStart.row + 1; i <= selectionEnd.row + 1; i++) { var curLine = lang.stringTrimLeft(lang.stringTrimRight(editor.session.doc.getLine(i))); if (curLine.length !== 0) { curLine = " " + curLine; } insertLine += curLine; }; if (selectionEnd.row + 1 < (editor.session.doc.getLength() - 1)) { insertLine += editor.session.doc.getNewLineCharacter(); } editor.clearSelection(); editor.session.doc.replace(new Range(selectionStart.row, 0, selectionEnd.row + 2, 0), insertLine); if (selectedCount > 0) { editor.selection.moveCursorTo(selectionStart.row, selectionStart.column); editor.selection.selectTo(selectionStart.row, selectionStart.column + selectedCount); } else { firstLineEndCol = editor.session.doc.getLine(selectionStart.row).length > firstLineEndCol ? (firstLineEndCol + 1) : firstLineEndCol; editor.selection.moveCursorTo(selectionStart.row, firstLineEndCol); } }, multiSelectAction: "forEach", readOnly: true }, { name: "invertSelection", bindKey: bindKey(null, null), exec: function(editor) { var endRow = editor.session.doc.getLength() - 1; var endCol = editor.session.doc.getLine(endRow).length; var ranges = editor.selection.rangeList.ranges; var newRanges = []; if (ranges.length < 1) { ranges = [editor.selection.getRange()]; } for (var i = 0; i < ranges.length; i++) { if (i == (ranges.length - 1)) { if (!(ranges[i].end.row === endRow && ranges[i].end.column === endCol)) { newRanges.push(new Range(ranges[i].end.row, ranges[i].end.column, endRow, endCol)); } } if (i === 0) { if (!(ranges[i].start.row === 0 && ranges[i].start.column === 0)) { newRanges.push(new Range(0, 0, ranges[i].start.row, ranges[i].start.column)); } } else { newRanges.push(new Range(ranges[i-1].end.row, ranges[i-1].end.column, ranges[i].start.row, ranges[i].start.column)); } } editor.exitMultiSelectMode(); editor.clearSelection(); for(var i = 0; i < newRanges.length; i++) { editor.selection.addRange(newRanges[i], false); } }, readOnly: true, scrollIntoView: "none" }]; }); ace.define("ace/editor",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/keyboard/textinput","ace/mouse/mouse_handler","ace/mouse/fold_handler","ace/keyboard/keybinding","ace/edit_session","ace/search","ace/range","ace/lib/event_emitter","ace/commands/command_manager","ace/commands/default_commands","ace/config","ace/token_iterator"], function(require, exports, module) { "use strict"; require("./lib/fixoldbrowsers"); var oop = require("./lib/oop"); var dom = require("./lib/dom"); var lang = require("./lib/lang"); var useragent = require("./lib/useragent"); var TextInput = require("./keyboard/textinput").TextInput; var MouseHandler = require("./mouse/mouse_handler").MouseHandler; var FoldHandler = require("./mouse/fold_handler").FoldHandler; var KeyBinding = require("./keyboard/keybinding").KeyBinding; var EditSession = require("./edit_session").EditSession; var Search = require("./search").Search; var Range = require("./range").Range; var EventEmitter = require("./lib/event_emitter").EventEmitter; var CommandManager = require("./commands/command_manager").CommandManager; var defaultCommands = require("./commands/default_commands").commands; var config = require("./config"); var TokenIterator = require("./token_iterator").TokenIterator; var Editor = function(renderer, session) { var container = renderer.getContainerElement(); this.container = container; this.renderer = renderer; this.commands = new CommandManager(useragent.isMac ? "mac" : "win", defaultCommands); this.textInput = new TextInput(renderer.getTextAreaContainer(), this); this.renderer.textarea = this.textInput.getElement(); this.keyBinding = new KeyBinding(this); this.$mouseHandler = new MouseHandler(this); new FoldHandler(this); this.$blockScrolling = 0; this.$search = new Search().set({ wrap: true }); this.$historyTracker = this.$historyTracker.bind(this); this.commands.on("exec", this.$historyTracker); this.$initOperationListeners(); this._$emitInputEvent = lang.delayedCall(function() { this._signal("input", {}); if (this.session && this.session.bgTokenizer) this.session.bgTokenizer.scheduleStart(); }.bind(this)); this.on("change", function(_, _self) { _self._$emitInputEvent.schedule(31); }); this.setSession(session || new EditSession("")); config.resetOptions(this); config._signal("editor", this); }; (function(){ oop.implement(this, EventEmitter); this.$initOperationListeners = function() { function last(a) {return a[a.length - 1]} this.selections = []; this.commands.on("exec", this.startOperation.bind(this), true); this.commands.on("afterExec", this.endOperation.bind(this), true); this.$opResetTimer = lang.delayedCall(this.endOperation.bind(this)); this.on("change", function() { this.curOp || this.startOperation(); this.curOp.docChanged = true; }.bind(this), true); this.on("changeSelection", function() { this.curOp || this.startOperation(); this.curOp.selectionChanged = true; }.bind(this), true); }; this.curOp = null; this.prevOp = {}; this.startOperation = function(commadEvent) { if (this.curOp) { if (!commadEvent || this.curOp.command) return; this.prevOp = this.curOp; } if (!commadEvent) { this.previousCommand = null; commadEvent = {}; } this.$opResetTimer.schedule(); this.curOp = { command: commadEvent.command || {}, args: commadEvent.args, scrollTop: this.renderer.scrollTop }; }; this.endOperation = function(e) { if (this.curOp) { if (e && e.returnValue === false) return this.curOp = null; var command = this.curOp.command; if (command && command.scrollIntoView) { switch (command.scrollIntoView) { case "center": this.renderer.scrollCursorIntoView(null, 0.5); break; case "animate": case "cursor": this.renderer.scrollCursorIntoView(); break; case "selectionPart": var range = this.selection.getRange(); var config = this.renderer.layerConfig; if (range.start.row >= config.lastRow || range.end.row <= config.firstRow) { this.renderer.scrollSelectionIntoView(this.selection.anchor, this.selection.lead); } break; default: break; } if (command.scrollIntoView == "animate") this.renderer.animateScrolling(this.curOp.scrollTop); } this.prevOp = this.curOp; this.curOp = null; } }; this.$mergeableCommands = ["backspace", "del", "insertstring"]; this.$historyTracker = function(e) { if (!this.$mergeUndoDeltas) return; var prev = this.prevOp; var mergeableCommands = this.$mergeableCommands; var shouldMerge = prev.command && (e.command.name == prev.command.name); if (e.command.name == "insertstring") { var text = e.args; if (this.mergeNextCommand === undefined) this.mergeNextCommand = true; shouldMerge = shouldMerge && this.mergeNextCommand // previous command allows to coalesce with && (!/\s/.test(text) || /\s/.test(prev.args)); // previous insertion was of same type this.mergeNextCommand = true; } else { shouldMerge = shouldMerge && mergeableCommands.indexOf(e.command.name) !== -1; // the command is mergeable } if ( this.$mergeUndoDeltas != "always" && Date.now() - this.sequenceStartTime > 2000 ) { shouldMerge = false; // the sequence is too long } if (shouldMerge) this.session.mergeUndoDeltas = true; else if (mergeableCommands.indexOf(e.command.name) !== -1) this.sequenceStartTime = Date.now(); }; this.setKeyboardHandler = function(keyboardHandler, cb) { if (keyboardHandler && typeof keyboardHandler === "string") { this.$keybindingId = keyboardHandler; var _self = this; config.loadModule(["keybinding", keyboardHandler], function(module) { if (_self.$keybindingId == keyboardHandler) _self.keyBinding.setKeyboardHandler(module && module.handler); cb && cb(); }); } else { this.$keybindingId = null; this.keyBinding.setKeyboardHandler(keyboardHandler); cb && cb(); } }; this.getKeyboardHandler = function() { return this.keyBinding.getKeyboardHandler(); }; this.setSession = function(session) { if (this.session == session) return; var oldSession = this.session; if (oldSession) { this.session.removeEventListener("change", this.$onDocumentChange); this.session.removeEventListener("changeMode", this.$onChangeMode); this.session.removeEventListener("tokenizerUpdate", this.$onTokenizerUpdate); this.session.removeEventListener("changeTabSize", this.$onChangeTabSize); this.session.removeEventListener("changeWrapLimit", this.$onChangeWrapLimit); this.session.removeEventListener("changeWrapMode", this.$onChangeWrapMode); this.session.removeEventListener("onChangeFold", this.$onChangeFold); this.session.removeEventListener("changeFrontMarker", this.$onChangeFrontMarker); this.session.removeEventListener("changeBackMarker", this.$onChangeBackMarker); this.session.removeEventListener("changeBreakpoint", this.$onChangeBreakpoint); this.session.removeEventListener("changeAnnotation", this.$onChangeAnnotation); this.session.removeEventListener("changeOverwrite", this.$onCursorChange); this.session.removeEventListener("changeScrollTop", this.$onScrollTopChange); this.session.removeEventListener("changeScrollLeft", this.$onScrollLeftChange); var selection = this.session.getSelection(); selection.removeEventListener("changeCursor", this.$onCursorChange); selection.removeEventListener("changeSelection", this.$onSelectionChange); } this.session = session; if (session) { this.$onDocumentChange = this.onDocumentChange.bind(this); session.addEventListener("change", this.$onDocumentChange); this.renderer.setSession(session); this.$onChangeMode = this.onChangeMode.bind(this); session.addEventListener("changeMode", this.$onChangeMode); this.$onTokenizerUpdate = this.onTokenizerUpdate.bind(this); session.addEventListener("tokenizerUpdate", this.$onTokenizerUpdate); this.$onChangeTabSize = this.renderer.onChangeTabSize.bind(this.renderer); session.addEventListener("changeTabSize", this.$onChangeTabSize); this.$onChangeWrapLimit = this.onChangeWrapLimit.bind(this); session.addEventListener("changeWrapLimit", this.$onChangeWrapLimit); this.$onChangeWrapMode = this.onChangeWrapMode.bind(this); session.addEventListener("changeWrapMode", this.$onChangeWrapMode); this.$onChangeFold = this.onChangeFold.bind(this); session.addEventListener("changeFold", this.$onChangeFold); this.$onChangeFrontMarker = this.onChangeFrontMarker.bind(this); this.session.addEventListener("changeFrontMarker", this.$onChangeFrontMarker); this.$onChangeBackMarker = this.onChangeBackMarker.bind(this); this.session.addEventListener("changeBackMarker", this.$onChangeBackMarker); this.$onChangeBreakpoint = this.onChangeBreakpoint.bind(this); this.session.addEventListener("changeBreakpoint", this.$onChangeBreakpoint); this.$onChangeAnnotation = this.onChangeAnnotation.bind(this); this.session.addEventListener("changeAnnotation", this.$onChangeAnnotation); this.$onCursorChange = this.onCursorChange.bind(this); this.session.addEventListener("changeOverwrite", this.$onCursorChange); this.$onScrollTopChange = this.onScrollTopChange.bind(this); this.session.addEventListener("changeScrollTop", this.$onScrollTopChange); this.$onScrollLeftChange = this.onScrollLeftChange.bind(this); this.session.addEventListener("changeScrollLeft", this.$onScrollLeftChange); this.selection = session.getSelection(); this.selection.addEventListener("changeCursor", this.$onCursorChange); this.$onSelectionChange = this.onSelectionChange.bind(this); this.selection.addEventListener("changeSelection", this.$onSelectionChange); this.onChangeMode(); this.$blockScrolling += 1; this.onCursorChange(); this.$blockScrolling -= 1; this.onScrollTopChange(); this.onScrollLeftChange(); this.onSelectionChange(); this.onChangeFrontMarker(); this.onChangeBackMarker(); this.onChangeBreakpoint(); this.onChangeAnnotation(); this.session.getUseWrapMode() && this.renderer.adjustWrapLimit(); this.renderer.updateFull(); } else { this.selection = null; this.renderer.setSession(session); } this._signal("changeSession", { session: session, oldSession: oldSession }); oldSession && oldSession._signal("changeEditor", {oldEditor: this}); session && session._signal("changeEditor", {editor: this}); }; this.getSession = function() { return this.session; }; this.setValue = function(val, cursorPos) { this.session.doc.setValue(val); if (!cursorPos) this.selectAll(); else if (cursorPos == 1) this.navigateFileEnd(); else if (cursorPos == -1) this.navigateFileStart(); return val; }; this.getValue = function() { return this.session.getValue(); }; this.getSelection = function() { return this.selection; }; this.resize = function(force) { this.renderer.onResize(force); }; this.setTheme = function(theme, cb) { this.renderer.setTheme(theme, cb); }; this.getTheme = function() { return this.renderer.getTheme(); }; this.setStyle = function(style) { this.renderer.setStyle(style); }; this.unsetStyle = function(style) { this.renderer.unsetStyle(style); }; this.getFontSize = function () { return this.getOption("fontSize") || dom.computedStyle(this.container, "fontSize"); }; this.setFontSize = function(size) { this.setOption("fontSize", size); }; this.$highlightBrackets = function() { if (this.session.$bracketHighlight) { this.session.removeMarker(this.session.$bracketHighlight); this.session.$bracketHighlight = null; } if (this.$highlightPending) { return; } var self = this; this.$highlightPending = true; setTimeout(function() { self.$highlightPending = false; var session = self.session; if (!session || !session.bgTokenizer) return; var pos = session.findMatchingBracket(self.getCursorPosition()); if (pos) { var range = new Range(pos.row, pos.column, pos.row, pos.column + 1); } else if (session.$mode.getMatching) { var range = session.$mode.getMatching(self.session); } if (range) session.$bracketHighlight = session.addMarker(range, "ace_bracket", "text"); }, 50); }; this.$highlightTags = function() { if (this.$highlightTagPending) return; var self = this; this.$highlightTagPending = true; setTimeout(function() { self.$highlightTagPending = false; var session = self.session; if (!session || !session.bgTokenizer) return; var pos = self.getCursorPosition(); var iterator = new TokenIterator(self.session, pos.row, pos.column); var token = iterator.getCurrentToken(); if (!token || token.type.indexOf('tag-name') === -1) { session.removeMarker(session.$tagHighlight); session.$tagHighlight = null; return; } var tag = token.value; var depth = 0; var prevToken = iterator.stepBackward(); if (prevToken.value == '<'){ do { prevToken = token; token = iterator.stepForward(); if (token && token.value === tag && token.type.indexOf('tag-name') !== -1) { if (prevToken.value === '<'){ depth++; } else if (prevToken.value === '= 0); } else { do { token = prevToken; prevToken = iterator.stepBackward(); if (token && token.value === tag && token.type.indexOf('tag-name') !== -1) { if (prevToken.value === '<') { depth++; } else if (prevToken.value === ' 1)) highlight = false; } if (session.$highlightLineMarker && !highlight) { session.removeMarker(session.$highlightLineMarker.id); session.$highlightLineMarker = null; } else if (!session.$highlightLineMarker && highlight) { var range = new Range(highlight.row, highlight.column, highlight.row, Infinity); range.id = session.addMarker(range, "ace_active-line", "screenLine"); session.$highlightLineMarker = range; } else if (highlight) { session.$highlightLineMarker.start.row = highlight.row; session.$highlightLineMarker.end.row = highlight.row; session.$highlightLineMarker.start.column = highlight.column; session._signal("changeBackMarker"); } }; this.onSelectionChange = function(e) { var session = this.session; if (session.$selectionMarker) { session.removeMarker(session.$selectionMarker); } session.$selectionMarker = null; if (!this.selection.isEmpty()) { var range = this.selection.getRange(); var style = this.getSelectionStyle(); session.$selectionMarker = session.addMarker(range, "ace_selection", style); } else { this.$updateHighlightActiveLine(); } var re = this.$highlightSelectedWord && this.$getSelectionHighLightRegexp(); this.session.highlight(re); this._signal("changeSelection"); }; this.$getSelectionHighLightRegexp = function() { var session = this.session; var selection = this.getSelectionRange(); if (selection.isEmpty() || selection.isMultiLine()) return; var startOuter = selection.start.column - 1; var endOuter = selection.end.column + 1; var line = session.getLine(selection.start.row); var lineCols = line.length; var needle = line.substring(Math.max(startOuter, 0), Math.min(endOuter, lineCols)); if ((startOuter >= 0 && /^[\w\d]/.test(needle)) || (endOuter <= lineCols && /[\w\d]$/.test(needle))) return; needle = line.substring(selection.start.column, selection.end.column); if (!/^[\w\d]+$/.test(needle)) return; var re = this.$search.$assembleRegExp({ wholeWord: true, caseSensitive: true, needle: needle }); return re; }; this.onChangeFrontMarker = function() { this.renderer.updateFrontMarkers(); }; this.onChangeBackMarker = function() { this.renderer.updateBackMarkers(); }; this.onChangeBreakpoint = function() { this.renderer.updateBreakpoints(); }; this.onChangeAnnotation = function() { this.renderer.setAnnotations(this.session.getAnnotations()); }; this.onChangeMode = function(e) { this.renderer.updateText(); this._emit("changeMode", e); }; this.onChangeWrapLimit = function() { this.renderer.updateFull(); }; this.onChangeWrapMode = function() { this.renderer.onResize(true); }; this.onChangeFold = function() { this.$updateHighlightActiveLine(); this.renderer.updateFull(); }; this.getSelectedText = function() { return this.session.getTextRange(this.getSelectionRange()); }; this.getCopyText = function() { var text = this.getSelectedText(); this._signal("copy", text); return text; }; this.onCopy = function() { this.commands.exec("copy", this); }; this.onCut = function() { this.commands.exec("cut", this); }; this.onPaste = function(text) { if (this.$readOnly) return; var e = {text: text}; this._signal("paste", e); this.insert(e.text, true); }; this.execCommand = function(command, args) { return this.commands.exec(command, this, args); }; this.insert = function(text, pasted) { var session = this.session; var mode = session.getMode(); var cursor = this.getCursorPosition(); if (this.getBehavioursEnabled() && !pasted) { var transform = mode.transformAction(session.getState(cursor.row), 'insertion', this, session, text); if (transform) { if (text !== transform.text) { this.session.mergeUndoDeltas = false; this.$mergeNextCommand = false; } text = transform.text; } } if (text == "\t") text = this.session.getTabString(); if (!this.selection.isEmpty()) { var range = this.getSelectionRange(); cursor = this.session.remove(range); this.clearSelection(); } else if (this.session.getOverwrite()) { var range = new Range.fromPoints(cursor, cursor); range.end.column += text.length; this.session.remove(range); } if (text == "\n" || text == "\r\n") { var line = session.getLine(cursor.row); if (cursor.column > line.search(/\S|$/)) { var d = line.substr(cursor.column).search(/\S|$/); session.doc.removeInLine(cursor.row, cursor.column, cursor.column + d); } } this.clearSelection(); var start = cursor.column; var lineState = session.getState(cursor.row); var line = session.getLine(cursor.row); var shouldOutdent = mode.checkOutdent(lineState, line, text); var end = session.insert(cursor, text); if (transform && transform.selection) { if (transform.selection.length == 2) { // Transform relative to the current column this.selection.setSelectionRange( new Range(cursor.row, start + transform.selection[0], cursor.row, start + transform.selection[1])); } else { // Transform relative to the current row. this.selection.setSelectionRange( new Range(cursor.row + transform.selection[0], transform.selection[1], cursor.row + transform.selection[2], transform.selection[3])); } } if (session.getDocument().isNewLine(text)) { var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString()); session.insert({row: cursor.row+1, column: 0}, lineIndent); } if (shouldOutdent) mode.autoOutdent(lineState, session, cursor.row); }; this.onTextInput = function(text) { this.keyBinding.onTextInput(text); }; this.onCommandKey = function(e, hashId, keyCode) { this.keyBinding.onCommandKey(e, hashId, keyCode); }; this.setOverwrite = function(overwrite) { this.session.setOverwrite(overwrite); }; this.getOverwrite = function() { return this.session.getOverwrite(); }; this.toggleOverwrite = function() { this.session.toggleOverwrite(); }; this.setScrollSpeed = function(speed) { this.setOption("scrollSpeed", speed); }; this.getScrollSpeed = function() { return this.getOption("scrollSpeed"); }; this.setDragDelay = function(dragDelay) { this.setOption("dragDelay", dragDelay); }; this.getDragDelay = function() { return this.getOption("dragDelay"); }; this.setSelectionStyle = function(val) { this.setOption("selectionStyle", val); }; this.getSelectionStyle = function() { return this.getOption("selectionStyle"); }; this.setHighlightActiveLine = function(shouldHighlight) { this.setOption("highlightActiveLine", shouldHighlight); }; this.getHighlightActiveLine = function() { return this.getOption("highlightActiveLine"); }; this.setHighlightGutterLine = function(shouldHighlight) { this.setOption("highlightGutterLine", shouldHighlight); }; this.getHighlightGutterLine = function() { return this.getOption("highlightGutterLine"); }; this.setHighlightSelectedWord = function(shouldHighlight) { this.setOption("highlightSelectedWord", shouldHighlight); }; this.getHighlightSelectedWord = function() { return this.$highlightSelectedWord; }; this.setAnimatedScroll = function(shouldAnimate){ this.renderer.setAnimatedScroll(shouldAnimate); }; this.getAnimatedScroll = function(){ return this.renderer.getAnimatedScroll(); }; this.setShowInvisibles = function(showInvisibles) { this.renderer.setShowInvisibles(showInvisibles); }; this.getShowInvisibles = function() { return this.renderer.getShowInvisibles(); }; this.setDisplayIndentGuides = function(display) { this.renderer.setDisplayIndentGuides(display); }; this.getDisplayIndentGuides = function() { return this.renderer.getDisplayIndentGuides(); }; this.setShowPrintMargin = function(showPrintMargin) { this.renderer.setShowPrintMargin(showPrintMargin); }; this.getShowPrintMargin = function() { return this.renderer.getShowPrintMargin(); }; this.setPrintMarginColumn = function(showPrintMargin) { this.renderer.setPrintMarginColumn(showPrintMargin); }; this.getPrintMarginColumn = function() { return this.renderer.getPrintMarginColumn(); }; this.setReadOnly = function(readOnly) { this.setOption("readOnly", readOnly); }; this.getReadOnly = function() { return this.getOption("readOnly"); }; this.setBehavioursEnabled = function (enabled) { this.setOption("behavioursEnabled", enabled); }; this.getBehavioursEnabled = function () { return this.getOption("behavioursEnabled"); }; this.setWrapBehavioursEnabled = function (enabled) { this.setOption("wrapBehavioursEnabled", enabled); }; this.getWrapBehavioursEnabled = function () { return this.getOption("wrapBehavioursEnabled"); }; this.setShowFoldWidgets = function(show) { this.setOption("showFoldWidgets", show); }; this.getShowFoldWidgets = function() { return this.getOption("showFoldWidgets"); }; this.setFadeFoldWidgets = function(fade) { this.setOption("fadeFoldWidgets", fade); }; this.getFadeFoldWidgets = function() { return this.getOption("fadeFoldWidgets"); }; this.remove = function(dir) { if (this.selection.isEmpty()){ if (dir == "left") this.selection.selectLeft(); else this.selection.selectRight(); } var range = this.getSelectionRange(); if (this.getBehavioursEnabled()) { var session = this.session; var state = session.getState(range.start.row); var new_range = session.getMode().transformAction(state, 'deletion', this, session, range); if (range.end.column === 0) { var text = session.getTextRange(range); if (text[text.length - 1] == "\n") { var line = session.getLine(range.end.row); if (/^\s+$/.test(line)) { range.end.column = line.length; } } } if (new_range) range = new_range; } this.session.remove(range); this.clearSelection(); }; this.removeWordRight = function() { if (this.selection.isEmpty()) this.selection.selectWordRight(); this.session.remove(this.getSelectionRange()); this.clearSelection(); }; this.removeWordLeft = function() { if (this.selection.isEmpty()) this.selection.selectWordLeft(); this.session.remove(this.getSelectionRange()); this.clearSelection(); }; this.removeToLineStart = function() { if (this.selection.isEmpty()) this.selection.selectLineStart(); this.session.remove(this.getSelectionRange()); this.clearSelection(); }; this.removeToLineEnd = function() { if (this.selection.isEmpty()) this.selection.selectLineEnd(); var range = this.getSelectionRange(); if (range.start.column == range.end.column && range.start.row == range.end.row) { range.end.column = 0; range.end.row++; } this.session.remove(range); this.clearSelection(); }; this.splitLine = function() { if (!this.selection.isEmpty()) { this.session.remove(this.getSelectionRange()); this.clearSelection(); } var cursor = this.getCursorPosition(); this.insert("\n"); this.moveCursorToPosition(cursor); }; this.transposeLetters = function() { if (!this.selection.isEmpty()) { return; } var cursor = this.getCursorPosition(); var column = cursor.column; if (column === 0) return; var line = this.session.getLine(cursor.row); var swap, range; if (column < line.length) { swap = line.charAt(column) + line.charAt(column-1); range = new Range(cursor.row, column-1, cursor.row, column+1); } else { swap = line.charAt(column-1) + line.charAt(column-2); range = new Range(cursor.row, column-2, cursor.row, column); } this.session.replace(range, swap); }; this.toLowerCase = function() { var originalRange = this.getSelectionRange(); if (this.selection.isEmpty()) { this.selection.selectWord(); } var range = this.getSelectionRange(); var text = this.session.getTextRange(range); this.session.replace(range, text.toLowerCase()); this.selection.setSelectionRange(originalRange); }; this.toUpperCase = function() { var originalRange = this.getSelectionRange(); if (this.selection.isEmpty()) { this.selection.selectWord(); } var range = this.getSelectionRange(); var text = this.session.getTextRange(range); this.session.replace(range, text.toUpperCase()); this.selection.setSelectionRange(originalRange); }; this.indent = function() { var session = this.session; var range = this.getSelectionRange(); if (range.start.row < range.end.row) { var rows = this.$getSelectedRows(); session.indentRows(rows.first, rows.last, "\t"); return; } else if (range.start.column < range.end.column) { var text = session.getTextRange(range); if (!/^\s+$/.test(text)) { var rows = this.$getSelectedRows(); session.indentRows(rows.first, rows.last, "\t"); return; } } var line = session.getLine(range.start.row); var position = range.start; var size = session.getTabSize(); var column = session.documentToScreenColumn(position.row, position.column); if (this.session.getUseSoftTabs()) { var count = (size - column % size); var indentString = lang.stringRepeat(" ", count); } else { var count = column % size; while (line[range.start.column] == " " && count) { range.start.column--; count--; } this.selection.setSelectionRange(range); indentString = "\t"; } return this.insert(indentString); }; this.blockIndent = function() { var rows = this.$getSelectedRows(); this.session.indentRows(rows.first, rows.last, "\t"); }; this.blockOutdent = function() { var selection = this.session.getSelection(); this.session.outdentRows(selection.getRange()); }; this.sortLines = function() { var rows = this.$getSelectedRows(); var session = this.session; var lines = []; for (i = rows.first; i <= rows.last; i++) lines.push(session.getLine(i)); lines.sort(function(a, b) { if (a.toLowerCase() < b.toLowerCase()) return -1; if (a.toLowerCase() > b.toLowerCase()) return 1; return 0; }); var deleteRange = new Range(0, 0, 0, 0); for (var i = rows.first; i <= rows.last; i++) { var line = session.getLine(i); deleteRange.start.row = i; deleteRange.end.row = i; deleteRange.end.column = line.length; session.replace(deleteRange, lines[i-rows.first]); } }; this.toggleCommentLines = function() { var state = this.session.getState(this.getCursorPosition().row); var rows = this.$getSelectedRows(); this.session.getMode().toggleCommentLines(state, this.session, rows.first, rows.last); }; this.toggleBlockComment = function() { var cursor = this.getCursorPosition(); var state = this.session.getState(cursor.row); var range = this.getSelectionRange(); this.session.getMode().toggleBlockComment(state, this.session, range, cursor); }; this.getNumberAt = function(row, column) { var _numberRx = /[\-]?[0-9]+(?:\.[0-9]+)?/g; _numberRx.lastIndex = 0; var s = this.session.getLine(row); while (_numberRx.lastIndex < column) { var m = _numberRx.exec(s); if(m.index <= column && m.index+m[0].length >= column){ var number = { value: m[0], start: m.index, end: m.index+m[0].length }; return number; } } return null; }; this.modifyNumber = function(amount) { var row = this.selection.getCursor().row; var column = this.selection.getCursor().column; var charRange = new Range(row, column-1, row, column); var c = this.session.getTextRange(charRange); if (!isNaN(parseFloat(c)) && isFinite(c)) { var nr = this.getNumberAt(row, column); if (nr) { var fp = nr.value.indexOf(".") >= 0 ? nr.start + nr.value.indexOf(".") + 1 : nr.end; var decimals = nr.start + nr.value.length - fp; var t = parseFloat(nr.value); t *= Math.pow(10, decimals); if(fp !== nr.end && column < fp){ amount *= Math.pow(10, nr.end - column - 1); } else { amount *= Math.pow(10, nr.end - column); } t += amount; t /= Math.pow(10, decimals); var nnr = t.toFixed(decimals); var replaceRange = new Range(row, nr.start, row, nr.end); this.session.replace(replaceRange, nnr); this.moveCursorTo(row, Math.max(nr.start +1, column + nnr.length - nr.value.length)); } } }; this.removeLines = function() { var rows = this.$getSelectedRows(); var range; if (rows.first === 0 || rows.last+1 < this.session.getLength()) range = new Range(rows.first, 0, rows.last+1, 0); else range = new Range( rows.first-1, this.session.getLine(rows.first-1).length, rows.last, this.session.getLine(rows.last).length ); this.session.remove(range); this.clearSelection(); }; this.duplicateSelection = function() { var sel = this.selection; var doc = this.session; var range = sel.getRange(); var reverse = sel.isBackwards(); if (range.isEmpty()) { var row = range.start.row; doc.duplicateLines(row, row); } else { var point = reverse ? range.start : range.end; var endPoint = doc.insert(point, doc.getTextRange(range), false); range.start = point; range.end = endPoint; sel.setSelectionRange(range, reverse); } }; this.moveLinesDown = function() { this.$moveLines(function(firstRow, lastRow) { return this.session.moveLinesDown(firstRow, lastRow); }); }; this.moveLinesUp = function() { this.$moveLines(function(firstRow, lastRow) { return this.session.moveLinesUp(firstRow, lastRow); }); }; this.moveText = function(range, toPosition, copy) { return this.session.moveText(range, toPosition, copy); }; this.copyLinesUp = function() { this.$moveLines(function(firstRow, lastRow) { this.session.duplicateLines(firstRow, lastRow); return 0; }); }; this.copyLinesDown = function() { this.$moveLines(function(firstRow, lastRow) { return this.session.duplicateLines(firstRow, lastRow); }); }; this.$moveLines = function(mover) { var selection = this.selection; if (!selection.inMultiSelectMode || this.inVirtualSelectionMode) { var range = selection.toOrientedRange(); var rows = this.$getSelectedRows(range); var linesMoved = mover.call(this, rows.first, rows.last); range.moveBy(linesMoved, 0); selection.fromOrientedRange(range); } else { var ranges = selection.rangeList.ranges; selection.rangeList.detach(this.session); for (var i = ranges.length; i--; ) { var rangeIndex = i; var rows = ranges[i].collapseRows(); var last = rows.end.row; var first = rows.start.row; while (i--) { rows = ranges[i].collapseRows(); if (first - rows.end.row <= 1) first = rows.end.row; else break; } i++; var linesMoved = mover.call(this, first, last); while (rangeIndex >= i) { ranges[rangeIndex].moveBy(linesMoved, 0); rangeIndex--; } } selection.fromOrientedRange(selection.ranges[0]); selection.rangeList.attach(this.session); } }; this.$getSelectedRows = function() { var range = this.getSelectionRange().collapseRows(); return { first: this.session.getRowFoldStart(range.start.row), last: this.session.getRowFoldEnd(range.end.row) }; }; this.onCompositionStart = function(text) { this.renderer.showComposition(this.getCursorPosition()); }; this.onCompositionUpdate = function(text) { this.renderer.setCompositionText(text); }; this.onCompositionEnd = function() { this.renderer.hideComposition(); }; this.getFirstVisibleRow = function() { return this.renderer.getFirstVisibleRow(); }; this.getLastVisibleRow = function() { return this.renderer.getLastVisibleRow(); }; this.isRowVisible = function(row) { return (row >= this.getFirstVisibleRow() && row <= this.getLastVisibleRow()); }; this.isRowFullyVisible = function(row) { return (row >= this.renderer.getFirstFullyVisibleRow() && row <= this.renderer.getLastFullyVisibleRow()); }; this.$getVisibleRowCount = function() { return this.renderer.getScrollBottomRow() - this.renderer.getScrollTopRow() + 1; }; this.$moveByPage = function(dir, select) { var renderer = this.renderer; var config = this.renderer.layerConfig; var rows = dir * Math.floor(config.height / config.lineHeight); this.$blockScrolling++; if (select === true) { this.selection.$moveSelection(function(){ this.moveCursorBy(rows, 0); }); } else if (select === false) { this.selection.moveCursorBy(rows, 0); this.selection.clearSelection(); } this.$blockScrolling--; var scrollTop = renderer.scrollTop; renderer.scrollBy(0, rows * config.lineHeight); if (select != null) renderer.scrollCursorIntoView(null, 0.5); renderer.animateScrolling(scrollTop); }; this.selectPageDown = function() { this.$moveByPage(1, true); }; this.selectPageUp = function() { this.$moveByPage(-1, true); }; this.gotoPageDown = function() { this.$moveByPage(1, false); }; this.gotoPageUp = function() { this.$moveByPage(-1, false); }; this.scrollPageDown = function() { this.$moveByPage(1); }; this.scrollPageUp = function() { this.$moveByPage(-1); }; this.scrollToRow = function(row) { this.renderer.scrollToRow(row); }; this.scrollToLine = function(line, center, animate, callback) { this.renderer.scrollToLine(line, center, animate, callback); }; this.centerSelection = function() { var range = this.getSelectionRange(); var pos = { row: Math.floor(range.start.row + (range.end.row - range.start.row) / 2), column: Math.floor(range.start.column + (range.end.column - range.start.column) / 2) }; this.renderer.alignCursor(pos, 0.5); }; this.getCursorPosition = function() { return this.selection.getCursor(); }; this.getCursorPositionScreen = function() { return this.session.documentToScreenPosition(this.getCursorPosition()); }; this.getSelectionRange = function() { return this.selection.getRange(); }; this.selectAll = function() { this.$blockScrolling += 1; this.selection.selectAll(); this.$blockScrolling -= 1; }; this.clearSelection = function() { this.selection.clearSelection(); }; this.moveCursorTo = function(row, column) { this.selection.moveCursorTo(row, column); }; this.moveCursorToPosition = function(pos) { this.selection.moveCursorToPosition(pos); }; this.jumpToMatching = function(select, expand) { var cursor = this.getCursorPosition(); var iterator = new TokenIterator(this.session, cursor.row, cursor.column); var prevToken = iterator.getCurrentToken(); var token = prevToken || iterator.stepForward(); if (!token) return; var matchType; var found = false; var depth = {}; var i = cursor.column - token.start; var bracketType; var brackets = { ")": "(", "(": "(", "]": "[", "[": "[", "{": "{", "}": "{" }; do { if (token.value.match(/[{}()\[\]]/g)) { for (; i < token.value.length && !found; i++) { if (!brackets[token.value[i]]) { continue; } bracketType = brackets[token.value[i]] + '.' + token.type.replace("rparen", "lparen"); if (isNaN(depth[bracketType])) { depth[bracketType] = 0; } switch (token.value[i]) { case '(': case '[': case '{': depth[bracketType]++; break; case ')': case ']': case '}': depth[bracketType]--; if (depth[bracketType] === -1) { matchType = 'bracket'; found = true; } break; } } } else if (token && token.type.indexOf('tag-name') !== -1) { if (isNaN(depth[token.value])) { depth[token.value] = 0; } if (prevToken.value === '<') { depth[token.value]++; } else if (prevToken.value === '= 0; --i) { if(this.$tryReplace(ranges[i], replacement)) { replaced++; } } this.selection.setSelectionRange(selection); this.$blockScrolling -= 1; return replaced; }; this.$tryReplace = function(range, replacement) { var input = this.session.getTextRange(range); replacement = this.$search.replace(input, replacement); if (replacement !== null) { range.end = this.session.replace(range, replacement); return range; } else { return null; } }; this.getLastSearchOptions = function() { return this.$search.getOptions(); }; this.find = function(needle, options, animate) { if (!options) options = {}; if (typeof needle == "string" || needle instanceof RegExp) options.needle = needle; else if (typeof needle == "object") oop.mixin(options, needle); var range = this.selection.getRange(); if (options.needle == null) { needle = this.session.getTextRange(range) || this.$search.$options.needle; if (!needle) { range = this.session.getWordRange(range.start.row, range.start.column); needle = this.session.getTextRange(range); } this.$search.set({needle: needle}); } this.$search.set(options); if (!options.start) this.$search.set({start: range}); var newRange = this.$search.find(this.session); if (options.preventScroll) return newRange; if (newRange) { this.revealRange(newRange, animate); return newRange; } if (options.backwards) range.start = range.end; else range.end = range.start; this.selection.setRange(range); }; this.findNext = function(options, animate) { this.find({skipCurrent: true, backwards: false}, options, animate); }; this.findPrevious = function(options, animate) { this.find(options, {skipCurrent: true, backwards: true}, animate); }; this.revealRange = function(range, animate) { this.$blockScrolling += 1; this.session.unfold(range); this.selection.setSelectionRange(range); this.$blockScrolling -= 1; var scrollTop = this.renderer.scrollTop; this.renderer.scrollSelectionIntoView(range.start, range.end, 0.5); if (animate !== false) this.renderer.animateScrolling(scrollTop); }; this.undo = function() { this.$blockScrolling++; this.session.getUndoManager().undo(); this.$blockScrolling--; this.renderer.scrollCursorIntoView(null, 0.5); }; this.redo = function() { this.$blockScrolling++; this.session.getUndoManager().redo(); this.$blockScrolling--; this.renderer.scrollCursorIntoView(null, 0.5); }; this.destroy = function() { this.renderer.destroy(); this._signal("destroy", this); if (this.session) { this.session.destroy(); } }; this.setAutoScrollEditorIntoView = function(enable) { if (!enable) return; var rect; var self = this; var shouldScroll = false; if (!this.$scrollAnchor) this.$scrollAnchor = document.createElement("div"); var scrollAnchor = this.$scrollAnchor; scrollAnchor.style.cssText = "position:absolute"; this.container.insertBefore(scrollAnchor, this.container.firstChild); var onChangeSelection = this.on("changeSelection", function() { shouldScroll = true; }); var onBeforeRender = this.renderer.on("beforeRender", function() { if (shouldScroll) rect = self.renderer.container.getBoundingClientRect(); }); var onAfterRender = this.renderer.on("afterRender", function() { if (shouldScroll && rect && (self.isFocused() || self.searchBox && self.searchBox.isFocused()) ) { var renderer = self.renderer; var pos = renderer.$cursorLayer.$pixelPos; var config = renderer.layerConfig; var top = pos.top - config.offset; if (pos.top >= 0 && top + rect.top < 0) { shouldScroll = true; } else if (pos.top < config.height && pos.top + rect.top + config.lineHeight > window.innerHeight) { shouldScroll = false; } else { shouldScroll = null; } if (shouldScroll != null) { scrollAnchor.style.top = top + "px"; scrollAnchor.style.left = pos.left + "px"; scrollAnchor.style.height = config.lineHeight + "px"; scrollAnchor.scrollIntoView(shouldScroll); } shouldScroll = rect = null; } }); this.setAutoScrollEditorIntoView = function(enable) { if (enable) return; delete this.setAutoScrollEditorIntoView; this.removeEventListener("changeSelection", onChangeSelection); this.renderer.removeEventListener("afterRender", onAfterRender); this.renderer.removeEventListener("beforeRender", onBeforeRender); }; }; this.$resetCursorStyle = function() { var style = this.$cursorStyle || "ace"; var cursorLayer = this.renderer.$cursorLayer; if (!cursorLayer) return; cursorLayer.setSmoothBlinking(/smooth/.test(style)); cursorLayer.isBlinking = !this.$readOnly && style != "wide"; dom.setCssClass(cursorLayer.element, "ace_slim-cursors", /slim/.test(style)); }; }).call(Editor.prototype); config.defineOptions(Editor.prototype, "editor", { selectionStyle: { set: function(style) { this.onSelectionChange(); this._signal("changeSelectionStyle", {data: style}); }, initialValue: "line" }, highlightActiveLine: { set: function() {this.$updateHighlightActiveLine();}, initialValue: true }, highlightSelectedWord: { set: function(shouldHighlight) {this.$onSelectionChange();}, initialValue: true }, readOnly: { set: function(readOnly) { this.$resetCursorStyle(); }, initialValue: false }, cursorStyle: { set: function(val) { this.$resetCursorStyle(); }, values: ["ace", "slim", "smooth", "wide"], initialValue: "ace" }, mergeUndoDeltas: { values: [false, true, "always"], initialValue: true }, behavioursEnabled: {initialValue: true}, wrapBehavioursEnabled: {initialValue: true}, autoScrollEditorIntoView: { set: function(val) {this.setAutoScrollEditorIntoView(val)} }, hScrollBarAlwaysVisible: "renderer", vScrollBarAlwaysVisible: "renderer", highlightGutterLine: "renderer", animatedScroll: "renderer", showInvisibles: "renderer", showPrintMargin: "renderer", printMarginColumn: "renderer", printMargin: "renderer", fadeFoldWidgets: "renderer", showFoldWidgets: "renderer", showLineNumbers: "renderer", showGutter: "renderer", displayIndentGuides: "renderer", fontSize: "renderer", fontFamily: "renderer", maxLines: "renderer", minLines: "renderer", scrollPastEnd: "renderer", fixedWidthGutter: "renderer", theme: "renderer", scrollSpeed: "$mouseHandler", dragDelay: "$mouseHandler", dragEnabled: "$mouseHandler", focusTimout: "$mouseHandler", tooltipFollowsMouse: "$mouseHandler", firstLineNumber: "session", overwrite: "session", newLineMode: "session", useWorker: "session", useSoftTabs: "session", tabSize: "session", wrap: "session", foldStyle: "session", mode: "session" }); exports.Editor = Editor; }); ace.define("ace/undomanager",["require","exports","module"], function(require, exports, module) { "use strict"; var UndoManager = function() { this.reset(); }; (function() { this.execute = function(options) { var deltas = options.args[0]; this.$doc = options.args[1]; if (options.merge && this.hasUndo()){ this.dirtyCounter--; deltas = this.$undoStack.pop().concat(deltas); } this.$undoStack.push(deltas); this.$redoStack = []; if (this.dirtyCounter < 0) { this.dirtyCounter = NaN; } this.dirtyCounter++; }; this.undo = function(dontSelect) { var deltas = this.$undoStack.pop(); var undoSelectionRange = null; if (deltas) { undoSelectionRange = this.$doc.undoChanges(deltas, dontSelect); this.$redoStack.push(deltas); this.dirtyCounter--; } return undoSelectionRange; }; this.redo = function(dontSelect) { var deltas = this.$redoStack.pop(); var redoSelectionRange = null; if (deltas) { redoSelectionRange = this.$doc.redoChanges(deltas, dontSelect); this.$undoStack.push(deltas); this.dirtyCounter++; } return redoSelectionRange; }; this.reset = function() { this.$undoStack = []; this.$redoStack = []; this.dirtyCounter = 0; }; this.hasUndo = function() { return this.$undoStack.length > 0; }; this.hasRedo = function() { return this.$redoStack.length > 0; }; this.markClean = function() { this.dirtyCounter = 0; }; this.isClean = function() { return this.dirtyCounter === 0; }; }).call(UndoManager.prototype); exports.UndoManager = UndoManager; }); ace.define("ace/layer/gutter",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter"], function(require, exports, module) { "use strict"; var dom = require("../lib/dom"); var oop = require("../lib/oop"); var lang = require("../lib/lang"); var EventEmitter = require("../lib/event_emitter").EventEmitter; var Gutter = function(parentEl) { this.element = dom.createElement("div"); this.element.className = "ace_layer ace_gutter-layer"; parentEl.appendChild(this.element); this.setShowFoldWidgets(this.$showFoldWidgets); this.gutterWidth = 0; this.$annotations = []; this.$updateAnnotations = this.$updateAnnotations.bind(this); this.$cells = []; }; (function() { oop.implement(this, EventEmitter); this.setSession = function(session) { if (this.session) this.session.removeEventListener("change", this.$updateAnnotations); this.session = session; if (session) session.on("change", this.$updateAnnotations); }; this.addGutterDecoration = function(row, className){ if (window.console) console.warn && console.warn("deprecated use session.addGutterDecoration"); this.session.addGutterDecoration(row, className); }; this.removeGutterDecoration = function(row, className){ if (window.console) console.warn && console.warn("deprecated use session.removeGutterDecoration"); this.session.removeGutterDecoration(row, className); }; this.setAnnotations = function(annotations) { this.$annotations = []; for (var i = 0; i < annotations.length; i++) { var annotation = annotations[i]; var row = annotation.row; var rowInfo = this.$annotations[row]; if (!rowInfo) rowInfo = this.$annotations[row] = {text: []}; var annoText = annotation.text; annoText = annoText ? lang.escapeHTML(annoText) : annotation.html || ""; if (rowInfo.text.indexOf(annoText) === -1) rowInfo.text.push(annoText); var type = annotation.type; if (type == "error") rowInfo.className = " ace_error"; else if (type == "warning" && rowInfo.className != " ace_error") rowInfo.className = " ace_warning"; else if (type == "info" && (!rowInfo.className)) rowInfo.className = " ace_info"; } }; this.$updateAnnotations = function (e) { if (!this.$annotations.length) return; var delta = e.data; var range = delta.range; var firstRow = range.start.row; var len = range.end.row - firstRow; if (len === 0) { } else if (delta.action == "removeText" || delta.action == "removeLines") { this.$annotations.splice(firstRow, len + 1, null); } else { var args = new Array(len + 1); args.unshift(firstRow, 1); this.$annotations.splice.apply(this.$annotations, args); } }; this.update = function(config) { var session = this.session; var firstRow = config.firstRow; var lastRow = Math.min(config.lastRow + config.gutterOffset, // needed to compensate for hor scollbar session.getLength() - 1); var fold = session.getNextFoldLine(firstRow); var foldStart = fold ? fold.start.row : Infinity; var foldWidgets = this.$showFoldWidgets && session.foldWidgets; var breakpoints = session.$breakpoints; var decorations = session.$decorations; var firstLineNumber = session.$firstLineNumber; var lastLineNumber = 0; var gutterRenderer = session.gutterRenderer || this.$renderer; var cell = null; var index = -1; var row = firstRow; while (true) { if (row > foldStart) { row = fold.end.row + 1; fold = session.getNextFoldLine(row, fold); foldStart = fold ? fold.start.row : Infinity; } if (row > lastRow) { while (this.$cells.length > index + 1) { cell = this.$cells.pop(); this.element.removeChild(cell.element); } break; } cell = this.$cells[++index]; if (!cell) { cell = {element: null, textNode: null, foldWidget: null}; cell.element = dom.createElement("div"); cell.textNode = document.createTextNode(''); cell.element.appendChild(cell.textNode); this.element.appendChild(cell.element); this.$cells[index] = cell; } var className = "ace_gutter-cell "; if (breakpoints[row]) className += breakpoints[row]; if (decorations[row]) className += decorations[row]; if (this.$annotations[row]) className += this.$annotations[row].className; if (cell.element.className != className) cell.element.className = className; var height = session.getRowLength(row) * config.lineHeight + "px"; if (height != cell.element.style.height) cell.element.style.height = height; if (foldWidgets) { var c = foldWidgets[row]; if (c == null) c = foldWidgets[row] = session.getFoldWidget(row); } if (c) { if (!cell.foldWidget) { cell.foldWidget = dom.createElement("span"); cell.element.appendChild(cell.foldWidget); } var className = "ace_fold-widget ace_" + c; if (c == "start" && row == foldStart && row < fold.end.row) className += " ace_closed"; else className += " ace_open"; if (cell.foldWidget.className != className) cell.foldWidget.className = className; var height = config.lineHeight + "px"; if (cell.foldWidget.style.height != height) cell.foldWidget.style.height = height; } else { if (cell.foldWidget) { cell.element.removeChild(cell.foldWidget); cell.foldWidget = null; } } var text = lastLineNumber = gutterRenderer ? gutterRenderer.getText(session, row) : row + firstLineNumber; if (text != cell.textNode.data) cell.textNode.data = text; row++; } this.element.style.height = config.minHeight + "px"; if (this.$fixedWidth || session.$useWrapMode) lastLineNumber = session.getLength() + firstLineNumber; var gutterWidth = gutterRenderer ? gutterRenderer.getWidth(session, lastLineNumber, config) : lastLineNumber.toString().length * config.characterWidth; var padding = this.$padding || this.$computePadding(); gutterWidth += padding.left + padding.right; if (gutterWidth !== this.gutterWidth && !isNaN(gutterWidth)) { this.gutterWidth = gutterWidth; this.element.style.width = Math.ceil(this.gutterWidth) + "px"; this._emit("changeGutterWidth", gutterWidth); } }; this.$fixedWidth = false; this.$showLineNumbers = true; this.$renderer = ""; this.setShowLineNumbers = function(show) { this.$renderer = !show && { getWidth: function() {return ""}, getText: function() {return ""} }; }; this.getShowLineNumbers = function() { return this.$showLineNumbers; }; this.$showFoldWidgets = true; this.setShowFoldWidgets = function(show) { if (show) dom.addCssClass(this.element, "ace_folding-enabled"); else dom.removeCssClass(this.element, "ace_folding-enabled"); this.$showFoldWidgets = show; this.$padding = null; }; this.getShowFoldWidgets = function() { return this.$showFoldWidgets; }; this.$computePadding = function() { if (!this.element.firstChild) return {left: 0, right: 0}; var style = dom.computedStyle(this.element.firstChild); this.$padding = {}; this.$padding.left = parseInt(style.paddingLeft) + 1 || 0; this.$padding.right = parseInt(style.paddingRight) || 0; return this.$padding; }; this.getRegion = function(point) { var padding = this.$padding || this.$computePadding(); var rect = this.element.getBoundingClientRect(); if (point.x < padding.left + rect.left) return "markers"; if (this.$showFoldWidgets && point.x > rect.right - padding.right) return "foldWidgets"; }; }).call(Gutter.prototype); exports.Gutter = Gutter; }); ace.define("ace/layer/marker",["require","exports","module","ace/range","ace/lib/dom"], function(require, exports, module) { "use strict"; var Range = require("../range").Range; var dom = require("../lib/dom"); var Marker = function(parentEl) { this.element = dom.createElement("div"); this.element.className = "ace_layer ace_marker-layer"; parentEl.appendChild(this.element); }; (function() { this.$padding = 0; this.setPadding = function(padding) { this.$padding = padding; }; this.setSession = function(session) { this.session = session; }; this.setMarkers = function(markers) { this.markers = markers; }; this.update = function(config) { var config = config || this.config; if (!config) return; this.config = config; var html = []; for (var key in this.markers) { var marker = this.markers[key]; if (!marker.range) { marker.update(html, this, this.session, config); continue; } var range = marker.range.clipRows(config.firstRow, config.lastRow); if (range.isEmpty()) continue; range = range.toScreenRange(this.session); if (marker.renderer) { var top = this.$getTop(range.start.row, config); var left = this.$padding + range.start.column * config.characterWidth; marker.renderer(html, range, left, top, config); } else if (marker.type == "fullLine") { this.drawFullLineMarker(html, range, marker.clazz, config); } else if (marker.type == "screenLine") { this.drawScreenLineMarker(html, range, marker.clazz, config); } else if (range.isMultiLine()) { if (marker.type == "text") this.drawTextMarker(html, range, marker.clazz, config); else this.drawMultiLineMarker(html, range, marker.clazz, config); } else { this.drawSingleLineMarker(html, range, marker.clazz + " ace_start", config); } } this.element.innerHTML = html.join(""); }; this.$getTop = function(row, layerConfig) { return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight; }; this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig, extraStyle) { var row = range.start.row; var lineRange = new Range( row, range.start.column, row, this.session.getScreenLastRowColumn(row) ); this.drawSingleLineMarker(stringBuilder, lineRange, clazz + " ace_start", layerConfig, 1, extraStyle); row = range.end.row; lineRange = new Range(row, 0, row, range.end.column); this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 0, extraStyle); for (row = range.start.row + 1; row < range.end.row; row++) { lineRange.start.row = row; lineRange.end.row = row; lineRange.end.column = this.session.getScreenLastRowColumn(row); this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1, extraStyle); } }; this.drawMultiLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { var padding = this.$padding; var height = config.lineHeight; var top = this.$getTop(range.start.row, config); var left = padding + range.start.column * config.characterWidth; extraStyle = extraStyle || ""; stringBuilder.push( "
" ); top = this.$getTop(range.end.row, config); var width = range.end.column * config.characterWidth; stringBuilder.push( "
" ); height = (range.end.row - range.start.row - 1) * config.lineHeight; if (height < 0) return; top = this.$getTop(range.start.row + 1, config); stringBuilder.push( "
" ); }; this.drawSingleLineMarker = function(stringBuilder, range, clazz, config, extraLength, extraStyle) { var height = config.lineHeight; var width = (range.end.column + (extraLength || 0) - range.start.column) * config.characterWidth; var top = this.$getTop(range.start.row, config); var left = this.$padding + range.start.column * config.characterWidth; stringBuilder.push( "
" ); }; this.drawFullLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { var top = this.$getTop(range.start.row, config); var height = config.lineHeight; if (range.start.row != range.end.row) height += this.$getTop(range.end.row, config) - top; stringBuilder.push( "
" ); }; this.drawScreenLineMarker = function(stringBuilder, range, clazz, config, extraStyle) { var top = this.$getTop(range.start.row, config); var height = config.lineHeight; stringBuilder.push( "
" ); }; }).call(Marker.prototype); exports.Marker = Marker; }); ace.define("ace/layer/text",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/lib/event_emitter"], function(require, exports, module) { "use strict"; var oop = require("../lib/oop"); var dom = require("../lib/dom"); var lang = require("../lib/lang"); var useragent = require("../lib/useragent"); var EventEmitter = require("../lib/event_emitter").EventEmitter; var Text = function(parentEl) { this.element = dom.createElement("div"); this.element.className = "ace_layer ace_text-layer"; parentEl.appendChild(this.element); this.$updateEolChar = this.$updateEolChar.bind(this); }; (function() { oop.implement(this, EventEmitter); this.EOF_CHAR = "\xB6"; this.EOL_CHAR_LF = "\xAC"; this.EOL_CHAR_CRLF = "\xa4"; this.EOL_CHAR = this.EOL_CHAR_LF; this.TAB_CHAR = "\u2192"; //"\u21E5"; this.SPACE_CHAR = "\xB7"; this.$padding = 0; this.$updateEolChar = function() { var EOL_CHAR = this.session.doc.getNewLineCharacter() == "\n" ? this.EOL_CHAR_LF : this.EOL_CHAR_CRLF; if (this.EOL_CHAR != EOL_CHAR) { this.EOL_CHAR = EOL_CHAR; return true; } } this.setPadding = function(padding) { this.$padding = padding; this.element.style.padding = "0 " + padding + "px"; }; this.getLineHeight = function() { return this.$fontMetrics.$characterSize.height || 0; }; this.getCharacterWidth = function() { return this.$fontMetrics.$characterSize.width || 0; }; this.$setFontMetrics = function(measure) { this.$fontMetrics = measure; this.$fontMetrics.on("changeCharacterSize", function(e) { this._signal("changeCharacterSize", e); }.bind(this)); this.$pollSizeChanges(); } this.checkForSizeChanges = function() { this.$fontMetrics.checkForSizeChanges(); }; this.$pollSizeChanges = function() { return this.$pollSizeChangesTimer = this.$fontMetrics.$pollSizeChanges(); }; this.setSession = function(session) { this.session = session; if (session) this.$computeTabString(); }; this.showInvisibles = false; this.setShowInvisibles = function(showInvisibles) { if (this.showInvisibles == showInvisibles) return false; this.showInvisibles = showInvisibles; this.$computeTabString(); return true; }; this.displayIndentGuides = true; this.setDisplayIndentGuides = function(display) { if (this.displayIndentGuides == display) return false; this.displayIndentGuides = display; this.$computeTabString(); return true; }; this.$tabStrings = []; this.onChangeTabSize = this.$computeTabString = function() { var tabSize = this.session.getTabSize(); this.tabSize = tabSize; var tabStr = this.$tabStrings = [0]; for (var i = 1; i < tabSize + 1; i++) { if (this.showInvisibles) { tabStr.push("" + this.TAB_CHAR + lang.stringRepeat("\xa0", i - 1) + ""); } else { tabStr.push(lang.stringRepeat("\xa0", i)); } } if (this.displayIndentGuides) { this.$indentGuideRe = /\s\S| \t|\t |\s$/; var className = "ace_indent-guide"; var spaceClass = ""; var tabClass = ""; if (this.showInvisibles) { className += " ace_invisible"; spaceClass = " ace_invisible_space"; tabClass = " ace_invisible_tab"; var spaceContent = lang.stringRepeat(this.SPACE_CHAR, this.tabSize); var tabContent = this.TAB_CHAR + lang.stringRepeat("\xa0", this.tabSize - 1); } else{ var spaceContent = lang.stringRepeat("\xa0", this.tabSize); var tabContent = spaceContent; } this.$tabStrings[" "] = "" + spaceContent + ""; this.$tabStrings["\t"] = "" + tabContent + ""; } }; this.updateLines = function(config, firstRow, lastRow) { if (this.config.lastRow != config.lastRow || this.config.firstRow != config.firstRow) { this.scrollLines(config); } this.config = config; var first = Math.max(firstRow, config.firstRow); var last = Math.min(lastRow, config.lastRow); var lineElements = this.element.childNodes; var lineElementsIdx = 0; for (var row = config.firstRow; row < first; row++) { var foldLine = this.session.getFoldLine(row); if (foldLine) { if (foldLine.containsRow(first)) { first = foldLine.start.row; break; } else { row = foldLine.end.row; } } lineElementsIdx ++; } var row = first; var foldLine = this.session.getNextFoldLine(row); var foldStart = foldLine ? foldLine.start.row : Infinity; while (true) { if (row > foldStart) { row = foldLine.end.row+1; foldLine = this.session.getNextFoldLine(row, foldLine); foldStart = foldLine ? foldLine.start.row :Infinity; } if (row > last) break; var lineElement = lineElements[lineElementsIdx++]; if (lineElement) { var html = []; this.$renderLine( html, row, !this.$useLineGroups(), row == foldStart ? foldLine : false ); lineElement.style.height = config.lineHeight * this.session.getRowLength(row) + "px"; lineElement.innerHTML = html.join(""); } row++; } }; this.scrollLines = function(config) { var oldConfig = this.config; this.config = config; if (!oldConfig || oldConfig.lastRow < config.firstRow) return this.update(config); if (config.lastRow < oldConfig.firstRow) return this.update(config); var el = this.element; if (oldConfig.firstRow < config.firstRow) for (var row=this.session.getFoldedRowCount(oldConfig.firstRow, config.firstRow - 1); row>0; row--) el.removeChild(el.firstChild); if (oldConfig.lastRow > config.lastRow) for (var row=this.session.getFoldedRowCount(config.lastRow + 1, oldConfig.lastRow); row>0; row--) el.removeChild(el.lastChild); if (config.firstRow < oldConfig.firstRow) { var fragment = this.$renderLinesFragment(config, config.firstRow, oldConfig.firstRow - 1); if (el.firstChild) el.insertBefore(fragment, el.firstChild); else el.appendChild(fragment); } if (config.lastRow > oldConfig.lastRow) { var fragment = this.$renderLinesFragment(config, oldConfig.lastRow + 1, config.lastRow); el.appendChild(fragment); } }; this.$renderLinesFragment = function(config, firstRow, lastRow) { var fragment = this.element.ownerDocument.createDocumentFragment(); var row = firstRow; var foldLine = this.session.getNextFoldLine(row); var foldStart = foldLine ? foldLine.start.row : Infinity; while (true) { if (row > foldStart) { row = foldLine.end.row+1; foldLine = this.session.getNextFoldLine(row, foldLine); foldStart = foldLine ? foldLine.start.row : Infinity; } if (row > lastRow) break; var container = dom.createElement("div"); var html = []; this.$renderLine(html, row, false, row == foldStart ? foldLine : false); container.innerHTML = html.join(""); if (this.$useLineGroups()) { container.className = 'ace_line_group'; fragment.appendChild(container); container.style.height = config.lineHeight * this.session.getRowLength(row) + "px"; } else { while(container.firstChild) fragment.appendChild(container.firstChild); } row++; } return fragment; }; this.update = function(config) { this.config = config; var html = []; var firstRow = config.firstRow, lastRow = config.lastRow; var row = firstRow; var foldLine = this.session.getNextFoldLine(row); var foldStart = foldLine ? foldLine.start.row : Infinity; while (true) { if (row > foldStart) { row = foldLine.end.row+1; foldLine = this.session.getNextFoldLine(row, foldLine); foldStart = foldLine ? foldLine.start.row :Infinity; } if (row > lastRow) break; if (this.$useLineGroups()) html.push("
") this.$renderLine(html, row, false, row == foldStart ? foldLine : false); if (this.$useLineGroups()) html.push("
"); // end the line group row++; } this.element.innerHTML = html.join(""); }; this.$textToken = { "text": true, "rparen": true, "lparen": true }; this.$renderToken = function(stringBuilder, screenColumn, token, value) { var self = this; var replaceReg = /\t|&|<|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g; var replaceFunc = function(c, a, b, tabIdx, idx4) { if (a) { return self.showInvisibles ? "" + lang.stringRepeat(self.SPACE_CHAR, c.length) + "" : lang.stringRepeat("\xa0", c.length); } else if (c == "&") { return "&"; } else if (c == "<") { return "<"; } else if (c == "\t") { var tabSize = self.session.getScreenTabSize(screenColumn + tabIdx); screenColumn += tabSize - 1; return self.$tabStrings[tabSize]; } else if (c == "\u3000") { var classToUse = self.showInvisibles ? "ace_cjk ace_invisible ace_invisible_space" : "ace_cjk"; var space = self.showInvisibles ? self.SPACE_CHAR : ""; screenColumn += 1; return "" + space + ""; } else if (b) { return "" + self.SPACE_CHAR + ""; } else { screenColumn += 1; return "" + c + ""; } }; var output = value.replace(replaceReg, replaceFunc); if (!this.$textToken[token.type]) { var classes = "ace_" + token.type.replace(/\./g, " ace_"); var style = ""; if (token.type == "fold") style = " style='width:" + (token.value.length * this.config.characterWidth) + "px;' "; stringBuilder.push("", output, ""); } else { stringBuilder.push(output); } return screenColumn + value.length; }; this.renderIndentGuide = function(stringBuilder, value, max) { var cols = value.search(this.$indentGuideRe); if (cols <= 0 || cols >= max) return value; if (value[0] == " ") { cols -= cols % this.tabSize; stringBuilder.push(lang.stringRepeat(this.$tabStrings[" "], cols/this.tabSize)); return value.substr(cols); } else if (value[0] == "\t") { stringBuilder.push(lang.stringRepeat(this.$tabStrings["\t"], cols)); return value.substr(cols); } return value; }; this.$renderWrappedLine = function(stringBuilder, tokens, splits, onlyContents) { var chars = 0; var split = 0; var splitChars = splits[0]; var screenColumn = 0; for (var i = 0; i < tokens.length; i++) { var token = tokens[i]; var value = token.value; if (i == 0 && this.displayIndentGuides) { chars = value.length; value = this.renderIndentGuide(stringBuilder, value, splitChars); if (!value) continue; chars -= value.length; } if (chars + value.length < splitChars) { screenColumn = this.$renderToken(stringBuilder, screenColumn, token, value); chars += value.length; } else { while (chars + value.length >= splitChars) { screenColumn = this.$renderToken( stringBuilder, screenColumn, token, value.substring(0, splitChars - chars) ); value = value.substring(splitChars - chars); chars = splitChars; if (!onlyContents) { stringBuilder.push("", "
" ); } split ++; screenColumn = 0; splitChars = splits[split] || Number.MAX_VALUE; } if (value.length != 0) { chars += value.length; screenColumn = this.$renderToken( stringBuilder, screenColumn, token, value ); } } } }; this.$renderSimpleLine = function(stringBuilder, tokens) { var screenColumn = 0; var token = tokens[0]; var value = token.value; if (this.displayIndentGuides) value = this.renderIndentGuide(stringBuilder, value); if (value) screenColumn = this.$renderToken(stringBuilder, screenColumn, token, value); for (var i = 1; i < tokens.length; i++) { token = tokens[i]; value = token.value; screenColumn = this.$renderToken(stringBuilder, screenColumn, token, value); } }; this.$renderLine = function(stringBuilder, row, onlyContents, foldLine) { if (!foldLine && foldLine != false) foldLine = this.session.getFoldLine(row); if (foldLine) var tokens = this.$getFoldLineTokens(row, foldLine); else var tokens = this.session.getTokens(row); if (!onlyContents) { stringBuilder.push( "
" ); } if (tokens.length) { var splits = this.session.getRowSplitData(row); if (splits && splits.length) this.$renderWrappedLine(stringBuilder, tokens, splits, onlyContents); else this.$renderSimpleLine(stringBuilder, tokens); } if (this.showInvisibles) { if (foldLine) row = foldLine.end.row stringBuilder.push( "", row == this.session.getLength() - 1 ? this.EOF_CHAR : this.EOL_CHAR, "" ); } if (!onlyContents) stringBuilder.push("
"); }; this.$getFoldLineTokens = function(row, foldLine) { var session = this.session; var renderTokens = []; function addTokens(tokens, from, to) { var idx = 0, col = 0; while ((col + tokens[idx].value.length) < from) { col += tokens[idx].value.length; idx++; if (idx == tokens.length) return; } if (col != from) { var value = tokens[idx].value.substring(from - col); if (value.length > (to - from)) value = value.substring(0, to - from); renderTokens.push({ type: tokens[idx].type, value: value }); col = from + value.length; idx += 1; } while (col < to && idx < tokens.length) { var value = tokens[idx].value; if (value.length + col > to) { renderTokens.push({ type: tokens[idx].type, value: value.substring(0, to - col) }); } else renderTokens.push(tokens[idx]); col += value.length; idx += 1; } } var tokens = session.getTokens(row); foldLine.walk(function(placeholder, row, column, lastColumn, isNewRow) { if (placeholder != null) { renderTokens.push({ type: "fold", value: placeholder }); } else { if (isNewRow) tokens = session.getTokens(row); if (tokens.length) addTokens(tokens, lastColumn, column); } }, foldLine.end.row, this.session.getLine(foldLine.end.row).length); return renderTokens; }; this.$useLineGroups = function() { return this.session.getUseWrapMode(); }; this.destroy = function() { clearInterval(this.$pollSizeChangesTimer); if (this.$measureNode) this.$measureNode.parentNode.removeChild(this.$measureNode); delete this.$measureNode; }; }).call(Text.prototype); exports.Text = Text; }); ace.define("ace/layer/cursor",["require","exports","module","ace/lib/dom"], function(require, exports, module) { "use strict"; var dom = require("../lib/dom"); var IE8; var Cursor = function(parentEl) { this.element = dom.createElement("div"); this.element.className = "ace_layer ace_cursor-layer"; parentEl.appendChild(this.element); if (IE8 === undefined) IE8 = "opacity" in this.element; this.isVisible = false; this.isBlinking = true; this.blinkInterval = 1000; this.smoothBlinking = false; this.cursors = []; this.cursor = this.addCursor(); dom.addCssClass(this.element, "ace_hidden-cursors"); this.$updateCursors = this.$updateVisibility.bind(this); }; (function() { this.$updateVisibility = function(val) { var cursors = this.cursors; for (var i = cursors.length; i--; ) cursors[i].style.visibility = val ? "" : "hidden"; }; this.$updateOpacity = function(val) { var cursors = this.cursors; for (var i = cursors.length; i--; ) cursors[i].style.opacity = val ? "" : "0"; }; this.$padding = 0; this.setPadding = function(padding) { this.$padding = padding; }; this.setSession = function(session) { this.session = session; }; this.setBlinking = function(blinking) { if (blinking != this.isBlinking){ this.isBlinking = blinking; this.restartTimer(); } }; this.setBlinkInterval = function(blinkInterval) { if (blinkInterval != this.blinkInterval){ this.blinkInterval = blinkInterval; this.restartTimer(); } }; this.setSmoothBlinking = function(smoothBlinking) { if (smoothBlinking != this.smoothBlinking && !IE8) { this.smoothBlinking = smoothBlinking; dom.setCssClass(this.element, "ace_smooth-blinking", smoothBlinking); this.$updateCursors(true); this.$updateCursors = (smoothBlinking ? this.$updateOpacity : this.$updateVisibility).bind(this); this.restartTimer(); } }; this.addCursor = function() { var el = dom.createElement("div"); el.className = "ace_cursor"; this.element.appendChild(el); this.cursors.push(el); return el; }; this.removeCursor = function() { if (this.cursors.length > 1) { var el = this.cursors.pop(); el.parentNode.removeChild(el); return el; } }; this.hideCursor = function() { this.isVisible = false; dom.addCssClass(this.element, "ace_hidden-cursors"); this.restartTimer(); }; this.showCursor = function() { this.isVisible = true; dom.removeCssClass(this.element, "ace_hidden-cursors"); this.restartTimer(); }; this.restartTimer = function() { var update = this.$updateCursors; clearInterval(this.intervalId); clearTimeout(this.timeoutId); if (this.smoothBlinking) { dom.removeCssClass(this.element, "ace_smooth-blinking"); } update(true); if (!this.isBlinking || !this.blinkInterval || !this.isVisible) return; if (this.smoothBlinking) { setTimeout(function(){ dom.addCssClass(this.element, "ace_smooth-blinking"); }.bind(this)); } var blink = function(){ this.timeoutId = setTimeout(function() { update(false); }, 0.6 * this.blinkInterval); }.bind(this); this.intervalId = setInterval(function() { update(true); blink(); }, this.blinkInterval); blink(); }; this.getPixelPosition = function(position, onScreen) { if (!this.config || !this.session) return {left : 0, top : 0}; if (!position) position = this.session.selection.getCursor(); var pos = this.session.documentToScreenPosition(position); var cursorLeft = this.$padding + pos.column * this.config.characterWidth; var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) * this.config.lineHeight; return {left : cursorLeft, top : cursorTop}; }; this.update = function(config) { this.config = config; var selections = this.session.$selectionMarkers; var i = 0, cursorIndex = 0; if (selections === undefined || selections.length === 0){ selections = [{cursor: null}]; } for (var i = 0, n = selections.length; i < n; i++) { var pixelPos = this.getPixelPosition(selections[i].cursor, true); if ((pixelPos.top > config.height + config.offset || pixelPos.top < 0) && i > 1) { continue; } var style = (this.cursors[cursorIndex++] || this.addCursor()).style; style.left = pixelPos.left + "px"; style.top = pixelPos.top + "px"; style.width = config.characterWidth + "px"; style.height = config.lineHeight + "px"; } while (this.cursors.length > cursorIndex) this.removeCursor(); var overwrite = this.session.getOverwrite(); this.$setOverwrite(overwrite); this.$pixelPos = pixelPos; this.restartTimer(); }; this.$setOverwrite = function(overwrite) { if (overwrite != this.overwrite) { this.overwrite = overwrite; if (overwrite) dom.addCssClass(this.element, "ace_overwrite-cursors"); else dom.removeCssClass(this.element, "ace_overwrite-cursors"); } }; this.destroy = function() { clearInterval(this.intervalId); clearTimeout(this.timeoutId); }; }).call(Cursor.prototype); exports.Cursor = Cursor; }); ace.define("ace/scrollbar",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/event","ace/lib/event_emitter"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var dom = require("./lib/dom"); var event = require("./lib/event"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var ScrollBar = function(parent) { this.element = dom.createElement("div"); this.element.className = "ace_scrollbar ace_scrollbar" + this.classSuffix; this.inner = dom.createElement("div"); this.inner.className = "ace_scrollbar-inner"; this.element.appendChild(this.inner); parent.appendChild(this.element); this.setVisible(false); this.skipEvent = false; event.addListener(this.element, "scroll", this.onScroll.bind(this)); event.addListener(this.element, "mousedown", event.preventDefault); }; (function() { oop.implement(this, EventEmitter); this.setVisible = function(isVisible) { this.element.style.display = isVisible ? "" : "none"; this.isVisible = isVisible; }; }).call(ScrollBar.prototype); var VScrollBar = function(parent, renderer) { ScrollBar.call(this, parent); this.scrollTop = 0; renderer.$scrollbarWidth = this.width = dom.scrollbarWidth(parent.ownerDocument); this.inner.style.width = this.element.style.width = (this.width || 15) + 5 + "px"; }; oop.inherits(VScrollBar, ScrollBar); (function() { this.classSuffix = '-v'; this.onScroll = function() { if (!this.skipEvent) { this.scrollTop = this.element.scrollTop; this._emit("scroll", {data: this.scrollTop}); } this.skipEvent = false; }; this.getWidth = function() { return this.isVisible ? this.width : 0; }; this.setHeight = function(height) { this.element.style.height = height + "px"; }; this.setInnerHeight = function(height) { this.inner.style.height = height + "px"; }; this.setScrollHeight = function(height) { this.inner.style.height = height + "px"; }; this.setScrollTop = function(scrollTop) { if (this.scrollTop != scrollTop) { this.skipEvent = true; this.scrollTop = this.element.scrollTop = scrollTop; } }; }).call(VScrollBar.prototype); var HScrollBar = function(parent, renderer) { ScrollBar.call(this, parent); this.scrollLeft = 0; this.height = renderer.$scrollbarWidth; this.inner.style.height = this.element.style.height = (this.height || 15) + 5 + "px"; }; oop.inherits(HScrollBar, ScrollBar); (function() { this.classSuffix = '-h'; this.onScroll = function() { if (!this.skipEvent) { this.scrollLeft = this.element.scrollLeft; this._emit("scroll", {data: this.scrollLeft}); } this.skipEvent = false; }; this.getHeight = function() { return this.isVisible ? this.height : 0; }; this.setWidth = function(width) { this.element.style.width = width + "px"; }; this.setInnerWidth = function(width) { this.inner.style.width = width + "px"; }; this.setScrollWidth = function(width) { this.inner.style.width = width + "px"; }; this.setScrollLeft = function(scrollLeft) { if (this.scrollLeft != scrollLeft) { this.skipEvent = true; this.scrollLeft = this.element.scrollLeft = scrollLeft; } }; }).call(HScrollBar.prototype); exports.ScrollBar = VScrollBar; // backward compatibility exports.ScrollBarV = VScrollBar; // backward compatibility exports.ScrollBarH = HScrollBar; // backward compatibility exports.VScrollBar = VScrollBar; exports.HScrollBar = HScrollBar; }); ace.define("ace/renderloop",["require","exports","module","ace/lib/event"], function(require, exports, module) { "use strict"; var event = require("./lib/event"); var RenderLoop = function(onRender, win) { this.onRender = onRender; this.pending = false; this.changes = 0; this.window = win || window; }; (function() { this.schedule = function(change) { this.changes = this.changes | change; if (!this.pending && this.changes) { this.pending = true; var _self = this; event.nextFrame(function() { _self.pending = false; var changes; while (changes = _self.changes) { _self.changes = 0; _self.onRender(changes); } }, this.window); } }; }).call(RenderLoop.prototype); exports.RenderLoop = RenderLoop; }); ace.define("ace/layer/font_metrics",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/lib/event_emitter"], function(require, exports, module) { var oop = require("../lib/oop"); var dom = require("../lib/dom"); var lang = require("../lib/lang"); var useragent = require("../lib/useragent"); var EventEmitter = require("../lib/event_emitter").EventEmitter; var CHAR_COUNT = 0; var FontMetrics = exports.FontMetrics = function(parentEl, interval) { this.el = dom.createElement("div"); this.$setMeasureNodeStyles(this.el.style, true); this.$main = dom.createElement("div"); this.$setMeasureNodeStyles(this.$main.style); this.$measureNode = dom.createElement("div"); this.$setMeasureNodeStyles(this.$measureNode.style); this.el.appendChild(this.$main); this.el.appendChild(this.$measureNode); parentEl.appendChild(this.el); if (!CHAR_COUNT) this.$testFractionalRect(); this.$measureNode.innerHTML = lang.stringRepeat("X", CHAR_COUNT); this.$characterSize = {width: 0, height: 0}; this.checkForSizeChanges(); }; (function() { oop.implement(this, EventEmitter); this.$characterSize = {width: 0, height: 0}; this.$testFractionalRect = function() { var el = dom.createElement("div"); this.$setMeasureNodeStyles(el.style); el.style.width = "0.2px"; document.documentElement.appendChild(el); var w = el.getBoundingClientRect().width; if (w > 0 && w < 1) CHAR_COUNT = 50; else CHAR_COUNT = 100; el.parentNode.removeChild(el); }; this.$setMeasureNodeStyles = function(style, isRoot) { style.width = style.height = "auto"; style.left = style.top = "-100px"; style.visibility = "hidden"; style.position = "fixed"; style.whiteSpace = "pre"; if (useragent.isIE < 8) { style["font-family"] = "inherit"; } else { style.font = "inherit"; } style.overflow = isRoot ? "hidden" : "visible"; }; this.checkForSizeChanges = function() { var size = this.$measureSizes(); if (size && (this.$characterSize.width !== size.width || this.$characterSize.height !== size.height)) { this.$measureNode.style.fontWeight = "bold"; var boldSize = this.$measureSizes(); this.$measureNode.style.fontWeight = ""; this.$characterSize = size; this.charSizes = Object.create(null); this.allowBoldFonts = boldSize && boldSize.width === size.width && boldSize.height === size.height; this._emit("changeCharacterSize", {data: size}); } }; this.$pollSizeChanges = function() { if (this.$pollSizeChangesTimer) return this.$pollSizeChangesTimer; var self = this; return this.$pollSizeChangesTimer = setInterval(function() { self.checkForSizeChanges(); }, 500); }; this.setPolling = function(val) { if (val) { this.$pollSizeChanges(); } else { if (this.$pollSizeChangesTimer) this.$pollSizeChangesTimer; } }; this.$measureSizes = function() { if (CHAR_COUNT === 50) { var rect = null; try { rect = this.$measureNode.getBoundingClientRect(); } catch(e) { rect = {width: 0, height:0 }; }; var size = { height: rect.height, width: rect.width / CHAR_COUNT }; } else { var size = { height: this.$measureNode.clientHeight, width: this.$measureNode.clientWidth / CHAR_COUNT }; } if (size.width === 0 || size.height === 0) return null; return size; }; this.$measureCharWidth = function(ch) { this.$main.innerHTML = lang.stringRepeat(ch, CHAR_COUNT); var rect = this.$main.getBoundingClientRect(); return rect.width / CHAR_COUNT; }; this.getCharacterWidth = function(ch) { var w = this.charSizes[ch]; if (w === undefined) { this.charSizes[ch] = this.$measureCharWidth(ch) / this.$characterSize.width; } return w; }; this.destroy = function() { clearInterval(this.$pollSizeChangesTimer); if (this.el && this.el.parentNode) this.el.parentNode.removeChild(this.el); }; }).call(FontMetrics.prototype); }); ace.define("ace/virtual_renderer",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/config","ace/lib/useragent","ace/layer/gutter","ace/layer/marker","ace/layer/text","ace/layer/cursor","ace/scrollbar","ace/scrollbar","ace/renderloop","ace/layer/font_metrics","ace/lib/event_emitter"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var dom = require("./lib/dom"); var config = require("./config"); var useragent = require("./lib/useragent"); var GutterLayer = require("./layer/gutter").Gutter; var MarkerLayer = require("./layer/marker").Marker; var TextLayer = require("./layer/text").Text; var CursorLayer = require("./layer/cursor").Cursor; var HScrollBar = require("./scrollbar").HScrollBar; var VScrollBar = require("./scrollbar").VScrollBar; var RenderLoop = require("./renderloop").RenderLoop; var FontMetrics = require("./layer/font_metrics").FontMetrics; var EventEmitter = require("./lib/event_emitter").EventEmitter; var editorCss = ".ace_editor {\ position: relative;\ overflow: hidden;\ font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;\ direction: ltr;\ }\ .ace_scroller {\ position: absolute;\ overflow: hidden;\ top: 0;\ bottom: 0;\ background-color: inherit;\ -ms-user-select: none;\ -moz-user-select: none;\ -webkit-user-select: none;\ user-select: none;\ cursor: text;\ }\ .ace_content {\ position: absolute;\ -moz-box-sizing: border-box;\ -webkit-box-sizing: border-box;\ box-sizing: border-box;\ min-width: 100%;\ }\ .ace_dragging .ace_scroller:before{\ position: absolute;\ top: 0;\ left: 0;\ right: 0;\ bottom: 0;\ content: '';\ background: rgba(250, 250, 250, 0.01);\ z-index: 1000;\ }\ .ace_dragging.ace_dark .ace_scroller:before{\ background: rgba(0, 0, 0, 0.01);\ }\ .ace_selecting, .ace_selecting * {\ cursor: text !important;\ }\ .ace_gutter {\ position: absolute;\ overflow : hidden;\ width: auto;\ top: 0;\ bottom: 0;\ left: 0;\ cursor: default;\ z-index: 4;\ -ms-user-select: none;\ -moz-user-select: none;\ -webkit-user-select: none;\ user-select: none;\ }\ .ace_gutter-active-line {\ position: absolute;\ left: 0;\ right: 0;\ }\ .ace_scroller.ace_scroll-left {\ box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;\ }\ .ace_gutter-cell {\ padding-left: 19px;\ padding-right: 6px;\ background-repeat: no-repeat;\ }\ .ace_gutter-cell.ace_error {\ background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==\");\ background-repeat: no-repeat;\ background-position: 2px center;\ }\ .ace_gutter-cell.ace_warning {\ background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==\");\ background-position: 2px center;\ }\ .ace_gutter-cell.ace_info {\ background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=\");\ background-position: 2px center;\ }\ .ace_dark .ace_gutter-cell.ace_info {\ background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC\");\ }\ .ace_scrollbar {\ position: absolute;\ right: 0;\ bottom: 0;\ z-index: 6;\ }\ .ace_scrollbar-inner {\ position: absolute;\ cursor: text;\ left: 0;\ top: 0;\ }\ .ace_scrollbar-v{\ overflow-x: hidden;\ overflow-y: scroll;\ top: 0;\ }\ .ace_scrollbar-h {\ overflow-x: scroll;\ overflow-y: hidden;\ left: 0;\ }\ .ace_print-margin {\ position: absolute;\ height: 100%;\ }\ .ace_text-input {\ position: absolute;\ z-index: 0;\ width: 0.5em;\ height: 1em;\ opacity: 0;\ background: transparent;\ -moz-appearance: none;\ appearance: none;\ border: none;\ resize: none;\ outline: none;\ overflow: hidden;\ font: inherit;\ padding: 0 1px;\ margin: 0 -1px;\ text-indent: -1em;\ -ms-user-select: text;\ -moz-user-select: text;\ -webkit-user-select: text;\ user-select: text;\ }\ .ace_text-input.ace_composition {\ background: inherit;\ color: inherit;\ z-index: 1000;\ opacity: 1;\ text-indent: 0;\ }\ .ace_layer {\ z-index: 1;\ position: absolute;\ overflow: hidden;\ white-space: pre;\ height: 100%;\ width: 100%;\ -moz-box-sizing: border-box;\ -webkit-box-sizing: border-box;\ box-sizing: border-box;\ pointer-events: none;\ }\ .ace_gutter-layer {\ position: relative;\ width: auto;\ text-align: right;\ pointer-events: auto;\ }\ .ace_text-layer {\ font: inherit !important;\ }\ .ace_cjk {\ display: inline-block;\ text-align: center;\ }\ .ace_cursor-layer {\ z-index: 4;\ }\ .ace_cursor {\ z-index: 4;\ position: absolute;\ -moz-box-sizing: border-box;\ -webkit-box-sizing: border-box;\ box-sizing: border-box;\ border-left: 2px solid\ }\ .ace_slim-cursors .ace_cursor {\ border-left-width: 1px;\ }\ .ace_overwrite-cursors .ace_cursor {\ border-left-width: 0;\ border-bottom: 1px solid;\ }\ .ace_hidden-cursors .ace_cursor {\ opacity: 0.2;\ }\ .ace_smooth-blinking .ace_cursor {\ -webkit-transition: opacity 0.18s;\ transition: opacity 0.18s;\ }\ .ace_editor.ace_multiselect .ace_cursor {\ border-left-width: 1px;\ }\ .ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {\ position: absolute;\ z-index: 3;\ }\ .ace_marker-layer .ace_selection {\ position: absolute;\ z-index: 5;\ }\ .ace_marker-layer .ace_bracket {\ position: absolute;\ z-index: 6;\ }\ .ace_marker-layer .ace_active-line {\ position: absolute;\ z-index: 2;\ }\ .ace_marker-layer .ace_selected-word {\ position: absolute;\ z-index: 4;\ -moz-box-sizing: border-box;\ -webkit-box-sizing: border-box;\ box-sizing: border-box;\ }\ .ace_line .ace_fold {\ -moz-box-sizing: border-box;\ -webkit-box-sizing: border-box;\ box-sizing: border-box;\ display: inline-block;\ height: 11px;\ margin-top: -2px;\ vertical-align: middle;\ background-image:\ url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII=\"),\ url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=\");\ background-repeat: no-repeat, repeat-x;\ background-position: center center, top left;\ color: transparent;\ border: 1px solid black;\ border-radius: 2px;\ cursor: pointer;\ pointer-events: auto;\ }\ .ace_dark .ace_fold {\ }\ .ace_fold:hover{\ background-image:\ url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII=\"),\ url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC\");\ }\ .ace_tooltip {\ background-color: #FFF;\ background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.1));\ background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));\ border: 1px solid gray;\ border-radius: 1px;\ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);\ color: black;\ max-width: 100%;\ padding: 3px 4px;\ position: fixed;\ z-index: 999999;\ -moz-box-sizing: border-box;\ -webkit-box-sizing: border-box;\ box-sizing: border-box;\ cursor: default;\ white-space: pre;\ word-wrap: break-word;\ line-height: normal;\ font-style: normal;\ font-weight: normal;\ letter-spacing: normal;\ pointer-events: none;\ }\ .ace_folding-enabled > .ace_gutter-cell {\ padding-right: 13px;\ }\ .ace_fold-widget {\ -moz-box-sizing: border-box;\ -webkit-box-sizing: border-box;\ box-sizing: border-box;\ margin: 0 -12px 0 1px;\ display: none;\ width: 11px;\ vertical-align: top;\ background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==\");\ background-repeat: no-repeat;\ background-position: center;\ border-radius: 3px;\ border: 1px solid transparent;\ cursor: pointer;\ }\ .ace_folding-enabled .ace_fold-widget {\ display: inline-block; \ }\ .ace_fold-widget.ace_end {\ background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==\");\ }\ .ace_fold-widget.ace_closed {\ background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==\");\ }\ .ace_fold-widget:hover {\ border: 1px solid rgba(0, 0, 0, 0.3);\ background-color: rgba(255, 255, 255, 0.2);\ box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);\ }\ .ace_fold-widget:active {\ border: 1px solid rgba(0, 0, 0, 0.4);\ background-color: rgba(0, 0, 0, 0.05);\ box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);\ }\ .ace_dark .ace_fold-widget {\ background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC\");\ }\ .ace_dark .ace_fold-widget.ace_end {\ background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==\");\ }\ .ace_dark .ace_fold-widget.ace_closed {\ background-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==\");\ }\ .ace_dark .ace_fold-widget:hover {\ box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);\ background-color: rgba(255, 255, 255, 0.1);\ }\ .ace_dark .ace_fold-widget:active {\ box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);\ }\ .ace_fold-widget.ace_invalid {\ background-color: #FFB4B4;\ border-color: #DE5555;\ }\ .ace_fade-fold-widgets .ace_fold-widget {\ -webkit-transition: opacity 0.4s ease 0.05s;\ transition: opacity 0.4s ease 0.05s;\ opacity: 0;\ }\ .ace_fade-fold-widgets:hover .ace_fold-widget {\ -webkit-transition: opacity 0.05s ease 0.05s;\ transition: opacity 0.05s ease 0.05s;\ opacity:1;\ }\ .ace_underline {\ text-decoration: underline;\ }\ .ace_bold {\ font-weight: bold;\ }\ .ace_nobold .ace_bold {\ font-weight: normal;\ }\ .ace_italic {\ font-style: italic;\ }\ .ace_error-marker {\ background-color: rgba(255, 0, 0,0.2);\ position: absolute;\ z-index: 9;\ }\ .ace_highlight-marker {\ background-color: rgba(255, 255, 0,0.2);\ position: absolute;\ z-index: 8;\ }\ "; dom.importCssString(editorCss, "ace_editor"); var VirtualRenderer = function(container, theme) { var _self = this; this.container = container || dom.createElement("div"); this.$keepTextAreaAtCursor = !useragent.isOldIE; dom.addCssClass(this.container, "ace_editor"); this.setTheme(theme); this.$gutter = dom.createElement("div"); this.$gutter.className = "ace_gutter"; this.container.appendChild(this.$gutter); this.scroller = dom.createElement("div"); this.scroller.className = "ace_scroller"; this.container.appendChild(this.scroller); this.content = dom.createElement("div"); this.content.className = "ace_content"; this.scroller.appendChild(this.content); this.$gutterLayer = new GutterLayer(this.$gutter); this.$gutterLayer.on("changeGutterWidth", this.onGutterResize.bind(this)); this.$markerBack = new MarkerLayer(this.content); var textLayer = this.$textLayer = new TextLayer(this.content); this.canvas = textLayer.element; this.$markerFront = new MarkerLayer(this.content); this.$cursorLayer = new CursorLayer(this.content); this.$horizScroll = false; this.$vScroll = false; this.scrollBar = this.scrollBarV = new VScrollBar(this.container, this); this.scrollBarH = new HScrollBar(this.container, this); this.scrollBarV.addEventListener("scroll", function(e) { if (!_self.$scrollAnimation) _self.session.setScrollTop(e.data - _self.scrollMargin.top); }); this.scrollBarH.addEventListener("scroll", function(e) { if (!_self.$scrollAnimation) _self.session.setScrollLeft(e.data - _self.scrollMargin.left); }); this.scrollTop = 0; this.scrollLeft = 0; this.cursorPos = { row : 0, column : 0 }; this.$fontMetrics = new FontMetrics(this.container, 500); this.$textLayer.$setFontMetrics(this.$fontMetrics); this.$textLayer.addEventListener("changeCharacterSize", function(e) { _self.updateCharacterSize(); _self.onResize(true, _self.gutterWidth, _self.$size.width, _self.$size.height); _self._signal("changeCharacterSize", e); }); this.$size = { width: 0, height: 0, scrollerHeight: 0, scrollerWidth: 0, $dirty: true }; this.layerConfig = { width : 1, padding : 0, firstRow : 0, firstRowScreen: 0, lastRow : 0, lineHeight : 0, characterWidth : 0, minHeight : 1, maxHeight : 1, offset : 0, height : 1, gutterOffset: 1 }; this.scrollMargin = { left: 0, right: 0, top: 0, bottom: 0, v: 0, h: 0 }; this.$loop = new RenderLoop( this.$renderChanges.bind(this), this.container.ownerDocument.defaultView ); this.$loop.schedule(this.CHANGE_FULL); this.updateCharacterSize(); this.setPadding(4); config.resetOptions(this); config._emit("renderer", this); }; (function() { this.CHANGE_CURSOR = 1; this.CHANGE_MARKER = 2; this.CHANGE_GUTTER = 4; this.CHANGE_SCROLL = 8; this.CHANGE_LINES = 16; this.CHANGE_TEXT = 32; this.CHANGE_SIZE = 64; this.CHANGE_MARKER_BACK = 128; this.CHANGE_MARKER_FRONT = 256; this.CHANGE_FULL = 512; this.CHANGE_H_SCROLL = 1024; oop.implement(this, EventEmitter); this.updateCharacterSize = function() { if (this.$textLayer.allowBoldFonts != this.$allowBoldFonts) { this.$allowBoldFonts = this.$textLayer.allowBoldFonts; this.setStyle("ace_nobold", !this.$allowBoldFonts); } this.layerConfig.characterWidth = this.characterWidth = this.$textLayer.getCharacterWidth(); this.layerConfig.lineHeight = this.lineHeight = this.$textLayer.getLineHeight(); this.$updatePrintMargin(); }; this.setSession = function(session) { if (this.session) this.session.doc.off("changeNewLineMode", this.onChangeNewLineMode); this.session = session; if (session && this.scrollMargin.top && session.getScrollTop() <= 0) session.setScrollTop(-this.scrollMargin.top); this.$cursorLayer.setSession(session); this.$markerBack.setSession(session); this.$markerFront.setSession(session); this.$gutterLayer.setSession(session); this.$textLayer.setSession(session); if (!session) return; this.$loop.schedule(this.CHANGE_FULL); this.session.$setFontMetrics(this.$fontMetrics); this.onChangeNewLineMode = this.onChangeNewLineMode.bind(this); this.onChangeNewLineMode() this.session.doc.on("changeNewLineMode", this.onChangeNewLineMode); }; this.updateLines = function(firstRow, lastRow, force) { if (lastRow === undefined) lastRow = Infinity; if (!this.$changedLines) { this.$changedLines = { firstRow: firstRow, lastRow: lastRow }; } else { if (this.$changedLines.firstRow > firstRow) this.$changedLines.firstRow = firstRow; if (this.$changedLines.lastRow < lastRow) this.$changedLines.lastRow = lastRow; } if (this.$changedLines.lastRow < this.layerConfig.firstRow) { if (force) this.$changedLines.lastRow = this.layerConfig.lastRow; else return; } if (this.$changedLines.firstRow > this.layerConfig.lastRow) return; this.$loop.schedule(this.CHANGE_LINES); }; this.onChangeNewLineMode = function() { this.$loop.schedule(this.CHANGE_TEXT); this.$textLayer.$updateEolChar(); }; this.onChangeTabSize = function() { this.$loop.schedule(this.CHANGE_TEXT | this.CHANGE_MARKER); this.$textLayer.onChangeTabSize(); }; this.updateText = function() { this.$loop.schedule(this.CHANGE_TEXT); }; this.updateFull = function(force) { if (force) this.$renderChanges(this.CHANGE_FULL, true); else this.$loop.schedule(this.CHANGE_FULL); }; this.updateFontSize = function() { this.$textLayer.checkForSizeChanges(); }; this.$changes = 0; this.$updateSizeAsync = function() { if (this.$loop.pending) this.$size.$dirty = true; else this.onResize(); }; this.onResize = function(force, gutterWidth, width, height) { if (this.resizing > 2) return; else if (this.resizing > 0) this.resizing++; else this.resizing = force ? 1 : 0; var el = this.container; if (!height) height = el.clientHeight || el.scrollHeight; if (!width) width = el.clientWidth || el.scrollWidth; var changes = this.$updateCachedSize(force, gutterWidth, width, height); if (!this.$size.scrollerHeight || (!width && !height)) return this.resizing = 0; if (force) this.$gutterLayer.$padding = null; if (force) this.$renderChanges(changes | this.$changes, true); else this.$loop.schedule(changes | this.$changes); if (this.resizing) this.resizing = 0; }; this.$updateCachedSize = function(force, gutterWidth, width, height) { height -= (this.$extraHeight || 0); var changes = 0; var size = this.$size; var oldSize = { width: size.width, height: size.height, scrollerHeight: size.scrollerHeight, scrollerWidth: size.scrollerWidth }; if (height && (force || size.height != height)) { size.height = height; changes |= this.CHANGE_SIZE; size.scrollerHeight = size.height; if (this.$horizScroll) size.scrollerHeight -= this.scrollBarH.getHeight(); this.scrollBarV.element.style.bottom = this.scrollBarH.getHeight() + "px"; changes = changes | this.CHANGE_SCROLL; } if (width && (force || size.width != width)) { changes |= this.CHANGE_SIZE; size.width = width; if (gutterWidth == null) gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; this.gutterWidth = gutterWidth; this.scrollBarH.element.style.left = this.scroller.style.left = gutterWidth + "px"; size.scrollerWidth = Math.max(0, width - gutterWidth - this.scrollBarV.getWidth()); this.scrollBarH.element.style.right = this.scroller.style.right = this.scrollBarV.getWidth() + "px"; this.scroller.style.bottom = this.scrollBarH.getHeight() + "px"; if (this.session && this.session.getUseWrapMode() && this.adjustWrapLimit() || force) changes |= this.CHANGE_FULL; } size.$dirty = !width || !height; if (changes) this._signal("resize", oldSize); return changes; }; this.onGutterResize = function() { var gutterWidth = this.$showGutter ? this.$gutter.offsetWidth : 0; if (gutterWidth != this.gutterWidth) this.$changes |= this.$updateCachedSize(true, gutterWidth, this.$size.width, this.$size.height); if (this.session.getUseWrapMode() && this.adjustWrapLimit()) { this.$loop.schedule(this.CHANGE_FULL); } else if (this.$size.$dirty) { this.$loop.schedule(this.CHANGE_FULL); } else { this.$computeLayerConfig(); this.$loop.schedule(this.CHANGE_MARKER); } }; this.adjustWrapLimit = function() { var availableWidth = this.$size.scrollerWidth - this.$padding * 2; var limit = Math.floor(availableWidth / this.characterWidth); return this.session.adjustWrapLimit(limit, this.$showPrintMargin && this.$printMarginColumn); }; this.setAnimatedScroll = function(shouldAnimate){ this.setOption("animatedScroll", shouldAnimate); }; this.getAnimatedScroll = function() { return this.$animatedScroll; }; this.setShowInvisibles = function(showInvisibles) { this.setOption("showInvisibles", showInvisibles); }; this.getShowInvisibles = function() { return this.getOption("showInvisibles"); }; this.getDisplayIndentGuides = function() { return this.getOption("displayIndentGuides"); }; this.setDisplayIndentGuides = function(display) { this.setOption("displayIndentGuides", display); }; this.setShowPrintMargin = function(showPrintMargin) { this.setOption("showPrintMargin", showPrintMargin); }; this.getShowPrintMargin = function() { return this.getOption("showPrintMargin"); }; this.setPrintMarginColumn = function(showPrintMargin) { this.setOption("printMarginColumn", showPrintMargin); }; this.getPrintMarginColumn = function() { return this.getOption("printMarginColumn"); }; this.getShowGutter = function(){ return this.getOption("showGutter"); }; this.setShowGutter = function(show){ return this.setOption("showGutter", show); }; this.getFadeFoldWidgets = function(){ return this.getOption("fadeFoldWidgets") }; this.setFadeFoldWidgets = function(show) { this.setOption("fadeFoldWidgets", show); }; this.setHighlightGutterLine = function(shouldHighlight) { this.setOption("highlightGutterLine", shouldHighlight); }; this.getHighlightGutterLine = function() { return this.getOption("highlightGutterLine"); }; this.$updateGutterLineHighlight = function() { var pos = this.$cursorLayer.$pixelPos; var height = this.layerConfig.lineHeight; if (this.session.getUseWrapMode()) { var cursor = this.session.selection.getCursor(); cursor.column = 0; pos = this.$cursorLayer.getPixelPosition(cursor, true); height *= this.session.getRowLength(cursor.row); } this.$gutterLineHighlight.style.top = pos.top - this.layerConfig.offset + "px"; this.$gutterLineHighlight.style.height = height + "px"; }; this.$updatePrintMargin = function() { if (!this.$showPrintMargin && !this.$printMarginEl) return; if (!this.$printMarginEl) { var containerEl = dom.createElement("div"); containerEl.className = "ace_layer ace_print-margin-layer"; this.$printMarginEl = dom.createElement("div"); this.$printMarginEl.className = "ace_print-margin"; containerEl.appendChild(this.$printMarginEl); this.content.insertBefore(containerEl, this.content.firstChild); } var style = this.$printMarginEl.style; style.left = ((this.characterWidth * this.$printMarginColumn) + this.$padding) + "px"; style.visibility = this.$showPrintMargin ? "visible" : "hidden"; if (this.session && this.session.$wrap == -1) this.adjustWrapLimit(); }; this.getContainerElement = function() { return this.container; }; this.getMouseEventTarget = function() { return this.content; }; this.getTextAreaContainer = function() { return this.container; }; this.$moveTextAreaToCursor = function() { if (!this.$keepTextAreaAtCursor) return; var config = this.layerConfig; var posTop = this.$cursorLayer.$pixelPos.top; var posLeft = this.$cursorLayer.$pixelPos.left; posTop -= config.offset; var h = this.lineHeight; if (posTop < 0 || posTop > config.height - h) return; var w = this.characterWidth; if (this.$composition) { var val = this.textarea.value.replace(/^\x01+/, ""); w *= (this.session.$getStringScreenWidth(val)[0]+2); h += 2; } posLeft -= this.scrollLeft; if (posLeft > this.$size.scrollerWidth - w) posLeft = this.$size.scrollerWidth - w; posLeft += this.gutterWidth; this.textarea.style.height = h + "px"; this.textarea.style.width = w + "px"; this.textarea.style.left = Math.min(posLeft, this.$size.scrollerWidth - w) + "px"; this.textarea.style.top = Math.min(posTop, this.$size.height - h) + "px"; }; this.getFirstVisibleRow = function() { return this.layerConfig.firstRow; }; this.getFirstFullyVisibleRow = function() { return this.layerConfig.firstRow + (this.layerConfig.offset === 0 ? 0 : 1); }; this.getLastFullyVisibleRow = function() { var flint = Math.floor((this.layerConfig.height + this.layerConfig.offset) / this.layerConfig.lineHeight); return this.layerConfig.firstRow - 1 + flint; }; this.getLastVisibleRow = function() { return this.layerConfig.lastRow; }; this.$padding = null; this.setPadding = function(padding) { this.$padding = padding; this.$textLayer.setPadding(padding); this.$cursorLayer.setPadding(padding); this.$markerFront.setPadding(padding); this.$markerBack.setPadding(padding); this.$loop.schedule(this.CHANGE_FULL); this.$updatePrintMargin(); }; this.setScrollMargin = function(top, bottom, left, right) { var sm = this.scrollMargin; sm.top = top|0; sm.bottom = bottom|0; sm.right = right|0; sm.left = left|0; sm.v = sm.top + sm.bottom; sm.h = sm.left + sm.right; if (sm.top && this.scrollTop <= 0 && this.session) this.session.setScrollTop(-sm.top); this.updateFull(); }; this.getHScrollBarAlwaysVisible = function() { return this.$hScrollBarAlwaysVisible; }; this.setHScrollBarAlwaysVisible = function(alwaysVisible) { this.setOption("hScrollBarAlwaysVisible", alwaysVisible); }; this.getVScrollBarAlwaysVisible = function() { return this.$hScrollBarAlwaysVisible; }; this.setVScrollBarAlwaysVisible = function(alwaysVisible) { this.setOption("vScrollBarAlwaysVisible", alwaysVisible); }; this.$updateScrollBarV = function() { var scrollHeight = this.layerConfig.maxHeight; var scrollerHeight = this.$size.scrollerHeight; if (!this.$maxLines && this.$scrollPastEnd) { scrollHeight -= (scrollerHeight - this.lineHeight) * this.$scrollPastEnd; if (this.scrollTop > scrollHeight - scrollerHeight) { scrollHeight = this.scrollTop + scrollerHeight; this.scrollBarV.scrollTop = null; } } this.scrollBarV.setScrollHeight(scrollHeight + this.scrollMargin.v); this.scrollBarV.setScrollTop(this.scrollTop + this.scrollMargin.top); }; this.$updateScrollBarH = function() { this.scrollBarH.setScrollWidth(this.layerConfig.width + 2 * this.$padding + this.scrollMargin.h); this.scrollBarH.setScrollLeft(this.scrollLeft + this.scrollMargin.left); }; this.$frozen = false; this.freeze = function() { this.$frozen = true; }; this.unfreeze = function() { this.$frozen = false; }; this.$renderChanges = function(changes, force) { if (this.$changes) { changes |= this.$changes; this.$changes = 0; } if ((!this.session || !this.container.offsetWidth || this.$frozen) || (!changes && !force)) { this.$changes |= changes; return; } if (this.$size.$dirty) { this.$changes |= changes; return this.onResize(true); } if (!this.lineHeight) { this.$textLayer.checkForSizeChanges(); } this._signal("beforeRender"); var config = this.layerConfig; if (changes & this.CHANGE_FULL || changes & this.CHANGE_SIZE || changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES || changes & this.CHANGE_SCROLL || changes & this.CHANGE_H_SCROLL ) { changes |= this.$computeLayerConfig(); if (config.firstRow != this.layerConfig.firstRow && config.firstRowScreen == this.layerConfig.firstRowScreen) { var st = this.scrollTop + (config.firstRow - this.layerConfig.firstRow) * this.lineHeight; if (st > 0) { this.scrollTop = st; changes = changes | this.CHANGE_SCROLL; changes |= this.$computeLayerConfig(); } } config = this.layerConfig; this.$updateScrollBarV(); if (changes & this.CHANGE_H_SCROLL) this.$updateScrollBarH(); this.$gutterLayer.element.style.marginTop = (-config.offset) + "px"; this.content.style.marginTop = (-config.offset) + "px"; this.content.style.width = config.width + 2 * this.$padding + "px"; this.content.style.height = config.minHeight + "px"; } if (changes & this.CHANGE_H_SCROLL) { this.content.style.marginLeft = -this.scrollLeft + "px"; this.scroller.className = this.scrollLeft <= 0 ? "ace_scroller" : "ace_scroller ace_scroll-left"; } if (changes & this.CHANGE_FULL) { this.$textLayer.update(config); if (this.$showGutter) this.$gutterLayer.update(config); this.$markerBack.update(config); this.$markerFront.update(config); this.$cursorLayer.update(config); this.$moveTextAreaToCursor(); this.$highlightGutterLine && this.$updateGutterLineHighlight(); this._signal("afterRender"); return; } if (changes & this.CHANGE_SCROLL) { if (changes & this.CHANGE_TEXT || changes & this.CHANGE_LINES) this.$textLayer.update(config); else this.$textLayer.scrollLines(config); if (this.$showGutter) this.$gutterLayer.update(config); this.$markerBack.update(config); this.$markerFront.update(config); this.$cursorLayer.update(config); this.$highlightGutterLine && this.$updateGutterLineHighlight(); this.$moveTextAreaToCursor(); this._signal("afterRender"); return; } if (changes & this.CHANGE_TEXT) { this.$textLayer.update(config); if (this.$showGutter) this.$gutterLayer.update(config); } else if (changes & this.CHANGE_LINES) { if (this.$updateLines() || (changes & this.CHANGE_GUTTER) && this.$showGutter) this.$gutterLayer.update(config); } else if (changes & this.CHANGE_TEXT || changes & this.CHANGE_GUTTER) { if (this.$showGutter) this.$gutterLayer.update(config); } if (changes & this.CHANGE_CURSOR) { this.$cursorLayer.update(config); this.$moveTextAreaToCursor(); this.$highlightGutterLine && this.$updateGutterLineHighlight(); } if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_FRONT)) { this.$markerFront.update(config); } if (changes & (this.CHANGE_MARKER | this.CHANGE_MARKER_BACK)) { this.$markerBack.update(config); } this._signal("afterRender"); }; this.$autosize = function() { var height = this.session.getScreenLength() * this.lineHeight; var maxHeight = this.$maxLines * this.lineHeight; var desiredHeight = Math.max( (this.$minLines||1) * this.lineHeight, Math.min(maxHeight, height) ) + this.scrollMargin.v + (this.$extraHeight || 0); var vScroll = height > maxHeight; if (desiredHeight != this.desiredHeight || this.$size.height != this.desiredHeight || vScroll != this.$vScroll) { if (vScroll != this.$vScroll) { this.$vScroll = vScroll; this.scrollBarV.setVisible(vScroll); } var w = this.container.clientWidth; this.container.style.height = desiredHeight + "px"; this.$updateCachedSize(true, this.$gutterWidth, w, desiredHeight); this.desiredHeight = desiredHeight; this._signal("autosize"); } }; this.$computeLayerConfig = function() { if (this.$maxLines && this.lineHeight > 1) this.$autosize(); var session = this.session; var size = this.$size; var hideScrollbars = size.height <= 2 * this.lineHeight; var screenLines = this.session.getScreenLength(); var maxHeight = screenLines * this.lineHeight; var offset = this.scrollTop % this.lineHeight; var minHeight = size.scrollerHeight + this.lineHeight; var longestLine = this.$getLongestLine(); var horizScroll = !hideScrollbars && (this.$hScrollBarAlwaysVisible || size.scrollerWidth - longestLine - 2 * this.$padding < 0); var hScrollChanged = this.$horizScroll !== horizScroll; if (hScrollChanged) { this.$horizScroll = horizScroll; this.scrollBarH.setVisible(horizScroll); } var scrollPastEnd = !this.$maxLines && this.$scrollPastEnd ? (size.scrollerHeight - this.lineHeight) * this.$scrollPastEnd : 0; maxHeight += scrollPastEnd; this.session.setScrollTop(Math.max(-this.scrollMargin.top, Math.min(this.scrollTop, maxHeight - size.scrollerHeight + this.scrollMargin.bottom))); this.session.setScrollLeft(Math.max(-this.scrollMargin.left, Math.min(this.scrollLeft, longestLine + 2 * this.$padding - size.scrollerWidth + this.scrollMargin.right))); var vScroll = !hideScrollbars && (this.$vScrollBarAlwaysVisible || size.scrollerHeight - maxHeight + scrollPastEnd < 0 || this.scrollTop); var vScrollChanged = this.$vScroll !== vScroll; if (vScrollChanged) { this.$vScroll = vScroll; this.scrollBarV.setVisible(vScroll); } var lineCount = Math.ceil(minHeight / this.lineHeight) - 1; var firstRow = Math.max(0, Math.round((this.scrollTop - offset) / this.lineHeight)); var lastRow = firstRow + lineCount; var firstRowScreen, firstRowHeight; var lineHeight = this.lineHeight; firstRow = session.screenToDocumentRow(firstRow, 0); var foldLine = session.getFoldLine(firstRow); if (foldLine) { firstRow = foldLine.start.row; } firstRowScreen = session.documentToScreenRow(firstRow, 0); firstRowHeight = session.getRowLength(firstRow) * lineHeight; lastRow = Math.min(session.screenToDocumentRow(lastRow, 0), session.getLength() - 1); minHeight = size.scrollerHeight + session.getRowLength(lastRow) * lineHeight + firstRowHeight; offset = this.scrollTop - firstRowScreen * lineHeight; var changes = 0; if (this.layerConfig.width != longestLine) changes = this.CHANGE_H_SCROLL; if (hScrollChanged || vScrollChanged) { changes = this.$updateCachedSize(true, this.gutterWidth, size.width, size.height); this._signal("scrollbarVisibilityChanged"); if (vScrollChanged) longestLine = this.$getLongestLine(); } this.layerConfig = { width : longestLine, padding : this.$padding, firstRow : firstRow, firstRowScreen: firstRowScreen, lastRow : lastRow, lineHeight : lineHeight, characterWidth : this.characterWidth, minHeight : minHeight, maxHeight : maxHeight, offset : offset, gutterOffset : Math.max(0, Math.ceil((offset + size.height - size.scrollerHeight) / lineHeight)), height : this.$size.scrollerHeight }; return changes; }; this.$updateLines = function() { var firstRow = this.$changedLines.firstRow; var lastRow = this.$changedLines.lastRow; this.$changedLines = null; var layerConfig = this.layerConfig; if (firstRow > layerConfig.lastRow + 1) { return; } if (lastRow < layerConfig.firstRow) { return; } if (lastRow === Infinity) { if (this.$showGutter) this.$gutterLayer.update(layerConfig); this.$textLayer.update(layerConfig); return; } this.$textLayer.updateLines(layerConfig, firstRow, lastRow); return true; }; this.$getLongestLine = function() { var charCount = this.session.getScreenWidth(); if (this.showInvisibles && !this.session.$useWrapMode) charCount += 1; return Math.max(this.$size.scrollerWidth - 2 * this.$padding, Math.round(charCount * this.characterWidth)); }; this.updateFrontMarkers = function() { this.$markerFront.setMarkers(this.session.getMarkers(true)); this.$loop.schedule(this.CHANGE_MARKER_FRONT); }; this.updateBackMarkers = function() { this.$markerBack.setMarkers(this.session.getMarkers()); this.$loop.schedule(this.CHANGE_MARKER_BACK); }; this.addGutterDecoration = function(row, className){ this.$gutterLayer.addGutterDecoration(row, className); }; this.removeGutterDecoration = function(row, className){ this.$gutterLayer.removeGutterDecoration(row, className); }; this.updateBreakpoints = function(rows) { this.$loop.schedule(this.CHANGE_GUTTER); }; this.setAnnotations = function(annotations) { this.$gutterLayer.setAnnotations(annotations); this.$loop.schedule(this.CHANGE_GUTTER); }; this.updateCursor = function() { this.$loop.schedule(this.CHANGE_CURSOR); }; this.hideCursor = function() { this.$cursorLayer.hideCursor(); }; this.showCursor = function() { this.$cursorLayer.showCursor(); }; this.scrollSelectionIntoView = function(anchor, lead, offset) { this.scrollCursorIntoView(anchor, offset); this.scrollCursorIntoView(lead, offset); }; this.scrollCursorIntoView = function(cursor, offset, $viewMargin) { if (this.$size.scrollerHeight === 0) return; var pos = this.$cursorLayer.getPixelPosition(cursor); var left = pos.left; var top = pos.top; var topMargin = $viewMargin && $viewMargin.top || 0; var bottomMargin = $viewMargin && $viewMargin.bottom || 0; var scrollTop = this.$scrollAnimation ? this.session.getScrollTop() : this.scrollTop; if (scrollTop + topMargin > top) { if (offset) top -= offset * this.$size.scrollerHeight; if (top === 0) top = -this.scrollMargin.top; this.session.setScrollTop(top); } else if (scrollTop + this.$size.scrollerHeight - bottomMargin < top + this.lineHeight) { if (offset) top += offset * this.$size.scrollerHeight; this.session.setScrollTop(top + this.lineHeight - this.$size.scrollerHeight); } var scrollLeft = this.scrollLeft; if (scrollLeft > left) { if (left < this.$padding + 2 * this.layerConfig.characterWidth) left = -this.scrollMargin.left; this.session.setScrollLeft(left); } else if (scrollLeft + this.$size.scrollerWidth < left + this.characterWidth) { this.session.setScrollLeft(Math.round(left + this.characterWidth - this.$size.scrollerWidth)); } else if (scrollLeft <= this.$padding && left - scrollLeft < this.characterWidth) { this.session.setScrollLeft(0); } }; this.getScrollTop = function() { return this.session.getScrollTop(); }; this.getScrollLeft = function() { return this.session.getScrollLeft(); }; this.getScrollTopRow = function() { return this.scrollTop / this.lineHeight; }; this.getScrollBottomRow = function() { return Math.max(0, Math.floor((this.scrollTop + this.$size.scrollerHeight) / this.lineHeight) - 1); }; this.scrollToRow = function(row) { this.session.setScrollTop(row * this.lineHeight); }; this.alignCursor = function(cursor, alignment) { if (typeof cursor == "number") cursor = {row: cursor, column: 0}; var pos = this.$cursorLayer.getPixelPosition(cursor); var h = this.$size.scrollerHeight - this.lineHeight; var offset = pos.top - h * (alignment || 0); this.session.setScrollTop(offset); return offset; }; this.STEPS = 8; this.$calcSteps = function(fromValue, toValue){ var i = 0; var l = this.STEPS; var steps = []; var func = function(t, x_min, dx) { return dx * (Math.pow(t - 1, 3) + 1) + x_min; }; for (i = 0; i < l; ++i) steps.push(func(i / this.STEPS, fromValue, toValue - fromValue)); return steps; }; this.scrollToLine = function(line, center, animate, callback) { var pos = this.$cursorLayer.getPixelPosition({row: line, column: 0}); var offset = pos.top; if (center) offset -= this.$size.scrollerHeight / 2; var initialScroll = this.scrollTop; this.session.setScrollTop(offset); if (animate !== false) this.animateScrolling(initialScroll, callback); }; this.animateScrolling = function(fromValue, callback) { var toValue = this.scrollTop; if (!this.$animatedScroll) return; var _self = this; if (fromValue == toValue) return; if (this.$scrollAnimation) { var oldSteps = this.$scrollAnimation.steps; if (oldSteps.length) { fromValue = oldSteps[0]; if (fromValue == toValue) return; } } var steps = _self.$calcSteps(fromValue, toValue); this.$scrollAnimation = {from: fromValue, to: toValue, steps: steps}; clearInterval(this.$timer); _self.session.setScrollTop(steps.shift()); _self.session.$scrollTop = toValue; this.$timer = setInterval(function() { if (steps.length) { _self.session.setScrollTop(steps.shift()); _self.session.$scrollTop = toValue; } else if (toValue != null) { _self.session.$scrollTop = -1; _self.session.setScrollTop(toValue); toValue = null; } else { _self.$timer = clearInterval(_self.$timer); _self.$scrollAnimation = null; callback && callback(); } }, 10); }; this.scrollToY = function(scrollTop) { if (this.scrollTop !== scrollTop) { this.$loop.schedule(this.CHANGE_SCROLL); this.scrollTop = scrollTop; } }; this.scrollToX = function(scrollLeft) { if (this.scrollLeft !== scrollLeft) this.scrollLeft = scrollLeft; this.$loop.schedule(this.CHANGE_H_SCROLL); }; this.scrollTo = function(x, y) { this.session.setScrollTop(y); this.session.setScrollLeft(y); }; this.scrollBy = function(deltaX, deltaY) { deltaY && this.session.setScrollTop(this.session.getScrollTop() + deltaY); deltaX && this.session.setScrollLeft(this.session.getScrollLeft() + deltaX); }; this.isScrollableBy = function(deltaX, deltaY) { if (deltaY < 0 && this.session.getScrollTop() >= 1 - this.scrollMargin.top) return true; if (deltaY > 0 && this.session.getScrollTop() + this.$size.scrollerHeight - this.layerConfig.maxHeight < -1 + this.scrollMargin.bottom) return true; if (deltaX < 0 && this.session.getScrollLeft() >= 1 - this.scrollMargin.left) return true; if (deltaX > 0 && this.session.getScrollLeft() + this.$size.scrollerWidth - this.layerConfig.width < -1 + this.scrollMargin.right) return true; }; this.pixelToScreenCoordinates = function(x, y) { var canvasPos = this.scroller.getBoundingClientRect(); var offset = (x + this.scrollLeft - canvasPos.left - this.$padding) / this.characterWidth; var row = Math.floor((y + this.scrollTop - canvasPos.top) / this.lineHeight); var col = Math.round(offset); return {row: row, column: col, side: offset - col > 0 ? 1 : -1}; }; this.screenToTextCoordinates = function(x, y) { var canvasPos = this.scroller.getBoundingClientRect(); var col = Math.round( (x + this.scrollLeft - canvasPos.left - this.$padding) / this.characterWidth ); var row = (y + this.scrollTop - canvasPos.top) / this.lineHeight; return this.session.screenToDocumentPosition(row, Math.max(col, 0)); }; this.textToScreenCoordinates = function(row, column) { var canvasPos = this.scroller.getBoundingClientRect(); var pos = this.session.documentToScreenPosition(row, column); var x = this.$padding + Math.round(pos.column * this.characterWidth); var y = pos.row * this.lineHeight; return { pageX: canvasPos.left + x - this.scrollLeft, pageY: canvasPos.top + y - this.scrollTop }; }; this.visualizeFocus = function() { dom.addCssClass(this.container, "ace_focus"); }; this.visualizeBlur = function() { dom.removeCssClass(this.container, "ace_focus"); }; this.showComposition = function(position) { if (!this.$composition) this.$composition = { keepTextAreaAtCursor: this.$keepTextAreaAtCursor, cssText: this.textarea.style.cssText }; this.$keepTextAreaAtCursor = true; dom.addCssClass(this.textarea, "ace_composition"); this.textarea.style.cssText = ""; this.$moveTextAreaToCursor(); }; this.setCompositionText = function(text) { this.$moveTextAreaToCursor(); }; this.hideComposition = function() { if (!this.$composition) return; dom.removeCssClass(this.textarea, "ace_composition"); this.$keepTextAreaAtCursor = this.$composition.keepTextAreaAtCursor; this.textarea.style.cssText = this.$composition.cssText; this.$composition = null; }; this.setTheme = function(theme, cb) { var _self = this; this.$themeId = theme; _self._dispatchEvent('themeChange',{theme:theme}); if (!theme || typeof theme == "string") { var moduleName = theme || this.$options.theme.initialValue; config.loadModule(["theme", moduleName], afterLoad); } else { afterLoad(theme); } function afterLoad(module) { if (_self.$themeId != theme) return cb && cb(); if (!module.cssClass) return; dom.importCssString( module.cssText, module.cssClass, _self.container.ownerDocument ); if (_self.theme) dom.removeCssClass(_self.container, _self.theme.cssClass); var padding = "padding" in module ? module.padding : "padding" in (_self.theme || {}) ? 4 : _self.$padding; if (_self.$padding && padding != _self.$padding) _self.setPadding(padding); _self.$theme = module.cssClass; _self.theme = module; dom.addCssClass(_self.container, module.cssClass); dom.setCssClass(_self.container, "ace_dark", module.isDark); if (_self.$size) { _self.$size.width = 0; _self.$updateSizeAsync(); } _self._dispatchEvent('themeLoaded', {theme:module}); cb && cb(); } }; this.getTheme = function() { return this.$themeId; }; this.setStyle = function(style, include) { dom.setCssClass(this.container, style, include !== false); }; this.unsetStyle = function(style) { dom.removeCssClass(this.container, style); }; this.setCursorStyle = function(style) { if (this.scroller.style.cursor != style) this.scroller.style.cursor = style; }; this.setMouseCursor = function(cursorStyle) { this.scroller.style.cursor = cursorStyle; }; this.destroy = function() { this.$textLayer.destroy(); this.$cursorLayer.destroy(); }; }).call(VirtualRenderer.prototype); config.defineOptions(VirtualRenderer.prototype, "renderer", { animatedScroll: {initialValue: false}, showInvisibles: { set: function(value) { if (this.$textLayer.setShowInvisibles(value)) this.$loop.schedule(this.CHANGE_TEXT); }, initialValue: false }, showPrintMargin: { set: function() { this.$updatePrintMargin(); }, initialValue: true }, printMarginColumn: { set: function() { this.$updatePrintMargin(); }, initialValue: 80 }, printMargin: { set: function(val) { if (typeof val == "number") this.$printMarginColumn = val; this.$showPrintMargin = !!val; this.$updatePrintMargin(); }, get: function() { return this.$showPrintMargin && this.$printMarginColumn; } }, showGutter: { set: function(show){ this.$gutter.style.display = show ? "block" : "none"; this.$loop.schedule(this.CHANGE_FULL); this.onGutterResize(); }, initialValue: true }, fadeFoldWidgets: { set: function(show) { dom.setCssClass(this.$gutter, "ace_fade-fold-widgets", show); }, initialValue: false }, showFoldWidgets: { set: function(show) {this.$gutterLayer.setShowFoldWidgets(show)}, initialValue: true }, showLineNumbers: { set: function(show) { this.$gutterLayer.setShowLineNumbers(show); this.$loop.schedule(this.CHANGE_GUTTER); }, initialValue: true }, displayIndentGuides: { set: function(show) { if (this.$textLayer.setDisplayIndentGuides(show)) this.$loop.schedule(this.CHANGE_TEXT); }, initialValue: true }, highlightGutterLine: { set: function(shouldHighlight) { if (!this.$gutterLineHighlight) { this.$gutterLineHighlight = dom.createElement("div"); this.$gutterLineHighlight.className = "ace_gutter-active-line"; this.$gutter.appendChild(this.$gutterLineHighlight); return; } this.$gutterLineHighlight.style.display = shouldHighlight ? "" : "none"; if (this.$cursorLayer.$pixelPos) this.$updateGutterLineHighlight(); }, initialValue: false, value: true }, hScrollBarAlwaysVisible: { set: function(val) { if (!this.$hScrollBarAlwaysVisible || !this.$horizScroll) this.$loop.schedule(this.CHANGE_SCROLL); }, initialValue: false }, vScrollBarAlwaysVisible: { set: function(val) { if (!this.$vScrollBarAlwaysVisible || !this.$vScroll) this.$loop.schedule(this.CHANGE_SCROLL); }, initialValue: false }, fontSize: { set: function(size) { if (typeof size == "number") size = size + "px"; this.container.style.fontSize = size; this.updateFontSize(); }, initialValue: 12 }, fontFamily: { set: function(name) { this.container.style.fontFamily = name; this.updateFontSize(); } }, maxLines: { set: function(val) { this.updateFull(); } }, minLines: { set: function(val) { this.updateFull(); } }, scrollPastEnd: { set: function(val) { val = +val || 0; if (this.$scrollPastEnd == val) return; this.$scrollPastEnd = val; this.$loop.schedule(this.CHANGE_SCROLL); }, initialValue: 0, handlesSet: true }, fixedWidthGutter: { set: function(val) { this.$gutterLayer.$fixedWidth = !!val; this.$loop.schedule(this.CHANGE_GUTTER); } }, theme: { set: function(val) { this.setTheme(val) }, get: function() { return this.$themeId || this.theme; }, initialValue: "./theme/textmate", handlesSet: true } }); exports.VirtualRenderer = VirtualRenderer; }); ace.define("ace/worker/worker_client",["require","exports","module","ace/lib/oop","ace/lib/net","ace/lib/event_emitter","ace/config"], function(require, exports, module) { "use strict"; var oop = require("../lib/oop"); var net = require("../lib/net"); var EventEmitter = require("../lib/event_emitter").EventEmitter; var config = require("../config"); var WorkerClient = function(topLevelNamespaces, mod, classname, workerUrl) { this.$sendDeltaQueue = this.$sendDeltaQueue.bind(this); this.changeListener = this.changeListener.bind(this); this.onMessage = this.onMessage.bind(this); if (require.nameToUrl && !require.toUrl) require.toUrl = require.nameToUrl; if (config.get("packaged") || !require.toUrl) { workerUrl = workerUrl || config.moduleUrl(mod, "worker"); } else { var normalizePath = this.$normalizePath; workerUrl = workerUrl || normalizePath(require.toUrl("ace/worker/worker.js", null, "_")); var tlns = {}; topLevelNamespaces.forEach(function(ns) { tlns[ns] = normalizePath(require.toUrl(ns, null, "_").replace(/(\.js)?(\?.*)?$/, "")); }); } try { this.$worker = new Worker(workerUrl); } catch(e) { if (e instanceof window.DOMException) { var blob = this.$workerBlob(workerUrl); var URL = window.URL || window.webkitURL; var blobURL = URL.createObjectURL(blob); this.$worker = new Worker(blobURL); URL.revokeObjectURL(blobURL); } else { throw e; } } this.$worker.postMessage({ init : true, tlns : tlns, module : mod, classname : classname }); this.callbackId = 1; this.callbacks = {}; this.$worker.onmessage = this.onMessage; }; (function(){ oop.implement(this, EventEmitter); this.onMessage = function(e) { var msg = e.data; switch(msg.type) { case "event": this._signal(msg.name, {data: msg.data}); break; case "call": var callback = this.callbacks[msg.id]; if (callback) { callback(msg.data); delete this.callbacks[msg.id]; } break; case "error": this.reportError(msg.data); break; case "log": window.console && console.log && console.log.apply(console, msg.data); break; } }; this.reportError = function(err) { window.console && console.error && console.error(err); }; this.$normalizePath = function(path) { return net.qualifyURL(path); }; this.terminate = function() { this._signal("terminate", {}); this.deltaQueue = null; this.$worker.terminate(); this.$worker = null; if (this.$doc) this.$doc.off("change", this.changeListener); this.$doc = null; }; this.send = function(cmd, args) { this.$worker.postMessage({command: cmd, args: args}); }; this.call = function(cmd, args, callback) { if (callback) { var id = this.callbackId++; this.callbacks[id] = callback; args.push(id); } this.send(cmd, args); }; this.emit = function(event, data) { try { this.$worker.postMessage({event: event, data: {data: data.data}}); } catch(ex) { console.error(ex.stack); } }; this.attachToDocument = function(doc) { if(this.$doc) this.terminate(); this.$doc = doc; this.call("setValue", [doc.getValue()]); doc.on("change", this.changeListener); }; this.changeListener = function(e) { if (!this.deltaQueue) { this.deltaQueue = [e.data]; setTimeout(this.$sendDeltaQueue, 0); } else this.deltaQueue.push(e.data); }; this.$sendDeltaQueue = function() { var q = this.deltaQueue; if (!q) return; this.deltaQueue = null; if (q.length > 20 && q.length > this.$doc.getLength() >> 1) { this.call("setValue", [this.$doc.getValue()]); } else this.emit("change", {data: q}); }; this.$workerBlob = function(workerUrl) { var script = "importScripts('" + net.qualifyURL(workerUrl) + "');"; try { return new Blob([script], {"type": "application/javascript"}); } catch (e) { // Backwards-compatibility var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder; var blobBuilder = new BlobBuilder(); blobBuilder.append(script); return blobBuilder.getBlob("application/javascript"); } }; }).call(WorkerClient.prototype); var UIWorkerClient = function(topLevelNamespaces, mod, classname) { this.$sendDeltaQueue = this.$sendDeltaQueue.bind(this); this.changeListener = this.changeListener.bind(this); this.callbackId = 1; this.callbacks = {}; this.messageBuffer = []; var main = null; var emitSync = false; var sender = Object.create(EventEmitter); var _self = this; this.$worker = {}; this.$worker.terminate = function() {}; this.$worker.postMessage = function(e) { _self.messageBuffer.push(e); if (main) { if (emitSync) setTimeout(processNext); else processNext(); } }; this.setEmitSync = function(val) { emitSync = val }; var processNext = function() { var msg = _self.messageBuffer.shift(); if (msg.command) main[msg.command].apply(main, msg.args); else if (msg.event) sender._signal(msg.event, msg.data); }; sender.postMessage = function(msg) { _self.onMessage({data: msg}); }; sender.callback = function(data, callbackId) { this.postMessage({type: "call", id: callbackId, data: data}); }; sender.emit = function(name, data) { this.postMessage({type: "event", name: name, data: data}); }; config.loadModule(["worker", mod], function(Main) { main = new Main[classname](sender); while (_self.messageBuffer.length) processNext(); }); }; UIWorkerClient.prototype = WorkerClient.prototype; exports.UIWorkerClient = UIWorkerClient; exports.WorkerClient = WorkerClient; }); ace.define("ace/placeholder",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/oop"], function(require, exports, module) { "use strict"; var Range = require("./range").Range; var EventEmitter = require("./lib/event_emitter").EventEmitter; var oop = require("./lib/oop"); var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) { var _self = this; this.length = length; this.session = session; this.doc = session.getDocument(); this.mainClass = mainClass; this.othersClass = othersClass; this.$onUpdate = this.onUpdate.bind(this); this.doc.on("change", this.$onUpdate); this.$others = others; this.$onCursorChange = function() { setTimeout(function() { _self.onCursorChange(); }); }; this.$pos = pos; var undoStack = session.getUndoManager().$undoStack || session.getUndoManager().$undostack || {length: -1}; this.$undoStackDepth = undoStack.length; this.setup(); session.selection.on("changeCursor", this.$onCursorChange); }; (function() { oop.implement(this, EventEmitter); this.setup = function() { var _self = this; var doc = this.doc; var session = this.session; var pos = this.$pos; this.selectionBefore = session.selection.toJSON(); if (session.selection.inMultiSelectMode) session.selection.toSingleRange(); this.pos = doc.createAnchor(pos.row, pos.column); this.markerId = session.addMarker(new Range(pos.row, pos.column, pos.row, pos.column + this.length), this.mainClass, null, false); this.pos.on("change", function(event) { session.removeMarker(_self.markerId); _self.markerId = session.addMarker(new Range(event.value.row, event.value.column, event.value.row, event.value.column+_self.length), _self.mainClass, null, false); }); this.others = []; this.$others.forEach(function(other) { var anchor = doc.createAnchor(other.row, other.column); _self.others.push(anchor); }); session.setUndoSelect(false); }; this.showOtherMarkers = function() { if(this.othersActive) return; var session = this.session; var _self = this; this.othersActive = true; this.others.forEach(function(anchor) { anchor.markerId = session.addMarker(new Range(anchor.row, anchor.column, anchor.row, anchor.column+_self.length), _self.othersClass, null, false); anchor.on("change", function(event) { session.removeMarker(anchor.markerId); anchor.markerId = session.addMarker(new Range(event.value.row, event.value.column, event.value.row, event.value.column+_self.length), _self.othersClass, null, false); }); }); }; this.hideOtherMarkers = function() { if(!this.othersActive) return; this.othersActive = false; for (var i = 0; i < this.others.length; i++) { this.session.removeMarker(this.others[i].markerId); } }; this.onUpdate = function(event) { var delta = event.data; var range = delta.range; if(range.start.row !== range.end.row) return; if(range.start.row !== this.pos.row) return; if (this.$updating) return; this.$updating = true; var lengthDiff = delta.action === "insertText" ? range.end.column - range.start.column : range.start.column - range.end.column; if(range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1) { var distanceFromStart = range.start.column - this.pos.column; this.length += lengthDiff; if(!this.session.$fromUndo) { if(delta.action === "insertText") { for (var i = this.others.length - 1; i >= 0; i--) { var otherPos = this.others[i]; var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; if(otherPos.row === range.start.row && range.start.column < otherPos.column) newPos.column += lengthDiff; this.doc.insert(newPos, delta.text); } } else if(delta.action === "removeText") { for (var i = this.others.length - 1; i >= 0; i--) { var otherPos = this.others[i]; var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart}; if(otherPos.row === range.start.row && range.start.column < otherPos.column) newPos.column += lengthDiff; this.doc.remove(new Range(newPos.row, newPos.column, newPos.row, newPos.column - lengthDiff)); } } if(range.start.column === this.pos.column && delta.action === "insertText") { setTimeout(function() { this.pos.setPosition(this.pos.row, this.pos.column - lengthDiff); for (var i = 0; i < this.others.length; i++) { var other = this.others[i]; var newPos = {row: other.row, column: other.column - lengthDiff}; if(other.row === range.start.row && range.start.column < other.column) newPos.column += lengthDiff; other.setPosition(newPos.row, newPos.column); } }.bind(this), 0); } else if(range.start.column === this.pos.column && delta.action === "removeText") { setTimeout(function() { for (var i = 0; i < this.others.length; i++) { var other = this.others[i]; if(other.row === range.start.row && range.start.column < other.column) { other.setPosition(other.row, other.column - lengthDiff); } } }.bind(this), 0); } } this.pos._emit("change", {value: this.pos}); for (var i = 0; i < this.others.length; i++) { this.others[i]._emit("change", {value: this.others[i]}); } } this.$updating = false; }; this.onCursorChange = function(event) { if (this.$updating || !this.session) return; var pos = this.session.selection.getCursor(); if (pos.row === this.pos.row && pos.column >= this.pos.column && pos.column <= this.pos.column + this.length) { this.showOtherMarkers(); this._emit("cursorEnter", event); } else { this.hideOtherMarkers(); this._emit("cursorLeave", event); } }; this.detach = function() { this.session.removeMarker(this.markerId); this.hideOtherMarkers(); this.doc.removeEventListener("change", this.$onUpdate); this.session.selection.removeEventListener("changeCursor", this.$onCursorChange); this.pos.detach(); for (var i = 0; i < this.others.length; i++) { this.others[i].detach(); } this.session.setUndoSelect(true); this.session = null; }; this.cancel = function() { if(this.$undoStackDepth === -1) throw Error("Canceling placeholders only supported with undo manager attached to session."); var undoManager = this.session.getUndoManager(); var undosRequired = (undoManager.$undoStack || undoManager.$undostack).length - this.$undoStackDepth; for (var i = 0; i < undosRequired; i++) { undoManager.undo(true); } if (this.selectionBefore) this.session.selection.fromJSON(this.selectionBefore); }; }).call(PlaceHolder.prototype); exports.PlaceHolder = PlaceHolder; }); ace.define("ace/mouse/multi_select_handler",["require","exports","module","ace/lib/event","ace/lib/useragent"], function(require, exports, module) { var event = require("../lib/event"); var useragent = require("../lib/useragent"); function isSamePoint(p1, p2) { return p1.row == p2.row && p1.column == p2.column; } function onMouseDown(e) { var ev = e.domEvent; var alt = ev.altKey; var shift = ev.shiftKey; var ctrl = ev.ctrlKey; var accel = e.getAccelKey(); var button = e.getButton(); if (ctrl && useragent.isMac) button = ev.button; if (e.editor.inMultiSelectMode && button == 2) { e.editor.textInput.onContextMenu(e.domEvent); return; } if (!ctrl && !alt && !accel) { if (button === 0 && e.editor.inMultiSelectMode) e.editor.exitMultiSelectMode(); return; } if (button !== 0) return; var editor = e.editor; var selection = editor.selection; var isMultiSelect = editor.inMultiSelectMode; var pos = e.getDocumentPosition(); var cursor = selection.getCursor(); var inSelection = e.inSelection() || (selection.isEmpty() && isSamePoint(pos, cursor)); var mouseX = e.x, mouseY = e.y; var onMouseSelection = function(e) { mouseX = e.clientX; mouseY = e.clientY; }; var session = editor.session; var screenAnchor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY); var screenCursor = screenAnchor; var selectionMode; if (editor.$mouseHandler.$enableJumpToDef) { if (ctrl && alt || accel && alt) selectionMode = "add"; else if (alt) selectionMode = "block"; } else { if (accel && !alt) { selectionMode = "add"; if (!isMultiSelect && shift) return; } else if (alt) { selectionMode = "block"; } } if (selectionMode && useragent.isMac && ev.ctrlKey) { editor.$mouseHandler.cancelContextMenu(); } if (selectionMode == "add") { if (!isMultiSelect && inSelection) return; // dragging if (!isMultiSelect) { var range = selection.toOrientedRange(); editor.addSelectionMarker(range); } var oldRange = selection.rangeList.rangeAtPoint(pos); editor.$blockScrolling++; editor.inVirtualSelectionMode = true; if (shift) { oldRange = null; range = selection.ranges[0]; editor.removeSelectionMarker(range); } editor.once("mouseup", function() { var tmpSel = selection.toOrientedRange(); if (oldRange && tmpSel.isEmpty() && isSamePoint(oldRange.cursor, tmpSel.cursor)) selection.substractPoint(tmpSel.cursor); else { if (shift) { selection.substractPoint(range.cursor); } else if (range) { editor.removeSelectionMarker(range); selection.addRange(range); } selection.addRange(tmpSel); } editor.$blockScrolling--; editor.inVirtualSelectionMode = false; }); } else if (selectionMode == "block") { e.stop(); editor.inVirtualSelectionMode = true; var initialRange; var rectSel = []; var blockSelect = function() { var newCursor = editor.renderer.pixelToScreenCoordinates(mouseX, mouseY); var cursor = session.screenToDocumentPosition(newCursor.row, newCursor.column); if (isSamePoint(screenCursor, newCursor) && isSamePoint(cursor, selection.lead)) return; screenCursor = newCursor; editor.selection.moveToPosition(cursor); editor.renderer.scrollCursorIntoView(); editor.removeSelectionMarkers(rectSel); rectSel = selection.rectangularRangeBlock(screenCursor, screenAnchor); if (editor.$mouseHandler.$clickSelection && rectSel.length == 1 && rectSel[0].isEmpty()) rectSel[0] = editor.$mouseHandler.$clickSelection.clone(); rectSel.forEach(editor.addSelectionMarker, editor); editor.updateSelectionMarkers(); }; if (isMultiSelect && !accel) { selection.toSingleRange(); } else if (!isMultiSelect && accel) { initialRange = selection.toOrientedRange(); editor.addSelectionMarker(initialRange); } if (shift) screenAnchor = session.documentToScreenPosition(selection.lead); else selection.moveToPosition(pos); screenCursor = {row: -1, column: -1}; var onMouseSelectionEnd = function(e) { clearInterval(timerId); editor.removeSelectionMarkers(rectSel); if (!rectSel.length) rectSel = [selection.toOrientedRange()]; editor.$blockScrolling++; if (initialRange) { editor.removeSelectionMarker(initialRange); selection.toSingleRange(initialRange); } for (var i = 0; i < rectSel.length; i++) selection.addRange(rectSel[i]); editor.inVirtualSelectionMode = false; editor.$mouseHandler.$clickSelection = null; editor.$blockScrolling--; }; var onSelectionInterval = blockSelect; event.capture(editor.container, onMouseSelection, onMouseSelectionEnd); var timerId = setInterval(function() {onSelectionInterval();}, 20); return e.preventDefault(); } } exports.onMouseDown = onMouseDown; }); ace.define("ace/commands/multi_select_commands",["require","exports","module","ace/keyboard/hash_handler"], function(require, exports, module) { exports.defaultCommands = [{ name: "addCursorAbove", exec: function(editor) { editor.selectMoreLines(-1); }, bindKey: {win: "Ctrl-Alt-Up", mac: "Ctrl-Alt-Up"}, readonly: true }, { name: "addCursorBelow", exec: function(editor) { editor.selectMoreLines(1); }, bindKey: {win: "Ctrl-Alt-Down", mac: "Ctrl-Alt-Down"}, readonly: true }, { name: "addCursorAboveSkipCurrent", exec: function(editor) { editor.selectMoreLines(-1, true); }, bindKey: {win: "Ctrl-Alt-Shift-Up", mac: "Ctrl-Alt-Shift-Up"}, readonly: true }, { name: "addCursorBelowSkipCurrent", exec: function(editor) { editor.selectMoreLines(1, true); }, bindKey: {win: "Ctrl-Alt-Shift-Down", mac: "Ctrl-Alt-Shift-Down"}, readonly: true }, { name: "selectMoreBefore", exec: function(editor) { editor.selectMore(-1); }, bindKey: {win: "Ctrl-Alt-Left", mac: "Ctrl-Alt-Left"}, readonly: true }, { name: "selectMoreAfter", exec: function(editor) { editor.selectMore(1); }, bindKey: {win: "Ctrl-Alt-Right", mac: "Ctrl-Alt-Right"}, readonly: true }, { name: "selectNextBefore", exec: function(editor) { editor.selectMore(-1, true); }, bindKey: {win: "Ctrl-Alt-Shift-Left", mac: "Ctrl-Alt-Shift-Left"}, readonly: true }, { name: "selectNextAfter", exec: function(editor) { editor.selectMore(1, true); }, bindKey: {win: "Ctrl-Alt-Shift-Right", mac: "Ctrl-Alt-Shift-Right"}, readonly: true }, { name: "splitIntoLines", exec: function(editor) { editor.multiSelect.splitIntoLines(); }, bindKey: {win: "Ctrl-Alt-L", mac: "Ctrl-Alt-L"}, readonly: true }, { name: "alignCursors", exec: function(editor) { editor.alignCursors(); }, bindKey: {win: "Ctrl-Alt-A", mac: "Ctrl-Alt-A"} }, { name: "findAll", exec: function(editor) { editor.findAll(); }, bindKey: {win: "Ctrl-Alt-K", mac: "Ctrl-Alt-G"}, readonly: true }]; exports.multiSelectCommands = [{ name: "singleSelection", bindKey: "esc", exec: function(editor) { editor.exitMultiSelectMode(); }, readonly: true, isAvailable: function(editor) {return editor && editor.inMultiSelectMode} }]; var HashHandler = require("../keyboard/hash_handler").HashHandler; exports.keyboardHandler = new HashHandler(exports.multiSelectCommands); }); ace.define("ace/multi_select",["require","exports","module","ace/range_list","ace/range","ace/selection","ace/mouse/multi_select_handler","ace/lib/event","ace/lib/lang","ace/commands/multi_select_commands","ace/search","ace/edit_session","ace/editor","ace/config"], function(require, exports, module) { var RangeList = require("./range_list").RangeList; var Range = require("./range").Range; var Selection = require("./selection").Selection; var onMouseDown = require("./mouse/multi_select_handler").onMouseDown; var event = require("./lib/event"); var lang = require("./lib/lang"); var commands = require("./commands/multi_select_commands"); exports.commands = commands.defaultCommands.concat(commands.multiSelectCommands); var Search = require("./search").Search; var search = new Search(); function find(session, needle, dir) { search.$options.wrap = true; search.$options.needle = needle; search.$options.backwards = dir == -1; return search.find(session); } var EditSession = require("./edit_session").EditSession; (function() { this.getSelectionMarkers = function() { return this.$selectionMarkers; }; }).call(EditSession.prototype); (function() { this.ranges = null; this.rangeList = null; this.addRange = function(range, $blockChangeEvents) { if (!range) return; if (!this.inMultiSelectMode && this.rangeCount === 0) { var oldRange = this.toOrientedRange(); this.rangeList.add(oldRange); this.rangeList.add(range); if (this.rangeList.ranges.length != 2) { this.rangeList.removeAll(); return $blockChangeEvents || this.fromOrientedRange(range); } this.rangeList.removeAll(); this.rangeList.add(oldRange); this.$onAddRange(oldRange); } if (!range.cursor) range.cursor = range.end; var removed = this.rangeList.add(range); this.$onAddRange(range); if (removed.length) this.$onRemoveRange(removed); if (this.rangeCount > 1 && !this.inMultiSelectMode) { this._signal("multiSelect"); this.inMultiSelectMode = true; this.session.$undoSelect = false; this.rangeList.attach(this.session); } return $blockChangeEvents || this.fromOrientedRange(range); }; this.toSingleRange = function(range) { range = range || this.ranges[0]; var removed = this.rangeList.removeAll(); if (removed.length) this.$onRemoveRange(removed); range && this.fromOrientedRange(range); }; this.substractPoint = function(pos) { var removed = this.rangeList.substractPoint(pos); if (removed) { this.$onRemoveRange(removed); return removed[0]; } }; this.mergeOverlappingRanges = function() { var removed = this.rangeList.merge(); if (removed.length) this.$onRemoveRange(removed); else if(this.ranges[0]) this.fromOrientedRange(this.ranges[0]); }; this.$onAddRange = function(range) { this.rangeCount = this.rangeList.ranges.length; this.ranges.unshift(range); this._signal("addRange", {range: range}); }; this.$onRemoveRange = function(removed) { this.rangeCount = this.rangeList.ranges.length; if (this.rangeCount == 1 && this.inMultiSelectMode) { var lastRange = this.rangeList.ranges.pop(); removed.push(lastRange); this.rangeCount = 0; } for (var i = removed.length; i--; ) { var index = this.ranges.indexOf(removed[i]); this.ranges.splice(index, 1); } this._signal("removeRange", {ranges: removed}); if (this.rangeCount === 0 && this.inMultiSelectMode) { this.inMultiSelectMode = false; this._signal("singleSelect"); this.session.$undoSelect = true; this.rangeList.detach(this.session); } lastRange = lastRange || this.ranges[0]; if (lastRange && !lastRange.isEqual(this.getRange())) this.fromOrientedRange(lastRange); }; this.$initRangeList = function() { if (this.rangeList) return; this.rangeList = new RangeList(); this.ranges = []; this.rangeCount = 0; }; this.getAllRanges = function() { return this.rangeCount ? this.rangeList.ranges.concat() : [this.getRange()]; }; this.splitIntoLines = function () { if (this.rangeCount > 1) { var ranges = this.rangeList.ranges; var lastRange = ranges[ranges.length - 1]; var range = Range.fromPoints(ranges[0].start, lastRange.end); this.toSingleRange(); this.setSelectionRange(range, lastRange.cursor == lastRange.start); } else { var range = this.getRange(); var isBackwards = this.isBackwards(); var startRow = range.start.row; var endRow = range.end.row; if (startRow == endRow) { if (isBackwards) var start = range.end, end = range.start; else var start = range.start, end = range.end; this.addRange(Range.fromPoints(end, end)); this.addRange(Range.fromPoints(start, start)); return; } var rectSel = []; var r = this.getLineRange(startRow, true); r.start.column = range.start.column; rectSel.push(r); for (var i = startRow + 1; i < endRow; i++) rectSel.push(this.getLineRange(i, true)); r = this.getLineRange(endRow, true); r.end.column = range.end.column; rectSel.push(r); rectSel.forEach(this.addRange, this); } }; this.toggleBlockSelection = function () { if (this.rangeCount > 1) { var ranges = this.rangeList.ranges; var lastRange = ranges[ranges.length - 1]; var range = Range.fromPoints(ranges[0].start, lastRange.end); this.toSingleRange(); this.setSelectionRange(range, lastRange.cursor == lastRange.start); } else { var cursor = this.session.documentToScreenPosition(this.selectionLead); var anchor = this.session.documentToScreenPosition(this.selectionAnchor); var rectSel = this.rectangularRangeBlock(cursor, anchor); rectSel.forEach(this.addRange, this); } }; this.rectangularRangeBlock = function(screenCursor, screenAnchor, includeEmptyLines) { var rectSel = []; var xBackwards = screenCursor.column < screenAnchor.column; if (xBackwards) { var startColumn = screenCursor.column; var endColumn = screenAnchor.column; } else { var startColumn = screenAnchor.column; var endColumn = screenCursor.column; } var yBackwards = screenCursor.row < screenAnchor.row; if (yBackwards) { var startRow = screenCursor.row; var endRow = screenAnchor.row; } else { var startRow = screenAnchor.row; var endRow = screenCursor.row; } if (startColumn < 0) startColumn = 0; if (startRow < 0) startRow = 0; if (startRow == endRow) includeEmptyLines = true; for (var row = startRow; row <= endRow; row++) { var range = Range.fromPoints( this.session.screenToDocumentPosition(row, startColumn), this.session.screenToDocumentPosition(row, endColumn) ); if (range.isEmpty()) { if (docEnd && isSamePoint(range.end, docEnd)) break; var docEnd = range.end; } range.cursor = xBackwards ? range.start : range.end; rectSel.push(range); } if (yBackwards) rectSel.reverse(); if (!includeEmptyLines) { var end = rectSel.length - 1; while (rectSel[end].isEmpty() && end > 0) end--; if (end > 0) { var start = 0; while (rectSel[start].isEmpty()) start++; } for (var i = end; i >= start; i--) { if (rectSel[i].isEmpty()) rectSel.splice(i, 1); } } return rectSel; }; }).call(Selection.prototype); var Editor = require("./editor").Editor; (function() { this.updateSelectionMarkers = function() { this.renderer.updateCursor(); this.renderer.updateBackMarkers(); }; this.addSelectionMarker = function(orientedRange) { if (!orientedRange.cursor) orientedRange.cursor = orientedRange.end; var style = this.getSelectionStyle(); orientedRange.marker = this.session.addMarker(orientedRange, "ace_selection", style); this.session.$selectionMarkers.push(orientedRange); this.session.selectionMarkerCount = this.session.$selectionMarkers.length; return orientedRange; }; this.removeSelectionMarker = function(range) { if (!range.marker) return; this.session.removeMarker(range.marker); var index = this.session.$selectionMarkers.indexOf(range); if (index != -1) this.session.$selectionMarkers.splice(index, 1); this.session.selectionMarkerCount = this.session.$selectionMarkers.length; }; this.removeSelectionMarkers = function(ranges) { var markerList = this.session.$selectionMarkers; for (var i = ranges.length; i--; ) { var range = ranges[i]; if (!range.marker) continue; this.session.removeMarker(range.marker); var index = markerList.indexOf(range); if (index != -1) markerList.splice(index, 1); } this.session.selectionMarkerCount = markerList.length; }; this.$onAddRange = function(e) { this.addSelectionMarker(e.range); this.renderer.updateCursor(); this.renderer.updateBackMarkers(); }; this.$onRemoveRange = function(e) { this.removeSelectionMarkers(e.ranges); this.renderer.updateCursor(); this.renderer.updateBackMarkers(); }; this.$onMultiSelect = function(e) { if (this.inMultiSelectMode) return; this.inMultiSelectMode = true; this.setStyle("ace_multiselect"); this.keyBinding.addKeyboardHandler(commands.keyboardHandler); this.commands.setDefaultHandler("exec", this.$onMultiSelectExec); this.renderer.updateCursor(); this.renderer.updateBackMarkers(); }; this.$onSingleSelect = function(e) { if (this.session.multiSelect.inVirtualMode) return; this.inMultiSelectMode = false; this.unsetStyle("ace_multiselect"); this.keyBinding.removeKeyboardHandler(commands.keyboardHandler); this.commands.removeDefaultHandler("exec", this.$onMultiSelectExec); this.renderer.updateCursor(); this.renderer.updateBackMarkers(); this._emit("changeSelection"); }; this.$onMultiSelectExec = function(e) { var command = e.command; var editor = e.editor; if (!editor.multiSelect) return; if (!command.multiSelectAction) { var result = command.exec(editor, e.args || {}); editor.multiSelect.addRange(editor.multiSelect.toOrientedRange()); editor.multiSelect.mergeOverlappingRanges(); } else if (command.multiSelectAction == "forEach") { result = editor.forEachSelection(command, e.args); } else if (command.multiSelectAction == "forEachLine") { result = editor.forEachSelection(command, e.args, true); } else if (command.multiSelectAction == "single") { editor.exitMultiSelectMode(); result = command.exec(editor, e.args || {}); } else { result = command.multiSelectAction(editor, e.args || {}); } return result; }; this.forEachSelection = function(cmd, args, options) { if (this.inVirtualSelectionMode) return; var keepOrder = options && options.keepOrder; var $byLines = options == true || options && options.$byLines var session = this.session; var selection = this.selection; var rangeList = selection.rangeList; var ranges = (keepOrder ? selection : rangeList).ranges; var result; if (!ranges.length) return cmd.exec ? cmd.exec(this, args || {}) : cmd(this, args || {}); var reg = selection._eventRegistry; selection._eventRegistry = {}; var tmpSel = new Selection(session); this.inVirtualSelectionMode = true; for (var i = ranges.length; i--;) { if ($byLines) { while (i > 0 && ranges[i].start.row == ranges[i - 1].end.row) i--; } tmpSel.fromOrientedRange(ranges[i]); tmpSel.index = i; this.selection = session.selection = tmpSel; var cmdResult = cmd.exec ? cmd.exec(this, args || {}) : cmd(this, args || {}); if (!result && cmdResult !== undefined) result = cmdResult; tmpSel.toOrientedRange(ranges[i]); } tmpSel.detach(); this.selection = session.selection = selection; this.inVirtualSelectionMode = false; selection._eventRegistry = reg; selection.mergeOverlappingRanges(); var anim = this.renderer.$scrollAnimation; this.onCursorChange(); this.onSelectionChange(); if (anim && anim.from == anim.to) this.renderer.animateScrolling(anim.from); return result; }; this.exitMultiSelectMode = function() { if (!this.inMultiSelectMode || this.inVirtualSelectionMode) return; this.multiSelect.toSingleRange(); }; this.getSelectedText = function() { var text = ""; if (this.inMultiSelectMode && !this.inVirtualSelectionMode) { var ranges = this.multiSelect.rangeList.ranges; var buf = []; for (var i = 0; i < ranges.length; i++) { buf.push(this.session.getTextRange(ranges[i])); } var nl = this.session.getDocument().getNewLineCharacter(); text = buf.join(nl); if (text.length == (buf.length - 1) * nl.length) text = ""; } else if (!this.selection.isEmpty()) { text = this.session.getTextRange(this.getSelectionRange()); } return text; }; this.$checkMultiselectChange = function(e, anchor) { if (this.inMultiSelectMode && !this.inVirtualSelectionMode) { var range = this.multiSelect.ranges[0]; if (this.multiSelect.isEmpty() && anchor == this.multiSelect.anchor) return; var pos = anchor == this.multiSelect.anchor ? range.cursor == range.start ? range.end : range.start : range.cursor; if (!isSamePoint(pos, anchor)) this.multiSelect.toSingleRange(this.multiSelect.toOrientedRange()); } }; this.onPaste = function(text) { if (this.$readOnly) return; var e = {text: text}; this._signal("paste", e); text = e.text; if (!this.inMultiSelectMode || this.inVirtualSelectionMode) return this.insert(text); var lines = text.split(/\r\n|\r|\n/); var ranges = this.selection.rangeList.ranges; if (lines.length > ranges.length || lines.length < 2 || !lines[1]) return this.commands.exec("insertstring", this, text); for (var i = ranges.length; i--;) { var range = ranges[i]; if (!range.isEmpty()) this.session.remove(range); this.session.insert(range.start, lines[i]); } }; this.findAll = function(needle, options, additive) { options = options || {}; options.needle = needle || options.needle; if (options.needle == undefined) { var range = this.selection.isEmpty() ? this.selection.getWordRange() : this.selection.getRange(); options.needle = this.session.getTextRange(range); } this.$search.set(options); var ranges = this.$search.findAll(this.session); if (!ranges.length) return 0; this.$blockScrolling += 1; var selection = this.multiSelect; if (!additive) selection.toSingleRange(ranges[0]); for (var i = ranges.length; i--; ) selection.addRange(ranges[i], true); if (range && selection.rangeList.rangeAtPoint(range.start)) selection.addRange(range, true); this.$blockScrolling -= 1; return ranges.length; }; this.selectMoreLines = function(dir, skip) { var range = this.selection.toOrientedRange(); var isBackwards = range.cursor == range.end; var screenLead = this.session.documentToScreenPosition(range.cursor); if (this.selection.$desiredColumn) screenLead.column = this.selection.$desiredColumn; var lead = this.session.screenToDocumentPosition(screenLead.row + dir, screenLead.column); if (!range.isEmpty()) { var screenAnchor = this.session.documentToScreenPosition(isBackwards ? range.end : range.start); var anchor = this.session.screenToDocumentPosition(screenAnchor.row + dir, screenAnchor.column); } else { var anchor = lead; } if (isBackwards) { var newRange = Range.fromPoints(lead, anchor); newRange.cursor = newRange.start; } else { var newRange = Range.fromPoints(anchor, lead); newRange.cursor = newRange.end; } newRange.desiredColumn = screenLead.column; if (!this.selection.inMultiSelectMode) { this.selection.addRange(range); } else { if (skip) var toRemove = range.cursor; } this.selection.addRange(newRange); if (toRemove) this.selection.substractPoint(toRemove); }; this.transposeSelections = function(dir) { var session = this.session; var sel = session.multiSelect; var all = sel.ranges; for (var i = all.length; i--; ) { var range = all[i]; if (range.isEmpty()) { var tmp = session.getWordRange(range.start.row, range.start.column); range.start.row = tmp.start.row; range.start.column = tmp.start.column; range.end.row = tmp.end.row; range.end.column = tmp.end.column; } } sel.mergeOverlappingRanges(); var words = []; for (var i = all.length; i--; ) { var range = all[i]; words.unshift(session.getTextRange(range)); } if (dir < 0) words.unshift(words.pop()); else words.push(words.shift()); for (var i = all.length; i--; ) { var range = all[i]; var tmp = range.clone(); session.replace(range, words[i]); range.start.row = tmp.start.row; range.start.column = tmp.start.column; } }; this.selectMore = function(dir, skip, stopAtFirst) { var session = this.session; var sel = session.multiSelect; var range = sel.toOrientedRange(); if (range.isEmpty()) { range = session.getWordRange(range.start.row, range.start.column); range.cursor = dir == -1 ? range.start : range.end; this.multiSelect.addRange(range); if (stopAtFirst) return; } var needle = session.getTextRange(range); var newRange = find(session, needle, dir); if (newRange) { newRange.cursor = dir == -1 ? newRange.start : newRange.end; this.$blockScrolling += 1; this.session.unfold(newRange); this.multiSelect.addRange(newRange); this.$blockScrolling -= 1; this.renderer.scrollCursorIntoView(null, 0.5); } if (skip) this.multiSelect.substractPoint(range.cursor); }; this.alignCursors = function() { var session = this.session; var sel = session.multiSelect; var ranges = sel.ranges; var row = -1; var sameRowRanges = ranges.filter(function(r) { if (r.cursor.row == row) return true; row = r.cursor.row; }); if (!ranges.length || sameRowRanges.length == ranges.length - 1) { var range = this.selection.getRange(); var fr = range.start.row, lr = range.end.row; var guessRange = fr == lr; if (guessRange) { var max = this.session.getLength(); var line; do { line = this.session.getLine(lr); } while (/[=:]/.test(line) && ++lr < max); do { line = this.session.getLine(fr); } while (/[=:]/.test(line) && --fr > 0); if (fr < 0) fr = 0; if (lr >= max) lr = max - 1; } var lines = this.session.doc.removeLines(fr, lr); lines = this.$reAlignText(lines, guessRange); this.session.doc.insert({row: fr, column: 0}, lines.join("\n") + "\n"); if (!guessRange) { range.start.column = 0; range.end.column = lines[lines.length - 1].length; } this.selection.setRange(range); } else { sameRowRanges.forEach(function(r) { sel.substractPoint(r.cursor); }); var maxCol = 0; var minSpace = Infinity; var spaceOffsets = ranges.map(function(r) { var p = r.cursor; var line = session.getLine(p.row); var spaceOffset = line.substr(p.column).search(/\S/g); if (spaceOffset == -1) spaceOffset = 0; if (p.column > maxCol) maxCol = p.column; if (spaceOffset < minSpace) minSpace = spaceOffset; return spaceOffset; }); ranges.forEach(function(r, i) { var p = r.cursor; var l = maxCol - p.column; var d = spaceOffsets[i] - minSpace; if (l > d) session.insert(p, lang.stringRepeat(" ", l - d)); else session.remove(new Range(p.row, p.column, p.row, p.column - l + d)); r.start.column = r.end.column = maxCol; r.start.row = r.end.row = p.row; r.cursor = r.end; }); sel.fromOrientedRange(ranges[0]); this.renderer.updateCursor(); this.renderer.updateBackMarkers(); } }; this.$reAlignText = function(lines, forceLeft) { var isLeftAligned = true, isRightAligned = true; var startW, textW, endW; return lines.map(function(line) { var m = line.match(/(\s*)(.*?)(\s*)([=:].*)/); if (!m) return [line]; if (startW == null) { startW = m[1].length; textW = m[2].length; endW = m[3].length; return m; } if (startW + textW + endW != m[1].length + m[2].length + m[3].length) isRightAligned = false; if (startW != m[1].length) isLeftAligned = false; if (startW > m[1].length) startW = m[1].length; if (textW < m[2].length) textW = m[2].length; if (endW > m[3].length) endW = m[3].length; return m; }).map(forceLeft ? alignLeft : isLeftAligned ? isRightAligned ? alignRight : alignLeft : unAlign); function spaces(n) { return lang.stringRepeat(" ", n); } function alignLeft(m) { return !m[2] ? m[0] : spaces(startW) + m[2] + spaces(textW - m[2].length + endW) + m[4].replace(/^([=:])\s+/, "$1 "); } function alignRight(m) { return !m[2] ? m[0] : spaces(startW + textW - m[2].length) + m[2] + spaces(endW, " ") + m[4].replace(/^([=:])\s+/, "$1 "); } function unAlign(m) { return !m[2] ? m[0] : spaces(startW) + m[2] + spaces(endW) + m[4].replace(/^([=:])\s+/, "$1 "); } }; }).call(Editor.prototype); function isSamePoint(p1, p2) { return p1.row == p2.row && p1.column == p2.column; } exports.onSessionChange = function(e) { var session = e.session; if (session && !session.multiSelect) { session.$selectionMarkers = []; session.selection.$initRangeList(); session.multiSelect = session.selection; } this.multiSelect = session && session.multiSelect; var oldSession = e.oldSession; if (oldSession) { oldSession.multiSelect.off("addRange", this.$onAddRange); oldSession.multiSelect.off("removeRange", this.$onRemoveRange); oldSession.multiSelect.off("multiSelect", this.$onMultiSelect); oldSession.multiSelect.off("singleSelect", this.$onSingleSelect); oldSession.multiSelect.lead.off("change", this.$checkMultiselectChange); oldSession.multiSelect.anchor.off("change", this.$checkMultiselectChange); } if (session) { session.multiSelect.on("addRange", this.$onAddRange); session.multiSelect.on("removeRange", this.$onRemoveRange); session.multiSelect.on("multiSelect", this.$onMultiSelect); session.multiSelect.on("singleSelect", this.$onSingleSelect); session.multiSelect.lead.on("change", this.$checkMultiselectChange); session.multiSelect.anchor.on("change", this.$checkMultiselectChange); } if (session && this.inMultiSelectMode != session.selection.inMultiSelectMode) { if (session.selection.inMultiSelectMode) this.$onMultiSelect(); else this.$onSingleSelect(); } }; function MultiSelect(editor) { if (editor.$multiselectOnSessionChange) return; editor.$onAddRange = editor.$onAddRange.bind(editor); editor.$onRemoveRange = editor.$onRemoveRange.bind(editor); editor.$onMultiSelect = editor.$onMultiSelect.bind(editor); editor.$onSingleSelect = editor.$onSingleSelect.bind(editor); editor.$multiselectOnSessionChange = exports.onSessionChange.bind(editor); editor.$checkMultiselectChange = editor.$checkMultiselectChange.bind(editor); editor.$multiselectOnSessionChange(editor); editor.on("changeSession", editor.$multiselectOnSessionChange); editor.on("mousedown", onMouseDown); editor.commands.addCommands(commands.defaultCommands); addAltCursorListeners(editor); } function addAltCursorListeners(editor){ var el = editor.textInput.getElement(); var altCursor = false; event.addListener(el, "keydown", function(e) { if (e.keyCode == 18 && !(e.ctrlKey || e.shiftKey || e.metaKey)) { if (!altCursor) { editor.renderer.setMouseCursor("crosshair"); altCursor = true; } } else if (altCursor) { reset(); } }); event.addListener(el, "keyup", reset); event.addListener(el, "blur", reset); function reset(e) { if (altCursor) { editor.renderer.setMouseCursor(""); altCursor = false; } } } exports.MultiSelect = MultiSelect; require("./config").defineOptions(Editor.prototype, "editor", { enableMultiselect: { set: function(val) { MultiSelect(this); if (val) { this.on("changeSession", this.$multiselectOnSessionChange); this.on("mousedown", onMouseDown); } else { this.off("changeSession", this.$multiselectOnSessionChange); this.off("mousedown", onMouseDown); } }, value: true } }); }); ace.define("ace/mode/folding/fold_mode",["require","exports","module","ace/range"], function(require, exports, module) { "use strict"; var Range = require("../../range").Range; var FoldMode = exports.FoldMode = function() {}; (function() { this.foldingStartMarker = null; this.foldingStopMarker = null; this.getFoldWidget = function(session, foldStyle, row) { var line = session.getLine(row); if (this.foldingStartMarker.test(line)) return "start"; if (foldStyle == "markbeginend" && this.foldingStopMarker && this.foldingStopMarker.test(line)) return "end"; return ""; }; this.getFoldWidgetRange = function(session, foldStyle, row) { return null; }; this.indentationBlock = function(session, row, column) { var re = /\S/; var line = session.getLine(row); var startLevel = line.search(re); if (startLevel == -1) return; var startColumn = column || line.length; var maxRow = session.getLength(); var startRow = row; var endRow = row; while (++row < maxRow) { var level = session.getLine(row).search(re); if (level == -1) continue; if (level <= startLevel) break; endRow = row; } if (endRow > startRow) { var endColumn = session.getLine(endRow).length; return new Range(startRow, startColumn, endRow, endColumn); } }; this.openingBracketBlock = function(session, bracket, row, column, typeRe) { var start = {row: row, column: column + 1}; var end = session.$findClosingBracket(bracket, start, typeRe); if (!end) return; var fw = session.foldWidgets[end.row]; if (fw == null) fw = session.getFoldWidget(end.row); if (fw == "start" && end.row > start.row) { end.row --; end.column = session.getLine(end.row).length; } return Range.fromPoints(start, end); }; this.closingBracketBlock = function(session, bracket, row, column, typeRe) { var end = {row: row, column: column}; var start = session.$findOpeningBracket(bracket, end); if (!start) return; start.column++; end.column--; return Range.fromPoints(start, end); }; }).call(FoldMode.prototype); }); ace.define("ace/theme/textmate",["require","exports","module","ace/lib/dom"], function(require, exports, module) { "use strict"; exports.isDark = false; exports.cssClass = "ace-tm"; exports.cssText = ".ace-tm .ace_gutter {\ background: #f0f0f0;\ color: #333;\ }\ .ace-tm .ace_print-margin {\ width: 1px;\ background: #e8e8e8;\ }\ .ace-tm .ace_fold {\ background-color: #6B72E6;\ }\ .ace-tm {\ background-color: #FFFFFF;\ color: black;\ }\ .ace-tm .ace_cursor {\ color: black;\ }\ .ace-tm .ace_invisible {\ color: rgb(191, 191, 191);\ }\ .ace-tm .ace_storage,\ .ace-tm .ace_keyword {\ color: blue;\ }\ .ace-tm .ace_constant {\ color: rgb(197, 6, 11);\ }\ .ace-tm .ace_constant.ace_buildin {\ color: rgb(88, 72, 246);\ }\ .ace-tm .ace_constant.ace_language {\ color: rgb(88, 92, 246);\ }\ .ace-tm .ace_constant.ace_library {\ color: rgb(6, 150, 14);\ }\ .ace-tm .ace_invalid {\ background-color: rgba(255, 0, 0, 0.1);\ color: red;\ }\ .ace-tm .ace_support.ace_function {\ color: rgb(60, 76, 114);\ }\ .ace-tm .ace_support.ace_constant {\ color: rgb(6, 150, 14);\ }\ .ace-tm .ace_support.ace_type,\ .ace-tm .ace_support.ace_class {\ color: rgb(109, 121, 222);\ }\ .ace-tm .ace_keyword.ace_operator {\ color: rgb(104, 118, 135);\ }\ .ace-tm .ace_string {\ color: rgb(3, 106, 7);\ }\ .ace-tm .ace_comment {\ color: rgb(76, 136, 107);\ }\ .ace-tm .ace_comment.ace_doc {\ color: rgb(0, 102, 255);\ }\ .ace-tm .ace_comment.ace_doc.ace_tag {\ color: rgb(128, 159, 191);\ }\ .ace-tm .ace_constant.ace_numeric {\ color: rgb(0, 0, 205);\ }\ .ace-tm .ace_variable {\ color: rgb(49, 132, 149);\ }\ .ace-tm .ace_xml-pe {\ color: rgb(104, 104, 91);\ }\ .ace-tm .ace_entity.ace_name.ace_function {\ color: #0000A2;\ }\ .ace-tm .ace_heading {\ color: rgb(12, 7, 255);\ }\ .ace-tm .ace_list {\ color:rgb(185, 6, 144);\ }\ .ace-tm .ace_meta.ace_tag {\ color:rgb(0, 22, 142);\ }\ .ace-tm .ace_string.ace_regex {\ color: rgb(255, 0, 0)\ }\ .ace-tm .ace_marker-layer .ace_selection {\ background: rgb(181, 213, 255);\ }\ .ace-tm.ace_multiselect .ace_selection.ace_start {\ box-shadow: 0 0 3px 0px white;\ border-radius: 2px;\ }\ .ace-tm .ace_marker-layer .ace_step {\ background: rgb(252, 255, 0);\ }\ .ace-tm .ace_marker-layer .ace_stack {\ background: rgb(164, 229, 101);\ }\ .ace-tm .ace_marker-layer .ace_bracket {\ margin: -1px 0 0 -1px;\ border: 1px solid rgb(192, 192, 192);\ }\ .ace-tm .ace_marker-layer .ace_active-line {\ background: rgba(0, 0, 0, 0.07);\ }\ .ace-tm .ace_gutter-active-line {\ background-color : #dcdcdc;\ }\ .ace-tm .ace_marker-layer .ace_selected-word {\ background: rgb(250, 250, 255);\ border: 1px solid rgb(200, 200, 250);\ }\ .ace-tm .ace_indent-guide {\ background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\ }\ "; var dom = require("../lib/dom"); dom.importCssString(exports.cssText, exports.cssClass); }); ace.define("ace/line_widgets",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/range"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var dom = require("./lib/dom"); var Range = require("./range").Range; function LineWidgets(session) { this.session = session; this.session.widgetManager = this; this.session.getRowLength = this.getRowLength; this.session.$getWidgetScreenLength = this.$getWidgetScreenLength; this.updateOnChange = this.updateOnChange.bind(this); this.renderWidgets = this.renderWidgets.bind(this); this.measureWidgets = this.measureWidgets.bind(this); this.session._changedWidgets = []; this.$onChangeEditor = this.$onChangeEditor.bind(this); this.session.on("change", this.updateOnChange); this.session.on("changeEditor", this.$onChangeEditor); } (function() { this.getRowLength = function(row) { var h; if (this.lineWidgets) h = this.lineWidgets[row] && this.lineWidgets[row].rowCount || 0; else h = 0; if (!this.$useWrapMode || !this.$wrapData[row]) { return 1 + h; } else { return this.$wrapData[row].length + 1 + h; } }; this.$getWidgetScreenLength = function() { var screenRows = 0; this.lineWidgets.forEach(function(w){ if (w && w.rowCount) screenRows +=w.rowCount; }); return screenRows; }; this.$onChangeEditor = function(e) { this.attach(e.editor); }; this.attach = function(editor) { if (editor && editor.widgetManager && editor.widgetManager != this) editor.widgetManager.detach(); if (this.editor == editor) return; this.detach(); this.editor = editor; if (editor) { editor.widgetManager = this; editor.renderer.on("beforeRender", this.measureWidgets); editor.renderer.on("afterRender", this.renderWidgets); } }; this.detach = function(e) { var editor = this.editor; if (!editor) return; this.editor = null; editor.widgetManager = null; editor.renderer.off("beforeRender", this.measureWidgets); editor.renderer.off("afterRender", this.renderWidgets); var lineWidgets = this.session.lineWidgets; lineWidgets && lineWidgets.forEach(function(w) { if (w && w.el && w.el.parentNode) { w._inDocument = false; w.el.parentNode.removeChild(w.el); } }); }; this.updateOnChange = function(e) { var lineWidgets = this.session.lineWidgets; if (!lineWidgets) return; var delta = e.data; var range = delta.range; var startRow = range.start.row; var len = range.end.row - startRow; if (len === 0) { } else if (delta.action == "removeText" || delta.action == "removeLines") { var removed = lineWidgets.splice(startRow + 1, len); removed.forEach(function(w) { w && this.removeLineWidget(w); }, this); this.$updateRows(); } else { var args = new Array(len); args.unshift(startRow, 0); lineWidgets.splice.apply(lineWidgets, args); this.$updateRows(); } }; this.$updateRows = function() { var lineWidgets = this.session.lineWidgets; if (!lineWidgets) return; var noWidgets = true; lineWidgets.forEach(function(w, i) { if (w) { noWidgets = false; w.row = i; } }); if (noWidgets) this.session.lineWidgets = null; }; this.addLineWidget = function(w) { if (!this.session.lineWidgets) this.session.lineWidgets = new Array(this.session.getLength()); this.session.lineWidgets[w.row] = w; var renderer = this.editor.renderer; if (w.html && !w.el) { w.el = dom.createElement("div"); w.el.innerHTML = w.html; } if (w.el) { dom.addCssClass(w.el, "ace_lineWidgetContainer"); w.el.style.position = "absolute"; w.el.style.zIndex = 5; renderer.container.appendChild(w.el); w._inDocument = true; } if (!w.coverGutter) { w.el.style.zIndex = 3; } if (!w.pixelHeight) { w.pixelHeight = w.el.offsetHeight; } if (w.rowCount == null) w.rowCount = w.pixelHeight / renderer.layerConfig.lineHeight; this.session._emit("changeFold", {data:{start:{row: w.row}}}); this.$updateRows(); this.renderWidgets(null, renderer); return w; }; this.removeLineWidget = function(w) { w._inDocument = false; if (w.el && w.el.parentNode) w.el.parentNode.removeChild(w.el); if (w.editor && w.editor.destroy) try { w.editor.destroy(); } catch(e){} if (this.session.lineWidgets) this.session.lineWidgets[w.row] = undefined; this.session._emit("changeFold", {data:{start:{row: w.row}}}); this.$updateRows(); }; this.onWidgetChanged = function(w) { this.session._changedWidgets.push(w); this.editor && this.editor.renderer.updateFull(); }; this.measureWidgets = function(e, renderer) { var changedWidgets = this.session._changedWidgets; var config = renderer.layerConfig; if (!changedWidgets || !changedWidgets.length) return; var min = Infinity; for (var i = 0; i < changedWidgets.length; i++) { var w = changedWidgets[i]; if (!w._inDocument) { w._inDocument = true; renderer.container.appendChild(w.el); } w.h = w.el.offsetHeight; if (!w.fixedWidth) { w.w = w.el.offsetWidth; w.screenWidth = Math.ceil(w.w / config.characterWidth); } var rowCount = w.h / config.lineHeight; if (w.coverLine) { rowCount -= this.session.getRowLineCount(w.row); if (rowCount < 0) rowCount = 0; } if (w.rowCount != rowCount) { w.rowCount = rowCount; if (w.row < min) min = w.row; } } if (min != Infinity) { this.session._emit("changeFold", {data:{start:{row: min}}}); this.session.lineWidgetWidth = null; } this.session._changedWidgets = []; }; this.renderWidgets = function(e, renderer) { var config = renderer.layerConfig; var lineWidgets = this.session.lineWidgets; if (!lineWidgets) return; var first = Math.min(this.firstRow, config.firstRow); var last = Math.max(this.lastRow, config.lastRow, lineWidgets.length); while (first > 0 && !lineWidgets[first]) first--; this.firstRow = config.firstRow; this.lastRow = config.lastRow; renderer.$cursorLayer.config = config; for (var i = first; i <= last; i++) { var w = lineWidgets[i]; if (!w || !w.el) continue; if (!w._inDocument) { w._inDocument = true; renderer.container.appendChild(w.el); } var top = renderer.$cursorLayer.getPixelPosition({row: i, column:0}, true).top; if (!w.coverLine) top += config.lineHeight * this.session.getRowLineCount(w.row); w.el.style.top = top - config.offset + "px"; var left = w.coverGutter ? 0 : renderer.gutterWidth; if (!w.fixedWidth) left -= renderer.scrollLeft; w.el.style.left = left + "px"; if (w.fixedWidth) { w.el.style.right = renderer.scrollBar.getWidth() + "px"; } else { w.el.style.right = ""; } } }; }).call(LineWidgets.prototype); exports.LineWidgets = LineWidgets; }); ace.define("ace/ext/error_marker",["require","exports","module","ace/line_widgets","ace/lib/dom","ace/range"], function(require, exports, module) { "use strict"; var LineWidgets = require("../line_widgets").LineWidgets; var dom = require("../lib/dom"); var Range = require("../range").Range; function binarySearch(array, needle, comparator) { var first = 0; var last = array.length - 1; while (first <= last) { var mid = (first + last) >> 1; var c = comparator(needle, array[mid]); if (c > 0) first = mid + 1; else if (c < 0) last = mid - 1; else return mid; } return -(first + 1); } function findAnnotations(session, row, dir) { var annotations = session.getAnnotations().sort(Range.comparePoints); if (!annotations.length) return; var i = binarySearch(annotations, {row: row, column: -1}, Range.comparePoints); if (i < 0) i = -i - 1; if (i >= annotations.length - 1) i = dir > 0 ? 0 : annotations.length - 1; else if (i === 0 && dir < 0) i = annotations.length - 1; var annotation = annotations[i]; if (!annotation || !dir) return; if (annotation.row === row) { do { annotation = annotations[i += dir]; } while (annotation && annotation.row === row); if (!annotation) return annotations.slice(); } var matched = []; row = annotation.row; do { matched[dir < 0 ? "unshift" : "push"](annotation); annotation = annotations[i += dir]; } while (annotation && annotation.row == row); return matched.length && matched; } exports.showErrorMarker = function(editor, dir) { var session = editor.session; if (!session.widgetManager) { session.widgetManager = new LineWidgets(session); session.widgetManager.attach(editor); } var pos = editor.getCursorPosition(); var row = pos.row; var oldWidget = session.lineWidgets && session.lineWidgets[row]; if (oldWidget) { oldWidget.destroy(); } else { row -= dir; } var annotations = findAnnotations(session, row, dir); var gutterAnno; if (annotations) { var annotation = annotations[0]; pos.column = (annotation.pos && typeof annotation.column != "number" ? annotation.pos.sc : annotation.column) || 0; pos.row = annotation.row; gutterAnno = editor.renderer.$gutterLayer.$annotations[pos.row]; } else if (oldWidget) { return; } else { gutterAnno = { text: ["Looks good!"], className: "ace_ok" }; } editor.session.unfold(pos.row); editor.selection.moveToPosition(pos); var w = { row: pos.row, fixedWidth: true, coverGutter: true, el: dom.createElement("div") }; var el = w.el.appendChild(dom.createElement("div")); var arrow = w.el.appendChild(dom.createElement("div")); arrow.className = "error_widget_arrow " + gutterAnno.className; var left = editor.renderer.$cursorLayer .getPixelPosition(pos).left; arrow.style.left = left + editor.renderer.gutterWidth - 5 + "px"; w.el.className = "error_widget_wrapper"; el.className = "error_widget " + gutterAnno.className; el.innerHTML = gutterAnno.text.join("
"); el.appendChild(dom.createElement("div")); var kb = function(_, hashId, keyString) { if (hashId === 0 && (keyString === "esc" || keyString === "return")) { w.destroy(); return {command: "null"}; } }; w.destroy = function() { if (editor.$mouseHandler.isMousePressed) return; editor.keyBinding.removeKeyboardHandler(kb); session.widgetManager.removeLineWidget(w); editor.off("changeSelection", w.destroy); editor.off("changeSession", w.destroy); editor.off("mouseup", w.destroy); editor.off("change", w.destroy); }; editor.keyBinding.addKeyboardHandler(kb); editor.on("changeSelection", w.destroy); editor.on("changeSession", w.destroy); editor.on("mouseup", w.destroy); editor.on("change", w.destroy); editor.session.widgetManager.addLineWidget(w); w.el.onmousedown = editor.focus.bind(editor); editor.renderer.scrollCursorIntoView(null, 0.5, {bottom: w.el.offsetHeight}); }; dom.importCssString("\ .error_widget_wrapper {\ background: inherit;\ color: inherit;\ border:none\ }\ .error_widget {\ border-top: solid 2px;\ border-bottom: solid 2px;\ margin: 5px 0;\ padding: 10px 40px;\ white-space: pre-wrap;\ }\ .error_widget.ace_error, .error_widget_arrow.ace_error{\ border-color: #ff5a5a\ }\ .error_widget.ace_warning, .error_widget_arrow.ace_warning{\ border-color: #F1D817\ }\ .error_widget.ace_info, .error_widget_arrow.ace_info{\ border-color: #5a5a5a\ }\ .error_widget.ace_ok, .error_widget_arrow.ace_ok{\ border-color: #5aaa5a\ }\ .error_widget_arrow {\ position: absolute;\ border: solid 5px;\ border-top-color: transparent!important;\ border-right-color: transparent!important;\ border-left-color: transparent!important;\ top: -5px;\ }\ ", ""); }); ace.define("ace/ace",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/dom","ace/lib/event","ace/editor","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/worker/worker_client","ace/keyboard/hash_handler","ace/placeholder","ace/multi_select","ace/mode/folding/fold_mode","ace/theme/textmate","ace/ext/error_marker","ace/config"], function(require, exports, module) { "use strict"; require("./lib/fixoldbrowsers"); var dom = require("./lib/dom"); var event = require("./lib/event"); var Editor = require("./editor").Editor; var EditSession = require("./edit_session").EditSession; var UndoManager = require("./undomanager").UndoManager; var Renderer = require("./virtual_renderer").VirtualRenderer; require("./worker/worker_client"); require("./keyboard/hash_handler"); require("./placeholder"); require("./multi_select"); require("./mode/folding/fold_mode"); require("./theme/textmate"); require("./ext/error_marker"); exports.config = require("./config"); exports.require = require; exports.edit = function(el) { if (typeof(el) == "string") { var _id = el; el = document.getElementById(_id); if (!el) throw new Error("ace.edit can't find div #" + _id); } if (el && el.env && el.env.editor instanceof Editor) return el.env.editor; var value = ""; if (el && /input|textarea/i.test(el.tagName)) { var oldNode = el; value = oldNode.value; el = dom.createElement("pre"); oldNode.parentNode.replaceChild(el, oldNode); } else { value = dom.getInnerText(el); el.innerHTML = ''; } var doc = exports.createEditSession(value); var editor = new Editor(new Renderer(el)); editor.setSession(doc); var env = { document: doc, editor: editor, onResize: editor.resize.bind(editor, null) }; if (oldNode) env.textarea = oldNode; event.addListener(window, "resize", env.onResize); editor.on("destroy", function() { event.removeListener(window, "resize", env.onResize); env.editor.container.env = null; // prevent memory leak on old ie }); editor.container.env = editor.env = env; return editor; }; exports.createEditSession = function(text, mode) { var doc = new EditSession(text, mode); doc.setUndoManager(new UndoManager()); return doc; } exports.EditSession = EditSession; exports.UndoManager = UndoManager; }); (function() { ace.require(["ace/ace"], function(a) { a && a.config.init(true); if (!window.ace) window.ace = a; for (var key in a) if (a.hasOwnProperty(key)) window.ace[key] = a[key]; }); })(); Swagger2-0.73/lib/Swagger2/public/cache/000755 000765 000024 00000000000 12660346320 021045 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/lib/Swagger2/public/mode-json.js000644 000765 000024 00000055004 12645227324 022244 0ustar00jhthorsenstaff000000 000000 ace.define("ace/mode/json_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function(require, exports, module) { "use strict"; var oop = require("../lib/oop"); var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var JsonHighlightRules = function() { this.$rules = { "start" : [ { token : "variable", // single line regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)' }, { token : "string", // single line regex : '"', next : "string" }, { token : "constant.numeric", // hex regex : "0[xX][0-9a-fA-F]+\\b" }, { token : "constant.numeric", // float regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" }, { token : "constant.language.boolean", regex : "(?:true|false)\\b" }, { token : "invalid.illegal", // single quoted strings are not allowed regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" }, { token : "invalid.illegal", // comments are not allowed regex : "\\/\\/.*$" }, { token : "paren.lparen", regex : "[[({]" }, { token : "paren.rparen", regex : "[\\])}]" }, { token : "text", regex : "\\s+" } ], "string" : [ { token : "constant.language.escape", regex : /\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|["\\\/bfnrt])/ }, { token : "string", regex : '[^"\\\\]+' }, { token : "string", regex : '"', next : "start" }, { token : "string", regex : "", next : "start" } ] }; }; oop.inherits(JsonHighlightRules, TextHighlightRules); exports.JsonHighlightRules = JsonHighlightRules; }); ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"], function(require, exports, module) { "use strict"; var Range = require("../range").Range; var MatchingBraceOutdent = function() {}; (function() { this.checkOutdent = function(line, input) { if (! /^\s+$/.test(line)) return false; return /^\s*\}/.test(input); }; this.autoOutdent = function(doc, row) { var line = doc.getLine(row); var match = line.match(/^(\s*\})/); if (!match) return 0; var column = match[1].length; var openBracePos = doc.findMatchingBracket({row: row, column: column}); if (!openBracePos || openBracePos.row == row) return 0; var indent = this.$getIndent(doc.getLine(openBracePos.row)); doc.replace(new Range(row, 0, row, column-1), indent); }; this.$getIndent = function(line) { return line.match(/^\s*/)[0]; }; }).call(MatchingBraceOutdent.prototype); exports.MatchingBraceOutdent = MatchingBraceOutdent; }); ace.define("ace/mode/behaviour/cstyle",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"], function(require, exports, module) { "use strict"; var oop = require("../../lib/oop"); var Behaviour = require("../behaviour").Behaviour; var TokenIterator = require("../../token_iterator").TokenIterator; var lang = require("../../lib/lang"); var SAFE_INSERT_IN_TOKENS = ["text", "paren.rparen", "punctuation.operator"]; var SAFE_INSERT_BEFORE_TOKENS = ["text", "paren.rparen", "punctuation.operator", "comment"]; var context; var contextCache = {}; var initContext = function(editor) { var id = -1; if (editor.multiSelect) { id = editor.selection.index; if (contextCache.rangeCount != editor.multiSelect.rangeCount) contextCache = {rangeCount: editor.multiSelect.rangeCount}; } if (contextCache[id]) return context = contextCache[id]; context = contextCache[id] = { autoInsertedBrackets: 0, autoInsertedRow: -1, autoInsertedLineEnd: "", maybeInsertedBrackets: 0, maybeInsertedRow: -1, maybeInsertedLineStart: "", maybeInsertedLineEnd: "" }; }; var CstyleBehaviour = function() { this.add("braces", "insertion", function(state, action, editor, session, text) { var cursor = editor.getCursorPosition(); var line = session.doc.getLine(cursor.row); if (text == '{') { initContext(editor); var selection = editor.getSelectionRange(); var selected = session.doc.getTextRange(selection); if (selected !== "" && selected !== "{" && editor.getWrapBehavioursEnabled()) { return { text: '{' + selected + '}', selection: false }; } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { if (/[\]\}\)]/.test(line[cursor.column]) || editor.inMultiSelectMode) { CstyleBehaviour.recordAutoInsert(editor, session, "}"); return { text: '{}', selection: [1, 1] }; } else { CstyleBehaviour.recordMaybeInsert(editor, session, "{"); return { text: '{', selection: [1, 1] }; } } } else if (text == '}') { initContext(editor); var rightChar = line.substring(cursor.column, cursor.column + 1); if (rightChar == '}') { var matching = session.$findOpeningBracket('}', {column: cursor.column + 1, row: cursor.row}); if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { CstyleBehaviour.popAutoInsertedClosing(); return { text: '', selection: [1, 1] }; } } } else if (text == "\n" || text == "\r\n") { initContext(editor); var closing = ""; if (CstyleBehaviour.isMaybeInsertedClosing(cursor, line)) { closing = lang.stringRepeat("}", context.maybeInsertedBrackets); CstyleBehaviour.clearMaybeInsertedClosing(); } var rightChar = line.substring(cursor.column, cursor.column + 1); if (rightChar === '}') { var openBracePos = session.findMatchingBracket({row: cursor.row, column: cursor.column+1}, '}'); if (!openBracePos) return null; var next_indent = this.$getIndent(session.getLine(openBracePos.row)); } else if (closing) { var next_indent = this.$getIndent(line); } else { CstyleBehaviour.clearMaybeInsertedClosing(); return; } var indent = next_indent + session.getTabString(); return { text: '\n' + indent + '\n' + next_indent + closing, selection: [1, indent.length, 1, indent.length] }; } else { CstyleBehaviour.clearMaybeInsertedClosing(); } }); this.add("braces", "deletion", function(state, action, editor, session, range) { var selected = session.doc.getTextRange(range); if (!range.isMultiLine() && selected == '{') { initContext(editor); var line = session.doc.getLine(range.start.row); var rightChar = line.substring(range.end.column, range.end.column + 1); if (rightChar == '}') { range.end.column++; return range; } else { context.maybeInsertedBrackets--; } } }); this.add("parens", "insertion", function(state, action, editor, session, text) { if (text == '(') { initContext(editor); var selection = editor.getSelectionRange(); var selected = session.doc.getTextRange(selection); if (selected !== "" && editor.getWrapBehavioursEnabled()) { return { text: '(' + selected + ')', selection: false }; } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { CstyleBehaviour.recordAutoInsert(editor, session, ")"); return { text: '()', selection: [1, 1] }; } } else if (text == ')') { initContext(editor); var cursor = editor.getCursorPosition(); var line = session.doc.getLine(cursor.row); var rightChar = line.substring(cursor.column, cursor.column + 1); if (rightChar == ')') { var matching = session.$findOpeningBracket(')', {column: cursor.column + 1, row: cursor.row}); if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { CstyleBehaviour.popAutoInsertedClosing(); return { text: '', selection: [1, 1] }; } } } }); this.add("parens", "deletion", function(state, action, editor, session, range) { var selected = session.doc.getTextRange(range); if (!range.isMultiLine() && selected == '(') { initContext(editor); var line = session.doc.getLine(range.start.row); var rightChar = line.substring(range.start.column + 1, range.start.column + 2); if (rightChar == ')') { range.end.column++; return range; } } }); this.add("brackets", "insertion", function(state, action, editor, session, text) { if (text == '[') { initContext(editor); var selection = editor.getSelectionRange(); var selected = session.doc.getTextRange(selection); if (selected !== "" && editor.getWrapBehavioursEnabled()) { return { text: '[' + selected + ']', selection: false }; } else if (CstyleBehaviour.isSaneInsertion(editor, session)) { CstyleBehaviour.recordAutoInsert(editor, session, "]"); return { text: '[]', selection: [1, 1] }; } } else if (text == ']') { initContext(editor); var cursor = editor.getCursorPosition(); var line = session.doc.getLine(cursor.row); var rightChar = line.substring(cursor.column, cursor.column + 1); if (rightChar == ']') { var matching = session.$findOpeningBracket(']', {column: cursor.column + 1, row: cursor.row}); if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) { CstyleBehaviour.popAutoInsertedClosing(); return { text: '', selection: [1, 1] }; } } } }); this.add("brackets", "deletion", function(state, action, editor, session, range) { var selected = session.doc.getTextRange(range); if (!range.isMultiLine() && selected == '[') { initContext(editor); var line = session.doc.getLine(range.start.row); var rightChar = line.substring(range.start.column + 1, range.start.column + 2); if (rightChar == ']') { range.end.column++; return range; } } }); this.add("string_dquotes", "insertion", function(state, action, editor, session, text) { if (text == '"' || text == "'") { initContext(editor); var quote = text; var selection = editor.getSelectionRange(); var selected = session.doc.getTextRange(selection); if (selected !== "" && selected !== "'" && selected != '"' && editor.getWrapBehavioursEnabled()) { return { text: quote + selected + quote, selection: false }; } else { var cursor = editor.getCursorPosition(); var line = session.doc.getLine(cursor.row); var leftChar = line.substring(cursor.column-1, cursor.column); if (leftChar == '\\') { return null; } var tokens = session.getTokens(selection.start.row); var col = 0, token; var quotepos = -1; // Track whether we're inside an open quote. for (var x = 0; x < tokens.length; x++) { token = tokens[x]; if (token.type == "string") { quotepos = -1; } else if (quotepos < 0) { quotepos = token.value.indexOf(quote); } if ((token.value.length + col) > selection.start.column) { break; } col += tokens[x].value.length; } if (!token || (quotepos < 0 && token.type !== "comment" && (token.type !== "string" || ((selection.start.column !== token.value.length+col-1) && token.value.lastIndexOf(quote) === token.value.length-1)))) { if (!CstyleBehaviour.isSaneInsertion(editor, session)) return; return { text: quote + quote, selection: [1,1] }; } else if (token && token.type === "string") { var rightChar = line.substring(cursor.column, cursor.column + 1); if (rightChar == quote) { return { text: '', selection: [1, 1] }; } } } } }); this.add("string_dquotes", "deletion", function(state, action, editor, session, range) { var selected = session.doc.getTextRange(range); if (!range.isMultiLine() && (selected == '"' || selected == "'")) { initContext(editor); var line = session.doc.getLine(range.start.row); var rightChar = line.substring(range.start.column + 1, range.start.column + 2); if (rightChar == selected) { range.end.column++; return range; } } }); }; CstyleBehaviour.isSaneInsertion = function(editor, session) { var cursor = editor.getCursorPosition(); var iterator = new TokenIterator(session, cursor.row, cursor.column); if (!this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) { var iterator2 = new TokenIterator(session, cursor.row, cursor.column + 1); if (!this.$matchTokenType(iterator2.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) return false; } iterator.stepForward(); return iterator.getCurrentTokenRow() !== cursor.row || this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_BEFORE_TOKENS); }; CstyleBehaviour.$matchTokenType = function(token, types) { return types.indexOf(token.type || token) > -1; }; CstyleBehaviour.recordAutoInsert = function(editor, session, bracket) { var cursor = editor.getCursorPosition(); var line = session.doc.getLine(cursor.row); if (!this.isAutoInsertedClosing(cursor, line, context.autoInsertedLineEnd[0])) context.autoInsertedBrackets = 0; context.autoInsertedRow = cursor.row; context.autoInsertedLineEnd = bracket + line.substr(cursor.column); context.autoInsertedBrackets++; }; CstyleBehaviour.recordMaybeInsert = function(editor, session, bracket) { var cursor = editor.getCursorPosition(); var line = session.doc.getLine(cursor.row); if (!this.isMaybeInsertedClosing(cursor, line)) context.maybeInsertedBrackets = 0; context.maybeInsertedRow = cursor.row; context.maybeInsertedLineStart = line.substr(0, cursor.column) + bracket; context.maybeInsertedLineEnd = line.substr(cursor.column); context.maybeInsertedBrackets++; }; CstyleBehaviour.isAutoInsertedClosing = function(cursor, line, bracket) { return context.autoInsertedBrackets > 0 && cursor.row === context.autoInsertedRow && bracket === context.autoInsertedLineEnd[0] && line.substr(cursor.column) === context.autoInsertedLineEnd; }; CstyleBehaviour.isMaybeInsertedClosing = function(cursor, line) { return context.maybeInsertedBrackets > 0 && cursor.row === context.maybeInsertedRow && line.substr(cursor.column) === context.maybeInsertedLineEnd && line.substr(0, cursor.column) == context.maybeInsertedLineStart; }; CstyleBehaviour.popAutoInsertedClosing = function() { context.autoInsertedLineEnd = context.autoInsertedLineEnd.substr(1); context.autoInsertedBrackets--; }; CstyleBehaviour.clearMaybeInsertedClosing = function() { if (context) { context.maybeInsertedBrackets = 0; context.maybeInsertedRow = -1; } }; oop.inherits(CstyleBehaviour, Behaviour); exports.CstyleBehaviour = CstyleBehaviour; }); ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"], function(require, exports, module) { "use strict"; var oop = require("../../lib/oop"); var Range = require("../../range").Range; var BaseFoldMode = require("./fold_mode").FoldMode; var FoldMode = exports.FoldMode = function(commentRegex) { if (commentRegex) { this.foldingStartMarker = new RegExp( this.foldingStartMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.start) ); this.foldingStopMarker = new RegExp( this.foldingStopMarker.source.replace(/\|[^|]*?$/, "|" + commentRegex.end) ); } }; oop.inherits(FoldMode, BaseFoldMode); (function() { this.foldingStartMarker = /(\{|\[)[^\}\]]*$|^\s*(\/\*)/; this.foldingStopMarker = /^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/; this.getFoldWidgetRange = function(session, foldStyle, row, forceMultiline) { var line = session.getLine(row); var match = line.match(this.foldingStartMarker); if (match) { var i = match.index; if (match[1]) return this.openingBracketBlock(session, match[1], row, i); var range = session.getCommentFoldRange(row, i + match[0].length, 1); if (range && !range.isMultiLine()) { if (forceMultiline) { range = this.getSectionRange(session, row); } else if (foldStyle != "all") range = null; } return range; } if (foldStyle === "markbegin") return; var match = line.match(this.foldingStopMarker); if (match) { var i = match.index + match[0].length; if (match[1]) return this.closingBracketBlock(session, match[1], row, i); return session.getCommentFoldRange(row, i, -1); } }; this.getSectionRange = function(session, row) { var line = session.getLine(row); var startIndent = line.search(/\S/); var startRow = row; var startColumn = line.length; row = row + 1; var endRow = row; var maxRow = session.getLength(); while (++row < maxRow) { line = session.getLine(row); var indent = line.search(/\S/); if (indent === -1) continue; if (startIndent > indent) break; var subRange = this.getFoldWidgetRange(session, "all", row); if (subRange) { if (subRange.start.row <= startRow) { break; } else if (subRange.isMultiLine()) { row = subRange.end.row; } else if (startIndent == indent) { break; } } endRow = row; } return new Range(startRow, startColumn, endRow, session.getLine(endRow).length); }; }).call(FoldMode.prototype); }); ace.define("ace/mode/json",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/json_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/behaviour/cstyle","ace/mode/folding/cstyle","ace/worker/worker_client"], function(require, exports, module) { "use strict"; var oop = require("../lib/oop"); var TextMode = require("./text").Mode; var HighlightRules = require("./json_highlight_rules").JsonHighlightRules; var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; var CstyleBehaviour = require("./behaviour/cstyle").CstyleBehaviour; var CStyleFoldMode = require("./folding/cstyle").FoldMode; var WorkerClient = require("../worker/worker_client").WorkerClient; var Mode = function() { this.HighlightRules = HighlightRules; this.$outdent = new MatchingBraceOutdent(); this.$behaviour = new CstyleBehaviour(); this.foldingRules = new CStyleFoldMode(); }; oop.inherits(Mode, TextMode); (function() { this.getNextLineIndent = function(state, line, tab) { var indent = this.$getIndent(line); if (state == "start") { var match = line.match(/^.*[\{\(\[]\s*$/); if (match) { indent += tab; } } return indent; }; this.checkOutdent = function(state, line, input) { return this.$outdent.checkOutdent(line, input); }; this.autoOutdent = function(state, doc, row) { this.$outdent.autoOutdent(doc, row); }; this.createWorker = function(session) { var worker = new WorkerClient(["ace"], "ace/mode/json_worker", "JsonWorker"); worker.attachToDocument(session.getDocument()); worker.on("error", function(e) { session.setAnnotations([e.data]); }); worker.on("ok", function() { session.clearAnnotations(); }); return worker; }; this.$id = "ace/mode/json"; }).call(Mode.prototype); exports.Mode = Mode; }); Swagger2-0.73/lib/Swagger2/public/mode-yaml.js000644 000765 000024 00000017313 12645227324 022236 0ustar00jhthorsenstaff000000 000000 ace.define("ace/mode/yaml_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function(require, exports, module) { "use strict"; var oop = require("../lib/oop"); var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var YamlHighlightRules = function() { this.$rules = { "start" : [ { token : "comment", regex : "#.*$" }, { token : "list.markup", regex : /^(?:-{3}|\.{3})\s*(?=#|$)/ }, { token : "list.markup", regex : /^\s*[\-?](?:$|\s)/ }, { token: "constant", regex: "!![\\w//]+" }, { token: "constant.language", regex: "[&\\*][a-zA-Z0-9-_]+" }, { token: ["meta.tag", "keyword"], regex: /^(\s*\w.*?)(\:(?:\s+|$))/ },{ token: ["meta.tag", "keyword"], regex: /(\w+?)(\s*\:(?:\s+|$))/ }, { token : "keyword.operator", regex : "<<\\w*:\\w*" }, { token : "keyword.operator", regex : "-\\s*(?=[{])" }, { token : "string", // single line regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' }, { token : "string", // multi line string start regex : '[|>][-+\\d\\s]*$', next : "qqstring" }, { token : "string", // single quoted string regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" }, { token : "constant.numeric", // float regex : /(\b|[+\-\.])[\d_]+(?:(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)/ }, { token : "constant.numeric", // other number regex : /[+\-]?\.inf\b|NaN\b|0x[\dA-Fa-f_]+|0b[10_]+/ }, { token : "constant.language.boolean", regex : "(?:true|false|TRUE|FALSE|True|False|yes|no)\\b" }, { token : "paren.lparen", regex : "[[({]" }, { token : "paren.rparen", regex : "[\\])}]" } ], "qqstring" : [ { token : "string", regex : '(?=(?:(?:\\\\.)|(?:[^:]))*?:)', next : "start" }, { token : "string", regex : '.+' } ]}; }; oop.inherits(YamlHighlightRules, TextHighlightRules); exports.YamlHighlightRules = YamlHighlightRules; }); ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"], function(require, exports, module) { "use strict"; var Range = require("../range").Range; var MatchingBraceOutdent = function() {}; (function() { this.checkOutdent = function(line, input) { if (! /^\s+$/.test(line)) return false; return /^\s*\}/.test(input); }; this.autoOutdent = function(doc, row) { var line = doc.getLine(row); var match = line.match(/^(\s*\})/); if (!match) return 0; var column = match[1].length; var openBracePos = doc.findMatchingBracket({row: row, column: column}); if (!openBracePos || openBracePos.row == row) return 0; var indent = this.$getIndent(doc.getLine(openBracePos.row)); doc.replace(new Range(row, 0, row, column-1), indent); }; this.$getIndent = function(line) { return line.match(/^\s*/)[0]; }; }).call(MatchingBraceOutdent.prototype); exports.MatchingBraceOutdent = MatchingBraceOutdent; }); ace.define("ace/mode/folding/coffee",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range"], function(require, exports, module) { "use strict"; var oop = require("../../lib/oop"); var BaseFoldMode = require("./fold_mode").FoldMode; var Range = require("../../range").Range; var FoldMode = exports.FoldMode = function() {}; oop.inherits(FoldMode, BaseFoldMode); (function() { this.getFoldWidgetRange = function(session, foldStyle, row) { var range = this.indentationBlock(session, row); if (range) return range; var re = /\S/; var line = session.getLine(row); var startLevel = line.search(re); if (startLevel == -1 || line[startLevel] != "#") return; var startColumn = line.length; var maxRow = session.getLength(); var startRow = row; var endRow = row; while (++row < maxRow) { line = session.getLine(row); var level = line.search(re); if (level == -1) continue; if (line[level] != "#") break; endRow = row; } if (endRow > startRow) { var endColumn = session.getLine(endRow).length; return new Range(startRow, startColumn, endRow, endColumn); } }; this.getFoldWidget = function(session, foldStyle, row) { var line = session.getLine(row); var indent = line.search(/\S/); var next = session.getLine(row + 1); var prev = session.getLine(row - 1); var prevIndent = prev.search(/\S/); var nextIndent = next.search(/\S/); if (indent == -1) { session.foldWidgets[row - 1] = prevIndent!= -1 && prevIndent < nextIndent ? "start" : ""; return ""; } if (prevIndent == -1) { if (indent == nextIndent && line[indent] == "#" && next[indent] == "#") { session.foldWidgets[row - 1] = ""; session.foldWidgets[row + 1] = ""; return "start"; } } else if (prevIndent == indent && line[indent] == "#" && prev[indent] == "#") { if (session.getLine(row - 2).search(/\S/) == -1) { session.foldWidgets[row - 1] = "start"; session.foldWidgets[row + 1] = ""; return ""; } } if (prevIndent!= -1 && prevIndent < indent) session.foldWidgets[row - 1] = "start"; else session.foldWidgets[row - 1] = ""; if (indent < nextIndent) return "start"; else return ""; }; }).call(FoldMode.prototype); }); ace.define("ace/mode/yaml",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/yaml_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/folding/coffee"], function(require, exports, module) { "use strict"; var oop = require("../lib/oop"); var TextMode = require("./text").Mode; var YamlHighlightRules = require("./yaml_highlight_rules").YamlHighlightRules; var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; var FoldMode = require("./folding/coffee").FoldMode; var Mode = function() { this.HighlightRules = YamlHighlightRules; this.$outdent = new MatchingBraceOutdent(); this.foldingRules = new FoldMode(); }; oop.inherits(Mode, TextMode); (function() { this.lineCommentStart = "#"; this.getNextLineIndent = function(state, line, tab) { var indent = this.$getIndent(line); if (state == "start") { var match = line.match(/^.*[\{\(\[]\s*$/); if (match) { indent += tab; } } return indent; }; this.checkOutdent = function(state, line, input) { return this.$outdent.checkOutdent(line, input); }; this.autoOutdent = function(state, doc, row) { this.$outdent.autoOutdent(doc, row); }; this.$id = "ace/mode/yaml"; }).call(Mode.prototype); exports.Mode = Mode; }); Swagger2-0.73/lib/Swagger2/public/theme-solarized_dark.js000644 000765 000024 00000005015 12645227324 024443 0ustar00jhthorsenstaff000000 000000 ace.define("ace/theme/solarized_dark",["require","exports","module","ace/lib/dom"], function(require, exports, module) { exports.isDark = true; exports.cssClass = "ace-solarized-dark"; exports.cssText = ".ace-solarized-dark .ace_gutter {\ background: #01313f;\ color: #d0edf7\ }\ .ace-solarized-dark .ace_print-margin {\ width: 1px;\ background: #33555E\ }\ .ace-solarized-dark {\ background-color: #002B36;\ color: #93A1A1\ }\ .ace-solarized-dark .ace_entity.ace_other.ace_attribute-name,\ .ace-solarized-dark .ace_storage {\ color: #93A1A1\ }\ .ace-solarized-dark .ace_cursor,\ .ace-solarized-dark .ace_string.ace_regexp {\ color: #D30102\ }\ .ace-solarized-dark .ace_marker-layer .ace_active-line,\ .ace-solarized-dark .ace_marker-layer .ace_selection {\ background: rgba(255, 255, 255, 0.1)\ }\ .ace-solarized-dark.ace_multiselect .ace_selection.ace_start {\ box-shadow: 0 0 3px 0px #002B36;\ border-radius: 2px\ }\ .ace-solarized-dark .ace_marker-layer .ace_step {\ background: rgb(102, 82, 0)\ }\ .ace-solarized-dark .ace_marker-layer .ace_bracket {\ margin: -1px 0 0 -1px;\ border: 1px solid rgba(147, 161, 161, 0.50)\ }\ .ace-solarized-dark .ace_gutter-active-line {\ background-color: #0d3440\ }\ .ace-solarized-dark .ace_marker-layer .ace_selected-word {\ border: 1px solid #073642\ }\ .ace-solarized-dark .ace_invisible {\ color: rgba(147, 161, 161, 0.50)\ }\ .ace-solarized-dark .ace_keyword,\ .ace-solarized-dark .ace_meta,\ .ace-solarized-dark .ace_support.ace_class,\ .ace-solarized-dark .ace_support.ace_type {\ color: #859900\ }\ .ace-solarized-dark .ace_constant.ace_character,\ .ace-solarized-dark .ace_constant.ace_other {\ color: #CB4B16\ }\ .ace-solarized-dark .ace_constant.ace_language {\ color: #B58900\ }\ .ace-solarized-dark .ace_constant.ace_numeric {\ color: #D33682\ }\ .ace-solarized-dark .ace_fold {\ background-color: #268BD2;\ border-color: #93A1A1\ }\ .ace-solarized-dark .ace_entity.ace_name.ace_function,\ .ace-solarized-dark .ace_entity.ace_name.ace_tag,\ .ace-solarized-dark .ace_support.ace_function,\ .ace-solarized-dark .ace_variable,\ .ace-solarized-dark .ace_variable.ace_language {\ color: #268BD2\ }\ .ace-solarized-dark .ace_string {\ color: #2AA198\ }\ .ace-solarized-dark .ace_comment {\ font-style: italic;\ color: #657B83\ }\ .ace-solarized-dark .ace_indent-guide {\ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNg0Db1ZVCxc/sPAAd4AlUHlLenAAAAAElFTkSuQmCC) right repeat-y\ }"; var dom = require("../lib/dom"); dom.importCssString(exports.cssText, exports.cssClass); }); Swagger2-0.73/lib/Swagger2/public/worker-json.js000644 000765 000024 00000206240 12645227324 022631 0ustar00jhthorsenstaff000000 000000 "no use strict"; ;(function(window) { if (typeof window.window != "undefined" && window.document) { return; } window.console = function() { var msgs = Array.prototype.slice.call(arguments, 0); postMessage({type: "log", data: msgs}); }; window.console.error = window.console.warn = window.console.log = window.console.trace = window.console; window.window = window; window.ace = window; window.onerror = function(message, file, line, col, err) { postMessage({type: "error", data: { message: message, file: file, line: line, col: col, stack: err.stack }}); }; window.normalizeModule = function(parentId, moduleName) { // normalize plugin requires if (moduleName.indexOf("!") !== -1) { var chunks = moduleName.split("!"); return window.normalizeModule(parentId, chunks[0]) + "!" + window.normalizeModule(parentId, chunks[1]); } // normalize relative requires if (moduleName.charAt(0) == ".") { var base = parentId.split("/").slice(0, -1).join("/"); moduleName = (base ? base + "/" : "") + moduleName; while(moduleName.indexOf(".") !== -1 && previous != moduleName) { var previous = moduleName; moduleName = moduleName.replace(/^\.\//, "").replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, ""); } } return moduleName; }; window.require = function(parentId, id) { if (!id) { id = parentId; parentId = null; } if (!id.charAt) throw new Error("worker.js require() accepts only (parentId, id) as arguments"); id = window.normalizeModule(parentId, id); var module = window.require.modules[id]; if (module) { if (!module.initialized) { module.initialized = true; module.exports = module.factory().exports; } return module.exports; } var chunks = id.split("/"); if (!window.require.tlns) return console.log("unable to load " + id); chunks[0] = window.require.tlns[chunks[0]] || chunks[0]; var path = chunks.join("/") + ".js"; window.require.id = id; importScripts(path); return window.require(parentId, id); }; window.require.modules = {}; window.require.tlns = {}; window.define = function(id, deps, factory) { if (arguments.length == 2) { factory = deps; if (typeof id != "string") { deps = id; id = window.require.id; } } else if (arguments.length == 1) { factory = id; deps = []; id = window.require.id; } if (typeof factory != "function") { window.require.modules[id] = { exports: factory, initialized: true }; return; } if (!deps.length) // If there is no dependencies, we inject 'require', 'exports' and // 'module' as dependencies, to provide CommonJS compatibility. deps = ['require', 'exports', 'module']; var req = function(childId) { return window.require(id, childId); }; window.require.modules[id] = { exports: {}, factory: function() { var module = this; var returnExports = factory.apply(this, deps.map(function(dep) { switch(dep) { // Because 'require', 'exports' and 'module' aren't actual // dependencies, we must handle them seperately. case 'require': return req; case 'exports': return module.exports; case 'module': return module; // But for all other dependencies, we can just go ahead and // require them. default: return req(dep); } })); if (returnExports) module.exports = returnExports; return module; } }; }; window.define.amd = {}; window.initBaseUrls = function initBaseUrls(topLevelNamespaces) { require.tlns = topLevelNamespaces; }; window.initSender = function initSender() { var EventEmitter = window.require("ace/lib/event_emitter").EventEmitter; var oop = window.require("ace/lib/oop"); var Sender = function() {}; (function() { oop.implement(this, EventEmitter); this.callback = function(data, callbackId) { postMessage({ type: "call", id: callbackId, data: data }); }; this.emit = function(name, data) { postMessage({ type: "event", name: name, data: data }); }; }).call(Sender.prototype); return new Sender(); }; var main = window.main = null; var sender = window.sender = null; window.onmessage = function(e) { var msg = e.data; if (msg.command) { if (main[msg.command]) main[msg.command].apply(main, msg.args); else throw new Error("Unknown command:" + msg.command); } else if (msg.init) { initBaseUrls(msg.tlns); require("ace/lib/es5-shim"); sender = window.sender = initSender(); var clazz = require(msg.module)[msg.classname]; main = window.main = new clazz(sender); } else if (msg.event && sender) { sender._signal(msg.event, msg.data); } }; })(this); ace.define("ace/lib/oop",["require","exports","module"], function(require, exports, module) { "use strict"; exports.inherits = function(ctor, superCtor) { ctor.super_ = superCtor; ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }); }; exports.mixin = function(obj, mixin) { for (var key in mixin) { obj[key] = mixin[key]; } return obj; }; exports.implement = function(proto, mixin) { exports.mixin(proto, mixin); }; }); ace.define("ace/lib/event_emitter",["require","exports","module"], function(require, exports, module) { "use strict"; var EventEmitter = {}; var stopPropagation = function() { this.propagationStopped = true; }; var preventDefault = function() { this.defaultPrevented = true; }; EventEmitter._emit = EventEmitter._dispatchEvent = function(eventName, e) { this._eventRegistry || (this._eventRegistry = {}); this._defaultHandlers || (this._defaultHandlers = {}); var listeners = this._eventRegistry[eventName] || []; var defaultHandler = this._defaultHandlers[eventName]; if (!listeners.length && !defaultHandler) return; if (typeof e != "object" || !e) e = {}; if (!e.type) e.type = eventName; if (!e.stopPropagation) e.stopPropagation = stopPropagation; if (!e.preventDefault) e.preventDefault = preventDefault; listeners = listeners.slice(); for (var i=0; i [" + this.end.row + "/" + this.end.column + "]"); }; this.contains = function(row, column) { return this.compare(row, column) == 0; }; this.compareRange = function(range) { var cmp, end = range.end, start = range.start; cmp = this.compare(end.row, end.column); if (cmp == 1) { cmp = this.compare(start.row, start.column); if (cmp == 1) { return 2; } else if (cmp == 0) { return 1; } else { return 0; } } else if (cmp == -1) { return -2; } else { cmp = this.compare(start.row, start.column); if (cmp == -1) { return -1; } else if (cmp == 1) { return 42; } else { return 0; } } }; this.comparePoint = function(p) { return this.compare(p.row, p.column); }; this.containsRange = function(range) { return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0; }; this.intersects = function(range) { var cmp = this.compareRange(range); return (cmp == -1 || cmp == 0 || cmp == 1); }; this.isEnd = function(row, column) { return this.end.row == row && this.end.column == column; }; this.isStart = function(row, column) { return this.start.row == row && this.start.column == column; }; this.setStart = function(row, column) { if (typeof row == "object") { this.start.column = row.column; this.start.row = row.row; } else { this.start.row = row; this.start.column = column; } }; this.setEnd = function(row, column) { if (typeof row == "object") { this.end.column = row.column; this.end.row = row.row; } else { this.end.row = row; this.end.column = column; } }; this.inside = function(row, column) { if (this.compare(row, column) == 0) { if (this.isEnd(row, column) || this.isStart(row, column)) { return false; } else { return true; } } return false; }; this.insideStart = function(row, column) { if (this.compare(row, column) == 0) { if (this.isEnd(row, column)) { return false; } else { return true; } } return false; }; this.insideEnd = function(row, column) { if (this.compare(row, column) == 0) { if (this.isStart(row, column)) { return false; } else { return true; } } return false; }; this.compare = function(row, column) { if (!this.isMultiLine()) { if (row === this.start.row) { return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0); }; } if (row < this.start.row) return -1; if (row > this.end.row) return 1; if (this.start.row === row) return column >= this.start.column ? 0 : -1; if (this.end.row === row) return column <= this.end.column ? 0 : 1; return 0; }; this.compareStart = function(row, column) { if (this.start.row == row && this.start.column == column) { return -1; } else { return this.compare(row, column); } }; this.compareEnd = function(row, column) { if (this.end.row == row && this.end.column == column) { return 1; } else { return this.compare(row, column); } }; this.compareInside = function(row, column) { if (this.end.row == row && this.end.column == column) { return 1; } else if (this.start.row == row && this.start.column == column) { return -1; } else { return this.compare(row, column); } }; this.clipRows = function(firstRow, lastRow) { if (this.end.row > lastRow) var end = {row: lastRow + 1, column: 0}; else if (this.end.row < firstRow) var end = {row: firstRow, column: 0}; if (this.start.row > lastRow) var start = {row: lastRow + 1, column: 0}; else if (this.start.row < firstRow) var start = {row: firstRow, column: 0}; return Range.fromPoints(start || this.start, end || this.end); }; this.extend = function(row, column) { var cmp = this.compare(row, column); if (cmp == 0) return this; else if (cmp == -1) var start = {row: row, column: column}; else var end = {row: row, column: column}; return Range.fromPoints(start || this.start, end || this.end); }; this.isEmpty = function() { return (this.start.row === this.end.row && this.start.column === this.end.column); }; this.isMultiLine = function() { return (this.start.row !== this.end.row); }; this.clone = function() { return Range.fromPoints(this.start, this.end); }; this.collapseRows = function() { if (this.end.column == 0) return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0) else return new Range(this.start.row, 0, this.end.row, 0) }; this.toScreenRange = function(session) { var screenPosStart = session.documentToScreenPosition(this.start); var screenPosEnd = session.documentToScreenPosition(this.end); return new Range( screenPosStart.row, screenPosStart.column, screenPosEnd.row, screenPosEnd.column ); }; this.moveBy = function(row, column) { this.start.row += row; this.start.column += column; this.end.row += row; this.end.column += column; }; }).call(Range.prototype); Range.fromPoints = function(start, end) { return new Range(start.row, start.column, end.row, end.column); }; Range.comparePoints = comparePoints; Range.comparePoints = function(p1, p2) { return p1.row - p2.row || p1.column - p2.column; }; exports.Range = Range; }); ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Anchor = exports.Anchor = function(doc, row, column) { this.$onChange = this.onChange.bind(this); this.attach(doc); if (typeof column == "undefined") this.setPosition(row.row, row.column); else this.setPosition(row, column); }; (function() { oop.implement(this, EventEmitter); this.getPosition = function() { return this.$clipPositionToDocument(this.row, this.column); }; this.getDocument = function() { return this.document; }; this.$insertRight = false; this.onChange = function(e) { var delta = e.data; var range = delta.range; if (range.start.row == range.end.row && range.start.row != this.row) return; if (range.start.row > this.row) return; if (range.start.row == this.row && range.start.column > this.column) return; var row = this.row; var column = this.column; var start = range.start; var end = range.end; if (delta.action === "insertText") { if (start.row === row && start.column <= column) { if (start.column === column && this.$insertRight) { } else if (start.row === end.row) { column += end.column - start.column; } else { column -= start.column; row += end.row - start.row; } } else if (start.row !== end.row && start.row < row) { row += end.row - start.row; } } else if (delta.action === "insertLines") { if (start.row === row && column === 0 && this.$insertRight) { } else if (start.row <= row) { row += end.row - start.row; } } else if (delta.action === "removeText") { if (start.row === row && start.column < column) { if (end.column >= column) column = start.column; else column = Math.max(0, column - (end.column - start.column)); } else if (start.row !== end.row && start.row < row) { if (end.row === row) column = Math.max(0, column - end.column) + start.column; row -= (end.row - start.row); } else if (end.row === row) { row -= end.row - start.row; column = Math.max(0, column - end.column) + start.column; } } else if (delta.action == "removeLines") { if (start.row <= row) { if (end.row <= row) row -= end.row - start.row; else { row = start.row; column = 0; } } } this.setPosition(row, column, true); }; this.setPosition = function(row, column, noClip) { var pos; if (noClip) { pos = { row: row, column: column }; } else { pos = this.$clipPositionToDocument(row, column); } if (this.row == pos.row && this.column == pos.column) return; var old = { row: this.row, column: this.column }; this.row = pos.row; this.column = pos.column; this._signal("change", { old: old, value: pos }); }; this.detach = function() { this.document.removeEventListener("change", this.$onChange); }; this.attach = function(doc) { this.document = doc || this.document; this.document.on("change", this.$onChange); }; this.$clipPositionToDocument = function(row, column) { var pos = {}; if (row >= this.document.getLength()) { pos.row = Math.max(0, this.document.getLength() - 1); pos.column = this.document.getLine(pos.row).length; } else if (row < 0) { pos.row = 0; pos.column = 0; } else { pos.row = row; pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column)); } if (column < 0) pos.column = 0; return pos; }; }).call(Anchor.prototype); }); ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) { "use strict"; var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Range = require("./range").Range; var Anchor = require("./anchor").Anchor; var Document = function(text) { this.$lines = []; if (text.length === 0) { this.$lines = [""]; } else if (Array.isArray(text)) { this._insertLines(0, text); } else { this.insert({row: 0, column:0}, text); } }; (function() { oop.implement(this, EventEmitter); this.setValue = function(text) { var len = this.getLength(); this.remove(new Range(0, 0, len, this.getLine(len-1).length)); this.insert({row: 0, column:0}, text); }; this.getValue = function() { return this.getAllLines().join(this.getNewLineCharacter()); }; this.createAnchor = function(row, column) { return new Anchor(this, row, column); }; if ("aaa".split(/a/).length === 0) this.$split = function(text) { return text.replace(/\r\n|\r/g, "\n").split("\n"); }; else this.$split = function(text) { return text.split(/\r\n|\r|\n/); }; this.$detectNewLine = function(text) { var match = text.match(/^.*?(\r\n|\r|\n)/m); this.$autoNewLine = match ? match[1] : "\n"; this._signal("changeNewLineMode"); }; this.getNewLineCharacter = function() { switch (this.$newLineMode) { case "windows": return "\r\n"; case "unix": return "\n"; default: return this.$autoNewLine || "\n"; } }; this.$autoNewLine = ""; this.$newLineMode = "auto"; this.setNewLineMode = function(newLineMode) { if (this.$newLineMode === newLineMode) return; this.$newLineMode = newLineMode; this._signal("changeNewLineMode"); }; this.getNewLineMode = function() { return this.$newLineMode; }; this.isNewLine = function(text) { return (text == "\r\n" || text == "\r" || text == "\n"); }; this.getLine = function(row) { return this.$lines[row] || ""; }; this.getLines = function(firstRow, lastRow) { return this.$lines.slice(firstRow, lastRow + 1); }; this.getAllLines = function() { return this.getLines(0, this.getLength()); }; this.getLength = function() { return this.$lines.length; }; this.getTextRange = function(range) { if (range.start.row == range.end.row) { return this.getLine(range.start.row) .substring(range.start.column, range.end.column); } var lines = this.getLines(range.start.row, range.end.row); lines[0] = (lines[0] || "").substring(range.start.column); var l = lines.length - 1; if (range.end.row - range.start.row == l) lines[l] = lines[l].substring(0, range.end.column); return lines.join(this.getNewLineCharacter()); }; this.$clipPosition = function(position) { var length = this.getLength(); if (position.row >= length) { position.row = Math.max(0, length - 1); position.column = this.getLine(length-1).length; } else if (position.row < 0) position.row = 0; return position; }; this.insert = function(position, text) { if (!text || text.length === 0) return position; position = this.$clipPosition(position); if (this.getLength() <= 1) this.$detectNewLine(text); var lines = this.$split(text); var firstLine = lines.splice(0, 1)[0]; var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0]; position = this.insertInLine(position, firstLine); if (lastLine !== null) { position = this.insertNewLine(position); // terminate first line position = this._insertLines(position.row, lines); position = this.insertInLine(position, lastLine || ""); } return position; }; this.insertLines = function(row, lines) { if (row >= this.getLength()) return this.insert({row: row, column: 0}, "\n" + lines.join("\n")); return this._insertLines(Math.max(row, 0), lines); }; this._insertLines = function(row, lines) { if (lines.length == 0) return {row: row, column: 0}; while (lines.length > 0xF000) { var end = this._insertLines(row, lines.slice(0, 0xF000)); lines = lines.slice(0xF000); row = end.row; } var args = [row, 0]; args.push.apply(args, lines); this.$lines.splice.apply(this.$lines, args); var range = new Range(row, 0, row + lines.length, 0); var delta = { action: "insertLines", range: range, lines: lines }; this._signal("change", { data: delta }); return range.end; }; this.insertNewLine = function(position) { position = this.$clipPosition(position); var line = this.$lines[position.row] || ""; this.$lines[position.row] = line.substring(0, position.column); this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length)); var end = { row : position.row + 1, column : 0 }; var delta = { action: "insertText", range: Range.fromPoints(position, end), text: this.getNewLineCharacter() }; this._signal("change", { data: delta }); return end; }; this.insertInLine = function(position, text) { if (text.length == 0) return position; var line = this.$lines[position.row] || ""; this.$lines[position.row] = line.substring(0, position.column) + text + line.substring(position.column); var end = { row : position.row, column : position.column + text.length }; var delta = { action: "insertText", range: Range.fromPoints(position, end), text: text }; this._signal("change", { data: delta }); return end; }; this.remove = function(range) { if (!(range instanceof Range)) range = Range.fromPoints(range.start, range.end); range.start = this.$clipPosition(range.start); range.end = this.$clipPosition(range.end); if (range.isEmpty()) return range.start; var firstRow = range.start.row; var lastRow = range.end.row; if (range.isMultiLine()) { var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1; var lastFullRow = lastRow - 1; if (range.end.column > 0) this.removeInLine(lastRow, 0, range.end.column); if (lastFullRow >= firstFullRow) this._removeLines(firstFullRow, lastFullRow); if (firstFullRow != firstRow) { this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length); this.removeNewLine(range.start.row); } } else { this.removeInLine(firstRow, range.start.column, range.end.column); } return range.start; }; this.removeInLine = function(row, startColumn, endColumn) { if (startColumn == endColumn) return; var range = new Range(row, startColumn, row, endColumn); var line = this.getLine(row); var removed = line.substring(startColumn, endColumn); var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length); this.$lines.splice(row, 1, newLine); var delta = { action: "removeText", range: range, text: removed }; this._signal("change", { data: delta }); return range.start; }; this.removeLines = function(firstRow, lastRow) { if (firstRow < 0 || lastRow >= this.getLength()) return this.remove(new Range(firstRow, 0, lastRow + 1, 0)); return this._removeLines(firstRow, lastRow); }; this._removeLines = function(firstRow, lastRow) { var range = new Range(firstRow, 0, lastRow + 1, 0); var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1); var delta = { action: "removeLines", range: range, nl: this.getNewLineCharacter(), lines: removed }; this._signal("change", { data: delta }); return removed; }; this.removeNewLine = function(row) { var firstLine = this.getLine(row); var secondLine = this.getLine(row+1); var range = new Range(row, firstLine.length, row+1, 0); var line = firstLine + secondLine; this.$lines.splice(row, 2, line); var delta = { action: "removeText", range: range, text: this.getNewLineCharacter() }; this._signal("change", { data: delta }); }; this.replace = function(range, text) { if (!(range instanceof Range)) range = Range.fromPoints(range.start, range.end); if (text.length == 0 && range.isEmpty()) return range.start; if (text == this.getTextRange(range)) return range.end; this.remove(range); if (text) { var end = this.insert(range.start, text); } else { end = range.start; } return end; }; this.applyDeltas = function(deltas) { for (var i=0; i=0; i--) { var delta = deltas[i]; var range = Range.fromPoints(delta.range.start, delta.range.end); if (delta.action == "insertLines") this._removeLines(range.start.row, range.end.row - 1); else if (delta.action == "insertText") this.remove(range); else if (delta.action == "removeLines") this._insertLines(range.start.row, delta.lines); else if (delta.action == "removeText") this.insert(range.start, delta.text); } }; this.indexToPosition = function(index, startRow) { var lines = this.$lines || this.getAllLines(); var newlineLength = this.getNewLineCharacter().length; for (var i = startRow || 0, l = lines.length; i < l; i++) { index -= lines[i].length + newlineLength; if (index < 0) return {row: i, column: index + lines[i].length + newlineLength}; } return {row: l-1, column: lines[l-1].length}; }; this.positionToIndex = function(pos, startRow) { var lines = this.$lines || this.getAllLines(); var newlineLength = this.getNewLineCharacter().length; var index = 0; var row = Math.min(pos.row, lines.length); for (var i = startRow || 0; i < row; ++i) index += lines[i].length + newlineLength; return index + pos.column; }; }).call(Document.prototype); exports.Document = Document; }); ace.define("ace/lib/lang",["require","exports","module"], function(require, exports, module) { "use strict"; exports.last = function(a) { return a[a.length - 1]; }; exports.stringReverse = function(string) { return string.split("").reverse().join(""); }; exports.stringRepeat = function (string, count) { var result = ''; while (count > 0) { if (count & 1) result += string; if (count >>= 1) string += string; } return result; }; var trimBeginRegexp = /^\s\s*/; var trimEndRegexp = /\s\s*$/; exports.stringTrimLeft = function (string) { return string.replace(trimBeginRegexp, ''); }; exports.stringTrimRight = function (string) { return string.replace(trimEndRegexp, ''); }; exports.copyObject = function(obj) { var copy = {}; for (var key in obj) { copy[key] = obj[key]; } return copy; }; exports.copyArray = function(array){ var copy = []; for (var i=0, l=array.length; i= '0' && ch <= '9') { string += ch; next(); } if (ch === '.') { string += '.'; while (next() && ch >= '0' && ch <= '9') { string += ch; } } if (ch === 'e' || ch === 'E') { string += ch; next(); if (ch === '-' || ch === '+') { string += ch; next(); } while (ch >= '0' && ch <= '9') { string += ch; next(); } } number = +string; if (isNaN(number)) { error("Bad number"); } else { return number; } }, string = function () { var hex, i, string = '', uffff; if (ch === '"') { while (next()) { if (ch === '"') { next(); return string; } else if (ch === '\\') { next(); if (ch === 'u') { uffff = 0; for (i = 0; i < 4; i += 1) { hex = parseInt(next(), 16); if (!isFinite(hex)) { break; } uffff = uffff * 16 + hex; } string += String.fromCharCode(uffff); } else if (typeof escapee[ch] === 'string') { string += escapee[ch]; } else { break; } } else { string += ch; } } } error("Bad string"); }, white = function () { while (ch && ch <= ' ') { next(); } }, word = function () { switch (ch) { case 't': next('t'); next('r'); next('u'); next('e'); return true; case 'f': next('f'); next('a'); next('l'); next('s'); next('e'); return false; case 'n': next('n'); next('u'); next('l'); next('l'); return null; } error("Unexpected '" + ch + "'"); }, value, // Place holder for the value function. array = function () { var array = []; if (ch === '[') { next('['); white(); if (ch === ']') { next(']'); return array; // empty array } while (ch) { array.push(value()); white(); if (ch === ']') { next(']'); return array; } next(','); white(); } } error("Bad array"); }, object = function () { var key, object = {}; if (ch === '{') { next('{'); white(); if (ch === '}') { next('}'); return object; // empty object } while (ch) { key = string(); white(); next(':'); if (Object.hasOwnProperty.call(object, key)) { error('Duplicate key "' + key + '"'); } object[key] = value(); white(); if (ch === '}') { next('}'); return object; } next(','); white(); } } error("Bad object"); }; value = function () { white(); switch (ch) { case '{': return object(); case '[': return array(); case '"': return string(); case '-': return number(); default: return ch >= '0' && ch <= '9' ? number() : word(); } }; return function (source, reviver) { var result; text = source; at = 0; ch = ' '; result = value(); white(); if (ch) { error("Syntax error"); } return typeof reviver === 'function' ? function walk(holder, key) { var k, v, value = holder[key]; if (value && typeof value === 'object') { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } } return reviver.call(holder, key, value); }({'': result}, '') : result; }; }); ace.define("ace/mode/json_worker",["require","exports","module","ace/lib/oop","ace/worker/mirror","ace/mode/json/json_parse"], function(require, exports, module) { "use strict"; var oop = require("../lib/oop"); var Mirror = require("../worker/mirror").Mirror; var parse = require("./json/json_parse"); var JsonWorker = exports.JsonWorker = function(sender) { Mirror.call(this, sender); this.setTimeout(200); }; oop.inherits(JsonWorker, Mirror); (function() { this.onUpdate = function() { var value = this.doc.getValue(); try { if (value) parse(value); } catch (e) { var pos = this.doc.indexToPosition(e.at-1); this.sender.emit("error", { row: pos.row, column: pos.column, text: e.message, type: "error" }); return; } this.sender.emit("ok"); }; }).call(JsonWorker.prototype); }); ace.define("ace/lib/es5-shim",["require","exports","module"], function(require, exports, module) { function Empty() {} if (!Function.prototype.bind) { Function.prototype.bind = function bind(that) { // .length is 1 var target = this; if (typeof target != "function") { throw new TypeError("Function.prototype.bind called on incompatible " + target); } var args = slice.call(arguments, 1); // for normal call var bound = function () { if (this instanceof bound) { var result = target.apply( this, args.concat(slice.call(arguments)) ); if (Object(result) === result) { return result; } return this; } else { return target.apply( that, args.concat(slice.call(arguments)) ); } }; if(target.prototype) { Empty.prototype = target.prototype; bound.prototype = new Empty(); Empty.prototype = null; } return bound; }; } var call = Function.prototype.call; var prototypeOfArray = Array.prototype; var prototypeOfObject = Object.prototype; var slice = prototypeOfArray.slice; var _toString = call.bind(prototypeOfObject.toString); var owns = call.bind(prototypeOfObject.hasOwnProperty); var defineGetter; var defineSetter; var lookupGetter; var lookupSetter; var supportsAccessors; if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) { defineGetter = call.bind(prototypeOfObject.__defineGetter__); defineSetter = call.bind(prototypeOfObject.__defineSetter__); lookupGetter = call.bind(prototypeOfObject.__lookupGetter__); lookupSetter = call.bind(prototypeOfObject.__lookupSetter__); } if ([1,2].splice(0).length != 2) { if(function() { // test IE < 9 to splice bug - see issue #138 function makeArray(l) { var a = new Array(l+2); a[0] = a[1] = 0; return a; } var array = [], lengthBefore; array.splice.apply(array, makeArray(20)); array.splice.apply(array, makeArray(26)); lengthBefore = array.length; //46 array.splice(5, 0, "XXX"); // add one element lengthBefore + 1 == array.length if (lengthBefore + 1 == array.length) { return true;// has right splice implementation without bugs } }()) {//IE 6/7 var array_splice = Array.prototype.splice; Array.prototype.splice = function(start, deleteCount) { if (!arguments.length) { return []; } else { return array_splice.apply(this, [ start === void 0 ? 0 : start, deleteCount === void 0 ? (this.length - start) : deleteCount ].concat(slice.call(arguments, 2))) } }; } else {//IE8 Array.prototype.splice = function(pos, removeCount){ var length = this.length; if (pos > 0) { if (pos > length) pos = length; } else if (pos == void 0) { pos = 0; } else if (pos < 0) { pos = Math.max(length + pos, 0); } if (!(pos+removeCount < length)) removeCount = length - pos; var removed = this.slice(pos, pos+removeCount); var insert = slice.call(arguments, 2); var add = insert.length; if (pos === length) { if (add) { this.push.apply(this, insert); } } else { var remove = Math.min(removeCount, length - pos); var tailOldPos = pos + remove; var tailNewPos = tailOldPos + add - remove; var tailCount = length - tailOldPos; var lengthAfterRemove = length - remove; if (tailNewPos < tailOldPos) { // case A for (var i = 0; i < tailCount; ++i) { this[tailNewPos+i] = this[tailOldPos+i]; } } else if (tailNewPos > tailOldPos) { // case B for (i = tailCount; i--; ) { this[tailNewPos+i] = this[tailOldPos+i]; } } // else, add == remove (nothing to do) if (add && pos === lengthAfterRemove) { this.length = lengthAfterRemove; // truncate array this.push.apply(this, insert); } else { this.length = lengthAfterRemove + add; // reserves space for (i = 0; i < add; ++i) { this[pos+i] = insert[i]; } } } return removed; }; } } if (!Array.isArray) { Array.isArray = function isArray(obj) { return _toString(obj) == "[object Array]"; }; } var boxedString = Object("a"), splitString = boxedString[0] != "a" || !(0 in boxedString); if (!Array.prototype.forEach) { Array.prototype.forEach = function forEach(fun /*, thisp*/) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, thisp = arguments[1], i = -1, length = self.length >>> 0; if (_toString(fun) != "[object Function]") { throw new TypeError(); // TODO message } while (++i < length) { if (i in self) { fun.call(thisp, self[i], i, object); } } }; } if (!Array.prototype.map) { Array.prototype.map = function map(fun /*, thisp*/) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, length = self.length >>> 0, result = Array(length), thisp = arguments[1]; if (_toString(fun) != "[object Function]") { throw new TypeError(fun + " is not a function"); } for (var i = 0; i < length; i++) { if (i in self) result[i] = fun.call(thisp, self[i], i, object); } return result; }; } if (!Array.prototype.filter) { Array.prototype.filter = function filter(fun /*, thisp */) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, length = self.length >>> 0, result = [], value, thisp = arguments[1]; if (_toString(fun) != "[object Function]") { throw new TypeError(fun + " is not a function"); } for (var i = 0; i < length; i++) { if (i in self) { value = self[i]; if (fun.call(thisp, value, i, object)) { result.push(value); } } } return result; }; } if (!Array.prototype.every) { Array.prototype.every = function every(fun /*, thisp */) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, length = self.length >>> 0, thisp = arguments[1]; if (_toString(fun) != "[object Function]") { throw new TypeError(fun + " is not a function"); } for (var i = 0; i < length; i++) { if (i in self && !fun.call(thisp, self[i], i, object)) { return false; } } return true; }; } if (!Array.prototype.some) { Array.prototype.some = function some(fun /*, thisp */) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, length = self.length >>> 0, thisp = arguments[1]; if (_toString(fun) != "[object Function]") { throw new TypeError(fun + " is not a function"); } for (var i = 0; i < length; i++) { if (i in self && fun.call(thisp, self[i], i, object)) { return true; } } return false; }; } if (!Array.prototype.reduce) { Array.prototype.reduce = function reduce(fun /*, initial*/) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, length = self.length >>> 0; if (_toString(fun) != "[object Function]") { throw new TypeError(fun + " is not a function"); } if (!length && arguments.length == 1) { throw new TypeError("reduce of empty array with no initial value"); } var i = 0; var result; if (arguments.length >= 2) { result = arguments[1]; } else { do { if (i in self) { result = self[i++]; break; } if (++i >= length) { throw new TypeError("reduce of empty array with no initial value"); } } while (true); } for (; i < length; i++) { if (i in self) { result = fun.call(void 0, result, self[i], i, object); } } return result; }; } if (!Array.prototype.reduceRight) { Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) { var object = toObject(this), self = splitString && _toString(this) == "[object String]" ? this.split("") : object, length = self.length >>> 0; if (_toString(fun) != "[object Function]") { throw new TypeError(fun + " is not a function"); } if (!length && arguments.length == 1) { throw new TypeError("reduceRight of empty array with no initial value"); } var result, i = length - 1; if (arguments.length >= 2) { result = arguments[1]; } else { do { if (i in self) { result = self[i--]; break; } if (--i < 0) { throw new TypeError("reduceRight of empty array with no initial value"); } } while (true); } do { if (i in this) { result = fun.call(void 0, result, self[i], i, object); } } while (i--); return result; }; } if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) { Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) { var self = splitString && _toString(this) == "[object String]" ? this.split("") : toObject(this), length = self.length >>> 0; if (!length) { return -1; } var i = 0; if (arguments.length > 1) { i = toInteger(arguments[1]); } i = i >= 0 ? i : Math.max(0, length + i); for (; i < length; i++) { if (i in self && self[i] === sought) { return i; } } return -1; }; } if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) { Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) { var self = splitString && _toString(this) == "[object String]" ? this.split("") : toObject(this), length = self.length >>> 0; if (!length) { return -1; } var i = length - 1; if (arguments.length > 1) { i = Math.min(i, toInteger(arguments[1])); } i = i >= 0 ? i : length - Math.abs(i); for (; i >= 0; i--) { if (i in self && sought === self[i]) { return i; } } return -1; }; } if (!Object.getPrototypeOf) { Object.getPrototypeOf = function getPrototypeOf(object) { return object.__proto__ || ( object.constructor ? object.constructor.prototype : prototypeOfObject ); }; } if (!Object.getOwnPropertyDescriptor) { var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " + "non-object: "; Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) { if ((typeof object != "object" && typeof object != "function") || object === null) throw new TypeError(ERR_NON_OBJECT + object); if (!owns(object, property)) return; var descriptor, getter, setter; descriptor = { enumerable: true, configurable: true }; if (supportsAccessors) { var prototype = object.__proto__; object.__proto__ = prototypeOfObject; var getter = lookupGetter(object, property); var setter = lookupSetter(object, property); object.__proto__ = prototype; if (getter || setter) { if (getter) descriptor.get = getter; if (setter) descriptor.set = setter; return descriptor; } } descriptor.value = object[property]; return descriptor; }; } if (!Object.getOwnPropertyNames) { Object.getOwnPropertyNames = function getOwnPropertyNames(object) { return Object.keys(object); }; } if (!Object.create) { var createEmpty; if (Object.prototype.__proto__ === null) { createEmpty = function () { return { "__proto__": null }; }; } else { createEmpty = function () { var empty = {}; for (var i in empty) empty[i] = null; empty.constructor = empty.hasOwnProperty = empty.propertyIsEnumerable = empty.isPrototypeOf = empty.toLocaleString = empty.toString = empty.valueOf = empty.__proto__ = null; return empty; } } Object.create = function create(prototype, properties) { var object; if (prototype === null) { object = createEmpty(); } else { if (typeof prototype != "object") throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'"); var Type = function () {}; Type.prototype = prototype; object = new Type(); object.__proto__ = prototype; } if (properties !== void 0) Object.defineProperties(object, properties); return object; }; } function doesDefinePropertyWork(object) { try { Object.defineProperty(object, "sentinel", {}); return "sentinel" in object; } catch (exception) { } } if (Object.defineProperty) { var definePropertyWorksOnObject = doesDefinePropertyWork({}); var definePropertyWorksOnDom = typeof document == "undefined" || doesDefinePropertyWork(document.createElement("div")); if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { var definePropertyFallback = Object.defineProperty; } } if (!Object.defineProperty || definePropertyFallback) { var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: "; var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: " var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " + "on this javascript engine"; Object.defineProperty = function defineProperty(object, property, descriptor) { if ((typeof object != "object" && typeof object != "function") || object === null) throw new TypeError(ERR_NON_OBJECT_TARGET + object); if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor); if (definePropertyFallback) { try { return definePropertyFallback.call(Object, object, property, descriptor); } catch (exception) { } } if (owns(descriptor, "value")) { if (supportsAccessors && (lookupGetter(object, property) || lookupSetter(object, property))) { var prototype = object.__proto__; object.__proto__ = prototypeOfObject; delete object[property]; object[property] = descriptor.value; object.__proto__ = prototype; } else { object[property] = descriptor.value; } } else { if (!supportsAccessors) throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); if (owns(descriptor, "get")) defineGetter(object, property, descriptor.get); if (owns(descriptor, "set")) defineSetter(object, property, descriptor.set); } return object; }; } if (!Object.defineProperties) { Object.defineProperties = function defineProperties(object, properties) { for (var property in properties) { if (owns(properties, property)) Object.defineProperty(object, property, properties[property]); } return object; }; } if (!Object.seal) { Object.seal = function seal(object) { return object; }; } if (!Object.freeze) { Object.freeze = function freeze(object) { return object; }; } try { Object.freeze(function () {}); } catch (exception) { Object.freeze = (function freeze(freezeObject) { return function freeze(object) { if (typeof object == "function") { return object; } else { return freezeObject(object); } }; })(Object.freeze); } if (!Object.preventExtensions) { Object.preventExtensions = function preventExtensions(object) { return object; }; } if (!Object.isSealed) { Object.isSealed = function isSealed(object) { return false; }; } if (!Object.isFrozen) { Object.isFrozen = function isFrozen(object) { return false; }; } if (!Object.isExtensible) { Object.isExtensible = function isExtensible(object) { if (Object(object) === object) { throw new TypeError(); // TODO message } var name = ''; while (owns(object, name)) { name += '?'; } object[name] = true; var returnValue = owns(object, name); delete object[name]; return returnValue; }; } if (!Object.keys) { var hasDontEnumBug = true, dontEnums = [ "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "constructor" ], dontEnumsLength = dontEnums.length; for (var key in {"toString": null}) { hasDontEnumBug = false; } Object.keys = function keys(object) { if ( (typeof object != "object" && typeof object != "function") || object === null ) { throw new TypeError("Object.keys called on a non-object"); } var keys = []; for (var name in object) { if (owns(object, name)) { keys.push(name); } } if (hasDontEnumBug) { for (var i = 0, ii = dontEnumsLength; i < ii; i++) { var dontEnum = dontEnums[i]; if (owns(object, dontEnum)) { keys.push(dontEnum); } } } return keys; }; } if (!Date.now) { Date.now = function now() { return new Date().getTime(); }; } var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" + "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + "\u2029\uFEFF"; if (!String.prototype.trim || ws.trim()) { ws = "[" + ws + "]"; var trimBeginRegexp = new RegExp("^" + ws + ws + "*"), trimEndRegexp = new RegExp(ws + ws + "*$"); String.prototype.trim = function trim() { return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, ""); }; } function toInteger(n) { n = +n; if (n !== n) { // isNaN n = 0; } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) { n = (n > 0 || -1) * Math.floor(Math.abs(n)); } return n; } function isPrimitive(input) { var type = typeof input; return ( input === null || type === "undefined" || type === "boolean" || type === "number" || type === "string" ); } function toPrimitive(input) { var val, valueOf, toString; if (isPrimitive(input)) { return input; } valueOf = input.valueOf; if (typeof valueOf === "function") { val = valueOf.call(input); if (isPrimitive(val)) { return val; } } toString = input.toString; if (typeof toString === "function") { val = toString.call(input); if (isPrimitive(val)) { return val; } } throw new TypeError(); } var toObject = function (o) { if (o == null) { // this matches both null and undefined throw new TypeError("can't convert "+o+" to object"); } return Object(o); }; }); Swagger2-0.73/lib/Swagger2/public/cache/05a9f0030e1b92e1603618dad61dbc8d000644 000765 000024 00000000147 12656601140 025326 0ustar00jhthorsenstaff000000 000000 The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.Swagger2-0.73/lib/Swagger2/public/cache/062bec94cfcd2cb0049773ae5d15da61000644 000765 000024 00000000147 12656600633 025503 0ustar00jhthorsenstaff000000 000000 The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.Swagger2-0.73/lib/Swagger2/public/cache/0a8e1de16692c32db582df9bdabdbdd7000644 000765 000024 00000010427 12656375137 025746 0ustar00jhthorsenstaff000000 000000 { "id": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#", "description": "Core schema meta-schema", "definitions": { "schemaArray": { "type": "array", "minItems": 1, "items": { "$ref": "#" } }, "positiveInteger": { "type": "integer", "minimum": 0 }, "positiveIntegerDefault0": { "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] }, "simpleTypes": { "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] }, "stringArray": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true } }, "type": "object", "properties": { "id": { "type": "string", "format": "uri" }, "$schema": { "type": "string", "format": "uri" }, "title": { "type": "string" }, "description": { "type": "string" }, "default": {}, "multipleOf": { "type": "number", "minimum": 0, "exclusiveMinimum": true }, "maximum": { "type": "number" }, "exclusiveMaximum": { "type": "boolean", "default": false }, "minimum": { "type": "number" }, "exclusiveMinimum": { "type": "boolean", "default": false }, "maxLength": { "$ref": "#/definitions/positiveInteger" }, "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, "pattern": { "type": "string", "format": "regex" }, "additionalItems": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ], "default": {} }, "items": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/schemaArray" } ], "default": {} }, "maxItems": { "$ref": "#/definitions/positiveInteger" }, "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, "uniqueItems": { "type": "boolean", "default": false }, "maxProperties": { "$ref": "#/definitions/positiveInteger" }, "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, "required": { "$ref": "#/definitions/stringArray" }, "additionalProperties": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ], "default": {} }, "definitions": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "properties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "patternProperties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "dependencies": { "type": "object", "additionalProperties": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/stringArray" } ] } }, "enum": { "type": "array", "minItems": 1, "uniqueItems": true }, "type": { "anyOf": [ { "$ref": "#/definitions/simpleTypes" }, { "type": "array", "items": { "$ref": "#/definitions/simpleTypes" }, "minItems": 1, "uniqueItems": true } ] }, "allOf": { "$ref": "#/definitions/schemaArray" }, "anyOf": { "$ref": "#/definitions/schemaArray" }, "oneOf": { "$ref": "#/definitions/schemaArray" }, "not": { "$ref": "#" } }, "dependencies": { "exclusiveMaximum": [ "maximum" ], "exclusiveMinimum": [ "minimum" ] }, "default": {} } Swagger2-0.73/lib/Swagger2/public/cache/36d1bd12eeed51e86c8695bd8876a9df000644 000765 000024 00000116050 12645227324 025550 0ustar00jhthorsenstaff000000 000000 { "title": "A JSON Schema for Swagger 2.0 API.", "id": "http://swagger.io/v2/schema.json#", "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "required": [ "swagger", "info", "paths" ], "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "swagger": { "type": "string", "enum": [ "2.0" ], "description": "The Swagger version of this document." }, "info": { "$ref": "#/definitions/info" }, "host": { "type": "string", "pattern": "^[^{}/ :\\\\]+(?::\\d+)?$", "description": "The host (name or ip) of the API. Example: 'swagger.io'" }, "basePath": { "type": "string", "pattern": "^/", "description": "The base path to the API. Example: '/api'." }, "schemes": { "$ref": "#/definitions/schemesList" }, "consumes": { "description": "A list of MIME types accepted by the API.", "$ref": "#/definitions/mediaTypeList" }, "produces": { "description": "A list of MIME types the API can produce.", "$ref": "#/definitions/mediaTypeList" }, "paths": { "$ref": "#/definitions/paths" }, "definitions": { "$ref": "#/definitions/definitions" }, "parameters": { "$ref": "#/definitions/parameterDefinitions" }, "responses": { "$ref": "#/definitions/responseDefinitions" }, "security": { "$ref": "#/definitions/security" }, "securityDefinitions": { "$ref": "#/definitions/securityDefinitions" }, "tags": { "type": "array", "items": { "$ref": "#/definitions/tag" }, "uniqueItems": true }, "externalDocs": { "$ref": "#/definitions/externalDocs" } }, "definitions": { "info": { "type": "object", "description": "General information about the API.", "required": [ "version", "title" ], "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "title": { "type": "string", "description": "A unique and precise title of the API." }, "version": { "type": "string", "description": "A semantic version number of the API." }, "description": { "type": "string", "description": "A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed." }, "termsOfService": { "type": "string", "description": "The terms of service for the API." }, "contact": { "$ref": "#/definitions/contact" }, "license": { "$ref": "#/definitions/license" } } }, "contact": { "type": "object", "description": "Contact information for the owners of the API.", "additionalProperties": false, "properties": { "name": { "type": "string", "description": "The identifying name of the contact person/organization." }, "url": { "type": "string", "description": "The URL pointing to the contact information.", "format": "uri" }, "email": { "type": "string", "description": "The email address of the contact person/organization.", "format": "email" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "license": { "type": "object", "required": [ "name" ], "additionalProperties": false, "properties": { "name": { "type": "string", "description": "The name of the license type. It's encouraged to use an OSI compatible license." }, "url": { "type": "string", "description": "The URL pointing to the license.", "format": "uri" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "paths": { "type": "object", "description": "Relative paths to the individual endpoints. They must be relative to the 'basePath'.", "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" }, "^/": { "$ref": "#/definitions/pathItem" } }, "additionalProperties": false }, "definitions": { "type": "object", "additionalProperties": { "$ref": "#/definitions/schema" }, "description": "One or more JSON objects describing the schemas being consumed and produced by the API." }, "parameterDefinitions": { "type": "object", "additionalProperties": { "$ref": "#/definitions/parameter" }, "description": "One or more JSON representations for parameters" }, "responseDefinitions": { "type": "object", "additionalProperties": { "$ref": "#/definitions/response" }, "description": "One or more JSON representations for parameters" }, "externalDocs": { "type": "object", "additionalProperties": false, "description": "information about external documentation", "required": [ "url" ], "properties": { "description": { "type": "string" }, "url": { "type": "string", "format": "uri" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "examples": { "type": "object", "additionalProperties": true }, "mimeType": { "type": "string", "description": "The MIME type of the HTTP message." }, "operation": { "type": "object", "required": [ "responses" ], "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "tags": { "type": "array", "items": { "type": "string" }, "uniqueItems": true }, "summary": { "type": "string", "description": "A brief summary of the operation." }, "description": { "type": "string", "description": "A longer description of the operation, GitHub Flavored Markdown is allowed." }, "externalDocs": { "$ref": "#/definitions/externalDocs" }, "operationId": { "type": "string", "description": "A unique identifier of the operation." }, "produces": { "description": "A list of MIME types the API can produce.", "$ref": "#/definitions/mediaTypeList" }, "consumes": { "description": "A list of MIME types the API can consume.", "$ref": "#/definitions/mediaTypeList" }, "parameters": { "$ref": "#/definitions/parametersList" }, "responses": { "$ref": "#/definitions/responses" }, "schemes": { "$ref": "#/definitions/schemesList" }, "deprecated": { "type": "boolean", "default": false }, "security": { "$ref": "#/definitions/security" } } }, "pathItem": { "type": "object", "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "$ref": { "type": "string" }, "get": { "$ref": "#/definitions/operation" }, "put": { "$ref": "#/definitions/operation" }, "post": { "$ref": "#/definitions/operation" }, "delete": { "$ref": "#/definitions/operation" }, "options": { "$ref": "#/definitions/operation" }, "head": { "$ref": "#/definitions/operation" }, "patch": { "$ref": "#/definitions/operation" }, "parameters": { "$ref": "#/definitions/parametersList" } } }, "responses": { "type": "object", "description": "Response objects names can either be any valid HTTP status code or 'default'.", "minProperties": 1, "additionalProperties": false, "patternProperties": { "^([0-9]{3})$|^(default)$": { "$ref": "#/definitions/responseValue" }, "^x-": { "$ref": "#/definitions/vendorExtension" } }, "not": { "type": "object", "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } } }, "responseValue": { "oneOf": [ { "$ref": "#/definitions/response" }, { "$ref": "#/definitions/jsonReference" } ] }, "response": { "type": "object", "required": [ "description" ], "properties": { "description": { "type": "string" }, "schema": { "oneOf": [ { "$ref": "#/definitions/schema" }, { "$ref": "#/definitions/fileSchema" } ] }, "headers": { "$ref": "#/definitions/headers" }, "examples": { "$ref": "#/definitions/examples" } }, "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "headers": { "type": "object", "additionalProperties": { "$ref": "#/definitions/header" } }, "header": { "type": "object", "additionalProperties": false, "required": [ "type" ], "properties": { "type": { "type": "string", "enum": [ "string", "number", "integer", "boolean", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormat" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "vendorExtension": { "description": "Any property starting with x- is valid.", "additionalProperties": true, "additionalItems": true }, "bodyParameter": { "type": "object", "required": [ "name", "in", "schema" ], "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "body" ] }, "required": { "type": "boolean", "description": "Determines whether or not this parameter is required or optional.", "default": false }, "schema": { "$ref": "#/definitions/schema" } }, "additionalProperties": false }, "headerParameterSubSchema": { "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "required": { "type": "boolean", "description": "Determines whether or not this parameter is required or optional.", "default": false }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "header" ] }, "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "type": { "type": "string", "enum": [ "string", "number", "boolean", "integer", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormat" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } } }, "queryParameterSubSchema": { "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "required": { "type": "boolean", "description": "Determines whether or not this parameter is required or optional.", "default": false }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "query" ] }, "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "allowEmptyValue": { "type": "boolean", "default": false, "description": "allows sending a parameter by name only or with an empty value." }, "type": { "type": "string", "enum": [ "string", "number", "boolean", "integer", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormatWithMulti" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } } }, "formDataParameterSubSchema": { "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "required": { "type": "boolean", "description": "Determines whether or not this parameter is required or optional.", "default": false }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "formData" ] }, "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "allowEmptyValue": { "type": "boolean", "default": false, "description": "allows sending a parameter by name only or with an empty value." }, "type": { "type": "string", "enum": [ "string", "number", "boolean", "integer", "array", "file" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormatWithMulti" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } } }, "pathParameterSubSchema": { "additionalProperties": false, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "required": [ "required" ], "properties": { "required": { "type": "boolean", "enum": [ true ], "description": "Determines whether or not this parameter is required or optional." }, "in": { "type": "string", "description": "Determines the location of the parameter.", "enum": [ "path" ] }, "description": { "type": "string", "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." }, "name": { "type": "string", "description": "The name of the parameter." }, "type": { "type": "string", "enum": [ "string", "number", "boolean", "integer", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormat" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } } }, "nonBodyParameter": { "type": "object", "required": [ "name", "in", "type" ], "oneOf": [ { "$ref": "#/definitions/headerParameterSubSchema" }, { "$ref": "#/definitions/formDataParameterSubSchema" }, { "$ref": "#/definitions/queryParameterSubSchema" }, { "$ref": "#/definitions/pathParameterSubSchema" } ] }, "parameter": { "oneOf": [ { "$ref": "#/definitions/bodyParameter" }, { "$ref": "#/definitions/nonBodyParameter" } ] }, "schema": { "type": "object", "description": "A deterministic version of a JSON Schema object.", "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "$ref": { "type": "string" }, "format": { "type": "string" }, "title": { "$ref": "http://json-schema.org/draft-04/schema#/properties/title" }, "description": { "$ref": "http://json-schema.org/draft-04/schema#/properties/description" }, "default": { "$ref": "http://json-schema.org/draft-04/schema#/properties/default" }, "multipleOf": { "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" }, "maximum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" }, "exclusiveMaximum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" }, "minimum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" }, "exclusiveMinimum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" }, "maxLength": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minLength": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "pattern": { "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" }, "maxItems": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minItems": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "uniqueItems": { "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" }, "maxProperties": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minProperties": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "required": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" }, "enum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" }, "additionalProperties": { "anyOf": [ { "$ref": "#/definitions/schema" }, { "type": "boolean" } ], "default": {} }, "type": { "$ref": "http://json-schema.org/draft-04/schema#/properties/type" }, "items": { "anyOf": [ { "$ref": "#/definitions/schema" }, { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/schema" } } ], "default": {} }, "allOf": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/schema" } }, "properties": { "type": "object", "additionalProperties": { "$ref": "#/definitions/schema" }, "default": {} }, "discriminator": { "type": "string" }, "readOnly": { "type": "boolean", "default": false }, "xml": { "$ref": "#/definitions/xml" }, "externalDocs": { "$ref": "#/definitions/externalDocs" }, "example": {} }, "additionalProperties": false }, "fileSchema": { "type": "object", "description": "A deterministic version of a JSON Schema object.", "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } }, "properties": { "format": { "type": "string" }, "title": { "$ref": "http://json-schema.org/draft-04/schema#/properties/title" }, "description": { "$ref": "http://json-schema.org/draft-04/schema#/properties/description" }, "default": { "$ref": "http://json-schema.org/draft-04/schema#/properties/default" }, "required": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" }, "type": { "type": "string", "enum": [ "file" ] }, "readOnly": { "type": "boolean", "default": false }, "externalDocs": { "$ref": "#/definitions/externalDocs" }, "example": {} }, "additionalProperties": false }, "primitivesItems": { "type": "object", "additionalProperties": false, "properties": { "type": { "type": "string", "enum": [ "string", "number", "integer", "boolean", "array" ] }, "format": { "type": "string" }, "items": { "$ref": "#/definitions/primitivesItems" }, "collectionFormat": { "$ref": "#/definitions/collectionFormat" }, "default": { "$ref": "#/definitions/default" }, "maximum": { "$ref": "#/definitions/maximum" }, "exclusiveMaximum": { "$ref": "#/definitions/exclusiveMaximum" }, "minimum": { "$ref": "#/definitions/minimum" }, "exclusiveMinimum": { "$ref": "#/definitions/exclusiveMinimum" }, "maxLength": { "$ref": "#/definitions/maxLength" }, "minLength": { "$ref": "#/definitions/minLength" }, "pattern": { "$ref": "#/definitions/pattern" }, "maxItems": { "$ref": "#/definitions/maxItems" }, "minItems": { "$ref": "#/definitions/minItems" }, "uniqueItems": { "$ref": "#/definitions/uniqueItems" }, "enum": { "$ref": "#/definitions/enum" }, "multipleOf": { "$ref": "#/definitions/multipleOf" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "security": { "type": "array", "items": { "$ref": "#/definitions/securityRequirement" }, "uniqueItems": true }, "securityRequirement": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" }, "uniqueItems": true } }, "xml": { "type": "object", "additionalProperties": false, "properties": { "name": { "type": "string" }, "namespace": { "type": "string" }, "prefix": { "type": "string" }, "attribute": { "type": "boolean", "default": false }, "wrapped": { "type": "boolean", "default": false } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "tag": { "type": "object", "additionalProperties": false, "required": [ "name" ], "properties": { "name": { "type": "string" }, "description": { "type": "string" }, "externalDocs": { "$ref": "#/definitions/externalDocs" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "securityDefinitions": { "type": "object", "additionalProperties": { "oneOf": [ { "$ref": "#/definitions/basicAuthenticationSecurity" }, { "$ref": "#/definitions/apiKeySecurity" }, { "$ref": "#/definitions/oauth2ImplicitSecurity" }, { "$ref": "#/definitions/oauth2PasswordSecurity" }, { "$ref": "#/definitions/oauth2ApplicationSecurity" }, { "$ref": "#/definitions/oauth2AccessCodeSecurity" } ] } }, "basicAuthenticationSecurity": { "type": "object", "additionalProperties": false, "required": [ "type" ], "properties": { "type": { "type": "string", "enum": [ "basic" ] }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "apiKeySecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "name", "in" ], "properties": { "type": { "type": "string", "enum": [ "apiKey" ] }, "name": { "type": "string" }, "in": { "type": "string", "enum": [ "header", "query" ] }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2ImplicitSecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "flow", "authorizationUrl" ], "properties": { "type": { "type": "string", "enum": [ "oauth2" ] }, "flow": { "type": "string", "enum": [ "implicit" ] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" }, "authorizationUrl": { "type": "string", "format": "uri" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2PasswordSecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "flow", "tokenUrl" ], "properties": { "type": { "type": "string", "enum": [ "oauth2" ] }, "flow": { "type": "string", "enum": [ "password" ] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" }, "tokenUrl": { "type": "string", "format": "uri" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2ApplicationSecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "flow", "tokenUrl" ], "properties": { "type": { "type": "string", "enum": [ "oauth2" ] }, "flow": { "type": "string", "enum": [ "application" ] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" }, "tokenUrl": { "type": "string", "format": "uri" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2AccessCodeSecurity": { "type": "object", "additionalProperties": false, "required": [ "type", "flow", "authorizationUrl", "tokenUrl" ], "properties": { "type": { "type": "string", "enum": [ "oauth2" ] }, "flow": { "type": "string", "enum": [ "accessCode" ] }, "scopes": { "$ref": "#/definitions/oauth2Scopes" }, "authorizationUrl": { "type": "string", "format": "uri" }, "tokenUrl": { "type": "string", "format": "uri" }, "description": { "type": "string" } }, "patternProperties": { "^x-": { "$ref": "#/definitions/vendorExtension" } } }, "oauth2Scopes": { "type": "object", "additionalProperties": { "type": "string" } }, "mediaTypeList": { "type": "array", "items": { "$ref": "#/definitions/mimeType" }, "uniqueItems": true }, "parametersList": { "type": "array", "description": "The parameters needed to send a valid API call.", "additionalItems": false, "items": { "oneOf": [ { "$ref": "#/definitions/parameter" }, { "$ref": "#/definitions/jsonReference" } ] }, "uniqueItems": true }, "schemesList": { "type": "array", "description": "The transfer protocol of the API.", "items": { "type": "string", "enum": [ "http", "https", "ws", "wss" ] }, "uniqueItems": true }, "collectionFormat": { "type": "string", "enum": [ "csv", "ssv", "tsv", "pipes" ], "default": "csv" }, "collectionFormatWithMulti": { "type": "string", "enum": [ "csv", "ssv", "tsv", "pipes", "multi" ], "default": "csv" }, "title": { "$ref": "http://json-schema.org/draft-04/schema#/properties/title" }, "description": { "$ref": "http://json-schema.org/draft-04/schema#/properties/description" }, "default": { "$ref": "http://json-schema.org/draft-04/schema#/properties/default" }, "multipleOf": { "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" }, "maximum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" }, "exclusiveMaximum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" }, "minimum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" }, "exclusiveMinimum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" }, "maxLength": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minLength": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "pattern": { "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" }, "maxItems": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" }, "minItems": { "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" }, "uniqueItems": { "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" }, "enum": { "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" }, "jsonReference": { "type": "object", "required": [ "$ref" ], "additionalProperties": false, "properties": { "$ref": { "type": "string" } } } } }Swagger2-0.73/lib/Swagger2/public/cache/49c95b866e40f788892a7fb3c816b0e8000644 000765 000024 00000010427 12645227324 025261 0ustar00jhthorsenstaff000000 000000 { "id": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#", "description": "Core schema meta-schema", "definitions": { "schemaArray": { "type": "array", "minItems": 1, "items": { "$ref": "#" } }, "positiveInteger": { "type": "integer", "minimum": 0 }, "positiveIntegerDefault0": { "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] }, "simpleTypes": { "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] }, "stringArray": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true } }, "type": "object", "properties": { "id": { "type": "string", "format": "uri" }, "$schema": { "type": "string", "format": "uri" }, "title": { "type": "string" }, "description": { "type": "string" }, "default": {}, "multipleOf": { "type": "number", "minimum": 0, "exclusiveMinimum": true }, "maximum": { "type": "number" }, "exclusiveMaximum": { "type": "boolean", "default": false }, "minimum": { "type": "number" }, "exclusiveMinimum": { "type": "boolean", "default": false }, "maxLength": { "$ref": "#/definitions/positiveInteger" }, "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, "pattern": { "type": "string", "format": "regex" }, "additionalItems": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ], "default": {} }, "items": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/schemaArray" } ], "default": {} }, "maxItems": { "$ref": "#/definitions/positiveInteger" }, "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, "uniqueItems": { "type": "boolean", "default": false }, "maxProperties": { "$ref": "#/definitions/positiveInteger" }, "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, "required": { "$ref": "#/definitions/stringArray" }, "additionalProperties": { "anyOf": [ { "type": "boolean" }, { "$ref": "#" } ], "default": {} }, "definitions": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "properties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "patternProperties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "dependencies": { "type": "object", "additionalProperties": { "anyOf": [ { "$ref": "#" }, { "$ref": "#/definitions/stringArray" } ] } }, "enum": { "type": "array", "minItems": 1, "uniqueItems": true }, "type": { "anyOf": [ { "$ref": "#/definitions/simpleTypes" }, { "type": "array", "items": { "$ref": "#/definitions/simpleTypes" }, "minItems": 1, "uniqueItems": true } ] }, "allOf": { "$ref": "#/definitions/schemaArray" }, "anyOf": { "$ref": "#/definitions/schemaArray" }, "oneOf": { "$ref": "#/definitions/schemaArray" }, "not": { "$ref": "#" } }, "dependencies": { "exclusiveMaximum": [ "maximum" ], "exclusiveMinimum": [ "minimum" ] }, "default": {} } Swagger2-0.73/lib/Swagger2/public/cache/630949337805585c8e52deea27d11419000644 000765 000024 00000000513 12656641071 025012 0ustar00jhthorsenstaff000000 000000 { "type" : "object", "required": [ "errors" ], "properties": { "errors": { "type": "array", "items": { "type" : "object", "required": [ "message", "path" ], "properties": { "message": { "type": "string" }, "path": { "type": "string" } } } } } } Swagger2-0.73/lib/Swagger2/public/cache/84a4b37fb9b912219cbeb486174f4066000644 000765 000024 00000002471 12656601621 025226 0ustar00jhthorsenstaff000000 000000 { "title": "JSON schema for JSONPatch files", "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": { "$ref": "#/definitions/operation" }, "definitions": { "operation": { "type": "object", "required": [ "op", "path" ], "allOf": [ { "$ref": "#/definitions/path" } ], "oneOf": [ { "required": [ "value" ], "properties": { "op": { "description": "The operation to perform.", "type": "string", "enum": [ "add", "replace", "test" ] }, "value": { "description": "The value to add, replace or test." } } }, { "properties": { "op": { "description": "The operation to perform.", "type": "string", "enum": [ "remove" ] } } }, { "required": [ "from" ], "properties": { "op": { "description": "The operation to perform.", "type": "string", "enum": [ "move", "copy" ] }, "from": { "description": "A JSON Pointer path pointing to the locatoin to move/copy from.", "type": "string" } } } ] }, "path": { "properties": { "path": { "description": "A JSON Pointer path.", "type": "string" } } } } } Swagger2-0.73/lib/Swagger2/public/cache/ea34d47d4e060a1c3b12d2287aff89a7000644 000765 000024 00000002471 12656375137 025441 0ustar00jhthorsenstaff000000 000000 { "title": "JSON schema for JSONPatch files", "$schema": "http://json-schema.org/draft-04/schema#", "type": "array", "items": { "$ref": "#/definitions/operation" }, "definitions": { "operation": { "type": "object", "required": [ "op", "path" ], "allOf": [ { "$ref": "#/definitions/path" } ], "oneOf": [ { "required": [ "value" ], "properties": { "op": { "description": "The operation to perform.", "type": "string", "enum": [ "add", "replace", "test" ] }, "value": { "description": "The value to add, replace or test." } } }, { "properties": { "op": { "description": "The operation to perform.", "type": "string", "enum": [ "remove" ] } } }, { "required": [ "from" ], "properties": { "op": { "description": "The operation to perform.", "type": "string", "enum": [ "move", "copy" ] }, "from": { "description": "A JSON Pointer path pointing to the locatoin to move/copy from.", "type": "string" } } } ] }, "path": { "properties": { "path": { "description": "A JSON Pointer path.", "type": "string" } } } } } Swagger2-0.73/lib/Swagger2/public/cache/eaa832720f36cff0abc20c05236a9cd9000644 000765 000024 00000000513 12656641071 025474 0ustar00jhthorsenstaff000000 000000 { "type" : "object", "required": [ "errors" ], "properties": { "errors": { "type": "array", "items": { "type" : "object", "required": [ "message", "path" ], "properties": { "message": { "type": "string" }, "path": { "type": "string" } } } } } } Swagger2-0.73/lib/Swagger2/Guides/CustomPlaceholder.pod000644 000765 000024 00000001710 12652632443 024071 0ustar00jhthorsenstaff000000 000000 =head1 NAME Swagger2::Guides::CustomPlaceholder - Custom placeholders =head2 OVERVIEW The default placeholder type is the L, meaning ":". This can be customized using C in the API specification. The example in L will enforce a L. =head1 SYNOPSIS { "swagger": "2.0", "basePath": "/api", "paths": { "/pets/{name}": { "get": { "operationId": "listPets", "parameters": [ { "name": "name", "in": "path", "type": "string", "x-mojo-placeholder": "#" } ], "responses": { "200": { ... } } } } } } =head1 AUTHOR Jan Henning Thorsen - C =cut Swagger2-0.73/lib/Swagger2/Guides/ProtectedApi.pod000644 000765 000024 00000003720 12645227324 023042 0ustar00jhthorsenstaff000000 000000 =head1 NAME Swagger2::Guides::ProtectedApi - Protected API Guide =head1 OVERVIEW It is possible to protect your API: You can either use a L or an L. Both can serve the same purpose, but the around action hook can be customized for every API resource. =head1 TUTORIAL =head2 Around action hook The C value is optional, but can hold the name of a method to call, which wraps around the autogenerated action which does input and output validation. This means that any data sent to the server is not yet converted into C<$input> to your action. Here is an example method which match the C from L, C: package MyApp; sub authenticate_api_request { my ($next, $c, $action_spec) = @_; # Go to the action if the Authorization header is valid return $next->($c) if $c->req->headers->authorization eq "s3cret!"; # ...or render an error if not return $c->render_swagger( {errors => [{message => "Invalid authorization key", path => "/"}]}, {}, 401 ); } C is also inherited from most levels, meaning that you define it globally for your whole API if you like: { "x-mojo-around-action": "MyApp::protect_any_resource", "paths": { "/pets": { "x-mojo-around-action": "MyApp::protect_any_method_under_foo", "get": { "x-mojo-around-action": "MyApp::protect_just_this_resource" } } } } =head2 Custom route use Mojolicious::Lite; my $route = app->routes->under->to( cb => sub { my $c = shift; return 1 if $c->param('secret'); return $c->render(json => {error => "Not authenticated"}, status => 401); } ); plugin Swagger2 => { route => $route, url => "data://api.json", }; __DATA__ @@ api.json {"swagger":"2.0", ...} =head1 AUTHOR Jan Henning Thorsen - C =cut Swagger2-0.73/lib/Swagger2/Guides/Render.pod000644 000765 000024 00000007257 12652632443 021707 0ustar00jhthorsenstaff000000 000000 =head1 NAME Swagger2::Guides::Render - Details about the render process =head1 OVERVIEW This guide will show how to render data with L. =head1 RENDER METHODS =head2 render This is the standard L render method. There is nothing that prevents you from calling this manually from inside your actions, but doing so will bypass the output validation code which is generated on the fly. There is an exception to this rule though: If you want to render binary data, then it won't make much sense to pass the data on to L and you must call L directly. =head2 render_swagger This method is called automatically by L. The process is: =over 4 =item 1. A request hit your web server and gets passed on to one of the autogenerated swagger routes. =item 2. There is a check called to see if the given controller and action exists. If this fail, L will be called with the L status code. =item 3. Next the input data is parsed to see if the request is valid. If this fail, L is called with the L status code. =item 4. The specified method (action) is called with the validated data and a callback. If the callback is called with response data, then the response data is parsed and validated. If the response is valid, then L is called with the L status code, if not it will be called with a L status code. =item 5. L will by default generate a JSON response using L. =back As for the L method above, there is nothing that prevents you from calling C manually from inside your actions, but doing so will bypass the output validation code which is generated on the fly. There should not be a case when you need to call this method directly. =head1 STATUS CODES =head2 200 The default C<$status> is 200, unless the method handling the request sent back another value. C<%err> will be empty in this case. =head2 400 This module will set C<$status> to 400 on invalid input. C<%err> then contains a data structure describing the errors. The default is to render a JSON document, like this: { "errors": [ { "message": "string value found, but a integer is required", "path": "/limit" }, ... ] } =head2 500 This module will set C<$status> to 500 on invalid response from the handler. C<%err> then contains a data structure describing the errors. The default is to render a JSON document, like this: { "errors": [ { "message": "is missing and it is required", "path": "/limit" }, ... ] } =head2 501 This module will set C<$status> to 501 if the given controller has not implemented the required method. C<%err> then contains a data structure describing the errors. The default is to render a JSON document, like this: { "errors": [ { "message": "No handler defined.", "path": "/" } ] } =head2 Default error schema The above statuses use the following error schema. It is general enough and so far works well. Feel free to use it in your applications like this: { "paths": "/pets" : { "get" : { "responses" : { "default": { "description": "Default error.", "schema": { "$ref": "http://git.io/vcKD4#" } } } } } } } L can also be provided as a full URL: L. =head1 AUTHOR Jan Henning Thorsen - C =cut Swagger2-0.73/lib/Swagger2/Guides/Tutorial.pod000644 000765 000024 00000010535 12657331575 022273 0ustar00jhthorsenstaff000000 000000 =head1 NAME Swagger2::Guides::Tutorial - Tutorial for Mojolicious::Plugin::Swagger2 =head1 OVERVIEW This tutorial will give you an introduction to how to use L. You can also check out L if you want to look at a complete example application. Another resources is the blog post L, which includes reasons for why you want to use L. =head1 TUTORIAL =head2 Swagger specification The input L to given as argument to the plugin need to point to a valid L document. Every operation must have "operationId" specified, so this plugin knows where to look for the controller and method. The naming convention is: "operationId": "methodControllerOptions" Example specification: { "swagger": "2.0", "basePath": "/api", "paths": { "/pets/{petId}": { "get": { "operationId": "showPetById", "parameters": [ ... ], "responses": { "200": { ... } } } } } } Here the "operationId" contains the method "show" and the controller "Pet". The "Pet" controller will again expand to C or C or whatever L is set to. The "options" part (ById) is simply ignored. Note that "showPetById" and "listPets" will both result in looking for the "Pet" controller, since the plural ending ("s") is removed. The table below try to illustrate how the controller/method is resolved: .---------------------------------------------------------------. | operationId | Controller | Method | Ignored | |------------------------|--------------|-------------|---------| | childrenOfPerson | Person | children | Of | | designByUser | User | design | By | | fooWithBar | Bar | foo | With | | getPetById | Pet | get | ById | | listUsers | User | list | s | | peopleInConversation | Conversation | people | In | | searchForPets | Pet | search | For, s | | sendToConversation | Conversation | send | To | | createFileInFileSystem | FileSystem | create_file | In | | removeFromFileSystem | FileSystem | remove | From | '---------------------------------------------------------------' The operationId rules will be updated I bugs or incompatibility is discovered. =head2 Application The application need to load the L plugin, with a URL to the API specification. The plugin will then add all the routes defined in the L. package MyApp; use Mojo::Base "Mojolicious"; sub startup { my $app = shift; $app->plugin(Swagger2 => { url => app->home->rel_file("api.json") }); } =head2 Controller The method names defined in the controller will be a L version of C. The example L above, will result in C in the controller below to be called. This method will receive the current L object, input arguments and a callback. The callback should be called with a HTTP status code, and a data structure which will be validated and serialized back to the user agent. C<$args> (input arguments) will be a hash, where the keys match "name" in the "parameters" defined in the Swagger spec, and the values are whatever input came from the client. This also goes for the "body" parameter: This means that the input JSON from HTTP body will not be flattened, but stored under the body parameter name in C<$args>. package MyApp::Controller::Pet; sub show { my ($c, $args, $cb) = @_; # Example $args: # $args->{body_param_name} == $c->req->json # $args->{query_param_name} == $c->req->url->query->param("query_param_name") # $args->{"X-Header-Name"} == $c->req->headers->header("X-Header-Name") $c->$cb({limit => 123}, 200); } =head1 SEE ALSO =over 4 =item * L - Protected API Guide =back =head1 AUTHOR Jan Henning Thorsen - C =cut Swagger2-0.73/lib/Swagger2/Guides/WebSocket.pod000644 000765 000024 00000006337 12645227324 022354 0ustar00jhthorsenstaff000000 000000 =head1 NAME Swagger2::Guides::WebSocket - How to expose Swagger over WebSockets =head1 OVERVIEW This guide will show how to expose a Swagger API over WebSockets. This feature is EXPERIMENTAL and is subject to change. =head1 DISCLAIMER This way of exposing Swagger over WebSockets is in no way compatible with L. =head1 SYNOPSIS =head2 Application package MyApp; use Mojo::Base "Mojolicious"; sub startup { my $app = shift; my $ws = $app->routes->websocket("/ws")->to("events#ws"); $app->plugin(Swagger2 => { url => app->home->rel_file("api.yaml"), ws => $ws, }); } In the example application class above, we create a custom route object for handling the WebSocket request. The route object C<$ws> is then passed on to the L and set up with a default route variable L. The reason why we create a custom websocket route is so it can be used bi-directional, instead of just dispatching to Swagger actions. =head2 Controller package MyApp::Controller::Events; sub ws { my $c = shift; $c->on(json => sub { my ($c, $data) = @_; return if $c->dispatch_to_swagger($data); }); } In the example controller above we listen to a L event which can L. This method will return boolean true if the input looks like a Swagger request. =head2 Request The input data to the WebSocket need to be JSON and look like this: { "id": "some unique string", "op": "operationId", "params": { "paramerName": "value" } } The "id" is used to map the response to a unique request. This means that the "id" need to be generated on the client side. The uniqueness requirement is only for this WebSocket connection. "op" need to match an operationId in the Swagger specification. "params" must be an object where the keys match the parameters in the Swagger specification. =head2 Response { "id": "some unique string", "code": 200, "body": {"any":"thing"} } The response contains the input "id", the HTTP status "code" and the response from the Swagger action inside "body". =head2 JavaScript example Here is an example JavaScript which can communicate over the socket: var ws = new WebSocket("ws://example.com/ws"); ws.onopen = function () { ws.send(JSON.stringify({ id: "42", op: "listPets", args: {limit: 60} }); }; ws.onmessage = function (e) { var data = JSON.parse(e.data); if (data.id == "42") { // Response from the request above, because of matching "id" console.log(data.code, data.body); } }; =head1 CAVEATS =over 4 =item * "x-mojo-around-action" is ignored when issuing WebSocket requests. This may be changed in future version. =item * Sharing a WebSocket route object between multiple Swagger plugins is unsupported. (The outcome is unknown) =item * The protocol and implementation is subject for change. L is highly appreciated. =back =head1 AUTHOR Jan Henning Thorsen - C =cut Swagger2-0.73/lib/Mojolicious/Command/000755 000765 000024 00000000000 12660346320 020715 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/lib/Mojolicious/Plugin/000755 000765 000024 00000000000 12660346320 020575 5ustar00jhthorsenstaff000000 000000 Swagger2-0.73/lib/Mojolicious/Plugin/Swagger2.pm000644 000765 000024 00000043760 12656642162 022636 0ustar00jhthorsenstaff000000 000000 package Mojolicious::Plugin::Swagger2; use Mojo::Base 'Mojolicious::Plugin'; use Mojo::JSON; use Mojo::Loader; use Mojo::Util 'decamelize'; use Swagger2; use Swagger2::SchemaValidator; use constant DEBUG => $ENV{SWAGGER2_DEBUG} || 0; my $SKIP_OP_RE = qr(By|From|For|In|Of|To|With); has url => ''; has _validator => sub { Swagger2::SchemaValidator->new; }; sub dispatch_to_swagger { return undef unless $_[1]->{op} and $_[1]->{id} and ref $_[1]->{params} eq 'HASH'; my ($c, $data) = @_; my $self = $c->stash('swagger.plugin'); my $reply = sub { $_[0]->send({json => {code => $_[2] || 200, id => $data->{id}, body => $_[1]}}) }; my $defaults = $self->{route_defaults}{$data->{op}} or return $c->$reply(_error('Unknown operationId.'), 400); my ($e, $input, @errors); return $c->$reply(_error($e), 501) if $e = _find_action($c, $defaults); for my $p (@{$defaults->{swagger_operation_spec}{parameters} || []}) { my $name = $p->{name}; my $value = $data->{params}{$name} // $p->{default}; my @e = $self->_validate_input_value($p, $name => $value); $input->{$name} = $value unless @e; push @errors, @e; } return $c->$reply({errors => \@errors}, 400) if @errors; return Mojo::IOLoop->delay( sub { my $delay = shift; my $action = $defaults->{action}; my $sc = $delay->data->{sc} = $defaults->{controller}->new(%$c); $sc->stash(swagger_operation_spec => $defaults->{swagger_operation_spec}); $sc->$action($input, $delay->begin); }, sub { my $delay = shift; my $data = shift; my $status = shift || 200; my @errors = $self->_validate_response($c, $data, $defaults->{swagger_operation_spec}, $status); return $c->$reply($data, $status) unless @errors; warn "[Swagger2] Invalid response: @errors\n" if DEBUG; $c->$reply({errors => \@errors}, 500); }, ); } sub render_swagger { my ($c, $err, $data, $status) = @_; return $c->render(json => $err, status => $status) if %$err; return $c->render(ref $data ? (json => $data) : (text => $data), status => $status); } sub register { my ($self, $app, $config) = @_; my ($base_path, $paths, $r, $swagger); $swagger = $config->{swagger} || Swagger2->new->load($config->{url} || '"url" is missing'); $swagger = $swagger->expand; $paths = $swagger->api_spec->get('/paths') || {}; if ($config->{validate} // 1) { my @errors = $swagger->validate; die join "\n", "Swagger2: Invalid spec:", @errors if @errors; } if (!$app->plugins->has_subscribers('swagger_route_added')) { $app->hook(swagger_route_added => \&_on_route_added); } local $config->{coerce} = $config->{coerce} || $ENV{SWAGGER_COERCE_VALUES}; $self->_validator->coerce($config->{coerce}) if $config->{coerce}; $self->url($swagger->url); $app->helper(dispatch_to_swagger => \&dispatch_to_swagger) unless $app->renderer->get_helper('dispatch_to_swagger'); $app->helper(render_swagger => \&render_swagger) unless $app->renderer->get_helper('render_swagger'); $r = $config->{route}; if ($r and !$r->pattern->unparsed) { $r->to(swagger => $swagger); $r = $r->any($swagger->base_url->path->to_string); } if (!$r) { $r = $app->routes->any($swagger->base_url->path->to_string); $r->to(swagger => $swagger); } if (my $ws = $config->{ws}) { $ws->to('swagger.plugin' => $self); } $base_path = $swagger->api_spec->data->{basePath} = $r->to_string; $base_path =~ s!/$!!; for my $path (sort { length $a <=> length $b } keys %$paths) { my $around_action = $paths->{$path}{'x-mojo-around-action'} || $swagger->api_spec->get('/x-mojo-around-action'); my $controller = $paths->{$path}{'x-mojo-controller'} || $swagger->api_spec->get('/x-mojo-controller'); for my $http_method (grep { !/^x-/ } keys %{$paths->{$path}}) { my $op_spec = $paths->{$path}{$http_method}; my $route_path = $path; my %parameters = map { ($_->{name}, $_) } @{$op_spec->{parameters} || []}; $route_path =~ s/{([^}]+)}/{ my $name = $1; my $type = $parameters{$name}{'x-mojo-placeholder'} || ':'; "($type$name)"; }/ge; $op_spec->{'x-mojo-around-action'} = $around_action if !$op_spec->{'x-mojo-around-action'} and $around_action; $op_spec->{'x-mojo-controller'} = $controller if !$op_spec->{'x-mojo-controller'} and $controller; $app->plugins->emit( swagger_route_added => $r->$http_method($route_path => $self->_generate_request_handler($op_spec))); warn "[Swagger2] Add route $http_method $base_path$route_path\n" if DEBUG; } } if (my $spec_path = $config->{spec_path} // '/') { my $title = $swagger->api_spec->get('/info/title'); $title =~ s!\W!_!g; $r->get($spec_path)->to(cb => sub { _render_spec(shift, $swagger) })->name(lc $title); } if ($config->{ensure_swagger_response}) { $self->_ensure_swagger_response($app, $config->{ensure_swagger_response}, $swagger); } } sub _ensure_swagger_response { my ($self, $app, $responses, $swagger) = @_; my $base_path = $swagger->api_spec->data->{basePath}; $responses->{exception} ||= 'Internal server error.'; $responses->{not_found} ||= 'Not found.'; $base_path = qr{^$base_path}; $app->hook( before_render => sub { my ($c, $args) = @_; return unless my $template = $args->{template}; return unless my $msg = $responses->{$template}; return unless $c->req->url->path->to_string =~ $base_path; $args->{json} = _error($msg); } ); } sub _generate_request_handler { my ($self, $op_spec) = @_; my $defaults = {swagger_operation_spec => $op_spec}; my $handler = sub { my $c = shift; my ($e, $v, $input); return $c->render_swagger(_error($e), {}, 501) if $e = _find_action($c, $defaults); $c = $defaults->{controller}->new(%$c); ($v, $input) = $self->_validate_input($c, $op_spec); return $c->render_swagger($v, {}, 400) if @{$v->{errors}}; return $c->delay( sub { my $action = $defaults->{action}; $c->app->log->debug(qq(Swagger2 routing to controller "$defaults->{controller}" and action "$action")); $c->$action($input, shift->begin); }, sub { my $delay = shift; my $data = shift; my $status = shift || 200; my @errors = $self->_validate_response($c, $data, $op_spec, $status); return $c->render_swagger({}, $data, $status) unless @errors; warn "[Swagger2] Invalid response: @errors\n" if DEBUG; $c->render_swagger({errors => \@errors}, $data, 500); }, ); }; for my $p (@{$op_spec->{parameters} || []}) { $defaults->{$p->{name}} = $p->{default} if $p->{in} eq 'path' and defined $p->{default}; } if (my $around_action = $op_spec->{'x-mojo-around-action'}) { my $next = $handler; $handler = sub { my $c = shift; my $around = $c->can($around_action) || $around_action; $around->($next, $c, $op_spec); }; } $self->{route_defaults}{$op_spec->{operationId}} = $defaults; return $defaults, $handler; } sub _on_route_added { my ($self, $r) = @_; my $op_spec = $r->pattern->defaults->{swagger_operation_spec}; my $controller = $op_spec->{'x-mojo-controller'}; my $route_name; $route_name = $controller ? decamelize join '::', map { ucfirst $_ } $controller, $op_spec->{operationId} : decamelize $op_spec->{operationId}; $route_name =~ s/\W+/_/g; $r->name($route_name); } sub _render_spec { my ($c, $swagger) = @_; my $spec = $swagger->api_spec->data; local $spec->{id}; delete $spec->{id}; local $spec->{host} = $c->req->url->to_abs->host_port; $c->render(json => $spec); } sub _validate_input { my ($self, $c, $op_spec) = @_; my (%cache, %input, @errors); for my $p (@{$op_spec->{parameters} || []}) { my ($in, $name, $type) = @$p{qw( in name type )}; my ($exists, $value); if ($in eq 'body') { $value = $c->req->json; $exists = $c->req->body_size; } else { $value = $cache{$in} ||= do { $in eq 'query' ? $c->req->url->query->to_hash : $in eq 'path' ? $c->match->stack->[-1] : $in eq 'formData' ? $c->req->body_params->to_hash : $in eq 'header' ? $c->req->headers->to_hash : {}; }; $exists = exists $value->{$name}; $value = $value->{$name}; } if (ref $p->{items} eq 'HASH' and $p->{collectionFormat}) { $value = _coerce_by_collection_format($value, $p); } if ($type and defined($value //= $p->{default})) { if (($type eq 'integer' or $type eq 'number') and $value =~ /^-?\d/) { $value += 0; } elsif ($type eq 'boolean') { $value = (!$value or $value eq 'false') ? Mojo::JSON->false : Mojo::JSON->true; } } my @e = $self->_validate_input_value($p, $name => $value); $input{$name} = $value if !@e and ($exists or exists $p->{default}); push @errors, @e; } return {errors => \@errors}, \%input; } sub _validate_input_value { my ($self, $p, $name, $value) = @_; my $type = $p->{type} || 'object'; my @e; return if !defined $value and !Swagger2::_is_true($p->{required}); my $schema = {properties => {$name => $p->{schema} || $p}, required => [$p->{required} ? ($name) : ()]}; my $in = $p->{in}; if ($in eq 'body') { warn "[Swagger2] Validate $in $name\n" if DEBUG; return $self->_validator->validate_input({$name => $value}, $schema); } elsif (defined $value) { warn "[Swagger2] Validate $in $name=$value\n" if DEBUG; return $self->_validator->validate_input({$name => $value}, $schema); } else { warn "[Swagger2] Validate $in $name=undef\n" if DEBUG; return $self->_validator->validate_input({$name => $value}, $schema); } return; } sub _validate_response { my ($self, $c, $data, $op_spec, $status) = @_; my $headers = $c->res->headers; my @errors; if (my $blueprint = $op_spec->{responses}{$status} || $op_spec->{responses}{default}) { my $input = $headers->to_hash(1); for my $n (keys %{$blueprint->{headers} || {}}) { my $p = $blueprint->{headers}{$n}; # jhthorsen: I think that the only way to make a header required, # is by defining "array" and "minItems" >= 1. if ($p->{type} eq 'array') { push @errors, $self->_validator->validate($input->{$n}, $p); } elsif ($input->{$n}) { push @errors, $self->_validator->validate($input->{$n}[0], $p); $headers->header($n => $input->{$n}[0] ? 'true' : 'false') if $p->{type} eq 'boolean' and !@errors; } } push @errors, $self->_validator->validate($data, $blueprint->{schema}) if $blueprint->{schema}; } else { push @errors, $self->_validator->validate($data, {}); } return @errors; } sub _coerce_by_collection_format { my ($value, $schema) = @_; my $re = $Swagger2::SchemaValidator::COLLECTION_RE{$schema->{collectionFormat}} || ''; my $type = $schema->{items}{type} || ''; my @data; return [ref $value ? @$value : $value] unless $re; defined and push @data, split /$re/ for ref $value ? @$value : $value; return [map { $_ + 0 } @data] if $type eq 'integer' or $type eq 'number'; return \@data; } sub _error { return {errors => [{message => $_[0], path => '/'}]}; } sub _find_action { return if $_[1]->{controller}; # cached my ($c, $defaults) = @_; my $op = $defaults->{swagger_operation_spec}{operationId} or return 'operationId is missing.'; my $can = sub { $defaults->{controller}->can($defaults->{action}) ? '' : qq(Method "$defaults->{action}" not implemented.); }; # specify controller manually @$defaults{qw( action controller )} = _load($c, $op, $defaults->{swagger_operation_spec}{'x-mojo-controller'}); return $can->() if $defaults->{controller}; # "createFileInFileSystem" = ("createFile", "FileSystem") @$defaults{qw( action controller )} = _load($c, split $SKIP_OP_RE, $op); return $can->() if $defaults->{controller}; # "showPetById" = "showPet" $op =~ s!$SKIP_OP_RE.*$!!; # "show_fooPet" = ("show_foo", "Pet") @$defaults{qw( action controller )} = _load($c, $op =~ /^([a-z_]+)([A-Z]\w+)$/); return $can->() if $defaults->{controller}; return qq(Controller from operationId "$defaults->{swagger_operation_spec}{operationId}" could not be loaded.); } sub _load { my ($c, $action, $controller) = @_; my (@classes, %uniq); return unless $controller; $action = decamelize ucfirst $action; if ($controller =~ /::/) { push @classes, $controller; } else { my $singular = $controller; $singular =~ s!s$!!; # "showPets" = "showPet" push @classes, grep { !$uniq{$_}++ } map { ("${_}::$controller", "${_}::$singular") } @{$c->app->routes->namespaces}; } while ($controller = shift @classes) { my $e = Mojo::Loader::load_class($controller); warn qq([Swagger2] Load "$controller": @{[ref $e ? $e : $e ? "Can't locate class" : "Success"]}.\n) if DEBUG; return ($action, $controller) if $controller->can('new'); } return; } 1; =encoding utf8 =head1 NAME Mojolicious::Plugin::Swagger2 - Mojolicious plugin for Swagger2 =head1 SYNOPSIS package MyApp; use Mojo::Base "Mojolicious"; sub startup { my $app = shift; $app->plugin(Swagger2 => {url => "data://MyApp/petstore.json"}); } __DATA__ @@ petstore.json { "swagger": "2.0", "info": {...}, "host": "petstore.swagger.wordnik.com", "basePath": "/api", "paths": { "/pets": { "get": {...} } } } =head1 DESCRIPTION L is L that add routes and input/output validation to your L application. Have a look at the L for a complete reference to what is possible or look at L for an introduction. =head1 RESOURCES =over 4 =item * L - Tutorial for this plugin =item * L - Details about the render process =item * L - Protected API Guide =item * L - Custom placeholder for your routes =item * L =item * L =item * L =item * L =back =head1 HOOKS =head2 swagger_route_added $app->hook(swagger_route_added => sub { my ($app, $r) = @_; my $op_spec = $r->pattern->defaults->{swagger_operation_spec}; # ... }); The "swagger_route_added" event will be emitted on the application object for every route that is added by this plugin. This can be useful if you want to do things like specifying a custom route name. =head1 STASH VARIABLES =head2 swagger The L object used to generate the routes is available as C from L. Example code: sub documentation { my ($c, $args, $cb); $c->$cb($c->stash('swagger')->pod->to_string, 200); } =head2 swagger_operation_spec The Swagger specification for the current L is stored in the "swagger_operation_spec" stash variable. sub list_pets { my ($c, $args, $cb); $c->app->log->info($c->stash("swagger_operation_spec")->{operationId}); ... } =head1 ATTRIBUTES =head2 url Holds the URL to the swagger specification file. =head1 HELPERS =head2 dispatch_to_swagger $bool = $c->dispatch_to_swagger(\%data); This helper can be used to handle WebSocket requests with swagger. See L for details. This helper is EXPERIMENTAL. =head2 render_swagger $c->render_swagger(\%err, \%data, $status); This method is used to render C<%data> from the controller method. The C<%err> hash will be empty on success, but can contain input/output validation errors. C<$status> is used to set a proper HTTP status code such as 200, 400 or 500. See also L for more information. =head1 METHODS =head2 register $self->register($app, \%config); This method is called when this plugin is registered in the L application. C<%config> can contain these parameters: =over 4 =item * coerce This argument will be passed on to L. =item * ensure_swagger_response $app->plugin(swagger2 => { ensure_swagger_response => { exception => "Internal server error.", not_found => "Not found.", } }); Adds a L hook which will make sure "exception" and "not_found" responses are in JSON format. There is no need to specify "exception" and "not_found" if you are happy with the defaults. =item * route Need to hold a Mojolicious route object. See L for an example. This parameter is optional. =item * spec_path Holds the location for where the specifiation can be served from. The default value is "/", relative to "basePath" in the specification. Can be disabled by setting this value to empty string. =item * validate A boolean value (default is true) that will cause your schema to be validated. This plugin will abort loading if the schema include errors =item * swagger A C object. This can be useful if you want to keep use the specification to other things in your application. Example: use Swagger2; my $swagger = Swagger2->new->load($url); plugin Swagger2 => {swagger => $swagger2}; app->defaults(swagger_spec => $swagger->api_spec); Either this parameter or C need to be present. =item * url This will be used to construct a new L object. The C can be anything that L can handle. Either this parameter or C need to be present. =back =head1 COPYRIGHT AND LICENSE Copyright (C) 2014-2015, Jan Henning Thorsen This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0. =head1 AUTHOR Jan Henning Thorsen - C =cut Swagger2-0.73/lib/Mojolicious/Command/swagger2.pm000644 000765 000024 00000014264 12656175040 023007 0ustar00jhthorsenstaff000000 000000 package Mojolicious::Command::swagger2; use Mojo::Base 'Mojolicious::Command'; use Mojo::Util; use Swagger2; my $app = __PACKAGE__; # used in tests our $OUT = \*STDOUT; has description => 'Interface with Swagger2.'; has usage => <<"HERE"; Usage: # Make a request to a Swagger server @{[__PACKAGE__->_usage('client')]} # Edit an API file in your browser # This command also takes whatever option "morbo" takes @{[__PACKAGE__->_usage('edit')]} # Write POD to STDOUT @{[__PACKAGE__->_usage('pod')]} # Run perldoc on the generated POD @{[__PACKAGE__->_usage('perldoc')]} # Validate an API file @{[__PACKAGE__->_usage('validate')]} HERE sub run { my $self = shift; my $action = shift || 'unknown'; my $code = $self->can("_action_$action"); die $self->usage unless $code; $self->$code(@_); } sub _action_client { my ($self, $file, @args) = @_; unshift @args, $file if $ENV{SWAGGER_API_FILE}; $ENV{SWAGGER_COERCE_VALUES} //= 1; my $method = shift @args; my $args = {}; my $base_url = $ENV{SWAGGER_BASE_URL}; my $i = 0; return print $OUT $self->_usage_client unless $ENV{SWAGGER_API_FILE} ||= $file; return print $OUT $self->_documentation_for('') if !$method or $method =~ /\W/; require Swagger2::Client; my $client = Swagger2::Client->generate($ENV{SWAGGER_API_FILE}); for (@args) { return $self->_documentation_for($method) if $_ eq 'help'; $base_url = $args[$i + 1] if $_ eq '-b'; $args = Mojo::JSON::decode_json($args[0]) if /^\{/; $args->{$1} = $2 if /^(\w+)=(.*)/; $i++; } $client->base_url->parse($base_url) if $base_url; eval { my $res = $client->$method($args); print $OUT $res->json ? Mojo::Util::dumper($res->json) : $res->body; 1; } or do { my $e = $@; $e =~ s! at .* line.*!!s; warn "ERROR! $e\n"; }; } sub _action_edit { my ($self, $file, @args) = @_; unshift @args, $file if $ENV{SWAGGER_API_FILE}; $ENV{SWAGGER_API_FILE} ||= $file || ''; $ENV{SWAGGER_LOAD_EDITOR} = 1; $file ||= __FILE__; require Swagger2::Editor; system 'morbo', -w => $file, @args, $INC{'Swagger2/Editor.pm'}; } sub _action_perldoc { my ($self, $file) = @_; die $self->_usage('perldoc'), "\n" unless $file; require Mojo::Asset::File; my $asset = Mojo::Asset::File->new; $asset->add_chunk(Swagger2->new($file)->pod->to_string); system perldoc => $asset->path; } sub _action_pod { my ($self, $file) = @_; die $self->_usage('pod'), "\n" unless $file; print $OUT Swagger2->new($file)->pod->to_string; } sub _action_validate { my ($self, $file) = @_; my @errors; die $self->_usage('validate'), "\n" unless $file; @errors = Swagger2->new($file)->validate; unless (@errors) { print $OUT "$file is valid.\n"; return; } for my $e (@errors) { print $OUT "$e\n"; } } sub _documentation_for { my ($self, $needle) = @_; my $pod = Swagger2->new($ENV{SWAGGER_API_FILE})->pod; my $paths = $pod->{api_spec}->get('/paths') || {}; my @methods; for my $path (sort keys %$paths) { for my $method (sort keys %{$paths->{$path}}) { push @methods, $paths->{$path}{$method}{operationId} || join ' ', $method, $path; delete $paths->{$path}{$method} unless $methods[-1] eq $needle; } delete $paths->{$path} unless %{$paths->{$path}}; } unless ($needle) { print $OUT "$_\n" for sort @methods; return; } require Pod::Simple; my $pod_text = Pod::Text->new; $pod_text->output_fh($OUT); $pod_text->parse_string_document($pod->_paths_to_string); } sub _usage { my $self = shift; return "Usage: mojo swagger2 edit" if $_[0] eq 'edit'; return "Usage: mojo swagger2 perldoc path/to/spec.json" if $_[0] eq 'perldoc'; return "Usage: mojo swagger2 pod path/to/spec.json" if $_[0] eq 'pod'; return "Usage: mojo swagger2 validate path/to/spec.json" if $_[0] eq 'validate'; return "Usage: mojo swagger2 client path/to/spec.json [args]" if $_[0] eq 'client'; die "No usage for '@_'"; } sub _usage_client { my $self = shift; return < [args] # List methods mojo swagger2 client path/to/spec.json # Get documentation for a method mojo swagger2 client path/to/spec.json help # Specify spec and/or base URL from environment. # Useful for shell wrappers SWAGGER_API_FILE=path/to/spec.json mojo swagger2 client SWAGGER_BASE_URL=https://example.com/1.0 mojo swagger2 client # Example arguments mojo swagger2 client path/to/spec.json list_pets '{"limit":10}' mojo swagger2 client path/to/spec.json list_pets limit=10 owner=joe mojo swagger2 client path/to/spec.json -b https://example.com/1.0 list_pets limit=10 owner=joe HERE } 1; =encoding utf8 =head1 NAME Mojolicious::Command::swagger2 - mojo swagger2 command =head1 DESCRIPTION L is a command for interfacing with L. =head1 SYNOPSIS # Call a method with arguments mojo swagger2 client path/to/spec.json [args] # List methods mojo swagger2 client path/to/spec.json # Get documentation for a method mojo swagger2 client path/to/spec.json help # Specify spec and/or base URL from environment. # Useful for shell wrappers SWAGGER_API_FILE=path/to/spec.json mojo swagger2 client SWAGGER_BASE_URL=https://example.com/1.0 mojo swagger2 client # Example arguments mojo swagger2 client path/to/spec.json list_pets '{"limit":10}' mojo swagger2 client path/to/spec.json list_pets limit=10 owner=joe mojo swagger2 client path/to/spec.json -b https://example.com/1.0 list_pets limit=10 owner=joe =head1 ATTRIBUTES =head2 description Returns description of this command. =head2 usage Returns usage of this command. =head1 METHODS =head2 run See L. =head1 COPYRIGHT AND LICENSE Copyright (C) 2014-2015, Jan Henning Thorsen This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0. =head1 AUTHOR Jan Henning Thorsen - C =cut